summaryrefslogtreecommitdiff
path: root/chromium/components/viz
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/viz')
-rw-r--r--chromium/components/viz/BUILD.gn13
-rw-r--r--chromium/components/viz/OWNERS2
-rw-r--r--chromium/components/viz/README.md13
-rw-r--r--chromium/components/viz/common/BUILD.gn36
-rw-r--r--chromium/components/viz/common/DEPS2
-rw-r--r--chromium/components/viz/common/display/renderer_settings.h1
-rw-r--r--chromium/components/viz/common/features.cc40
-rw-r--r--chromium/components/viz/common/features.h7
-rw-r--r--chromium/components/viz/common/frame_sinks/README.md4
-rw-r--r--chromium/components/viz/common/frame_sinks/blit_request.cc13
-rw-r--r--chromium/components/viz/common/frame_sinks/blit_request.h30
-rw-r--r--chromium/components/viz/common/frame_sinks/copy_output_request.cc1
-rw-r--r--chromium/components/viz/common/frame_sinks/copy_output_request.h14
-rw-r--r--chromium/components/viz/common/gl_i420_converter.cc209
-rw-r--r--chromium/components/viz/common/gl_i420_converter.h195
-rw-r--r--chromium/components/viz/common/gl_i420_converter_pixeltest.cc129
-rw-r--r--chromium/components/viz/common/gl_i420_converter_unittest.cc77
-rw-r--r--chromium/components/viz/common/gl_nv12_converter.cc195
-rw-r--r--chromium/components/viz/common/gl_nv12_converter.h200
-rw-r--r--chromium/components/viz/common/gl_nv12_converter_pixeltest.cc154
-rw-r--r--chromium/components/viz/common/gl_scaler.cc1661
-rw-r--r--chromium/components/viz/common/gl_scaler.h538
-rw-r--r--chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc532
-rw-r--r--chromium/components/viz/common/gl_scaler_pixeltest.cc628
-rw-r--r--chromium/components/viz/common/gl_scaler_shader_pixeltest.cc785
-rw-r--r--chromium/components/viz/common/gl_scaler_unittest.cc236
-rw-r--r--chromium/components/viz/common/gpu/context_cache_controller.cc1
-rw-r--r--chromium/components/viz/common/overlay_state/win/DEPS8
-rw-r--r--chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.cc28
-rw-r--r--chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.h29
-rw-r--r--chromium/components/viz/common/overlay_state/win/overlay_state_service.cc184
-rw-r--r--chromium/components/viz/common/overlay_state/win/overlay_state_service.h83
-rw-r--r--chromium/components/viz/common/overlay_state/win/overlay_state_service_unittest.cc195
-rw-r--r--chromium/components/viz/common/quads/compositor_render_pass_unittest.cc2
-rw-r--r--chromium/components/viz/common/quads/debug_border_draw_quad.cc9
-rw-r--r--chromium/components/viz/common/quads/debug_border_draw_quad.h2
-rw-r--r--chromium/components/viz/common/quads/draw_quad_unittest.cc9
-rw-r--r--chromium/components/viz/common/quads/render_pass_io.cc95
-rw-r--r--chromium/components/viz/common/quads/shared_quad_state.cc12
-rw-r--r--chromium/components/viz/common/quads/solid_color_draw_quad.cc8
-rw-r--r--chromium/components/viz/common/quads/solid_color_draw_quad.h4
-rw-r--r--chromium/components/viz/common/quads/surface_draw_quad.cc6
-rw-r--r--chromium/components/viz/common/quads/surface_draw_quad.h2
-rw-r--r--chromium/components/viz/common/quads/texture_draw_quad.cc6
-rw-r--r--chromium/components/viz/common/quads/texture_draw_quad.h2
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.cc38
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.h2
-rw-r--r--chromium/components/viz/common/resources/transferable_resource.h26
-rw-r--r--chromium/components/viz/common/surfaces/local_surface_id_unittest.cc2
-rw-r--r--chromium/components/viz/common/switches.cc18
-rw-r--r--chromium/components/viz/common/switches.h2
-rw-r--r--chromium/components/viz/common/transition_utils.cc23
-rw-r--r--chromium/components/viz/common/yuv_readback_unittest.cc14
-rw-r--r--chromium/components/viz/demo/demo_main.cc2
-rw-r--r--chromium/components/viz/demo/service/demo_service.cc2
-rw-r--r--chromium/components/viz/host/client_frame_sink_video_capturer.h4
-rw-r--r--chromium/components/viz/host/gpu_host_impl.cc11
-rw-r--r--chromium/components/viz/host/gpu_host_impl.h5
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.cc31
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.h3
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.cc9
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.h2
-rw-r--r--chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc4
-rw-r--r--chromium/components/viz/host/renderer_settings_creation.cc1
-rw-r--r--chromium/components/viz/service/BUILD.gn220
-rw-r--r--chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc3
-rw-r--r--chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h3
-rw-r--r--chromium/components/viz/service/display/DEPS2
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.cc19
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.h11
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.cc45
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.h5
-rw-r--r--chromium/components/viz/service/display/direct_renderer.cc89
-rw-r--r--chromium/components/viz/service/display/direct_renderer.h45
-rw-r--r--chromium/components/viz/service/display/display.cc74
-rw-r--r--chromium/components/viz/service/display/display.h3
-rw-r--r--chromium/components/viz/service/display/display_damage_tracker.cc5
-rw-r--r--chromium/components/viz/service/display/display_damage_tracker.h1
-rw-r--r--chromium/components/viz/service/display/display_perftest.cc6
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.cc10
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.h34
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_gl.cc425
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_gl.h165
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_gl_unittest.cc718
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_skia.cc31
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_skia.h9
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc283
-rw-r--r--chromium/components/viz/service/display/display_scheduler.cc25
-rw-r--r--chromium/components/viz/service/display/display_scheduler_unittest.cc4
-rw-r--r--chromium/components/viz/service/display/display_unittest.cc879
-rw-r--r--chromium/components/viz/service/display/dynamic_geometry_binding.cc68
-rw-r--r--chromium/components/viz/service/display/dynamic_geometry_binding.h40
-rw-r--r--chromium/components/viz/service/display/external_use_client.h8
-rw-r--r--chromium/components/viz/service/display/frame_rate_decider_unittest.cc4
-rw-r--r--chromium/components/viz/service/display/geometry_binding.cc75
-rw-r--r--chromium/components/viz/service/display/geometry_binding.h64
-rw-r--r--chromium/components/viz/service/display/gl_renderer.cc4514
-rw-r--r--chromium/components/viz/service/display/gl_renderer.h525
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.cc1298
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.h485
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier_perftest.cc338
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc958
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier_unittest.cc224
-rw-r--r--chromium/components/viz/service/display/gl_renderer_draw_cache.cc13
-rw-r--r--chromium/components/viz/service/display/gl_renderer_draw_cache.h62
-rw-r--r--chromium/components/viz/service/display/gl_renderer_unittest.cc5195
-rw-r--r--chromium/components/viz/service/display/layer_quad.cc121
-rw-r--r--chromium/components/viz/service/display/layer_quad.h110
-rw-r--r--chromium/components/viz/service/display/layer_quad_unittest.cc69
-rw-r--r--chromium/components/viz/service/display/null_renderer.h1
-rw-r--r--chromium/components/viz/service/display/output_surface.cc9
-rw-r--r--chromium/components/viz/service/display/output_surface.h74
-rw-r--r--chromium/components/viz/service/display/output_surface_client.h6
-rw-r--r--chromium/components/viz/service/display/overlay_ca_unittest.cc73
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.cc470
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.h201
-rw-r--r--chromium/components/viz/service/display/overlay_dc_unittest.cc87
-rw-r--r--chromium/components/viz/service/display/overlay_processor_delegated.cc18
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.h7
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.cc61
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.h2
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc35
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.cc47
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.h2
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_fullscreen.cc18
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_single_on_top.cc20
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay.cc27
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc52
-rw-r--r--chromium/components/viz/service/display/overlay_unittest.cc262
-rw-r--r--chromium/components/viz/service/display/program_binding.cc301
-rw-r--r--chromium/components/viz/service/display/program_binding.h480
-rw-r--r--chromium/components/viz/service/display/renderer_perftest.cc117
-rw-r--r--chromium/components/viz/service/display/renderer_pixeltest.cc381
-rw-r--r--chromium/components/viz/service/display/resource_fence.h10
-rw-r--r--chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc96
-rw-r--r--chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.h49
-rw-r--r--chromium/components/viz/service/display/scoped_render_pass_texture.cc127
-rw-r--r--chromium/components/viz/service/display/scoped_render_pass_texture.h61
-rw-r--r--chromium/components/viz/service/display/shader.cc1168
-rw-r--r--chromium/components/viz/service/display/shader.h324
-rw-r--r--chromium/components/viz/service/display/shader_unittest.cc58
-rw-r--r--chromium/components/viz/service/display/skia_output_surface.h31
-rw-r--r--chromium/components/viz/service/display/skia_readback_pixeltest.cc50
-rw-r--r--chromium/components/viz/service/display/skia_renderer.cc409
-rw-r--r--chromium/components/viz/service/display/skia_renderer.h119
-rw-r--r--chromium/components/viz/service/display/software_renderer.cc32
-rw-r--r--chromium/components/viz/service/display/software_renderer_unittest.cc79
-rw-r--r--chromium/components/viz/service/display/static_geometry_binding.cc74
-rw-r--r--chromium/components/viz/service/display/static_geometry_binding.h41
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.cc141
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.h28
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_pixeltest.cc4
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_unittest.cc9
-rw-r--r--chromium/components/viz/service/display/sync_query_collection.cc151
-rw-r--r--chromium/components/viz/service/display/sync_query_collection.h42
-rw-r--r--chromium/components/viz/service/display/texture_deleter.cc87
-rw-r--r--chromium/components/viz/service/display/texture_deleter.h64
-rw-r--r--chromium/components/viz/service/display/texture_deleter_unittest.cc84
-rw-r--r--chromium/components/viz/service/display/viz_pixel_test.cc3
-rw-r--r--chromium/components/viz/service/display/viz_pixel_test.h4
-rw-r--r--chromium/components/viz/service/display_embedder/DEPS6
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc30
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_gpu_thread.h12
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface.cc265
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface.h114
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_android.cc26
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_android.h32
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc314
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h111
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc359
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.cc25
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.h33
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.cc139
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.h57
-rw-r--r--chromium/components/viz/service/display_embedder/image_context_impl.h4
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter.cc10
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_gl.cc35
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider.h3
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc119
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider_impl.h30
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_unified.cc16
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_unified.h12
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device.cc9
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc10
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_gl.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_webview.cc7
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_webview.h2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc195
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.h37
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc650
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h108
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc62
-rw-r--r--chromium/components/viz/service/display_embedder/skia_render_copy_results.cc46
-rw-r--r--chromium/components/viz/service/display_embedder/skia_render_copy_results.h66
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.cc41
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.h12
-rw-r--r--chromium/components/viz/service/display_embedder/viz_process_context_provider.cc348
-rw-r--r--chromium/components/viz/service/display_embedder/viz_process_context_provider.h136
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc14
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h3
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc40
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h12
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc82
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc6
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc197
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc53
-rw-r--r--chromium/components/viz/service/gl/DEPS1
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.cc67
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.h28
-rw-r--r--chromium/components/viz/service/main/viz_compositor_thread_runner.h20
-rw-r--r--chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc25
-rw-r--r--chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h3
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.cc45
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.h23
-rw-r--r--chromium/components/viz/service/main/viz_main_impl_unittest.cc7
-rw-r--r--chromium/components/viz/service/performance_hint/hint_session.cc17
-rw-r--r--chromium/components/viz/service/performance_hint/hint_session.h2
-rw-r--r--chromium/components/viz/service/surfaces/surface.cc149
-rw-r--r--chromium/components/viz/service/surfaces/surface.h81
-rw-r--r--chromium/components/viz/service/surfaces/surface_allocation_group.h2
-rw-r--r--chromium/components/viz/service/surfaces/surface_client.h10
-rw-r--r--chromium/components/viz/service/surfaces/surface_manager.cc45
-rw-r--r--chromium/components/viz/service/surfaces/surface_manager.h20
-rw-r--r--chromium/components/viz/service/surfaces/surface_observer.h3
-rw-r--r--chromium/components/viz/service/transitions/surface_animation_manager.cc32
-rw-r--r--chromium/components/viz/service/transitions/surface_animation_manager.h3
-rw-r--r--chromium/components/viz/test/BUILD.gn1
-rw-r--r--chromium/components/viz/viz.gni7
228 files changed, 4476 insertions, 29985 deletions
diff --git a/chromium/components/viz/BUILD.gn b/chromium/components/viz/BUILD.gn
index db7f49872ec..a1d5c682e06 100644
--- a/chromium/components/viz/BUILD.gn
+++ b/chromium/components/viz/BUILD.gn
@@ -41,13 +41,14 @@ viz_test("viz_unittests") {
}
if (is_fuchsia) {
- use_cfv2 = false
- additional_manifest_fragments = [
- # TODO(crbug.com/1185811): Figure out why jit_capabilities is needed.
- "//build/config/fuchsia/test/jit_capabilities.test-cmx",
+ use_cfv1 = false
- "//build/config/fuchsia/test/vulkan_capabilities.test-cmx",
- ]
+ # TODO(https://crbug.com/1185811): Investigate removing the requirement for
+ # job_policy_ambient_mark_vmo_exec for the sake of V8's allocator in tests.
+ test_runner_shard = "//build/config/fuchsia/test/elf_test_ambient_exec_runner.shard.test-cml"
+
+ additional_manifest_fragments =
+ [ "//third_party/fuchsia-sdk/sdk/pkg/vulkan/client.shard.cml" ]
}
}
diff --git a/chromium/components/viz/OWNERS b/chromium/components/viz/OWNERS
index ee2085c35b7..d5881ea1a6b 100644
--- a/chromium/components/viz/OWNERS
+++ b/chromium/components/viz/OWNERS
@@ -7,10 +7,8 @@
# display / resources / quads / passes
vmpstr@chromium.org
-weiliangc@chromium.org
# renderers (GL/Skia/Software)
-weiliangc@chromium.org
rjkroege@chromium.org
ccameron@chromium.org
penghuang@chromium.org
diff --git a/chromium/components/viz/README.md b/chromium/components/viz/README.md
index d6a63a63702..1170d457693 100644
--- a/chromium/components/viz/README.md
+++ b/chromium/components/viz/README.md
@@ -131,13 +131,6 @@ Code here supports presentation of the backing store drawn by the display
compositor (typically thought of as SwapBuffers), as well as the use of
overlays.
-The source code is split into two build targets,
-``components/viz/service:service`` and
-``components/viz/service:gpu_service_dependencies``. The latter is
-code that requires being run in the gpu process, thus could not work
-if the viz service is located elsewhere. This is forward-looking code
-as the viz service is moving into the gpu process always.
-
| Can depend on: |
|:--------------------------------------|
| viz/common/* |
@@ -187,12 +180,6 @@ method.
deallocating) gpu memory buffers, setting up a channel for the command buffer,
etc.
-Similar to ``service/display_embedder`` this is split into two targets in
-the build system. Code that must run in the gpu process is compiled in
-the ``components/viz/service:gpu_service_dependencies`` build target,
-and the rest is compiled in ``components/viz/service:service``. As all
-code moves to the gpu process, these two build targets will merge.
-
| Can depend on: |
|:----------------------|
| viz/common/* |
diff --git a/chromium/components/viz/common/BUILD.gn b/chromium/components/viz/common/BUILD.gn
index 7abb58d2112..9dbc3d66be3 100644
--- a/chromium/components/viz/common/BUILD.gn
+++ b/chromium/components/viz/common/BUILD.gn
@@ -180,12 +180,6 @@ viz_component("common") {
"frame_sinks/delay_based_time_source.h",
"frame_timing_details.h",
"frame_timing_details_map.h",
- "gl_i420_converter.cc",
- "gl_i420_converter.h",
- "gl_nv12_converter.cc",
- "gl_nv12_converter.h",
- "gl_scaler.cc",
- "gl_scaler.h",
"gpu/context_cache_controller.cc",
"gpu/context_cache_controller.h",
"gpu/context_lost_observer.h",
@@ -340,6 +334,10 @@ viz_component("common") {
sources += [
"display/use_layered_window.cc",
"display/use_layered_window.h",
+ "overlay_state/win/overlay_state_aggregator.cc",
+ "overlay_state/win/overlay_state_aggregator.h",
+ "overlay_state/win/overlay_state_service.cc",
+ "overlay_state/win/overlay_state_service.h",
]
deps += [ "//ui/base" ]
@@ -395,18 +393,6 @@ viz_source_set("unit_tests") {
"yuv_readback_unittest.cc",
]
- if (enable_gl_renderer_tests) {
- sources += [
- "gl_i420_converter_pixeltest.cc",
- "gl_i420_converter_unittest.cc",
- "gl_nv12_converter_pixeltest.cc",
- "gl_scaler_overscan_pixeltest.cc",
- "gl_scaler_pixeltest.cc",
- "gl_scaler_shader_pixeltest.cc",
- "gl_scaler_unittest.cc",
- ]
- }
-
if (enable_vulkan) {
sources += [ "gpu/vulkan_in_process_context_provider_unittest.cc" ]
}
@@ -428,6 +414,14 @@ viz_source_set("unit_tests") {
"//ui/gfx/geometry",
"//ui/latency",
]
+
+ if (is_win) {
+ sources += [ "overlay_state/win/overlay_state_service_unittest.cc" ]
+ deps += [
+ "//components/viz/test:test_suite",
+ "//media/mojo/mojom",
+ ]
+ }
}
viz_source_set("perf_tests") {
@@ -446,7 +440,11 @@ viz_source_set("perf_tests") {
if (is_android) {
android_library("common_java") {
- deps = [ "//base:base_java" ]
+ deps = [
+ "//base:base_java",
+ "//base:jni_java",
+ "//build/android:build_java",
+ ]
sources = [
"java/src/org/chromium/components/viz/common/VizSwitches.java",
"java/src/org/chromium/components/viz/common/display/DeJellyUtils.java",
diff --git a/chromium/components/viz/common/DEPS b/chromium/components/viz/common/DEPS
index bff0504c2df..398e9db0ce5 100644
--- a/chromium/components/viz/common/DEPS
+++ b/chromium/components/viz/common/DEPS
@@ -42,5 +42,5 @@ specific_include_rules = {
"bitmap_allocation.cc" : [
# Only used to pass Mojo handles, not to communicate with the viz service.
"+mojo/public/cpp/base/shared_memory_utils.h",
- ],
+ ]
}
diff --git a/chromium/components/viz/common/display/renderer_settings.h b/chromium/components/viz/common/display/renderer_settings.h
index 8b0b5eda59c..bc48a50a766 100644
--- a/chromium/components/viz/common/display/renderer_settings.h
+++ b/chromium/components/viz/common/display/renderer_settings.h
@@ -30,7 +30,6 @@ class VIZ_COMMON_EXPORT RendererSettings {
bool partial_swap_enabled = false;
bool should_clear_root_render_pass = true;
bool release_overlay_resources_after_gpu_query = false;
- bool use_skia_renderer = true;
bool dont_round_texture_sizes_for_pixel_tests = false;
int highp_threshold_min = 0;
bool auto_resize_output_surface = true;
diff --git a/chromium/components/viz/common/features.cc b/chromium/components/viz/common/features.cc
index fa5f838ac37..808900f9bc9 100644
--- a/chromium/components/viz/common/features.cc
+++ b/chromium/components/viz/common/features.cc
@@ -37,12 +37,13 @@ namespace features {
const base::Feature kAdpf{"Adpf", base::FEATURE_DISABLED_BY_DEFAULT};
// Target duration used for power hint on Android.
+// `0` indicates use hard coded default.
const base::FeatureParam<int> kAdpfTargetDurationMs{&kAdpf,
- "AdpfTargetDurationMs", 12};
+ "AdpfTargetDurationMs", 0};
const base::Feature kEnableOverlayPrioritization {
"EnableOverlayPrioritization",
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
base::FEATURE_ENABLED_BY_DEFAULT
#else
base::FEATURE_DISABLED_BY_DEFAULT
@@ -68,10 +69,6 @@ const base::Feature kVideoDetectorIgnoreNonVideos{
const base::Feature kSimpleFrameRateThrottling{
"SimpleFrameRateThrottling", base::FEATURE_DISABLED_BY_DEFAULT};
-// Use the SkiaRenderer.
-const base::Feature kUseSkiaRenderer{"UseSkiaRenderer",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
// Kill-switch to disable de-jelly, even if flags/properties indicate it should
// be enabled.
const base::Feature kDisableDeJelly{"DisableDeJelly",
@@ -84,10 +81,6 @@ const base::Feature kDynamicColorGamut{"DynamicColorGamut",
base::FEATURE_DISABLED_BY_DEFAULT};
#endif
-// Uses glClear to composite solid color quads whenever possible.
-const base::Feature kFastSolidColorDraw{"FastSolidColorDraw",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
// Submit CompositorFrame from SynchronousLayerTreeFrameSink directly to viz in
// WebView.
const base::Feature kVizFrameSubmissionForWebView{
@@ -190,15 +183,13 @@ bool IsAdpfEnabled() {
return base::FeatureList::IsEnabled(kAdpf);
}
-bool IsClipPrewalkDamageEnabled() {
- static constexpr base::Feature kClipPrewalkDamage{
- "ClipPrewalkDamage", base::FEATURE_ENABLED_BY_DEFAULT};
-
- return base::FeatureList::IsEnabled(kClipPrewalkDamage);
-}
-
bool IsOverlayPrioritizationEnabled() {
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // DelegatedCompositing in Lacros makes this feature a no-op.
+ return false;
+#else
return base::FeatureList::IsEnabled(kEnableOverlayPrioritization);
+#endif
}
bool IsDelegatedCompositingEnabled() {
@@ -218,11 +209,6 @@ bool IsSimpleFrameRateThrottlingEnabled() {
return base::FeatureList::IsEnabled(kSimpleFrameRateThrottling);
}
-bool IsUsingSkiaRenderer() {
- return base::FeatureList::IsEnabled(kUseSkiaRenderer) ||
- features::IsUsingVulkan();
-}
-
#if BUILDFLAG(IS_ANDROID)
bool IsDynamicColorGamutEnabled() {
if (viz::AlwaysUseWideColorGamut())
@@ -234,10 +220,6 @@ bool IsDynamicColorGamutEnabled() {
}
#endif
-bool IsUsingFastPathForSolidColorQuad() {
- return base::FeatureList::IsEnabled(kFastSolidColorDraw);
-}
-
bool IsUsingVizFrameSubmissionForWebView() {
return base::FeatureList::IsEnabled(kVizFrameSubmissionForWebView);
}
@@ -290,8 +272,8 @@ bool ShouldUsePlatformDelegatedInk() {
return base::FeatureList::IsEnabled(kUsePlatformDelegatedInk);
}
-#if BUILDFLAG(IS_ANDROID)
bool UseSurfaceLayerForVideo() {
+#if BUILDFLAG(IS_ANDROID)
// SurfaceLayer video should work fine with new heuristic.
if (base::FeatureList::IsEnabled(kWebViewNewInvalidateHeuristic))
return true;
@@ -301,8 +283,12 @@ bool UseSurfaceLayerForVideo() {
return true;
}
return base::FeatureList::IsEnabled(kUseSurfaceLayerForVideoDefault);
+#else
+ return true;
+#endif
}
+#if BUILDFLAG(IS_ANDROID)
bool UseRealVideoColorSpaceForDisplay() {
// We need Android S for proper color space support in SurfaceControl.
if (base::android::BuildInfo::GetInstance()->sdk_int() <
diff --git a/chromium/components/viz/common/features.h b/chromium/components/viz/common/features.h
index 139f9430c10..aab8f02e427 100644
--- a/chromium/components/viz/common/features.h
+++ b/chromium/components/viz/common/features.h
@@ -22,7 +22,6 @@ namespace features {
VIZ_COMMON_EXPORT extern const base::Feature kAdpf;
VIZ_COMMON_EXPORT extern const base::FeatureParam<int> kAdpfTargetDurationMs;
VIZ_COMMON_EXPORT extern const base::Feature kEnableOverlayPrioritization;
-VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRenderer;
VIZ_COMMON_EXPORT extern const base::Feature kDelegatedCompositing;
VIZ_COMMON_EXPORT extern const base::Feature kRecordSkPicture;
VIZ_COMMON_EXPORT extern const base::Feature kDisableDeJelly;
@@ -32,7 +31,6 @@ VIZ_COMMON_EXPORT extern const base::Feature kVideoDetectorIgnoreNonVideos;
#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT extern const base::Feature kDynamicColorGamut;
#endif
-VIZ_COMMON_EXPORT extern const base::Feature kFastSolidColorDraw;
VIZ_COMMON_EXPORT extern const base::Feature kVizFrameSubmissionForWebView;
VIZ_COMMON_EXPORT extern const base::Feature kUsePreferredIntervalForVideo;
VIZ_COMMON_EXPORT extern const base::Feature kUseRealBuffersForPageFlipTest;
@@ -69,7 +67,6 @@ VIZ_COMMON_EXPORT extern const char kPredictorLinear2[];
VIZ_COMMON_EXPORT extern const char kPredictorLsq[];
VIZ_COMMON_EXPORT bool IsAdpfEnabled();
-VIZ_COMMON_EXPORT bool IsClipPrewalkDamageEnabled();
VIZ_COMMON_EXPORT bool IsSimpleFrameRateThrottlingEnabled();
#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT bool IsDynamicColorGamutEnabled();
@@ -77,8 +74,6 @@ VIZ_COMMON_EXPORT bool IsDynamicColorGamutEnabled();
VIZ_COMMON_EXPORT bool IsOverlayPrioritizationEnabled();
VIZ_COMMON_EXPORT bool IsDelegatedCompositingEnabled();
VIZ_COMMON_EXPORT bool IsSyncWindowDestructionEnabled();
-VIZ_COMMON_EXPORT bool IsUsingFastPathForSolidColorQuad();
-VIZ_COMMON_EXPORT bool IsUsingSkiaRenderer();
VIZ_COMMON_EXPORT bool IsUsingVizFrameSubmissionForWebView();
VIZ_COMMON_EXPORT bool IsUsingPreferredIntervalForVideo();
VIZ_COMMON_EXPORT bool ShouldUseRealBuffersForPageFlipTest();
@@ -89,8 +84,8 @@ VIZ_COMMON_EXPORT bool ShouldUseSetPresentDuration();
VIZ_COMMON_EXPORT absl::optional<int> ShouldDrawPredictedInkPoints();
VIZ_COMMON_EXPORT std::string InkPredictor();
VIZ_COMMON_EXPORT bool ShouldUsePlatformDelegatedInk();
-#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT bool UseSurfaceLayerForVideo();
+#if BUILDFLAG(IS_ANDROID)
VIZ_COMMON_EXPORT bool UseRealVideoColorSpaceForDisplay();
#endif
VIZ_COMMON_EXPORT bool IsSurfaceSyncThrottling();
diff --git a/chromium/components/viz/common/frame_sinks/README.md b/chromium/components/viz/common/frame_sinks/README.md
index fc04942b7cf..f134b4e142e 100644
--- a/chromium/components/viz/common/frame_sinks/README.md
+++ b/chromium/components/viz/common/frame_sinks/README.md
@@ -56,8 +56,8 @@ properties:
Note that all coordinates are constrained to be integer values, to avoid
introducing alignment, rounding or other "fuzz" issues.
- * Result format: An RGBA-interleaved bitmap (SkBitmap) or I420 Y+U+V image
- planes.
+ * Result format: An RGBA-interleaved bitmap (SkBitmap), I420 Y+U+V image
+ planes, or NV12 Y+UV image planes.
For efficient video capture, the above are used as follows: An issuer of
CopyOutputRequests "locks into" a target area within the Surface (usually the
diff --git a/chromium/components/viz/common/frame_sinks/blit_request.cc b/chromium/components/viz/common/frame_sinks/blit_request.cc
index 29bbb2d2fb5..b55f2a216fd 100644
--- a/chromium/components/viz/common/frame_sinks/blit_request.cc
+++ b/chromium/components/viz/common/frame_sinks/blit_request.cc
@@ -31,10 +31,14 @@ std::string BlendBitmap::ToString() const {
BlitRequest::BlitRequest(
const gfx::Point& destination_region_offset,
+ LetterboxingBehavior letterboxing_behavior,
const std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes>&
- mailboxes)
+ mailboxes,
+ bool populates_gpu_memory_buffer)
: destination_region_offset_(destination_region_offset),
- mailboxes_(mailboxes) {}
+ letterboxing_behavior_(letterboxing_behavior),
+ mailboxes_(mailboxes),
+ populates_gpu_memory_buffer_(populates_gpu_memory_buffer) {}
BlitRequest::BlitRequest(BlitRequest&& other) = default;
BlitRequest& BlitRequest::operator=(BlitRequest&& other) = default;
@@ -42,9 +46,10 @@ BlitRequest& BlitRequest::operator=(BlitRequest&& other) = default;
BlitRequest::~BlitRequest() = default;
std::string BlitRequest::ToString() const {
- return base::StringPrintf("blit to %s, blend %u bitmaps",
+ return base::StringPrintf("blit to %s, blend %u bitmaps, populates GMB? %d",
destination_region_offset_.ToString().c_str(),
- static_cast<uint32_t>(blend_bitmaps_.size()));
+ static_cast<uint32_t>(blend_bitmaps_.size()),
+ populates_gpu_memory_buffer_);
}
} // namespace viz
diff --git a/chromium/components/viz/common/frame_sinks/blit_request.h b/chromium/components/viz/common/frame_sinks/blit_request.h
index b236231c611..ee4656b2332 100644
--- a/chromium/components/viz/common/frame_sinks/blit_request.h
+++ b/chromium/components/viz/common/frame_sinks/blit_request.h
@@ -53,6 +53,16 @@ class VIZ_COMMON_EXPORT BlendBitmap {
sk_sp<SkImage> image_;
};
+// Enum used to specify letteboxing behavior for a BlitRequest.
+enum class LetterboxingBehavior {
+ // No letterboxing is needed - only the destination region will be written
+ // into by the handler of CopyOutputRequest.
+ kDoNotLetterbox,
+ // Letterboxing is needed - everything outside of the destination region
+ // will be filled with black by the handler of CopyOutputRequest.
+ kLetterbox
+};
+
// Structure describing a blit operation that can be appended to
// `CopyOutputRequest` if the callers want to place the results of the operation
// in textures that they own.
@@ -60,8 +70,10 @@ class VIZ_COMMON_EXPORT BlitRequest {
public:
explicit BlitRequest(
const gfx::Point& destination_region_offset,
+ LetterboxingBehavior letterboxing_behavior,
const std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes>&
- mailboxes);
+ mailboxes,
+ bool populates_gpu_memory_buffer);
BlitRequest(BlitRequest&& other);
BlitRequest& operator=(BlitRequest&& other);
@@ -74,6 +86,10 @@ class VIZ_COMMON_EXPORT BlitRequest {
return destination_region_offset_;
}
+ LetterboxingBehavior letterboxing_behavior() const {
+ return letterboxing_behavior_;
+ }
+
const std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes>&
mailboxes() const {
return mailboxes_;
@@ -84,6 +100,10 @@ class VIZ_COMMON_EXPORT BlitRequest {
return mailboxes_[i];
}
+ bool populates_gpu_memory_buffer() const {
+ return populates_gpu_memory_buffer_;
+ }
+
// Appends a new `BlendBitmap` request to this blit request.
// |source_region| is expressed in |image|'s coordinate system
// (i.e. 0,0 width x height rectangle). |destination_region| is expressed
@@ -106,12 +126,20 @@ class VIZ_COMMON_EXPORT BlitRequest {
// images.
gfx::Point destination_region_offset_;
+ // Specifies the letterboxing behavior of this request.
+ LetterboxingBehavior letterboxing_behavior_;
+
// Mailboxes with planes that will be populated.
// The textures can (but don't have to be) backed by
// a GpuMemoryBuffer. The pixel format of the request determines
// how many planes need to be present.
std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes> mailboxes_;
+ // True if `mailboxes_` describe shared images that have been created from
+ // a GpuMemoryBuffer. In this case, the CopyOutputResult needs to be sent out
+ // only after it's safe to map the GpuMemoryBuffer to system memory.
+ bool populates_gpu_memory_buffer_;
+
// Collection of bitmaps that will be blended onto the textures.
// They will be blended in order (so if i < j, bitmap at offset i will
// be blended before bitmap at offset j), using SrcOver blend mode.
diff --git a/chromium/components/viz/common/frame_sinks/copy_output_request.cc b/chromium/components/viz/common/frame_sinks/copy_output_request.cc
index 648a6fa7f0a..63f2ff3fd1f 100644
--- a/chromium/components/viz/common/frame_sinks/copy_output_request.cc
+++ b/chromium/components/viz/common/frame_sinks/copy_output_request.cc
@@ -107,6 +107,7 @@ void CopyOutputRequest::set_blit_request(BlitRequest blit_request) {
DCHECK(!blit_request_);
DCHECK_EQ(result_destination(), ResultDestination::kNativeTextures);
DCHECK_EQ(result_format(), ResultFormat::NV12_PLANES);
+ DCHECK(has_result_selection());
// Destination region must start at an even offset for NV12 results:
DCHECK_EQ(blit_request.destination_region_offset().x() % 2, 0);
diff --git a/chromium/components/viz/common/frame_sinks/copy_output_request.h b/chromium/components/viz/common/frame_sinks/copy_output_request.h
index fa9a5ddd42a..28fef1f9b69 100644
--- a/chromium/components/viz/common/frame_sinks/copy_output_request.h
+++ b/chromium/components/viz/common/frame_sinks/copy_output_request.h
@@ -116,12 +116,14 @@ class VIZ_COMMON_EXPORT CopyOutputRequest {
// Optionally specify that only a portion of the result be generated. The
// selection rect will be clamped to the result bounds, which always starts at
// 0,0 and spans the post-scaling size of the copy area (see set_area()
- // above). Only RGBA format supports odd-sized result selection.
+ // above). Only RGBA format supports odd-sized result selection. Can only be
+ // called before blit request was set on the copy request.
void set_result_selection(const gfx::Rect& selection) {
DCHECK(result_format_ == ResultFormat::RGBA ||
(selection.width() % 2 == 0 && selection.height() % 2 == 0))
<< "CopyOutputRequest supports odd-sized result_selection() only for "
"RGBA!";
+ DCHECK(!has_blit_request());
result_selection_ = selection;
}
bool has_result_selection() const { return result_selection_.has_value(); }
@@ -129,7 +131,15 @@ class VIZ_COMMON_EXPORT CopyOutputRequest {
// Requests that the region copied by the CopyOutputRequest be blitted into
// the caller's textures. Can be called only for CopyOutputRequests that
- // target native textures.
+ // target native textures. Requires that result selection was set, in which
+ // case the caller's textures will be populated with the results of the
+ // copy request. The region in the caller's textures that will be populated
+ // is specified by `gfx::Rect(blit_request.destination_region_offset(),
+ // result_selection().size())`. If blit request is configured to perform
+ // letterboxing, all contents outside of that region will be overwritten with
+ // black, otherwise they will be unchanged. If the copy request's result would
+ // be smaller than `result_selection().size()`, the request will fail (i.e.
+ // empty result will be sent).
void set_blit_request(BlitRequest blit_request);
bool has_blit_request() const { return blit_request_.has_value(); }
const BlitRequest& blit_request() const { return *blit_request_; }
diff --git a/chromium/components/viz/common/gl_i420_converter.cc b/chromium/components/viz/common/gl_i420_converter.cc
deleted file mode 100644
index c00e202c351..00000000000
--- a/chromium/components/viz/common/gl_i420_converter.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_i420_converter.h"
-
-#include <utility>
-
-#include "components/viz/common/gpu/context_provider.h"
-
-namespace viz {
-
-GLI420Converter::GLI420Converter(ContextProvider* context_provider)
- : GLI420Converter(context_provider, true) {
- DCHECK(context_provider_);
-}
-
-GLI420Converter::GLI420Converter(ContextProvider* context_provider,
- bool allow_mrt_path)
- : context_provider_(context_provider),
- step1_(context_provider_),
- step2_(context_provider_) {
- DCHECK(context_provider_);
- context_provider_->AddObserver(this);
- if (!allow_mrt_path || step1_.GetMaxDrawBuffersSupported() < 2) {
- step3_ = std::make_unique<GLScaler>(context_provider_);
- step4_ = std::make_unique<GLScaler>(context_provider_);
- }
-}
-
-GLI420Converter::~GLI420Converter() {
- OnContextLost(); // Free context-related resources.
-}
-
-bool GLI420Converter::Configure(const Parameters& params) {
- Parameters step1_params = params;
- if (!step1_params.output_color_space.IsValid()) {
- step1_params.output_color_space = gfx::ColorSpace::CreateREC709();
- }
-
- // Configure the "step 1" scaler.
- if (is_using_mrt_path()) {
- step1_params.export_format = Parameters::ExportFormat::NV61;
- DCHECK_EQ(step1_params.swizzle[0], params.swizzle[0]);
- step1_params.swizzle[1] = GL_RGBA; // Don't swizzle 2nd rendering target.
- } else {
- step1_params.export_format = Parameters::ExportFormat::INTERLEAVED_QUADS;
- step1_params.swizzle[0] = GL_RGBA; // Will swizzle in steps 2-4.
- }
- if (!step1_.Configure(step1_params)) {
- return false;
- }
-
- // Configure the "step 2" scaler (and steps 3 and 4 for the non-MRT path) that
- // further transform the output from the "step 1" scaler to produce the final
- // outputs.
- Parameters step2_params;
- step2_params.scale_to = gfx::Vector2d(1, 1);
- step2_params.source_color_space = step1_params.output_color_space;
- step2_params.output_color_space = step1_params.output_color_space;
- // Use FAST quality, a single bilinear pass, because there will either be no
- // scaling or exactly 50% scaling.
- step2_params.quality = Parameters::Quality::FAST;
- step2_params.swizzle[0] = params.swizzle[0];
- if (is_using_mrt_path()) {
- // NV61 provides half-width and full-height U/V. I420 U/V planes are
- // half-width and half-height. So, scale Y by 50%.
- step2_params.scale_from = gfx::Vector2d(1, 2);
- step2_params.export_format =
- Parameters::ExportFormat::DEINTERLEAVE_PAIRWISE;
- step2_params.swizzle[1] = step2_params.swizzle[0];
- if (!step2_.Configure(step2_params)) {
- return false;
- }
- } else {
- // Extract a full-size Y plane from the interleaved YUVA from step 1.
- step2_params.scale_from = gfx::Vector2d(1, 1);
- step2_params.export_format = Parameters::ExportFormat::CHANNEL_0;
- if (!step2_.Configure(step2_params)) {
- return false;
- }
- // Extract half-size U/V planes from the interleaved YUVA from step 1.
- step2_params.scale_from = gfx::Vector2d(2, 2);
- step2_params.export_format = Parameters::ExportFormat::CHANNEL_1;
- if (!step3_->Configure(step2_params)) {
- return false;
- }
- step2_params.export_format = Parameters::ExportFormat::CHANNEL_2;
- if (!step4_->Configure(step2_params)) {
- return false;
- }
- }
-
- params_ = params;
- return true;
-}
-
-bool GLI420Converter::Convert(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- const gfx::Rect& output_rect,
- const GLuint yuv_textures[3]) {
- DCHECK_EQ(output_rect.x() % 8, 0);
- DCHECK_EQ(output_rect.width() % 8, 0);
- DCHECK_EQ(output_rect.y() % 2, 0);
- DCHECK_EQ(output_rect.height() % 2, 0);
-
- if (!context_provider_) {
- return false;
- }
-
- if (is_using_mrt_path()) {
- const gfx::Rect luma_output_rect(output_rect.x() / 4, output_rect.y(),
- output_rect.width() / 4,
- output_rect.height());
- EnsureIntermediateTextureDefined(luma_output_rect.size());
- const gfx::Rect chroma_output_rect(
- gfx::Size(luma_output_rect.width() / 2, luma_output_rect.height() / 2));
- return (step1_.ScaleToMultipleOutputs(
- src_texture, src_texture_size, src_offset, yuv_textures[0],
- intermediate_texture_, luma_output_rect) &&
- step2_.ScaleToMultipleOutputs(intermediate_texture_,
- intermediate_texture_size_,
- gfx::Vector2d(), yuv_textures[1],
- yuv_textures[2], chroma_output_rect));
- }
-
- // Non-MRT path:
- EnsureIntermediateTextureDefined(output_rect.size());
- const gfx::Rect luma_output_rect(0, 0, output_rect.width() / 4,
- output_rect.height());
- const gfx::Rect chroma_output_rect(0, 0, luma_output_rect.width() / 2,
- luma_output_rect.height() / 2);
- return (step1_.Scale(src_texture, src_texture_size, src_offset,
- intermediate_texture_, output_rect) &&
- step2_.Scale(intermediate_texture_, intermediate_texture_size_,
- gfx::Vector2d(), yuv_textures[0], luma_output_rect) &&
- step3_->Scale(intermediate_texture_, intermediate_texture_size_,
- gfx::Vector2d(), yuv_textures[1], chroma_output_rect) &&
- step4_->Scale(intermediate_texture_, intermediate_texture_size_,
- gfx::Vector2d(), yuv_textures[2], chroma_output_rect));
-}
-
-// static
-gfx::Rect GLI420Converter::ToAlignedRect(const gfx::Rect& rect) {
- // Origin coordinates: FLOOR(...)
- const int aligned_x =
- ((rect.x() < 0) ? ((rect.x() - 7) / 8) : (rect.x() / 8)) * 8;
- const int aligned_y =
- ((rect.y() < 0) ? ((rect.y() - 1) / 2) : (rect.y() / 2)) * 2;
- // Span coordinates: CEIL(...)
- const int aligned_right =
- ((rect.right() < 0) ? (rect.right() / 8) : ((rect.right() + 7) / 8)) * 8;
- const int aligned_bottom =
- ((rect.bottom() < 0) ? (rect.bottom() / 2) : ((rect.bottom() + 1) / 2)) *
- 2;
- return gfx::Rect(aligned_x, aligned_y, aligned_right - aligned_x,
- aligned_bottom - aligned_y);
-}
-
-// static
-bool GLI420Converter::ParametersAreEquivalent(const Parameters& a,
- const Parameters& b) {
- const auto Resolve = [](Parameters params) {
- // Per header comments, if an invalid output_color_space is specified, use
- // REC709.
- if (!params.output_color_space.IsValid()) {
- params.output_color_space = gfx::ColorSpace::CreateREC709();
- }
- // Both of these fields are overwritten, in Configure(), whether the MRT
- // path is going to be used or not. So, for the purposes of "equivalence,"
- // just set these like the MRT path would.
- params.export_format = Parameters::ExportFormat::NV61;
- params.swizzle[1] = GL_RGBA;
- return params;
- };
- return GLScaler::ParametersAreEquivalent(Resolve(a), Resolve(b));
-}
-
-void GLI420Converter::EnsureIntermediateTextureDefined(
- const gfx::Size& required) {
- if (intermediate_texture_size_ == required) {
- return;
- }
- auto* const gl = context_provider_->ContextGL();
- if (intermediate_texture_ == 0) {
- gl->GenTextures(1, &intermediate_texture_);
- }
- gl->BindTexture(GL_TEXTURE_2D, intermediate_texture_);
- gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, required.width(), required.height(),
- 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- intermediate_texture_size_ = required;
-}
-
-void GLI420Converter::OnContextLost() {
- if (intermediate_texture_ != 0) {
- if (auto* gl = context_provider_->ContextGL()) {
- gl->DeleteTextures(1, &intermediate_texture_);
- }
- intermediate_texture_ = 0;
- intermediate_texture_size_ = gfx::Size();
- }
- if (context_provider_) {
- context_provider_->RemoveObserver(this);
- context_provider_ = nullptr;
- }
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_i420_converter.h b/chromium/components/viz/common/gl_i420_converter.h
deleted file mode 100644
index 6792ca8fdc8..00000000000
--- a/chromium/components/viz/common/gl_i420_converter.h
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_COMMON_GL_I420_CONVERTER_H_
-#define COMPONENTS_VIZ_COMMON_GL_I420_CONVERTER_H_
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "components/viz/common/gl_scaler.h"
-#include "components/viz/common/gpu/context_lost_observer.h"
-#include "components/viz/common/viz_common_export.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace gfx {
-class Rect;
-class Vector2d;
-} // namespace gfx
-
-namespace viz {
-
-class ContextProvider;
-
-// A convenience wrapper around GLScaler that also reformats the scaler's output
-// from interleaved RGBA to I420 planes. The I420 format consists of three
-// planes of image data: the Y (luma) plane at full size, plus U and V (chroma)
-// planes at half-width and half-height. There are two possible modes of
-// operation (auto-detected at runtime):
-//
-// The faster, multiple rendering target (MRT) path: If the platform supports
-// MRTs (most of the GPUs in use today), scaling and conversion is a two step
-// process:
-//
-// Step 1: Produce NV61 format output, a luma plane and a UV-interleaved
-// image. The luma plane is the same as the desired I420 luma plane. Note,
-// that the UV image is of half-width but not yet half-height.
-//
-// (interleaved quads)
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// |
-// | (luma plane) (chroma, interleaved)
-// | YYYY YYYY UVUV UVUV
-// +---> { YYYY YYYY + UVUV UVUV }
-// YYYY YYYY UVUV UVUV
-// YYYY YYYY UVUV UVUV
-//
-// Step 2: Derives the two I420 chroma planes from the UV-interleaved image
-// from Step 1. This step separates the U and V pixels into separate planes,
-// and also scales the height by half. This produces the desired I420 chroma
-// planes.
-//
-// (chroma, interleaved) (two chroma planes)
-// UVUV UVUV
-// UVUV UVUV --> { UUUU + VVVV }
-// UVUV UVUV UUUU VVVV
-// UVUV UVUV
-//
-// The non-MRT path: For platforms that can only render to a single target at a
-// time. This first scales the source to its final size and color-converts,
-// transforming an RGBA input into a YUVA output. Then, it scans the YUVA image
-// three times to generate each of the Y+U+V planes.
-//
-// Texture packing: OpenGLES2 treats all of the input and output textures as
-// RGBA format. See comments for the Convert() method, which explains how the
-// planar image data is packed into GL_RGBA textures, how the output textures
-// should be sized, and why there are alignment requirements when specifying the
-// output rect.
-class VIZ_COMMON_EXPORT GLI420Converter final : public ContextLostObserver {
- public:
- // GLI420Converter uses the exact same parameters as GLScaler.
- using Parameters = GLScaler::Parameters;
-
- explicit GLI420Converter(ContextProvider* context_provider);
-
- GLI420Converter(const GLI420Converter&) = delete;
- GLI420Converter& operator=(const GLI420Converter&) = delete;
-
- ~GLI420Converter() final;
-
- // Returns true if the GL context provides the necessary support for enabling
- // precise color management (see Parameters::enable_precise_color_management).
- bool SupportsPreciseColorManagement() const {
- return step1_.SupportsPreciseColorManagement();
- }
-
- // [Re]Configure the converter with the given |new_params|. Returns true on
- // success, or false on failure. If |new_params| does not specify an
- // |output_color_space|, it will be default to REC709.
- [[nodiscard]] bool Configure(const Parameters& new_params);
-
- // Returns the currently-configured and resolved Parameters. Results are
- // undefined if Configure() has never been called successfully.
- const Parameters& params() const { return params_; }
-
- // Scales a portion of |src_texture|, then format-converts it to three I420
- // planes, placing the results into |yuv_textures| at offset (0, 0). Returns
- // true to indicate success, or false if this GLI420Converter is not valid.
- //
- // |src_texture_size| is the full, allocated size of the |src_texture|. This
- // is required for computing texture coordinate transforms (and only because
- // the OpenGL ES 2.0 API lacks the ability to query this info).
- //
- // |src_offset| is the offset in the source texture corresponding to point
- // (0,0) in the source/output coordinate spaces. This prevents the need for
- // extra texture copies just to re-position the source coordinate system.
- //
- // |aligned_output_rect| selects the region to draw (in the scaled, not the
- // source, coordinate space). This is used to save work in cases where only a
- // portion needs to be re-scaled. Because of the way the planar image data is
- // packed in the output textures, the output rect's coordinates must be
- // aligned (see ToAlignedRect() below).
- //
- // The |yuv_textures| are packed with planar data, meaning that each RGBA quad
- // contains four pixel values: R is pixel 0, G is pixel 1, and so on. This
- // makes it trivial to read-back the textures from a pixel buffer as a
- // sequence of unsigned bytes. Thus, the output texture for the Y plane should
- // be defined as GL_RGBA and be at least 1/4 the width of that specified in
- // |aligned_output_rect|. Similarly, the output textures for the U and V
- // planes should be defined as GL_RGBA and have at least 1/8 the width and 1/2
- // the height of |aligned_output_rect|.
- //
- // WARNING: The output will always be placed at (0, 0) in the output textures,
- // and not at |aligned_output_rect.origin()|.
- //
- // Note that the |src_texture| will have the min/mag filter set to GL_LINEAR
- // and wrap_s/t set to CLAMP_TO_EDGE in this call.
- bool Convert(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- const gfx::Rect& aligned_output_rect,
- const GLuint yuv_textures[3]);
-
- // Returns the smallest Rect that encloses |rect| and lays on aligned
- // boundaries, as required by the |aligned_output_rect| argument passed to
- // Convert(). The horizontal coordinates will always be a multiple of 8, and
- // the vertical coordinates a multiple of 2.
- static gfx::Rect ToAlignedRect(const gfx::Rect& rect);
-
- // Returns true if configuring a GLI420Converter with either |a| or |b| will
- // produce identical behaviors and results.
- static bool ParametersAreEquivalent(const Parameters& a, const Parameters& b);
-
- private:
- friend class GLI420ConverterPixelTest;
-
- GLI420Converter(ContextProvider* context_provider, bool allow_mrt_path);
-
- bool is_using_mrt_path() const { return !step3_; }
-
- // Creates or re-defines the intermediate texture, to ensure a texture of the
- // given |required| size is defined.
- void EnsureIntermediateTextureDefined(const gfx::Size& required);
-
- // ContextLostObserver implementation.
- void OnContextLost() final;
-
- // The provider of the GL context. This is non-null while the GL context is
- // valid and GLI420Converter is observing for context loss.
- raw_ptr<ContextProvider> context_provider_;
-
- // Scales the source content and produces either:
- // * MRT path: NV61-format output in two textures.
- // * Non-MRT path: YUVA interleaved output in one texture.
- GLScaler step1_;
-
- // Holds the results from executing the first-stage |scaler_|, and is read by
- // the other scalers:
- // * MRT path: This holds the UV-interleaved data (2nd rendering target).
- // * Non-MRT path: The scaled YUVA interleaved data.
- GLuint intermediate_texture_ = 0;
- gfx::Size intermediate_texture_size_;
-
- // Step 2 operation using the |intermediate_texture_| as input:
- // * MRT path: Separates-out the U and V planes (and scales height by half).
- // * Non-MRT path: Extracts the luma plane.
- GLScaler step2_;
-
- // Steps 3 and 4 are used by the non-MRT path only, to extract the two chroma
- // planes from |intermediate_texture_|.
- std::unique_ptr<GLScaler> step3_;
- std::unique_ptr<GLScaler> step4_;
-
- // The Parameters that were provided to the last successful Configure() call.
- Parameters params_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_COMMON_GL_I420_CONVERTER_H_
diff --git a/chromium/components/viz/common/gl_i420_converter_pixeltest.cc b/chromium/components/viz/common/gl_i420_converter_pixeltest.cc
deleted file mode 100644
index 1cf61bbd691..00000000000
--- a/chromium/components/viz/common/gl_i420_converter_pixeltest.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_i420_converter.h"
-
-#include <GLES2/gl2ext.h>
-
-#include "cc/test/pixel_test.h"
-#include "cc/test/pixel_test_utils.h"
-#include "components/viz/test/gl_scaler_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace viz {
-
-class GLI420ConverterPixelTest : public cc::PixelTest,
- public GLScalerTestUtil,
- public testing::WithParamInterface<bool> {
- public:
- bool allow_mrt_path() const { return GetParam(); }
- GLI420Converter* converter() const { return converter_.get(); }
-
- GLuint CreateTexture(const gfx::Size& size) {
- return texture_helper_->CreateTexture(size);
- }
-
- GLuint UploadTexture(const SkBitmap& bitmap) {
- return texture_helper_->UploadTexture(bitmap);
- }
-
- SkBitmap DownloadTexture(GLuint texture, const gfx::Size& size) {
- return texture_helper_->DownloadTexture(texture, size);
- }
-
- protected:
- void SetUp() final {
- cc::PixelTest::SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
- converter_.reset(new GLI420Converter(context_provider(), allow_mrt_path()));
- texture_helper_ = std::make_unique<GLScalerTestTextureHelper>(
- context_provider()->ContextGL());
- }
-
- void TearDown() final {
- texture_helper_.reset();
- converter_.reset();
- cc::PixelTest::TearDown();
- }
-
- private:
- std::unique_ptr<GLI420Converter> converter_;
- std::unique_ptr<GLScalerTestTextureHelper> texture_helper_;
-};
-
-// Note: This test is pretty much the same as
-// GLScalerPixelTest.Example_ScaleAndExportForScreenVideoCapture. The goal of
-// this pixel test is to just confirm that everything internal to
-// GLI420Converter has been plumbed-through correctly.
-TEST_P(GLI420ConverterPixelTest, ScaleAndConvert) {
- // These parameters have been chosen based on: 1) overriding defaults, to
- // confirm Parameters plumbing; and 2) typical operation on most platforms
- // (e.g., flipped source textures, the need to swizzle outputs, etc.).
- GLI420Converter::Parameters params;
- params.scale_from = gfx::Vector2d(2160, 1440);
- params.scale_to = gfx::Vector2d(1280, 720);
- params.source_color_space = DefaultRGBColorSpace();
- params.output_color_space = DefaultYUVColorSpace();
- params.enable_precise_color_management =
- converter()->SupportsPreciseColorManagement();
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = true;
- params.flip_output = true;
- params.swizzle[0] = GL_BGRA_EXT; // Swizzle for readback.
- ASSERT_TRUE(converter()->Configure(params));
-
- constexpr gfx::Size kSourceSize = gfx::Size(2160, 1440);
- const GLuint src_texture = UploadTexture(
- CreateVerticallyFlippedBitmap(CreateSMPTETestImage(kSourceSize)));
- constexpr gfx::Rect kOutputRect = gfx::Rect(0, 0, 1280, 720);
- ASSERT_EQ(kOutputRect, GLI420Converter::ToAlignedRect(kOutputRect));
- SkBitmap expected = CreateSMPTETestImage(kOutputRect.size());
- ConvertRGBABitmapToYUV(&expected);
-
- // While the output size is 1280x720, the packing of 4 pixels into one RGBA
- // quad means that the texture width must be divided by 4 (for the Y
- // plane). Then, the other two planes are half the size of the Y plane in both
- // dimensions.
- const gfx::Size y_plane_size(kOutputRect.width() / 4, kOutputRect.height());
- const gfx::Size chroma_plane_size(y_plane_size.width() / 2,
- y_plane_size.height() / 2);
- const GLuint yuv_textures[3] = {CreateTexture(y_plane_size),
- CreateTexture(chroma_plane_size),
- CreateTexture(chroma_plane_size)};
-
- ASSERT_TRUE(converter()->Convert(src_texture, kSourceSize, gfx::Vector2d(),
- kOutputRect, yuv_textures));
-
- // Download the textures, and unpack them into an interleaved YUV bitmap, for
- // comparison against the |expected| rendition.
- SkBitmap actual = AllocateRGBABitmap(kOutputRect.size());
- actual.eraseColor(SkColorSetARGB(0xff, 0x00, 0x80, 0x80));
- SkBitmap y_plane = DownloadTexture(yuv_textures[0], y_plane_size);
- SwizzleBitmap(&y_plane);
- UnpackPlanarBitmap(y_plane, 0, &actual);
- SkBitmap u_plane = DownloadTexture(yuv_textures[1], chroma_plane_size);
- SwizzleBitmap(&u_plane);
- UnpackPlanarBitmap(u_plane, 1, &actual);
- SkBitmap v_plane = DownloadTexture(yuv_textures[2], chroma_plane_size);
- SwizzleBitmap(&v_plane);
- UnpackPlanarBitmap(v_plane, 2, &actual);
-
- // Provide generous error limits to account for the chroma subsampling in the
- // |actual| result when compared to the perfect |expected| rendition.
- constexpr float kAvgAbsoluteErrorLimit = 16.f;
- constexpr int kMaxAbsoluteErrorLimit = 0x80;
- EXPECT_TRUE(cc::FuzzyPixelComparator(false, 100.f, 0.f,
- kAvgAbsoluteErrorLimit,
- kMaxAbsoluteErrorLimit, 0)
- .Compare(expected, actual))
- << "\nActual: " << cc::GetPNGDataUrl(actual)
- << "\nExpected: " << cc::GetPNGDataUrl(expected);
-}
-
-// Run the tests twice, once disallowing use of the MRT path, and once allowing
-// its use (auto-detecting whether the current platform supports it).
-INSTANTIATE_TEST_SUITE_P(All, GLI420ConverterPixelTest, testing::Bool());
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_i420_converter_unittest.cc b/chromium/components/viz/common/gl_i420_converter_unittest.cc
deleted file mode 100644
index 9fd42188e99..00000000000
--- a/chromium/components/viz/common/gl_i420_converter_unittest.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_i420_converter.h"
-
-#include <string>
-
-#include "base/strings/stringprintf.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace viz {
-namespace {
-
-// Syntactic convenience: It's clearer to express the tests in terms of
-// left+top+right+bottom coordinates, rather than gfx::Rect's x+y+width+height
-// scheme.
-SkIRect ToAlignedRect(const SkIRect& rect) {
- const gfx::Rect& result = GLI420Converter::ToAlignedRect(
- gfx::Rect(rect.fLeft, rect.fTop, rect.fRight - rect.fLeft,
- rect.fBottom - rect.fTop));
- return SkIRect{result.x(), result.y(), result.right(), result.bottom()};
-}
-
-// Logging convenience.
-std::string ToString(const SkIRect& rect) {
- return base::StringPrintf("%d,%d~%d%d", rect.fLeft, rect.fTop, rect.fRight,
- rect.fBottom);
-}
-
-TEST(GLI420ConverterTest, AlignsOutputRects) {
- struct {
- SkIRect expected;
- SkIRect input;
- } kTestCases[] = {
- {SkIRect{0, 0, 0, 0}, SkIRect{0, 0, 0, 0}},
-
- {SkIRect{-16, 0, 16, 4}, SkIRect{-9, 0, 16, 4}},
- {SkIRect{-8, 0, 16, 4}, SkIRect{-8, 0, 16, 4}},
- {SkIRect{-8, 0, 16, 4}, SkIRect{-7, 0, 16, 4}},
- {SkIRect{-8, 0, 16, 4}, SkIRect{-1, 0, 16, 4}},
- {SkIRect{0, 0, 16, 4}, SkIRect{0, 0, 16, 4}},
- {SkIRect{0, 0, 16, 4}, SkIRect{1, 0, 16, 4}},
- {SkIRect{0, 0, 16, 4}, SkIRect{7, 0, 16, 4}},
- {SkIRect{8, 0, 16, 4}, SkIRect{8, 0, 16, 4}},
- {SkIRect{8, 0, 16, 4}, SkIRect{9, 0, 16, 4}},
-
- {SkIRect{0, -4, 16, 4}, SkIRect{0, -3, 16, 4}},
- {SkIRect{0, -2, 16, 4}, SkIRect{0, -2, 16, 4}},
- {SkIRect{0, -2, 16, 4}, SkIRect{0, -1, 16, 4}},
- {SkIRect{0, 0, 16, 4}, SkIRect{0, 0, 16, 4}},
- {SkIRect{0, 0, 16, 4}, SkIRect{0, 1, 16, 4}},
- {SkIRect{0, 2, 16, 4}, SkIRect{0, 2, 16, 4}},
- {SkIRect{0, 2, 16, 4}, SkIRect{0, 3, 16, 4}},
-
- {SkIRect{0, 0, 8, 2}, SkIRect{0, 0, 1, 2}},
- {SkIRect{0, 0, 8, 2}, SkIRect{0, 0, 7, 2}},
- {SkIRect{0, 0, 8, 2}, SkIRect{0, 0, 8, 2}},
- {SkIRect{0, 0, 16, 2}, SkIRect{0, 0, 9, 2}},
-
- {SkIRect{0, 0, 8, 2}, SkIRect{0, 0, 8, 1}},
- {SkIRect{0, 0, 8, 2}, SkIRect{0, 0, 8, 2}},
- {SkIRect{0, 0, 8, 4}, SkIRect{0, 0, 8, 3}},
- {SkIRect{0, 0, 8, 4}, SkIRect{0, 0, 8, 4}},
- };
-
- for (const auto& test_case : kTestCases) {
- EXPECT_EQ(test_case.expected, ToAlignedRect(test_case.input))
- << "ToAlignedRect(" << ToString(test_case.input) << ") should be "
- << ToString(test_case.expected);
- }
-}
-
-} // namespace
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_nv12_converter.cc b/chromium/components/viz/common/gl_nv12_converter.cc
deleted file mode 100644
index 2c737130a6b..00000000000
--- a/chromium/components/viz/common/gl_nv12_converter.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_nv12_converter.h"
-
-#include "base/memory/ptr_util.h"
-#include "components/viz/common/gl_i420_converter.h"
-#include "components/viz/common/gpu/context_provider.h"
-
-namespace viz {
-
-// static
-std::unique_ptr<GLNV12Converter> GLNV12Converter::CreateConverterForTest(
- ContextProvider* context_provider,
- bool allow_mrt_path) {
- return base::WrapUnique(
- new GLNV12Converter(context_provider, allow_mrt_path));
-}
-
-GLNV12Converter::GLNV12Converter(ContextProvider* context_provider)
- : GLNV12Converter(context_provider, true) {}
-
-GLNV12Converter::GLNV12Converter(ContextProvider* context_provider,
- bool allow_mrt_path)
- : context_provider_(context_provider),
- step1_(context_provider_),
- step2_(context_provider_) {
- DCHECK(context_provider_);
- context_provider_->AddObserver(this);
- if (!allow_mrt_path || step1_.GetMaxDrawBuffersSupported() < 2) {
- step3_ = std::make_unique<GLScaler>(context_provider_);
- }
-}
-
-GLNV12Converter::~GLNV12Converter() {
- OnContextLost(); // Free context-related resources.
-}
-
-// static
-gfx::Rect GLNV12Converter::ToAlignedRect(const gfx::Rect& rect) {
- // Origin coordinates: FLOOR(...)
- const int aligned_x =
- ((rect.x() < 0) ? ((rect.x() - 3) / 4) : (rect.x() / 4)) * 4;
- const int aligned_y =
- ((rect.y() < 0) ? ((rect.y() - 1) / 2) : (rect.y() / 2)) * 2;
- // Span coordinates: CEIL(...)
- const int aligned_right =
- ((rect.right() < 0) ? (rect.right() / 4) : ((rect.right() + 3) / 4)) * 4;
- const int aligned_bottom =
- ((rect.bottom() < 0) ? (rect.bottom() / 2) : ((rect.bottom() + 1) / 2)) *
- 2;
- return gfx::Rect(aligned_x, aligned_y, aligned_right - aligned_x,
- aligned_bottom - aligned_y);
-}
-
-// static
-bool GLNV12Converter::ParametersAreEquivalent(const Parameters& a,
- const Parameters& b) {
- // Implemented in terms of GLI420Converter:
- return GLI420Converter::ParametersAreEquivalent(a, b);
-}
-
-void GLNV12Converter::EnsureIntermediateTextureDefined(
- const gfx::Size& required) {
- if (intermediate_texture_size_ == required) {
- return;
- }
- auto* const gl = context_provider_->ContextGL();
- if (intermediate_texture_ == 0) {
- gl->GenTextures(1, &intermediate_texture_);
- }
- gl->BindTexture(GL_TEXTURE_2D, intermediate_texture_);
- gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, required.width(), required.height(),
- 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- intermediate_texture_size_ = required;
-}
-
-bool GLNV12Converter::Configure(const Parameters& params) {
- Parameters step1_params = params;
- if (!step1_params.output_color_space.IsValid()) {
- step1_params.output_color_space = gfx::ColorSpace::CreateREC709();
- }
-
- // Configure the "step 1" scaler.
- if (is_using_mrt_path()) {
- step1_params.export_format = Parameters::ExportFormat::NV61;
- DCHECK_EQ(step1_params.swizzle[0], params.swizzle[0]);
- step1_params.swizzle[1] = GL_RGBA; // Don't swizzle 2nd rendering target.
- } else {
- step1_params.export_format = Parameters::ExportFormat::INTERLEAVED_QUADS;
- step1_params.swizzle[0] = GL_RGBA; // Will swizzle in steps 2-3.
- }
- if (!step1_.Configure(step1_params)) {
- return false;
- }
-
- // Configure the "step 2" scaler (and step 3 for the non-MRT path) that
- // further transform the output from the "step 1" scaler to produce the final
- // outputs.
- Parameters step2_params;
- step2_params.scale_to = gfx::Vector2d(1, 1);
- step2_params.source_color_space = step1_params.output_color_space;
- step2_params.output_color_space = step1_params.output_color_space;
- // Use FAST quality, a single bilinear pass, because there will either be no
- // scaling or exactly 50% scaling.
- step2_params.quality = Parameters::Quality::FAST;
- step2_params.swizzle[0] = params.swizzle[0];
- if (is_using_mrt_path()) {
- // NV61 provides half-width and full-height U/V. NV12 UV planes are
- // half-width and half-height. So, scale just the Y by 50%.
- step2_params.scale_from = gfx::Vector2d(1, 2);
- step2_params.export_format = Parameters::ExportFormat::INTERLEAVED_QUADS;
- step2_params.swizzle[1] = step2_params.swizzle[0];
- if (!step2_.Configure(step2_params)) {
- return false;
- }
- } else {
- // Extract a full-size Y plane from the interleaved YUVA from step 1.
- step2_params.scale_from = gfx::Vector2d(1, 1);
- step2_params.export_format = Parameters::ExportFormat::CHANNEL_0;
- if (!step2_.Configure(step2_params)) {
- return false;
- }
- // Extract a half-size UV plane from the interleaved YUVA from step 1.
- // UV_CHANNELS provides half-width and full-height UV plane. NV12 UV planes
- // are half-wifth and half-height. So, scale just the Y by 50%.
- step2_params.scale_from = gfx::Vector2d(1, 2);
- step2_params.export_format = Parameters::ExportFormat::UV_CHANNELS;
- if (!step3_->Configure(step2_params)) {
- return false;
- }
- }
-
- params_ = params;
- return true;
-}
-
-bool GLNV12Converter::Convert(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- const gfx::Rect& aligned_output_rect,
- const GLuint yuv_textures[2]) {
- DCHECK_EQ(aligned_output_rect.x() % 4, 0);
- DCHECK_EQ(aligned_output_rect.width() % 4, 0);
- DCHECK_EQ(aligned_output_rect.y() % 2, 0);
- DCHECK_EQ(aligned_output_rect.height() % 2, 0);
-
- if (!context_provider_) {
- return false;
- }
-
- if (is_using_mrt_path()) {
- const gfx::Rect luma_output_rect(
- aligned_output_rect.x() / 4, aligned_output_rect.y(),
- aligned_output_rect.width() / 4, aligned_output_rect.height());
- EnsureIntermediateTextureDefined(luma_output_rect.size());
- const gfx::Rect chroma_output_rect(
- gfx::Size(luma_output_rect.width(), luma_output_rect.height() / 2));
- return (step1_.ScaleToMultipleOutputs(
- src_texture, src_texture_size, src_offset, yuv_textures[0],
- intermediate_texture_, luma_output_rect) &&
- step2_.Scale(intermediate_texture_, intermediate_texture_size_,
- gfx::Vector2d(), yuv_textures[1], chroma_output_rect));
- }
-
- // Non-MRT path:
- EnsureIntermediateTextureDefined(aligned_output_rect.size());
- const gfx::Rect luma_output_rect(0, 0, aligned_output_rect.width() / 4,
- aligned_output_rect.height());
- const gfx::Rect chroma_output_rect(0, 0, luma_output_rect.width(),
- luma_output_rect.height() / 2);
- return (step1_.Scale(src_texture, src_texture_size, src_offset,
- intermediate_texture_, aligned_output_rect) &&
- step2_.Scale(intermediate_texture_, intermediate_texture_size_,
- gfx::Vector2d(), yuv_textures[0], luma_output_rect) &&
- step3_->Scale(intermediate_texture_, intermediate_texture_size_,
- gfx::Vector2d(), yuv_textures[1], chroma_output_rect));
-}
-
-void GLNV12Converter::OnContextLost() {
- if (intermediate_texture_ != 0) {
- if (auto* gl = context_provider_->ContextGL()) {
- gl->DeleteTextures(1, &intermediate_texture_);
- }
- intermediate_texture_ = 0;
- intermediate_texture_size_ = gfx::Size();
- }
- if (context_provider_) {
- context_provider_->RemoveObserver(this);
- context_provider_ = nullptr;
- }
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_nv12_converter.h b/chromium/components/viz/common/gl_nv12_converter.h
deleted file mode 100644
index 15c6944270f..00000000000
--- a/chromium/components/viz/common/gl_nv12_converter.h
+++ /dev/null
@@ -1,200 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_COMMON_GL_NV12_CONVERTER_H_
-#define COMPONENTS_VIZ_COMMON_GL_NV12_CONVERTER_H_
-
-#include <memory>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "components/viz/common/gl_scaler.h"
-#include "components/viz/common/gpu/context_lost_observer.h"
-#include "components/viz/common/viz_common_export.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace gfx {
-class Rect;
-class Vector2d;
-} // namespace gfx
-
-namespace viz {
-
-class ContextProvider;
-
-// A convenience wrapper around GLScaler that also reformats the scaler's output
-// from interleaved RGBA to NV12 planes. The NV12 format consists of two
-// planes of image data: the Y (luma) plane at full size, plus interleaved UV
-// (chroma) plane at half-width and half-height. There are two possible modes of
-// operation (auto-detected at runtime):
-//
-// The faster, multiple rendering target (MRT) path: If the platform supports
-// MRTs (most of the GPUs in use today), scaling and conversion is a two step
-// process:
-//
-// Step 1: Produce NV61 format output, a luma plane and a UV-interleaved
-// image. The luma plane is the same as the desired NV12 luma plane. Note,
-// that the UV image is of half-width but not yet half-height.
-//
-// (interleaved quads)
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
-// |
-// | (luma plane) (chroma, interleaved)
-// | YYYY YYYY UVUV UVUV
-// +---> { YYYY YYYY + UVUV UVUV }
-// YYYY YYYY UVUV UVUV
-// YYYY YYYY UVUV UVUV
-//
-// Step 2: Downscales the chroma plane.
-//
-// (chroma, interleaved) (chroma, interleaved)
-// UVUV UVUV
-// UVUV UVUV --> UVUV UVUV
-// UVUV UVUV UVUV UVUV
-// UVUV UVUV
-//
-// The non-MRT path: For platforms that can only render to a single target at a
-// time. This first scales the source to its final size and color-converts,
-// transforming an RGBA input into a YUVx output. Then, it scans the YUVA image
-// two times to generate each of the Y+UV planes.
-//
-// Texture packing: OpenGLES2 treats all of the input and output textures as
-// RGBA format. See comments for the Convert() method, which explains how the
-// planar image data is packed into GL_RGBA textures, how the output textures
-// should be sized, and why there are alignment requirements when specifying the
-// output rect.
-class VIZ_COMMON_EXPORT GLNV12Converter final : public ContextLostObserver {
- public:
- // GLNV12Converter uses the exact same parameters as GLScaler.
- using Parameters = GLScaler::Parameters;
-
- explicit GLNV12Converter(ContextProvider* context_provider);
- ~GLNV12Converter() final;
-
- // Returns true if the GL context provides the necessary support for enabling
- // precise color management (see Parameters::enable_precise_color_management).
- bool SupportsPreciseColorManagement() const {
- return step1_.SupportsPreciseColorManagement();
- }
-
- // [Re]Configure the converter with the given |new_params|. Returns true on
- // success, or false on failure. If |new_params| does not specify an
- // |output_color_space|, it will be default to REC709.
- [[nodiscard]] bool Configure(const Parameters& new_params);
-
- // Returns the currently-configured and resolved Parameters. Results are
- // undefined if Configure() has never been called successfully.
- const Parameters& params() const { return params_; }
-
- // Scales a portion of |src_texture|, then format-converts it to two NV12
- // planes, placing the results into |yuv_textures| at offset (0, 0). Returns
- // true to indicate success, or false if this GLNV12Converter is not valid.
- //
- // |src_texture_size| is the full, allocated size of the |src_texture|. This
- // is required for computing texture coordinate transforms (and only because
- // the OpenGL ES 2.0 API lacks the ability to query this info).
- //
- // |src_offset| is the offset in the source texture corresponding to point
- // (0,0) in the source/output coordinate spaces. This prevents the need for
- // extra texture copies just to re-position the source coordinate system.
- //
- // |aligned_output_rect| selects the region to draw (in the scaled, not the
- // source, coordinate space). This is used to save work in cases where only a
- // portion needs to be re-scaled. Because of the way the planar image data is
- // packed in the output textures, the output rect's coordinates must be
- // aligned (see ToAlignedRect() below).
- //
- // The |yuv_textures| are packed with planar data. Depending on the plane,
- // the packing is as follows:
- // - for Y plane, each RGBA quad contains four pixel values: R is pixel 0,
- // G is pixel 1, and so on.
- // - for UV plane, each RGBA quad contains 2 pixel values: RG are UV values
- // for pixel 0, BA are UV values for pixel 1, and so on.
- // This makes it trivial to read-back the textures from a pixel buffer as a
- // sequence of unsigned bytes. Thus, the output texture for the Y plane should
- // be defined as GL_RGBA and be at least 1/4 the width of that specified in
- // |aligned_output_rect|. Similarly, the output texture for the UV plane
- // should be defined as GL_RGBA and have at least 1/4 the width [1]
- // and 1/2 the height [2] of |aligned_output_rect|.
- //
- // [1] 1/4 width = 1/4 // we pack 4 values per pixel
- // * 1/2 // chroma planes are subsampled
- // * 2 // we pack 2 chroma planes
- // * width
- // [2] 1/2 height = 1/2 // chroma planes are subsampled
- // * height
- //
- // WARNING: The output will always be placed at (0, 0) in the output textures,
- // and not at |aligned_output_rect.origin()|.
- //
- // Note that the |src_texture| will have the min/mag filter set to GL_LINEAR
- // and wrap_s/t set to CLAMP_TO_EDGE in this call.
- bool Convert(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- const gfx::Rect& aligned_output_rect,
- const GLuint yuv_textures[2]);
-
- // Returns the smallest Rect that encloses |rect| and lays on aligned
- // boundaries, as required by the |aligned_output_rect| argument passed to
- // Convert(). The horizontal coordinates will always be a multiple of 4, and
- // the vertical coordinates a multiple of 2.
- static gfx::Rect ToAlignedRect(const gfx::Rect& rect);
-
- // Returns true if configuring a GLNV12Converter with either |a| or |b| will
- // produce identical behaviors and results.
- static bool ParametersAreEquivalent(const Parameters& a, const Parameters& b);
-
- static std::unique_ptr<GLNV12Converter> CreateConverterForTest(
- ContextProvider* context_provider,
- bool allow_mrt_path);
-
- private:
- GLNV12Converter(ContextProvider* context_provider, bool allow_mrt_path);
-
- bool is_using_mrt_path() const { return !step3_; }
-
- // Creates or re-defines the intermediate texture, to ensure a texture of the
- // given |required| size is defined.
- void EnsureIntermediateTextureDefined(const gfx::Size& required);
-
- // ContextLostObserver implementation.
- void OnContextLost() final;
-
- // The provider of the GL context. This is non-null while the GL context is
- // valid and GLNV12Converter is observing for context loss.
- raw_ptr<ContextProvider> context_provider_;
-
- // Scales the source content and produces either:
- // * MRT path: NV61-format output in two textures.
- // * Non-MRT path: YUVA interleaved output in one texture.
- GLScaler step1_;
-
- // Holds the results from executing the first-stage |scaler_|, and is read by
- // the other scalers:
- // * MRT path: This holds the UV-interleaved data (2nd rendering target).
- // * Non-MRT path: The scaled YUVA interleaved data.
- GLuint intermediate_texture_ = 0;
- gfx::Size intermediate_texture_size_;
-
- // Step 2 operation using the |intermediate_texture_| as input:
- // * MRT path: Scales the height by half.
- // * Non-MRT path: Extracts the luma plane.
- GLScaler step2_;
-
- // Steps 3 is used by the non-MRT path only, to extract the interleaved chroma
- // planes from |intermediate_texture_|.
- std::unique_ptr<GLScaler> step3_;
-
- // The Parameters that were provided to the last successful Configure() call.
- Parameters params_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_COMMON_GL_NV12_CONVERTER_H_
diff --git a/chromium/components/viz/common/gl_nv12_converter_pixeltest.cc b/chromium/components/viz/common/gl_nv12_converter_pixeltest.cc
deleted file mode 100644
index ad3ec480837..00000000000
--- a/chromium/components/viz/common/gl_nv12_converter_pixeltest.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_nv12_converter.h"
-
-#include <GLES2/gl2ext.h>
-
-#include "cc/test/pixel_test.h"
-#include "cc/test/pixel_test_utils.h"
-#include "components/viz/test/gl_scaler_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-namespace viz {
-
-class GLNV12ConverterPixelTest
- : public cc::PixelTest,
- public GLScalerTestUtil,
- public testing::WithParamInterface<
- std::tuple<bool, bool, gfx::Vector2d, gfx::Vector2d>> {
- public:
- bool allow_mrt_path() const { return std::get<0>(GetParam()); }
- bool is_rgba() const { return std::get<1>(GetParam()); }
- gfx::Vector2d scale_from() const { return std::get<2>(GetParam()); }
- gfx::Vector2d scale_to() const { return std::get<3>(GetParam()); }
-
- GLNV12Converter* converter() const { return converter_.get(); }
-
- GLuint CreateTexture(const gfx::Size& size) {
- return texture_helper_->CreateTexture(size);
- }
-
- GLuint UploadTexture(const SkBitmap& bitmap) {
- return texture_helper_->UploadTexture(bitmap);
- }
-
- SkBitmap DownloadTexture(GLuint texture, const gfx::Size& size) {
- return texture_helper_->DownloadTexture(texture, size);
- }
-
- protected:
- void SetUp() final {
- cc::PixelTest::SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
- converter_ = GLNV12Converter::CreateConverterForTest(context_provider(),
- allow_mrt_path());
- texture_helper_ = std::make_unique<GLScalerTestTextureHelper>(
- context_provider()->ContextGL());
- }
-
- void TearDown() final {
- texture_helper_.reset();
- converter_.reset();
- cc::PixelTest::TearDown();
- }
-
- private:
- std::unique_ptr<GLNV12Converter> converter_;
- std::unique_ptr<GLScalerTestTextureHelper> texture_helper_;
-};
-
-// Note: This test is pretty much the same as
-// GLScalerPixelTest.Example_ScaleAndExportForScreenVideoCapture. The goal of
-// this pixel test is to just confirm that everything internal to
-// GLNV12Converter has been plumbed-through correctly.
-TEST_P(GLNV12ConverterPixelTest, ScaleAndConvert) {
- GLNV12Converter::Parameters params;
- params.scale_from = scale_from();
- params.scale_to = scale_to();
- params.source_color_space = DefaultRGBColorSpace();
- params.output_color_space = DefaultYUVColorSpace();
- params.enable_precise_color_management =
- converter()->SupportsPreciseColorManagement();
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = true;
- params.flip_output = true;
- params.swizzle[0] =
- is_rgba() ? GL_RGBA : GL_BGRA_EXT; // Swizzle for readback.
- ASSERT_TRUE(converter()->Configure(params));
-
- const gfx::Size kSourceSize = gfx::Size(scale_from().x(), scale_from().y());
- const GLuint src_texture = UploadTexture(
- CreateVerticallyFlippedBitmap(CreateSMPTETestImage(kSourceSize)));
- const gfx::Rect kOutputRect = gfx::Rect(0, 0, scale_to().x(), scale_to().y());
- ASSERT_EQ(kOutputRect, GLNV12Converter::ToAlignedRect(kOutputRect));
- SkBitmap expected = CreateSMPTETestImage(kOutputRect.size());
- ConvertRGBABitmapToYUV(&expected);
-
- // While the output size is `kOutputRect.Size()`, the packing of 4 pixels into
- // one RGBA quad means that the texture width must be divided by 4 (for the Y
- // plane). Then, the chroma plane is half the size of the Y plane in both
- // dimensions, but the width is actually double that since we pack 2 values,
- // so `y_plane_size.width() * 1/2 * 2` term is simplified to just
- // `y_plane_size.width()`.
- const gfx::Size y_plane_size(kOutputRect.width() / 4, kOutputRect.height());
- const gfx::Size chroma_plane_size(y_plane_size.width(),
- y_plane_size.height() / 2);
-
- const GLuint yuv_textures[2] = {CreateTexture(y_plane_size),
- CreateTexture(chroma_plane_size)};
-
- ASSERT_TRUE(converter()->Convert(src_texture, kSourceSize, gfx::Vector2d(),
- kOutputRect, yuv_textures));
-
- // Download the textures, and unpack them into an interleaved YUV bitmap, for
- // comparison against the |expected| rendition.
- SkBitmap actual = AllocateRGBABitmap(kOutputRect.size());
- actual.eraseColor(SkColorSetARGB(0xff, 0x00, 0x00, 0x00));
-
- SkBitmap y_plane = DownloadTexture(yuv_textures[0], y_plane_size);
- SkBitmap uv_plane = DownloadTexture(yuv_textures[1], chroma_plane_size);
-
- if (!is_rgba()) {
- // We've asked the converter to produce output in BGRA, & downloaded it to
- // RGBA SkBitmap, so swizzle it.
- SwizzleBitmap(&y_plane);
- SwizzleBitmap(&uv_plane);
- }
-
- UnpackPlanarBitmap(y_plane, 0, &actual);
- UnpackUVBitmap(uv_plane, &actual);
-
- // Provide generous error limits to account for the chroma subsampling in the
- // |actual| result when compared to the perfect |expected| rendition.
- constexpr float kAvgAbsoluteErrorLimit = 16.f;
- constexpr int kMaxAbsoluteErrorLimit = 0x80;
- EXPECT_TRUE(cc::FuzzyPixelComparator(false, 100.f, 0.f,
- kAvgAbsoluteErrorLimit,
- kMaxAbsoluteErrorLimit, 0)
- .Compare(expected, actual))
- << "\nActual: " << cc::GetPNGDataUrl(actual)
- << "\nExpected: " << cc::GetPNGDataUrl(expected);
-}
-
-// Run the tests, first parameter controls whether the MRT path is allowed,
-// the second controls whether the converter will use RGBA format vs BGRA (true
-// for RGBA, i.e. no swizzling done by the converter, false for BGRA, i.e. the
-// converter will swizzle the results when writing to texture).
-// These parameters have been chosen based on: 1) overriding defaults, to
-// confirm Parameters plumbing; and 2) typical operation on most platforms
-// (e.g., flipped source textures, the need to swizzle outputs, etc.). In
-// addition, the `scale_to()` is made to return width that is divisible by 4,
-// but not by 8, to test alignment requirements.
-INSTANTIATE_TEST_SUITE_P(
- All,
- GLNV12ConverterPixelTest,
- testing::Combine(testing::Bool(),
- testing::Bool(),
- testing::Values(gfx::Vector2d(2160, 1440)),
- testing::Values(gfx::Vector2d(1280, 720),
- gfx::Vector2d(900, 600))));
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_scaler.cc b/chromium/components/viz/common/gl_scaler.cc
deleted file mode 100644
index 2393ebc8d09..00000000000
--- a/chromium/components/viz/common/gl_scaler.cc
+++ /dev/null
@@ -1,1661 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_scaler.h"
-
-#include <algorithm>
-#include <array>
-#include <sstream>
-#include <string>
-
-#include "base/logging.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "gpu/GLES2/gl2chromium.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "third_party/skia/include/third_party/skcms/skcms.h"
-#include "ui/gfx/color_transform.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-
-namespace viz {
-
-namespace {
-
-// The code in GLScaler that computes the ScalerStages is greatly simplified by
-// being able to access the X and Y components by index (instead of
-// Vector2d::x() or Vector2d::y()). Thus, define a helper class to represent the
-// relative size as a 2-element std::array and convert to/from Vector2d.
-struct RelativeSize : public std::array<int, 2> {
- using std::array<int, 2>::operator[];
-
- RelativeSize(int width, int height) : std::array<int, 2>{{width, height}} {}
- explicit RelativeSize(const gfx::Vector2d& v)
- : std::array<int, 2>{{v.x(), v.y()}} {}
-
- gfx::Vector2d AsVector2d() const {
- return gfx::Vector2d((*this)[0], (*this)[1]);
- }
-};
-
-std::ostream& operator<<(std::ostream& out, const RelativeSize& size) {
- return (out << size[0] << 'x' << size[1]);
-}
-
-} // namespace
-
-GLScaler::GLScaler(ContextProvider* context_provider)
- : context_provider_(context_provider) {
- if (context_provider_) {
- DCHECK(context_provider_->ContextGL());
- context_provider_->AddObserver(this);
- }
-}
-
-GLScaler::~GLScaler() {
- OnContextLost(); // Ensures destruction in dependency order.
-}
-
-bool GLScaler::SupportsPreciseColorManagement() const {
- if (!context_provider_) {
- return false;
- }
- if (!supports_half_floats_.has_value()) {
- supports_half_floats_ = AreAllGLExtensionsPresent(
- context_provider_->ContextGL(),
- {"GL_EXT_color_buffer_half_float", "GL_OES_texture_half_float_linear"});
- }
- return supports_half_floats_.value();
-}
-
-int GLScaler::GetMaxDrawBuffersSupported() const {
- if (!context_provider_) {
- return 0;
- }
-
- if (max_draw_buffers_ < 0) {
- // Query the GL context for the multiple draw buffers extension and, if
- // present, the actual platform-supported maximum.
- GLES2Interface* const gl = context_provider_->ContextGL();
- DCHECK(gl);
- if (AreAllGLExtensionsPresent(gl, {"GL_EXT_draw_buffers"})) {
- gl->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
- } else {
- // The extension is not present & OpenGL ES 2.0 does not support
- // glDrawBuffers function without it.
- max_draw_buffers_ = 0;
- }
- }
-
- return max_draw_buffers_;
-}
-
-bool GLScaler::Configure(const Parameters& new_params) {
- chain_.reset();
- shader_programs_.clear();
-
- if (!context_provider_) {
- return false;
- }
- GLES2Interface* const gl = context_provider_->ContextGL();
- DCHECK(gl);
-
- params_ = new_params;
-
- // Ensure the client has provided valid scaling vectors.
- if (params_.scale_from.x() == 0 || params_.scale_from.y() == 0 ||
- params_.scale_to.x() == 0 || params_.scale_to.y() == 0) {
- // The caller computed invalid scale_from and/or scale_to values.
- DVLOG(1) << __func__ << ": Invalid scaling vectors: scale_from="
- << params_.scale_from.ToString()
- << ", scale_to=" << params_.scale_to.ToString();
- return false;
- }
-
- // Resolve the color spaces according to the rules described in the header
- // file.
- if (!params_.source_color_space.IsValid()) {
- params_.source_color_space = gfx::ColorSpace::CreateSRGB();
- }
- if (!params_.output_color_space.IsValid()) {
- params_.output_color_space = params_.source_color_space;
- }
-
- // Check that 16-bit half floats are supported if precise color management is
- // being requested.
- if (params_.enable_precise_color_management) {
- if (!SupportsPreciseColorManagement()) {
- DVLOG(1) << __func__
- << ": GL context does not support the half-floats "
- "required for precise color management.";
- return false;
- }
- }
-
- // Check that MRT support is available if certain export formats were
- // specified in the Parameters.
- if (params_.export_format == Parameters::ExportFormat::NV61 ||
- params_.export_format ==
- Parameters::ExportFormat::DEINTERLEAVE_PAIRWISE) {
- if (GetMaxDrawBuffersSupported() < 2) {
- DVLOG(1) << __func__ << ": GL context does not support 2+ draw buffers.";
- return false;
- }
- }
-
- // Color space transformation is meaningless when using the deinterleaver
- // because it only deals with two color channels. This also means precise
- // color management must be disabled.
- if (params_.export_format ==
- Parameters::ExportFormat::DEINTERLEAVE_PAIRWISE &&
- (params_.source_color_space != params_.output_color_space ||
- params_.enable_precise_color_management)) {
- NOTIMPLEMENTED();
- return false;
- }
-
- // Check that one of the two implemented output swizzles has been specified.
- for (GLenum s : params_.swizzle) {
- if (s != GL_RGBA && s != GL_BGRA_EXT) {
- NOTIMPLEMENTED();
- return false;
- }
- }
-
- // Create the chain of ScalerStages. If the quality setting is FAST or there
- // is no scaling to be done, just create a single stage.
- std::unique_ptr<ScalerStage> chain;
- if (params_.quality == Parameters::Quality::FAST ||
- params_.scale_from == params_.scale_to) {
- chain = std::make_unique<ScalerStage>(gl, Shader::BILINEAR, HORIZONTAL,
- params_.scale_from, params_.scale_to);
- } else if (params_.quality == Parameters::Quality::GOOD) {
- chain = CreateAGoodScalingChain(gl, params_.scale_from, params_.scale_to);
- } else if (params_.quality == Parameters::Quality::BEST) {
- chain = CreateTheBestScalingChain(gl, params_.scale_from, params_.scale_to);
- } else {
- NOTREACHED();
- }
- chain = MaybeAppendExportStage(gl, std::move(chain), params_.export_format);
-
- // Determine the color space and the data type of the pixels in the
- // intermediate textures, depending on whether precise color management is
- // enabled. Note that nothing special need be done here if no scaling will be
- // performed.
- GLenum intermediate_texture_type;
- if (params_.enable_precise_color_management &&
- params_.scale_from != params_.scale_to) {
- // Ensure the scaling color space is using a linear transfer function.
- constexpr auto kLinearFunction = std::make_tuple(1, 0, 1, 0, 0, 0, 1);
- skcms_TransferFunction fn;
- if (params_.source_color_space.GetTransferFunction(&fn) &&
- std::make_tuple(fn.a, fn.b, fn.c, fn.d, fn.e, fn.f, fn.g) ==
- kLinearFunction) {
- scaling_color_space_ = params_.source_color_space;
- } else {
- // Use the source color space, but with a linear transfer function.
- skcms_Matrix3x3 to_XYZD50;
- params_.source_color_space.GetPrimaryMatrix(&to_XYZD50);
- std::tie(fn.a, fn.b, fn.c, fn.d, fn.e, fn.f, fn.g) = kLinearFunction;
- scaling_color_space_ = gfx::ColorSpace::CreateCustom(to_XYZD50, fn);
- }
- intermediate_texture_type = GL_HALF_FLOAT_OES;
- } else {
- scaling_color_space_ = params_.source_color_space;
- intermediate_texture_type = GL_UNSIGNED_BYTE;
- }
-
- // Set the shader program on the final stage. Include color space
- // transformation and swizzling, if necessary.
- std::unique_ptr<gfx::ColorTransform> transform;
- if (scaling_color_space_ != params_.output_color_space) {
- transform = gfx::ColorTransform::NewColorTransform(
- scaling_color_space_, params_.output_color_space);
- }
- ScalerStage* const final_stage = chain.get();
- final_stage->set_shader_program(
- GetShaderProgram(final_stage->shader(), intermediate_texture_type,
- transform.get(), params_.swizzle));
-
- // Set the shader program on all prior stages. These stages are all operating
- // in the same color space, |scaling_color_space_|.
- static const GLenum kNoSwizzle[2] = {GL_RGBA, GL_RGBA};
- ScalerStage* input_stage = final_stage;
- while (input_stage->input_stage()) {
- input_stage = input_stage->input_stage();
- input_stage->set_shader_program(GetShaderProgram(
- input_stage->shader(), intermediate_texture_type, nullptr, kNoSwizzle));
- }
- // From this point, |input_stage| points to the first ScalerStage (i.e., the
- // one that will be reading from the source).
-
- // If necessary, prepend an extra "import stage" that color-converts the input
- // before any scaling occurs. It's important not to merge color space
- // conversion of the source with any other steps because the texture sampler
- // must not linearly interpolate until after the colors have been mapped to a
- // linear color space.
- if (params_.source_color_space != scaling_color_space_) {
- input_stage->set_input_stage(std::make_unique<ScalerStage>(
- gl, Shader::BILINEAR, HORIZONTAL, input_stage->scale_from(),
- input_stage->scale_from()));
- input_stage = input_stage->input_stage();
- transform = gfx::ColorTransform::NewColorTransform(
- params_.source_color_space, scaling_color_space_);
- input_stage->set_shader_program(
- GetShaderProgram(input_stage->shader(), intermediate_texture_type,
- transform.get(), kNoSwizzle));
- }
-
- // If the source content is Y-flipped, the input scaler stage will perform
- // math to account for this. It also will flip the content during scaling so
- // that all following stages may assume the content is not flipped. Then, the
- // final stage must ensure the final output is correctly flipped-back (or not)
- // based on what the first stage did PLUS what is being requested by the
- // client code.
- if (params_.is_flipped_source) {
- input_stage->set_is_flipped_source(true);
- input_stage->set_flip_output(true);
- }
- if (input_stage->flip_output() != params_.flip_output) {
- final_stage->set_flip_output(!final_stage->flip_output());
- }
-
- chain_ = std::move(chain);
- VLOG(2) << __func__ << " built this: " << *this;
- return true;
-}
-
-bool GLScaler::ScaleToMultipleOutputs(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- GLuint dest_texture_0,
- GLuint dest_texture_1,
- const gfx::Rect& output_rect) {
- if (!chain_) {
- return false;
- }
-
- // Bind the vertex attributes used to sweep the entire source area when
- // executing the shader programs.
- GLES2Interface* const gl = context_provider_->ContextGL();
- DCHECK(gl);
- if (vertex_attributes_buffer_) {
- gl->BindBuffer(GL_ARRAY_BUFFER, vertex_attributes_buffer_);
- } else {
- gl->GenBuffers(1, &vertex_attributes_buffer_);
- gl->BindBuffer(GL_ARRAY_BUFFER, vertex_attributes_buffer_);
- gl->BufferData(GL_ARRAY_BUFFER, sizeof(ShaderProgram::kVertexAttributes),
- ShaderProgram::kVertexAttributes, GL_STATIC_DRAW);
- }
-
- // Disable GL clipping/blending features that interfere with assumptions made
- // by the implementation. Only those known to possibly be enabled elsewhere in
- // Chromium code are disabled here, while the remainder are sanity-DCHECK'ed.
- gl->Disable(GL_SCISSOR_TEST);
- gl->Disable(GL_STENCIL_TEST);
- gl->Disable(GL_BLEND);
- DCHECK_NE(gl->IsEnabled(GL_CULL_FACE), GL_TRUE);
- DCHECK_NE(gl->IsEnabled(GL_DEPTH_TEST), GL_TRUE);
- DCHECK_NE(gl->IsEnabled(GL_POLYGON_OFFSET_FILL), GL_TRUE);
- DCHECK_NE(gl->IsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE), GL_TRUE);
- DCHECK_NE(gl->IsEnabled(GL_SAMPLE_COVERAGE), GL_TRUE);
- DCHECK_NE(gl->IsEnabled(GL_SCISSOR_TEST), GL_TRUE);
- DCHECK_NE(gl->IsEnabled(GL_STENCIL_TEST), GL_TRUE);
-
- chain_->ScaleToMultipleOutputs(src_texture, src_texture_size, src_offset,
- dest_texture_0, dest_texture_1, output_rect);
-
- gl->BindBuffer(GL_ARRAY_BUFFER, 0);
- return true;
-}
-
-// static
-bool GLScaler::ParametersHasSameScaleRatio(const GLScaler::Parameters& params,
- const gfx::Vector2d& from,
- const gfx::Vector2d& to) {
- // Returns true iff a_num/a_denom == b_num/b_denom.
- const auto AreRatiosEqual = [](int32_t a_num, int32_t a_denom, int32_t b_num,
- int32_t b_denom) -> bool {
- // The math (for each dimension):
- // If: a_num/a_denom == b_num/b_denom
- // Then: a_num*b_denom == b_num*a_denom
- //
- // ...and cast to int64_t to guarantee no overflow from the multiplications.
- return (static_cast<int64_t>(a_num) * b_denom) ==
- (static_cast<int64_t>(b_num) * a_denom);
- };
-
- return AreRatiosEqual(params.scale_from.x(), params.scale_to.x(), from.x(),
- to.x()) &&
- AreRatiosEqual(params.scale_from.y(), params.scale_to.y(), from.y(),
- to.y());
-}
-
-// static
-bool GLScaler::ParametersAreEquivalent(const Parameters& a,
- const Parameters& b) {
- if (!ParametersHasSameScaleRatio(a, b.scale_from, b.scale_to) ||
- a.enable_precise_color_management != b.enable_precise_color_management ||
- a.quality != b.quality || a.is_flipped_source != b.is_flipped_source ||
- a.flip_output != b.flip_output || a.export_format != b.export_format ||
- a.swizzle[0] != b.swizzle[0] || a.swizzle[1] != b.swizzle[1]) {
- return false;
- }
-
- const gfx::ColorSpace source_color_space_a =
- a.source_color_space.IsValid() ? a.source_color_space
- : gfx::ColorSpace::CreateSRGB();
- const gfx::ColorSpace source_color_space_b =
- b.source_color_space.IsValid() ? b.source_color_space
- : gfx::ColorSpace::CreateSRGB();
- if (source_color_space_a != source_color_space_b) {
- return false;
- }
-
- const gfx::ColorSpace output_color_space_a = a.output_color_space.IsValid()
- ? a.output_color_space
- : source_color_space_a;
- const gfx::ColorSpace output_color_space_b = b.output_color_space.IsValid()
- ? b.output_color_space
- : source_color_space_b;
- return output_color_space_a == output_color_space_b;
-}
-
-void GLScaler::OnContextLost() {
- // The destruction order here is important due to data dependencies.
- chain_.reset();
- shader_programs_.clear();
- if (vertex_attributes_buffer_) {
- if (auto* gl = context_provider_->ContextGL()) {
- gl->DeleteBuffers(1, &vertex_attributes_buffer_);
- }
- vertex_attributes_buffer_ = 0;
- }
- if (context_provider_) {
- context_provider_->RemoveObserver(this);
- context_provider_ = nullptr;
- }
-}
-
-GLScaler::ShaderProgram* GLScaler::GetShaderProgram(
- Shader shader,
- GLenum texture_type,
- const gfx::ColorTransform* color_transform,
- const GLenum swizzle[2]) {
- const ShaderCacheKey key{
- shader,
- texture_type,
- color_transform ? color_transform->GetSrcColorSpace() : gfx::ColorSpace(),
- color_transform ? color_transform->GetDstColorSpace() : gfx::ColorSpace(),
- swizzle[0],
- swizzle[1]};
- auto it = shader_programs_.find(key);
- if (it == shader_programs_.end()) {
- GLES2Interface* const gl = context_provider_->ContextGL();
- DCHECK(gl);
- it = shader_programs_
- .emplace(std::piecewise_construct, std::forward_as_tuple(key),
- std::forward_as_tuple(gl, shader, texture_type,
- color_transform, swizzle))
- .first;
- }
- return &it->second;
-}
-
-// static
-std::unique_ptr<GLScaler::ScalerStage> GLScaler::CreateAGoodScalingChain(
- gpu::gles2::GLES2Interface* gl,
- const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to) {
- DCHECK(scale_from.x() != 0 && scale_from.y() != 0)
- << "Bad scale_from: " << scale_from.ToString();
- DCHECK(scale_to.x() != 0 && scale_to.y() != 0)
- << "Bad scale_to: " << scale_to.ToString();
- DCHECK(scale_from != scale_to);
-
- // The GOOD quality chain performs one bilinear upscale followed by N bilinear
- // halvings, and does this is both directions. Exception: No upscale is needed
- // when |scale_from| is a power of two multiple of |scale_to|.
- //
- // Since all shaders use bilinear filtering, the heuristics below attempt to
- // greedily merge steps wherever possible to minimize GPU memory usage and
- // processing time. This also means that it will be extremely rare for the
- // stage doing the initial upscale to actually require a larger output texture
- // than the source texture (a downscale will be merged into the same stage).
-
- // Determine the initial upscaled-to size, as the minimum number of doublings
- // to make |scale_to| greater than |scale_from|.
- const RelativeSize from(scale_from);
- const RelativeSize to(scale_to);
- RelativeSize upscale_to = to;
- for (Axis x_or_y : std::array<Axis, 2>{HORIZONTAL, VERTICAL}) {
- while (upscale_to[x_or_y] < from[x_or_y]) {
- upscale_to[x_or_y] *= 2;
- }
- }
-
- // Create the stages in order from first-to-last, taking the greediest path
- // each time. Something like an A* algorithm would be better for discovering
- // an optimal sequence of operations, and would allow using the BILINEAR3
- // shader as well, but the run-time performance to compute the stages would be
- // too prohibitive.
- std::unique_ptr<ScalerStage> chain;
- struct CandidateOp {
- Shader shader;
- Axis primary_axis;
- RelativeSize output_size;
- };
- std::vector<CandidateOp> candidates;
- for (RelativeSize cur = from; cur != to;
- cur = RelativeSize(chain->scale_to())) {
- candidates.clear();
-
- // Determine whether it's possible to do exactly 2 bilinear passes in both
- // directions.
- RelativeSize output_size_2x2 = {0, 0};
- for (Axis x_or_y : std::array<Axis, 2>{VERTICAL, HORIZONTAL}) {
- if (cur[x_or_y] == from[x_or_y]) {
- // For the first stage, the 2 bilinear passes must be the initial
- // upscale followed by one downscale. If there is no initial upscale,
- // then the 2 passes must both be downscales.
- if (upscale_to[x_or_y] != from[x_or_y] &&
- upscale_to[x_or_y] / 2 >= to[x_or_y]) {
- output_size_2x2[x_or_y] = upscale_to[x_or_y] / 2;
- } else if (upscale_to[x_or_y] == from[x_or_y] &&
- upscale_to[x_or_y] / 4 >= to[x_or_y]) {
- output_size_2x2[x_or_y] = cur[x_or_y] / 4;
- }
- } else {
- // For all later stages, the 2 bilinear passes must be 2 halvings.
- if (cur[x_or_y] / 4 >= to[x_or_y]) {
- output_size_2x2[x_or_y] = cur[x_or_y] / 4;
- }
- }
- }
- if (output_size_2x2[HORIZONTAL] != 0 && output_size_2x2[VERTICAL] != 0) {
- candidates.push_back(
- CandidateOp{Shader::BILINEAR2X2, HORIZONTAL, output_size_2x2});
- }
-
- // Determine the valid set of Ops that do 1 to 3 bilinear passes in one
- // direction and 0 or 1 pass in the other direction.
- for (Axis x_or_y : std::array<Axis, 2>{VERTICAL, HORIZONTAL}) {
- // The first bilinear pass in x_or_y must be an upscale or a halving.
- Shader shader = Shader::BILINEAR;
- RelativeSize output_size = cur;
- if (cur[x_or_y] == from[x_or_y] && upscale_to[x_or_y] != from[x_or_y]) {
- output_size[x_or_y] = upscale_to[x_or_y];
- } else if (cur[x_or_y] / 2 >= to[x_or_y]) {
- output_size[x_or_y] /= 2;
- } else {
- DCHECK_EQ(cur[x_or_y], to[x_or_y]);
- continue;
- }
-
- // Determine whether 1 or 2 additional passes can be made in the same
- // direction.
- if (output_size[x_or_y] / 4 >= to[x_or_y]) {
- shader = Shader::BILINEAR4; // 2 more passes == 3 total.
- output_size[x_or_y] /= 4;
- } else if (output_size[x_or_y] / 2 >= to[x_or_y]) {
- shader = Shader::BILINEAR2; // 1 more pass == 2 total.
- output_size[x_or_y] /= 2;
- } else {
- DCHECK_EQ(output_size[x_or_y], to[x_or_y]);
- }
-
- // Determine whether 0 or 1 bilinear passes can be made in the other
- // direction at the same time.
- const Axis y_or_x = TheOtherAxis(x_or_y);
- if (cur[y_or_x] == from[y_or_x] && upscale_to[y_or_x] != from[y_or_x]) {
- output_size[y_or_x] = upscale_to[y_or_x];
- } else if (cur[y_or_x] / 2 >= to[y_or_x]) {
- output_size[y_or_x] /= 2;
- } else {
- DCHECK_EQ(cur[y_or_x], to[y_or_x]);
- }
-
- candidates.push_back(CandidateOp{shader, x_or_y, output_size});
- }
-
- // From the candidates, pick the one that produces the fewest number of
- // output pixels, and append a new ScalerStage. There are opportunities to
- // improve the "cost function" here (e.g., pixels in the Y direction
- // probably cost more to process than pixels in the X direction), but that
- // would require more research.
- const auto best_candidate = std::min_element(
- candidates.begin(), candidates.end(),
- [](const CandidateOp& a, const CandidateOp& b) {
- static_assert(sizeof(a.output_size[0]) <= sizeof(int32_t),
- "Overflow issue in the math here.");
- const int64_t cost_of_a =
- int64_t{a.output_size[HORIZONTAL]} * a.output_size[VERTICAL];
- const int64_t cost_of_b =
- int64_t{b.output_size[HORIZONTAL]} * b.output_size[VERTICAL];
- return cost_of_a < cost_of_b;
- });
- DCHECK(best_candidate != candidates.end());
- DCHECK(cur != best_candidate->output_size)
- << "Best candidate's output size (" << best_candidate->output_size
- << ") should not equal the input size.";
- auto next_stage = std::make_unique<ScalerStage>(
- gl, best_candidate->shader, best_candidate->primary_axis,
- cur.AsVector2d(), best_candidate->output_size.AsVector2d());
- next_stage->set_input_stage(std::move(chain));
- chain = std::move(next_stage);
- }
-
- return chain;
-}
-
-// static
-std::unique_ptr<GLScaler::ScalerStage> GLScaler::CreateTheBestScalingChain(
- gpu::gles2::GLES2Interface* gl,
- const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to) {
- // The BEST quality chain performs one bicubic upscale followed by N bicubic
- // halvings, and does this is both directions. Exception: No upscale is needed
- // when |scale_from| is a power of two multiple of |scale_to|.
-
- // Determine the initial upscaled-to size, as the minimum number of doublings
- // to make |scale_to| greater than |scale_from|.
- const RelativeSize from(scale_from);
- const RelativeSize to(scale_to);
- RelativeSize upscale_to = to;
- for (Axis x_or_y : std::array<Axis, 2>{HORIZONTAL, VERTICAL}) {
- while (upscale_to[x_or_y] < from[x_or_y]) {
- upscale_to[x_or_y] *= 2;
- }
- }
-
- // Create the stages in order from first-to-last.
- RelativeSize cur = from;
- std::unique_ptr<ScalerStage> chain;
- for (Axis x_or_y : std::array<Axis, 2>{VERTICAL, HORIZONTAL}) {
- if (upscale_to[x_or_y] != from[x_or_y]) {
- RelativeSize next = cur;
- next[x_or_y] = upscale_to[x_or_y];
- auto upscale_stage =
- std::make_unique<ScalerStage>(gl, Shader::BICUBIC_UPSCALE, x_or_y,
- cur.AsVector2d(), next.AsVector2d());
- upscale_stage->set_input_stage(std::move(chain));
- chain = std::move(upscale_stage);
- cur = next;
- }
- while (cur[x_or_y] > to[x_or_y]) {
- RelativeSize next = cur;
- next[x_or_y] /= 2;
- auto next_stage =
- std::make_unique<ScalerStage>(gl, Shader::BICUBIC_HALF_1D, x_or_y,
- cur.AsVector2d(), next.AsVector2d());
- next_stage->set_input_stage(std::move(chain));
- chain = std::move(next_stage);
- cur = next;
- }
- }
- DCHECK_EQ(cur, to);
-
- return chain;
-}
-
-// static
-std::unique_ptr<GLScaler::ScalerStage> GLScaler::MaybeAppendExportStage(
- gpu::gles2::GLES2Interface* gl,
- std::unique_ptr<GLScaler::ScalerStage> chain,
- GLScaler::Parameters::ExportFormat export_format) {
- DCHECK(chain);
-
- if (export_format == Parameters::ExportFormat::INTERLEAVED_QUADS) {
- return chain; // No format change.
- }
-
- // If the final stage uses the BILINEAR shader that is not upscaling, the
- // export stage can replace it with no change in the results. Otherwise, a
- // separate export stage will be appended.
- gfx::Vector2d scale_from = chain->scale_from();
- const gfx::Vector2d scale_to = chain->scale_to();
- if (chain->shader() == Shader::BILINEAR && scale_from.x() >= scale_to.x() &&
- scale_from.y() >= scale_to.y()) {
- chain = chain->take_input_stage();
- } else {
- scale_from = scale_to;
- }
-
- Shader shader = Shader::BILINEAR;
- scale_from.set_x(scale_from.x() * 4);
- switch (export_format) {
- case Parameters::ExportFormat::INTERLEAVED_QUADS:
- NOTREACHED();
- break;
- case Parameters::ExportFormat::CHANNEL_0:
- shader = Shader::PLANAR_CHANNEL_0;
- break;
- case Parameters::ExportFormat::CHANNEL_1:
- shader = Shader::PLANAR_CHANNEL_1;
- break;
- case Parameters::ExportFormat::CHANNEL_2:
- shader = Shader::PLANAR_CHANNEL_2;
- break;
- case Parameters::ExportFormat::CHANNEL_3:
- shader = Shader::PLANAR_CHANNEL_3;
- break;
- case Parameters::ExportFormat::NV61:
- shader = Shader::I422_NV61_MRT;
- break;
- case Parameters::ExportFormat::DEINTERLEAVE_PAIRWISE:
- shader = Shader::DEINTERLEAVE_PAIRWISE_MRT;
- // Horizontal scale is only 0.5X, not 0.25X like all the others.
- scale_from.set_x(scale_from.x() / 2);
- break;
- case Parameters::ExportFormat::UV_CHANNELS:
- shader = Shader::PLANAR_CHANNELS_1_2;
- break;
- }
-
- auto export_stage = std::make_unique<ScalerStage>(gl, shader, HORIZONTAL,
- scale_from, scale_to);
- export_stage->set_input_stage(std::move(chain));
- return export_stage;
-}
-
-// static
-GLScaler::Axis GLScaler::TheOtherAxis(GLScaler::Axis x_or_y) {
- return x_or_y == HORIZONTAL ? VERTICAL : HORIZONTAL;
-}
-
-// static
-const char* GLScaler::GetShaderName(GLScaler::Shader shader) {
- switch (shader) {
-#define CASE_RETURN_SHADER_STR(x) \
- case Shader::x: \
- return #x
- CASE_RETURN_SHADER_STR(BILINEAR);
- CASE_RETURN_SHADER_STR(BILINEAR2);
- CASE_RETURN_SHADER_STR(BILINEAR3);
- CASE_RETURN_SHADER_STR(BILINEAR4);
- CASE_RETURN_SHADER_STR(BILINEAR2X2);
- CASE_RETURN_SHADER_STR(BICUBIC_UPSCALE);
- CASE_RETURN_SHADER_STR(BICUBIC_HALF_1D);
- CASE_RETURN_SHADER_STR(PLANAR_CHANNEL_0);
- CASE_RETURN_SHADER_STR(PLANAR_CHANNEL_1);
- CASE_RETURN_SHADER_STR(PLANAR_CHANNEL_2);
- CASE_RETURN_SHADER_STR(PLANAR_CHANNEL_3);
- CASE_RETURN_SHADER_STR(I422_NV61_MRT);
- CASE_RETURN_SHADER_STR(DEINTERLEAVE_PAIRWISE_MRT);
- CASE_RETURN_SHADER_STR(PLANAR_CHANNELS_1_2);
-#undef CASE_RETURN_SHADER_STR
- }
-}
-
-// static
-bool GLScaler::AreAllGLExtensionsPresent(
- gpu::gles2::GLES2Interface* gl,
- const std::vector<std::string>& names) {
- DCHECK(gl);
- if (const auto* extensions = gl->GetString(GL_EXTENSIONS)) {
- const std::string extensions_string =
- " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
- for (const std::string& name : names) {
- if (extensions_string.find(" " + name + " ") == std::string::npos) {
- return false;
- }
- }
- return true;
- }
- return false;
-}
-
-GLScaler::Parameters::Parameters() = default;
-GLScaler::Parameters::Parameters(const Parameters& other) = default;
-GLScaler::Parameters::~Parameters() = default;
-
-// static
-const GLfloat GLScaler::ShaderProgram::kVertexAttributes[16] = {
- -1.0f, -1.0f, 0.0f, 0.0f, // vertex 0
- 1.0f, -1.0f, 1.0f, 0.0f, // vertex 1
- -1.0f, 1.0f, 0.0f, 1.0f, // vertex 2
- 1.0f, 1.0f, 1.0f, 1.0f, // vertex 3
-};
-
-GLScaler::ShaderProgram::ShaderProgram(
- gpu::gles2::GLES2Interface* gl,
- GLScaler::Shader shader,
- GLenum texture_type,
- const gfx::ColorTransform* color_transform,
- const GLenum swizzle[2])
- : gl_(gl),
- shader_(shader),
- texture_type_(texture_type),
- program_(gl_->CreateProgram()) {
- DCHECK(program_);
-
- std::basic_ostringstream<GLchar> vertex_header;
- std::basic_ostringstream<GLchar> fragment_directives;
- std::basic_ostringstream<GLchar> fragment_header;
- std::basic_ostringstream<GLchar> shared_variables;
- std::basic_ostringstream<GLchar> vertex_main;
- std::basic_ostringstream<GLchar> fragment_main;
-
- vertex_header
- << ("precision highp float;\n"
- "attribute vec2 a_position;\n"
- "attribute vec2 a_texcoord;\n"
- "uniform vec4 src_rect;\n");
-
- fragment_header << "precision mediump float;\n";
- switch (texture_type_) {
- case GL_FLOAT:
- fragment_header << "precision highp sampler2D;\n";
- break;
- case GL_HALF_FLOAT_OES:
- fragment_header << "precision mediump sampler2D;\n";
- break;
- default:
- fragment_header << "precision lowp sampler2D;\n";
- break;
- }
- fragment_header << "uniform sampler2D s_texture;\n";
-
- if (color_transform && shader_ != Shader::PLANAR_CHANNEL_3) {
- const std::string& source = color_transform->GetShaderSource();
- // Assumption: gfx::ColorTransform::GetShaderSource() should provide a
- // function named DoColorConversion() that takes a vec3 argument and returns
- // a vec3.
- DCHECK_NE(source.find("DoColorConversion"), std::string::npos);
- fragment_header << source;
- }
-
- vertex_main
- << (" gl_Position = vec4(a_position, 0.0, 1.0);\n"
- " vec2 texcoord = src_rect.xy + a_texcoord * src_rect.zw;\n");
-
- switch (shader_) {
- case Shader::BILINEAR:
- shared_variables << "varying highp vec2 v_texcoord;\n";
- vertex_main << " v_texcoord = texcoord;\n";
- fragment_main << " vec4 sample = texture2D(s_texture, v_texcoord);\n";
- if (color_transform) {
- fragment_main << " sample.rgb = DoColorConversion(sample.rgb);\n";
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " sample.rb = sample.br;\n";
- }
- fragment_main << " gl_FragColor = sample;\n";
- break;
-
- case Shader::BILINEAR2:
- // This is equivialent to two passes of the BILINEAR shader above. It can
- // be used to scale an image down 1.0x-2.0x in either dimension, or
- // exactly 4x.
- shared_variables << "varying highp vec4 v_texcoords;\n";
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 4.0;\n"
- " v_texcoords.xy = texcoord + step;\n"
- " v_texcoords.zw = texcoord - step;\n");
- fragment_main
- << (" vec4 blended = (texture2D(s_texture, v_texcoords.xy) +\n"
- " texture2D(s_texture, v_texcoords.zw)) /\n"
- " 2.0;\n");
- if (color_transform) {
- fragment_main << " blended.rgb = DoColorConversion(blended.rgb);\n";
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " blended.rb = blended.br;\n";
- }
- fragment_main << " gl_FragColor = blended;\n";
- break;
-
- case Shader::BILINEAR3:
- // This is kind of like doing 1.5 passes of the BILINEAR shader. It can be
- // used to scale an image down 1.5x-3.0x, or exactly 6x.
- shared_variables
- << ("varying highp vec4 v_texcoords0;\n"
- "varying highp vec2 v_texcoords1;\n");
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 3.0;\n"
- " v_texcoords0.xy = texcoord + step;\n"
- " v_texcoords0.zw = texcoord;\n"
- " v_texcoords1 = texcoord - step;\n");
- fragment_main
- << (" vec4 blended = (texture2D(s_texture, v_texcoords0.xy) +\n"
- " texture2D(s_texture, v_texcoords0.zw) +\n"
- " texture2D(s_texture, v_texcoords1)) / 3.0;\n");
- if (color_transform) {
- fragment_main << " blended.rgb = DoColorConversion(blended.rgb);\n";
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " blended.rb = blended.br;\n";
- }
- fragment_main << " gl_FragColor = blended;\n";
- break;
-
- case Shader::BILINEAR4:
- // This is equivialent to three passes of the BILINEAR shader above. It
- // can be used to scale an image down 2.0x-4.0x or exactly 8x.
- shared_variables << "varying highp vec4 v_texcoords[2];\n";
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 8.0;\n"
- " v_texcoords[0].xy = texcoord - step * 3.0;\n"
- " v_texcoords[0].zw = texcoord - step;\n"
- " v_texcoords[1].xy = texcoord + step;\n"
- " v_texcoords[1].zw = texcoord + step * 3.0;\n");
- fragment_main
- << (" vec4 blended = (\n"
- " texture2D(s_texture, v_texcoords[0].xy) +\n"
- " texture2D(s_texture, v_texcoords[0].zw) +\n"
- " texture2D(s_texture, v_texcoords[1].xy) +\n"
- " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
- if (color_transform) {
- fragment_main << " blended.rgb = DoColorConversion(blended.rgb);\n";
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " blended.rb = blended.br;\n";
- }
- fragment_main << " gl_FragColor = blended;\n";
- break;
-
- case Shader::BILINEAR2X2:
- // This is equivialent to four passes of the BILINEAR shader above, two in
- // each dimension. It can be used to scale an image down 1.0x-2.0x in both
- // X and Y directions. Or, it could be used to scale an image down by
- // exactly 4x in both dimensions.
- shared_variables << "varying highp vec4 v_texcoords[2];\n";
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 4.0;\n"
- " v_texcoords[0].xy = texcoord + vec2(step.x, step.y);\n"
- " v_texcoords[0].zw = texcoord + vec2(step.x, -step.y);\n"
- " v_texcoords[1].xy = texcoord + vec2(-step.x, step.y);\n"
- " v_texcoords[1].zw = texcoord + vec2(-step.x, -step.y);\n");
- fragment_main
- << (" vec4 blended = (\n"
- " texture2D(s_texture, v_texcoords[0].xy) +\n"
- " texture2D(s_texture, v_texcoords[0].zw) +\n"
- " texture2D(s_texture, v_texcoords[1].xy) +\n"
- " texture2D(s_texture, v_texcoords[1].zw)) / 4.0;\n");
- if (color_transform) {
- fragment_main << " blended.rgb = DoColorConversion(blended.rgb);\n";
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " blended.rb = blended.br;\n";
- }
- fragment_main << " gl_FragColor = blended;\n";
- break;
-
- case Shader::BICUBIC_UPSCALE:
- // When scaling up, 4 texture reads are necessary. However, some
- // instructions can be saved because the parameter passed to the bicubic
- // function will be in a known range. Also, when sampling the bicubic
- // function like this, the sum is always exactly one, so normalization can
- // be skipped as well.
- shared_variables << "varying highp vec2 v_texcoord;\n";
- vertex_main << " v_texcoord = texcoord;\n";
- fragment_header
- << ("uniform highp vec2 src_pixelsize;\n"
- "uniform highp vec2 scaling_vector;\n"
- "const float a = -0.5;\n"
- // This function is equivialent to calling the bicubic
- // function with x-1, x, 1-x and 2-x (assuming
- // 0 <= x < 1). The following is the Catmull-Rom spline.
- // See: http://wikipedia.org/wiki/Cubic_Hermite_spline
- "vec4 filt4(float x) {\n"
- " return vec4(x * x * x, x * x, x, 1) *\n"
- " mat4( a, -2.0 * a, a, 0.0,\n"
- " a + 2.0, -a - 3.0, 0.0, 1.0,\n"
- " -a - 2.0, 3.0 + 2.0 * a, -a, 0.0,\n"
- " -a, a, 0.0, 0.0);\n"
- "}\n"
- "mat4 pixels_x(highp vec2 pos, highp vec2 step) {\n"
- " return mat4(texture2D(s_texture, pos - step),\n"
- " texture2D(s_texture, pos),\n"
- " texture2D(s_texture, pos + step),\n"
- " texture2D(s_texture, pos + step * 2.0));\n"
- "}\n");
- fragment_main
- << (" highp vec2 pixel_pos = v_texcoord * src_pixelsize - \n"
- " scaling_vector / 2.0;\n"
- " highp float frac = fract(dot(pixel_pos, scaling_vector));\n"
- " highp vec2 base = \n"
- " (floor(pixel_pos) + vec2(0.5)) / src_pixelsize;\n"
- " highp vec2 step = scaling_vector / src_pixelsize;\n"
- " vec4 blended = pixels_x(base, step) * filt4(frac);\n");
- if (color_transform) {
- fragment_main << " blended.rgb = DoColorConversion(blended.rgb);\n";
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " blended.rb = blended.br;\n";
- }
- fragment_main << " gl_FragColor = blended;\n";
- break;
-
- case Shader::BICUBIC_HALF_1D:
- // This scales down an image by exactly half in one dimension. The
- // bilinear lookup reduces the number of texture reads from 8 to 4.
- shared_variables << "varying highp vec4 v_texcoords[2];\n";
- vertex_header
- << ("uniform vec2 scaling_vector;\n"
- "const float CenterDist = 99.0 / 140.0;\n"
- "const float LobeDist = 11.0 / 4.0;\n");
- vertex_main
- << (" vec2 step = scaling_vector / 2.0;\n"
- " v_texcoords[0].xy = texcoord - LobeDist * step;\n"
- " v_texcoords[0].zw = texcoord - CenterDist * step;\n"
- " v_texcoords[1].xy = texcoord + CenterDist * step;\n"
- " v_texcoords[1].zw = texcoord + LobeDist * step;\n");
- fragment_header
- << ("const float CenterWeight = 35.0 / 64.0;\n"
- "const float LobeWeight = -3.0 / 64.0;\n");
- fragment_main
- << (" vec4 blended = \n"
- // Lobe pixels
- " (texture2D(s_texture, v_texcoords[0].xy) +\n"
- " texture2D(s_texture, v_texcoords[1].zw)) *\n"
- " LobeWeight +\n"
- // Center pixels
- " (texture2D(s_texture, v_texcoords[0].zw) +\n"
- " texture2D(s_texture, v_texcoords[1].xy)) *\n"
- " CenterWeight;\n");
- if (color_transform) {
- fragment_main << " blended.rgb = DoColorConversion(blended.rgb);\n";
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " blended.rb = blended.br;\n";
- }
- fragment_main << " gl_FragColor = blended;\n";
- break;
-
- case Shader::PLANAR_CHANNEL_0:
- case Shader::PLANAR_CHANNEL_1:
- case Shader::PLANAR_CHANNEL_2:
- case Shader::PLANAR_CHANNEL_3: {
- // Select one color channel, and pack 4 pixels into one output quad. See
- // header file for diagram.
- shared_variables << "varying highp vec4 v_texcoords[2];\n";
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 4.0;\n"
- " v_texcoords[0].xy = texcoord - step * 1.5;\n"
- " v_texcoords[0].zw = texcoord - step * 0.5;\n"
- " v_texcoords[1].xy = texcoord + step * 0.5;\n"
- " v_texcoords[1].zw = texcoord + step * 1.5;\n");
- std::basic_string<GLchar> convert_open;
- std::basic_string<GLchar> convert_close;
- if (color_transform && shader_ != Shader::PLANAR_CHANNEL_3) {
- convert_open = "DoColorConversion(";
- convert_close = ".rgb)";
- }
- const char selector = "rgba"[static_cast<int>(shader_) -
- static_cast<int>(Shader::PLANAR_CHANNEL_0)];
- fragment_main << " vec4 packed_quad = vec4(\n"
- << " " << convert_open
- << "texture2D(s_texture, v_texcoords[0].xy)"
- << convert_close << '.' << selector << ",\n"
- << " " << convert_open
- << "texture2D(s_texture, v_texcoords[0].zw)"
- << convert_close << '.' << selector << ",\n"
- << " " << convert_open
- << "texture2D(s_texture, v_texcoords[1].xy)"
- << convert_close << '.' << selector << ",\n"
- << " " << convert_open
- << "texture2D(s_texture, v_texcoords[1].zw)"
- << convert_close << '.' << selector << ");\n";
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " packed_quad.rb = packed_quad.br;\n";
- }
- fragment_main << " gl_FragColor = packed_quad;\n";
- break;
- }
-
- case Shader::I422_NV61_MRT:
- // I422 sampling, delivered via two output textures (NV61 format). See
- // header file for diagram.
- shared_variables << "varying highp vec4 v_texcoords[2];\n";
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 4.0;\n"
- " v_texcoords[0].xy = texcoord - step * 1.5;\n"
- " v_texcoords[0].zw = texcoord - step * 0.5;\n"
- " v_texcoords[1].xy = texcoord + step * 0.5;\n"
- " v_texcoords[1].zw = texcoord + step * 1.5;\n");
- fragment_directives << "#extension GL_EXT_draw_buffers : enable\n";
- fragment_main
- << (" vec3 pixel0 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n"
- " vec3 pixel1 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n"
- " vec3 pixel01 = (pixel0 + pixel1) / 2.0;\n"
- " vec3 pixel2 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n"
- " vec3 pixel3 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n"
- " vec3 pixel23 = (pixel2 + pixel3) / 2.0;\n");
- if (color_transform) {
- fragment_main
- << (" pixel0 = DoColorConversion(pixel0);\n"
- " pixel1 = DoColorConversion(pixel1);\n"
- " pixel01 = DoColorConversion(pixel01);\n"
- " pixel2 = DoColorConversion(pixel2);\n"
- " pixel3 = DoColorConversion(pixel3);\n"
- " pixel23 = DoColorConversion(pixel23);\n");
- }
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main
- << (" gl_FragData[0] = \n"
- " vec4(pixel2.r, pixel1.r, pixel0.r, pixel3.r);\n");
- } else {
- fragment_main
- << (" gl_FragData[0] = \n"
- " vec4(pixel0.r, pixel1.r, pixel2.r, pixel3.r);\n");
- }
- if (swizzle[1] == GL_BGRA_EXT) {
- fragment_main
- << (" gl_FragData[1] = \n"
- " vec4(pixel23.g, pixel01.b, pixel01.g, pixel23.b);\n");
- } else {
- fragment_main
- << (" gl_FragData[1] = \n"
- " vec4(pixel01.g, pixel01.b, pixel23.g, pixel23.b);\n");
- }
- break;
-
- case Shader::DEINTERLEAVE_PAIRWISE_MRT:
- // Sample two pixels and unswizzle them. There's no need to do vertical
- // scaling with math, since the bilinear interpolation in the sampler
- // takes care of that.
- shared_variables << "varying highp vec4 v_texcoords;\n";
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 2.0;\n"
- " v_texcoords.xy = texcoord - step * 0.5;\n"
- " v_texcoords.zw = texcoord + step * 0.5;\n");
- fragment_directives << "#extension GL_EXT_draw_buffers : enable\n";
- DCHECK(!color_transform);
- fragment_main
- << (" vec4 lo_uvuv = texture2D(s_texture, v_texcoords.xy);\n"
- " vec4 hi_uvuv = texture2D(s_texture, v_texcoords.zw);\n"
- " vec4 uuuu = vec4(lo_uvuv.rb, hi_uvuv.rb);\n"
- " vec4 vvvv = vec4(lo_uvuv.ga, hi_uvuv.ga);\n");
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " uuuu.rb = uuuu.br;\n";
- }
- fragment_main << " gl_FragData[0] = uuuu;\n";
- if (swizzle[1] == GL_BGRA_EXT) {
- fragment_main << " vvvv.rb = vvvv.br;\n";
- }
- fragment_main << " gl_FragData[1] = vvvv;\n";
- break;
-
- case Shader::PLANAR_CHANNELS_1_2: {
- // Select two color channels, and pack 2 pairs of pixels into one output
- // quad. See header file for diagram.
- // This shader performs the same work that is being done by
- // Shader::I422_NV61_MRT (see above) for its second render target.
- shared_variables << "varying highp vec4 v_texcoords[2];\n";
- vertex_header << "uniform vec2 scaling_vector;\n";
- vertex_main
- << (" vec2 step = scaling_vector / 4.0;\n"
- " v_texcoords[0].xy = texcoord - step * 1.5;\n"
- " v_texcoords[0].zw = texcoord - step * 0.5;\n"
- " v_texcoords[1].xy = texcoord + step * 0.5;\n"
- " v_texcoords[1].zw = texcoord + step * 1.5;\n");
- fragment_main
- << (" vec3 pixel0 = texture2D(s_texture, v_texcoords[0].xy).rgb;\n"
- " vec3 pixel1 = texture2D(s_texture, v_texcoords[0].zw).rgb;\n"
- " vec3 pixel01 = (pixel0 + pixel1) / 2.0;\n"
- " vec3 pixel2 = texture2D(s_texture, v_texcoords[1].xy).rgb;\n"
- " vec3 pixel3 = texture2D(s_texture, v_texcoords[1].zw).rgb;\n"
- " vec3 pixel23 = (pixel2 + pixel3) / 2.0;\n");
-
- if (color_transform) {
- fragment_main
- << (" pixel01 = DoColorConversion(pixel01);\n"
- " pixel23 = DoColorConversion(pixel23);\n");
- }
-
- fragment_main
- << (" vec4 packed_quad = vec4(\n"
- " pixel01.g, pixel01.b, pixel23.g, pixel23.b);\n");
-
- if (swizzle[0] == GL_BGRA_EXT) {
- fragment_main << " packed_quad.rb = packed_quad.br;\n";
- }
-
- fragment_main << " gl_FragColor = packed_quad;\n";
- break;
- }
- }
-
- // Helper function to compile the shader source and log the GLSL compiler's
- // results.
- const char* shader_name = GLScaler::GetShaderName(shader_);
- const auto CompileShaderFromSource =
- [shader_name](GLES2Interface* gl, const std::basic_string<GLchar>& source,
- GLenum type) -> GLuint {
- VLOG(2) << __func__ << ": Compiling shader " << type
- << " with source:" << std::endl
- << source << ", for GLScaler::Shader=" << shader_name;
- const GLuint shader = gl->CreateShader(type);
- const GLchar* source_data = source.data();
- const GLint length = base::checked_cast<GLint>(source.size());
- gl->ShaderSource(shader, 1, &source_data, &length);
- gl->CompileShader(shader);
- GLint compile_status = GL_FALSE;
- gl->GetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
-
- // Fetch logs and forward them to the system logger. If compilation failed,
- // clean-up and return 0 for error.
- if (compile_status != GL_TRUE || VLOG_IS_ON(2)) {
- GLint log_length = 0;
- gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
- std::string log;
- if (log_length > 0) {
- std::unique_ptr<GLchar[]> tmp(new GLchar[log_length]);
- GLsizei returned_log_length = 0;
- gl->GetShaderInfoLog(shader, log_length, &returned_log_length,
- tmp.get());
- log.assign(tmp.get(), returned_log_length);
- }
- if (log.empty()) {
- log = "<<NO LOG>>";
- }
- if (compile_status != GL_TRUE) {
- LOG(ERROR) << __func__ << ": Compilation of shader " << type
- << " failed:" << std::endl
- << log;
- gl->DeleteShader(shader);
- return 0;
- }
- VLOG(2) << __func__ << ": Compilation of shader " << type
- << " succeeded:" << std::endl
- << log;
- }
- return shader;
- };
-
- // Compile the vertex shader and attach it to the program.
- const std::string shared_variables_str = shared_variables.str();
- const GLuint vertex_shader =
- CompileShaderFromSource(gl_,
- vertex_header.str() + shared_variables_str +
- "void main() {\n" + vertex_main.str() + "}\n",
- GL_VERTEX_SHADER);
- if (vertex_shader == 0) {
- return;
- }
- gl_->AttachShader(program_, vertex_shader);
- gl_->DeleteShader(vertex_shader);
-
- // Compile the fragment shader and attach to |program_|.
- const GLuint fragment_shader = CompileShaderFromSource(
- gl_,
- fragment_directives.str() + fragment_header.str() + shared_variables_str +
- "void main() {\n" + fragment_main.str() + "}\n",
- GL_FRAGMENT_SHADER);
- if (fragment_shader == 0) {
- return;
- }
- gl_->AttachShader(program_, fragment_shader);
- gl_->DeleteShader(fragment_shader);
-
- // Link the program.
- gl_->LinkProgram(program_);
- GLint link_status = GL_FALSE;
- gl_->GetProgramiv(program_, GL_LINK_STATUS, &link_status);
- if (link_status != GL_TRUE) {
- LOG(ERROR) << "Failed to link shader program.";
- return;
- }
-
-#define DCHECK_RESOLVED_LOCATION(member) \
- DCHECK(member != -1 || gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR) \
- << "Failed to get " #member " in program, or GPU process crashed."
-
- // Resolve the locations of the global variables.
- position_location_ = gl_->GetAttribLocation(program_, "a_position");
- DCHECK_RESOLVED_LOCATION(position_location_);
- texcoord_location_ = gl_->GetAttribLocation(program_, "a_texcoord");
- DCHECK_RESOLVED_LOCATION(texcoord_location_);
- texture_location_ = gl_->GetUniformLocation(program_, "s_texture");
- DCHECK_RESOLVED_LOCATION(texture_location_);
- src_rect_location_ = gl_->GetUniformLocation(program_, "src_rect");
- DCHECK_RESOLVED_LOCATION(src_rect_location_);
- switch (shader_) {
- case Shader::BILINEAR:
- break;
-
- case Shader::BILINEAR2:
- case Shader::BILINEAR3:
- case Shader::BILINEAR4:
- case Shader::BILINEAR2X2:
- case Shader::BICUBIC_HALF_1D:
- case Shader::PLANAR_CHANNEL_0:
- case Shader::PLANAR_CHANNEL_1:
- case Shader::PLANAR_CHANNEL_2:
- case Shader::PLANAR_CHANNEL_3:
- case Shader::I422_NV61_MRT:
- case Shader::DEINTERLEAVE_PAIRWISE_MRT:
- case Shader::PLANAR_CHANNELS_1_2:
- scaling_vector_location_ =
- gl_->GetUniformLocation(program_, "scaling_vector");
- DCHECK_RESOLVED_LOCATION(scaling_vector_location_);
- break;
-
- case Shader::BICUBIC_UPSCALE:
- src_pixelsize_location_ =
- gl_->GetUniformLocation(program_, "src_pixelsize");
- DCHECK_RESOLVED_LOCATION(src_pixelsize_location_);
- scaling_vector_location_ =
- gl_->GetUniformLocation(program_, "scaling_vector");
- DCHECK_RESOLVED_LOCATION(scaling_vector_location_);
- break;
- }
-
-#undef DCHECK_RESOLVED_LOCATION
-}
-
-GLScaler::ShaderProgram::~ShaderProgram() {
- gl_->DeleteProgram(program_);
-}
-
-void GLScaler::ShaderProgram::UseProgram(const gfx::Size& src_texture_size,
- const gfx::RectF& src_rect,
- const gfx::Size& dst_size,
- GLScaler::Axis primary_axis,
- bool flip_y) {
- gl_->UseProgram(program_);
-
- // OpenGL defines the last parameter to VertexAttribPointer as type
- // "const GLvoid*" even though it is actually an offset into the buffer
- // object's data store and not a pointer to the client's address space.
- const void* offsets[2] = {nullptr,
- reinterpret_cast<const void*>(2 * sizeof(GLfloat))};
-
- gl_->VertexAttribPointer(position_location_, 2, GL_FLOAT, GL_FALSE,
- 4 * sizeof(GLfloat), offsets[0]);
- gl_->EnableVertexAttribArray(position_location_);
-
- gl_->VertexAttribPointer(texcoord_location_, 2, GL_FLOAT, GL_FALSE,
- 4 * sizeof(GLfloat), offsets[1]);
- gl_->EnableVertexAttribArray(texcoord_location_);
-
- // Always sample from the first texture unit.
- gl_->Uniform1i(texture_location_, 0);
-
- // Convert |src_rect| from pixel coordinates to texture coordinates. The
- // source texture coordinates are in the range [0.0,1.0] for each dimension,
- // but the sampling rect may slightly "spill" outside that range (e.g., for
- // scaler overscan).
- GLfloat src_rect_texcoord[4] = {
- src_rect.x() / src_texture_size.width(),
- src_rect.y() / src_texture_size.height(),
- src_rect.width() / src_texture_size.width(),
- src_rect.height() / src_texture_size.height(),
- };
- if (flip_y) {
- src_rect_texcoord[1] += src_rect_texcoord[3];
- src_rect_texcoord[3] *= -1.0f;
- }
- gl_->Uniform4fv(src_rect_location_, 1, src_rect_texcoord);
-
- // Set shader-specific uniform inputs. The |scaling_vector| is the ratio of
- // the number of source pixels sampled per dest pixels output. It is used by
- // the shader programs to locate distinct texels from the source texture, and
- // sample them at the appropriate offset to produce each output texel.
- switch (shader_) {
- case Shader::BILINEAR:
- break;
-
- case Shader::BILINEAR2:
- case Shader::BILINEAR3:
- case Shader::BILINEAR4:
- case Shader::BICUBIC_HALF_1D:
- case Shader::PLANAR_CHANNEL_0:
- case Shader::PLANAR_CHANNEL_1:
- case Shader::PLANAR_CHANNEL_2:
- case Shader::PLANAR_CHANNEL_3:
- case Shader::I422_NV61_MRT:
- case Shader::DEINTERLEAVE_PAIRWISE_MRT:
- case Shader::PLANAR_CHANNELS_1_2:
- switch (primary_axis) {
- case HORIZONTAL:
- gl_->Uniform2f(scaling_vector_location_,
- src_rect_texcoord[2] / dst_size.width(), 0.0);
- break;
- case VERTICAL:
- gl_->Uniform2f(scaling_vector_location_, 0.0,
- src_rect_texcoord[3] / dst_size.height());
- break;
- }
- break;
-
- case Shader::BILINEAR2X2:
- gl_->Uniform2f(scaling_vector_location_,
- src_rect_texcoord[2] / dst_size.width(),
- src_rect_texcoord[3] / dst_size.height());
- break;
-
- case Shader::BICUBIC_UPSCALE:
- gl_->Uniform2f(src_pixelsize_location_, src_texture_size.width(),
- src_texture_size.height());
- // For this shader program, the |scaling_vector| has an alternate meaning:
- // It is only being used to select whether bicubic sampling is stepped in
- // the X or the Y direction.
- gl_->Uniform2f(scaling_vector_location_,
- primary_axis == HORIZONTAL ? 1.0 : 0.0,
- primary_axis == VERTICAL ? 1.0 : 0.0);
- break;
- }
-}
-
-GLScaler::ScalerStage::ScalerStage(gpu::gles2::GLES2Interface* gl,
- GLScaler::Shader shader,
- GLScaler::Axis primary_axis,
- const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to)
- : gl_(gl),
- shader_(shader),
- primary_axis_(primary_axis),
- scale_from_(scale_from),
- scale_to_(scale_to) {
- DCHECK(gl_);
-}
-
-GLScaler::ScalerStage::~ScalerStage() {
- if (dest_framebuffer_) {
- gl_->DeleteFramebuffers(1, &dest_framebuffer_);
- }
- if (intermediate_texture_) {
- gl_->DeleteTextures(1, &intermediate_texture_);
- }
-}
-
-void GLScaler::ScalerStage::ScaleToMultipleOutputs(
- GLuint src_texture,
- gfx::Size src_texture_size,
- const gfx::Vector2d& src_offset,
- GLuint dest_texture_0,
- GLuint dest_texture_1,
- const gfx::Rect& output_rect) {
- if (output_rect.IsEmpty())
- return; // No work to do.
-
- // Make a recursive call to the "input" ScalerStage to produce an intermediate
- // texture for this stage to source from. Adjust src_* variables to use the
- // intermediate texture as input.
- //
- // If there is no input stage, simply modify |src_rect| to account for the
- // overall |src_offset| and Y-flip.
- gfx::RectF src_rect = ToSourceRect(output_rect);
- if (input_stage_) {
- const gfx::Rect input_rect = ToInputRect(src_rect);
- EnsureIntermediateTextureDefined(input_rect.size());
- input_stage_->ScaleToMultipleOutputs(src_texture, src_texture_size,
- src_offset, intermediate_texture_, 0,
- input_rect);
- src_texture = intermediate_texture_;
- src_texture_size = intermediate_texture_size_;
- DCHECK(!is_flipped_source_);
- src_rect -= input_rect.OffsetFromOrigin();
- } else {
- if (is_flipped_source_) {
- src_rect.set_x(src_rect.x() + src_offset.x());
- src_rect.set_y(src_texture_size.height() - src_rect.bottom() -
- src_offset.y());
- } else {
- src_rect += src_offset;
- }
- }
-
- // Attach the output texture(s) to the framebuffer.
- if (!dest_framebuffer_) {
- gl_->GenFramebuffers(1, &dest_framebuffer_);
- }
- gl_->BindFramebuffer(GL_FRAMEBUFFER, dest_framebuffer_);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- dest_texture_0, 0);
- if (dest_texture_1 > 0) {
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1,
- GL_TEXTURE_2D, dest_texture_1, 0);
- }
-
- // Bind to the source texture and set the texture sampler to use bilinear
- // filtering and clamp-to-edge, as required by all shader programs.
- //
- // It would be better to stash the existing parameter values, and restore them
- // back later. However, glGetTexParameteriv() currently requires a blocking
- // call to the GPU service, which is extremely costly performance-wise.
- gl_->ActiveTexture(GL_TEXTURE0);
- gl_->BindTexture(GL_TEXTURE_2D, src_texture);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- // Prepare the shader program for drawing.
- DCHECK(program_);
- program_->UseProgram(src_texture_size, src_rect, output_rect.size(),
- primary_axis_, flip_output_);
-
- // Execute the draw.
- gl_->Viewport(0, 0, output_rect.width(), output_rect.height());
- const GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1};
- if (dest_texture_1 > 0) {
- gl_->DrawBuffersEXT(2, buffers);
- }
- gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- if (dest_texture_1 > 0) {
- // Set the draw buffers back, to not disrupt external operations.
- gl_->DrawBuffersEXT(1, buffers);
- }
-
- gl_->BindTexture(GL_TEXTURE_2D, 0);
- gl_->BindFramebuffer(GL_FRAMEBUFFER, 0);
-}
-
-gfx::RectF GLScaler::ScalerStage::ToSourceRect(
- const gfx::Rect& output_rect) const {
- return gfx::ScaleRect(gfx::RectF(output_rect),
- static_cast<float>(scale_from_.x()) / scale_to_.x(),
- static_cast<float>(scale_from_.y()) / scale_to_.y());
-}
-
-gfx::Rect GLScaler::ScalerStage::ToInputRect(gfx::RectF source_rect) const {
- int overscan_x = 0;
- int overscan_y = 0;
- switch (shader_) {
- case Shader::BILINEAR:
- case Shader::BILINEAR2:
- case Shader::BILINEAR3:
- case Shader::BILINEAR4: {
- // These shaders sample 1 or more points along the primary axis, and only
- // 1 point in the other direction, in order to produce each output pixel.
- // The amount of overscan is always 0 or 1 pixel along the primary axis,
- // and this can be determined by looking at the upper-left-most source
- // texture sampling point: If this point is to the left of the middle of
- // the upper-left-most source pixel, the texture sampler will also read
- // the pixel to the left of that (for linear interpolation). Similar
- // behavior can occur towards the right, upwards, and downwards at the
- // source boundaries.
- int threshold;
- switch (shader_) {
- default:
- threshold = 1;
- break;
- case Shader::BILINEAR2:
- threshold = 2;
- break;
- case Shader::BILINEAR3:
- threshold = 3;
- break;
- case Shader::BILINEAR4:
- threshold = 4;
- break;
- }
- switch (primary_axis_) {
- case HORIZONTAL:
- if (scale_from_.x() < threshold * scale_to_.x()) {
- overscan_x = 1;
- }
- if (scale_from_.y() < scale_to_.y()) {
- overscan_y = 1;
- }
- break;
- case VERTICAL:
- if (scale_from_.x() < scale_to_.x()) {
- overscan_x = 1;
- }
- if (scale_from_.y() < threshold * scale_to_.y()) {
- overscan_y = 1;
- }
- break;
- }
- break;
- }
-
- case Shader::BILINEAR2X2:
- // This shader samples 2 points along both axes, and the overscan is 0 or
- // 1 pixel in both directions (same explanation as for the other BILINEAR
- // shaders).
- if (scale_from_.x() < 2 * scale_to_.x()) {
- overscan_x = 1;
- }
- if (scale_from_.y() < 2 * scale_to_.y()) {
- overscan_y = 1;
- }
- break;
-
- case Shader::BICUBIC_UPSCALE:
- // For each output pixel, this shader always reads 2 pixels about the
- // source position in one dimension, and has no overscan in the other
- // dimension.
- if (scale_from_.x() < scale_to_.x()) {
- DCHECK_EQ(HORIZONTAL, primary_axis_);
- overscan_x = 2;
- } else if (scale_from_.y() < scale_to_.y()) {
- DCHECK_EQ(VERTICAL, primary_axis_);
- overscan_y = 2;
- } else if (scale_from_ == scale_to_) {
- // Special case: When not scaling, the math in the shader will resolve
- // to just outputting the value for a single source pixel. The shader
- // will sample surrounding pixels, but then apply a zero weight to them
- // during convolution. Thus, there is effectively no overscan.
- NOTREACHED(); // This is a crazy-expensive way to do a 1:1 copy!
- } else {
- NOTREACHED(); // Downscaling is meaningless.
- }
- break;
-
- case Shader::BICUBIC_HALF_1D: {
- // For each output pixel, this shader always reads 4 pixels about the
- // source position in one dimension, and has no overscan in the other
- // dimension. However, since the source position always has a distance
- // >= 1 inside the "logical" bounds, there can never be more than 3 pixels
- // of overscan.
- if (scale_from_.x() == 2 * scale_to_.x()) {
- DCHECK_EQ(HORIZONTAL, primary_axis_);
- overscan_x = 3;
- } else if (scale_from_.y() == 2 * scale_to_.y()) {
- DCHECK_EQ(VERTICAL, primary_axis_);
- overscan_y = 3;
- } else {
- // Anything but a half-downscale in one dimension is meaningless.
- NOTREACHED();
- }
- break;
- }
-
- case Shader::PLANAR_CHANNEL_0:
- case Shader::PLANAR_CHANNEL_1:
- case Shader::PLANAR_CHANNEL_2:
- case Shader::PLANAR_CHANNEL_3:
- case Shader::I422_NV61_MRT:
- case Shader::PLANAR_CHANNELS_1_2:
- // All of these sample 4x1 source pixels to produce each output "pixel".
- // There is no overscan. They can also be combined with a bilinear
- // downscale, but not an upscale.
- DCHECK_GE(scale_from_.x(), 4 * scale_to_.x());
- DCHECK_EQ(HORIZONTAL, primary_axis_);
- break;
-
- case Shader::DEINTERLEAVE_PAIRWISE_MRT:
- // This shader samples 2x1 source pixels to produce each output "pixel".
- // There is no overscan. It can also be combined with a bilinear
- // downscale, but not an upscale.
- DCHECK_GE(scale_from_.x(), 2 * scale_to_.x());
- DCHECK_EQ(HORIZONTAL, primary_axis_);
- break;
- }
-
- source_rect.Inset(gfx::InsetsF::VH(-overscan_y, -overscan_x));
- return gfx::ToEnclosingRect(source_rect);
-}
-
-void GLScaler::ScalerStage::EnsureIntermediateTextureDefined(
- const gfx::Size& size) {
- // Reallocate a new texture, if needed.
- if (!intermediate_texture_) {
- gl_->GenTextures(1, &intermediate_texture_);
- }
- if (intermediate_texture_size_ != size) {
- gl_->BindTexture(GL_TEXTURE_2D, intermediate_texture_);
- // Note: Not setting the filter or wrap parameters on the texture here
- // because that will be done in ScaleToMultipleOutputs() anyway.
- gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
- GL_RGBA, program_->texture_type(), nullptr);
- intermediate_texture_size_ = size;
- }
-}
-
-std::ostream& operator<<(std::ostream& out, const GLScaler& scaler) {
- if (!scaler.chain_) {
- return (out << "[GLScaler NOT configured]");
- }
-
- out << "Output";
- const GLScaler::ScalerStage* const final_stage = scaler.chain_.get();
- for (auto* stage = final_stage; stage; stage = stage->input_stage()) {
- out << u8" ← {" << GLScaler::GetShaderName(stage->shader());
- if (stage->shader_program()) {
- switch (stage->shader_program()->texture_type()) {
- case GL_FLOAT:
- out << "/highp";
- break;
- case GL_HALF_FLOAT_OES:
- out << "/mediump";
- break;
- default:
- out << "/lowp";
- break;
- }
- }
- if (stage->flip_output()) {
- out << "+flip_y";
- }
- if (stage->scale_from() == stage->scale_to()) {
- out << " copy";
- } else {
- out << ' ' << stage->scale_from().ToString() << " to "
- << stage->scale_to().ToString();
- }
- if (!stage->input_stage() &&
- scaler.params_.source_color_space != scaler.scaling_color_space_) {
- out << ", with color x-form "
- << scaler.params_.source_color_space.ToString() << " to "
- << scaler.scaling_color_space_.ToString();
- }
- if (stage == final_stage) {
- if (scaler.params_.output_color_space != scaler.scaling_color_space_) {
- out << ", with color x-form to "
- << scaler.params_.output_color_space.ToString();
- }
- for (int i = 0; i < 2; ++i) {
- if (scaler.params_.swizzle[i] != GL_RGBA) {
- out << ", with swizzle(" << i << ')';
- }
- }
- }
- out << '}';
- }
- out << u8" ← Source";
- return out;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_scaler.h b/chromium/components/viz/common/gl_scaler.h
deleted file mode 100644
index 99013e8cadf..00000000000
--- a/chromium/components/viz/common/gl_scaler.h
+++ /dev/null
@@ -1,538 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_COMMON_GL_SCALER_H_
-#define COMPONENTS_VIZ_COMMON_GL_SCALER_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <ostream>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "base/memory/scoped_refptr.h"
-#include "components/viz/common/gpu/context_lost_observer.h"
-#include "components/viz/common/viz_common_export.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/geometry/vector2d.h"
-
-namespace gfx {
-class ColorTransform;
-} // namespace gfx
-
-namespace viz {
-
-class ContextProvider;
-
-// A high-performance texture scaler for use with an OpenGL ES 2.0 context. It
-// can be configured to operate at different quality levels, manages/converts
-// color spaces, and optionally re-arranges/formats data in output textures for
-// use with more-efficient texture readback pipelines.
-class VIZ_COMMON_EXPORT GLScaler final : public ContextLostObserver {
- public:
- struct VIZ_COMMON_EXPORT Parameters {
- // Relative scale from/to factors. Both of these must be non-zero.
- gfx::Vector2d scale_from = gfx::Vector2d(1, 1);
- gfx::Vector2d scale_to = gfx::Vector2d(1, 1);
-
- // The color space of the source texture and the desired color space of the
- // output texture. If |source_color_space| is not set (or invalid), sRGB is
- // assumed. If |output_color_space| is not set (or invalid), the source
- // color space is assumed.
- gfx::ColorSpace source_color_space;
- gfx::ColorSpace output_color_space;
-
- // Enable color management heuristics, using higher precision texture and
- // gamma-aware scaling?
- //
- // When disabled, the gamma of the source color space and other concerns are
- // ignored and 8-bit precision is used.
- //
- // When enabled, scaling occurs in a linear color space with 16-bit floats.
- // This produces excellent results for virtually all color spaces while
- // typically requiring twice the memory and execution resources. The caller
- // must ensure the GL context supports the use of GL_RGBA16F format
- // textures.
- //
- // Relevant reading: http://www.ericbrasseur.org/gamma.html
- bool enable_precise_color_management = false;
-
- // Selects the trade-off between quality and speed.
- enum class Quality : int8_t {
- // Bilinear single pass. Fastest possible. Do not use this unless the GL
- // implementation is so slow that the other quality options won't work.
- FAST,
-
- // Bilinear upscale + N * 50% bilinear downscales. This is still fast
- // enough for general-purpose use, and image quality is nearly as good as
- // BEST when downscaling.
- GOOD,
-
- // Bicubic upscale + N * 50% bicubic downscales. Produces very good
- // quality scaled images, but it's 2-8x slower than the "GOOD" quality.
- BEST,
- } quality = Quality::GOOD;
-
- // Is the source texture Y-flipped (i.e., the origin is the lower-left
- // corner and not the upper-left corner)? Most GL textures are Y-flipped.
- // This information is required so that the scaler can correctly compute the
- // sampling region.
- bool is_flipped_source = true;
-
- // Should the output be vertically flipped? Usually, this is used when the
- // source is not Y-flipped, but the destination texture needs to be. Or, it
- // can be used to draw the final output upside-down to avoid having to copy
- // the rows in reverse order after a glReadPixels().
- bool flip_output = false;
-
- // Optionally rearrange the image data for export. Generally, this is used
- // to make later readback steps more efficient (e.g., using glReadPixels()
- // will produce the raw bytes in their correct locations).
- //
- // Output textures are assumed to be using one of the 4-channel RGBA
- // formats. While it may be more "proper" to use a single-component texture
- // format for the planar-oriented image data, not all GL implementations
- // support the use of those formats. However, all must support at least
- // GL_RGBA. Therefore, each RGBA pixel is treated as a generic "vec4" (a
- // quad of values).
- //
- // When using this feature, it is usually necessary to adjust the
- // |output_rect| passed to Scale() or ScaleToMultipleOutputs(). See notes
- // below.
- enum class ExportFormat : int8_t {
- // Do not rearrange the image data:
- //
- // (interleaved quads) (interleaved quads)
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
- // RGBA RGBA RGBA RGBA --> RGBA RGBA RGBA RGBA
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
- INTERLEAVED_QUADS,
-
- // Select one color channel, packing each of 4 pixels' values into the 4
- // elements of one output quad.
- //
- // For example, for CHANNEL_0:
- //
- // (interleaved quads) (channel 0)
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA RRRR RRRR
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA --> RRRR RRRR
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA RRRR RRRR
- //
- // Note: Because of this packing, the horizontal coordinates of the
- // |output_rect| used with Scale() should be divided by 4.
- CHANNEL_0,
- CHANNEL_1,
- CHANNEL_2,
- CHANNEL_3,
-
- // I422 sampling, delivered via two output textures (NV61 format): The
- // first texture is produced the same as CHANNEL_0, while the second
- // texture contains CHANNEL_1 and CHANNEL_2 at half-width interleaved and
- // full-height. For example, if this is combined with RGB→YUV color space
- // conversion:
- //
- // (interleaved quads)
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
- // RGBA RGBA RGBA RGBA RGBA RGBA RGBA RGBA
- // |
- // | (luma plane) (chroma, interleaved)
- // | YYYY YYYY UVUV UVUV
- // +---> { YYYY YYYY + UVUV UVUV }
- // YYYY YYYY UVUV UVUV
- //
- // Note: Because of this packing, the horizontal coordinates of the
- // |output_rect| used with ScaleToMultipleOutputs() should be divided by
- // 4.
- // Note 2: This requires a GL context that supports multiple render
- // targets with at least two draw buffers.
- NV61,
-
- // Deinterleave into two output textures.
- //
- // UVUV UVUV UUUU VVVV
- // UVUV UVUV --> { UUUU + VVVV }
- // UVUV UVUV UUUU VVVV
- //
- // Note: Because of this packing, the horizontal coordinates of the
- // |output_rect| used with ScaleToMultipleOutputs() should be divided by
- // 2.
- // Note 2: This requires a GL context that supports multiple render
- // targets with at least two draw buffers.
- DEINTERLEAVE_PAIRWISE,
-
- // Select CHANNEL_1 and CHANNEL_2, packing each 2-channel pair from
- // 4-pixel values into the 2 elements of one output quad. The channels
- // will be selected at half-width and full height. This should be
- // equivalent to the second texture produced by ExportFormat::NV61 (see
- // above). If used on textures after they have gone through RGB→YUV color
- // space conversion, the transformation is:
- //
- // (interleaved quads) (channels 1 & 2)
- // YUVx YUVx YUVx YUVx YUVx YUVx YUVx YUVx UVUV UVUV
- // YUVx YUVx YUVx YUVx YUVx YUVx YUVx YUVx --> UVUV UVUV
- // YUVx YUVx YUVx YUVx YUVx YUVx YUVx YUVx UVUV UVUV
- //
- // Note: Because of this packing, the horizontal coordinates of the
- // |output_rect| used with Scale() should be divided by 4.
- UV_CHANNELS,
- } export_format = ExportFormat::INTERLEAVED_QUADS;
-
- // Optionally swizzle the ordering of the values in each output quad. If the
- // output of the scaler is not going to be read back (e.g., used with
- // glReadPixels()), simply leave these unchanged. Otherwise, changing this
- // allows a read-back pipeline to use the native format of the platform to
- // avoid having to perform extra "BGRA⇄RGBA swizzle" memcpy's. Usually, this
- // should match the format to be used with glReadPixels(), and that should
- // match the GL_IMPLEMENTATION_COLOR_READ_FORMAT.
- GLenum swizzle[2] = {
- GL_RGBA, // For |dest_texture_0|.
- GL_RGBA, // For |dest_texture_1|.
- };
-
- Parameters();
- Parameters(const Parameters& other);
- ~Parameters();
- };
-
- explicit GLScaler(ContextProvider* context_provider);
-
- GLScaler(const GLScaler&) = delete;
- GLScaler& operator=(const GLScaler&) = delete;
-
- ~GLScaler() final;
-
- // Returns true if the GL context provides the necessary support for enabling
- // precise color management (see Parameters::enable_precise_color_management).
- bool SupportsPreciseColorManagement() const;
-
- // Returns the maximum number of simultaneous drawing buffers supported by the
- // GL context. Certain Parameters can only be used when this is more than 1.
- int GetMaxDrawBuffersSupported() const;
-
- // [Re]Configure the scaler with the given |new_params|. Returns true on
- // success, or false on failure.
- [[nodiscard]] bool Configure(const Parameters& new_params);
-
- // Returns the currently-configured and resolved Parameters. Note that these
- // Parameters might not be exactly the same as those that were passed to
- // Configure() because some properties (e.g., color spaces) are auto-resolved;
- // however, ParametersAreEquivalent() will still return true. Results are
- // undefined if Configure() has never been called successfully.
- const Parameters& params() const { return params_; }
-
- // Scales a portion of |src_texture| and draws the result into |dest_texture|
- // at offset (0, 0). Returns true to indicate success, or false if this
- // GLScaler is not valid.
- //
- // |src_texture_size| is the full, allocated size of the |src_texture|. This
- // is required for computing texture coordinate transforms (and only because
- // the OpenGL ES 2.0 API lacks the ability to query this info).
- //
- // |src_offset| is the offset in the source texture corresponding to point
- // (0,0) in the source/output coordinate spaces. This prevents the need for
- // extra texture copies just to re-position the source coordinate system.
- //
- // |output_rect| selects the region to draw (in the scaled, not the source,
- // coordinate space). This is used to save work in cases where only a portion
- // needs to be re-scaled. The implementation will back-compute, internally, to
- // determine the region of the |src_texture| to sample.
- //
- // WARNING: The output will always be placed at (0, 0) in the |dest_texture|,
- // and not at |output_rect.origin()|.
- //
- // Note that the |src_texture| will have the min/mag filter set to GL_LINEAR
- // and wrap_s/t set to CLAMP_TO_EDGE in this call.
- [[nodiscard]] bool Scale(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- GLuint dest_texture,
- const gfx::Rect& output_rect) {
- return ScaleToMultipleOutputs(src_texture, src_texture_size, src_offset,
- dest_texture, 0, output_rect);
- }
-
- // Same as above, but for use cases where there are two output textures drawn
- // (see Parameters::ExportFormat).
- [[nodiscard]] bool ScaleToMultipleOutputs(GLuint src_texture,
- const gfx::Size& src_texture_size,
- const gfx::Vector2d& src_offset,
- GLuint dest_texture_0,
- GLuint dest_texture_1,
- const gfx::Rect& output_rect);
-
- // Returns true if from:to represent the same scale ratio as that specified in
- // |params|.
- static bool ParametersHasSameScaleRatio(const Parameters& params,
- const gfx::Vector2d& from,
- const gfx::Vector2d& to);
-
- // Returns true if configuring a GLScaler with either |a| or |b| will produce
- // identical behaviors and results.
- static bool ParametersAreEquivalent(const Parameters& a, const Parameters& b);
-
- private:
- friend class GLScalerOverscanPixelTest;
- friend class GLScalerShaderPixelTest;
- friend VIZ_COMMON_EXPORT std::ostream& operator<<(std::ostream&,
- const GLScaler&);
-
- using GLES2Interface = gpu::gles2::GLES2Interface;
-
- enum Axis { HORIZONTAL = 0, VERTICAL = 1 };
-
- // The shaders used by each stage in the scaling pipeline.
- enum class Shader : int8_t {
- BILINEAR,
- BILINEAR2,
- BILINEAR3,
- BILINEAR4,
- BILINEAR2X2,
- BICUBIC_UPSCALE,
- BICUBIC_HALF_1D,
- PLANAR_CHANNEL_0,
- PLANAR_CHANNEL_1,
- PLANAR_CHANNEL_2,
- PLANAR_CHANNEL_3,
- PLANAR_CHANNELS_1_2,
- I422_NV61_MRT,
- DEINTERLEAVE_PAIRWISE_MRT,
- };
-
- // A cached, re-usable shader program that performs one step in the scaling
- // pipeline.
- class VIZ_COMMON_EXPORT ShaderProgram {
- public:
- ShaderProgram(GLES2Interface* gl,
- Shader shader,
- GLenum texture_type,
- const gfx::ColorTransform* color_transform,
- const GLenum swizzle[2]);
-
- ShaderProgram(const ShaderProgram&) = delete;
- ShaderProgram& operator=(const ShaderProgram&) = delete;
-
- ~ShaderProgram();
-
- Shader shader() const { return shader_; }
- GLenum texture_type() const { return texture_type_; }
-
- // UseProgram must be called with GL_ARRAY_BUFFER bound to a vertex
- // attribute buffer. |src_texture_size| is the size of the entire source
- // texture, regardless of which region is to be sampled. |src_rect| is the
- // source region, not including overscan pixels past the edges.
- // |primary_axis| determines whether multiple texture samplings occur in one
- // direction or the other (for some shaders). Note that this cannot
- // necessarily be determined by just comparing the src and dst sizes.
- // |flip_y| causes the |src_rect| to be scanned upside-down, to produce a
- // vertically-flipped result.
- void UseProgram(const gfx::Size& src_texture_size,
- const gfx::RectF& src_rect,
- const gfx::Size& dst_size,
- Axis primary_axis,
- bool flip_y);
-
- // GL_ARRAY_BUFFER data that must be bound when drawing with a
- // ShaderProgram. These are the vertex attributes that will sweep the entire
- // source area when executing the program. They represent triangle strip
- // coordinates: The first two columns are (x,y) values interpolated to
- // produce the vertex coordinates in object space, while the latter two
- // columns are (s,t) values interpolated to produce the texture coordinates
- // that correspond to the vertex coordinates.
- static const GLfloat kVertexAttributes[16];
-
- private:
- const raw_ptr<GLES2Interface> gl_;
- const Shader shader_;
- const GLenum texture_type_;
-
- // A program for copying a source texture into a destination texture.
- const GLuint program_;
-
- // The location of the position in the program.
- GLint position_location_ = -1;
- // The location of the texture coordinate in the program.
- GLint texcoord_location_ = -1;
- // The location of the source texture in the program.
- GLint texture_location_ = -1;
- // The location of the texture coordinate of the source rectangle in the
- // program.
- GLint src_rect_location_ = -1;
- // Location of size of source image in pixels.
- GLint src_pixelsize_location_ = -1;
- // Location of vector for scaling ratio between source and dest textures.
- GLint scaling_vector_location_ = -1;
- };
-
- // One scaling stage in a chain of scaler pipeline stages. Each ScalerStage
- // owns the previous ScalerStage in the chain: At execution time, a "working
- // backwards" approach is used: The previous "input" stage renders an
- // intermediate result that will be used as input for the current stage.
- //
- // Each ScalerStage caches textures and framebuffers to avoid reallocating
- // them for each separate image scaling, which can be expensive on some
- // platforms/drivers.
- class VIZ_COMMON_EXPORT ScalerStage {
- public:
- ScalerStage(GLES2Interface* gl,
- Shader shader,
- Axis primary_axis,
- const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to);
-
- ScalerStage(const ScalerStage&) = delete;
- ScalerStage& operator=(const ScalerStage&) = delete;
-
- ~ScalerStage();
-
- Shader shader() const { return shader_; }
- const gfx::Vector2d& scale_from() const { return scale_from_; }
- const gfx::Vector2d& scale_to() const { return scale_to_; }
-
- ScalerStage* input_stage() const { return input_stage_.get(); }
- void set_input_stage(std::unique_ptr<ScalerStage> stage) {
- input_stage_ = std::move(stage);
- }
- std::unique_ptr<ScalerStage> take_input_stage() {
- return std::move(input_stage_);
- }
-
- ShaderProgram* shader_program() const { return program_; }
- void set_shader_program(ShaderProgram* program) { program_ = program; }
-
- bool is_flipped_source() const { return is_flipped_source_; }
- void set_is_flipped_source(bool flipped) { is_flipped_source_ = flipped; }
-
- bool flip_output() const { return flip_output_; }
- void set_flip_output(bool flip) { flip_output_ = flip; }
-
- void ScaleToMultipleOutputs(GLuint src_texture,
- gfx::Size src_texture_size,
- const gfx::Vector2d& src_offset,
- GLuint dest_texture_0,
- GLuint dest_texture_1,
- const gfx::Rect& output_rect);
-
- private:
- friend class GLScalerOverscanPixelTest;
-
- // Returns the given |output_rect| mapped to the input stage's coordinate
- // system.
- gfx::RectF ToSourceRect(const gfx::Rect& output_rect) const;
-
- // Returns the given |source_rect| padded to include the overscan pixels the
- // shader program will access.
- gfx::Rect ToInputRect(gfx::RectF source_rect) const;
-
- // Generates the intermediate texture and/or re-defines it if its size has
- // changed.
- void EnsureIntermediateTextureDefined(const gfx::Size& size);
-
- const raw_ptr<GLES2Interface> gl_;
- const Shader shader_;
- const Axis primary_axis_;
- const gfx::Vector2d scale_from_;
- const gfx::Vector2d scale_to_;
-
- std::unique_ptr<ScalerStage> input_stage_;
- raw_ptr<ShaderProgram> program_ = nullptr;
- bool is_flipped_source_ = false;
- bool flip_output_ = false;
-
- GLuint intermediate_texture_ = 0;
- gfx::Size intermediate_texture_size_;
- GLuint dest_framebuffer_ = 0;
- };
-
- // ContextLostObserver implementation.
- void OnContextLost() final;
-
- // Returns a cached ShaderProgram, creating one on-demand if necessary.
- ShaderProgram* GetShaderProgram(Shader shader,
- GLenum texture_type,
- const gfx::ColorTransform* color_transform,
- const GLenum swizzle[2]);
-
- // Create a scaling chain using the bilinear shaders.
- static std::unique_ptr<ScalerStage> CreateAGoodScalingChain(
- gpu::gles2::GLES2Interface* gl,
- const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to);
-
- // Create a scaling chain using the bicubic shaders.
- static std::unique_ptr<ScalerStage> CreateTheBestScalingChain(
- gpu::gles2::GLES2Interface* gl,
- const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to);
-
- // Modifies |chain| by appending an export stage, to rearrange the image data
- // according to the requested |export_format|. In some cases, this will delete
- // the final stage in |chain| before appending the export stage.
- static std::unique_ptr<ScalerStage> MaybeAppendExportStage(
- gpu::gles2::GLES2Interface* gl,
- std::unique_ptr<ScalerStage> chain,
- Parameters::ExportFormat export_format);
-
- // Returns the other of the two axes.
- static Axis TheOtherAxis(Axis axis);
-
- // Returns the name of the |shader| in string form, for logging purposes.
- static const char* GetShaderName(Shader shader);
-
- // Returns true if the given |gl| context mentions all of |names| in its
- // extensions string.
- static bool AreAllGLExtensionsPresent(gpu::gles2::GLES2Interface* gl,
- const std::vector<std::string>& names);
-
- // The provider of the GL context. This is non-null while the GL context is
- // valid and GLScaler is observing for context loss.
- raw_ptr<ContextProvider> context_provider_;
-
- // Set by Configure() to the resolved set of Parameters.
- Parameters params_;
-
- // If set to true, half-float textures are supported. This is lazy-initialized
- // by SupportsPreciseColorManagement().
- mutable absl::optional<bool> supports_half_floats_;
-
- // The maximum number of simultaneous draw buffers, lazy-initialized by
- // GetMaxDrawBuffersSupported(). -1 means "not yet known."
- mutable int max_draw_buffers_ = -1;
-
- // Cache of ShaderPrograms. The cache key consists of fields that correspond
- // to the arguments of GetShaderProgram(): the shader, the texture format, the
- // source and output color spaces (color transform), and the two swizzles.
- using ShaderCacheKey = std::
- tuple<Shader, GLenum, gfx::ColorSpace, gfx::ColorSpace, GLenum, GLenum>;
- std::map<ShaderCacheKey, ShaderProgram> shader_programs_;
-
- // The GL_ARRAY_BUFFER that holds the vertices and the texture coordinates
- // data for sweeping the source area when a ScalerStage draws a quad (to
- // execute its shader program).
- GLuint vertex_attributes_buffer_ = 0;
-
- // The chain of ScalerStages.
- std::unique_ptr<ScalerStage> chain_;
-
- // The color space in which the scaling stages operate.
- gfx::ColorSpace scaling_color_space_;
-};
-
-// For logging.
-VIZ_COMMON_EXPORT std::ostream& operator<<(std::ostream& out,
- const GLScaler& scaler);
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_COMMON_GL_SCALER_H_
diff --git a/chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc b/chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc
deleted file mode 100644
index 30f4810b0e5..00000000000
--- a/chromium/components/viz/common/gl_scaler_overscan_pixeltest.cc
+++ /dev/null
@@ -1,532 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_scaler.h"
-
-#include "build/build_config.h"
-#include "cc/test/pixel_test.h"
-#include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/test/gl_scaler_test_util.h"
-#include "gpu/GLES2/gl2chromium.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkRect.h"
-
-namespace viz {
-
-class GLScalerOverscanPixelTest : public cc::PixelTest,
- public GLScalerTestUtil {
- public:
- using Axis = GLScaler::Axis;
- using ScalerStage = GLScaler::ScalerStage;
- using Shader = GLScaler::Shader;
-
- bool AreMultipleRenderingTargetsSupported() const {
- return scaler_->GetMaxDrawBuffersSupported() > 1;
- }
-
- // Creates a ScalerStage chain consisting of a single stage having the given
- // configuration.
- void UseScaler(Shader shader,
- Axis primary_axis,
- const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to) {
- scaler_->chain_ = std::make_unique<ScalerStage>(gl_, shader, primary_axis,
- scale_from, scale_to);
- scaler_->chain_->set_shader_program(scaler_->GetShaderProgram(
- shader, GL_UNSIGNED_BYTE, nullptr, GLScaler::Parameters().swizzle));
- }
-
- // Converts the given |source_rect| into a possibly-larger one that includes
- // all of the pixels that would be sampled by the current scaler (i.e.,
- // including overscan). This uses the math of the internal implementation to
- // compute the values.
- gfx::Rect ToInputRect(gfx::Rect source_rect) {
- CHECK(scaler_ && scaler_->chain_);
- return scaler_->chain_->ToInputRect(gfx::RectF(source_rect));
- }
-
- // Renders images using the current scaler to auto-detect its overscan. This
- // does NOT use the internal implementation to compute the values, but instead
- // discovers them experimentally. This is used to confirm that: a) the scaler
- // behaves as ToInputRect() expects; and b) the math internal to ToInputRect()
- // is correct.
- //
- // The general approach is to upload a source image containing a blue box in
- // the center, surrounded by a red background. The size of the blue box is
- // varied: It starts out at a size encompassing more than all of the pixels to
- // be sampled by the scaler, and is gradually shrunk until the scaler's output
- // begins to include red "bleed-in." At that point, the overscan amount is
- // confirmed experimentally.
- gfx::Vector2d DetectScalerOverscan(const gfx::Vector2d& scale_from,
- const gfx::Vector2d& scale_to) {
- // Assume a source size three times the "scale from" width and height. This
- // allows for scaling the middle third of a source image, to test possible
- // bleed-in on all sides of the output.
- const gfx::Size src_size(scale_from.x() * 3, scale_from.y() * 3);
-
- // The requested output rect is the center third of the image, in the
- // destination coordinate space.
- const gfx::Rect dst_rect(
- src_size.width() / 3 * scale_to.x() / scale_from.x(),
- src_size.height() / 3 * scale_to.y() / scale_from.y(),
- src_size.width() / 3 * scale_to.x() / scale_from.x(),
- src_size.height() / 3 * scale_to.y() / scale_from.y());
- const GLuint dst_texture = texture_helper_->CreateTexture(dst_rect.size());
-
- // This is our "basis for comparison" image. If scaled output images match
- // this, then there is no bleed-in.
- SkBitmap output_without_bleed_in;
- {
- const bool did_scale =
- scaler_->Scale(texture_helper_->UploadTexture(CreateBlueBoxOnRedImage(
- src_size, gfx::Rect(src_size))),
- src_size, gfx::Vector2d(0, 0), dst_texture, dst_rect);
- CHECK(did_scale);
- output_without_bleed_in =
- texture_helper_->DownloadTexture(dst_texture, dst_rect.size());
- VLOG(2) << scale_from.ToString() << "→" << scale_to.ToString()
- << ": Output without bleed-in is "
- << cc::GetPNGDataUrl(output_without_bleed_in);
- }
-
- // Perform a linear search for the minimal overscan values that do not cause
- // the red bleed-in in the scaled output image. There are actually two
- // separate searches here, one horizontally and one vertically. Note that an
- // overscan result of -1 indicates a failed search and/or a broken
- // implementation.
- gfx::Vector2d min_overscan(5, 5);
- for (int is_horizontal = 1; is_horizontal >= 0; --is_horizontal) {
- while (min_overscan.x() >= 0 && min_overscan.y() >= 0) {
- // Decrease the overscan by one pixel (one dimension at a time).
- const gfx::Vector2d overscan(
- is_horizontal ? (min_overscan.x() - 1) : min_overscan.x(),
- is_horizontal ? min_overscan.y() : (min_overscan.y() - 1));
-
- // Create the source texture consisting of a centered blue box
- // surrounded by red.
- const gfx::Rect blue_rect(scale_from.x() - overscan.x(),
- scale_from.y() - overscan.y(),
- scale_from.x() + 2 * overscan.x(),
- scale_from.y() + 2 * overscan.y());
- const SkBitmap source_image =
- CreateBlueBoxOnRedImage(src_size, blue_rect);
- const bool did_scale = scaler_->Scale(
- texture_helper_->UploadTexture(source_image), src_size,
- gfx::Vector2d(0, 0), dst_texture, dst_rect);
- CHECK(did_scale);
- const SkBitmap output =
- texture_helper_->DownloadTexture(dst_texture, dst_rect.size());
-
- // Compare |output| with |output_without_bleed_in|. If they are
- // different, then the blue rect became too small.
- bool output_has_bleed_in = false;
- for (int y = 0; y < output.height(); ++y) {
- for (int x = 0; x < output.width(); ++x) {
- if (output.getColor(x, y) !=
- output_without_bleed_in.getColor(x, y)) {
- output_has_bleed_in = true;
- break;
- }
- }
- }
-
- VLOG(2) << scale_from.ToString() << "→" << scale_to.ToString()
- << ": Testing overscan=" << overscan.ToString() << std::endl
- << "\tSource image is " << cc::GetPNGDataUrl(source_image)
- << std::endl
- << "\tOutput image is " << cc::GetPNGDataUrl(output);
-
- if (output_has_bleed_in) {
- break; // Search complete: Red bleed-in detected.
- }
-
- min_overscan = overscan;
- }
- }
-
- return min_overscan;
- }
-
- static SkBitmap CreateBlueBoxOnRedImage(const gfx::Size& size,
- const gfx::Rect& blue_rect) {
- SkBitmap result = AllocateRGBABitmap(size);
- // Note: None of the color channel values should be close to 0 or 255. This
- // is because the bicubic scaler will generate values that overshoot and
- // clip, and this will mess-up detection of the number of overscan pixels.
- result.eraseColor(SkColorSetRGB(0xc0, 0x40, 0x40));
- result.erase(SkColorSetRGB(0x40, 0x40, 0xc0),
- SkIRect{blue_rect.x(), blue_rect.y(), blue_rect.right(),
- blue_rect.bottom()});
- return result;
- }
-
- protected:
- void SetUp() final {
- cc::PixelTest::SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
-
- scaler_ = std::make_unique<GLScaler>(context_provider());
- gl_ = context_provider()->ContextGL();
- CHECK(gl_);
- texture_helper_ = std::make_unique<GLScalerTestTextureHelper>(gl_);
- }
-
- void TearDown() final {
- texture_helper_.reset();
- gl_ = nullptr;
- scaler_.reset();
-
- cc::PixelTest::TearDown();
- }
-
- std::unique_ptr<GLScaler> scaler_;
- gpu::gles2::GLES2Interface* gl_ = nullptr;
- std::unique_ptr<GLScalerTestTextureHelper> texture_helper_;
-};
-
-namespace {
-constexpr gfx::Rect kTenByTenRect = gfx::Rect(10, 10, 10, 10);
-} // namespace
-
-TEST_F(GLScalerOverscanPixelTest, Bilinear) {
- constexpr struct {
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- gfx::Vector2d expected_overscan;
- } kTestCases[] = {
- // No scaling.
- {gfx::Vector2d(32, 20), gfx::Vector2d(32, 20), gfx::Vector2d(0, 0)},
-
- // Scale by 0.5X.
- {gfx::Vector2d(32, 20), gfx::Vector2d(16, 20), gfx::Vector2d(0, 0)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(32, 10), gfx::Vector2d(0, 0)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(16, 10), gfx::Vector2d(0, 0)},
-
- // Scale by 0.75X.
- {gfx::Vector2d(32, 20), gfx::Vector2d(24, 20), gfx::Vector2d(0, 0)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(32, 15), gfx::Vector2d(0, 0)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(24, 15), gfx::Vector2d(0, 0)},
-
- // Scale by 1.5X.
- {gfx::Vector2d(32, 20), gfx::Vector2d(48, 20), gfx::Vector2d(1, 0)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(32, 30), gfx::Vector2d(0, 1)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(48, 30), gfx::Vector2d(1, 1)},
-
- // Scale by 4X.
- {gfx::Vector2d(32, 20), gfx::Vector2d(128, 20), gfx::Vector2d(1, 0)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(32, 80), gfx::Vector2d(0, 1)},
- {gfx::Vector2d(32, 20), gfx::Vector2d(128, 80), gfx::Vector2d(1, 1)},
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message() << "scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(Shader::BILINEAR, Axis::HORIZONTAL, tc.scale_from, tc.scale_to);
- EXPECT_EQ(tc.expected_overscan,
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
-
- // Sanity-check that the internal math estimating the overscan is correct.
- gfx::Rect expected_input_rect = kTenByTenRect;
- expected_input_rect.Inset(
- gfx::Insets::VH(-tc.expected_overscan.y(), -tc.expected_overscan.x()));
- EXPECT_EQ(expected_input_rect, ToInputRect(kTenByTenRect));
- }
-}
-
-TEST_F(GLScalerOverscanPixelTest, TwoTapBilinear) {
- constexpr struct {
- Axis primary_axis;
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- gfx::Vector2d expected_overscan;
- } kTestCases[] = {
- // Scale by 0.25X in one direction only.
- {Axis::HORIZONTAL, gfx::Vector2d(64, 40), gfx::Vector2d(16, 40),
- gfx::Vector2d(0, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 40), gfx::Vector2d(64, 10),
- gfx::Vector2d(0, 0)},
-
- // Scale by 0.25X in one direction, 0.5X in the other.
- {Axis::HORIZONTAL, gfx::Vector2d(64, 40), gfx::Vector2d(16, 20),
- gfx::Vector2d(0, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 40), gfx::Vector2d(32, 10),
- gfx::Vector2d(0, 0)},
-
- // Scale by 0.75X (1.5X * 0.5X).
- {Axis::HORIZONTAL, gfx::Vector2d(64, 40), gfx::Vector2d(48, 40),
- gfx::Vector2d(1, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 40), gfx::Vector2d(64, 30),
- gfx::Vector2d(0, 1)},
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message() << "scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(Shader::BILINEAR2, tc.primary_axis, tc.scale_from, tc.scale_to);
- EXPECT_EQ(tc.expected_overscan,
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
-
- // Sanity-check that the internal math estimating the overscan is correct.
- gfx::Rect expected_input_rect = kTenByTenRect;
- expected_input_rect.Inset(
- gfx::Insets::VH(-tc.expected_overscan.y(), -tc.expected_overscan.x()));
- EXPECT_EQ(expected_input_rect, ToInputRect(kTenByTenRect));
- }
-}
-
-TEST_F(GLScalerOverscanPixelTest, ThreeTapBilinear) {
- constexpr struct {
- Axis primary_axis;
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- gfx::Vector2d expected_overscan;
- } kTestCases[] = {
- // Scale by 0.16...X in one direction only.
- {Axis::HORIZONTAL, gfx::Vector2d(66, 40), gfx::Vector2d(11, 40),
- gfx::Vector2d(0, 0)},
- {Axis::VERTICAL, gfx::Vector2d(32, 60), gfx::Vector2d(32, 10),
- gfx::Vector2d(0, 0)},
-
- // Scale by 0.16...X in one direction, 0.5X in the other.
- {Axis::HORIZONTAL, gfx::Vector2d(66, 40), gfx::Vector2d(11, 20),
- gfx::Vector2d(0, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 60), gfx::Vector2d(32, 10),
- gfx::Vector2d(0, 0)},
-
- // Scale by 0.75X (3.0X * 0.5X * 0.5X).
- {Axis::HORIZONTAL, gfx::Vector2d(64, 40), gfx::Vector2d(48, 40),
- gfx::Vector2d(1, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 40), gfx::Vector2d(64, 30),
- gfx::Vector2d(0, 1)},
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message() << "scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(Shader::BILINEAR3, tc.primary_axis, tc.scale_from, tc.scale_to);
- EXPECT_EQ(tc.expected_overscan,
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
-
- // Sanity-check that the internal math estimating the overscan is correct.
- gfx::Rect expected_input_rect = kTenByTenRect;
- expected_input_rect.Inset(
- gfx::Insets::VH(-tc.expected_overscan.y(), -tc.expected_overscan.x()));
- EXPECT_EQ(expected_input_rect, ToInputRect(kTenByTenRect));
- }
-}
-
-TEST_F(GLScalerOverscanPixelTest, FourTapBilinear) {
- constexpr struct {
- Axis primary_axis;
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- gfx::Vector2d expected_overscan;
- } kTestCases[] = {
- // Scale by 0.125X in one direction only.
- {Axis::HORIZONTAL, gfx::Vector2d(64, 40), gfx::Vector2d(8, 40),
- gfx::Vector2d(0, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 40), gfx::Vector2d(64, 5),
- gfx::Vector2d(0, 0)},
-
- // Scale by 0.125X in one direction, 0.5X in the other.
- {Axis::HORIZONTAL, gfx::Vector2d(64, 40), gfx::Vector2d(8, 20),
- gfx::Vector2d(0, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 40), gfx::Vector2d(32, 5),
- gfx::Vector2d(0, 0)},
-
- // Scale by 0.75X (6.0X * 0.5X * 0.5X * 0.5X).
- {Axis::HORIZONTAL, gfx::Vector2d(64, 40), gfx::Vector2d(48, 40),
- gfx::Vector2d(1, 0)},
- {Axis::VERTICAL, gfx::Vector2d(64, 40), gfx::Vector2d(64, 30),
- gfx::Vector2d(0, 1)},
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message() << "scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(Shader::BILINEAR4, tc.primary_axis, tc.scale_from, tc.scale_to);
- EXPECT_EQ(tc.expected_overscan,
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
-
- // Sanity-check that the internal math estimating the overscan is correct.
- gfx::Rect expected_input_rect = kTenByTenRect;
- expected_input_rect.Inset(
- gfx::Insets::VH(-tc.expected_overscan.y(), -tc.expected_overscan.x()));
- EXPECT_EQ(expected_input_rect, ToInputRect(kTenByTenRect));
- }
-}
-
-TEST_F(GLScalerOverscanPixelTest, TwoByTwoTapBilinear) {
- constexpr struct {
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- gfx::Vector2d expected_overscan;
- } kTestCases[] = {
- // Scale by 0.25X in both directions.
- {gfx::Vector2d(64, 40), gfx::Vector2d(16, 10), gfx::Vector2d(0, 0)},
-
- // Scale by 0.75X (1.5X * 0.5X) in one direction, 0.25X in the other.
- {gfx::Vector2d(64, 40), gfx::Vector2d(48, 10), gfx::Vector2d(1, 0)},
- {gfx::Vector2d(64, 40), gfx::Vector2d(16, 30), gfx::Vector2d(0, 1)},
-
- // Scale by 0.75X (1.5X * 0.5X) in both directions.
- {gfx::Vector2d(64, 40), gfx::Vector2d(48, 30), gfx::Vector2d(1, 1)},
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message() << "scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(Shader::BILINEAR2X2, Axis::HORIZONTAL, tc.scale_from,
- tc.scale_to);
- EXPECT_EQ(tc.expected_overscan,
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
-
- // Sanity-check that the internal math estimating the overscan is correct.
- gfx::Rect expected_input_rect = kTenByTenRect;
- expected_input_rect.Inset(
- gfx::Insets::VH(-tc.expected_overscan.y(), -tc.expected_overscan.x()));
- EXPECT_EQ(expected_input_rect, ToInputRect(kTenByTenRect));
- }
-}
-
-TEST_F(GLScalerOverscanPixelTest, BicubicUpscale) {
-#if BUILDFLAG(IS_ANDROID)
- // Unfortunately, on our current Android bots, there are some inaccuracies
- // introduced by the platform that seem to throw-off the pixel testing of the
- // bicubic sampler.
- constexpr bool kSkipDetectionTest = true;
- LOG(WARNING) << "Skipping overscan detection due to platform issues.";
-#else
- constexpr bool kSkipDetectionTest = false;
-#endif
-
- constexpr struct {
- Axis primary_axis;
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- gfx::Vector2d expected_overscan;
- } kTestCases[] = {
- // Scale by 1.5X, 2X, and 3.3...X horizontally.
- {Axis::HORIZONTAL, gfx::Vector2d(12, 10), gfx::Vector2d(18, 10),
- gfx::Vector2d(2, 0)},
- {Axis::HORIZONTAL, gfx::Vector2d(12, 10), gfx::Vector2d(24, 10),
- gfx::Vector2d(2, 0)},
- {Axis::HORIZONTAL, gfx::Vector2d(12, 10), gfx::Vector2d(40, 10),
- gfx::Vector2d(2, 0)},
-
- // Scale by 1.5X, 2X, and 3.3...X vertically.
- {Axis::VERTICAL, gfx::Vector2d(12, 10), gfx::Vector2d(12, 15),
- gfx::Vector2d(0, 2)},
- {Axis::VERTICAL, gfx::Vector2d(12, 10), gfx::Vector2d(12, 20),
- gfx::Vector2d(0, 2)},
- {Axis::VERTICAL, gfx::Vector2d(12, 9), gfx::Vector2d(12, 30),
- gfx::Vector2d(0, 2)},
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message() << "scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(Shader::BICUBIC_UPSCALE, tc.primary_axis, tc.scale_from,
- tc.scale_to);
- if (!kSkipDetectionTest) {
- EXPECT_EQ(tc.expected_overscan,
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
- }
-
- // Sanity-check that the internal math estimating the overscan is correct.
- gfx::Rect expected_input_rect = kTenByTenRect;
- expected_input_rect.Inset(
- gfx::Insets::VH(-tc.expected_overscan.y(), -tc.expected_overscan.x()));
- EXPECT_EQ(expected_input_rect, ToInputRect(kTenByTenRect));
- }
-}
-
-TEST_F(GLScalerOverscanPixelTest, BicubicHalving) {
- constexpr struct {
- Axis primary_axis;
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- gfx::Vector2d expected_overscan;
- } kTestCases[] = {
- {Axis::HORIZONTAL, gfx::Vector2d(16, 16), gfx::Vector2d(8, 16),
- gfx::Vector2d(3, 0)},
- {Axis::VERTICAL, gfx::Vector2d(16, 16), gfx::Vector2d(16, 8),
- gfx::Vector2d(0, 3)},
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message() << "scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(Shader::BICUBIC_HALF_1D, tc.primary_axis, tc.scale_from,
- tc.scale_to);
- EXPECT_EQ(tc.expected_overscan,
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
-
- // Sanity-check that the internal math estimating the overscan is correct.
- gfx::Rect expected_input_rect = kTenByTenRect;
- expected_input_rect.Inset(
- gfx::Insets::VH(-tc.expected_overscan.y(), -tc.expected_overscan.x()));
- EXPECT_EQ(expected_input_rect, ToInputRect(kTenByTenRect));
- }
-}
-
-TEST_F(GLScalerOverscanPixelTest, Planerizers) {
- if (!AreMultipleRenderingTargetsSupported()) {
- LOG(WARNING) << "Skipping test due to lack of MRT support on this machine.";
- return;
- }
-
- constexpr struct {
- Shader shader;
- Axis primary_axis;
- gfx::Vector2d scale_from;
- gfx::Vector2d scale_to;
- } kTestCases[] = {
- {Shader::PLANAR_CHANNEL_0, Axis::HORIZONTAL, gfx::Vector2d(16, 16),
- gfx::Vector2d(4, 16)},
- // Note: Other PLANAR_CHANNEL_N shaders don't need to be tested since they
- // use the same code path.
- {Shader::I422_NV61_MRT, Axis::HORIZONTAL, gfx::Vector2d(16, 16),
- gfx::Vector2d(4, 16)},
- {
- Shader::DEINTERLEAVE_PAIRWISE_MRT, Axis::HORIZONTAL,
- gfx::Vector2d(16, 16), gfx::Vector2d(8, 16),
- },
- };
-
- for (const auto& tc : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "shader=" << static_cast<int>(tc.shader)
- << ", scale_from=" << tc.scale_from.ToString()
- << ", scale_to=" << tc.scale_to.ToString());
-
- // Test the effect on the pixels.
- UseScaler(tc.shader, tc.primary_axis, tc.scale_from, tc.scale_to);
- EXPECT_EQ(gfx::Vector2d(0, 0),
- DetectScalerOverscan(tc.scale_from, tc.scale_to));
-
- // Sanity-check that the internal math estimating the overscan is correct.
- EXPECT_EQ(kTenByTenRect, ToInputRect(kTenByTenRect));
- }
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_scaler_pixeltest.cc b/chromium/components/viz/common/gl_scaler_pixeltest.cc
deleted file mode 100644
index 9c1df00fc82..00000000000
--- a/chromium/components/viz/common/gl_scaler_pixeltest.cc
+++ /dev/null
@@ -1,628 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_scaler.h"
-
-#include <sstream>
-
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/strings/pattern.h"
-#include "build/build_config.h"
-#include "cc/test/pixel_test.h"
-#include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/test/gl_scaler_test_util.h"
-#include "components/viz/test/paths.h"
-#include "gpu/GLES2/gl2chromium.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/color_space.h"
-
-#if BUILDFLAG(IS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
-namespace {
-
-// Loads a PNG test image from the test directory, and converts it to GL_RGBA
-// byte order.
-SkBitmap LoadPNGTestImage(const std::string& basename) {
- base::FilePath test_dir;
- if (!base::PathService::Get(viz::Paths::DIR_TEST_DATA, &test_dir)) {
- LOG(FATAL) << "Unable to get Paths::DIR_TEST_DATA from base::PathService.";
- return SkBitmap();
- }
- const auto source_file = test_dir.AppendASCII(basename);
- SkBitmap as_n32;
- if (!cc::ReadPNGFile(source_file, &as_n32)) {
- return SkBitmap();
- }
- SkBitmap as_rgba = viz::GLScalerTestUtil::AllocateRGBABitmap(
- gfx::Size(as_n32.width(), as_n32.height()));
- if (!as_n32.readPixels(SkPixmap(as_rgba.info(), as_rgba.getAddr(0, 0),
- as_rgba.rowBytes()))) {
- return SkBitmap();
- }
- return as_rgba;
-}
-
-} // namespace
-
-namespace viz {
-
-#define EXPECT_STRING_MATCHES(expected, actual) \
- if (!base::MatchPattern(actual, expected)) { \
- ADD_FAILURE() << "\nActual: " << (actual) \
- << "\nExpected to match pattern: " << (expected); \
- }
-
-class GLScalerPixelTest : public cc::PixelTest, public GLScalerTestUtil {
- public:
- GLScaler* scaler() const { return scaler_.get(); }
-
- std::string GetScalerString() const {
- std::ostringstream oss;
- oss << *scaler_;
- return oss.str();
- }
-
- GLuint CreateTexture(const gfx::Size& size) {
- return texture_helper_->CreateTexture(size);
- }
-
- GLuint UploadTexture(const SkBitmap& bitmap) {
- return texture_helper_->UploadTexture(bitmap);
- }
-
- SkBitmap DownloadTexture(GLuint texture, const gfx::Size& size) {
- return texture_helper_->DownloadTexture(texture, size);
- }
-
- // Test convenience to upload |src_bitmap| to the GPU, execute the scaling,
- // then download the result from the GPU and return it as a SkBitmap.
- SkBitmap Scale(const SkBitmap& src_bitmap,
- const gfx::Vector2d& src_offset,
- const gfx::Rect& output_rect) {
- const GLuint src_texture = UploadTexture(src_bitmap);
- const GLuint dest_texture = CreateTexture(output_rect.size());
- if (!scaler()->Scale(src_texture,
- gfx::Size(src_bitmap.width(), src_bitmap.height()),
- src_offset, dest_texture, output_rect)) {
- return SkBitmap();
- }
- return DownloadTexture(dest_texture, output_rect.size());
- }
-
- // Returns the amount of color error expected due to bugs in the current
- // platform's bilinear texture sampler.
- int GetBaselineColorDifference() const {
-#if BUILDFLAG(IS_ANDROID)
- // Android seems to have texture sampling problems that are not at all seen
- // on any of the desktop platforms. Also, versions before Marshmallow seem
- // to have a much larger accuracy issues.
- if (base::android::BuildInfo::GetInstance()->sdk_int() <
- base::android::SDK_VERSION_MARSHMALLOW) {
- return 12;
- }
- return 2;
-#else
- return 0;
-#endif
- }
-
- protected:
- void SetUp() final {
- cc::PixelTest::SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
-
- scaler_ = std::make_unique<GLScaler>(context_provider());
- gl_ = context_provider()->ContextGL();
- CHECK(gl_);
- texture_helper_ = std::make_unique<GLScalerTestTextureHelper>(gl_);
- }
-
- bool IsAndroidMarshmallow() {
-#if BUILDFLAG(IS_ANDROID)
- return base::android::BuildInfo::GetInstance()->sdk_int() ==
- base::android::SDK_VERSION_MARSHMALLOW;
-#else
- return false;
-#endif
- }
-
- void TearDown() final {
- texture_helper_.reset();
- gl_ = nullptr;
- scaler_.reset();
-
- cc::PixelTest::TearDown();
- }
-
- private:
- std::unique_ptr<GLScaler> scaler_;
- gpu::gles2::GLES2Interface* gl_ = nullptr;
- std::unique_ptr<GLScalerTestTextureHelper> texture_helper_;
-};
-
-// Tests that the default GLScaler::Parameters produces an unscaled copy.
-TEST_F(GLScalerPixelTest, CopiesByDefault) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- ASSERT_TRUE(scaler()->Configure(GLScaler::Parameters()));
- EXPECT_EQ(u8"Output ← {BILINEAR/lowp copy} ← Source", GetScalerString());
- const SkBitmap source = CreateSMPTETestImage(kSMPTEFullSize);
- const SkBitmap actual =
- Scale(source, gfx::Vector2d(), gfx::Rect(kSMPTEFullSize));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(
- actual, kSMPTEFullSize, gfx::Rect(kSMPTEFullSize), 0, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests a FAST quality scaling of 2→1 in X and 3→2 in Y.
-TEST_F(GLScalerPixelTest, ScalesAtFastQuality) {
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(2, 3);
- params.scale_to = gfx::Vector2d(1, 2);
- params.quality = GLScaler::Parameters::Quality::FAST;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(u8"Output ← {BILINEAR/lowp [2 3] to [1 2]} ← Source",
- GetScalerString());
- const SkBitmap source = CreateSMPTETestImage(kSMPTEFullSize);
- static_assert(kSMPTEFullSize.width() % 2 == 0, "Fix kSMPTEFullSize.");
- static_assert(kSMPTEFullSize.height() % 3 == 0, "Fix kSMPTEFullSize.");
- const SkBitmap actual = Scale(source, gfx::Vector2d(),
- gfx::Rect(0, 0, kSMPTEFullSize.width() / 2,
- kSMPTEFullSize.height() * 2 / 3));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(
- actual, kSMPTEFullSize, gfx::Rect(kSMPTEFullSize), 2, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests a GOOD quality scaling of 1280x720 → 1024x700.
-TEST_F(GLScalerPixelTest, ScalesALittleAtGoodQuality) {
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(1280, 720);
- params.scale_to = gfx::Vector2d(1024, 700);
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(u8"Output ← {BILINEAR2X2/lowp [1280 720] to [1024 700]} ← Source",
- GetScalerString());
- constexpr gfx::Size kSourceSize = gfx::Size(1280, 720);
- const SkBitmap source = CreateSMPTETestImage(kSourceSize);
- const SkBitmap actual =
- Scale(source, gfx::Vector2d(), gfx::Rect(0, 0, 1024, 700));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(
- actual, kSourceSize, gfx::Rect(kSourceSize), 2, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests a large, skewed reduction at GOOD quality: 3840x720 → 128x256.
-TEST_F(GLScalerPixelTest, ScalesALotHorizontallyAtGoodQuality) {
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(3840, 720);
- params.scale_to = gfx::Vector2d(128, 256);
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(
- u8"Output "
- u8"← {BILINEAR/lowp [256 256] to [128 256]} "
- u8"← {BILINEAR4/lowp [2048 512] to [256 256]} "
- u8"← {BILINEAR2X2/lowp [3840 720] to [2048 512]} "
- u8"← Source",
- GetScalerString());
- constexpr gfx::Size kSourceSize = gfx::Size(3840, 720);
- const SkBitmap source = CreateSMPTETestImage(kSourceSize);
- const SkBitmap actual =
- Scale(source, gfx::Vector2d(), gfx::Rect(0, 0, 128, 256));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(
- actual, kSourceSize, gfx::Rect(kSourceSize), 2, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests a large, skewed reduction at GOOD quality: 640x2160 → 256x128.
-TEST_F(GLScalerPixelTest, ScalesALotVerticallyAtGoodQuality) {
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(640, 2160);
- params.scale_to = gfx::Vector2d(256, 128);
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(
- u8"Output "
- u8"← {BILINEAR/lowp [256 256] to [256 128]} "
- u8"← {BILINEAR4/lowp [512 2048] to [256 256]} "
- u8"← {BILINEAR2X2/lowp [640 2160] to [512 2048]} "
- u8"← Source",
- GetScalerString());
- constexpr gfx::Size kSourceSize = gfx::Size(640, 2160);
- const SkBitmap source = CreateSMPTETestImage(kSourceSize);
- const SkBitmap actual =
- Scale(source, gfx::Vector2d(), gfx::Rect(0, 0, 256, 128));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(
- actual, kSourceSize, gfx::Rect(kSourceSize), 2, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests a BEST quality scaling of 1280x720 → 1024x700.
-TEST_F(GLScalerPixelTest, ScalesAtBestQuality) {
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(1280, 720);
- params.scale_to = gfx::Vector2d(1024, 700);
- params.quality = GLScaler::Parameters::Quality::BEST;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(
- u8"Output "
- u8"← {BICUBIC_HALF_1D/lowp [2048 700] to [1024 700]} "
- u8"← {BICUBIC_UPSCALE/lowp [1280 700] to [2048 700]} "
- u8"← {BICUBIC_HALF_1D/lowp [1280 1400] to [1280 700]} "
- u8"← {BICUBIC_UPSCALE/lowp [1280 720] to [1280 1400]} "
- u8"← Source",
- GetScalerString());
- constexpr gfx::Size kSourceSize = gfx::Size(1280, 720);
- const SkBitmap source = CreateSMPTETestImage(kSourceSize);
- const SkBitmap actual =
- Scale(source, gfx::Vector2d(), gfx::Rect(0, 0, 1024, 700));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(
- actual, kSourceSize, gfx::Rect(kSourceSize), 4, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests that a source offset can be provided to sample the source starting at a
-// different location.
-TEST_F(GLScalerPixelTest, TranslatesWithSourceOffset) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- GLScaler::Parameters params;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(u8"Output ← {BILINEAR/lowp copy} ← Source", GetScalerString());
- const SkBitmap source = CreateSMPTETestImage(kSMPTEFullSize);
- static_assert(kSMPTEFullSize.width() % 2 == 0, "Fix kSMPTEFullSize.");
- static_assert(kSMPTEFullSize.height() % 4 == 0, "Fix kSMPTEFullSize.");
- const gfx::Vector2d offset(kSMPTEFullSize.width() / 2,
- kSMPTEFullSize.height() / 4);
- const gfx::Rect src_rect(offset.x(), offset.y(),
- kSMPTEFullSize.width() - offset.x(),
- kSMPTEFullSize.height() - offset.y());
- const gfx::Rect output_rect(0, 0, kSMPTEFullSize.width() - offset.x(),
- kSMPTEFullSize.height() - offset.y());
- const SkBitmap actual = Scale(source, offset, output_rect);
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(actual, kSMPTEFullSize, src_rect, 0,
- &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests that the source offset works when the source content is vertically
-// flipped.
-TEST_F(GLScalerPixelTest, TranslatesVerticallyFlippedSourceWithSourceOffset) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- GLScaler::Parameters params;
- params.is_flipped_source = true;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(u8"Output ← {BILINEAR/lowp copy} ← Source", GetScalerString());
- const SkBitmap flipped_source =
- CreateVerticallyFlippedBitmap(CreateSMPTETestImage(kSMPTEFullSize));
- const gfx::Vector2d offset(kSMPTEFullSize.width() / 2,
- kSMPTEFullSize.height() / 4);
- const gfx::Rect src_rect(offset.x(), offset.y(),
- kSMPTEFullSize.width() - offset.x(),
- kSMPTEFullSize.height() - offset.y());
- const gfx::Rect output_rect(0, 0, kSMPTEFullSize.width() - offset.x(),
- kSMPTEFullSize.height() - offset.y());
- const SkBitmap flipped_back_actual =
- CreateVerticallyFlippedBitmap(Scale(flipped_source, offset, output_rect));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(flipped_back_actual, kSMPTEFullSize,
- src_rect, 0, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual (flipped-back): " << cc::GetPNGDataUrl(flipped_back_actual);
-}
-
-// Tests that the correct source selection is made when both translating the
-// source and then scaling. Scale "from" and "to" values are chosen such that a
-// multi-stage scaler will be configured (to test that offsets are correcty
-// calculated and passed between multiple stages).
-TEST_F(GLScalerPixelTest, ScalesWithTranslatedSourceOffset) {
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(640, 2160);
- params.scale_to = gfx::Vector2d(256, 128);
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(
- u8"Output "
- u8"← {BILINEAR/lowp [256 256] to [256 128]} "
- u8"← {BILINEAR4/lowp [512 2048] to [256 256]} "
- u8"← {BILINEAR2X2/lowp [640 2160] to [512 2048]} "
- u8"← Source",
- GetScalerString());
- constexpr gfx::Size kSourceSize = gfx::Size(640, 2160);
- const SkBitmap source = CreateSMPTETestImage(kSourceSize);
- const gfx::Vector2d offset(kSourceSize.width() / 2, kSourceSize.height() / 4);
- const gfx::Rect output_rect(0, 0, 128, 64);
- const SkBitmap actual = Scale(source, offset, output_rect);
- const gfx::Rect expected_copy_rect(
- offset.x(), offset.y(),
- output_rect.width() * params.scale_from.x() / params.scale_to.x(),
- output_rect.height() * params.scale_from.y() / params.scale_to.y());
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(actual, kSourceSize, expected_copy_rect,
- 2, &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nExpected crop region of source: " << expected_copy_rect.ToString()
- << "\nFull (uncropped) Source: " << cc::GetPNGDataUrl(source)
- << "\nActual: " << cc::GetPNGDataUrl(actual);
-}
-
-// Tests that the output is vertically flipped, if requested in the parameters.
-TEST_F(GLScalerPixelTest, VerticallyFlipsOutput) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- GLScaler::Parameters params;
- params.is_flipped_source = false;
- params.flip_output = true;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(u8"Output ← {BILINEAR/lowp+flip_y copy} ← Source",
- GetScalerString());
- const SkBitmap source = CreateSMPTETestImage(kSMPTEFullSize);
- const SkBitmap flipped_back_actual = CreateVerticallyFlippedBitmap(
- Scale(source, gfx::Vector2d(), gfx::Rect(kSMPTEFullSize)));
- int max_color_diff = GetBaselineColorDifference();
- EXPECT_TRUE(LooksLikeSMPTETestImage(flipped_back_actual, kSMPTEFullSize,
- gfx::Rect(kSMPTEFullSize), 0,
- &max_color_diff))
- << "max_color_diff measured was " << max_color_diff
- << "\nActual (flipped-back): " << cc::GetPNGDataUrl(flipped_back_actual);
-}
-
-// Tests that the single-channel export ScalerStage works by executing a red
-// channel export.
-TEST_F(GLScalerPixelTest, ExportsTheRedColorChannel) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- GLScaler::Parameters params;
- params.is_flipped_source = false;
- params.export_format = GLScaler::Parameters::ExportFormat::CHANNEL_0;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(u8"Output ← {PLANAR_CHANNEL_0/lowp [4 1] to [1 1]} ← Source",
- GetScalerString());
- const SkBitmap source = CreateSMPTETestImage(kSMPTEFullSize);
- const SkBitmap expected = CreatePackedPlanarBitmap(source, 0);
- const gfx::Size output_size(expected.width(), expected.height());
- const SkBitmap actual =
- Scale(source, gfx::Vector2d(), gfx::Rect(output_size));
- constexpr float kAvgAbsoluteErrorLimit = 1.f;
- constexpr int kMaxAbsoluteErrorLimit = 2;
- EXPECT_TRUE(cc::FuzzyPixelComparator(
- false, 100.f, 0.f,
- GetBaselineColorDifference() + kAvgAbsoluteErrorLimit,
- GetBaselineColorDifference() + kMaxAbsoluteErrorLimit, 0)
- .Compare(expected, actual))
- << "\nActual: " << cc::GetPNGDataUrl(actual)
- << "\Expected: " << cc::GetPNGDataUrl(expected);
-}
-
-// A test that also stands as an example for how to use the GLScaler to scale a
-// screen-sized RGB source (2160x1440, 16:10 aspect ratio) to a typical video
-// resolution (720p, 16:9). The end-goal is to produce three textures, which
-// contain the three YUV planes in I420 format.
-//
-// This is a two step process: First, the source is scaled and color space
-// converted, with the final result exported as NV61 format (a full size luma
-// plane + a half-width interleaved UV image). Second, the interleaved UV image
-// is scaled by half in the vertical direction and then separated into one U and
-// one V plane.
-TEST_F(GLScalerPixelTest, Example_ScaleAndExportForScreenVideoCapture) {
- if (scaler()->GetMaxDrawBuffersSupported() < 2) {
- LOG(WARNING) << "Skipping test due to lack of MRT support.";
- return;
- }
-
- // Step 1: Produce a scaled NV61-format result.
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(2160, 1440);
- params.scale_to = gfx::Vector2d(1280, 720);
- params.source_color_space = DefaultRGBColorSpace();
- params.output_color_space = DefaultYUVColorSpace();
- params.enable_precise_color_management = true;
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = true;
- params.flip_output = true;
- params.export_format = GLScaler::Parameters::ExportFormat::NV61;
- params.swizzle[0] = GL_BGRA_EXT; // Swizzle for readback.
- params.swizzle[1] = GL_RGBA; // Don't swizzle output for Step 2.
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_STRING_MATCHES(
- u8"Output "
- u8"← {I422_NV61_MRT/mediump [5120 720] to [1280 720], with color x-form "
- u8"to *BT709*, with swizzle(0)} "
- u8"← {BILINEAR2/mediump [2160 1440] to [1280 720]} "
- u8"← {BILINEAR/mediump+flip_y copy, with color x-form *BT709* to "
- u8"*transfer:1.0000\\*x*} "
- u8"← Source",
- GetScalerString());
-
- constexpr gfx::Size kSourceSize = gfx::Size(2160, 1440);
- const GLuint src_texture = UploadTexture(
- CreateVerticallyFlippedBitmap(CreateSMPTETestImage(kSourceSize)));
- constexpr gfx::Size kOutputSize = gfx::Size(1280, 720);
- SkBitmap expected = CreateSMPTETestImage(kOutputSize);
- ConvertRGBABitmapToYUV(&expected);
-
- // While the output size is 1280x720, the packing of 4 pixels into one RGBA
- // quad means that the texture width must be divided by 4, and that size
- // passed in the output_rect argument in the call to ScaleToMultipleOutputs().
- const gfx::Size y_plane_size(kOutputSize.width() / 4, kOutputSize.height());
- const GLuint y_plane_texture = CreateTexture(y_plane_size);
- const GLuint uv_interleaved_texture = CreateTexture(y_plane_size);
-
- ASSERT_TRUE(scaler()->ScaleToMultipleOutputs(
- src_texture, kSourceSize, gfx::Vector2d(), y_plane_texture,
- uv_interleaved_texture, gfx::Rect(y_plane_size)));
-
- // Step 2: Run the scaler again with the deinterleaver exporter, to produce
- // the I420 U and V planes from the NV61 UV interleaved image.
- params = GLScaler::Parameters(); // Reset params.
- params.scale_from = gfx::Vector2d(1, 2);
- params.scale_to = gfx::Vector2d(1, 1);
- params.source_color_space = DefaultYUVColorSpace();
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = false; // Output was already flipped in Step 1.
- params.export_format =
- GLScaler::Parameters::ExportFormat::DEINTERLEAVE_PAIRWISE;
- params.swizzle[0] = GL_BGRA_EXT; // Swizzle for readback.
- params.swizzle[1] = GL_BGRA_EXT; // Swizzle for readback.
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(
- u8"Output "
- u8"← {DEINTERLEAVE_PAIRWISE_MRT/lowp [2 2] to [1 1], with swizzle(0), "
- u8"with swizzle(1)} "
- u8"← Source",
- GetScalerString());
-
- const gfx::Size uv_plane_size(y_plane_size.width() / 2,
- y_plane_size.height() / 2);
- const GLuint u_plane_texture = CreateTexture(uv_plane_size);
- const GLuint v_plane_texture = CreateTexture(uv_plane_size);
- ASSERT_TRUE(scaler()->ScaleToMultipleOutputs(
- uv_interleaved_texture, y_plane_size, gfx::Vector2d(), u_plane_texture,
- v_plane_texture, gfx::Rect(uv_plane_size)));
-
- // Download the textures, and unpack them into an interleaved YUV bitmap, for
- // comparison against the |expected| rendition.
- SkBitmap actual = AllocateRGBABitmap(kOutputSize);
- actual.eraseColor(SkColorSetARGB(0xff, 0x00, 0x80, 0x80));
- SkBitmap y_plane = DownloadTexture(y_plane_texture, y_plane_size);
- SwizzleBitmap(&y_plane);
- UnpackPlanarBitmap(y_plane, 0, &actual);
- SkBitmap u_plane = DownloadTexture(u_plane_texture, uv_plane_size);
- SwizzleBitmap(&u_plane);
- UnpackPlanarBitmap(u_plane, 1, &actual);
- SkBitmap v_plane = DownloadTexture(v_plane_texture, uv_plane_size);
- SwizzleBitmap(&v_plane);
- UnpackPlanarBitmap(v_plane, 2, &actual);
-
- // Provide generous error limits to account for the chroma subsampling in the
- // |actual| result when compared to the perfect |expected| rendition.
- constexpr float kAvgAbsoluteErrorLimit = 16.f;
- constexpr int kMaxAbsoluteErrorLimit = 0x80;
- EXPECT_TRUE(cc::FuzzyPixelComparator(false, 100.f, 0.f,
- kAvgAbsoluteErrorLimit,
- kMaxAbsoluteErrorLimit, 0)
- .Compare(expected, actual))
- << "\nActual: " << cc::GetPNGDataUrl(actual)
- << "\nExpected: " << cc::GetPNGDataUrl(expected);
-}
-
-// Performs a scaling-with-gamma-correction experiment to test GLScaler's
-// "precise color management" feature. A 50% scale is executed on the same
-// source image, once with color management turned on, and once with it turned
-// off. The results, each of which should be different, are then examined.
-TEST_F(GLScalerPixelTest, ScalesWithColorManagement) {
- if (!scaler()->SupportsPreciseColorManagement()) {
- LOG(WARNING) << "Skipping test due to lack of 16-bit float support.";
- return;
- }
-
- // An image of a raspberry (source:
- // https://commons.wikimedia.org/wiki/File:Framboise_Margy_3.jpg) has been
- // transformed in such a way that scaling it by half in both directions will
- // reveal whether scaling is occurring on linearized color values. When scaled
- // correctly, the output image should contain a visible raspberry blended
- // heavily with solid gray. However, if done naively, the output will be a
- // solid 50% gray. For details, see: http://www.ericbrasseur.org/gamma.html
- //
- // Note that the |source| and |expected| images both use the sRGB color space.
- const SkBitmap source = LoadPNGTestImage("rasp-grayator.png");
- ASSERT_FALSE(source.isNull());
- const SkBitmap expected = LoadPNGTestImage("rasp-grayator-half.png");
- ASSERT_FALSE(expected.isNull());
- const gfx::Size output_size =
- gfx::Size(source.width() / 2, source.height() / 2);
- ASSERT_EQ(gfx::Size(expected.width(), expected.height()), output_size);
- const SkBitmap expected_naive = AllocateRGBABitmap(output_size);
- expected_naive.eraseColor(SkColorSetARGB(0xff, 0x7f, 0x7f, 0x7f));
-
- // Scale the right way: With color management enabled, the raspberry should be
- // visible in the downscaled result.
- GLScaler::Parameters params;
- params.scale_from = gfx::Vector2d(2, 2);
- params.scale_to = gfx::Vector2d(1, 1);
- params.source_color_space = gfx::ColorSpace::CreateSRGB();
- params.enable_precise_color_management = true;
- params.quality = GLScaler::Parameters::Quality::GOOD;
- params.is_flipped_source = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_STRING_MATCHES(
- u8"Output "
- u8"← {BILINEAR/mediump [2 2] to [1 1], with color x-form to *BT709*} "
- u8"← {BILINEAR/mediump copy, with color x-form *BT709* to "
- u8"*transfer:1.0000\\*x*} "
- u8"← Source",
- GetScalerString());
- const SkBitmap actual =
- Scale(source, gfx::Vector2d(), gfx::Rect(output_size));
- constexpr float kAvgAbsoluteErrorLimit = 1.f;
- constexpr int kMaxAbsoluteErrorLimit = 2;
- EXPECT_TRUE(cc::FuzzyPixelComparator(
- false, 100.f, 0.f,
- GetBaselineColorDifference() + kAvgAbsoluteErrorLimit,
- GetBaselineColorDifference() + kMaxAbsoluteErrorLimit, 0)
- .Compare(expected, actual))
- << "\nActual: " << cc::GetPNGDataUrl(actual)
- << "\nExpected (half size): " << cc::GetPNGDataUrl(expected)
- << "\nOriginal: " << cc::GetPNGDataUrl(source);
-
- // Scale the naive way: Without color management, expect a solid gray result.
- params.enable_precise_color_management = false;
- ASSERT_TRUE(scaler()->Configure(params));
- EXPECT_EQ(u8"Output ← {BILINEAR/lowp [2 2] to [1 1]} ← Source",
- GetScalerString());
- const SkBitmap actual_naive =
- Scale(source, gfx::Vector2d(), gfx::Rect(output_size));
- EXPECT_TRUE(cc::FuzzyPixelComparator(
- false, 100.f, 0.f,
- GetBaselineColorDifference() + kAvgAbsoluteErrorLimit,
- GetBaselineColorDifference() + kMaxAbsoluteErrorLimit, 0)
- .Compare(expected_naive, actual_naive))
- << "\nActual: " << cc::GetPNGDataUrl(actual_naive)
- << "\nExpected (half size): " << cc::GetPNGDataUrl(expected_naive)
- << "\nOriginal: " << cc::GetPNGDataUrl(source);
-}
-
-#undef EXPECT_STRING_MATCHES
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_scaler_shader_pixeltest.cc b/chromium/components/viz/common/gl_scaler_shader_pixeltest.cc
deleted file mode 100644
index e1e7b8c226d..00000000000
--- a/chromium/components/viz/common/gl_scaler_shader_pixeltest.cc
+++ /dev/null
@@ -1,785 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_scaler.h"
-
-#include <sstream>
-#include <tuple>
-#include <vector>
-
-#include "build/build_config.h"
-#include "cc/test/pixel_test.h"
-#include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/test/gl_scaler_test_util.h"
-#include "gpu/GLES2/gl2chromium.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkImageInfo.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "ui/gfx/color_transform.h"
-
-#if BUILDFLAG(IS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
-namespace viz {
-
-namespace {
-
-// Base size of test images to be operated upon. Both dimensions must be
-// divisible by 2, 3, or 4.
-constexpr gfx::Size kBaseSize = gfx::Size(16 * 4 * 3, 9 * 4 * 3);
-
-} // namespace
-
-class GLScalerShaderPixelTest
- : public cc::PixelTest,
- public testing::WithParamInterface<std::tuple<bool, bool>>,
- public GLScalerTestUtil {
- public:
- using Axis = GLScaler::Axis;
- using Shader = GLScaler::Shader;
- using ShaderProgram = GLScaler::ShaderProgram;
-
- GLScalerShaderPixelTest()
- : scoped_trace_(
- __FILE__,
- __LINE__,
- (testing::Message()
- << "is_converting_rgb_to_yuv=" << is_converting_rgb_to_yuv()
- << ", is_swizzling_output=" << is_swizzling_output())) {}
-
- bool is_converting_rgb_to_yuv() const { return std::get<0>(GetParam()); }
- bool is_swizzling_output() const { return std::get<1>(GetParam()); }
-
- bool AreMultipleRenderingTargetsSupported() const {
- return scaler_->GetMaxDrawBuffersSupported() > 1;
- }
-
- // Returns a cached ShaderProgram, maybe configured to convert RGB→YUV and/or
- // swizzle the 1st and 3rd bytes in the output (depending on GetParams()).
- ShaderProgram* GetShaderProgram(Shader shader) {
- std::unique_ptr<gfx::ColorTransform> transform;
- if (is_converting_rgb_to_yuv()) {
- transform = gfx::ColorTransform::NewColorTransform(
- DefaultRGBColorSpace(), DefaultYUVColorSpace());
- }
- const GLenum swizzle[2] = {
- static_cast<GLenum>(is_swizzling_output() ? GL_BGRA_EXT : GL_RGBA),
- static_cast<GLenum>(is_swizzling_output() ? GL_BGRA_EXT : GL_RGBA),
- };
- return scaler_->GetShaderProgram(shader, GL_UNSIGNED_BYTE, transform.get(),
- swizzle);
- }
-
- GLuint CreateTexture(const gfx::Size& size) {
- return texture_helper_->CreateTexture(size);
- }
-
- GLuint UploadTexture(const SkBitmap& bitmap) {
- return texture_helper_->UploadTexture(bitmap);
- }
-
- SkBitmap DownloadTexture(GLuint texture, const gfx::Size& size) {
- return texture_helper_->DownloadTexture(texture, size);
- }
-
- GLuint RenderToNewTexture(GLuint src_texture, const gfx::Size& size) {
- return RenderToNewTextures(src_texture, size, false).first;
- }
-
- // Using the current shader program, creates new texture(s) of the given
- // |size| and draws using |src_texture| as input. If |dual_outputs| is true,
- // two new textures are created and drawn-to simultaneously; otherwise, only
- // one is created and drawn-to. The caller does not take ownership of the new
- // texture(s).
- std::pair<GLuint, GLuint> RenderToNewTextures(GLuint src_texture,
- const gfx::Size& size,
- bool dual_outputs) {
- std::pair<GLuint, GLuint> dst_textures(
- CreateTexture(size), dual_outputs ? CreateTexture(size) : 0u);
- GLuint framebuffer = 0;
- gl_->GenFramebuffers(1, &framebuffer);
- gl_->BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, dst_textures.first, 0);
- if (dual_outputs) {
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + 1,
- GL_TEXTURE_2D, dst_textures.second, 0);
- }
-
- gl_->BindTexture(GL_TEXTURE_2D, src_texture);
-
- gl_->Viewport(0, 0, size.width(), size.height());
- const GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT0 + 1};
- if (dual_outputs) {
- gl_->DrawBuffersEXT(2, buffers);
- }
- // Assumption: The |vertex_attributes_buffer_| created in SetUp() is
- // currently bound to GL_ARRAY_BUFFER.
- gl_->DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-
- gl_->DeleteFramebuffers(1, &framebuffer);
-
- return dst_textures;
- }
-
- // Returns a texture that converts the input |texture| back to unswizzled RGB,
- // if necessary, depending on GetParam(). The caller does not take ownership
- // of the returned texture, which could be the same texture as the input
- // argument in some cases.
- GLuint ConvertBackToUnswizzledRGB(GLuint texture, const gfx::Size& size) {
- GLuint result = texture;
- if (is_swizzling_output()) {
- const GLenum swizzle[2] = {GL_BGRA_EXT, GL_BGRA_EXT};
- scaler_
- ->GetShaderProgram(Shader::BILINEAR, GL_UNSIGNED_BYTE, nullptr,
- swizzle)
- ->UseProgram(size, gfx::RectF(gfx::Rect(size)), size,
- Axis::HORIZONTAL, false);
- result = RenderToNewTexture(result, size);
- }
- if (is_converting_rgb_to_yuv()) {
- const auto transform = gfx::ColorTransform::NewColorTransform(
- DefaultYUVColorSpace(), DefaultRGBColorSpace());
- const GLenum swizzle[2] = {GL_RGBA, GL_RGBA};
- scaler_
- ->GetShaderProgram(Shader::BILINEAR, GL_UNSIGNED_BYTE,
- transform.get(), swizzle)
- ->UseProgram(size, gfx::RectF(gfx::Rect(size)), size,
- Axis::HORIZONTAL, false);
- result = RenderToNewTexture(result, size);
- }
- return result;
- }
-
- // A test case executed by RunSMPTEScalingTestCases().
- struct SMPTEScalingTestCase {
- gfx::Rect src_rect; // Selects a subrect of the source.
- int scale_from; // Scale ratio denominator.
- int scale_to; // Scale ratio numerator.
- int fuzzy_bar_border; // Ignored pixels between color bars, when comparing.
- };
-
- // Draws with the given shader for each of the provided |test_cases| and adds
- // gtest failure(s) if the output does not look like a part of the SMPTE test
- // image.
- void RunSMPTEScalingTestCases(
- Shader shader,
- const std::vector<SMPTEScalingTestCase>& test_cases) {
- const SkBitmap source = CreateSMPTETestImage(kBaseSize);
- const GLuint src_texture = UploadTexture(source);
-
- for (const auto& tc : test_cases) {
- for (int is_horizontal = 0; is_horizontal <= 1; ++is_horizontal) {
- gfx::Size dst_size = tc.src_rect.size();
- Axis axis;
- if (is_horizontal) {
- CHECK_EQ((dst_size.width() * tc.scale_to) % tc.scale_from, 0);
- dst_size.set_width(dst_size.width() * tc.scale_to / tc.scale_from);
- axis = Axis::HORIZONTAL;
- } else {
- CHECK_EQ((dst_size.height() * tc.scale_to) % tc.scale_from, 0);
- dst_size.set_height(dst_size.height() * tc.scale_to / tc.scale_from);
- axis = Axis::VERTICAL;
- }
-
- SCOPED_TRACE(testing::Message()
- << "src_rect=" << tc.src_rect.ToString()
- << ", scale from→to=" << tc.scale_from << "→"
- << tc.scale_to << ", dst_size=" << dst_size.ToString());
-
- GetShaderProgram(shader)->UseProgram(kBaseSize, gfx::RectF(tc.src_rect),
- dst_size, axis, false);
- const SkBitmap actual = DownloadTexture(
- ConvertBackToUnswizzledRGB(
- RenderToNewTexture(src_texture, dst_size), dst_size),
- dst_size);
- int max_color_diff = GetMaxAllowedColorDifference();
- if (!LooksLikeSMPTETestImage(actual, kBaseSize, tc.src_rect,
- tc.fuzzy_bar_border, &max_color_diff)) {
- ADD_FAILURE() << "Scaled image does not look like the correct scaled "
- "subrect of the SMPTE test image (max diff measured="
- << max_color_diff
- << "):\nActual: " << cc::GetPNGDataUrl(actual);
- }
- }
- }
- }
-
- // Adds test failures if an |actual| image does not match the |expected|
- // image. When not doing color space conversion, the images must match
- // exactly; otherwise, some minor differences are allowed.
- void ExpectAreTheSameImage(const SkBitmap& expected,
- const SkBitmap& actual) const {
- const int max_color_diff = GetMaxAllowedColorDifference();
- if (!cc::FuzzyPixelComparator(false, 100.0f, 0.0f, max_color_diff,
- max_color_diff, 0)
- .Compare(expected, actual)) {
- ADD_FAILURE() << "Images are not similar enough (max_color_diff="
- << max_color_diff
- << "):\nExpected: " << cc::GetPNGDataUrl(expected)
- << "\nActual: " << cc::GetPNGDataUrl(actual);
- }
- }
-
- // Draws with the given shader to downscale a "striped pattern" image by
- // |downscale_factor| in one dimension only, and adds gtest failure(s) if the
- // resulting image is not of the |expected_solid_color|. |cycle| specifies the
- // colors of the stripes, which should average to |expected_solid_color|.
- //
- // If the shader program is correct, it should be sampling the texture halfway
- // between each pair of stripes and then averaging the result. This means that
- // every N pixels in the source will be averaged to one pixel in the output,
- // creating a solid color fill as output. If the shader is sampling the
- // texture at the wrong points, the result will be tinted and/or contain
- // striping.
- void RunMultiplePassBilinearTest(Shader shader,
- int downscale_factor,
- const std::vector<SkColor>& cycle) {
- // Compute the expected solid fill color from the colors in |cycle|.
- uint32_t sum_red = 0;
- uint32_t sum_green = 0;
- uint32_t sum_blue = 0;
- uint32_t sum_alpha = 0;
- for (SkColor c : cycle) {
- sum_red += SkColorGetR(c);
- sum_green += SkColorGetG(c);
- sum_blue += SkColorGetB(c);
- sum_alpha += SkColorGetA(c);
- }
- const float count = cycle.size();
- // Note: Taking the rounded average for each color channel.
- const SkColor expected_solid_color =
- SkColorSetARGB(sum_alpha / count + 0.5f, sum_red / count + 0.5f,
- sum_green / count + 0.5f, sum_blue / count + 0.5f);
-
- // Run the test for the vertical direction, and again for the horizontal
- // direction.
- const gfx::Rect src_rect =
- gfx::Rect(0, 0, 10 * downscale_factor, 10 * downscale_factor);
- for (int is_horizontal = 0; is_horizontal <= 1; ++is_horizontal) {
- gfx::Size dst_size = src_rect.size();
- Axis axis;
- CyclicalPattern pattern;
- if (is_horizontal) {
- dst_size.set_width(dst_size.width() / downscale_factor);
- axis = Axis::HORIZONTAL;
- pattern = VERTICAL_STRIPES;
- } else {
- dst_size.set_height(dst_size.height() / downscale_factor);
- axis = Axis::VERTICAL;
- pattern = HORIZONTAL_STRIPES;
- }
-
- // Create the expected output image consisting of a solid fill color.
- SkBitmap expected = AllocateRGBABitmap(dst_size);
- expected.eraseColor(expected_solid_color);
-
- // Run the test for each of N possible rotations of the |cycle| of
- // stripes.
- for (size_t rotation = 0; rotation < cycle.size(); ++rotation) {
- SCOPED_TRACE(testing::Message() << "is_horizontal=" << !!is_horizontal
- << ", rotation=" << rotation
- << ", expected_solid_color=" << std::hex
- << expected_solid_color);
-
- const SkBitmap source =
- CreateCyclicalTestImage(src_rect.size(), pattern, cycle, rotation);
- const GLuint src_texture = UploadTexture(source);
-
- // Execute the program, and convert the shader program's drawn result
- // back to an unswizzled RGB form, and compare that with the expected
- // image.
- GetShaderProgram(shader)->UseProgram(
- src_rect.size(), gfx::RectF(src_rect), dst_size, axis, false);
- const SkBitmap actual = DownloadTexture(
- ConvertBackToUnswizzledRGB(
- RenderToNewTexture(src_texture, dst_size), dst_size),
- dst_size);
- ExpectAreTheSameImage(expected, actual);
- }
- }
- }
-
- protected:
- void SetUp() final {
- cc::PixelTest::SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
-
- scaler_ = std::make_unique<GLScaler>(context_provider());
- gl_ = context_provider()->ContextGL();
- CHECK(gl_);
-
- // Set up vertex attributes buffer and its data.
- gl_->GenBuffers(1, &vertex_attributes_buffer_);
- gl_->BindBuffer(GL_ARRAY_BUFFER, vertex_attributes_buffer_);
- gl_->BufferData(GL_ARRAY_BUFFER, sizeof(ShaderProgram::kVertexAttributes),
- ShaderProgram::kVertexAttributes, GL_STATIC_DRAW);
-
- texture_helper_ = std::make_unique<GLScalerTestTextureHelper>(gl_);
- }
-
- void TearDown() final {
- texture_helper_.reset();
-
- if (vertex_attributes_buffer_) {
- gl_->DeleteBuffers(1, &vertex_attributes_buffer_);
- vertex_attributes_buffer_ = 0;
- }
-
- gl_ = nullptr;
- scaler_.reset();
-
- cc::PixelTest::TearDown();
- }
-
- // Returns the maximum allowed absolute difference between any two color
- // values in the expected vs actual image comparisons, given the current test
- // parameters and known platform-specific inaccuracy.
- int GetMaxAllowedColorDifference() const {
-#if BUILDFLAG(IS_ANDROID)
- // Android seems to have texture sampling and/or readback accuracy issues
- // with these programs that are not at all seen on any of the desktop
- // platforms. Also, versions before Marshmallow seem to have a much larger
- // accuracy issues with a few of the programs. Thus, use higher thresholds,
- // assuming that the programs are correct if they can pass a much lower
- // threshold on other platforms.
- if (base::android::BuildInfo::GetInstance()->sdk_int() <
- base::android::SDK_VERSION_MARSHMALLOW) {
- return (is_converting_rgb_to_yuv() || is_swizzling_output()) ? 24 : 12;
- }
- return (is_converting_rgb_to_yuv() || is_swizzling_output()) ? 4 : 2;
-#else
- return (is_converting_rgb_to_yuv() || is_swizzling_output()) ? 2 : 0;
-#endif
- }
-
- bool IsAndroidMarshmallow() {
-#if BUILDFLAG(IS_ANDROID)
- return base::android::BuildInfo::GetInstance()->sdk_int() ==
- base::android::SDK_VERSION_MARSHMALLOW;
-#else
- return false;
-#endif
- }
-
- testing::ScopedTrace scoped_trace_;
- std::unique_ptr<GLScaler> scaler_;
- gpu::gles2::GLES2Interface* gl_ = nullptr;
- GLuint vertex_attributes_buffer_ = 0;
- std::unique_ptr<GLScalerTestTextureHelper> texture_helper_;
-};
-
-// As the BILINEAR shader is used by some of the test helpers, this test is
-// necessary to ensure the correctness of the tools used by all the other tests.
-TEST_P(GLScalerShaderPixelTest, ValidateTestHelpers) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- // Create/validate a SMPTE color bar test image.
- const SkBitmap original = CreateSMPTETestImage(kBaseSize);
- int max_color_diff = GetMaxAllowedColorDifference();
- ASSERT_TRUE(LooksLikeSMPTETestImage(original, kBaseSize, gfx::Rect(kBaseSize),
- 0, &max_color_diff))
- << "max diff measured=" << max_color_diff;
-
- // Create and upload a test image that has had RGB→YUV conversion performed
- // and/or had its color channels swizzled, depending on the testing params.
- SkBitmap image = CreateSMPTETestImage(kBaseSize);
- if (is_converting_rgb_to_yuv()) {
- ConvertRGBABitmapToYUV(&image);
- }
- if (is_swizzling_output()) {
- SwizzleBitmap(&image);
- }
- const GLuint uploaded_texture = UploadTexture(image);
-
- // Use the convert-back helper, which uses the BILINEAR shader to convert the
- // |uploaded_texture| back to an unswizzled RGB form. Then, download the
- // result and check whether it matches the original.
- const gfx::Size size(image.width(), image.height());
- const GLuint converted_back_texture =
- ConvertBackToUnswizzledRGB(uploaded_texture, size);
- const SkBitmap actual = DownloadTexture(converted_back_texture, size);
- ExpectAreTheSameImage(original, actual);
-}
-
-// Tests the default, one-pass bilinear shader which can upscale or downscale by
-// up to 2X.
-TEST_P(GLScalerShaderPixelTest, Bilinear) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- constexpr gfx::Rect whole = gfx::Rect(kBaseSize);
- constexpr gfx::Rect quadrant =
- gfx::Rect(kBaseSize.width() / 2, kBaseSize.height() / 2,
- kBaseSize.width() / 2, kBaseSize.height() / 2);
- const std::vector<SMPTEScalingTestCase> kTestCases = {
- // No scaling.
- {whole, 1, 1, 0},
- // Downscale by half.
- {whole, 2, 1, 1},
- // Upscale by 1.5.
- {whole, 2, 3, 1},
- // No scaling; lower-right quadrant only.
- {quadrant, 1, 1, 0},
- // Downscale by half; lower-right quadrant only.
- {quadrant, 2, 1, 1},
- // Upscale by 1.5; lower-right quadrant only.
- {quadrant, 2, 3, 1},
- };
-
- RunSMPTEScalingTestCases(Shader::BILINEAR, kTestCases);
-}
-
-// Test the 2-tap bilinear shader, which downscales by 4X in one dimension.
-TEST_P(GLScalerShaderPixelTest, TwoTapBilinear) {
- RunMultiplePassBilinearTest(Shader::BILINEAR2, 4,
- {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff)});
-}
-
-// Test the 3-tap bilinear shader, which downscales by 6X in one dimension.
-TEST_P(GLScalerShaderPixelTest, ThreeTapBilinear) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- RunMultiplePassBilinearTest(Shader::BILINEAR3, 6,
- {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0xbf, 0x00, 0x80, 0xff),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0xbf, 0xff, 0x80, 0x00),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff)});
-}
-
-// Test the 4-tap bilinear shader, which downscales by 8X in one dimension.
-TEST_P(GLScalerShaderPixelTest, FourTapBilinear) {
- RunMultiplePassBilinearTest(Shader::BILINEAR4, 8,
- {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff),
- SkColorSetARGB(0xff, 0xff, 0xff, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x80),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x80),
- SkColorSetARGB(0xff, 0xff, 0x00, 0xff)});
-}
-
-// Test the 2-by-2-tap bilinear shader, which downscales by 4X in both
-// dimensions at the same time.
-TEST_P(GLScalerShaderPixelTest, TwoByTwoTapBilinear) {
- RunMultiplePassBilinearTest(Shader::BILINEAR2X2, 4,
- {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0x7f, 0x00, 0x80, 0x00),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff)});
-}
-
-// Tests the bicubic upscaler for a variety of scaling factors between 1X and
-// 2X, and over the entire source texture versus just its lower-right quadrant.
-TEST_P(GLScalerShaderPixelTest, BicubicUpscale) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- constexpr gfx::Rect whole = gfx::Rect(kBaseSize);
- constexpr gfx::Rect quadrant =
- gfx::Rect(kBaseSize.width() / 2, kBaseSize.height() / 2,
- kBaseSize.width() / 2, kBaseSize.height() / 2);
- const std::vector<SMPTEScalingTestCase> kTestCases = {
- // No scaling.
- {whole, 1, 1, 0},
- // Upscale by 4/3.
- {whole, 3, 4, 3},
- // Upscale by 3/2.
- {whole, 2, 3, 3},
- // Upscale by 2X.
- {whole, 1, 2, 3},
- // No scaling; lower-right quadrant only.
- {quadrant, 1, 1, 0},
- // Upscale by 4/3.
- {quadrant, 3, 4, 3},
- // Upscale by 3/2.
- {quadrant, 2, 3, 3},
- // Upscale by 2X.
- {quadrant, 1, 2, 3},
- };
-
- RunSMPTEScalingTestCases(Shader::BICUBIC_UPSCALE, kTestCases);
-}
-
-// Tests the bicubic half-downscaler, both over an entire source texture and
-// over just its lower-right quadrant.
-TEST_P(GLScalerShaderPixelTest, BicubicDownscaleByHalf) {
- constexpr gfx::Rect whole = gfx::Rect(kBaseSize);
- constexpr gfx::Rect quadrant =
- gfx::Rect(kBaseSize.width() / 2, kBaseSize.height() / 2,
- kBaseSize.width() / 2, kBaseSize.height() / 2);
- const std::vector<SMPTEScalingTestCase> kTestCases = {
- // Downscale by half.
- {whole, 2, 1, 2},
- // Downscale by half; lower-right quadrant only.
- {quadrant, 2, 1, 2},
- };
-
- RunSMPTEScalingTestCases(Shader::BICUBIC_HALF_1D, kTestCases);
-}
-
-// Tests the shaders that read a normal 4-channel interleaved texture and
-// produce a planar texture consisting of just one color channel, packed into
-// RGBA quads.
-TEST_P(GLScalerShaderPixelTest, Export_Planar) {
- // Disabled on Marshmallow. See crbug.com/933080
- if (IsAndroidMarshmallow())
- return;
-
- const std::vector<SkColor> kCycle = {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0x80, 0x00, 0x80, 0x00),
- SkColorSetARGB(0x80, 0x00, 0x80, 0x00),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff)};
- SkBitmap source = CreateCyclicalTestImage(kBaseSize, STAGGERED, kCycle, 0);
- const GLuint src_texture = UploadTexture(source);
-
- // For each channel, create an expected bitmap and compare it to the result
- // from drawing with the shader program.
- if (is_converting_rgb_to_yuv()) {
- ConvertRGBABitmapToYUV(&source);
- }
- for (int channel = 0; channel <= 3; ++channel) {
- SkBitmap expected = CreatePackedPlanarBitmap(source, channel);
- if (is_swizzling_output()) {
- SwizzleBitmap(&expected);
- }
-
- const Shader shader = static_cast<Shader>(
- static_cast<int>(Shader::PLANAR_CHANNEL_0) + channel);
- const gfx::Size dst_size(kBaseSize.width() / 4, kBaseSize.height());
- GetShaderProgram(shader)->UseProgram(kBaseSize,
- gfx::RectF(gfx::Rect(kBaseSize)),
- dst_size, Axis::HORIZONTAL, false);
- const SkBitmap actual =
- DownloadTexture(RenderToNewTexture(src_texture, dst_size), dst_size);
- ExpectAreTheSameImage(expected, actual);
- }
-}
-
-// Tests that the I422/NV61 formatter shader program produces a planar texture
-// and an interleaved half-width texture from a normal 4-channel interleaved
-// texture. See gl_shader.h for more specifics.
-TEST_P(GLScalerShaderPixelTest, Export_I422_NV61) {
- if (!AreMultipleRenderingTargetsSupported()) {
- LOG(WARNING) << "Skipping test due to lack of MRT support on this machine.";
- return;
- }
-
- // Use a vertical stripes source image/texture to test that the shader is
- // sampling the texture at the correct points and performing
- // downscale-blending in the second texture.
- const std::vector<SkColor> kCycle = {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0x80, 0x00, 0x80, 0x00),
- SkColorSetARGB(0x80, 0x00, 0x80, 0x00),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff)};
- SkBitmap source =
- CreateCyclicalTestImage(kBaseSize, VERTICAL_STRIPES, kCycle, 0);
- const GLuint src_texture = UploadTexture(source);
-
- // Create the expected output images: The first (A) is simply the first color
- // channel of the source packed into a planar format. The second (BC) consists
- // of the second and third color channels downscaled by half and interleaved.
- // The following can be considered a reference implementation for what the
- // shader program is supposed to do.
- if (is_converting_rgb_to_yuv()) {
- ConvertRGBABitmapToYUV(&source);
- }
- SkBitmap expected_a = CreatePackedPlanarBitmap(source, 0);
- if (is_swizzling_output()) {
- SwizzleBitmap(&expected_a);
- }
- const gfx::Size dst_size(expected_a.width(), expected_a.height());
- SkBitmap expected_bc = AllocateRGBABitmap(dst_size);
- for (int y = 0; y < dst_size.height(); ++y) {
- const uint32_t* const src = source.getAddr32(0, y);
- uint32_t* const dst_bc = expected_bc.getAddr32(0, y);
- for (int x = 0; x < dst_size.width(); ++x) {
- // (src[0..3]) (dst_bc)
- // RGBA RGBA rgba rgba --> GBgb (e.g, two G's blended into one G)
- const uint32_t g01 = ((((src[x * 4 + 0] >> kGreenShift) & 0xff) +
- ((src[x * 4 + 1] >> kGreenShift) & 0xff)) /
- 2.f +
- 0.5f);
- const uint32_t b01 = ((((src[x * 4 + 0] >> kBlueShift) & 0xff) +
- ((src[x * 4 + 1] >> kBlueShift) & 0xff)) /
- 2.f +
- 0.5f);
- const uint32_t g23 = ((((src[x * 4 + 2] >> kGreenShift) & 0xff) +
- ((src[x * 4 + 3] >> kGreenShift) & 0xff)) /
- 2.f +
- 0.5f);
- const uint32_t b23 = ((((src[x * 4 + 2] >> kBlueShift) & 0xff) +
- ((src[x * 4 + 3] >> kBlueShift) & 0xff)) /
- 2.f +
- 0.5f);
- dst_bc[x] = ((g01 << kRedShift) | (b01 << kGreenShift) |
- (g23 << kBlueShift) | (b23 << kAlphaShift));
- }
- }
- if (is_swizzling_output()) {
- SwizzleBitmap(&expected_bc);
- }
-
- // Execute the program, and compare the shader program's drawn result with the
- // expected images.
- GetShaderProgram(Shader::I422_NV61_MRT)
- ->UseProgram(kBaseSize, gfx::RectF(gfx::Rect(kBaseSize)), dst_size,
- Axis::HORIZONTAL, false);
- const auto textures = RenderToNewTextures(src_texture, dst_size, true);
- const SkBitmap actual_a = DownloadTexture(textures.first, dst_size);
- ExpectAreTheSameImage(expected_a, actual_a);
- const SkBitmap actual_bc = DownloadTexture(textures.second, dst_size);
- ExpectAreTheSameImage(expected_bc, actual_bc);
-}
-
-// Tests that the PLANAR_CHANNELS_1_2 formatter shader program produces an
-// interleaved half-width texture from a normal 4-channel interleaved texture.
-// See gl_shader.h for more specifics.
-TEST_P(GLScalerShaderPixelTest, Export_PLANAR_CHANNELS_1_2) {
- // Use a vertical stripes source image/texture to test that the shader is
- // sampling the texture at the correct points and performing
- // downscale-blending in the second texture.
- const std::vector<SkColor> kCycle = {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0x80, 0x00, 0x80, 0x00),
- SkColorSetARGB(0x80, 0x00, 0x80, 0x00),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff)};
- SkBitmap source =
- CreateCyclicalTestImage(kBaseSize, VERTICAL_STRIPES, kCycle, 0);
- const GLuint src_texture = UploadTexture(source);
-
- // Create the expected output image: it consists of the second and third
- // color channels (BC) downscaled by half and interleaved.
- // The following can be considered a reference implementation for what the
- // shader program is supposed to do.
- if (is_converting_rgb_to_yuv()) {
- ConvertRGBABitmapToYUV(&source);
- }
-
- // 4x1 pixels get converted to a packed 1x1 pixel.
- const gfx::Size dst_size(source.width() / 4, source.height());
- SkBitmap expected_bc = AllocateRGBABitmap(dst_size);
- for (int y = 0; y < dst_size.height(); ++y) {
- const uint32_t* const src = source.getAddr32(0, y);
- uint32_t* const dst_bc = expected_bc.getAddr32(0, y);
- for (int x = 0; x < dst_size.width(); ++x) {
- // (src[0..3]) (dst_bc)
- // RGBA RGBA rgba rgba --> GBgb (e.g, two G's blended into one G)
- const uint32_t g01 = ((((src[x * 4 + 0] >> kGreenShift) & 0xff) +
- ((src[x * 4 + 1] >> kGreenShift) & 0xff)) /
- 2.f +
- 0.5f);
- const uint32_t b01 = ((((src[x * 4 + 0] >> kBlueShift) & 0xff) +
- ((src[x * 4 + 1] >> kBlueShift) & 0xff)) /
- 2.f +
- 0.5f);
- const uint32_t g23 = ((((src[x * 4 + 2] >> kGreenShift) & 0xff) +
- ((src[x * 4 + 3] >> kGreenShift) & 0xff)) /
- 2.f +
- 0.5f);
- const uint32_t b23 = ((((src[x * 4 + 2] >> kBlueShift) & 0xff) +
- ((src[x * 4 + 3] >> kBlueShift) & 0xff)) /
- 2.f +
- 0.5f);
- dst_bc[x] = ((g01 << kRedShift) | (b01 << kGreenShift) |
- (g23 << kBlueShift) | (b23 << kAlphaShift));
- }
- }
- if (is_swizzling_output()) {
- SwizzleBitmap(&expected_bc);
- }
-
- // Execute the program, and compare the shader program's drawn result with the
- // expected images.
- GetShaderProgram(Shader::PLANAR_CHANNELS_1_2)
- ->UseProgram(kBaseSize, gfx::RectF(gfx::Rect(kBaseSize)), dst_size,
- Axis::HORIZONTAL, false);
- const auto texture = RenderToNewTexture(src_texture, dst_size);
- const SkBitmap actual_bc = DownloadTexture(texture, dst_size);
- ExpectAreTheSameImage(expected_bc, actual_bc);
-}
-
-// Tests the pairwise-deinterleave shader program that produces two planar
-// textures from a single interleaved one.
-TEST_P(GLScalerShaderPixelTest, Export_PairwiseDeinterleave) {
- if (!AreMultipleRenderingTargetsSupported()) {
- LOG(WARNING) << "Skipping test due to lack of MRT support on this machine.";
- return;
- }
-
- // This shader does not provide color space conversion. It is just a
- // demultiplexer/repackager.
- if (is_converting_rgb_to_yuv()) {
- return;
- }
-
- // Create a source image/texture with a pattern suitable for ensuring the
- // shader is sampling the texture at the correct points.
- const std::vector<SkColor> kCycle = {SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0xc0, 0x00, 0xc0, 0x00),
- SkColorSetARGB(0x80, 0x00, 0x00, 0x80),
- SkColorSetARGB(0xff, 0xff, 0xff, 0xff)};
- const SkBitmap source =
- CreateCyclicalTestImage(kBaseSize, STAGGERED, kCycle, 0);
- const GLuint src_texture = UploadTexture(source);
-
- // Create the expected pair of planar images.
- const gfx::Size dst_size(kBaseSize.width() / 2, kBaseSize.height());
- SkBitmap expected_a = AllocateRGBABitmap(dst_size);
- SkBitmap expected_b = AllocateRGBABitmap(dst_size);
- for (int y = 0; y < dst_size.height(); ++y) {
- const uint32_t* const src = source.getAddr32(0, y);
- uint32_t* const dst_a = expected_a.getAddr32(0, y);
- uint32_t* const dst_b = expected_b.getAddr32(0, y);
- for (int x = 0; x < dst_size.width(); ++x) {
- // (src) (dst_a) (dst_b)
- // ABAB abab --> { AAaa + BBbb }
- dst_a[x] = ((((src[x * 2 + 0] >> kRedShift) & 0xff) << kRedShift) |
- (((src[x * 2 + 0] >> kBlueShift) & 0xff) << kGreenShift) |
- (((src[x * 2 + 1] >> kRedShift) & 0xff) << kBlueShift) |
- (((src[x * 2 + 1] >> kBlueShift) & 0xff) << kAlphaShift));
- dst_b[x] = ((((src[x * 2 + 0] >> kGreenShift) & 0xff) << kRedShift) |
- (((src[x * 2 + 0] >> kAlphaShift) & 0xff) << kGreenShift) |
- (((src[x * 2 + 1] >> kGreenShift) & 0xff) << kBlueShift) |
- (((src[x * 2 + 1] >> kAlphaShift) & 0xff) << kAlphaShift));
- }
- }
- if (is_swizzling_output()) {
- SwizzleBitmap(&expected_a);
- SwizzleBitmap(&expected_b);
- }
-
- // Execute the program, and compare the shader program's drawn result with the
- // expected images.
- GetShaderProgram(Shader::DEINTERLEAVE_PAIRWISE_MRT)
- ->UseProgram(kBaseSize, gfx::RectF(gfx::Rect(kBaseSize)), dst_size,
- Axis::HORIZONTAL, false);
- const auto textures = RenderToNewTextures(src_texture, dst_size, true);
- const SkBitmap actual_a = DownloadTexture(textures.first, dst_size);
- ExpectAreTheSameImage(expected_a, actual_a);
- const SkBitmap actual_b = DownloadTexture(textures.second, dst_size);
- ExpectAreTheSameImage(expected_b, actual_b);
-}
-
-INSTANTIATE_TEST_SUITE_P(All,
- GLScalerShaderPixelTest,
- testing::Combine(testing::Bool(), testing::Bool()));
-
-} // namespace viz
diff --git a/chromium/components/viz/common/gl_scaler_unittest.cc b/chromium/components/viz/common/gl_scaler_unittest.cc
deleted file mode 100644
index 67cab05ba02..00000000000
--- a/chromium/components/viz/common/gl_scaler_unittest.cc
+++ /dev/null
@@ -1,236 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/common/gl_scaler.h"
-
-#include "cc/test/pixel_test.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/test/gl_scaler_test_util.h"
-#include "gpu/GLES2/gl2chromium.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/common/capabilities.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-using ::testing::ByRef;
-using ::testing::Eq;
-using ::testing::Mock;
-using ::testing::NiceMock;
-using ::testing::NotNull;
-using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::SaveArg;
-using ::testing::Sequence;
-
-namespace viz {
-namespace {
-
-class MockContextProvider : public ContextProvider {
- public:
- MockContextProvider() {
- ON_CALL(*this, ContextGL())
- .WillByDefault(
- Return(reinterpret_cast<gpu::gles2::GLES2Interface*>(0xdeadbeef)));
- ON_CALL(*this, ContextCapabilities()).WillByDefault(ReturnRef(caps_));
- }
-
- MOCK_METHOD1(AddObserver, void(ContextLostObserver* obs));
- MOCK_METHOD1(RemoveObserver, void(ContextLostObserver* obs));
- MOCK_CONST_METHOD0(ContextCapabilities, const gpu::Capabilities&());
- MOCK_METHOD0(ContextGL, gpu::gles2::GLES2Interface*());
-
- // Stubbed-out, because the tests just stack-allocate this object.
- void AddRef() const final {}
- void Release() const final {}
-
- private:
- gpu::Capabilities caps_;
-
- // Other ContextProvider methods; but stubbed-out because they are never
- // called.
- gpu::ContextResult BindToCurrentThread() final {
- NOTREACHED();
- return gpu::ContextResult::kSuccess;
- }
- base::Lock* GetLock() final {
- NOTREACHED();
- return nullptr;
- }
- ContextCacheController* CacheController() final {
- NOTREACHED();
- return nullptr;
- }
- gpu::ContextSupport* ContextSupport() final {
- NOTREACHED();
- return nullptr;
- }
- class GrDirectContext* GrContext() final {
- NOTREACHED();
- return nullptr;
- }
- gpu::SharedImageInterface* SharedImageInterface() final {
- NOTREACHED();
- return nullptr;
- }
- const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const final {
- NOTREACHED();
- return *reinterpret_cast<gpu::GpuFeatureInfo*>(0xdeadbeef);
- }
-};
-
-class GLScalerTest : public cc::PixelTest {
- protected:
- void SetUp() final {
- cc::PixelTest::SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
- }
-
- void TearDown() final { cc::PixelTest::TearDown(); }
-};
-
-TEST_F(GLScalerTest, AddAndRemovesSelfAsContextLossObserver) {
- NiceMock<MockContextProvider> provider;
- ContextLostObserver* registered_observer = nullptr;
- Sequence s;
- EXPECT_CALL(provider, AddObserver(NotNull()))
- .InSequence(s)
- .WillOnce(SaveArg<0>(&registered_observer));
- EXPECT_CALL(provider, RemoveObserver(Eq(ByRef(registered_observer))))
- .InSequence(s);
- GLScaler scaler(&provider);
-}
-
-TEST_F(GLScalerTest, RemovesObserverWhenContextIsLost) {
- NiceMock<MockContextProvider> provider;
- ContextLostObserver* registered_observer = nullptr;
- Sequence s;
- EXPECT_CALL(provider, AddObserver(NotNull()))
- .InSequence(s)
- .WillOnce(SaveArg<0>(&registered_observer));
- EXPECT_CALL(provider, RemoveObserver(Eq(ByRef(registered_observer))))
- .InSequence(s);
- GLScaler scaler(&provider);
- static_cast<ContextLostObserver&>(scaler).OnContextLost();
- // Verify RemoveObserver() was called before |scaler| goes out-of-scope.
- Mock::VerifyAndClearExpectations(&provider);
-}
-
-TEST_F(GLScalerTest, StopsScalingWhenContextIsLost) {
- GLScaler scaler(context_provider());
-
- // Configure the scaler with default parameters (1:1 scale ratio).
- ASSERT_TRUE(scaler.Configure(GLScaler::Parameters()));
-
- // Call Scale() and expect it to return true to indicate the operation
- // succeeded.
- GLScalerTestTextureHelper helper(context_provider()->ContextGL());
- constexpr gfx::Size kSomeSize = gfx::Size(32, 32);
- const GLuint src_texture = helper.CreateTexture(kSomeSize);
- const GLuint dest_texture = helper.CreateTexture(kSomeSize);
- EXPECT_TRUE(scaler.Scale(src_texture, kSomeSize, gfx::Vector2d(),
- dest_texture, gfx::Rect(kSomeSize)));
-
- // After the context is lost, another call to Scale() should return false.
- static_cast<ContextLostObserver&>(scaler).OnContextLost();
- EXPECT_FALSE(scaler.Scale(src_texture, kSomeSize, gfx::Vector2d(),
- dest_texture, gfx::Rect(kSomeSize)));
-}
-
-TEST_F(GLScalerTest, Configure_RequiresValidScalingVectors) {
- GLScaler scaler(context_provider());
-
- GLScaler::Parameters params;
- EXPECT_TRUE(scaler.Configure(params));
-
- for (int i = 0; i < 4; ++i) {
- params.scale_from = gfx::Vector2d(i == 0 ? 0 : 1, i == 1 ? 0 : 1);
- params.scale_to = gfx::Vector2d(i == 2 ? 0 : 1, i == 3 ? 0 : 1);
- EXPECT_FALSE(scaler.Configure(params));
- }
-}
-
-TEST_F(GLScalerTest, Configure_ResolvesUnspecifiedColorSpaces) {
- GLScaler scaler(context_provider());
-
- // Neither source nor output space specified: Both should resolve to sRGB.
- GLScaler::Parameters params;
- EXPECT_TRUE(scaler.Configure(params));
- const auto srgb = gfx::ColorSpace::CreateSRGB();
- EXPECT_EQ(srgb, scaler.params().source_color_space);
- EXPECT_EQ(srgb, scaler.params().output_color_space);
- EXPECT_TRUE(GLScaler::ParametersAreEquivalent(params, scaler.params()));
-
- // Source space set to XYZD50 with no output space specified: Both should
- // resolve to XYZD50.
- const auto xyzd50 = gfx::ColorSpace::CreateXYZD50();
- params.source_color_space = xyzd50;
- EXPECT_TRUE(scaler.Configure(params));
- EXPECT_EQ(xyzd50, scaler.params().source_color_space);
- EXPECT_EQ(xyzd50, scaler.params().output_color_space);
- EXPECT_TRUE(GLScaler::ParametersAreEquivalent(params, scaler.params()));
-
- // Source space set to XYZD50 with output space set to P3D65: Nothing should
- // change.
- const auto p3d65 = gfx::ColorSpace::CreateDisplayP3D65();
- params.output_color_space = p3d65;
- EXPECT_TRUE(scaler.Configure(params));
- EXPECT_EQ(xyzd50, scaler.params().source_color_space);
- EXPECT_EQ(p3d65, scaler.params().output_color_space);
- EXPECT_TRUE(GLScaler::ParametersAreEquivalent(params, scaler.params()));
-}
-
-TEST_F(GLScalerTest, Configure_RequiresValidSwizzles) {
- GLScaler scaler(context_provider());
- GLScaler::Parameters params;
-
- // Test that all valid combinations work.
- for (int i = 0; i < 4; ++i) {
- params.swizzle[0] = (i % 2 == 0) ? GL_RGBA : GL_BGRA_EXT;
- params.swizzle[1] = (i / 2 == 0) ? GL_RGBA : GL_BGRA_EXT;
- EXPECT_TRUE(scaler.Configure(params)) << "i=" << i;
- }
-
- // Test that invalid combinations don't work.
- for (int i = 1; i < 4; ++i) {
- params.swizzle[0] = (i % 2 == 0) ? GL_RGBA : GL_RGB;
- params.swizzle[1] = (i / 2 == 0) ? GL_RGBA : GL_RGB;
- EXPECT_FALSE(scaler.Configure(params)) << "i=" << i;
- }
-}
-
-TEST_F(GLScalerTest, DetectsEquivalentScaleRatios) {
- GLScaler::Parameters params;
- EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(params, gfx::Vector2d(1, 1),
- gfx::Vector2d(1, 1)));
- EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(
- params, gfx::Vector2d(15, 15), gfx::Vector2d(15, 15)));
-
- params.scale_from = gfx::Vector2d(2, 1);
- EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(params, gfx::Vector2d(2, 1),
- gfx::Vector2d(1, 1)));
- EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(
- params, gfx::Vector2d(30, 15), gfx::Vector2d(15, 15)));
-
- params.scale_from = gfx::Vector2d(1, 2);
- EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(params, gfx::Vector2d(1, 2),
- gfx::Vector2d(1, 1)));
- EXPECT_TRUE(GLScaler::ParametersHasSameScaleRatio(
- params, gfx::Vector2d(15, 30), gfx::Vector2d(15, 15)));
-
- params.scale_from = gfx::Vector2d(2, 1);
- EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio(
- params, gfx::Vector2d(1, 2), gfx::Vector2d(1, 1)));
- EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio(
- params, gfx::Vector2d(15, 30), gfx::Vector2d(15, 15)));
-
- params.scale_from = gfx::Vector2d(1, 2);
- EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio(
- params, gfx::Vector2d(2, 1), gfx::Vector2d(1, 1)));
- EXPECT_FALSE(GLScaler::ParametersHasSameScaleRatio(
- params, gfx::Vector2d(30, 15), gfx::Vector2d(15, 15)));
-}
-
-} // namespace
-} // namespace viz
diff --git a/chromium/components/viz/common/gpu/context_cache_controller.cc b/chromium/components/viz/common/gpu/context_cache_controller.cc
index 80425d801e6..9086c6e42cd 100644
--- a/chromium/components/viz/common/gpu/context_cache_controller.cc
+++ b/chromium/components/viz/common/gpu/context_cache_controller.cc
@@ -11,6 +11,7 @@
#include "base/check_op.h"
#include "base/memory/ptr_util.h"
#include "base/synchronization/lock.h"
+#include "base/time/time.h"
#include "gpu/command_buffer/client/context_support.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
diff --git a/chromium/components/viz/common/overlay_state/win/DEPS b/chromium/components/viz/common/overlay_state/win/DEPS
new file mode 100644
index 00000000000..19fb5f11f6f
--- /dev/null
+++ b/chromium/components/viz/common/overlay_state/win/DEPS
@@ -0,0 +1,8 @@
+# Please consult components/viz/README.md about allowable dependencies.
+
+include_rules = [
+ "+components/viz/test",
+ "+gpu/command_buffer",
+ "+gpu/ipc/common",
+ "+mojo/public/cpp/bindings",
+]
diff --git a/chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.cc b/chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.cc
new file mode 100644
index 00000000000..bebe165d095
--- /dev/null
+++ b/chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.cc
@@ -0,0 +1,28 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/common/overlay_state/win/overlay_state_aggregator.h"
+
+namespace viz {
+
+bool OverlayStateAggregator::SetPromotionHint(bool promoted) {
+ OverlayStateAggregator::PromotionState recommendation =
+ promoted ? OverlayStateAggregator::PromotionState::kPromoted
+ : OverlayStateAggregator::PromotionState::kNotPromoted;
+
+ if (recommendation != promotion_state_) {
+ promotion_state_ = recommendation;
+ return true;
+ }
+
+ // No change.
+ return false;
+}
+
+OverlayStateAggregator::PromotionState
+OverlayStateAggregator::GetPromotionState() {
+ return promotion_state_;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.h b/chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.h
new file mode 100644
index 00000000000..7fc87afa568
--- /dev/null
+++ b/chromium/components/viz/common/overlay_state/win/overlay_state_aggregator.h
@@ -0,0 +1,29 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_COMMON_OVERLAY_STATE_WIN_OVERLAY_STATE_AGGREGATOR_H_
+#define COMPONENTS_VIZ_COMMON_OVERLAY_STATE_WIN_OVERLAY_STATE_AGGREGATOR_H_
+
+namespace viz {
+
+class OverlayStateAggregator {
+ public:
+ OverlayStateAggregator() = default;
+ ~OverlayStateAggregator() = default;
+
+ enum class PromotionState { kUnset, kNotPromoted, kPromoted };
+
+ // Sets a new promotion hint & returns whether the promotion recommendation
+ // state has changed.
+ bool SetPromotionHint(bool promoted);
+ // Gets current promotion recommendation.
+ PromotionState GetPromotionState();
+
+ private:
+ PromotionState promotion_state_ = PromotionState::kUnset;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_OVERLAY_STATE_WIN_OVERLAY_STATE_AGGREGATOR_H_
diff --git a/chromium/components/viz/common/overlay_state/win/overlay_state_service.cc b/chromium/components/viz/common/overlay_state/win/overlay_state_service.cc
new file mode 100644
index 00000000000..38edb2d39ff
--- /dev/null
+++ b/chromium/components/viz/common/overlay_state/win/overlay_state_service.cc
@@ -0,0 +1,184 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/common/overlay_state/win/overlay_state_service.h"
+
+#include <utility>
+
+#include "base/task/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+
+namespace viz {
+
+OverlayStateService::MailboxState::MailboxState() = default;
+OverlayStateService::MailboxState::~MailboxState() = default;
+OverlayStateService::OverlayStateService() = default;
+OverlayStateService::~OverlayStateService() = default;
+
+OverlayStateService* OverlayStateService::GetInstance() {
+ // TODO(wicarr, crbug.com/1316009): Ideally the OverlayStateService should be
+ // a singleton. Instead the GpuServiceImpl should be responsible for creating
+ // the OverlayStateService and injecting it into dependent GpuChannel(s) and
+ // the DCLayerOverlayProcessor. Further the OverlayStateService should live
+ // in gpu to avoid gpu needing to take a dependency on viz.
+ static base::NoDestructor<OverlayStateService> service_wrapper;
+ return service_wrapper.get();
+}
+
+void OverlayStateService::Initialize(
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
+ // GpuServiceImpl is expected to initialize the OverlayStateService and
+ // OverlayStateService will operate on the GpuMain sequenced task runner.
+ // RegisterObserver is expected to be called by GpuChannel and should operate
+ // on the same GpuMain sequence as GpuServiceImpl.
+ // SetPromotionHint is called by DCLayerOverlayProcessor which operates on a
+ // separate task sequence, VizCompositorThread, so calls are posted to
+ // 'task_runner_' to allow mojo'ing back out to bound PromotionHintObserver
+ // clients on the proper sequence.
+ DCHECK(!initialized_);
+ task_runner_ = std::move(task_runner);
+ initialized_ = true;
+}
+
+bool OverlayStateService::IsInitialized() {
+ return initialized_;
+}
+
+void OverlayStateService::RegisterObserver(
+ mojo::PendingRemote<gpu::mojom::OverlayStateObserver>
+ overlay_state_observer,
+ const gpu::Mailbox& mailbox) {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+ MailboxState*& mailbox_state = mailboxes_[mailbox];
+ if (!mailbox_state) {
+ mailbox_state = new MailboxState();
+ // Use of base::Unretained is safe as OverlayStateService is a singleton
+ // service bound to the lifetime of the GPU process.
+ mailbox_state->observer_set_.set_disconnect_handler(
+ base::BindRepeating(&OverlayStateService::OnBoundObserverDisconnect,
+ base::Unretained(this), mailbox));
+ }
+
+ // Add observer to the RemoteSet
+ mojo::RemoteSetElementId id =
+ mailbox_state->observer_set_.Add(std::move(overlay_state_observer));
+
+ // It's possible that the overlay processor has already set promotion hint
+ // information for this mailbox. If this is the case then we send a Hint
+ // Changed event to the observer to inform them of the current promotion
+ // state.
+ OverlayStateAggregator::PromotionState promotion_state =
+ mailbox_state->aggregator_.GetPromotionState();
+
+ // If promotion state is unset there is no further work to do. If it is set
+ // then inform the new observer of the current state.
+ if (promotion_state != OverlayStateAggregator::PromotionState::kUnset) {
+ bool promoted =
+ promotion_state == OverlayStateAggregator::PromotionState::kPromoted;
+ mailbox_state->observer_set_.Get(id)->OnStateChanged(promoted);
+ }
+}
+
+void OverlayStateService::OnBoundObserverDisconnect(const gpu::Mailbox& mailbox,
+ mojo::RemoteSetElementId) {
+ auto mailbox_iterator = mailboxes_.find(mailbox);
+ if (mailbox_iterator != mailboxes_.end() &&
+ mailbox_iterator->second->observer_set_.empty()) {
+ // When the last observer has been disconnected, stop tracking mailbox.
+ mailboxes_.erase(mailbox_iterator);
+ }
+}
+
+void OverlayStateService::OnStateChanged(
+ const gpu::Mailbox& mailbox,
+ OverlayStateAggregator::PromotionState promotion_state) {
+ // If promotion state is unset there is no further work to do.
+ if (promotion_state == OverlayStateAggregator::PromotionState::kUnset)
+ return;
+
+ if (!task_runner_->RunsTasksInCurrentSequence()) {
+ // Use of base::Unretained is safe as OverlayStateService is a singleton
+ // service bound to the lifetime of the GPU process.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OverlayStateService::OnStateChangedOnTaskRunnerSequence,
+ base::Unretained(this), mailbox, promotion_state));
+ } else {
+ OnStateChangedOnTaskRunnerSequence(mailbox, promotion_state);
+ }
+}
+
+void OverlayStateService::OnStateChangedOnTaskRunnerSequence(
+ const gpu::Mailbox& mailbox,
+ OverlayStateAggregator::PromotionState promotion_state) {
+ // Notify all observers of the new hint state.
+ bool promoted =
+ promotion_state == OverlayStateAggregator::PromotionState::kPromoted;
+ auto mailbox_iterator = mailboxes_.find(mailbox);
+ DCHECK(mailbox_iterator != mailboxes_.end());
+ for (auto& observer : mailbox_iterator->second->observer_set_) {
+ observer->OnStateChanged(promoted);
+ }
+}
+
+void OverlayStateService::SetPromotionHint(const gpu::Mailbox& mailbox,
+ bool promoted) {
+ DCHECK(!task_runner_->RunsTasksInCurrentSequence());
+ // Use of base::Unretained is safe as OverlayStateService is a singleton
+ // service bound to the lifetime of the GPU process.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OverlayStateService::SetPromotionHintOnTaskRunnerSequence,
+ base::Unretained(this), mailbox, promoted));
+}
+
+void OverlayStateService::SetPromotionHintOnTaskRunnerSequence(
+ const gpu::Mailbox& mailbox,
+ bool promoted) {
+ // The OverlayStateService is made aware of mailboxes of interest through two
+ // channels:
+ // 1.) The registration of an observer for a mailbox.
+ // 2.) The setting of a promotion hint for a mailbox (the overlay processor
+ // will only send hints for mailboxes which are tagged as
+ // 'wants_promotion_hint' on their TransferResource).
+ //
+ // If this is the first promotion hint associated with a mailbox which has
+ // not had an observer registered yet, then we will not have an existing
+ // entry in 'mailboxes_' tracking it. Since there is no guarantee when we'll
+ // receive another promotion hint for the mailbox we'll store the result so
+ // any future observer can be informed of the current promotion state.
+ auto mailbox_iterator = mailboxes_.find(mailbox);
+ if (mailbox_iterator != mailboxes_.end()) {
+ bool state_change =
+ mailbox_iterator->second->aggregator_.SetPromotionHint(promoted);
+ if (state_change) {
+ // Notifying observers requires an IPC so we only send an update when
+ // the underlying state changes.
+ OnStateChanged(mailbox,
+ mailbox_iterator->second->aggregator_.GetPromotionState());
+ }
+ } else {
+ MailboxState* new_mailbox_state = new MailboxState();
+ new_mailbox_state->aggregator_.SetPromotionHint(promoted);
+ mailboxes_.insert({mailbox, new_mailbox_state});
+ }
+}
+
+void OverlayStateService::MailboxDestroyed(const gpu::Mailbox& mailbox) {
+ DCHECK(!task_runner_->RunsTasksInCurrentSequence());
+ // Use of base::Unretained is safe as OverlayStateService is a singleton
+ // service bound to the lifetime of the GPU process.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OverlayStateService::MailboxDestroyedOnTaskRunnerSequence,
+ base::Unretained(this), mailbox));
+}
+
+void OverlayStateService::MailboxDestroyedOnTaskRunnerSequence(
+ const gpu::Mailbox& mailbox) {
+ mailboxes_.erase(mailbox);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/overlay_state/win/overlay_state_service.h b/chromium/components/viz/common/overlay_state/win/overlay_state_service.h
new file mode 100644
index 00000000000..50c95d0f371
--- /dev/null
+++ b/chromium/components/viz/common/overlay_state/win/overlay_state_service.h
@@ -0,0 +1,83 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_COMMON_OVERLAY_STATE_WIN_OVERLAY_STATE_SERVICE_H_
+#define COMPONENTS_VIZ_COMMON_OVERLAY_STATE_WIN_OVERLAY_STATE_SERVICE_H_
+
+#include "base/no_destructor.h"
+#include "components/viz/common/overlay_state/win/overlay_state_aggregator.h"
+#include "components/viz/common/viz_common_export.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/ipc/common/gpu_channel.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+
+namespace viz {
+
+using OverlayStateObserver = gpu::mojom::OverlayStateObserver;
+
+// The OverlayStateService allows a MediaFoundationRendererClient, running in
+// a Renderer process, to understand whether the quads associated with its
+// video presentation textures are being promoted to a Direct Composition layer
+// by Viz. This allows the MediaFoundationRendererClient to determine the
+// appropriate presentation mode to use as the Windowless Swapchain mode
+// requires Direct Composition support to work.
+//
+// The mailbox associated with a texture is used as the common identifier
+// between the overlay processor in Viz & the MediaFoundationRendererClient.
+// Further the quad associated with the mailbox has it's associated
+// TransferResource tagged with 'wants_promotion_hint' to ensure that the
+// overlay processor only sends the OverlayStateService hints for mailboxes of
+// interest.
+//
+// The OverlayStateService aggregates hints to help ensure minimal IPC overhead
+// in keeping the MediaFoundationRendererClient informed of the current
+// promotion state.
+class VIZ_COMMON_EXPORT OverlayStateService {
+ public:
+ static OverlayStateService* GetInstance();
+ void Initialize(scoped_refptr<base::SequencedTaskRunner> task_runner);
+ bool IsInitialized();
+
+ void RegisterObserver(mojo::PendingRemote<gpu::mojom::OverlayStateObserver>
+ promotion_hint_observer,
+ const gpu::Mailbox& mailbox);
+ void SetPromotionHint(const gpu::Mailbox& mailbox, bool promoted);
+ void MailboxDestroyed(const gpu::Mailbox& mailbox);
+
+ private:
+ friend class base::NoDestructor<OverlayStateService>;
+ OverlayStateService();
+ ~OverlayStateService();
+ OverlayStateService(const OverlayStateService&) = delete;
+ OverlayStateService& operator=(const OverlayStateService&) = delete;
+
+ void OnBoundObserverDisconnect(const gpu::Mailbox& mailbox,
+ mojo::RemoteSetElementId);
+ void OnStateChanged(const gpu::Mailbox& mailbox,
+ OverlayStateAggregator::PromotionState promoted);
+ void OnStateChangedOnTaskRunnerSequence(
+ const gpu::Mailbox& mailbox,
+ OverlayStateAggregator::PromotionState promoted);
+ void SetPromotionHintOnTaskRunnerSequence(const gpu::Mailbox& mailbox,
+ bool promoted);
+ void MailboxDestroyedOnTaskRunnerSequence(const gpu::Mailbox& mailbox);
+
+ struct MailboxState {
+ MailboxState();
+ ~MailboxState();
+ OverlayStateAggregator aggregator_;
+ mojo::RemoteSet<OverlayStateObserver> observer_set_;
+ };
+
+ bool initialized_ = false;
+ base::flat_map<gpu::Mailbox, MailboxState*> mailboxes_;
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_OVERLAY_STATE_WIN_OVERLAY_STATE_SERVICE_H_
diff --git a/chromium/components/viz/common/overlay_state/win/overlay_state_service_unittest.cc b/chromium/components/viz/common/overlay_state/win/overlay_state_service_unittest.cc
new file mode 100644
index 00000000000..dcd05e86023
--- /dev/null
+++ b/chromium/components/viz/common/overlay_state/win/overlay_state_service_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "base/task/single_thread_task_runner.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread.h"
+#include "components/viz/common/overlay_state/win/overlay_state_service.h"
+#include "components/viz/test/viz_test_suite.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/ipc/common/gpu_channel.mojom.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Combine;
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgPointee;
+using testing::Values;
+
+namespace viz {
+
+class OverlayStateServiceUnittest : public testing::Test,
+ public gpu::mojom::OverlayStateObserver {
+ public:
+ OverlayStateServiceUnittest()
+ : receiver_(this), other_thread_("Other Thread") {}
+ // PromotionHintObserver
+ void OnStateChanged(bool promoted) override;
+ void SetUp() override;
+
+ protected:
+ void PerformRegistration(const gpu::Mailbox& mailbox);
+ void SetService();
+
+ // Helper functions for running SetPromotionHint & MailboxDestroyed calls to
+ // the OverlayStateService on a separate task sequence.
+ base::OnceClosure SetPromotionHintClosure(const gpu::Mailbox& mailbox,
+ bool promoted);
+ void SetPromotionHint(const gpu::Mailbox& mailbox, bool promoted);
+ void SetPromotionHintWorker(const gpu::Mailbox& mailbox, bool promoted);
+ base::OnceClosure DestroyMailboxClosure(const gpu::Mailbox& mailbox);
+ void DestroyMailbox(const gpu::Mailbox& mailbox);
+ void DestroyMailboxWorker(const gpu::Mailbox& mailbox);
+
+ // In order to simulate the OverlayStateService running on GpuMain and the
+ // DCLayerOverlayProcessor running on VizCompositorMain we create a separate
+ // thread & task runner where SetPromotionHint & DestroyMailbox calls are
+ // executed from.
+ scoped_refptr<base::SingleThreadTaskRunner> other_thread_task_runner_;
+
+ raw_ptr<OverlayStateService> service_;
+ mojo::Receiver<gpu::mojom::OverlayStateObserver> receiver_;
+ int hint_received_ = 0;
+ bool last_promote_value_ = false;
+
+ private:
+ base::Thread other_thread_;
+};
+
+void OverlayStateServiceUnittest::SetUp() {
+ other_thread_.StartAndWaitForTesting();
+ other_thread_task_runner_ = other_thread_.task_runner();
+}
+
+void OverlayStateServiceUnittest::OnStateChanged(bool promoted) {
+ hint_received_++;
+ last_promote_value_ = promoted;
+}
+
+void OverlayStateServiceUnittest::PerformRegistration(
+ const gpu::Mailbox& mailbox) {
+ service_->RegisterObserver(receiver_.BindNewPipeAndPassRemote(), mailbox);
+}
+
+void OverlayStateServiceUnittest::SetService() {
+ service_ = OverlayStateService::GetInstance();
+ if (!service_->IsInitialized()) {
+ service_->Initialize(base::SequencedTaskRunnerHandle::Get());
+ }
+}
+
+void OverlayStateServiceUnittest::SetPromotionHint(const gpu::Mailbox& mailbox,
+ bool promoted) {
+ base::RunLoop run_loop;
+ other_thread_task_runner_->PostTask(
+ FROM_HERE, SetPromotionHintClosure(std::move(mailbox), promoted));
+ other_thread_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+base::OnceClosure OverlayStateServiceUnittest::SetPromotionHintClosure(
+ const gpu::Mailbox& mailbox,
+ bool promoted) {
+ return base::BindOnce(&OverlayStateServiceUnittest::SetPromotionHintWorker,
+ base::Unretained(this), std::move(mailbox), promoted);
+}
+
+void OverlayStateServiceUnittest::SetPromotionHintWorker(
+ const gpu::Mailbox& mailbox,
+ bool promoted) {
+ service_->SetPromotionHint(mailbox, promoted);
+}
+
+void OverlayStateServiceUnittest::DestroyMailbox(const gpu::Mailbox& mailbox) {
+ base::RunLoop run_loop;
+ other_thread_task_runner_->PostTask(
+ FROM_HERE, DestroyMailboxClosure(std::move(mailbox)));
+ other_thread_task_runner_->PostTask(FROM_HERE,
+ base::BindOnce(run_loop.QuitClosure()));
+ run_loop.Run();
+}
+
+base::OnceClosure OverlayStateServiceUnittest::DestroyMailboxClosure(
+ const gpu::Mailbox& mailbox) {
+ return base::BindOnce(&OverlayStateServiceUnittest::DestroyMailboxWorker,
+ base::Unretained(this), std::move(mailbox));
+}
+
+void OverlayStateServiceUnittest::DestroyMailboxWorker(
+ const gpu::Mailbox& mailbox) {
+ service_->MailboxDestroyed(mailbox);
+}
+
+TEST_F(OverlayStateServiceUnittest, ServiceSingleton) {
+ OverlayStateService* service = OverlayStateService::GetInstance();
+ EXPECT_NE(service, nullptr);
+
+ OverlayStateService* service_instance_2 = OverlayStateService::GetInstance();
+ EXPECT_EQ(service, service_instance_2);
+}
+
+TEST_F(OverlayStateServiceUnittest, AddObserver) {
+ SetService();
+
+ // Add observer for a new mailbox
+ gpu::Mailbox mailbox = gpu::Mailbox::Generate();
+ PerformRegistration(mailbox);
+
+ // Add observer for existing mailbox with set promotion state
+ gpu::Mailbox mailbox2 = gpu::Mailbox::Generate();
+ SetPromotionHint(mailbox2, true);
+ VizTestSuite::RunUntilIdle();
+ receiver_.reset();
+ PerformRegistration(mailbox2);
+ VizTestSuite::RunUntilIdle();
+ EXPECT_EQ(hint_received_, 1);
+ EXPECT_EQ(last_promote_value_, true);
+}
+
+TEST_F(OverlayStateServiceUnittest, SetHint) {
+ SetService();
+ gpu::Mailbox mailbox = gpu::Mailbox::Generate();
+ PerformRegistration(mailbox);
+ VizTestSuite::RunUntilIdle();
+ SetPromotionHint(mailbox, true);
+ VizTestSuite::RunUntilIdle();
+ EXPECT_EQ(hint_received_, 1);
+ EXPECT_EQ(last_promote_value_, true);
+ SetPromotionHint(mailbox, false);
+ VizTestSuite::RunUntilIdle();
+ EXPECT_EQ(hint_received_, 2);
+ EXPECT_EQ(last_promote_value_, false);
+}
+
+TEST_F(OverlayStateServiceUnittest, DeleteMailbox) {
+ SetService();
+ gpu::Mailbox mailbox = gpu::Mailbox::Generate();
+ PerformRegistration(mailbox);
+ VizTestSuite::RunUntilIdle();
+ SetPromotionHint(mailbox, true);
+ VizTestSuite::RunUntilIdle();
+ EXPECT_EQ(hint_received_, 1);
+ EXPECT_EQ(last_promote_value_, true);
+ // Tell the OverlayStateService the mailbox has been destroyed, but
+ // don't actually destroy the mailbox for testing purposes as we want to
+ // ensure another mailbox with the same identifier is treated as a separate
+ // entity.
+ DestroyMailbox(mailbox);
+ // Send another promotion hint for the mailbox - we expect that we will not
+ // receive a hint changed callback this time because when the mailbox was
+ // "destroyed" any registered observers should have been removed.
+ SetPromotionHint(mailbox, false);
+ VizTestSuite::RunUntilIdle();
+ EXPECT_EQ(hint_received_, 1);
+ EXPECT_EQ(last_promote_value_, true);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc b/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc
index c6d54156909..dcc1d09ddd6 100644
--- a/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc
+++ b/chromium/components/viz/common/quads/compositor_render_pass_unittest.cc
@@ -333,7 +333,7 @@ TEST(CompositorRenderPassTest, ReplacedQuadsGetColor) {
quad->SetNew(quad_state, quad_rect, quad_rect, SK_ColorRED, false);
pass->ReplaceExistingQuadWithSolidColor(pass->quad_list.begin(),
SK_ColorGREEN, SkBlendMode::kSrcOver);
- EXPECT_EQ(SK_ColorGREEN, quad->color);
+ EXPECT_EQ(SkColors::kGreen, quad->color);
}
TEST(CompositorRenderPassTest, ReplacedQuadsGetBlendMode) {
diff --git a/chromium/components/viz/common/quads/debug_border_draw_quad.cc b/chromium/components/viz/common/quads/debug_border_draw_quad.cc
index f519911e3be..ef991ec8a21 100644
--- a/chromium/components/viz/common/quads/debug_border_draw_quad.cc
+++ b/chromium/components/viz/common/quads/debug_border_draw_quad.cc
@@ -20,7 +20,8 @@ void DebugBorderDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
bool needs_blending = SkColorGetA(c) < 255;
DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kDebugBorder, rect,
visible_rect, needs_blending);
- color = c;
+ // TODO(crbug/1308932) remove FromColor and make all SkColor4f
+ color = SkColor4f::FromColor(c);
width = w;
}
@@ -32,7 +33,8 @@ void DebugBorderDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
int w) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kDebugBorder, rect,
visible_rect, needs_blending);
- color = c;
+ // TODO(crbug/1308932) remove FromColor and make all SkColor4f
+ color = SkColor4f::FromColor(c);
width = w;
}
@@ -44,7 +46,8 @@ const DebugBorderDrawQuad* DebugBorderDrawQuad::MaterialCast(
void DebugBorderDrawQuad::ExtendValue(
base::trace_event::TracedValue* value) const {
- value->SetString("color", color_utils::SkColorToRgbaString(color));
+ value->SetString("color",
+ color_utils::SkColorToRgbaString(color.toSkColor()));
value->SetInteger("width", width);
}
diff --git a/chromium/components/viz/common/quads/debug_border_draw_quad.h b/chromium/components/viz/common/quads/debug_border_draw_quad.h
index 8772645f855..9d8119e6912 100644
--- a/chromium/components/viz/common/quads/debug_border_draw_quad.h
+++ b/chromium/components/viz/common/quads/debug_border_draw_quad.h
@@ -28,7 +28,7 @@ class VIZ_COMMON_EXPORT DebugBorderDrawQuad : public DrawQuad {
SkColor c,
int w);
- SkColor color = SK_ColorTRANSPARENT;
+ SkColor4f color = SkColors::kTransparent;
int width = 0;
static const DebugBorderDrawQuad* MaterialCast(const DrawQuad*);
diff --git a/chromium/components/viz/common/quads/draw_quad_unittest.cc b/chromium/components/viz/common/quads/draw_quad_unittest.cc
index 8f0a24327e1..ca9c0f29d06 100644
--- a/chromium/components/viz/common/quads/draw_quad_unittest.cc
+++ b/chromium/components/viz/common/quads/draw_quad_unittest.cc
@@ -179,12 +179,12 @@ TEST(DrawQuadTest, CopyDebugBorderDrawQuad) {
CREATE_QUAD_NEW(DebugBorderDrawQuad, visible_rect, color, width);
EXPECT_EQ(DrawQuad::Material::kDebugBorder, copy_quad->material);
EXPECT_EQ(visible_rect, copy_quad->visible_rect);
- EXPECT_EQ(color, copy_quad->color);
+ EXPECT_EQ(SkColor4f::FromColor(color), copy_quad->color);
EXPECT_EQ(width, copy_quad->width);
CREATE_QUAD_ALL(DebugBorderDrawQuad, color, width);
EXPECT_EQ(DrawQuad::Material::kDebugBorder, copy_quad->material);
- EXPECT_EQ(color, copy_quad->color);
+ EXPECT_EQ(SkColor4f::FromColor(color), copy_quad->color);
EXPECT_EQ(width, copy_quad->width);
}
@@ -226,6 +226,7 @@ TEST(DrawQuadTest, CopyRenderPassDrawQuad) {
TEST(DrawQuadTest, CopySolidColorDrawQuad) {
gfx::Rect visible_rect(40, 50, 30, 20);
+ // TODO(crbug.com/1308932): Use SkColor4f here
SkColor color = 0x49494949;
bool force_anti_aliasing_off = false;
CREATE_SHARED_STATE();
@@ -234,12 +235,12 @@ TEST(DrawQuadTest, CopySolidColorDrawQuad) {
force_anti_aliasing_off);
EXPECT_EQ(DrawQuad::Material::kSolidColor, copy_quad->material);
EXPECT_EQ(visible_rect, copy_quad->visible_rect);
- EXPECT_EQ(color, copy_quad->color);
+ EXPECT_EQ(SkColor4f::FromColor(color), copy_quad->color);
EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
CREATE_QUAD_ALL(SolidColorDrawQuad, color, force_anti_aliasing_off);
EXPECT_EQ(DrawQuad::Material::kSolidColor, copy_quad->material);
- EXPECT_EQ(color, copy_quad->color);
+ EXPECT_EQ(SkColor4f::FromColor(color), copy_quad->color);
EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
}
diff --git a/chromium/components/viz/common/quads/render_pass_io.cc b/chromium/components/viz/common/quads/render_pass_io.cc
index 51f57f46f3c..4a3fa5d6c68 100644
--- a/chromium/components/viz/common/quads/render_pass_io.cc
+++ b/chromium/components/viz/common/quads/render_pass_io.cc
@@ -160,6 +160,50 @@ bool PointFromDict(const base::Value& dict, gfx::Point* point) {
return true;
}
+base::Value SkColor4fToDict(const SkColor4f color) {
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetDoubleKey("red", color.fR);
+ dict.SetDoubleKey("green", color.fG);
+ dict.SetDoubleKey("blue", color.fB);
+ dict.SetDoubleKey("alpha", color.fA);
+ return dict;
+}
+
+bool SkColor4fFromDict(const base::Value& dict, SkColor4f* color) {
+ DCHECK(color);
+ if (!dict.is_dict())
+ return false;
+ absl::optional<double> red = dict.FindDoubleKey("red");
+ absl::optional<double> green = dict.FindDoubleKey("green");
+ absl::optional<double> blue = dict.FindDoubleKey("blue");
+ absl::optional<double> alpha = dict.FindDoubleKey("alpha");
+ if (!red || !green || !blue || !alpha)
+ return false;
+ color->fR = static_cast<float>(red.value());
+ color->fG = static_cast<float>(green.value());
+ color->fB = static_cast<float>(blue.value());
+ color->fA = static_cast<float>(alpha.value());
+ return true;
+}
+
+// Many quads now store color as an SkColor4f, but older logs will still store
+// SkColors (which are ints). For backward compatibility's sake, read either.
+bool ColorFromDict(const base::Value& dict,
+ base::StringPiece key,
+ SkColor& output_color) {
+ const base::Value* color_key = dict.FindDictKey(key);
+ SkColor4f color_4f;
+ if (!color_key || !SkColor4fFromDict(*color_key, &color_4f)) {
+ absl::optional<int> color_int = dict.FindIntKey(key);
+ if (!color_int)
+ return false;
+ output_color = static_cast<SkColor>(color_int.value());
+ return true;
+ }
+ output_color = color_4f.toSkColor();
+ return true;
+}
+
base::Value PointFToDict(const gfx::PointF& point) {
base::Value dict(base::Value::Type::DICTIONARY);
dict.SetDoubleKey("x", point.x());
@@ -467,7 +511,7 @@ base::Value FilterOperationToDict(const cc::FilterOperation& filter) {
dict.SetKey("drop_shadow_offset",
PointToDict(filter.drop_shadow_offset()));
dict.SetIntKey("drop_shadow_color",
- bit_cast<int>(filter.drop_shadow_color()));
+ base::bit_cast<int>(filter.drop_shadow_color()));
break;
case cc::FilterOperation::REFERENCE:
dict.SetStringKey("image_filter",
@@ -540,7 +584,7 @@ bool FilterOperationFromDict(const base::Value& dict,
}
filter.set_drop_shadow_offset(offset);
filter.set_drop_shadow_color(
- bit_cast<SkColor>(drop_shadow_color.value()));
+ base::bit_cast<SkColor>(drop_shadow_color.value()));
} break;
case cc::FilterOperation::REFERENCE:
if (!image_filter)
@@ -649,6 +693,7 @@ const char* ColorSpaceTransferIdToString(gfx::ColorSpace::TransferID id) {
MATCH_ENUM_CASE(TransferID, CUSTOM)
MATCH_ENUM_CASE(TransferID, CUSTOM_HDR)
MATCH_ENUM_CASE(TransferID, PIECEWISE_HDR)
+ MATCH_ENUM_CASE(TransferID, SCRGB_LINEAR_80_NITS)
}
}
@@ -729,6 +774,7 @@ uint8_t StringToColorSpaceTransferId(const std::string& token) {
MATCH_ENUM_CASE(TransferID, CUSTOM)
MATCH_ENUM_CASE(TransferID, CUSTOM_HDR)
MATCH_ENUM_CASE(TransferID, PIECEWISE_HDR)
+ MATCH_ENUM_CASE(TransferID, SCRGB_LINEAR_80_NITS)
return -1;
}
@@ -1131,7 +1177,7 @@ void SolidColorDrawQuadToDict(const SolidColorDrawQuad* draw_quad,
base::Value* dict) {
DCHECK(draw_quad);
DCHECK(dict);
- dict->SetIntKey("color", static_cast<int>(draw_quad->color));
+ dict->SetKey("color", SkColor4fToDict(draw_quad->color));
dict->SetBoolKey("force_anti_aliasing_off",
draw_quad->force_anti_aliasing_off);
}
@@ -1178,8 +1224,8 @@ void SurfaceDrawQuadToDict(const SurfaceDrawQuad* draw_quad,
DCHECK(draw_quad);
DCHECK(dict);
dict->SetKey("surface_range", SurfaceRangeToDict(draw_quad->surface_range));
- dict->SetIntKey("default_background_color",
- bit_cast<int>(draw_quad->default_background_color));
+ dict->SetKey("default_background_color",
+ SkColor4fToDict(draw_quad->default_background_color));
dict->SetBoolKey("stretch_content",
draw_quad->stretch_content_to_fill_bounds);
dict->SetBoolKey("is_reflection", draw_quad->is_reflection);
@@ -1193,8 +1239,8 @@ void TextureDrawQuadToDict(const TextureDrawQuad* draw_quad,
dict->SetBoolKey("premultiplied_alpha", draw_quad->premultiplied_alpha);
dict->SetKey("uv_top_left", PointFToDict(draw_quad->uv_top_left));
dict->SetKey("uv_bottom_right", PointFToDict(draw_quad->uv_bottom_right));
- dict->SetIntKey("background_color",
- static_cast<int>(draw_quad->background_color));
+ dict->SetKey("background_color",
+ SkColor4fToDict(draw_quad->background_color));
dict->SetKey("vertex_opacity", FloatArrayToList(draw_quad->vertex_opacity));
dict->SetBoolKey("y_flipped", draw_quad->y_flipped);
dict->SetBoolKey("nearest_neighbor", draw_quad->nearest_neighbor);
@@ -1355,13 +1401,17 @@ bool SolidColorDrawQuadFromDict(const base::Value& dict,
DCHECK(draw_quad);
if (!dict.is_dict())
return false;
- absl::optional<int> color = dict.FindIntKey("color");
absl::optional<bool> force_anti_aliasing_off =
dict.FindBoolKey("force_anti_aliasing_off");
- if (!color || !force_anti_aliasing_off)
+ if (!force_anti_aliasing_off)
return false;
+
+ SkColor t_color;
+ if (!ColorFromDict(dict, "color", t_color))
+ return false;
+
draw_quad->SetAll(common.shared_quad_state, common.rect, common.visible_rect,
- common.needs_blending, static_cast<SkColor>(color.value()),
+ common.needs_blending, t_color,
force_anti_aliasing_off.value());
return true;
}
@@ -1413,19 +1463,21 @@ bool SurfaceDrawQuadFromDict(const base::Value& dict,
return false;
absl::optional<SurfaceRange> surface_range =
SurfaceRangeFromDict(*surface_range_dict);
- absl::optional<int> default_background_color =
- dict.FindIntKey("default_background_color");
absl::optional<bool> stretch_content = dict.FindBoolKey("stretch_content");
absl::optional<bool> is_reflection = dict.FindBoolKey("is_reflection");
absl::optional<bool> allow_merge = dict.FindBoolKey("allow_merge");
- if (!surface_range || !default_background_color || !stretch_content ||
- !is_reflection || !allow_merge)
+ if (!surface_range || !stretch_content || !is_reflection || !allow_merge)
+ return false;
+
+ SkColor t_default_background_color;
+ if (!ColorFromDict(dict, "default_background_color",
+ t_default_background_color))
return false;
draw_quad->SetAll(common.shared_quad_state, common.rect, common.visible_rect,
common.needs_blending, *surface_range,
- bit_cast<SkColor>(*default_background_color),
- *stretch_content, *is_reflection, *allow_merge);
+ t_default_background_color, *stretch_content,
+ *is_reflection, *allow_merge);
return true;
}
@@ -1442,7 +1494,6 @@ bool TextureDrawQuadFromDict(const base::Value& dict,
dict.FindBoolKey("premultiplied_alpha");
const base::Value* uv_top_left = dict.FindDictKey("uv_top_left");
const base::Value* uv_bottom_right = dict.FindDictKey("uv_bottom_right");
- absl::optional<int> background_color = dict.FindIntKey("background_color");
const base::Value* vertex_opacity = dict.FindListKey("vertex_opacity");
const base::Value* damage_rect = dict.FindDictKey("damage_rect");
absl::optional<bool> y_flipped = dict.FindBoolKey("y_flipped");
@@ -1455,7 +1506,7 @@ bool TextureDrawQuadFromDict(const base::Value& dict,
dict.FindDictKey("resource_size_in_pixels");
if (!premultiplied_alpha || !uv_top_left || !uv_bottom_right ||
- !background_color || !vertex_opacity || !y_flipped || !nearest_neighbor ||
+ !vertex_opacity || !y_flipped || !nearest_neighbor ||
!secure_output_only || !protected_video_type ||
!resource_size_in_pixels) {
return false;
@@ -1466,9 +1517,11 @@ bool TextureDrawQuadFromDict(const base::Value& dict,
return false;
gfx::PointF t_uv_top_left, t_uv_bottom_right;
gfx::Size t_resource_size_in_pixels;
+ SkColor t_background_color;
if (!PointFFromDict(*uv_top_left, &t_uv_top_left) ||
!PointFFromDict(*uv_bottom_right, &t_uv_bottom_right) ||
- !SizeFromDict(*resource_size_in_pixels, &t_resource_size_in_pixels)) {
+ !SizeFromDict(*resource_size_in_pixels, &t_resource_size_in_pixels) ||
+ !ColorFromDict(dict, "background_color", t_background_color)) {
return false;
}
float t_vertex_opacity[4];
@@ -1480,8 +1533,8 @@ bool TextureDrawQuadFromDict(const base::Value& dict,
common.shared_quad_state, common.rect, common.visible_rect,
common.needs_blending, resource_id, t_resource_size_in_pixels,
premultiplied_alpha.value(), t_uv_top_left, t_uv_bottom_right,
- static_cast<SkColor>(background_color.value()), t_vertex_opacity,
- y_flipped.value(), nearest_neighbor.value(), secure_output_only.value(),
+ t_background_color, t_vertex_opacity, y_flipped.value(),
+ nearest_neighbor.value(), secure_output_only.value(),
static_cast<gfx::ProtectedVideoType>(protected_video_type_index));
gfx::Rect t_damage_rect;
diff --git a/chromium/components/viz/common/quads/shared_quad_state.cc b/chromium/components/viz/common/quads/shared_quad_state.cc
index a96dcaff5cc..b2d89498de6 100644
--- a/chromium/components/viz/common/quads/shared_quad_state.cc
+++ b/chromium/components/viz/common/quads/shared_quad_state.cc
@@ -48,9 +48,15 @@ void SharedQuadState::AsValueInto(base::trace_event::TracedValue* value) const {
visible_quad_layer_rect, value);
cc::MathUtil::AddToTracedValue("mask_filter_bounds",
mask_filter_info.bounds(), value);
- cc::MathUtil::AddCornerRadiiToTracedValue(
- "mask_filter_rounded_corners_radii",
- mask_filter_info.rounded_corner_bounds(), value);
+ if (mask_filter_info.HasRoundedCorners()) {
+ cc::MathUtil::AddCornerRadiiToTracedValue(
+ "mask_filter_rounded_corners_radii",
+ mask_filter_info.rounded_corner_bounds(), value);
+ }
+ if (mask_filter_info.HasGradientMask()) {
+ cc::MathUtil::AddToTracedValue("mask_filter_gradient_mask",
+ mask_filter_info.gradient_mask(), value);
+ }
if (clip_rect) {
cc::MathUtil::AddToTracedValue("clip_rect", *clip_rect, value);
diff --git a/chromium/components/viz/common/quads/solid_color_draw_quad.cc b/chromium/components/viz/common/quads/solid_color_draw_quad.cc
index b69a713edf8..c7029b7ec9d 100644
--- a/chromium/components/viz/common/quads/solid_color_draw_quad.cc
+++ b/chromium/components/viz/common/quads/solid_color_draw_quad.cc
@@ -11,7 +11,7 @@
namespace viz {
SolidColorDrawQuad::SolidColorDrawQuad()
- : color(0), force_anti_aliasing_off(false) {}
+ : color(SkColors::kTransparent), force_anti_aliasing_off(false) {}
void SolidColorDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
@@ -21,7 +21,7 @@ void SolidColorDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
bool needs_blending = SkColorGetA(c) != 255;
DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSolidColor, rect,
visible_rect, needs_blending);
- color = c;
+ color = SkColor4f::FromColor(c);
force_anti_aliasing_off = anti_aliasing_off;
}
@@ -33,7 +33,7 @@ void SolidColorDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
bool anti_aliasing_off) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSolidColor, rect,
visible_rect, needs_blending);
- color = c;
+ color = SkColor4f::FromColor(c);
force_anti_aliasing_off = anti_aliasing_off;
}
@@ -45,7 +45,7 @@ const SolidColorDrawQuad* SolidColorDrawQuad::MaterialCast(
void SolidColorDrawQuad::ExtendValue(
base::trace_event::TracedValue* value) const {
- value->SetString("color", color_utils::SkColorToRgbaString(color));
+ value->SetString("color", color_utils::SkColor4fToRgbaString(color));
value->SetBoolean("force_anti_aliasing_off", force_anti_aliasing_off);
}
diff --git a/chromium/components/viz/common/quads/solid_color_draw_quad.h b/chromium/components/viz/common/quads/solid_color_draw_quad.h
index 129a06562fd..0d5b3ceedf1 100644
--- a/chromium/components/viz/common/quads/solid_color_draw_quad.h
+++ b/chromium/components/viz/common/quads/solid_color_draw_quad.h
@@ -28,8 +28,8 @@ class VIZ_COMMON_EXPORT SolidColorDrawQuad : public DrawQuad {
SkColor c,
bool anti_aliasing_off);
- SkColor color;
- bool force_anti_aliasing_off;
+ SkColor4f color;
+ bool force_anti_aliasing_off = false;
static const SolidColorDrawQuad* MaterialCast(const DrawQuad*);
diff --git a/chromium/components/viz/common/quads/surface_draw_quad.cc b/chromium/components/viz/common/quads/surface_draw_quad.cc
index 3eaf425e7bf..beb51546b9c 100644
--- a/chromium/components/viz/common/quads/surface_draw_quad.cc
+++ b/chromium/components/viz/common/quads/surface_draw_quad.cc
@@ -30,7 +30,8 @@ void SurfaceDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSurfaceContent, rect,
visible_rect, needs_blending);
surface_range = range;
- default_background_color = background_color;
+ // TODO(crbug/1308932) remove FromColor and make all SkColor4f
+ default_background_color = SkColor4f::FromColor(background_color);
stretch_content_to_fill_bounds = stretch_content;
}
@@ -46,7 +47,8 @@ void SurfaceDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kSurfaceContent, rect,
visible_rect, needs_blending);
surface_range = range;
- default_background_color = background_color;
+ // TODO(crbug/1308932) remove FromColor and make all SkColor4f
+ default_background_color = SkColor4f::FromColor(background_color);
stretch_content_to_fill_bounds = stretch_content;
is_reflection = reflection;
allow_merge = merge;
diff --git a/chromium/components/viz/common/quads/surface_draw_quad.h b/chromium/components/viz/common/quads/surface_draw_quad.h
index 3516469da17..740aa89fd73 100644
--- a/chromium/components/viz/common/quads/surface_draw_quad.h
+++ b/chromium/components/viz/common/quads/surface_draw_quad.h
@@ -38,7 +38,7 @@ class VIZ_COMMON_EXPORT SurfaceDrawQuad : public DrawQuad {
bool merge);
SurfaceRange surface_range;
- SkColor default_background_color = SK_ColorWHITE;
+ SkColor4f default_background_color = SkColors::kWhite;
bool stretch_content_to_fill_bounds = false;
bool is_reflection = false;
// If true, allows this surface to be merged into the embedding surface,
diff --git a/chromium/components/viz/common/quads/texture_draw_quad.cc b/chromium/components/viz/common/quads/texture_draw_quad.cc
index 617acd367a4..3686ed4607c 100644
--- a/chromium/components/viz/common/quads/texture_draw_quad.cc
+++ b/chromium/components/viz/common/quads/texture_draw_quad.cc
@@ -53,7 +53,7 @@ void TextureDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
premultiplied_alpha = premultiplied;
uv_top_left = top_left;
uv_bottom_right = bottom_right;
- background_color = background;
+ background_color = SkColor4f::FromColor(background);
vertex_opacity[0] = opacity[0];
vertex_opacity[1] = opacity[1];
vertex_opacity[2] = opacity[2];
@@ -87,7 +87,7 @@ void TextureDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
premultiplied_alpha = premultiplied;
uv_top_left = top_left;
uv_bottom_right = bottom_right;
- background_color = background;
+ background_color = SkColor4f::FromColor(background);
vertex_opacity[0] = opacity[0];
vertex_opacity[1] = opacity[1];
vertex_opacity[2] = opacity[2];
@@ -112,7 +112,7 @@ void TextureDrawQuad::ExtendValue(base::trace_event::TracedValue* value) const {
cc::MathUtil::AddToTracedValue("uv_bottom_right", uv_bottom_right, value);
value->SetString("background_color",
- color_utils::SkColorToRgbaString(background_color));
+ color_utils::SkColor4fToRgbaString(background_color));
value->BeginArray("vertex_opacity");
for (size_t i = 0; i < 4; ++i)
diff --git a/chromium/components/viz/common/quads/texture_draw_quad.h b/chromium/components/viz/common/quads/texture_draw_quad.h
index 3f8ecefa1a4..6a9d0982c0c 100644
--- a/chromium/components/viz/common/quads/texture_draw_quad.h
+++ b/chromium/components/viz/common/quads/texture_draw_quad.h
@@ -61,7 +61,7 @@ class VIZ_COMMON_EXPORT TextureDrawQuad : public DrawQuad {
gfx::PointF uv_top_left;
gfx::PointF uv_bottom_right;
- SkColor background_color = SK_ColorTRANSPARENT;
+ SkColor4f background_color = SkColors::kTransparent;
float vertex_opacity[4] = {0, 0, 0, 0};
bool y_flipped : 1;
bool nearest_neighbor : 1;
diff --git a/chromium/components/viz/common/resources/resource_format_utils.cc b/chromium/components/viz/common/resources/resource_format_utils.cc
index 52dc3be16a3..7e93dcb77e4 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.cc
+++ b/chromium/components/viz/common/resources/resource_format_utils.cc
@@ -266,44 +266,6 @@ unsigned int GLInternalFormat(ResourceFormat format) {
}
}
-unsigned int GLCopyTextureInternalFormat(ResourceFormat format) {
- // In GLES2, valid formats for glCopyTexImage2D are: GL_ALPHA, GL_LUMINANCE,
- // GL_LUMINANCE_ALPHA, GL_RGB, or GL_RGBA.
- // Extensions typically used for glTexImage2D do not also work for
- // glCopyTexImage2D. For instance GL_BGRA_EXT may not be used for
- // anything but gl(Sub)TexImage2D:
- // https://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_format_BGRA8888.txt
- DCHECK_LE(format, RESOURCE_FORMAT_MAX);
- static const GLenum format_gl_data_format[] = {
- GL_RGBA, // RGBA_8888
- GL_RGBA, // RGBA_4444
- GL_RGBA, // BGRA_8888
- GL_ALPHA, // ALPHA_8
- GL_LUMINANCE, // LUMINANCE_8
- GL_RGB, // RGB_565
- GL_RGB, // BGR_565
- GL_RGB, // ETC1
- GL_LUMINANCE, // RED_8
- GL_RGBA, // RG_88
- GL_LUMINANCE, // LUMINANCE_F16
- GL_RGBA, // RGBA_F16
- GL_LUMINANCE, // R16_EXT
- GL_RGBA, // RG16_EXT
- GL_RGB, // RGBX_8888
- GL_RGB, // BGRX_8888
- GL_ZERO, // RGBA_1010102
- GL_ZERO, // BGRA_1010102
- GL_ZERO, // YVU_420
- GL_ZERO, // YUV_420_BIPLANAR
- GL_ZERO, // P010
- };
-
- static_assert(std::size(format_gl_data_format) == (RESOURCE_FORMAT_MAX + 1),
- "format_gl_data_format does not handle all cases.");
-
- return format_gl_data_format[format];
-}
-
gfx::BufferFormat BufferFormat(ResourceFormat format) {
switch (format) {
case BGRA_8888:
diff --git a/chromium/components/viz/common/resources/resource_format_utils.h b/chromium/components/viz/common/resources/resource_format_utils.h
index fe2ee221a20..ae1328b9e6b 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.h
+++ b/chromium/components/viz/common/resources/resource_format_utils.h
@@ -36,8 +36,6 @@ SkColorTypeToResourceFormat(SkColorType color_type);
VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLDataType(ResourceFormat format);
VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLDataFormat(ResourceFormat format);
VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLInternalFormat(ResourceFormat format);
-VIZ_RESOURCE_FORMAT_EXPORT unsigned int GLCopyTextureInternalFormat(
- ResourceFormat format);
// Returns the pixel format of the resource when mapped into client-side memory.
// Returns a default value when IsGpuMemoryBufferFormatSupported() returns false
diff --git a/chromium/components/viz/common/resources/transferable_resource.h b/chromium/components/viz/common/resources/transferable_resource.h
index 0a360bc3ade..4f07426d0db 100644
--- a/chromium/components/viz/common/resources/transferable_resource.h
+++ b/chromium/components/viz/common/resources/transferable_resource.h
@@ -27,6 +27,22 @@ namespace viz {
struct ReturnedResource;
struct VIZ_COMMON_EXPORT TransferableResource {
+ enum class SynchronizationType : uint8_t {
+ // Commands issued (SyncToken) - a resource can be reused as soon as display
+ // compositor issues the latest command on it and SyncToken will be signaled
+ // when this happens.
+ kSyncToken = 0,
+ // Commands completed (aka read lock fence) - If a gpu resource is backed by
+ // a GpuMemoryBuffer, then it will be accessed out-of-band, and a gpu fence
+ // needs to be waited on before the resource is returned and reused. In
+ // other words, the resource will be returned only when gpu commands are
+ // completed.
+ kGpuCommandsCompleted,
+ // Commands submitted (release fence) - a resource will be returned after
+ // gpu service submitted commands to the gpu and provide the fence.
+ kReleaseFence,
+ };
+
TransferableResource();
~TransferableResource();
@@ -104,10 +120,10 @@ struct VIZ_COMMON_EXPORT TransferableResource {
// drawing it. Typically GL_LINEAR, or GL_NEAREST if no anti-aliasing
// during scaling is desired.
uint32_t filter = 0;
- // If a gpu resource is backed by a GpuMemoryBuffer, then it will be accessed
- // out-of-band, and a gpu fence needs to be waited on before the resource is
- // returned and reused.
- bool read_lock_fences_enabled = false;
+
+ // This defines when the display compositor returns resources. Clients may use
+ // different synchronization types based on their needs.
+ SynchronizationType synchronization_type = SynchronizationType::kSyncToken;
// YCbCr info for resources backed by YCbCr Vulkan images.
absl::optional<gpu::VulkanYCbCrInfo> ycbcr_info;
@@ -145,7 +161,7 @@ struct VIZ_COMMON_EXPORT TransferableResource {
#elif BUILDFLAG(IS_WIN)
wants_promotion_hint == o.wants_promotion_hint &&
#endif
- read_lock_fences_enabled == o.read_lock_fences_enabled;
+ synchronization_type == o.synchronization_type;
}
bool operator!=(const TransferableResource& o) const { return !(*this == o); }
};
diff --git a/chromium/components/viz/common/surfaces/local_surface_id_unittest.cc b/chromium/components/viz/common/surfaces/local_surface_id_unittest.cc
index 4a07df62e94..943d4693a86 100644
--- a/chromium/components/viz/common/surfaces/local_surface_id_unittest.cc
+++ b/chromium/components/viz/common/surfaces/local_surface_id_unittest.cc
@@ -38,6 +38,7 @@ TEST(LocalSurfaceIdTest, VerifyToString) {
int previous_log_lvl = logging::GetMinLogLevel();
+#if BUILDFLAG(USE_RUNTIME_VLOG)
// When |g_min_log_level| is set to LOG_VERBOSE we expect verbose versions
// of local_surface_id::ToString().
logging::SetMinLogLevel(logging::LOG_VERBOSE);
@@ -45,6 +46,7 @@ TEST(LocalSurfaceIdTest, VerifyToString) {
EXPECT_EQ(verbose_expected, local_surface_id.ToString());
EXPECT_EQ(big_verbose_expected, big_local_surface_id.ToString());
EXPECT_EQ(small_verbose_expected, small_local_surface_id.ToString());
+#endif // BUILDFLAG(USE_RUNTIME_VLOG)
// When |g_min_log_level| is set to LOG_INFO we expect less verbose versions
// of local_surface_id::ToString().
diff --git a/chromium/components/viz/common/switches.cc b/chromium/components/viz/common/switches.cc
index e6d3acbf514..c5cf3aab5df 100644
--- a/chromium/components/viz/common/switches.cc
+++ b/chromium/components/viz/common/switches.cc
@@ -29,10 +29,6 @@ const char kDeadlineToSynchronizeSurfaces[] =
// Also implies --disable-gpu-vsync (see //ui/gl/gl_switches.h).
const char kDisableFrameRateLimit[] = "disable-frame-rate-limit";
-// Slows down animations during a DocumentTransition for debugging.
-const char kDocumentTransitionSlowdownFactor[] =
- "document-transition-slowdown-factor";
-
// Sets the number of max pending frames in the GL buffer queue to 1.
const char kDoubleBufferCompositing[] = "double-buffer-compositing";
@@ -87,18 +83,4 @@ absl::optional<uint32_t> GetDeadlineToSynchronizeSurfaces() {
return activation_deadline_in_frames;
}
-int GetDocumentTransitionSlowDownFactor() {
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (!command_line ||
- !command_line->HasSwitch(kDocumentTransitionSlowdownFactor))
- return 1;
-
- auto factor_str =
- command_line->GetSwitchValueASCII(kDocumentTransitionSlowdownFactor);
- int factor = 0;
- LOG_IF(ERROR, !base::StringToInt(factor_str, &factor))
- << "Error parsing document transition slow down factor " << factor_str;
- return std::max(1, factor);
-}
-
} // namespace switches
diff --git a/chromium/components/viz/common/switches.h b/chromium/components/viz/common/switches.h
index b76565e96c5..a602615d40b 100644
--- a/chromium/components/viz/common/switches.h
+++ b/chromium/components/viz/common/switches.h
@@ -17,7 +17,6 @@ namespace switches {
VIZ_COMMON_EXPORT extern const char kDeJellyScreenWidth[];
VIZ_COMMON_EXPORT extern const char kDeadlineToSynchronizeSurfaces[];
VIZ_COMMON_EXPORT extern const char kDisableFrameRateLimit[];
-VIZ_COMMON_EXPORT extern const char kDocumentTransitionSlowdownFactor[];
VIZ_COMMON_EXPORT extern const char kDoubleBufferCompositing[];
VIZ_COMMON_EXPORT extern const char kEnableDeJelly[];
VIZ_COMMON_EXPORT extern const char kEnableHardwareOverlays[];
@@ -33,7 +32,6 @@ VIZ_COMMON_EXPORT extern const char kTintCompositedContentModulate[];
VIZ_COMMON_EXPORT extern const char kShowDCLayerDebugBorders[];
VIZ_COMMON_EXPORT absl::optional<uint32_t> GetDeadlineToSynchronizeSurfaces();
-VIZ_COMMON_EXPORT int GetDocumentTransitionSlowDownFactor();
} // namespace switches
diff --git a/chromium/components/viz/common/transition_utils.cc b/chromium/components/viz/common/transition_utils.cc
index a59ef9e5eb3..30f611dd4e5 100644
--- a/chromium/components/viz/common/transition_utils.cc
+++ b/chromium/components/viz/common/transition_utils.cc
@@ -20,6 +20,10 @@
namespace viz {
namespace {
+
+constexpr int kMaxListToProcess = 32;
+constexpr int kMaxQuadsPerFrame = 8;
+
struct StackFrame {
StackFrame(int list_index,
SharedQuadStateList::ConstIterator sqs_iter,
@@ -44,6 +48,10 @@ std::string SkColorToRGBAString(SkColor color) {
return str.str();
}
+std::string SkColorToRGBAString(SkColor4f color) {
+ return SkColorToRGBAString(color.toSkColor());
+}
+
std::unordered_set<uint64_t> ProcessStack(
std::ostringstream& str,
std::vector<StackFrame>& stack,
@@ -78,6 +86,7 @@ std::unordered_set<uint64_t> ProcessStack(
str << "(" << quad << ") CompositorRenderPassDrawQuad\n";
};
std::unordered_set<uint64_t> seen_render_pass_ids;
+ int quads_per_frame_logged = 0;
while (!stack.empty()) {
auto& frame = stack.back();
auto& pass = list[frame.list_index];
@@ -100,6 +109,14 @@ std::unordered_set<uint64_t> ProcessStack(
frame.indent += 2;
} else {
if (++frame.quad_iter == pass->quad_list.end()) {
+ quads_per_frame_logged = 0;
+ stack.pop_back();
+ continue;
+ }
+ if (++quads_per_frame_logged > kMaxQuadsPerFrame) {
+ write_indent(frame.indent);
+ str << "(more quads - orphaned list may not be correct)\n";
+ quads_per_frame_logged = 0;
stack.pop_back();
continue;
}
@@ -157,6 +174,12 @@ std::string TransitionUtils::RenderPassListToString(
const CompositorRenderPassList& list) {
std::ostringstream str;
+ if (list.size() > kMaxListToProcess) {
+ str << "RenderPassList too large (" << list.size()
+ << "), max supported list length " << kMaxListToProcess;
+ return str.str();
+ }
+
std::vector<StackFrame> stack;
stack.emplace_back(list.size() - 1,
list.back()->shared_quad_state_list.begin(),
diff --git a/chromium/components/viz/common/yuv_readback_unittest.cc b/chromium/components/viz/common/yuv_readback_unittest.cc
index 6a0851cf10a..cc228ed0bca 100644
--- a/chromium/components/viz/common/yuv_readback_unittest.cc
+++ b/chromium/components/viz/common/yuv_readback_unittest.cc
@@ -49,17 +49,9 @@ class YUVReadbackTest : public testing::Test {
context_ = std::make_unique<gpu::GLInProcessContext>();
auto result = context_->Initialize(
- TestGpuServiceHolder::GetInstance()->task_executor(),
- nullptr, /* surface */
- true, /* offscreen */
- gpu::kNullSurfaceHandle, /* window */
- attributes, gpu::SharedMemoryLimits(),
- nullptr, /* gpu_memory_buffer_manager */
- nullptr, /* image_factory */
- nullptr, /* gpu::GpuTaskSchedulerHelper */
- nullptr,
- /* gpu::DisplayCompositorMemoryAndTaskControllerOnGpu */
- base::ThreadTaskRunnerHandle::Get());
+ TestGpuServiceHolder::GetInstance()->task_executor(), attributes,
+ gpu::SharedMemoryLimits(),
+ /*image_factory=*/nullptr);
DCHECK_EQ(result, gpu::ContextResult::kSuccess);
gl_ = context_->GetImplementation();
gpu::ContextSupport* support = context_->GetImplementation();
diff --git a/chromium/components/viz/demo/demo_main.cc b/chromium/components/viz/demo/demo_main.cc
index db021f9870f..8cce35cdfe4 100644
--- a/chromium/components/viz/demo/demo_main.cc
+++ b/chromium/components/viz/demo/demo_main.cc
@@ -148,7 +148,7 @@ class DemoWindow : public ui::PlatformWindowDelegate {
// Next, create the host and the service, and pass them the right ends of
// the message-pipes.
host_ = std::make_unique<demo::DemoHost>(
- widget_, platform_window_->GetBounds().size(),
+ widget_, platform_window_->GetBoundsInPixels().size(),
std::move(frame_sink_manager_client_receiver),
std::move(frame_sink_manager));
diff --git a/chromium/components/viz/demo/service/demo_service.cc b/chromium/components/viz/demo/service/demo_service.cc
index 2d2d153c1ad..ba174324880 100644
--- a/chromium/components/viz/demo/service/demo_service.cc
+++ b/chromium/components/viz/demo/service/demo_service.cc
@@ -22,7 +22,7 @@ DemoService::DemoService(
params->frame_sink_manager = std::move(receiver);
params->frame_sink_manager_client = std::move(client);
runner_ = std::make_unique<viz::VizCompositorThreadRunnerImpl>();
- runner_->CreateFrameSinkManager(std::move(params));
+ runner_->CreateFrameSinkManager(std::move(params), /*gpu_service=*/nullptr);
}
DemoService::~DemoService() = default;
diff --git a/chromium/components/viz/host/client_frame_sink_video_capturer.h b/chromium/components/viz/host/client_frame_sink_video_capturer.h
index 6775aea4a58..ce514b0a8b7 100644
--- a/chromium/components/viz/host/client_frame_sink_video_capturer.h
+++ b/chromium/components/viz/host/client_frame_sink_video_capturer.h
@@ -107,6 +107,10 @@ class VIZ_HOST_EXPORT ClientFrameSinkVideoCapturer
// owned pointer to an Overlay.
std::unique_ptr<Overlay> CreateOverlay(int32_t stacking_index);
+ // Getter for `format_`. Returns the pixel format set by the last call to
+ // `SetFormat()`, or nullopt if the format was not yet set.
+ absl::optional<media::VideoPixelFormat> GetFormat() const { return format_; }
+
private:
struct ResolutionConstraints {
ResolutionConstraints(const gfx::Size& min_size,
diff --git a/chromium/components/viz/host/gpu_host_impl.cc b/chromium/components/viz/host/gpu_host_impl.cc
index bb0369de155..60e908d2d31 100644
--- a/chromium/components/viz/host/gpu_host_impl.cc
+++ b/chromium/components/viz/host/gpu_host_impl.cc
@@ -136,7 +136,7 @@ GpuHostImpl::GpuHostImpl(Delegate* delegate,
viz_main_->CreateGpuService(
gpu_service_remote_.BindNewPipeAndPassReceiver(task_runner),
gpu_host_receiver_.BindNewPipeAndPassRemote(task_runner),
- std::move(discardable_manager_remote), activity_flags_.CloneHandle(),
+ std::move(discardable_manager_remote), activity_flags_.CloneRegion(),
GetFontRenderParams().Get()->subpixel_rendering);
#if defined(USE_OZONE)
@@ -194,9 +194,8 @@ void GpuHostImpl::AddConnectionErrorHandler(base::OnceClosure handler) {
void GpuHostImpl::BlockLiveOffscreenContexts() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- for (auto iter = urls_with_live_offscreen_contexts_.begin();
- iter != urls_with_live_offscreen_contexts_.end(); ++iter) {
- delegate_->BlockDomainFrom3DAPIs(*iter, gpu::DomainGuilt::kUnknown);
+ for (auto& url : urls_with_live_offscreen_contexts_) {
+ delegate_->BlockDomainFrom3DAPIs(url, gpu::DomainGuilt::kUnknown);
}
}
@@ -565,8 +564,8 @@ void GpuHostImpl::DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) {
delegate_->DidUpdateOverlayInfo(overlay_info);
}
-void GpuHostImpl::DidUpdateHDRStatus(bool hdr_enabled) {
- delegate_->DidUpdateHDRStatus(hdr_enabled);
+void GpuHostImpl::DidUpdateDXGIInfo(gfx::mojom::DXGIInfoPtr dxgi_info) {
+ delegate_->DidUpdateDXGIInfo(std::move(dxgi_info));
}
void GpuHostImpl::SetChildSurface(gpu::SurfaceHandle parent,
diff --git a/chromium/components/viz/host/gpu_host_impl.h b/chromium/components/viz/host/gpu_host_impl.h
index 1253e39ab93..1d77a895981 100644
--- a/chromium/components/viz/host/gpu_host_impl.h
+++ b/chromium/components/viz/host/gpu_host_impl.h
@@ -42,6 +42,7 @@
#if BUILDFLAG(IS_WIN)
#include "services/viz/privileged/mojom/gl/info_collection_gpu_service.mojom.h"
+#include "ui/gfx/mojom/dxgi_info.mojom.h"
#endif
namespace gfx {
@@ -79,7 +80,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost
virtual void DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) = 0;
#if BUILDFLAG(IS_WIN)
virtual void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) = 0;
- virtual void DidUpdateHDRStatus(bool hdr_enabled) = 0;
+ virtual void DidUpdateDXGIInfo(gfx::mojom::DXGIInfoPtr dxgi_info) = 0;
#endif
virtual void BlockDomainFrom3DAPIs(const GURL& url,
gpu::DomainGuilt guilt) = 0;
@@ -250,7 +251,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost
void DidUpdateGPUInfo(const gpu::GPUInfo& gpu_info) override;
#if BUILDFLAG(IS_WIN)
void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
- void DidUpdateHDRStatus(bool hdr_enabled) override;
+ void DidUpdateDXGIInfo(gfx::mojom::DXGIInfoPtr dxgi_info) override;
void SetChildSurface(gpu::SurfaceHandle parent,
gpu::SurfaceHandle child) override;
#endif
diff --git a/chromium/components/viz/host/hit_test/hit_test_query.cc b/chromium/components/viz/host/hit_test/hit_test_query.cc
index e703c39804c..e01a3e63109 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query.cc
+++ b/chromium/components/viz/host/hit_test/hit_test_query.cc
@@ -9,7 +9,6 @@
#include <utility>
#include "base/containers/stack.h"
-#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "components/viz/common/features.h"
#include "components/viz/common/hit_test/hit_test_region_list.h"
@@ -194,9 +193,6 @@ bool HitTestQuery::FindTargetInRegionForLocation(
target->frame_sink_id = hit_test_data_[region_index].frame_sink_id;
target->location_in_target = gfx::PointF();
target->flags = HitTestRegionFlags::kHitTestAsk;
- RecordSlowPathHitTestReasons(
- AsyncHitTestReasons::kPerspectiveTransform |
- hit_test_data_[region_index].async_hit_test_reasons);
return true;
}
@@ -243,8 +239,6 @@ bool HitTestQuery::FindTargetInRegionForLocation(
target->frame_sink_id = hit_test_data_[region_index].frame_sink_id;
target->location_in_target = location_in_target;
target->flags = flags;
- RecordSlowPathHitTestReasons(
- hit_test_data_[region_index].async_hit_test_reasons);
return true;
}
@@ -273,18 +267,14 @@ bool HitTestQuery::FindTargetInRegionForLocation(
!(flags & HitTestRegionFlags::kHitTestIgnore)) {
target->frame_sink_id = hit_test_data_[region_index].frame_sink_id;
target->location_in_target = location_in_target;
- uint32_t async_hit_test_reasons =
- hit_test_data_[region_index].async_hit_test_reasons;
uint32_t target_flags = flags;
if (root_view_overlapped) {
DCHECK_EQ(hit_test_data_[region_index].async_hit_test_reasons,
AsyncHitTestReasons::kOverlappedRegion);
target_flags &= ~HitTestRegionFlags::kHitTestAsk;
- async_hit_test_reasons = AsyncHitTestReasons::kNotAsyncHitTest;
}
target->flags = target_flags;
// We record fast path hit testing instances with reason kNotAsyncHitTest.
- RecordSlowPathHitTestReasons(async_hit_test_reasons);
return true;
}
return false;
@@ -365,27 +355,6 @@ bool HitTestQuery::GetTransformToTargetRecursively(
return false;
}
-void HitTestQuery::RecordSlowPathHitTestReasons(uint32_t reasons) const {
- static const char* kAsyncHitTestReasonsHistogramName =
- "Event.VizHitTest.AsyncHitTestReasons";
- if (reasons == AsyncHitTestReasons::kNotAsyncHitTest) {
- UMA_HISTOGRAM_ENUMERATION(
- kAsyncHitTestReasonsHistogramName,
- AsyncHitTestReasons::kNotAsyncHitTest,
- AsyncHitTestReasons::kAsyncHitTestReasonCount + 1);
- return;
- }
-
- for (uint32_t i = 0; i < AsyncHitTestReasons::kAsyncHitTestReasonCount; ++i) {
- unsigned val = 1 << i;
- if (reasons & val) {
- UMA_HISTOGRAM_ENUMERATION(
- kAsyncHitTestReasonsHistogramName, i + 1,
- AsyncHitTestReasons::kAsyncHitTestReasonCount + 1);
- }
- }
-}
-
std::string HitTestQuery::PrintHitTestData() const {
std::ostringstream oss;
base::stack<uint32_t> parents;
diff --git a/chromium/components/viz/host/hit_test/hit_test_query.h b/chromium/components/viz/host/hit_test/hit_test_query.h
index c6c6f12ebaa..8451940c3e6 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query.h
+++ b/chromium/components/viz/host/hit_test/hit_test_query.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
#define COMPONENTS_VIZ_HOST_HIT_TEST_HIT_TEST_QUERY_H_
+#include <string>
#include <vector>
#include "base/callback.h"
@@ -153,8 +154,6 @@ class VIZ_HOST_EXPORT HitTestQuery {
size_t region_index,
gfx::Transform* transform) const;
- void RecordSlowPathHitTestReasons(uint32_t) const;
-
std::vector<AggregatedHitTestRegion> hit_test_data_;
};
diff --git a/chromium/components/viz/host/host_frame_sink_manager.cc b/chromium/components/viz/host/host_frame_sink_manager.cc
index 1ad1e78b6a7..90429aee8e6 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.cc
+++ b/chromium/components/viz/host/host_frame_sink_manager.cc
@@ -288,6 +288,15 @@ void HostFrameSinkManager::Throttle(const std::vector<FrameSinkId>& ids,
frame_sink_manager_->Throttle(ids, interval);
}
+void HostFrameSinkManager::StartThrottlingAllFrameSinks(
+ base::TimeDelta interval) {
+ frame_sink_manager_->StartThrottlingAllFrameSinks(interval);
+}
+
+void HostFrameSinkManager::StopThrottlingAllFrameSinks() {
+ frame_sink_manager_->StopThrottlingAllFrameSinks();
+}
+
void HostFrameSinkManager::AddHitTestRegionObserver(
HitTestRegionObserver* observer) {
observers_.AddObserver(observer);
diff --git a/chromium/components/viz/host/host_frame_sink_manager.h b/chromium/components/viz/host/host_frame_sink_manager.h
index 5a0d8946432..44db2fc33d9 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.h
+++ b/chromium/components/viz/host/host_frame_sink_manager.h
@@ -194,6 +194,8 @@ class VIZ_HOST_EXPORT HostFrameSinkManager
std::unique_ptr<CopyOutputRequest> request);
void Throttle(const std::vector<FrameSinkId>& ids, base::TimeDelta interval);
+ void StartThrottlingAllFrameSinks(base::TimeDelta interval);
+ void StopThrottlingAllFrameSinks();
// Add/Remove an observer to receive notifications of when the host receives
// new hit test data.
diff --git a/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc b/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
index 3da44d37dcd..79c205298b1 100644
--- a/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
+++ b/chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
@@ -186,7 +186,9 @@ class TestGpuService : public mojom::GpuService {
void GetPeakMemoryUsage(uint32_t sequence_num,
GetPeakMemoryUsageCallback callback) override {}
- void RequestHDRStatus(RequestHDRStatusCallback callback) override {}
+#if BUILDFLAG(IS_WIN)
+ void RequestDXGIInfo(RequestDXGIInfoCallback callback) override {}
+#endif
void LoadedShader(int32_t client_id,
const std::string& key,
diff --git a/chromium/components/viz/host/renderer_settings_creation.cc b/chromium/components/viz/host/renderer_settings_creation.cc
index 6a830ec9f29..9d34ced3660 100644
--- a/chromium/components/viz/host/renderer_settings_creation.cc
+++ b/chromium/components/viz/host/renderer_settings_creation.cc
@@ -66,7 +66,6 @@ RendererSettings CreateRendererSettings() {
#endif
renderer_settings.allow_antialiasing =
!command_line->HasSwitch(switches::kDisableCompositedAntialiasing);
- renderer_settings.use_skia_renderer = features::IsUsingSkiaRenderer();
if (command_line->HasSwitch(switches::kSlowDownCompositingScaleFactor)) {
const int kMinSlowDownScaleFactor = 1;
diff --git a/chromium/components/viz/service/BUILD.gn b/chromium/components/viz/service/BUILD.gn
index 002b3ddfb0f..10d10f49e7a 100644
--- a/chromium/components/viz/service/BUILD.gn
+++ b/chromium/components/viz/service/BUILD.gn
@@ -39,12 +39,12 @@ viz_component("service") {
"display/display.cc",
"display/display.h",
"display/display_client.h",
+ "display/display_compositor_memory_and_task_controller.cc",
+ "display/display_compositor_memory_and_task_controller.h",
"display/display_damage_tracker.cc",
"display/display_damage_tracker.h",
"display/display_resource_provider.cc",
"display/display_resource_provider.h",
- "display/display_resource_provider_gl.cc",
- "display/display_resource_provider_gl.h",
"display/display_resource_provider_null.cc",
"display/display_resource_provider_null.h",
"display/display_resource_provider_skia.cc",
@@ -57,22 +57,10 @@ viz_component("service") {
"display/display_scheduler_base.h",
"display/draw_polygon.cc",
"display/draw_polygon.h",
- "display/dynamic_geometry_binding.cc",
- "display/dynamic_geometry_binding.h",
"display/external_use_client.cc",
"display/external_use_client.h",
"display/frame_rate_decider.cc",
"display/frame_rate_decider.h",
- "display/geometry_binding.cc",
- "display/geometry_binding.h",
- "display/gl_renderer.cc",
- "display/gl_renderer.h",
- "display/gl_renderer_copier.cc",
- "display/gl_renderer_copier.h",
- "display/gl_renderer_draw_cache.cc",
- "display/gl_renderer_draw_cache.h",
- "display/layer_quad.cc",
- "display/layer_quad.h",
"display/null_renderer.cc",
"display/null_renderer.h",
"display/output_surface.cc",
@@ -92,19 +80,11 @@ viz_component("service") {
"display/overlay_processor_stub.h",
"display/pending_swap_params.cc",
"display/pending_swap_params.h",
- "display/program_binding.cc",
- "display/program_binding.h",
"display/renderer_utils.cc",
"display/renderer_utils.h",
"display/resolved_frame_data.cc",
"display/resolved_frame_data.h",
"display/resource_fence.h",
- "display/scoped_gpu_memory_buffer_texture.cc",
- "display/scoped_gpu_memory_buffer_texture.h",
- "display/scoped_render_pass_texture.cc",
- "display/scoped_render_pass_texture.h",
- "display/shader.cc",
- "display/shader.h",
"display/shared_bitmap_manager.h",
"display/skia_output_surface.cc",
"display/skia_output_surface.h",
@@ -114,35 +94,46 @@ viz_component("service") {
"display/software_output_device.h",
"display/software_renderer.cc",
"display/software_renderer.h",
- "display/static_geometry_binding.cc",
- "display/static_geometry_binding.h",
"display/surface_aggregator.cc",
"display/surface_aggregator.h",
- "display/sync_query_collection.cc",
- "display/sync_query_collection.h",
- "display/texture_deleter.cc",
- "display/texture_deleter.h",
"display_embedder/buffer_queue.cc",
"display_embedder/buffer_queue.h",
"display_embedder/compositor_gpu_thread.cc",
"display_embedder/compositor_gpu_thread.h",
- "display_embedder/gl_output_surface.cc",
- "display_embedder/gl_output_surface.h",
- "display_embedder/gl_output_surface_buffer_queue.cc",
- "display_embedder/gl_output_surface_buffer_queue.h",
- "display_embedder/gl_output_surface_offscreen.cc",
- "display_embedder/gl_output_surface_offscreen.h",
+ "display_embedder/image_context_impl.cc",
+ "display_embedder/image_context_impl.h",
"display_embedder/in_process_gpu_memory_buffer_manager.cc",
"display_embedder/in_process_gpu_memory_buffer_manager.h",
+ "display_embedder/output_presenter.cc",
+ "display_embedder/output_presenter.h",
+ "display_embedder/output_presenter_gl.cc",
+ "display_embedder/output_presenter_gl.h",
"display_embedder/output_surface_provider.h",
"display_embedder/output_surface_provider_impl.cc",
"display_embedder/output_surface_provider_impl.h",
"display_embedder/server_shared_bitmap_manager.cc",
"display_embedder/server_shared_bitmap_manager.h",
+ "display_embedder/skia_output_device.cc",
+ "display_embedder/skia_output_device.h",
+ "display_embedder/skia_output_device_buffer_queue.cc",
+ "display_embedder/skia_output_device_buffer_queue.h",
+ "display_embedder/skia_output_device_gl.cc",
+ "display_embedder/skia_output_device_gl.h",
+ "display_embedder/skia_output_device_offscreen.cc",
+ "display_embedder/skia_output_device_offscreen.h",
+ "display_embedder/skia_output_device_webview.cc",
+ "display_embedder/skia_output_device_webview.h",
+ "display_embedder/skia_output_surface_dependency.h",
+ "display_embedder/skia_output_surface_dependency_impl.cc",
+ "display_embedder/skia_output_surface_dependency_impl.h",
+ "display_embedder/skia_output_surface_impl.cc",
+ "display_embedder/skia_output_surface_impl.h",
+ "display_embedder/skia_output_surface_impl_on_gpu.cc",
+ "display_embedder/skia_output_surface_impl_on_gpu.h",
+ "display_embedder/skia_render_copy_results.cc",
+ "display_embedder/skia_render_copy_results.h",
"display_embedder/software_output_surface.cc",
"display_embedder/software_output_surface.h",
- "display_embedder/viz_process_context_provider.cc",
- "display_embedder/viz_process_context_provider.h",
"display_embedder/vsync_parameter_listener.cc",
"display_embedder/vsync_parameter_listener.h",
"frame_sinks/begin_frame_tracker.cc",
@@ -184,6 +175,8 @@ viz_component("service") {
"frame_sinks/video_capture/video_frame_pool.h",
"frame_sinks/video_detector.cc",
"frame_sinks/video_detector.h",
+ "gl/gpu_service_impl.cc",
+ "gl/gpu_service_impl.h",
"hit_test/hit_test_aggregator.cc",
"hit_test/hit_test_aggregator.h",
"hit_test/hit_test_aggregator_delegate.h",
@@ -225,8 +218,6 @@ viz_component("service") {
defines = [ "VIZ_SERVICE_IMPLEMENTATION" ]
- allow_circular_includes_from = [ ":gpu_service_dependencies" ]
-
deps = [
"//build:chromecast_buildflags",
"//build:chromeos_buildflags",
@@ -234,13 +225,12 @@ viz_component("service") {
"//cc/paint",
"//components/crash/core/common:crash_key",
"//components/power_scheduler",
- "//gpu/command_buffer/client:gles2_cmd_helper",
- "//gpu/command_buffer/client:gles2_implementation",
- "//gpu/command_buffer/client:raster",
# Note that dependency on //gpu/ipc/client is for GpuMemoryBufferImpl. This
# dependency should not be in public_deps.
"//components/viz/common",
+ "//gpu/command_buffer/client",
+ "//gpu/config",
"//gpu/ipc/client",
"//gpu/ipc/common:common",
"//gpu/ipc/common:surface_handle_type",
@@ -260,14 +250,20 @@ viz_component("service") {
]
public_deps = [
- ":gpu_service_dependencies",
"//base",
"//cc",
"//cc/debug",
"//components/viz/common",
- "//gpu/command_buffer/client:gles2_interface",
+ "//gpu/command_buffer/service:gles2",
+ "//gpu/ipc:gl_in_process_context",
+ "//gpu/ipc/service",
+ "//gpu/vulkan:buildflags",
+ "//media/gpu/ipc/service",
+ "//media/mojo/services",
"//services/viz/privileged/mojom/compositing",
+ "//services/viz/privileged/mojom/gl",
"//services/viz/public/mojom",
+ "//skia",
"//ui/base/prediction",
"//ui/gfx",
"//ui/gfx/geometry",
@@ -276,9 +272,17 @@ viz_component("service") {
if (is_chromeos_ash) {
sources += [
- "display_embedder/gl_output_surface_chromeos.cc",
- "display_embedder/gl_output_surface_chromeos.h",
+ "display_embedder/output_surface_unified.cc",
+ "display_embedder/output_surface_unified.h",
]
+
+ deps += [
+ "//components/chromeos_camera:jpeg_encode_accelerator_service",
+ "//components/chromeos_camera:mjpeg_decode_accelerator_service",
+ "//gpu/command_buffer/service:gles2",
+ "//media/mojo/services",
+ ]
+
if (use_v4l2_codec || use_vaapi) {
deps += [ "//ash/components/arc/video_accelerator" ]
}
@@ -329,8 +333,6 @@ viz_component("service") {
"display/overlay_processor_android.h",
"display/overlay_processor_surface_control.cc",
"display/overlay_processor_surface_control.h",
- "display_embedder/gl_output_surface_android.cc",
- "display_embedder/gl_output_surface_android.h",
"frame_sinks/external_begin_frame_source_android.cc",
"frame_sinks/external_begin_frame_source_android.h",
"gl/throw_uncaught_exception.cc",
@@ -367,85 +369,6 @@ viz_component("service") {
"display_embedder/output_device_backing.h",
"display_embedder/software_output_device_win.cc",
"display_embedder/software_output_device_win.h",
- ]
- }
-
- if (is_chromeos_ash) {
- sources += [
- "display_embedder/output_surface_unified.cc",
- "display_embedder/output_surface_unified.h",
- ]
- }
-
- if (enable_vulkan) {
- deps += [ "//gpu/vulkan" ]
- }
-}
-
-# The gpu_service_dependencies source set contains source files that
-# use the service side GL library (ui/gl), while the rest of
-# viz/service use the client side GL library. This split is needed
-# because the two GL libraries are incompatible and can't compile
-# together in jumbo builds.
-#
-# Long term all service code is moving to be in the gpu process and
-# then this build target will no longer be needed.
-viz_source_set("gpu_service_dependencies") {
- sources = [
- "display/display_compositor_memory_and_task_controller.cc",
- "display/display_compositor_memory_and_task_controller.h",
- "display_embedder/image_context_impl.cc",
- "display_embedder/image_context_impl.h",
- "display_embedder/output_presenter.cc",
- "display_embedder/output_presenter.h",
- "display_embedder/output_presenter_gl.cc",
- "display_embedder/output_presenter_gl.h",
- "display_embedder/skia_output_device.cc",
- "display_embedder/skia_output_device.h",
- "display_embedder/skia_output_device_buffer_queue.cc",
- "display_embedder/skia_output_device_buffer_queue.h",
- "display_embedder/skia_output_device_gl.cc",
- "display_embedder/skia_output_device_gl.h",
- "display_embedder/skia_output_device_offscreen.cc",
- "display_embedder/skia_output_device_offscreen.h",
- "display_embedder/skia_output_device_webview.cc",
- "display_embedder/skia_output_device_webview.h",
- "display_embedder/skia_output_surface_dependency.h",
- "display_embedder/skia_output_surface_dependency_impl.cc",
- "display_embedder/skia_output_surface_dependency_impl.h",
- "display_embedder/skia_output_surface_impl.cc",
- "display_embedder/skia_output_surface_impl.h",
- "display_embedder/skia_output_surface_impl_on_gpu.cc",
- "display_embedder/skia_output_surface_impl_on_gpu.h",
- "display_embedder/skia_render_copy_results.cc",
- "display_embedder/skia_render_copy_results.h",
- "gl/gpu_service_impl.cc",
- "gl/gpu_service_impl.h",
- ]
-
- public_deps = [
- "//gpu/command_buffer/service:gles2",
- "//gpu/ipc:gl_in_process_context",
- "//gpu/ipc/service",
- "//gpu/vulkan:buildflags",
- "//media/gpu/ipc/service",
- "//media/mojo/services",
- "//services/viz/privileged/mojom/gl",
- "//skia",
- "//ui/latency:latency",
- ]
-
- defines = [ "VIZ_SERVICE_IMPLEMENTATION" ]
-
- deps = [
- "//base",
- "//build:chromeos_buildflags",
- "//gpu/config",
- "//third_party/libyuv",
- ]
-
- if (is_win) {
- sources += [
"gl/info_collection_gpu_service_impl.cc",
"gl/info_collection_gpu_service_impl.h",
]
@@ -461,34 +384,25 @@ viz_source_set("gpu_service_dependencies") {
]
}
- if (is_chromeos_ash) {
- deps += [
- "//components/chromeos_camera:jpeg_encode_accelerator_service",
- "//components/chromeos_camera:mjpeg_decode_accelerator_service",
- "//gpu/command_buffer/service:gles2",
- "//media/mojo/services",
+ if (is_fuchsia) {
+ sources += [
+ "display_embedder/output_presenter_fuchsia.cc",
+ "display_embedder/output_presenter_fuchsia.h",
]
- if (use_v4l2_codec || use_vaapi) {
- deps += [ "//ash/components/arc/video_accelerator" ]
- }
}
if (use_vaapi) {
deps += [ "//media/gpu/vaapi" ]
}
- if (use_ozone) {
- deps += [ "//ui/ozone" ]
- }
-
if (enable_vulkan) {
+ deps += [ "//gpu/vulkan" ]
+
sources += [
"display_embedder/skia_output_device_vulkan.cc",
"display_embedder/skia_output_device_vulkan.h",
]
- public_deps += [ "//gpu/vulkan" ]
-
if (is_android) {
sources += [
"display_embedder/skia_output_device_vulkan_secondary_cb.cc",
@@ -528,13 +442,6 @@ viz_source_set("gpu_service_dependencies") {
"//third_party/dawn/src/dawn/native",
]
}
-
- if (is_fuchsia) {
- sources += [
- "display_embedder/output_presenter_fuchsia.cc",
- "display_embedder/output_presenter_fuchsia.h",
- ]
- }
}
viz_source_set("unit_tests") {
@@ -546,26 +453,21 @@ viz_source_set("unit_tests") {
"display/delegated_ink_point_pixel_test_helper.cc",
"display/delegated_ink_point_pixel_test_helper.h",
"display/display_damage_tracker_unittest.cc",
- "display/display_resource_provider_gl_unittest.cc",
"display/display_resource_provider_skia_unittest.cc",
"display/display_resource_provider_software_unittest.cc",
"display/display_scheduler_unittest.cc",
"display/display_unittest.cc",
"display/draw_polygon_unittest.cc",
"display/frame_rate_decider_unittest.cc",
- "display/layer_quad_unittest.cc",
"display/renderer_pixeltest.cc",
"display/resolved_frame_data_unittest.cc",
- "display/shader_unittest.cc",
"display/skia_readback_pixeltest.cc",
"display/software_renderer_unittest.cc",
"display/surface_aggregator_pixeltest.cc",
"display/surface_aggregator_unittest.cc",
- "display/texture_deleter_unittest.cc",
"display/viz_pixel_test.cc",
"display/viz_pixel_test.h",
"display_embedder/buffer_queue_unittest.cc",
- "display_embedder/gl_output_surface_buffer_queue_unittest.cc",
"display_embedder/server_shared_bitmap_manager_unittest.cc",
"display_embedder/skia_output_device_buffer_queue_unittest.cc",
"display_embedder/skia_output_surface_impl_unittest.cc",
@@ -591,14 +493,6 @@ viz_source_set("unit_tests") {
"transitions/transferable_resource_tracker_unittest.cc",
]
- if (enable_gl_renderer_tests) {
- sources += [
- "display/gl_renderer_copier_pixeltest.cc",
- "display/gl_renderer_copier_unittest.cc",
- "display/gl_renderer_unittest.cc",
- ]
- }
-
if (!use_aura && !is_mac) {
sources -= [ "display_embedder/buffer_queue_unittest.cc" ]
}
@@ -619,7 +513,6 @@ viz_source_set("unit_tests") {
"//components/viz/test:test_suite",
"//components/viz/test:test_support",
"//gpu/command_buffer/client",
- "//gpu/command_buffer/client:gles2_implementation",
"//gpu/ipc:gl_in_process_context",
"//gpu/ipc/service",
"//media",
@@ -690,7 +583,6 @@ viz_source_set("perf_tests") {
sources = [
"display/bsp_tree_perftest.cc",
"display/display_perftest.cc",
- "display/gl_renderer_copier_perftest.cc",
"display/renderer_perftest.cc",
"display/surface_aggregator_perftest.cc",
"display/viz_perftest.cc",
@@ -728,6 +620,8 @@ if (is_android) {
android_library("service_java") {
deps = [
"//base:base_java",
+ "//base:jni_java",
+ "//build/android:build_java",
"//ui/android:ui_no_recycler_view_java",
]
annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
diff --git a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc
index 9b0b639fdae..941f49d8688 100644
--- a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc
+++ b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.cc
@@ -89,8 +89,7 @@ FuzzerSoftwareOutputSurfaceProvider::~FuzzerSoftwareOutputSurfaceProvider() =
std::unique_ptr<DisplayCompositorMemoryAndTaskController>
FuzzerSoftwareOutputSurfaceProvider::CreateGpuDependency(
bool gpu_compositing,
- gpu::SurfaceHandle surface_handle,
- const RendererSettings& renderer_settings) {
+ gpu::SurfaceHandle surface_handle) {
return nullptr;
}
diff --git a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h
index 2f115f653b8..24ccdee8476 100644
--- a/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h
+++ b/chromium/components/viz/service/compositor_frame_fuzzer/fuzzer_software_output_surface_provider.h
@@ -30,8 +30,7 @@ class FuzzerSoftwareOutputSurfaceProvider : public OutputSurfaceProvider {
// OutputSurfaceProvider implementation.
std::unique_ptr<DisplayCompositorMemoryAndTaskController> CreateGpuDependency(
bool gpu_compositing,
- gpu::SurfaceHandle surface_handle,
- const RendererSettings& renderer_settings) override;
+ gpu::SurfaceHandle surface_handle) override;
std::unique_ptr<OutputSurface> CreateOutputSurface(
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
diff --git a/chromium/components/viz/service/display/DEPS b/chromium/components/viz/service/display/DEPS
index 057df66329e..ca3f9db0518 100644
--- a/chromium/components/viz/service/display/DEPS
+++ b/chromium/components/viz/service/display/DEPS
@@ -16,7 +16,7 @@ include_rules = [
"+components/viz/service/display_embedder/overlay_candidate_validator_win.h",
"+components/viz/service/display_embedder/skia_output_surface_dependency.h",
"+components/viz/common",
- "+gpu/command_buffer/client",
+ "+gpu/command_buffer/client/shared_image_interface.h",
"+gpu/command_buffer/common",
"+gpu/command_buffer/service",
"+gpu/GLES2",
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.cc b/chromium/components/viz/service/display/ca_layer_overlay.cc
index 1c873a3e7a7..9da6b5e17d5 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.cc
+++ b/chromium/components/viz/service/display/ca_layer_overlay.cc
@@ -136,6 +136,10 @@ gfx::CALayerResult FromRenderPassQuad(
ca_layer_overlay->rpdq = quad;
ca_layer_overlay->contents_rect = gfx::RectF(0, 0, 1, 1);
+ // For RenderPassDrawQuad, the opacity is applied when its ddl is recorded, so
+ // the content already is with opacity applied.
+ ca_layer_overlay->opacity = 1.0;
+
return gfx::kCALayerSuccess;
}
@@ -156,7 +160,7 @@ gfx::CALayerResult FromSolidColorDrawQuad(const SolidColorDrawQuad* quad,
CALayerOverlay* ca_layer_overlay,
bool* skip) {
// Do not generate quads that are completely transparent.
- if (SkColorGetA(quad->color) == 0) {
+ if (quad->color.fA == 0.0f) {
*skip = true;
return gfx::kCALayerSuccess;
}
@@ -187,7 +191,7 @@ gfx::CALayerResult FromTextureQuad(DisplayResourceProvider* resource_provider,
if (quad->vertex_opacity[i] != quad->vertex_opacity[0])
return gfx::kCALayerFailedDifferentVertexOpacities;
}
- ca_layer_overlay->shared_state->opacity *= quad->vertex_opacity[0];
+ ca_layer_overlay->opacity *= quad->vertex_opacity[0];
ca_layer_overlay->filter = quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR;
if (quad->is_video_frame)
ca_layer_overlay->protected_video_type = quad->protected_video_type;
@@ -310,13 +314,13 @@ class CALayerOverlayProcessorInternal {
// Enable edge anti-aliasing only on layer boundaries.
ca_layer_overlay->edge_aa_mask = 0;
if (quad->IsLeftEdge())
- ca_layer_overlay->edge_aa_mask |= GL_CA_LAYER_EDGE_LEFT_CHROMIUM;
+ ca_layer_overlay->edge_aa_mask |= ui::CALayerEdge::kLayerEdgeLeft;
if (quad->IsRightEdge())
- ca_layer_overlay->edge_aa_mask |= GL_CA_LAYER_EDGE_RIGHT_CHROMIUM;
+ ca_layer_overlay->edge_aa_mask |= ui::CALayerEdge::kLayerEdgeRight;
if (quad->IsBottomEdge())
- ca_layer_overlay->edge_aa_mask |= GL_CA_LAYER_EDGE_BOTTOM_CHROMIUM;
+ ca_layer_overlay->edge_aa_mask |= ui::CALayerEdge::kLayerEdgeBottom;
if (quad->IsTopEdge())
- ca_layer_overlay->edge_aa_mask |= GL_CA_LAYER_EDGE_TOP_CHROMIUM;
+ ca_layer_overlay->edge_aa_mask |= ui::CALayerEdge::kLayerEdgeTop;
if (most_recent_shared_quad_state_ != quad->shared_quad_state) {
most_recent_shared_quad_state_ = quad->shared_quad_state;
@@ -331,14 +335,13 @@ class CALayerOverlayProcessorInternal {
most_recent_overlay_shared_state_->rounded_corner_bounds =
quad->shared_quad_state->mask_filter_info.rounded_corner_bounds();
- most_recent_overlay_shared_state_->opacity =
- quad->shared_quad_state->opacity;
most_recent_overlay_shared_state_->transform =
quad->shared_quad_state->quad_to_target_transform;
}
ca_layer_overlay->shared_state = most_recent_overlay_shared_state_;
ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
+ ca_layer_overlay->opacity = quad->shared_quad_state->opacity;
*render_pass_draw_quad =
quad->material == DrawQuad::Material::kAggregatedRenderPass;
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.h b/chromium/components/viz/service/display/ca_layer_overlay.h
index 7d3dacb6ead..8174a19ac5a 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.h
+++ b/chromium/components/viz/service/display/ca_layer_overlay.h
@@ -14,7 +14,6 @@
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/rrect_f.h"
@@ -22,8 +21,6 @@
#include "ui/gfx/video_types.h"
#include "ui/gl/ca_renderer_layer_params.h"
-class SkDeferredDisplayList;
-
namespace viz {
class AggregatedRenderPassDrawQuad;
class DisplayResourceProvider;
@@ -43,8 +40,6 @@ class VIZ_SERVICE_EXPORT CALayerOverlaySharedState
bool is_clipped = false;
gfx::RectF clip_rect;
gfx::RRectF rounded_corner_bounds;
- // The opacity property for the CAayer.
- float opacity = 1;
// The transform to apply to the CALayer.
gfx::Transform transform;
@@ -73,8 +68,10 @@ class VIZ_SERVICE_EXPORT CALayerOverlay {
gfx::RectF contents_rect;
// The bounds for the CALayer in pixels.
gfx::RectF bounds_rect;
+ // The opacity property for the CAayer.
+ float opacity = 1;
// The background color property for the CALayer.
- SkColor background_color = SK_ColorTRANSPARENT;
+ SkColor4f background_color = SkColors::kTransparent;
// The edge anti-aliasing mask property for the CALayer.
unsigned edge_aa_mask = 0;
// The minification and magnification filters for the CALayer.
@@ -85,8 +82,6 @@ class VIZ_SERVICE_EXPORT CALayerOverlay {
// If |rpdq| is present, then the renderer must draw the filter effects and
// copy the result into an IOSurface.
const AggregatedRenderPassDrawQuad* rpdq = nullptr;
- // The DDL for generating render pass overlay buffer with SkiaRenderer.
- sk_sp<SkDeferredDisplayList> ddl;
};
typedef std::vector<CALayerOverlay> CALayerOverlayList;
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.cc b/chromium/components/viz/service/display/dc_layer_overlay.cc
index 0d97d7c3277..bb845f7ea91 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.cc
+++ b/chromium/components/viz/service/display/dc_layer_overlay.cc
@@ -13,6 +13,7 @@
#include "build/build_config.h"
#include "cc/base/math_util.h"
#include "components/viz/common/display/renderer_settings.h"
+#include "components/viz/common/overlay_state/win/overlay_state_service.h"
#include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
#include "components/viz/common/quads/debug_border_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
@@ -23,6 +24,7 @@
#include "components/viz/service/display/overlay_processor_interface.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/config/gpu_finch_features.h"
+#include "media/base/win/mf_feature_checks.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -317,7 +319,7 @@ bool IsOccluded(
overlap_rect = ClippedQuadRectangle(quad);
if (quad->material == DrawQuad::Material::kSolidColor) {
- SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
+ SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color.toSkColor();
float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
if (quad->ShouldDrawWithBlending() &&
alpha < std::numeric_limits<float>::epsilon())
@@ -436,6 +438,7 @@ DCLayerOverlayProcessor::DCLayerOverlayProcessor(
UpdateHasHwOverlaySupport();
ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
}
+ allow_promotion_hinting_ = media::SupportMediaFoundationClearPlayback();
}
DCLayerOverlayProcessor::~DCLayerOverlayProcessor() {
@@ -675,6 +678,7 @@ void DCLayerOverlayProcessor::Process(
continue;
}
+ gpu::Mailbox promotion_hint_mailbox;
DCLayerResult result;
switch (it->material) {
case DrawQuad::Material::kYuvVideoContent:
@@ -686,19 +690,50 @@ void DCLayerOverlayProcessor::Process(
if (result == DC_LAYER_SUCCESS)
processed_yuv_overlay_count_++;
break;
- case DrawQuad::Material::kStreamVideoContent:
+ case DrawQuad::Material::kStreamVideoContent: {
+ if (allow_promotion_hinting_) {
+ // If this quad has marked itself as wanting promotion hints then get
+ // the associated mailbox.
+ const StreamVideoDrawQuad* sv_quad =
+ StreamVideoDrawQuad::MaterialCast(*it);
+ ResourceId id = sv_quad->resource_id();
+ if (resource_provider->DoesResourceWantPromotionHint(id)) {
+ promotion_hint_mailbox = resource_provider->GetMailbox(id);
+ }
+ }
// Stream video quads contain Media Foundation dcomp surface which is
// always presented as overlay.
result = DC_LAYER_SUCCESS;
- break;
- case DrawQuad::Material::kTextureContent:
+ } break;
+ case DrawQuad::Material::kTextureContent: {
result = ValidateTextureQuad(TextureDrawQuad::MaterialCast(*it),
backdrop_filter_rects, resource_provider);
- break;
+
+ if (allow_promotion_hinting_) {
+ // If this quad has marked itself as wanting promotion hints then get
+ // the associated mailbox.
+ const TextureDrawQuad* tex_quad = TextureDrawQuad::MaterialCast(*it);
+ ResourceId id = tex_quad->resource_id();
+ if (resource_provider->DoesResourceWantPromotionHint(id)) {
+ promotion_hint_mailbox = resource_provider->GetMailbox(id);
+ }
+ }
+ } break;
default:
result = DC_LAYER_FAILED_UNSUPPORTED_QUAD;
}
+ if (!promotion_hint_mailbox.IsZero()) {
+ DCHECK(allow_promotion_hinting_);
+ bool promoted = result == DC_LAYER_SUCCESS;
+ auto* overlay_state_service = OverlayStateService::GetInstance();
+ // The OverlayStateService should always be initialized by GpuServiceImpl
+ // at creation - DCHECK here just to assert there aren't any corner cases
+ // where this isn't true.
+ DCHECK(overlay_state_service->IsInitialized());
+ overlay_state_service->SetPromotionHint(promotion_hint_mailbox, promoted);
+ }
+
if (result != DC_LAYER_SUCCESS) {
RecordDCLayerResult(result, it);
continue;
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.h b/chromium/components/viz/service/display/dc_layer_overlay.h
index 390be729590..fab70d446b3 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.h
+++ b/chromium/components/viz/service/display/dc_layer_overlay.h
@@ -162,16 +162,17 @@ class VIZ_SERVICE_EXPORT DCLayerOverlayProcessor
const raw_ptr<const DebugRendererSettings> debug_settings_;
bool previous_frame_underlay_is_opaque_ = true;
+ bool allow_promotion_hinting_ = false;
gfx::RectF previous_display_rect_;
std::vector<size_t> damages_to_be_removed_;
struct OverlayRect {
gfx::Rect rect;
bool is_overlay; // If false, it's an underlay.
- bool operator==(const OverlayRect& b) {
+ bool operator==(const OverlayRect& b) const {
return rect == b.rect && is_overlay == b.is_overlay;
}
- bool operator!=(const OverlayRect& b) { return !(*this == b); }
+ bool operator!=(const OverlayRect& b) const { return !(*this == b); }
};
std::vector<OverlayRect> previous_frame_overlay_rects_;
std::vector<OverlayRect> current_frame_overlay_rects_;
diff --git a/chromium/components/viz/service/display/direct_renderer.cc b/chromium/components/viz/service/display/direct_renderer.cc
index 65407f9e679..ce0b247406d 100644
--- a/chromium/components/viz/service/display/direct_renderer.cc
+++ b/chromium/components/viz/service/display/direct_renderer.cc
@@ -92,21 +92,10 @@ DirectRenderer::DirectRenderer(const RendererSettings* settings,
DirectRenderer::~DirectRenderer() = default;
void DirectRenderer::Initialize() {
- auto* context_provider = output_surface_->context_provider();
-
use_partial_swap_ = settings_->partial_swap_enabled && CanPartialSwap();
- allow_empty_swap_ = use_partial_swap_;
- if (context_provider) {
- if (context_provider->ContextCapabilities().commit_overlay_planes)
- allow_empty_swap_ = true;
-#if DCHECK_IS_ON()
- supports_occlusion_query_ =
- context_provider->ContextCapabilities().occlusion_query;
-#endif
- } else {
- allow_empty_swap_ |=
- output_surface_->capabilities().supports_commit_overlay_planes;
- }
+ allow_empty_swap_ =
+ use_partial_swap_ ||
+ output_surface_->capabilities().supports_commit_overlay_planes;
initialized_ = true;
}
@@ -226,28 +215,6 @@ void DirectRenderer::DrawFrame(
auto* root_render_pass = render_passes_in_draw_order->back().get();
DCHECK(root_render_pass);
-#if DCHECK_IS_ON()
- bool overdraw_tracing_enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("viz.overdraw"),
- &overdraw_tracing_enabled);
- DLOG_IF(WARNING, !overdraw_tracing_support_missing_logged_once_ &&
- overdraw_tracing_enabled && !supports_occlusion_query_)
- << "Overdraw tracing enabled on platform without support.";
- overdraw_tracing_support_missing_logged_once_ = true;
-#endif
-
- bool overdraw_feedback = debug_settings_->show_overdraw_feedback;
- if (overdraw_feedback && !output_surface_->capabilities().supports_stencil) {
-#if DCHECK_IS_ON()
- DLOG_IF(WARNING, !overdraw_feedback_support_missing_logged_once_)
- << "Overdraw feedback enabled on platform without support.";
- overdraw_feedback_support_missing_logged_once_ = true;
-#endif
- overdraw_feedback = false;
- }
- base::AutoReset<bool> auto_reset_overdraw_feedback(&overdraw_feedback_,
- overdraw_feedback);
-
current_frame_valid_ = true;
current_frame_ = DrawingFrame();
current_frame()->render_passes_in_draw_order = render_passes_in_draw_order;
@@ -366,26 +333,21 @@ void DirectRenderer::DrawFrame(
// Only reshape when we know we are going to draw. Otherwise, the reshape
// can leave the window at the wrong size if we never draw and the proper
// viewport size is never set.
- bool use_stencil = overdraw_feedback_;
bool needs_full_frame_redraw = false;
auto display_transform = output_surface_->GetDisplayTransform();
+ OutputSurface::ReshapeParams reshape_params;
+ reshape_params.size = surface_resource_size;
+ reshape_params.device_scale_factor = device_scale_factor;
+ reshape_params.color_space = frame_color_space;
+ reshape_params.sdr_white_level = CurrentFrameSDRWhiteLevel();
+ reshape_params.format = frame_buffer_format;
if (next_frame_needs_full_frame_redraw_ ||
- surface_resource_size != reshape_surface_size_ ||
- device_scale_factor != reshape_device_scale_factor_ ||
- frame_color_space != reshape_color_space_ ||
- frame_buffer_format != reshape_buffer_format_ ||
- use_stencil != reshape_use_stencil_ ||
+ reshape_params != reshape_params_ ||
display_transform != reshape_display_transform_) {
next_frame_needs_full_frame_redraw_ = false;
- reshape_surface_size_ = surface_resource_size;
- reshape_device_scale_factor_ = device_scale_factor;
- reshape_color_space_ = frame_color_space;
- reshape_buffer_format_ = frame_buffer_format;
- reshape_use_stencil_ = overdraw_feedback_;
+ reshape_params_ = reshape_params;
reshape_display_transform_ = display_transform;
- output_surface_->Reshape(reshape_surface_size_,
- reshape_device_scale_factor_, reshape_color_space_,
- *reshape_buffer_format_, reshape_use_stencil_);
+ output_surface_->Reshape(reshape_params);
#if BUILDFLAG(IS_APPLE)
// For Mac, all render passes will be promoted to CALayer, the redraw full
// frame is for the main surface only.
@@ -422,16 +384,6 @@ void DirectRenderer::DrawFrame(
if (!skip_drawing_root_render_pass)
DrawRenderPassAndExecuteCopyRequests(root_render_pass);
- // Use a fence to synchronize display of the main fb used by the output
- // surface. Note that gpu_fence_id may have the special value 0 ("no fence")
- // if fences are not supported. In that case synchronization will happen
- // through other means on the service side.
- // TODO(afrantzis): Consider using per-overlay fences instead of the one
- // associated with the output surface when possible.
- if (current_frame()->output_surface_plane)
- current_frame()->output_surface_plane->gpu_fence_id =
- output_surface_->UpdateGpuFence();
-
if (overlay_processor_)
overlay_processor_->TakeOverlayCandidates(&current_frame()->overlay_list);
@@ -657,16 +609,8 @@ void DirectRenderer::DrawRenderPass(const AggregatedRenderPass* render_pass) {
const bool render_pass_requires_scissor =
render_pass_is_clipped || (supports_dc_layers && is_root_render_pass);
- const bool has_external_stencil_test =
- is_root_render_pass && output_surface_->HasExternalStencilTest();
const bool should_clear_surface =
- !has_external_stencil_test &&
- (!is_root_render_pass || settings_->should_clear_root_render_pass);
-
- // If |has_external_stencil_test| we can't discard or clear. Make sure we
- // don't need to.
- DCHECK(!has_external_stencil_test ||
- !current_frame()->current_render_pass->has_transparent_background);
+ !is_root_render_pass || settings_->should_clear_root_render_pass;
SurfaceInitializationMode mode;
if (should_clear_surface && render_pass_requires_scissor) {
@@ -737,9 +681,6 @@ void DirectRenderer::DrawRenderPass(const AggregatedRenderPass* render_pass) {
render_pass_requires_scissor);
FinishDrawingQuadList();
- if (is_root_render_pass && overdraw_feedback_)
- FlushOverdrawFeedback(render_pass_scissor_in_draw_space);
-
if (render_pass->generate_mipmap)
GenerateMipmap();
}
@@ -1007,6 +948,10 @@ bool DirectRenderer::ShouldApplyRoundedCorner(const DrawQuad* quad) const {
return false;
}
+float DirectRenderer::CurrentFrameSDRWhiteLevel() const {
+ return current_frame()->display_color_spaces.GetSDRMaxLuminanceNits();
+}
+
gfx::ColorSpace DirectRenderer::RootRenderPassColorSpace() const {
return current_frame()->display_color_spaces.GetOutputColorSpace(
current_frame()->root_render_pass->content_color_usage,
diff --git a/chromium/components/viz/service/display/direct_renderer.h b/chromium/components/viz/service/display/direct_renderer.h
index 0c6a57744c2..881356c9c73 100644
--- a/chromium/components/viz/service/display/direct_renderer.h
+++ b/chromium/components/viz/service/display/direct_renderer.h
@@ -23,7 +23,6 @@
#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display/overlay_processor_interface.h"
#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/delegated_ink_metadata.h"
@@ -111,8 +110,6 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
virtual void SwapBuffersSkipped() {}
virtual void SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {}
virtual void BuffersPresented() {}
- virtual void DidReceiveTextureInUseResponses(
- const gpu::TextureInUseResponses& responses) {}
virtual void DidReceiveReleasedOverlays(
const std::vector<gpu::Mailbox>& released_overlays) {}
@@ -264,7 +261,6 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
virtual void DoDrawQuad(const DrawQuad* quad,
const gfx::QuadF* clip_region) = 0;
virtual void BeginDrawingFrame() = 0;
- virtual void FlushOverdrawFeedback(const gfx::Rect& output_rect) {}
virtual void FinishDrawingFrame() = 0;
// If a pass contains a single tile draw quad and can be drawn without
// a render pass (e.g. applying a filter directly to the tile quad)
@@ -282,7 +278,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
virtual void GenerateMipmap() = 0;
gfx::Size surface_size_for_swap_buffers() const {
- return reshape_surface_size_;
+ return reshape_params_ ? reshape_params_->size : gfx::Size();
}
gfx::Size viewport_size_for_swap_buffers() const {
return device_viewport_size_;
@@ -290,8 +286,16 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
bool ShouldApplyRoundedCorner(const DrawQuad* quad) const;
+ float CurrentFrameSDRWhiteLevel() const;
gfx::ColorSpace RootRenderPassColorSpace() const;
gfx::ColorSpace CurrentRenderPassColorSpace() const;
+ // Return the SkColorSpace for rendering to the current render pass. Unlike
+ // CurrentRenderPassColorSpace, this color space has the value of
+ // CurrentFrameSDRWhiteLevel incorporated into it.
+ sk_sp<SkColorSpace> CurrentRenderPassSkColorSpace() const {
+ return CurrentRenderPassColorSpace().ToSkColorSpace(
+ CurrentFrameSDRWhiteLevel());
+ }
const raw_ptr<const RendererSettings> settings_;
// Points to the viz-global singleton.
@@ -308,8 +312,6 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
bool allow_empty_swap_ = false;
// Whether partial swap can be used.
bool use_partial_swap_ = false;
- // Whether overdraw feedback is enabled and can be used.
- bool overdraw_feedback_ = false;
// A map from RenderPass id to the single quad present in and replacing the
// RenderPass. The DrawQuads are owned by their RenderPasses, which outlive
@@ -350,10 +352,13 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
return &current_frame_;
}
gfx::BufferFormat reshape_buffer_format() const {
- DCHECK(reshape_buffer_format_);
- return reshape_buffer_format_.value();
+ DCHECK(reshape_params_);
+ return reshape_params_->format;
+ }
+ gfx::ColorSpace reshape_color_space() const {
+ DCHECK(reshape_params_);
+ return reshape_params_->color_space;
}
- gfx::ColorSpace reshape_color_space() const { return reshape_color_space_; }
// Sets a DelegatedInkPointRendererSkiaForTest to be used for testing only, in
// order to save delegated ink metadata values that would otherwise be reset.
@@ -364,11 +369,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
virtual void DrawDelegatedInkTrail();
bool initialized_ = false;
-#if DCHECK_IS_ON()
- bool overdraw_feedback_support_missing_logged_once_ = false;
- bool overdraw_tracing_support_missing_logged_once_ = false;
- bool supports_occlusion_query_ = false;
-#endif
+
gfx::Rect last_root_render_pass_scissor_rect_;
gfx::Size enlarge_pass_texture_amount_;
@@ -379,20 +380,16 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
bool current_frame_valid_ = false;
// Time of most recent reshape that ended up with |device_viewport_size_| !=
- // |reshape_surface_size_|.
+ // |reshape_params->size|.
base::TimeTicks last_viewport_resize_time_;
bool next_frame_needs_full_frame_redraw_ = false;
- // Cached values given to Reshape(). The |reshape_buffer_format_| is optional
- // to prevent use of uninitialized values. This may be larger than the
- // |device_viewport_size_| that users see.
- gfx::Size reshape_surface_size_;
+ // Cached values given to Reshape(). The `reshape_params_` is optional
+ // to prevent use of uninitialized values. The size in these parameters
+ // may be larger than the `device_viewport_size_` that users see.
+ absl::optional<OutputSurface::ReshapeParams> reshape_params_;
gfx::Size device_viewport_size_;
- float reshape_device_scale_factor_ = 0.f;
- gfx::ColorSpace reshape_color_space_;
- absl::optional<gfx::BufferFormat> reshape_buffer_format_;
- bool reshape_use_stencil_ = false;
gfx::OverlayTransform reshape_display_transform_ =
gfx::OVERLAY_TRANSFORM_INVALID;
};
diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc
index 40db30fb146..07d38ad3d92 100644
--- a/chromium/components/viz/service/display/display.cc
+++ b/chromium/components/viz/service/display/display.cc
@@ -24,6 +24,7 @@
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/shared_quad_state.h"
@@ -34,12 +35,10 @@
#include "components/viz/service/display/delegated_ink_point_renderer_base.h"
#include "components/viz/service/display/direct_renderer.h"
#include "components/viz/service/display/display_client.h"
-#include "components/viz/service/display/display_resource_provider_gl.h"
#include "components/viz/service/display/display_resource_provider_null.h"
#include "components/viz/service/display/display_resource_provider_skia.h"
#include "components/viz/service/display/display_resource_provider_software.h"
#include "components/viz/service/display/display_scheduler.h"
-#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/service/display/null_renderer.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/renderer_utils.h"
@@ -49,8 +48,6 @@
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/ipc/scheduler_sequence.h"
#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -108,9 +105,6 @@ int64_t GetStartingTraceId() {
gfx::PresentationFeedback SanitizePresentationFeedback(
const gfx::PresentationFeedback& feedback,
base::TimeTicks draw_time) {
- // Temporary to investigate large presentation times.
- // https://crbug.com/894440
- DCHECK(!draw_time.is_null());
if (feedback.timestamp.is_null())
return feedback;
@@ -130,26 +124,10 @@ gfx::PresentationFeedback SanitizePresentationFeedback(
gfx::PresentationFeedback::kVSync)) != 0)
? kAllowedDeltaFromFuture
: base::TimeDelta();
- if (feedback.timestamp > now + allowed_delta_from_future) {
- const auto diff = feedback.timestamp - now;
- UMA_HISTOGRAM_MEDIUM_TIMES(
- "Graphics.PresentationTimestamp.InvalidFromFuture", diff);
+ if ((feedback.timestamp > now + allowed_delta_from_future) ||
+ (feedback.timestamp < draw_time)) {
return gfx::PresentationFeedback::Failure();
}
-
- if (feedback.timestamp < draw_time) {
- const auto diff = draw_time - feedback.timestamp;
- UMA_HISTOGRAM_MEDIUM_TIMES(
- "Graphics.PresentationTimestamp.InvalidBeforeSwap", diff);
- return gfx::PresentationFeedback::Failure();
- }
-
- const auto difference = feedback.timestamp - draw_time;
- if (difference.InMinutes() > 3) {
- UMA_HISTOGRAM_CUSTOM_TIMES(
- "Graphics.PresentationTimestamp.LargePresentationDelta", difference,
- base::Minutes(3), base::Hours(1), 50);
- }
return feedback;
}
@@ -360,15 +338,6 @@ Display::~Display() {
if (resource_provider_) {
resource_provider_->SetAllowAccessToGPUThread(true);
}
-#if BUILDFLAG(IS_ANDROID)
- // In certain cases, drivers hang when tearing down the display. Finishing
- // before teardown appears to address this. As we're during display teardown,
- // an additional finish should have minimal impact.
- // TODO(ericrk): Add a more robust workaround. crbug.com/899705
- if (auto* context = output_surface_->context_provider()) {
- context->ContextGL()->Finish();
- }
-#endif
if (no_pending_swaps_callback_)
std::move(no_pending_swaps_callback_).Run();
@@ -383,8 +352,6 @@ Display::~Display() {
// Only do this if Initialize() happened.
if (client_) {
- if (auto* context = output_surface_->context_provider())
- context->RemoveObserver(this);
if (skia_output_surface_)
skia_output_surface_->RemoveContextLostObserver(this);
}
@@ -426,9 +393,6 @@ void Display::Initialize(DisplayClient* client,
// This depends on assumptions that Display::Initialize will happen on the
// same callstack as the ContextProvider being created/initialized or else
// it could miss a callback before setting this.
- if (auto* context = output_surface_->context_provider())
- context->AddObserver(this);
-
if (skia_output_surface_)
skia_output_surface_->AddContextLostObserver(this);
}
@@ -508,8 +472,7 @@ void Display::DisableSwapUntilResize(
scheduler_->ForceImmediateSwapIfPossible();
if (no_pending_swaps_callback && pending_swaps_ > 0 &&
- (output_surface_->context_provider() ||
- output_surface_->AsSkiaOutputSurface())) {
+ output_surface_->AsSkiaOutputSurface()) {
no_pending_swaps_callback_ = std::move(no_pending_swaps_callback);
}
@@ -562,14 +525,6 @@ void Display::InitializeRenderer(bool enable_shared_images) {
resource_provider.get(), overlay_processor_.get(),
skia_output_surface_);
resource_provider_ = std::move(resource_provider);
- } else if (output_surface_->context_provider()) {
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider(), enable_shared_images);
- renderer_ = std::make_unique<GLRenderer>(
- &settings_, debug_settings_, output_surface_.get(),
- resource_provider.get(), overlay_processor_.get(),
- current_task_runner_);
- resource_provider_ = std::move(resource_provider);
} else if (output_surface_->capabilities().skips_draw) {
auto resource_provider = std::make_unique<DisplayResourceProviderNull>();
renderer_ = std::make_unique<NullRenderer>(
@@ -895,21 +850,6 @@ bool Display::DrawAndSwap(const DrawAndSwapParams& params) {
renderer_->DrawFrame(&frame.render_pass_list, device_scale_factor_,
current_surface_size, display_color_spaces_,
std::move(frame.surface_damage_rect_list_));
- switch (output_surface_->type()) {
- case OutputSurface::Type::kSoftware:
- UMA_HISTOGRAM_COUNTS_1M(
- "Compositing.DirectRenderer.Software.DrawFrameUs",
- draw_timer->Elapsed().InMicroseconds());
- break;
- case OutputSurface::Type::kOpenGL:
- UMA_HISTOGRAM_COUNTS_1M("Compositing.DirectRenderer.GL.DrawFrameUs",
- draw_timer->Elapsed().InMicroseconds());
- break;
- case OutputSurface::Type::kVulkan:
- UMA_HISTOGRAM_COUNTS_1M("Compositing.DirectRenderer.VK.DrawFrameUs",
- draw_timer->Elapsed().InMicroseconds());
- break;
- }
} else {
TRACE_EVENT_INSTANT0("viz", "Draw skipped.", TRACE_EVENT_SCOPE_THREAD);
}
@@ -1113,12 +1053,6 @@ void Display::DidReceiveSwapBuffersAck(const gfx::SwapTimings& timings,
}
}
-void Display::DidReceiveTextureInUseResponses(
- const gpu::TextureInUseResponses& responses) {
- if (renderer_)
- renderer_->DidReceiveTextureInUseResponses(responses);
-}
-
void Display::DidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) {
if (client_)
diff --git a/chromium/components/viz/service/display/display.h b/chromium/components/viz/service/display/display.h
index 3cdb7e3012e..cb26d6cab8c 100644
--- a/chromium/components/viz/service/display/display.h
+++ b/chromium/components/viz/service/display/display.h
@@ -35,7 +35,6 @@
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_manager.h"
#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/gfx/swap_result.h"
@@ -161,8 +160,6 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
void DidReceiveSwapBuffersAck(const gfx::SwapTimings& timings,
gfx::GpuFenceHandle release_fence) override;
- void DidReceiveTextureInUseResponses(
- const gpu::TextureInUseResponses& responses) override;
void DidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) override;
void DidSwapWithSize(const gfx::Size& pixel_size) override;
diff --git a/chromium/components/viz/service/display/display_damage_tracker.cc b/chromium/components/viz/service/display/display_damage_tracker.cc
index 2c477b65304..94bcdf68391 100644
--- a/chromium/components/viz/service/display/display_damage_tracker.cc
+++ b/chromium/components/viz/service/display/display_damage_tracker.cc
@@ -176,11 +176,6 @@ bool DisplayDamageTracker::OnSurfaceDamaged(const SurfaceId& surface_id,
return display_damaged;
}
-void DisplayDamageTracker::OnSurfaceDestroyed(const SurfaceId& surface_id) {
- TRACE_EVENT0("viz", "DisplayDamageTracker::SurfaceDestroyed");
- aggregator_->ReleaseResources(surface_id);
-}
-
void DisplayDamageTracker::OnSurfaceDamageExpected(const SurfaceId& surface_id,
const BeginFrameArgs& args) {
TRACE_EVENT1("viz", "DisplayDamageTracker::SurfaceDamageExpected",
diff --git a/chromium/components/viz/service/display/display_damage_tracker.h b/chromium/components/viz/service/display/display_damage_tracker.h
index dfc451ee009..3abe233ff1c 100644
--- a/chromium/components/viz/service/display/display_damage_tracker.h
+++ b/chromium/components/viz/service/display/display_damage_tracker.h
@@ -81,7 +81,6 @@ class VIZ_SERVICE_EXPORT DisplayDamageTracker : public SurfaceObserver {
void OnSurfaceMarkedForDestruction(const SurfaceId& surface_id) override;
bool OnSurfaceDamaged(const SurfaceId& surface_id,
const BeginFrameAck& ack) override;
- void OnSurfaceDestroyed(const SurfaceId& surface_id) override;
void OnSurfaceDamageExpected(const SurfaceId& surface_id,
const BeginFrameArgs& args) override;
diff --git a/chromium/components/viz/service/display/display_perftest.cc b/chromium/components/viz/service/display/display_perftest.cc
index 5327ee598c3..0ee8fd42e42 100644
--- a/chromium/components/viz/service/display/display_perftest.cc
+++ b/chromium/components/viz/service/display/display_perftest.cc
@@ -22,7 +22,7 @@
#include "components/viz/service/display/overlay_processor_stub.h"
#include "components/viz/service/display/shared_bitmap_manager.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
-#include "components/viz/test/fake_output_surface.h"
+#include "components/viz/test/fake_skia_output_surface.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_result_reporter.h"
@@ -68,8 +68,8 @@ class RemoveOverdrawQuadPerfTest : public testing::Test {
auto scheduler = std::make_unique<DisplayScheduler>(
&begin_frame_source_, task_runner_.get(), PendingSwapParams(1));
- std::unique_ptr<FakeOutputSurface> output_surface =
- FakeOutputSurface::Create3d();
+ std::unique_ptr<FakeSkiaOutputSurface> output_surface =
+ FakeSkiaOutputSurface::Create3d();
auto overlay_processor = std::make_unique<OverlayProcessorStub>();
// Normally display will need to take ownership of a
diff --git a/chromium/components/viz/service/display/display_resource_provider.cc b/chromium/components/viz/service/display/display_resource_provider.cc
index eb87fff486f..6f80ebffcfb 100644
--- a/chromium/components/viz/service/display/display_resource_provider.cc
+++ b/chromium/components/viz/service/display/display_resource_provider.cc
@@ -8,6 +8,7 @@
#include <string>
#include "base/atomic_sequence_num.h"
+#include "base/notreached.h"
#include "base/numerics/safe_math.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -306,9 +307,9 @@ void DisplayResourceProvider::TryReleaseResource(ResourceId id,
}
}
-bool DisplayResourceProvider::ReadLockFenceHasPassed(
+bool DisplayResourceProvider::ResourceFenceHasPassed(
const ChildResource* resource) {
- return !resource->read_lock_fence || resource->read_lock_fence->HasPassed();
+ return !resource->resource_fence || resource->resource_fence->HasPassed();
}
DisplayResourceProvider::CanDeleteNowResult
@@ -322,7 +323,7 @@ DisplayResourceProvider::CanDeleteNow(const Child& child_info,
// Defer this resource deletion.
return CanDeleteNowResult::kNo;
- } else if (!ReadLockFenceHasPassed(&resource)) {
+ } else if (!ResourceFenceHasPassed(&resource)) {
// TODO(dcastagna): see if it's possible to use this logic for
// the branch above too, where the resource is locked or still exported.
// We can't postpone the deletion, so we'll have to lose it.
@@ -473,7 +474,8 @@ void DisplayResourceProvider::ScopedReadLockSharedImage::SetReleaseFence(
bool DisplayResourceProvider::ScopedReadLockSharedImage::HasReadLockFence()
const {
DCHECK(resource_);
- return resource_->transferable.read_lock_fences_enabled;
+ return resource_->transferable.synchronization_type ==
+ TransferableResource::SynchronizationType::kGpuCommandsCompleted;
}
void DisplayResourceProvider::ScopedReadLockSharedImage::Reset() {
diff --git a/chromium/components/viz/service/display/display_resource_provider.h b/chromium/components/viz/service/display/display_resource_provider.h
index 5d897625a42..be07f99feb7 100644
--- a/chromium/components/viz/service/display/display_resource_provider.h
+++ b/chromium/components/viz/service/display/display_resource_provider.h
@@ -162,10 +162,16 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
// Sets the current read fence. If a resource is locked for read
// and has read fences enabled, the resource will not allow writes
- // until this fence has passed.
- void SetReadLockFence(ResourceFence* fence) {
- current_read_lock_fence_ = fence;
+ // until this fence has passed. This is used if a client uses
+ // TransferableResource::SynchronizationType::kGpuCommandsCompleted.
+ void SetGpuCommandsCompletedFence(ResourceFence* fence) {
+ current_gpu_commands_completed_fence_ = fence;
}
+ // Sets the current release fence. If a client uses
+ // TransferableResource::SynchronizationType::kReleaseFence, resources must be
+ // returned only after a release fence is stored in this resource fence.
+ // Returned only when gpu commands and the gpu fence are submitted.
+ void SetReleaseFence(ResourceFence* fence) { current_release_fence_ = fence; }
// Creates accounting for a child. Returns a child ID. surface_id is used to
// associate resources to the surface they belong to. This is used for
@@ -333,12 +339,14 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
// mapped for use in the display compositor.
base::UnguessableToken shared_bitmap_tracing_guid;
- // A fence used for accessing a gpu resource for reading, that ensures any
- // writing done to the resource has been completed. This is implemented and
- // used to implement transferring ownership of the resource from the client
- // to the service, and in the GL drawing code before reading from the
- // texture.
- scoped_refptr<ResourceFence> read_lock_fence;
+ // A fence used for returning resources after the display compositor has
+ // completed accessing the resources it received from a client. This can
+ // either be a read lock or a release fence. If the |transferable| has
+ // synchronization type set as kGpuCommandsCompleted, the resource can be
+ // returned after ResourceFence::HasPassed is true. If the |transferable|
+ // has the synchronization type set as kReleaseFence, the resource can be
+ // returned after the fence has a release fence set.
+ scoped_refptr<ResourceFence> resource_fence;
// SkiaRenderer specific details about this resource. Added to ChildResource
// to avoid map lookups further down the pipeline.
@@ -371,10 +379,7 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
ChildResource* TryGetResource(ResourceId id);
void TryReleaseResource(ResourceId id, ChildResource* resource);
- // Binds the given GL resource to a texture target for sampling using the
- // specified filter for both minification and magnification. Returns the
- // texture target used. The resource must be locked for reading.
- bool ReadLockFenceHasPassed(const ChildResource* resource);
+ bool ResourceFenceHasPassed(const ChildResource* resource);
void DeleteAndReturnUnusedResourcesToChild(
ChildMap::iterator child_it,
@@ -404,7 +409,8 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
ChildMap children_;
base::flat_map<int, std::vector<ResourceId>> batched_returning_resources_;
- scoped_refptr<ResourceFence> current_read_lock_fence_;
+ scoped_refptr<ResourceFence> current_gpu_commands_completed_fence_;
+ scoped_refptr<ResourceFence> current_release_fence_;
// Keep track of whether deleted resources should be batched up or returned
// immediately.
int batch_return_resources_lock_count_ = 0;
diff --git a/chromium/components/viz/service/display/display_resource_provider_gl.cc b/chromium/components/viz/service/display/display_resource_provider_gl.cc
deleted file mode 100644
index 501cd716a1f..00000000000
--- a/chromium/components/viz/service/display/display_resource_provider_gl.cc
+++ /dev/null
@@ -1,425 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/display_resource_provider_gl.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/dcheck_is_on.h"
-#include "base/memory/raw_ptr.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/gfx/gpu_fence.h"
-#include "ui/gl/gl_fence.h"
-
-using gpu::gles2::GLES2Interface;
-
-namespace viz {
-namespace {
-
-class ScopedSetActiveTexture {
- public:
- ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
- : gl_(gl), unit_(unit) {
-#if DCHECK_IS_ON()
- GLint active_unit = 0;
- gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
- DCHECK_EQ(GL_TEXTURE0, active_unit);
-#endif
-
- if (unit_ != GL_TEXTURE0)
- gl_->ActiveTexture(unit_);
- }
-
- ~ScopedSetActiveTexture() {
- // Active unit being GL_TEXTURE0 is effectively the ground state.
- if (unit_ != GL_TEXTURE0)
- gl_->ActiveTexture(GL_TEXTURE0);
- }
-
- private:
- raw_ptr<GLES2Interface> gl_;
- GLenum unit_;
-};
-
-} // namespace
-
-DisplayResourceProviderGL::DisplayResourceProviderGL(
- ContextProvider* compositor_context_provider,
- bool enable_shared_images)
- : DisplayResourceProvider(DisplayResourceProvider::kGpu),
- compositor_context_provider_(compositor_context_provider),
- enable_shared_images_(enable_shared_images) {
- DCHECK(compositor_context_provider_);
-}
-
-DisplayResourceProviderGL::~DisplayResourceProviderGL() {
- Destroy();
- GLES2Interface* gl = ContextGL();
- if (gl)
- gl->Finish();
-
- while (!resources_.empty())
- DeleteResourceInternal(resources_.begin());
-}
-
-void DisplayResourceProviderGL::DeleteResourceInternal(
- ResourceMap::iterator it) {
- TRACE_EVENT0("viz", "DisplayResourceProvider::DeleteResourceInternal");
- ChildResource* resource = &it->second;
-
- if (resource->gl_id) {
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- gl->DeleteTextures(1, &resource->gl_id);
- }
-
- resources_.erase(it);
-}
-
-GLES2Interface* DisplayResourceProviderGL::ContextGL() const {
- DCHECK(compositor_context_provider_);
- return compositor_context_provider_->ContextGL();
-}
-
-const DisplayResourceProvider::ChildResource*
-DisplayResourceProviderGL::LockForRead(ResourceId id, bool overlay_only) {
- // TODO(ericrk): We should never fail TryGetResource, but we appear to be
- // doing so on Android in rare cases. Handle this gracefully until a better
- // solution can be found. https://crbug.com/811858
- ChildResource* resource = TryGetResource(id);
- if (!resource)
- return nullptr;
-
- // Mailbox sync_tokens must be processed by a call to WaitSyncToken() prior to
- // calling LockForRead().
- DCHECK_NE(NEEDS_WAIT, resource->synchronization_state());
- DCHECK(resource->is_gpu_resource_type());
-
- const gpu::Mailbox& mailbox = resource->transferable.mailbox_holder.mailbox;
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- if (!resource->gl_id) {
- if (mailbox.IsSharedImage() && enable_shared_images_) {
- resource->gl_id =
- gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
- } else {
- resource->gl_id = gl->CreateAndConsumeTextureCHROMIUM(
- resource->transferable.mailbox_holder.mailbox.name);
- }
- resource->SetLocallyUsed();
- }
- if (mailbox.IsSharedImage() && enable_shared_images_) {
- if (overlay_only) {
- if (resource->lock_for_overlay_count == 0) {
- // If |lock_for_read_count| > 0, then BeginSharedImageAccess has
- // already been called with READ, so don't re-lock with OVERLAY.
- if (resource->lock_for_read_count == 0) {
- gl->BeginSharedImageAccessDirectCHROMIUM(
- resource->gl_id, GL_SHARED_IMAGE_ACCESS_MODE_OVERLAY_CHROMIUM);
- }
- }
- } else {
- if (resource->lock_for_read_count == 0) {
- // If |lock_for_overlay_count| > 0, then we have already begun access
- // for OVERLAY. End this access and "upgrade" it to READ.
- // See https://crbug.com/1113925 for how this can go wrong.
- if (resource->lock_for_overlay_count > 0)
- gl->EndSharedImageAccessDirectCHROMIUM(resource->gl_id);
- gl->BeginSharedImageAccessDirectCHROMIUM(
- resource->gl_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
- }
- }
- }
-
- if (overlay_only)
- resource->lock_for_overlay_count++;
- else
- resource->lock_for_read_count++;
- if (resource->transferable.read_lock_fences_enabled) {
- if (current_read_lock_fence_.get())
- current_read_lock_fence_->Set();
- resource->read_lock_fence = current_read_lock_fence_;
- }
-
- return resource;
-}
-
-void DisplayResourceProviderGL::UnlockForRead(ResourceId id,
- bool overlay_only) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- ChildResource* resource = TryGetResource(id);
- // TODO(ericrk): We should never fail to find id, but we appear to be
- // doing so on Android in rare cases. Handle this gracefully until a better
- // solution can be found. https://crbug.com/811858
- if (!resource)
- return;
-
- DCHECK(resource->is_gpu_resource_type());
- if (resource->transferable.mailbox_holder.mailbox.IsSharedImage() &&
- enable_shared_images_) {
- // If this is the last READ or OVERLAY access, then end access.
- if (resource->lock_for_read_count + resource->lock_for_overlay_count == 1) {
- DCHECK(resource->gl_id);
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- if (!resource->release_fence.is_null()) {
- auto fence = gfx::GpuFence(resource->release_fence.Clone());
- if (gl::GLFence::IsGpuFenceSupported()) {
- auto fence_id =
- gl->CreateClientGpuFenceCHROMIUM(fence.AsClientGpuFence());
- gl->WaitGpuFenceCHROMIUM(fence_id);
- gl->DestroyGpuFenceCHROMIUM(fence_id);
- } else {
- fence.Wait();
- }
- }
- gl->EndSharedImageAccessDirectCHROMIUM(resource->gl_id);
- }
- }
- if (overlay_only) {
- DCHECK_GT(resource->lock_for_overlay_count, 0);
- resource->lock_for_overlay_count--;
- } else {
- DCHECK_GT(resource->lock_for_read_count, 0);
- resource->lock_for_read_count--;
- }
- TryReleaseResource(id, resource);
-}
-
-std::vector<ReturnedResource>
-DisplayResourceProviderGL::DeleteAndReturnUnusedResourcesToChildImpl(
- Child& child_info,
- DeleteStyle style,
- const std::vector<ResourceId>& unused) {
- std::vector<ReturnedResource> to_return;
- // Reserve enough space to avoid re-allocating, so we can keep item pointers
- // for later using.
- to_return.reserve(unused.size());
- std::vector<ReturnedResource*> need_synchronization_resources;
- std::vector<GLbyte*> unverified_sync_tokens;
-
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- DCHECK(can_access_gpu_thread_);
- for (ResourceId local_id : unused) {
- auto it = resources_.find(local_id);
- CHECK(it != resources_.end());
- ChildResource& resource = it->second;
- DCHECK(resource.is_gpu_resource_type());
-
- ResourceId child_id = resource.transferable.id;
- DCHECK(child_info.child_to_parent_map.count(child_id));
-
- auto can_delete = CanDeleteNow(child_info, resource, style);
- if (can_delete == CanDeleteNowResult::kNo) {
- // Defer this resource deletion.
- resource.marked_for_deletion = true;
- continue;
- }
-
- const bool is_lost = can_delete == CanDeleteNowResult::kYesButLoseResource;
-
- if (resource.gl_id && resource.filter != resource.transferable.filter) {
- DCHECK(resource.transferable.mailbox_holder.texture_target);
- DCHECK(!resource.ShouldWaitSyncToken());
- gl->BindTexture(resource.transferable.mailbox_holder.texture_target,
- resource.gl_id);
- gl->TexParameteri(resource.transferable.mailbox_holder.texture_target,
- GL_TEXTURE_MIN_FILTER, resource.transferable.filter);
- gl->TexParameteri(resource.transferable.mailbox_holder.texture_target,
- GL_TEXTURE_MAG_FILTER, resource.transferable.filter);
- resource.SetLocallyUsed();
- }
-
- to_return.emplace_back(child_id, resource.sync_token(),
- std::move(resource.release_fence),
- resource.imported_count, is_lost);
- auto& returned = to_return.back();
-
- if (resource.needs_sync_token()) {
- need_synchronization_resources.push_back(&returned);
- } else if (returned.sync_token.HasData() &&
- !returned.sync_token.verified_flush()) {
- unverified_sync_tokens.push_back(returned.sync_token.GetData());
- }
-
- child_info.child_to_parent_map.erase(child_id);
- resource.imported_count = 0;
- DeleteResourceInternal(it);
- }
-
- gpu::SyncToken new_sync_token;
- if (!need_synchronization_resources.empty()) {
- gl->GenUnverifiedSyncTokenCHROMIUM(new_sync_token.GetData());
- unverified_sync_tokens.push_back(new_sync_token.GetData());
- }
-
- if (!unverified_sync_tokens.empty()) {
- gl->VerifySyncTokensCHROMIUM(unverified_sync_tokens.data(),
- unverified_sync_tokens.size());
- }
-
- // Set sync token after verification.
- for (ReturnedResource* returned : need_synchronization_resources)
- returned->sync_token = new_sync_token;
-
- return to_return;
-}
-
-GLenum DisplayResourceProviderGL::GetResourceTextureTarget(ResourceId id) {
- return GetResource(id)->transferable.mailbox_holder.texture_target;
-}
-
-void DisplayResourceProviderGL::WaitSyncToken(ResourceId id) {
- ChildResource* resource = TryGetResource(id);
- // TODO(ericrk): We should never fail TryGetResource, but we appear to
- // be doing so on Android in rare cases. Handle this gracefully until a
- // better solution can be found. https://crbug.com/811858
- if (!resource)
- return;
- WaitSyncTokenInternal(resource);
-}
-
-GLenum DisplayResourceProviderGL::BindForSampling(ResourceId resource_id,
- GLenum unit,
- GLenum filter) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- GLES2Interface* gl = ContextGL();
- auto it = resources_.find(resource_id);
- // TODO(ericrk): We should never fail to find resource_id, but we appear to
- // be doing so on Android in rare cases. Handle this gracefully until a
- // better solution can be found. https://crbug.com/811858
- if (it == resources_.end())
- return GL_TEXTURE_2D;
-
- ChildResource* resource = &it->second;
- DCHECK(resource->lock_for_read_count);
-
- ScopedSetActiveTexture scoped_active_tex(gl, unit);
- GLenum target = resource->transferable.mailbox_holder.texture_target;
- gl->BindTexture(target, resource->gl_id);
-
- // Texture parameters can be modified by concurrent reads so reset them
- // before binding the texture. See https://crbug.com/1092080.
- gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
- gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
- resource->filter = filter;
-
- return target;
-}
-
-void DisplayResourceProviderGL::WaitSyncTokenInternal(ChildResource* resource) {
- DCHECK(resource);
- if (!resource->ShouldWaitSyncToken())
- return;
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- // In the case of context lost, this sync token may be empty (see comment in
- // the UpdateSyncToken() function). The WaitSyncTokenCHROMIUM() function
- // handles empty sync tokens properly so just wait anyways and update the
- // state the synchronized.
- gl->WaitSyncTokenCHROMIUM(resource->sync_token().GetConstData());
- resource->SetSynchronized();
-}
-
-DisplayResourceProviderGL::ScopedReadLockGL::ScopedReadLockGL(
- DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id)
- : resource_provider_(resource_provider), resource_id_(resource_id) {
- const ChildResource* resource =
- resource_provider->LockForRead(resource_id, false /* overlay_only */);
- // TODO(ericrk): We should never fail LockForRead, but we appear to be
- // doing so on Android in rare cases. Handle this gracefully until a better
- // solution can be found. https://crbug.com/811858
- if (!resource)
- return;
-
- texture_id_ = resource->gl_id;
- target_ = resource->transferable.mailbox_holder.texture_target;
- size_ = resource->transferable.size;
- color_space_ = resource->transferable.color_space;
- hdr_metadata_ = resource->transferable.hdr_metadata;
-}
-
-DisplayResourceProviderGL::ScopedReadLockGL::~ScopedReadLockGL() {
- resource_provider_->UnlockForRead(resource_id_, false /* overlay_only */);
-}
-
-DisplayResourceProviderGL::ScopedSamplerGL::ScopedSamplerGL(
- DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id,
- GLenum filter)
- : resource_lock_(resource_provider, resource_id),
- unit_(GL_TEXTURE0),
- target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {}
-
-DisplayResourceProviderGL::ScopedSamplerGL::ScopedSamplerGL(
- DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id,
- GLenum unit,
- GLenum filter)
- : resource_lock_(resource_provider, resource_id),
- unit_(unit),
- target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {}
-
-DisplayResourceProviderGL::ScopedSamplerGL::~ScopedSamplerGL() = default;
-
-DisplayResourceProviderGL::ScopedOverlayLockGL::ScopedOverlayLockGL(
- DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id)
- : resource_provider_(resource_provider), resource_id_(resource_id) {
- const ChildResource* resource =
- resource_provider->LockForRead(resource_id, true /* overlay_only */);
- if (!resource)
- return;
-
- texture_id_ = resource->gl_id;
-}
-
-DisplayResourceProviderGL::ScopedOverlayLockGL::~ScopedOverlayLockGL() {
- resource_provider_->UnlockForRead(resource_id_, true /* overlay_only */);
-}
-
-void DisplayResourceProviderGL::ScopedOverlayLockGL::SetReleaseFence(
- gfx::GpuFenceHandle release_fence) {
- auto* resource = resource_provider_->GetResource(resource_id_);
- DCHECK(resource);
- resource->release_fence = std::move(release_fence);
-}
-
-bool DisplayResourceProviderGL::ScopedOverlayLockGL::HasReadLockFence() const {
- auto* resource = resource_provider_->GetResource(resource_id_);
- DCHECK(resource);
- return resource->transferable.read_lock_fences_enabled;
-}
-
-DisplayResourceProviderGL::SynchronousFence::SynchronousFence(
- gpu::gles2::GLES2Interface* gl)
- : gl_(gl), has_synchronized_(true) {}
-
-DisplayResourceProviderGL::SynchronousFence::~SynchronousFence() = default;
-
-void DisplayResourceProviderGL::SynchronousFence::Set() {
- has_synchronized_ = false;
-}
-
-bool DisplayResourceProviderGL::SynchronousFence::HasPassed() {
- if (!has_synchronized_) {
- has_synchronized_ = true;
- Synchronize();
- }
- return true;
-}
-
-void DisplayResourceProviderGL::SynchronousFence::Synchronize() {
- TRACE_EVENT0("viz", "DisplayResourceProvider::SynchronousFence::Synchronize");
- gl_->Finish();
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/display_resource_provider_gl.h b/chromium/components/viz/service/display/display_resource_provider_gl.h
deleted file mode 100644
index 8a75cf568a8..00000000000
--- a/chromium/components/viz/service/display/display_resource_provider_gl.h
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_GL_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_GL_H_
-
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/service/display/display_resource_provider.h"
-#include "components/viz/service/viz_service_export.h"
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-} // namespace gles2
-} // namespace gpu
-
-namespace viz {
-
-class ContextProvider;
-
-// DisplayResourceProvider implementation used with GLRenderer.
-class VIZ_SERVICE_EXPORT DisplayResourceProviderGL
- : public DisplayResourceProvider {
- public:
- // Android with GLRenderer doesn't support overlays with shared images
- // enabled. For everything else |enable_shared_images| is true.
- DisplayResourceProviderGL(ContextProvider* compositor_context_provider,
- bool enable_shared_images = true);
- ~DisplayResourceProviderGL() override;
-
- GLenum GetResourceTextureTarget(ResourceId id);
- void WaitSyncToken(ResourceId id);
-
- // The following lock classes are part of the DisplayResourceProvider API and
- // are needed to read the resource contents. The user must ensure that they
- // only use GL locks on GL resources, etc, and this is enforced by assertions.
- class VIZ_SERVICE_EXPORT ScopedReadLockGL {
- public:
- ScopedReadLockGL(DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id);
- ~ScopedReadLockGL();
-
- ScopedReadLockGL(const ScopedReadLockGL&) = delete;
- ScopedReadLockGL& operator=(const ScopedReadLockGL&) = delete;
-
- GLuint texture_id() const { return texture_id_; }
- GLenum target() const { return target_; }
- const gfx::Size& size() const { return size_; }
- const gfx::ColorSpace& color_space() const { return color_space_; }
- const absl::optional<gfx::HDRMetadata>& hdr_metadata() const {
- return hdr_metadata_;
- }
-
- private:
- const raw_ptr<DisplayResourceProviderGL> resource_provider_;
- const ResourceId resource_id_;
-
- GLuint texture_id_ = 0;
- GLenum target_ = GL_TEXTURE_2D;
- gfx::Size size_;
- gfx::ColorSpace color_space_;
- absl::optional<gfx::HDRMetadata> hdr_metadata_;
- };
-
- class VIZ_SERVICE_EXPORT ScopedSamplerGL {
- public:
- ScopedSamplerGL(DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id,
- GLenum filter);
- ScopedSamplerGL(DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id,
- GLenum unit,
- GLenum filter);
- ~ScopedSamplerGL();
-
- ScopedSamplerGL(const ScopedSamplerGL&) = delete;
- ScopedSamplerGL& operator=(const ScopedSamplerGL&) = delete;
-
- GLuint texture_id() const { return resource_lock_.texture_id(); }
- GLenum target() const { return target_; }
- const gfx::ColorSpace& color_space() const {
- return resource_lock_.color_space();
- }
- const absl::optional<gfx::HDRMetadata>& hdr_metadata() const {
- return resource_lock_.hdr_metadata();
- }
-
- private:
- const ScopedReadLockGL resource_lock_;
- const GLenum unit_;
- const GLenum target_;
- };
-
- class VIZ_SERVICE_EXPORT ScopedOverlayLockGL {
- public:
- ScopedOverlayLockGL(DisplayResourceProviderGL* resource_provider,
- ResourceId resource_id);
- ~ScopedOverlayLockGL();
-
- ScopedOverlayLockGL(const ScopedOverlayLockGL&) = delete;
- ScopedOverlayLockGL& operator=(const ScopedOverlayLockGL&) = delete;
-
- GLuint texture_id() const { return texture_id_; }
-
- // Sets the given |release_fence| onto this resource.
- // This is propagated to ReturnedResource when the resource is freed.
- void SetReleaseFence(gfx::GpuFenceHandle release_fence);
-
- // Returns true iff this resource has a read lock fence set.
- bool HasReadLockFence() const;
-
- private:
- const raw_ptr<DisplayResourceProviderGL> resource_provider_;
- const ResourceId resource_id_;
- GLuint texture_id_ = 0;
- };
-
- class VIZ_SERVICE_EXPORT SynchronousFence : public ResourceFence {
- public:
- explicit SynchronousFence(gpu::gles2::GLES2Interface* gl);
-
- SynchronousFence(const SynchronousFence&) = delete;
- SynchronousFence& operator=(const SynchronousFence&) = delete;
-
- // ResourceFence implementation.
- void Set() override;
- bool HasPassed() override;
-
- // Returns true if fence has been set but not yet synchornized.
- bool has_synchronized() const { return has_synchronized_; }
-
- private:
- ~SynchronousFence() override;
-
- void Synchronize();
-
- raw_ptr<gpu::gles2::GLES2Interface> gl_;
- bool has_synchronized_;
- };
-
- private:
- const ChildResource* LockForRead(ResourceId id, bool overlay_only);
- void UnlockForRead(ResourceId id, bool overlay_only);
-
- // DisplayResourceProvider overrides:
- std::vector<ReturnedResource> DeleteAndReturnUnusedResourcesToChildImpl(
- Child& child_info,
- DeleteStyle style,
- const std::vector<ResourceId>& unused) override;
-
- gpu::gles2::GLES2Interface* ContextGL() const;
- void DeleteResourceInternal(ResourceMap::iterator it);
- GLenum BindForSampling(ResourceId resource_id, GLenum unit, GLenum filter);
- void WaitSyncTokenInternal(ChildResource* resource);
-
- const raw_ptr<ContextProvider> compositor_context_provider_;
- const bool enable_shared_images_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_GL_H_
diff --git a/chromium/components/viz/service/display/display_resource_provider_gl_unittest.cc b/chromium/components/viz/service/display/display_resource_provider_gl_unittest.cc
deleted file mode 100644
index 1c2d058d1a3..00000000000
--- a/chromium/components/viz/service/display/display_resource_provider_gl_unittest.cc
+++ /dev/null
@@ -1,718 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/display_resource_provider_gl.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/check.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
-#include "components/viz/client/client_resource_provider.h"
-#include "components/viz/common/resources/release_callback.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "components/viz/common/resources/returned_resource.h"
-#include "components/viz/test/test_context_provider.h"
-#include "components/viz/test/test_gles2_interface.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-#include "ui/gfx/geometry/rect.h"
-
-using testing::_;
-using testing::ByMove;
-using testing::DoAll;
-using testing::Return;
-using testing::SaveArg;
-
-namespace viz {
-namespace {
-
-class MockReleaseCallback {
- public:
- MOCK_METHOD2(Released, void(const gpu::SyncToken& token, bool lost));
-};
-
-MATCHER_P(MatchesSyncToken, sync_token, "") {
- gpu::SyncToken other;
- memcpy(&other, arg, sizeof(other));
- return other == sync_token;
-}
-
-static void CollectResources(std::vector<ReturnedResource>* array,
- std::vector<ReturnedResource> returned) {
- array->insert(array->end(), std::make_move_iterator(returned.begin()),
- std::make_move_iterator(returned.end()));
-}
-
-class ResourceProviderGLES2Interface : public TestGLES2Interface {
- public:
- ResourceProviderGLES2Interface() = default;
-
- void WaitSyncTokenCHROMIUM(const GLbyte* sync_token) override {
- gpu::SyncToken sync_token_data;
- if (sync_token)
- memcpy(&sync_token_data, sync_token, sizeof(sync_token_data));
-
- if (sync_token_data.release_count() >
- last_waited_sync_token_.release_count()) {
- last_waited_sync_token_ = sync_token_data;
- }
- }
-
- const gpu::SyncToken& last_waited_sync_token() const {
- return last_waited_sync_token_;
- }
-
- private:
- gpu::SyncToken last_waited_sync_token_;
-};
-
-class DisplayResourceProviderGLTest : public testing::Test {
- public:
- DisplayResourceProviderGLTest() {
- auto gl_owned = std::make_unique<ResourceProviderGLES2Interface>();
- gl_ = gl_owned.get();
- context_provider_ = TestContextProvider::Create(std::move(gl_owned));
- context_provider_->UnboundTestContextGL()
- ->set_support_texture_format_bgra8888(true);
- context_provider_->BindToCurrentThread();
-
- child_context_provider_ = TestContextProvider::Create();
- child_context_provider_->UnboundTestContextGL()
- ->set_support_texture_format_bgra8888(true);
- child_context_provider_->BindToCurrentThread();
-
- resource_provider_ =
- std::make_unique<DisplayResourceProviderGL>(context_provider_.get());
-
- child_resource_provider_ = std::make_unique<ClientResourceProvider>();
- }
-
- ~DisplayResourceProviderGLTest() override {
- child_resource_provider_->ShutdownAndReleaseAllResources();
- }
-
- static ReturnCallback GetReturnCallback(
- std::vector<ReturnedResource>* array) {
- return base::BindRepeating(&CollectResources, array);
- }
-
- static void SetResourceFilter(DisplayResourceProviderGL* resource_provider,
- ResourceId id,
- GLenum filter) {
- DisplayResourceProviderGL::ScopedSamplerGL sampler(resource_provider, id,
- GL_TEXTURE_2D, filter);
- }
-
- TransferableResource CreateResource(ResourceFormat format) {
- constexpr gfx::Size size(64, 64);
- gpu::Mailbox gpu_mailbox = gpu::Mailbox::Generate();
- gpu::SyncToken sync_token = GenSyncToken();
- EXPECT_TRUE(sync_token.HasData());
-
- TransferableResource gl_resource = TransferableResource::MakeGL(
- gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token, size,
- false /* is_overlay_candidate */);
- gl_resource.format = format;
- return gl_resource;
- }
-
- ResourceId MakeGpuResourceAndSendToDisplay(
- GLuint filter,
- GLuint target,
- const gpu::SyncToken& sync_token,
- DisplayResourceProvider* resource_provider) {
- ReturnCallback return_callback = base::DoNothing();
-
- int child = resource_provider->CreateChild(return_callback, SurfaceId());
-
- gpu::Mailbox gpu_mailbox = gpu::Mailbox::Generate();
- constexpr gfx::Size size(64, 64);
- auto resource =
- TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR, target, sync_token,
- size, false /* is_overlay_candidate */);
- resource.id = ResourceId(11);
- resource_provider->ReceiveFromChild(child, {resource});
- auto& map = resource_provider->GetChildToParentMap(child);
- return map.find(resource.id)->second;
- }
-
- gpu::SyncToken GenSyncToken() {
- gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x123),
- next_fence_sync_++);
- sync_token.SetVerifyFlush();
- return sync_token;
- }
-
- protected:
- raw_ptr<ResourceProviderGLES2Interface> gl_ = nullptr;
- uint64_t next_fence_sync_ = 1;
- scoped_refptr<TestContextProvider> context_provider_;
- scoped_refptr<TestContextProvider> child_context_provider_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- std::unique_ptr<ClientResourceProvider> child_resource_provider_;
-};
-
-TEST_F(DisplayResourceProviderGLTest, ReadLockCountStopsReturnToChildOrDelete) {
- MockReleaseCallback release;
- TransferableResource tran = CreateResource(RGBA_8888);
- ResourceId id1 = child_resource_provider_->ImportResource(
- tran, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider_->CreateChild(
- GetReturnCallback(&returned_to_child), SurfaceId());
- {
- // Transfer some resources to the parent.
- std::vector<TransferableResource> list;
- child_resource_provider_->PrepareSendToParent(
- {id1}, &list,
- static_cast<RasterContextProvider*>(child_context_provider_.get()));
- ASSERT_EQ(1u, list.size());
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
-
- resource_provider_->ReceiveFromChild(child_id, list);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider_->GetChildToParentMap(child_id);
- ResourceId mapped_resource_id = resource_map[list[0].id];
- resource_provider_->WaitSyncToken(mapped_resource_id);
- DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(),
- mapped_resource_id);
-
- resource_provider_->DeclareUsedResourcesFromChild(child_id,
- ResourceIdSet());
- EXPECT_EQ(0u, returned_to_child.size());
- }
-
- EXPECT_EQ(1u, returned_to_child.size());
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
-
- // No need to wait for the sync token here -- it will be returned to the
- // client on delete.
- {
- EXPECT_CALL(release, Released(_, _));
- child_resource_provider_->RemoveImportedResource(id1);
- }
-
- resource_provider_->DestroyChild(child_id);
-}
-
-class TestFence : public ResourceFence {
- public:
- TestFence() = default;
-
- // ResourceFence implementation.
- void Set() override {}
- bool HasPassed() override { return passed; }
-
- bool passed = false;
-
- private:
- ~TestFence() override = default;
-};
-
-TEST_F(DisplayResourceProviderGLTest, ReadLockFenceStopsReturnToChildOrDelete) {
- MockReleaseCallback release;
- TransferableResource tran1 = CreateResource(RGBA_8888);
- tran1.read_lock_fences_enabled = true;
- ResourceId id1 = child_resource_provider_->ImportResource(
- tran1, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider_->CreateChild(
- GetReturnCallback(&returned_to_child), SurfaceId());
-
- // Transfer some resources to the parent.
- std::vector<TransferableResource> list;
- child_resource_provider_->PrepareSendToParent(
- {id1}, &list,
- static_cast<RasterContextProvider*>(child_context_provider_.get()));
- ASSERT_EQ(1u, list.size());
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
- EXPECT_TRUE(list[0].read_lock_fences_enabled);
-
- resource_provider_->ReceiveFromChild(child_id, list);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider_->GetChildToParentMap(child_id);
-
- scoped_refptr<TestFence> fence(new TestFence);
- resource_provider_->SetReadLockFence(fence.get());
- {
- ResourceId parent_id = resource_map[list.front().id];
- resource_provider_->WaitSyncToken(parent_id);
- DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(),
- parent_id);
- }
- resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(0u, returned_to_child.size());
-
- resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(0u, returned_to_child.size());
- fence->passed = true;
-
- resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(1u, returned_to_child.size());
-
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
- EXPECT_CALL(release, Released(_, _));
- child_resource_provider_->RemoveImportedResource(id1);
-}
-
-TEST_F(DisplayResourceProviderGLTest, ReadLockFenceDestroyChild) {
- MockReleaseCallback release;
-
- TransferableResource tran1 = CreateResource(RGBA_8888);
- tran1.read_lock_fences_enabled = true;
- ResourceId id1 = child_resource_provider_->ImportResource(
- tran1, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
-
- TransferableResource tran2 = CreateResource(RGBA_8888);
- tran2.read_lock_fences_enabled = false;
- ResourceId id2 = child_resource_provider_->ImportResource(
- tran2, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider_->CreateChild(
- GetReturnCallback(&returned_to_child), SurfaceId());
-
- // Transfer resources to the parent.
- std::vector<TransferableResource> list;
- child_resource_provider_->PrepareSendToParent(
- {id1, id2}, &list,
- static_cast<RasterContextProvider*>(child_context_provider_.get()));
- ASSERT_EQ(2u, list.size());
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
-
- resource_provider_->ReceiveFromChild(child_id, list);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider_->GetChildToParentMap(child_id);
-
- scoped_refptr<TestFence> fence(new TestFence);
- resource_provider_->SetReadLockFence(fence.get());
- {
- for (auto& resource : list) {
- ResourceId parent_id = resource_map[resource.id];
- resource_provider_->WaitSyncToken(parent_id);
- DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider_.get(),
- parent_id);
- }
- }
- EXPECT_EQ(0u, returned_to_child.size());
-
- EXPECT_EQ(2u, resource_provider_->num_resources());
-
- resource_provider_->DestroyChild(child_id);
-
- EXPECT_EQ(0u, resource_provider_->num_resources());
- EXPECT_EQ(2u, returned_to_child.size());
-
- // id1 should be lost and id2 should not.
- EXPECT_EQ(returned_to_child[0].lost, returned_to_child[0].id == id1);
- EXPECT_EQ(returned_to_child[1].lost, returned_to_child[1].id == id1);
-
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
- EXPECT_CALL(release, Released(_, _)).Times(2);
- child_resource_provider_->RemoveImportedResource(id1);
- child_resource_provider_->RemoveImportedResource(id2);
-}
-
-// Test that ScopedBatchReturnResources batching works.
-TEST_F(DisplayResourceProviderGLTest,
- ScopedBatchReturnResourcesPreventsReturn) {
- MockReleaseCallback release;
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider_->CreateChild(
- GetReturnCallback(&returned_to_child), SurfaceId());
-
- // Transfer some resources to the parent.
- constexpr size_t kTotalResources = 5;
- constexpr size_t kLockedResources = 3;
- constexpr size_t kUsedResources = 4;
- ResourceId ids[kTotalResources];
- for (auto& id : ids) {
- TransferableResource tran = CreateResource(RGBA_8888);
- id = child_resource_provider_->ImportResource(
- tran, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
- }
- std::vector<ResourceId> resource_ids_to_transfer(ids, ids + kTotalResources);
-
- std::vector<TransferableResource> list;
- child_resource_provider_->PrepareSendToParent(
- resource_ids_to_transfer, &list,
- static_cast<RasterContextProvider*>(child_context_provider_.get()));
- ASSERT_EQ(kTotalResources, list.size());
- for (const auto& id : ids)
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
-
- resource_provider_->ReceiveFromChild(child_id, list);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider_->GetChildToParentMap(child_id);
- std::vector<std::unique_ptr<DisplayResourceProviderGL::ScopedReadLockGL>>
- read_locks;
- for (size_t i = 0; i < kLockedResources; i++) {
- ResourceId mapped_resource_id = resource_map[ids[i]];
- resource_provider_->WaitSyncToken(mapped_resource_id);
- read_locks.push_back(
- std::make_unique<DisplayResourceProviderGL::ScopedReadLockGL>(
- resource_provider_.get(), mapped_resource_id));
- }
-
- // Mark all locked resources, and one unlocked resource as used for first
- // batch.
- {
- DisplayResourceProviderGL::ScopedBatchReturnResources returner(
- resource_provider_.get());
- resource_provider_->DeclareUsedResourcesFromChild(
- child_id, ResourceIdSet(ids, ids + kUsedResources));
- EXPECT_EQ(0u, returned_to_child.size());
- }
- EXPECT_EQ(1u, returned_to_child.size());
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
- returned_to_child.clear();
-
- // Return all locked resources.
- {
- DisplayResourceProviderGL::ScopedBatchReturnResources returner(
- resource_provider_.get());
- resource_provider_->DeclareUsedResourcesFromChild(
- child_id, ResourceIdSet(ids + kLockedResources, ids + kUsedResources));
- // Can be called multiple times while batching is enabled. This happens in
- // practice when the same surface is visited using different paths during
- // surface aggregation.
- resource_provider_->DeclareUsedResourcesFromChild(
- child_id, ResourceIdSet(ids + kLockedResources, ids + kUsedResources));
- read_locks.clear();
- EXPECT_EQ(0u, returned_to_child.size());
- }
- EXPECT_EQ(kLockedResources, returned_to_child.size());
- // Returned resources that were locked share the same sync token.
- for (const auto& resource : returned_to_child)
- EXPECT_EQ(resource.sync_token, returned_to_child[0].sync_token);
-
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
- returned_to_child.clear();
-
- // Returns from destroying the child is also batched.
- {
- DisplayResourceProviderGL::ScopedBatchReturnResources returner(
- resource_provider_.get());
- resource_provider_->DestroyChild(child_id);
- EXPECT_EQ(0u, returned_to_child.size());
- }
- EXPECT_EQ(1u, returned_to_child.size());
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
- returned_to_child.clear();
-
- EXPECT_CALL(release, Released(_, _)).Times(kTotalResources);
- for (const auto& id : ids)
- child_resource_provider_->RemoveImportedResource(id);
-}
-
-class TextureStateTrackingGLES2Interface : public TestGLES2Interface {
- public:
- MOCK_METHOD2(BindTexture, void(GLenum target, GLuint texture));
- MOCK_METHOD3(TexParameteri, void(GLenum target, GLenum pname, GLint param));
- MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token));
- MOCK_METHOD1(CreateAndConsumeTextureCHROMIUM,
- unsigned(const GLbyte* mailbox));
-
- // Force all textures to be consecutive numbers starting at "1",
- // so we easily can test for them.
- GLuint NextTextureId() override { return next_texture_id_++; }
-
- void RetireTextureId(GLuint) override {}
-};
-
-class ResourceProviderTestImportedResourceGLFilters {
- public:
- static void RunTest(bool mailbox_nearest_neighbor, GLenum sampler_filter) {
- auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
- TextureStateTrackingGLES2Interface* gl = gl_owned.get();
- auto context_provider = TestContextProvider::Create(std::move(gl_owned));
- context_provider->BindToCurrentThread();
-
- auto resource_provider =
- std::make_unique<DisplayResourceProviderGL>(context_provider.get());
-
- auto child_gl_owned =
- std::make_unique<TextureStateTrackingGLES2Interface>();
- TextureStateTrackingGLES2Interface* child_gl = child_gl_owned.get();
- auto child_context_provider =
- TestContextProvider::Create(std::move(child_gl_owned));
- child_context_provider->BindToCurrentThread();
-
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- unsigned texture_id = 1;
- gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x12),
- 0x34);
-
- EXPECT_CALL(*child_gl, BindTexture(_, _)).Times(0);
- EXPECT_CALL(*child_gl, WaitSyncTokenCHROMIUM(_)).Times(0);
- EXPECT_CALL(*child_gl, CreateAndConsumeTextureCHROMIUM(_)).Times(0);
-
- gpu::Mailbox gpu_mailbox = gpu::Mailbox::Generate();
- GLuint filter = mailbox_nearest_neighbor ? GL_NEAREST : GL_LINEAR;
- constexpr gfx::Size size(64, 64);
- auto resource = TransferableResource::MakeGL(
- gpu_mailbox, filter, GL_TEXTURE_2D, sync_token, size,
- false /* is_overlay_candidate */);
-
- MockReleaseCallback release;
- ResourceId resource_id = child_resource_provider->ImportResource(
- resource, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
- EXPECT_NE(kInvalidResourceId, resource_id);
-
- testing::Mock::VerifyAndClearExpectations(child_gl);
-
- // Transfer resources to the parent.
- std::vector<TransferableResource> send_to_parent;
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider->CreateChild(
- base::BindRepeating(&CollectResources, &returned_to_child),
- SurfaceId());
- child_resource_provider->PrepareSendToParent(
- {resource_id}, &send_to_parent,
- static_cast<RasterContextProvider*>(child_context_provider.get()));
- resource_provider->ReceiveFromChild(child_id, send_to_parent);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider->GetChildToParentMap(child_id);
- ResourceId mapped_resource_id = resource_map[resource_id];
- {
- // The verified flush flag will be set by
- // ClientResourceProvider::PrepareSendToParent. Before checking if
- // the gpu::SyncToken matches, set this flag first.
- sync_token.SetVerifyFlush();
-
- // Mailbox sync point WaitSyncToken before using the texture.
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(MatchesSyncToken(sync_token)));
- resource_provider->WaitSyncToken(mapped_resource_id);
- testing::Mock::VerifyAndClearExpectations(gl);
-
- EXPECT_CALL(*gl, CreateAndConsumeTextureCHROMIUM(_))
- .WillOnce(Return(texture_id));
- EXPECT_CALL(*gl, BindTexture(GL_TEXTURE_2D, texture_id));
-
- // The sampler will reset these if |mailbox_nearest_neighbor| does not
- // match |sampler_filter|.
- if (mailbox_nearest_neighbor != (sampler_filter == GL_NEAREST)) {
- EXPECT_CALL(*gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- sampler_filter));
- EXPECT_CALL(*gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
- sampler_filter));
- }
-
- DisplayResourceProviderGL::ScopedSamplerGL lock(
- resource_provider.get(), mapped_resource_id, sampler_filter);
- testing::Mock::VerifyAndClearExpectations(gl);
-
- // When done with it, a sync point should be inserted, but no produce is
- // necessary.
- EXPECT_CALL(*child_gl, WaitSyncTokenCHROMIUM(_)).Times(0);
- EXPECT_CALL(*child_gl, CreateAndConsumeTextureCHROMIUM(_)).Times(0);
- }
-
- EXPECT_EQ(0u, returned_to_child.size());
- // Transfer resources back from the parent to the child. Set no resources as
- // being in use.
- resource_provider->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(1u, returned_to_child.size());
- child_resource_provider->ReceiveReturnsFromParent(
- std::move(returned_to_child));
-
- gpu::SyncToken released_sync_token;
- {
- EXPECT_CALL(release, Released(_, false))
- .WillOnce(SaveArg<0>(&released_sync_token));
- child_resource_provider->RemoveImportedResource(resource_id);
- }
- EXPECT_TRUE(released_sync_token.HasData());
- }
-};
-
-TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_LinearToLinear) {
- ResourceProviderTestImportedResourceGLFilters::RunTest(false, GL_LINEAR);
-}
-
-TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_NearestToNearest) {
- ResourceProviderTestImportedResourceGLFilters::RunTest(true, GL_NEAREST);
-}
-
-TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_NearestToLinear) {
- ResourceProviderTestImportedResourceGLFilters::RunTest(true, GL_LINEAR);
-}
-
-TEST_F(DisplayResourceProviderGLTest, ReceiveGLTexture2D_LinearToNearest) {
- ResourceProviderTestImportedResourceGLFilters::RunTest(false, GL_NEAREST);
-}
-
-TEST_F(DisplayResourceProviderGLTest, ReceiveGLTextureExternalOES) {
- auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
- TextureStateTrackingGLES2Interface* gl = gl_owned.get();
- auto context_provider = TestContextProvider::Create(std::move(gl_owned));
- context_provider->BindToCurrentThread();
-
- auto resource_provider =
- std::make_unique<DisplayResourceProviderGL>(context_provider.get());
-
- auto child_gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
- TextureStateTrackingGLES2Interface* child_gl = child_gl_owned.get();
- auto child_context_provider =
- TestContextProvider::Create(std::move(child_gl_owned));
- child_context_provider->BindToCurrentThread();
-
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34);
-
- EXPECT_CALL(*child_gl, BindTexture(_, _)).Times(0);
- EXPECT_CALL(*child_gl, WaitSyncTokenCHROMIUM(_)).Times(0);
- EXPECT_CALL(*child_gl, CreateAndConsumeTextureCHROMIUM(_)).Times(0);
-
- gpu::Mailbox gpu_mailbox = gpu::Mailbox::Generate();
- ReleaseCallback callback = base::DoNothing();
-
- constexpr gfx::Size size(64, 64);
- auto resource = TransferableResource::MakeGL(
- gpu_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, sync_token, size,
- false /* is_overlay_candidate */);
-
- ResourceId resource_id =
- child_resource_provider->ImportResource(resource, std::move(callback));
- EXPECT_NE(kInvalidResourceId, resource_id);
-
- testing::Mock::VerifyAndClearExpectations(child_gl);
-
- // Transfer resources to the parent.
- std::vector<TransferableResource> send_to_parent;
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider->CreateChild(
- base::BindRepeating(&CollectResources, &returned_to_child), SurfaceId());
- child_resource_provider->PrepareSendToParent(
- {resource_id}, &send_to_parent,
- static_cast<RasterContextProvider*>(child_context_provider_.get()));
- resource_provider->ReceiveFromChild(child_id, send_to_parent);
-
- // Before create DrawQuad in DisplayResourceProvider's namespace, get the
- // mapped resource id first.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider->GetChildToParentMap(child_id);
- ResourceId mapped_resource_id = resource_map[resource_id];
- {
- // The verified flush flag will be set by
- // ClientResourceProvider::PrepareSendToParent. Before checking if
- // the gpu::SyncToken matches, set this flag first.
- sync_token.SetVerifyFlush();
-
- // Mailbox sync point WaitSyncToken before using the texture.
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(MatchesSyncToken(sync_token)));
- resource_provider->WaitSyncToken(mapped_resource_id);
- testing::Mock::VerifyAndClearExpectations(gl);
-
- unsigned texture_id = 1;
-
- EXPECT_CALL(*gl, CreateAndConsumeTextureCHROMIUM(_))
- .WillOnce(Return(texture_id));
-
- DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider.get(),
- mapped_resource_id);
- testing::Mock::VerifyAndClearExpectations(gl);
-
- // When done with it, a sync point should be inserted, but no produce is
- // necessary.
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(0);
- EXPECT_CALL(*gl, CreateAndConsumeTextureCHROMIUM(_)).Times(0);
- testing::Mock::VerifyAndClearExpectations(gl);
- }
- EXPECT_EQ(0u, returned_to_child.size());
- // Transfer resources back from the parent to the child. Set no resources as
- // being in use.
- resource_provider->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(1u, returned_to_child.size());
- child_resource_provider->ReceiveReturnsFromParent(
- std::move(returned_to_child));
-
- child_resource_provider->RemoveImportedResource(resource_id);
-}
-
-TEST_F(DisplayResourceProviderGLTest, WaitSyncTokenIfNeeded) {
- auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
- TextureStateTrackingGLES2Interface* gl = gl_owned.get();
- auto context_provider = TestContextProvider::Create(std::move(gl_owned));
- context_provider->BindToCurrentThread();
-
- auto resource_provider =
- std::make_unique<DisplayResourceProviderGL>(context_provider.get());
-
- EXPECT_CALL(*gl, BindTexture(_, _)).Times(0);
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(0);
- EXPECT_CALL(*gl, CreateAndConsumeTextureCHROMIUM(_)).Times(0);
-
- gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34);
- ResourceId id_with_sync = MakeGpuResourceAndSendToDisplay(
- GL_LINEAR, GL_TEXTURE_2D, sync_token, resource_provider.get());
- ResourceId id_without_sync = MakeGpuResourceAndSendToDisplay(
- GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(), resource_provider.get());
-
- // First call to WaitSyncToken should call WaitSyncToken, but only if a
- // SyncToken was present.
- {
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(MatchesSyncToken(sync_token)))
- .Times(1);
- resource_provider->WaitSyncToken(id_with_sync);
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(0);
- resource_provider->WaitSyncToken(id_without_sync);
- }
-
- {
- // Subsequent calls to WaitSyncToken shouldn't call WaitSyncToken.
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(0);
- resource_provider->WaitSyncToken(id_with_sync);
- resource_provider->WaitSyncToken(id_without_sync);
- }
-}
-
-} // namespace
-} // namespace viz
diff --git a/chromium/components/viz/service/display/display_resource_provider_skia.cc b/chromium/components/viz/service/display/display_resource_provider_skia.cc
index 3d4b0e51011..6e4ea305a8c 100644
--- a/chromium/components/viz/service/display/display_resource_provider_skia.cc
+++ b/chromium/components/viz/service/display/display_resource_provider_skia.cc
@@ -84,6 +84,13 @@ DisplayResourceProviderSkia::DeleteAndReturnUnusedResourcesToChildImpl(
continue;
}
+ if (resource.transferable.synchronization_type ==
+ TransferableResource::SynchronizationType::kReleaseFence) {
+ // The resource might have never been used.
+ if (resource.resource_fence)
+ resource.release_fence = resource.resource_fence->GetGpuFenceHandle();
+ }
+
const bool is_lost = can_delete == CanDeleteNowResult::kYesButLoseResource;
to_return.emplace_back(child_id, resource.sync_token(),
@@ -130,7 +137,7 @@ DisplayResourceProviderSkia::LockSetForExternalUse::LockResource(
ResourceId id,
bool maybe_concurrent_reads,
bool is_video_plane,
- const absl::optional<gfx::ColorSpace>& override_color_space,
+ sk_sp<SkColorSpace> override_color_space,
bool raw_draw_is_possible) {
auto it = resource_provider_->resources_.find(id);
DCHECK(it != resource_provider_->resources_.end());
@@ -154,8 +161,9 @@ DisplayResourceProviderSkia::LockSetForExternalUse::LockResource(
// is very subtle.
image_color_space =
override_color_space
- .value_or(resource.transferable.color_space.GetAsFullRangeRGB())
- .ToSkColorSpace();
+ ? override_color_space
+ : resource.transferable.color_space.GetAsFullRangeRGB()
+ .ToSkColorSpace();
}
resource.image_context =
resource_provider_->external_use_client_->CreateImageContext(
@@ -166,11 +174,20 @@ DisplayResourceProviderSkia::LockSetForExternalUse::LockResource(
}
resource.locked_for_external_use = true;
- if (resource.transferable.read_lock_fences_enabled) {
- if (resource_provider_->current_read_lock_fence_.get())
- resource_provider_->current_read_lock_fence_->Set();
- resource.read_lock_fence = resource_provider_->current_read_lock_fence_;
+ switch (resource.transferable.synchronization_type) {
+ case TransferableResource::SynchronizationType::kGpuCommandsCompleted:
+ resource.resource_fence =
+ resource_provider_->current_gpu_commands_completed_fence_;
+ break;
+ case TransferableResource::SynchronizationType::kReleaseFence:
+ resource.resource_fence = resource_provider_->current_release_fence_;
+ break;
+ default:
+ break;
}
+
+ if (resource.resource_fence)
+ resource.resource_fence->Set();
}
DCHECK(base::Contains(resources_, std::make_pair(id, &resource)));
diff --git a/chromium/components/viz/service/display/display_resource_provider_skia.h b/chromium/components/viz/service/display/display_resource_provider_skia.h
index 32982471449..6fc3b4385cf 100644
--- a/chromium/components/viz/service/display/display_resource_provider_skia.h
+++ b/chromium/components/viz/service/display/display_resource_provider_skia.h
@@ -51,15 +51,14 @@ class VIZ_SERVICE_EXPORT DisplayResourceProviderSkia
// Lock a resource for external use. The return value was created by
// |client| at some point in the past. The SkImage color space will be set
- // to |color_space| if valid, otherwise it will be set to the resource's
- // color space. If |is_video_plane| is true, the image color space will be
- // set to nullptr (to avoid LOG spam).
+ // to |override_color_space| if non-nullptr, otherwise it will be set to the
+ // resource's color space. If |is_video_plane| is true, the image color
+ // space will be set to nullptr (to avoid LOG spam).
ExternalUseClient::ImageContext* LockResource(
ResourceId resource_id,
bool maybe_concurrent_reads,
bool is_video_plane,
- const absl::optional<gfx::ColorSpace>& override_color_space =
- absl::nullopt,
+ sk_sp<SkColorSpace> override_color_space = nullptr,
bool raw_draw_if_possible = false);
// Unlock all locked resources with a |sync_token|. The |sync_token| should
diff --git a/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc b/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc
index 35ac8f1b95b..878db989dd3 100644
--- a/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc
+++ b/chromium/components/viz/service/display/display_resource_provider_skia_unittest.cc
@@ -17,10 +17,12 @@
#include "base/callback_helpers.h"
#include "base/check.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/resources/release_callback.h"
#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/test/test_context_provider.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -29,6 +31,7 @@
#include "third_party/khronos/GLES2/gl2ext.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gpu_fence_handle.h"
using testing::_;
using testing::ByMove;
@@ -296,134 +299,218 @@ TEST_F(DisplayResourceProviderSkiaTest, LockForExternalUseWebView) {
child_resource_provider_->RemoveImportedResource(id1);
}
-class TestFence : public ResourceFence {
+class TestGpuCommandsCompletedFence : public ResourceFence {
public:
- TestFence() = default;
+ TestGpuCommandsCompletedFence() = default;
// ResourceFence implementation.
void Set() override {}
bool HasPassed() override { return passed; }
+ gfx::GpuFenceHandle GetGpuFenceHandle() override {
+ NOTREACHED();
+ return gfx::GpuFenceHandle();
+ }
bool passed = false;
private:
- ~TestFence() override = default;
+ ~TestGpuCommandsCompletedFence() override = default;
};
-TEST_F(DisplayResourceProviderSkiaTest,
- ReadLockFenceStopsReturnToChildOrDelete) {
- MockReleaseCallback release;
- TransferableResource tran1 = CreateResource(RGBA_8888);
- tran1.read_lock_fences_enabled = true;
- ResourceId id1 = child_resource_provider_->ImportResource(
- tran1, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider_->CreateChild(
- GetReturnCallback(&returned_to_child), SurfaceId());
-
- // Transfer some resources to the parent.
- std::vector<TransferableResource> list;
- child_resource_provider_->PrepareSendToParent(
- {id1}, &list,
- static_cast<RasterContextProvider*>(child_context_provider_.get()));
- ASSERT_EQ(1u, list.size());
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
- EXPECT_TRUE(list[0].read_lock_fences_enabled);
-
- resource_provider_->ReceiveFromChild(child_id, list);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider_->GetChildToParentMap(child_id);
+class TestReleaseFence : public ResourceFence {
+ public:
+ TestReleaseFence() = default;
- scoped_refptr<TestFence> fence(new TestFence);
- resource_provider_->SetReadLockFence(fence.get());
- {
- ResourceId parent_id = resource_map[list.front().id];
- lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true,
- /*is_video_plane=*/false);
- lock_set_->UnlockResources(GenSyncToken());
+ // ResourceFence implementation.
+ void Set() override {}
+ bool HasPassed() override { return release_fence_.has_value(); }
+ gfx::GpuFenceHandle GetGpuFenceHandle() override {
+ return HasPassed() ? release_fence_->Clone() : gfx::GpuFenceHandle();
}
- resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(0u, returned_to_child.size());
- resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(0u, returned_to_child.size());
- fence->passed = true;
+ void SetReleaseFence(gfx::GpuFenceHandle release_fence) {
+ release_fence_ = std::move(release_fence);
+ }
- resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
- EXPECT_EQ(1u, returned_to_child.size());
+ private:
+ ~TestReleaseFence() override = default;
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
- EXPECT_CALL(release, Released(_, _));
- child_resource_provider_->RemoveImportedResource(id1);
-}
+ absl::optional<gfx::GpuFenceHandle> release_fence_;
+};
-TEST_F(DisplayResourceProviderSkiaTest, ReadLockFenceDestroyChild) {
- MockReleaseCallback release;
+TEST_F(DisplayResourceProviderSkiaTest,
+ ResourceFenceStopsReturnToChildOrDelete) {
+ const std::vector<TransferableResource::SynchronizationType>
+ kSynchronizationTypes = {
+ TransferableResource::SynchronizationType::kGpuCommandsCompleted,
+ TransferableResource::SynchronizationType::kReleaseFence};
+ for (auto sync_type : kSynchronizationTypes) {
+ MockReleaseCallback release;
+ TransferableResource tran1 = CreateResource(RGBA_8888);
+ tran1.synchronization_type = sync_type;
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ tran1, base::BindOnce(&MockReleaseCallback::Released,
+ base::Unretained(&release)));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id = resource_provider_->CreateChild(
+ GetReturnCallback(&returned_to_child), SurfaceId());
+
+ // Transfer some resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent(
+ {id1}, &list,
+ static_cast<RasterContextProvider*>(child_context_provider_.get()));
+ ASSERT_EQ(1u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ EXPECT_EQ(list[0].synchronization_type, sync_type);
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ scoped_refptr<ResourceFence> fence;
+ TestGpuCommandsCompletedFence* gpu_commands_completed_fence = nullptr;
+ TestReleaseFence* release_fence = nullptr;
+ if (sync_type ==
+ TransferableResource::SynchronizationType::kGpuCommandsCompleted) {
+ fence = base::MakeRefCounted<TestGpuCommandsCompletedFence>();
+ gpu_commands_completed_fence =
+ static_cast<TestGpuCommandsCompletedFence*>(fence.get());
+ resource_provider_->SetGpuCommandsCompletedFence(fence.get());
+ } else {
+ ASSERT_EQ(TransferableResource::SynchronizationType::kReleaseFence,
+ sync_type);
+ fence = base::MakeRefCounted<TestReleaseFence>();
+ release_fence = static_cast<TestReleaseFence*>(fence.get());
+ resource_provider_->SetReleaseFence(fence.get());
+ }
- TransferableResource tran1 = CreateResource(RGBA_8888);
- tran1.read_lock_fences_enabled = true;
- ResourceId id1 = child_resource_provider_->ImportResource(
- tran1, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
+ {
+ ResourceId parent_id = resource_map[list.front().id];
+ lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true,
+ /*is_video_plane=*/false);
+ lock_set_->UnlockResources(GenSyncToken());
+ }
- TransferableResource tran2 = CreateResource(RGBA_8888);
- tran2.read_lock_fences_enabled = false;
- ResourceId id2 = child_resource_provider_->ImportResource(
- tran2, base::BindOnce(&MockReleaseCallback::Released,
- base::Unretained(&release)));
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ ResourceIdSet());
+ EXPECT_EQ(0u, returned_to_child.size());
- std::vector<ReturnedResource> returned_to_child;
- int child_id = resource_provider_->CreateChild(
- GetReturnCallback(&returned_to_child), SurfaceId());
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ ResourceIdSet());
+ EXPECT_EQ(0u, returned_to_child.size());
- // Transfer resources to the parent.
- std::vector<TransferableResource> list;
- child_resource_provider_->PrepareSendToParent(
- {id1, id2}, &list,
- static_cast<RasterContextProvider*>(child_context_provider_.get()));
- ASSERT_EQ(2u, list.size());
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
- EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+ if (gpu_commands_completed_fence) {
+ gpu_commands_completed_fence->passed = true;
+ } else {
+ gfx::GpuFenceHandle fake_handle;
+#if BUILDFLAG(IS_POSIX)
+ const int32_t kFenceFd = dup(1);
+ fake_handle.owned_fd.reset(kFenceFd);
+#endif
+ release_fence->SetReleaseFence(std::move(fake_handle));
+ }
- resource_provider_->ReceiveFromChild(child_id, list);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ ResourceIdSet());
+ EXPECT_EQ(1u, returned_to_child.size());
+
+#if BUILDFLAG(IS_POSIX)
+ if (release_fence)
+ EXPECT_FALSE(returned_to_child.begin()->release_fence.is_null());
+ else
+ EXPECT_TRUE(returned_to_child.begin()->release_fence.is_null());
+#endif
+
+ child_resource_provider_->ReceiveReturnsFromParent(
+ std::move(returned_to_child));
+ EXPECT_CALL(release, Released(_, _));
+ child_resource_provider_->RemoveImportedResource(id1);
+ }
+}
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- resource_provider_->GetChildToParentMap(child_id);
+TEST_F(DisplayResourceProviderSkiaTest, ResourceFenceDestroyChild) {
+ const std::vector<TransferableResource::SynchronizationType>
+ kSynchronizationTypes = {
+ TransferableResource::SynchronizationType::kGpuCommandsCompleted,
+ TransferableResource::SynchronizationType::kReleaseFence};
+ for (auto sync_type : kSynchronizationTypes) {
+ MockReleaseCallback release;
+
+ TransferableResource tran1 = CreateResource(RGBA_8888);
+ tran1.synchronization_type = sync_type;
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ tran1, base::BindOnce(&MockReleaseCallback::Released,
+ base::Unretained(&release)));
+
+ TransferableResource tran2 = CreateResource(RGBA_8888);
+ ASSERT_EQ(tran2.synchronization_type,
+ TransferableResource::SynchronizationType::kSyncToken);
+ ResourceId id2 = child_resource_provider_->ImportResource(
+ tran2, base::BindOnce(&MockReleaseCallback::Released,
+ base::Unretained(&release)));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id = resource_provider_->CreateChild(
+ GetReturnCallback(&returned_to_child), SurfaceId());
+
+ // Transfer resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent(
+ {id1, id2}, &list,
+ static_cast<RasterContextProvider*>(child_context_provider_.get()));
+ ASSERT_EQ(2u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ scoped_refptr<ResourceFence> fence;
+ if (sync_type ==
+ TransferableResource::SynchronizationType::kGpuCommandsCompleted) {
+ fence = base::MakeRefCounted<TestGpuCommandsCompletedFence>();
+ resource_provider_->SetGpuCommandsCompletedFence(fence.get());
+ } else {
+ ASSERT_EQ(TransferableResource::SynchronizationType::kReleaseFence,
+ sync_type);
+ fence = base::MakeRefCounted<TestReleaseFence>();
+ resource_provider_->SetReleaseFence(fence.get());
+ }
- scoped_refptr<TestFence> fence(new TestFence);
- resource_provider_->SetReadLockFence(fence.get());
- {
- for (auto& resource : list) {
- ResourceId parent_id = resource_map[resource.id];
- lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true,
- /*is_video_plane=*/false);
+ {
+ for (auto& resource : list) {
+ ResourceId parent_id = resource_map[resource.id];
+ lock_set_->LockResource(parent_id, /*maybe_concurrent_reads=*/true,
+ /*is_video_plane=*/false);
+ }
+ lock_set_->UnlockResources(GenSyncToken());
}
- lock_set_->UnlockResources(GenSyncToken());
- }
- EXPECT_EQ(0u, returned_to_child.size());
+ EXPECT_EQ(0u, returned_to_child.size());
- EXPECT_EQ(2u, resource_provider_->num_resources());
+ EXPECT_EQ(2u, resource_provider_->num_resources());
- resource_provider_->DestroyChild(child_id);
+ resource_provider_->DestroyChild(child_id);
- EXPECT_EQ(0u, resource_provider_->num_resources());
- EXPECT_EQ(2u, returned_to_child.size());
+ EXPECT_EQ(0u, resource_provider_->num_resources());
+ EXPECT_EQ(2u, returned_to_child.size());
- // id1 should be lost and id2 should not.
- EXPECT_EQ(returned_to_child[0].lost, returned_to_child[0].id == id1);
- EXPECT_EQ(returned_to_child[1].lost, returned_to_child[1].id == id1);
+ // id1 should be lost and id2 should not.
+ EXPECT_EQ(returned_to_child[0].lost, returned_to_child[0].id == id1);
+ EXPECT_EQ(returned_to_child[1].lost, returned_to_child[1].id == id1);
- child_resource_provider_->ReceiveReturnsFromParent(
- std::move(returned_to_child));
- EXPECT_CALL(release, Released(_, _)).Times(2);
- child_resource_provider_->RemoveImportedResource(id1);
- child_resource_provider_->RemoveImportedResource(id2);
+ child_resource_provider_->ReceiveReturnsFromParent(
+ std::move(returned_to_child));
+ EXPECT_CALL(release, Released(_, _)).Times(2);
+ child_resource_provider_->RemoveImportedResource(id1);
+ child_resource_provider_->RemoveImportedResource(id2);
+ }
}
// Test that ScopedBatchReturnResources batching works.
diff --git a/chromium/components/viz/service/display/display_scheduler.cc b/chromium/components/viz/service/display/display_scheduler.cc
index 1139afa955e..b1757695422 100644
--- a/chromium/components/viz/service/display/display_scheduler.cc
+++ b/chromium/components/viz/service/display/display_scheduler.cc
@@ -17,6 +17,23 @@
namespace viz {
+namespace {
+
+base::TimeDelta ComputeAdpfTarget(const BeginFrameArgs& args) {
+ int target_ms = features::kAdpfTargetDurationMs.Get();
+ if (target_ms > 0 && target_ms <= 1000) {
+ return base::Milliseconds(target_ms);
+ }
+ if (args.possible_deadlines) {
+ const auto& deadline = args.possible_deadlines->GetPreferredDeadline();
+ // Arbitrarily use 75% of the deadline for CPU work.
+ return deadline.latch_delta * 3 / 4;
+ }
+ return base::Milliseconds(12);
+}
+
+} // namespace
+
class DisplayScheduler::BeginFrameObserver : public BeginFrameObserverBase {
public:
explicit BeginFrameObserver(DisplayScheduler* scheduler)
@@ -160,12 +177,9 @@ void DisplayScheduler::MaybeCreateHintSession(
if ((!create_session_for_current_thread_ids_failed_ && !hint_session_) ||
current_thread_ids_ != thread_ids) {
hint_session_.reset();
- int target_ms = features::kAdpfTargetDurationMs.Get();
- if (target_ms <= 0 || target_ms > 1000)
- target_ms = 12;
current_thread_ids_ = std::move(thread_ids);
hint_session_ = hint_session_factory_->CreateSession(
- current_thread_ids_, base::Milliseconds(target_ms));
+ current_thread_ids_, ComputeAdpfTarget(current_begin_frame_args_));
create_session_for_current_thread_ids_failed_ = !hint_session_;
}
}
@@ -241,6 +255,9 @@ bool DisplayScheduler::OnBeginFrame(const BeginFrameArgs& args) {
// Schedule the deadline.
current_begin_frame_args_ = save_args;
+ if (hint_session_) {
+ hint_session_->UpdateTargetDuration(ComputeAdpfTarget(save_args));
+ }
base::TimeDelta delta;
if (client_ && dynamic_scheduler_deadlines_percentile_.has_value() &&
diff --git a/chromium/components/viz/service/display/display_scheduler_unittest.cc b/chromium/components/viz/service/display/display_scheduler_unittest.cc
index 041b801f58e..c26548bfae7 100644
--- a/chromium/components/viz/service/display/display_scheduler_unittest.cc
+++ b/chromium/components/viz/service/display/display_scheduler_unittest.cc
@@ -181,7 +181,9 @@ class DisplaySchedulerTest : public testing::Test {
: wait_for_all_surfaces_before_draw_(wait_for_all_surfaces_before_draw),
fake_begin_frame_source_(0.f, false),
task_runner_(new base::NullTaskRunner),
- surface_manager_(nullptr, 4u),
+ surface_manager_(nullptr,
+ /*activation_deadline_in_frames=*/4u,
+ /*max_uncommitted_frames=*/0),
resource_provider_(&shared_bitmap_manager_),
aggregator_(&surface_manager_, &resource_provider_, false, false),
damage_tracker_(
diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc
index df18d96d450..7175b9ef94d 100644
--- a/chromium/components/viz/service/display/display_unittest.cc
+++ b/chromium/components/viz/service/display/display_unittest.cc
@@ -68,7 +68,6 @@
#include "ui/gfx/delegated_ink_point.h"
#include "ui/gfx/mojom/delegated_ink_point_renderer.mojom.h"
#include "ui/gfx/overlay_transform.h"
-#include "ui/gfx/presentation_feedback.h"
using testing::_;
using testing::AnyNumber;
@@ -169,10 +168,11 @@ class DisplayTest : public testing::Test {
~DisplayTest() override {}
void SetUpSoftwareDisplay(const RendererSettings& settings) {
- std::unique_ptr<FakeOutputSurface> output_surface;
+ std::unique_ptr<FakeSoftwareOutputSurface> output_surface;
auto device = std::make_unique<TestSoftwareOutputDevice>();
software_output_device_ = device.get();
- output_surface = FakeOutputSurface::CreateSoftware(std::move(device));
+ output_surface =
+ std::make_unique<FakeSoftwareOutputSurface>(std::move(device));
output_surface_ = output_surface.get();
CreateDisplaySchedulerAndDisplay(settings, kArbitraryFrameSinkId,
@@ -272,7 +272,7 @@ class DisplayTest : public testing::Test {
std::unique_ptr<BeginFrameSource> begin_frame_source_;
std::unique_ptr<Display> display_;
raw_ptr<TestSoftwareOutputDevice> software_output_device_ = nullptr;
- raw_ptr<FakeOutputSurface> output_surface_ = nullptr;
+ raw_ptr<FakeSoftwareOutputSurface> output_surface_ = nullptr;
raw_ptr<FakeSkiaOutputSurface> skia_output_surface_ = nullptr;
raw_ptr<TestDisplayScheduler> scheduler_ = nullptr;
};
@@ -283,7 +283,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
settings.partial_swap_enabled = true;
SetUpSoftwareDisplay(settings);
gfx::ColorSpace color_space_1 = gfx::ColorSpace::CreateXYZD50();
- gfx::ColorSpace color_space_2 = gfx::ColorSpace::CreateSCRGBLinear();
+ gfx::ColorSpace color_space_2 = gfx::ColorSpace::CreateSRGBLinear();
gfx::DisplayColorSpaces color_spaces_1(color_space_1);
gfx::DisplayColorSpaces color_spaces_2(color_space_2);
@@ -862,7 +862,7 @@ TEST_F(DisplayTest, CompositorFrameDamagesCorrectDisplay) {
TestDisplayScheduler* scheduler2 = scheduler_for_display2.get();
auto display2 = CreateDisplay(
settings, kAnotherFrameSinkId, std::move(scheduler_for_display2),
- FakeOutputSurface::CreateSoftware(
+ std::make_unique<FakeSoftwareOutputSurface>(
std::make_unique<TestSoftwareOutputDevice>()));
manager_.RegisterBeginFrameSource(begin_frame_source2.get(),
kAnotherFrameSinkId);
@@ -1055,9 +1055,9 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// DrawQuad, so the size of quad_list remains unchanged after calling
// RemoveOverdrawQuads.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
SharedQuadState* shared_quad_state2 =
frame.render_pass_list.front()->CreateAndAppendSharedQuadState();
@@ -1089,12 +1089,12 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// which cannot be represented by a smaller rect (its visible_rect stays
// the same).
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
// +------+ +------+
@@ -1123,13 +1123,12 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// screen is rect3 - rect1 U rect3 = (25, 100, 50x25), which updates its
// visible_rect accordingly.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(25, 100, 50, 25).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(25, 100, 50, 25),
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
// +--+ +--+
@@ -1159,12 +1158,12 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// cannot be represented by a smaller rect (its visible_rect stays the
// same).
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect7.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect6.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect7,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect6,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
// +----+ +--+
@@ -1190,12 +1189,12 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// after calling RemoveOverdrawQuads. The visible region of |quad2| on
// screen is rect4 (150, 0, 50x50), its visible_rect stays the same.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect4.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect4,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
// +-----++
// | ||
@@ -1223,12 +1222,12 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
// which cannot be represented by a smaller rect (its visible_rect stays the
// same).
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect5.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect5,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
}
@@ -1278,12 +1277,12 @@ TEST_F(DisplayTest, DrawOcclusionWithSingleOverlapBehindDisjointedDrawQuads) {
// third quad is removed from the |quad_list|, leaving the first and second
// (defined by rects[1](150, 0, 150x150); the largest) quads intact.
ASSERT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rects[0].ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rects[1].ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rects[0],
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rects[1],
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
}
@@ -1334,12 +1333,12 @@ TEST_F(DisplayTest, DrawOcclusionWithMultipleOverlapBehindDisjointedDrawQuads) {
// 0, 150x150)) quads, respectively, so both are removed from the
// |quad_list|, leaving the first and and second quads intact.
ASSERT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rects[0].ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rects[1].ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rects[0],
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rects[1],
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
}
@@ -1385,9 +1384,9 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
display_->RemoveOverdrawQuads(&frame);
// |quad2| overlaps |quad1|, so |quad2| is removed from the |quad_list|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
// +-----+
// | +-+ |
@@ -1410,9 +1409,9 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
// |quad2| is hiding behind |quad1|, so |quad2| is removed from the
// |quad_list|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
// +-----+
@@ -1436,9 +1435,9 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
// |quad2| is behind |quad1| and aligns with the edge of |quad1|, so |quad2|
// is removed from the |quad_list|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
// +-----++
@@ -1464,9 +1463,9 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
// |quad2| is covered by |quad 1|, so |quad2| is removed from the
// |quad_list|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -1527,9 +1526,9 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// |quad2| is now covered by |quad|. So the size of |quad_list| is reduced
// by 1.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
{
@@ -1550,9 +1549,9 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// |quad2| is now covered by |quad|. So the size of |quad_list| is reduced
// by 1.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
{
@@ -1575,9 +1574,9 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// |quad2| is now covered by |quad1|. So the size of |quad_list| is reduced
// by 1.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
{
@@ -1591,9 +1590,9 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// The compositor frame contains only one quad, so |quad_list| remains 1
// after calling RemoveOverdrawQuads.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
{
@@ -1618,12 +1617,12 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// Since visible region of |rect5| is not a rect, quad2::visible_rect stays
// the same.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect5.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(4)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect5,
+ frame.render_pass_list.front()->quad_list.ElementAt(4)->visible_rect);
}
{
@@ -1646,13 +1645,12 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// Since visible region of |rect5| is (12, 50, 25x12), quad2::visible_rect
// updates accordingly.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(12, 50, 25, 12).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(4)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(12, 50, 25, 12),
+ frame.render_pass_list.front()->quad_list.ElementAt(4)->visible_rect);
}
{
@@ -1675,12 +1673,12 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// Since visible region of |rect7| is not a rect, quad2::visible_rect stays
// the same.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect7.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(4)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect7,
+ frame.render_pass_list.front()->quad_list.ElementAt(4)->visible_rect);
}
{
@@ -1703,12 +1701,12 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// Since visible region of |rect8| is not a rect, quad2::visible_rect stays
// the same.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect8.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(4)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect8,
+ frame.render_pass_list.front()->quad_list.ElementAt(4)->visible_rect);
}
{
@@ -1731,12 +1729,12 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// Since visible region of |rect9| is not a rect, quad2::visible_rect stays
// the same
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect10.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect9.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(4)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect10,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect9,
+ frame.render_pass_list.front()->quad_list.ElementAt(4)->visible_rect);
}
}
@@ -1786,12 +1784,12 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
// draw occlusion algorithm.
EXPECT_FALSE(zero_scale.GetInverse(&inverted));
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -1816,12 +1814,12 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
epsilon_scale, rect)
.IsEmpty());
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -1843,9 +1841,9 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
// occlusion rect, so |quad2| is removed.
EXPECT_TRUE(larger_epsilon_scale.GetInverse(&inverted));
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -1894,12 +1892,12 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
// |
// |
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -1926,12 +1924,12 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
// | |
// |----+
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -1958,9 +1956,9 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
// |
// |
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -2012,12 +2010,12 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
// transform) and |quad2| becomes (75, 75 10x10). So |quad2| does not
// intersect with |quad|. No changes in quads.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -2036,9 +2034,9 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
// (53, 75 8x10) (after applying rotation transform). So |quad2| is behind
// |quad|. |quad2| is removed from |quad_list|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
{
@@ -2058,12 +2056,12 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
// transform) and |quad2| becomes (50, 50, 25x100). So |quad2| does not
// intersect with |quad|. No changes in quads.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
}
{
@@ -2084,12 +2082,12 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
// does not cover |rect3| initially, |quad| does not cover |quad2| in target
// space.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
}
}
@@ -2137,12 +2135,12 @@ TEST_F(DisplayTest, CompositorFrameWithPerspective) {
// long to define a enclosed rect to describe the occlusion region,
// occlusion region is not defined and no changes in quads.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -2161,9 +2159,9 @@ TEST_F(DisplayTest, CompositorFrameWithPerspective) {
// an enclosing rect to describe |quad2|. |quad2| is hiding behind |quad|,
// so it's removed from |quad_list|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -2204,12 +2202,12 @@ TEST_F(DisplayTest, CompositorFrameWithOpacityChange) {
// Since the opacity of |rect2| is less than 1, |rect1| cannot occlude
// |rect2| even though |rect2| is inside |rect1|.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -2225,9 +2223,9 @@ TEST_F(DisplayTest, CompositorFrameWithOpacityChange) {
display_->RemoveOverdrawQuads(&frame);
// Repeat the above test and set the opacity of |rect1| to 1.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -2267,12 +2265,12 @@ TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) {
// Since the opaqueness of |rect2| is false, |rect1| cannot occlude
// |rect2| even though |rect2| is inside |rect1|.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -2288,9 +2286,9 @@ TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) {
display_->RemoveOverdrawQuads(&frame);
// Repeat the above test and set the opaqueness of |rect2| to true.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -2338,12 +2336,10 @@ TEST_F(DisplayTest, CompositorFrameZTranslate) {
// Since both |quad| and |quad2| are inside of a 3d object, DrawOcclusion
// will not be applied to them.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->rect.ToString());
+ EXPECT_EQ(rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->rect);
+ EXPECT_EQ(rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->rect);
}
}
@@ -2394,12 +2390,12 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
// |rect2| and |rect1| are disjoined as show in the first image. The size of
// |quad_list| remains 2.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -2424,9 +2420,9 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
// translation transform. |quad2| will be covered by |quad|, so |quad_list|
// size is reduced by 1.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
{
@@ -2455,13 +2451,12 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
// |quad2| is (100, 100, 100x20). So the visible region of |quad2| is
// (150, 100, 50x20).
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(150, 100, 50, 20).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(150, 100, 50, 20),
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
}
}
@@ -2521,12 +2516,12 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
// |rect2|. |rect3| is covered by both |rect1| and |rect2|, so |rect3| is
// removed from |quad_list|.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
{
@@ -2548,16 +2543,15 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
// and |rect2|, is (0, 0, 160x60). Since visible region of rect 4 is
// (160, 10, 30x30), |visible_rect| of |quad3| is updated.
EXPECT_EQ(3u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(160, 10, 30, 30).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(3)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(160, 10, 30, 30),
+ frame.render_pass_list.front()->quad_list.ElementAt(3)->visible_rect);
}
{
@@ -2577,16 +2571,15 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
// and |rect2|, is (0, 0, 160x60). Since visible region of rect 5 is
// (10, 60, 120x50), |visible_rect| of |quad3| is updated.
EXPECT_EQ(3u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(10, 60, 120, 50).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(3)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(10, 60, 120, 50),
+ frame.render_pass_list.front()->quad_list.ElementAt(3)->visible_rect);
}
}
@@ -2699,15 +2692,15 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleRenderPass) {
// But |rect3| so |rect3| is to be removed from |quad_list|.
EXPECT_EQ(2u, frame.render_pass_list.at(1)->quad_list.size());
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.at(1)
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.at(1)
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.at(1)->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.at(1)->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ rect3,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -2770,12 +2763,12 @@ TEST_F(DisplayTest, CompositorFrameWithCoveredRenderPass) {
// |quad_list|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
EXPECT_EQ(1u, frame.render_pass_list.at(1)->quad_list.size());
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.at(1)
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.at(1)->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -2823,9 +2816,9 @@ TEST_F(DisplayTest, CompositorFrameWithClip) {
// |rect1| covers |rect2| as shown in the figure above, So the size of
// |quad_list| is reduced by 1.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
{
@@ -2851,12 +2844,12 @@ TEST_F(DisplayTest, CompositorFrameWithClip) {
// (0, 0, 60x60) |quad| and |quad2| (50, 50, 25x25) don't intersect in the
// target space. So no change is applied to quads.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
}
{
@@ -2881,13 +2874,12 @@ TEST_F(DisplayTest, CompositorFrameWithClip) {
// visible region of |quad2| is (60, 50, 10x10). So |quad2| is updated
// accordingly.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(60, 50, 10, 10).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(60, 50, 10, 10),
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
}
}
@@ -2931,9 +2923,9 @@ TEST_F(DisplayTest, CompositorFrameWithCopyRequest) {
// occlusion with copy_request on root RenderPass, |quad_list| reduces its
// size by 1 after calling remove overdraw.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -3009,18 +3001,18 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
// occlude each other. Since AggregatedRenderPassDrawQuad |r1| and |r2|
// cannot be removed to reduce overdraw, |quad_list| remains unchanged.
EXPECT_EQ(4u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
- EXPECT_EQ(rect4.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(3)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ rect3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
+ EXPECT_EQ(
+ rect4,
+ frame.render_pass_list.front()->quad_list.ElementAt(3)->visible_rect);
}
{
@@ -3057,18 +3049,18 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
// occlude each other. Since AggregatedRenderPassDrawQuad |r1| and |r2|
// cannot be removed to reduce overdraw, |quad_list| remains unchanged.
EXPECT_EQ(4u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect5.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
- EXPECT_EQ(rect6.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(3)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect5,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ rect3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
+ EXPECT_EQ(
+ rect6,
+ frame.render_pass_list.front()->quad_list.ElementAt(3)->visible_rect);
}
{
@@ -3104,15 +3096,15 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
// Since AggregatedRenderPassDrawQuad |r1| and |r2| cannot be removed to
// reduce overdraw, |quad_list| is reduced by 1.
EXPECT_EQ(3u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect5.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect5,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ rect3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
}
}
@@ -3183,18 +3175,18 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
// |visible_rect| of |shared_quad_state| is formed by 4 DrawQuads and it
// covers the visible region of |shared_quad_state2|.
EXPECT_EQ(4u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1_1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1_2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1_3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1_4.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(3)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1_1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect1_2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ rect1_3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
+ EXPECT_EQ(
+ rect1_4,
+ frame.render_pass_list.front()->quad_list.ElementAt(3)->visible_rect);
}
{
@@ -3219,22 +3211,21 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
// partially covers the visible region of |shared_quad_state2|. The
// |visible_rect| of |quad5| is updated.
EXPECT_EQ(5u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1_1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1_2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1_3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
- EXPECT_EQ(rect1_4.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(3)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(100, 0, 30, 30).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(5)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1_1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect1_2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ rect1_3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
+ EXPECT_EQ(
+ rect1_4,
+ frame.render_pass_list.front()->quad_list.ElementAt(3)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(100, 0, 30, 30),
+ frame.render_pass_list.front()->quad_list.ElementAt(5)->visible_rect);
}
{
@@ -3267,26 +3258,24 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
// |visible_rect| of DrawQuads in |share_quad_state2| are updated to the
// region shown on screen.
EXPECT_EQ(6u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect2_1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2_2.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2_3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
- EXPECT_EQ(rect2_4.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(3)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(0, 0, 20, 30).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(5)
- ->visible_rect.ToString());
- EXPECT_EQ(gfx::Rect(120, 0, 20, 30).ToString(),
- frame.render_pass_list.front()
- ->quad_list.ElementAt(6)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect2_1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect2_2,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
+ EXPECT_EQ(
+ rect2_3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
+ EXPECT_EQ(
+ rect2_4,
+ frame.render_pass_list.front()->quad_list.ElementAt(3)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(0, 0, 20, 30),
+ frame.render_pass_list.front()->quad_list.ElementAt(5)->visible_rect);
+ EXPECT_EQ(
+ gfx::Rect(120, 0, 20, 30),
+ frame.render_pass_list.front()->quad_list.ElementAt(6)->visible_rect);
}
}
@@ -3354,12 +3343,12 @@ TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) {
display_->RemoveOverdrawQuads(&frame);
// |quad2| is removed because it is not shown on screen in the target space.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(rect3.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(2)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ rect3,
+ frame.render_pass_list.front()->quad_list.ElementAt(2)->visible_rect);
}
{
@@ -3385,9 +3374,9 @@ TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) {
// |quad3| follows an non-invertible transform and it's covered by the
// occlusion rect. So |quad3| is removed from the |frame|.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -3425,9 +3414,9 @@ TEST_F(DisplayTest, DrawOcclusionWithLargeDrawQuad) {
// DrawQuad, so the size of quad_list remains unchanged after calling
// RemoveOverdrawQuads.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(rect1.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ rect1,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -3762,137 +3751,6 @@ TEST_F(DisplayTest, DontThrottleWhenParentBlocked) {
UpdateBeginFrameTime(sub_support.get(), frame_time);
}
-TEST_F(DisplayTest, InvalidPresentationTimestamps) {
- RendererSettings settings;
- id_allocator_.GenerateId();
- const LocalSurfaceId local_surface_id(
- id_allocator_.GetCurrentLocalSurfaceId());
-
- // Set up first display.
- SetUpSoftwareDisplay(settings);
- StubDisplayClient client;
- display_->Initialize(&client, manager_.surface_manager());
- display_->SetLocalSurfaceId(local_surface_id, 1.f);
- display_->Resize(gfx::Size(25, 25));
-
- {
- // A regular presentation timestamp.
- base::HistogramTester histograms;
- CompositorFrame frame =
- CompositorFrameBuilder()
- .AddRenderPass(gfx::Rect(25, 25), gfx::Rect(25, 25))
- .Build();
- support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
- display_->DrawAndSwap({base::TimeTicks::Now(), base::TimeTicks::Now()});
- display_->DidReceiveSwapBuffersAck(GetTestSwapTimings(),
- /*release_fence=*/gfx::GpuFenceHandle());
- display_->DidReceivePresentationFeedback({base::TimeTicks::Now(), {}, 0});
- EXPECT_THAT(histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidBeforeSwap"),
- testing::IsEmpty());
- EXPECT_THAT(histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidFromFuture"),
- testing::IsEmpty());
- }
-
- {
- // A presentation-timestamp that is earlier than the swap time.
- base::HistogramTester histograms;
- CompositorFrame frame =
- CompositorFrameBuilder()
- .AddRenderPass(gfx::Rect(25, 25), gfx::Rect(25, 25))
- .Build();
- support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
- display_->DrawAndSwap({base::TimeTicks::Now(), base::TimeTicks::Now()});
- display_->DidReceiveSwapBuffersAck(GetTestSwapTimings(),
- /*release_fence=*/gfx::GpuFenceHandle());
- display_->DidReceivePresentationFeedback(
- {base::TimeTicks::Now() - base::Seconds(1), {}, 0});
- EXPECT_THAT(histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidFromFuture"),
- testing::IsEmpty());
- auto buckets = histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidBeforeSwap");
- ASSERT_EQ(buckets.size(), 1u);
- EXPECT_GT(buckets[0].min, 0);
- EXPECT_LE(buckets[0].min, 1000);
- EXPECT_EQ(buckets[0].count, 1);
- }
-
- {
- // A presentation-timestamp that is in the near-future with hwclock: this
- // should be valid.
- base::HistogramTester histograms;
- CompositorFrame frame =
- CompositorFrameBuilder()
- .AddRenderPass(gfx::Rect(25, 25), gfx::Rect(25, 25))
- .Build();
- support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
- display_->DrawAndSwap({base::TimeTicks::Now(), base::TimeTicks::Now()});
- display_->DidReceiveSwapBuffersAck(GetTestSwapTimings(),
- /*release_fence=*/gfx::GpuFenceHandle());
- display_->DidReceivePresentationFeedback(
- {base::TimeTicks::Now() + base::Milliseconds(1),
- {},
- gfx::PresentationFeedback::kHWClock});
- EXPECT_THAT(histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidBeforeSwap"),
- testing::IsEmpty());
- EXPECT_THAT(histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidFromFuture"),
- testing::IsEmpty());
- }
-
- {
- // A presentation-timestamp that is in the near-future.
- base::HistogramTester histograms;
- CompositorFrame frame =
- CompositorFrameBuilder()
- .AddRenderPass(gfx::Rect(25, 25), gfx::Rect(25, 25))
- .Build();
- support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
- display_->DrawAndSwap({base::TimeTicks::Now(), base::TimeTicks::Now()});
- display_->DidReceiveSwapBuffersAck(GetTestSwapTimings(),
- /*release_fence=*/gfx::GpuFenceHandle());
- display_->DidReceivePresentationFeedback(
- {base::TimeTicks::Now() + base::Milliseconds(1), {}, 0});
- EXPECT_THAT(histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidBeforeSwap"),
- testing::IsEmpty());
- auto buckets = histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidFromFuture");
- ASSERT_EQ(buckets.size(), 1u);
- EXPECT_GE(buckets[0].min, 0);
- EXPECT_LE(buckets[0].min, 1);
- EXPECT_EQ(buckets[0].count, 1);
- }
-
- {
- // A presentation-timestamp that is in the future.
- base::HistogramTester histograms;
- CompositorFrame frame =
- CompositorFrameBuilder()
- .AddRenderPass(gfx::Rect(25, 25), gfx::Rect(25, 25))
- .Build();
- support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
- display_->DrawAndSwap({base::TimeTicks::Now(), base::TimeTicks::Now()});
- display_->DidReceiveSwapBuffersAck(GetTestSwapTimings(),
- /*release_fence=*/gfx::GpuFenceHandle());
- display_->DidReceivePresentationFeedback(
- {base::TimeTicks::Now() + base::Seconds(1), {}, 0});
- EXPECT_THAT(histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidBeforeSwap"),
- testing::IsEmpty());
-
- auto buckets = histograms.GetAllSamples(
- "Graphics.PresentationTimestamp.InvalidFromFuture");
- ASSERT_EQ(buckets.size(), 1u);
- EXPECT_GT(buckets[0].min, 0);
- EXPECT_LE(buckets[0].min, 1000);
- EXPECT_EQ(buckets[0].count, 1);
- }
-}
-
TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerDoesNotOcclude) {
SetUpGpuDisplay(RendererSettings());
@@ -3939,12 +3797,12 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerDoesNotOcclude) {
// Since none of the quads are culled, there should be 2 quads.
EXPECT_EQ(2u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(quad_rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
- EXPECT_EQ(quad_rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(1)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ quad_rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
+ EXPECT_EQ(
+ quad_rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(1)->visible_rect);
}
}
@@ -3995,9 +3853,9 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerDoesOcclude) {
// no rounded corner, the later quad is culled. We should only have 1 quad
// in the final list now.
EXPECT_EQ(1u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(quad_rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ quad_rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
}
}
@@ -4061,9 +3919,9 @@ TEST_F(DisplayTest, DrawOcclusionSplit) {
EXPECT_EQ(4u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
display_->RemoveOverdrawQuads(&frame);
ASSERT_EQ(6u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(occluding_rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ occluding_rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
// Computed the expected quads
// +--------------------------------+
@@ -4333,9 +4191,9 @@ TEST_F(DisplayTest, DrawOcclusionWithRoundedCornerPartialOcclude) {
// no rounded corner, the later quad is culled. We should only have 1 quad
// in the final list now.
EXPECT_EQ(5u, NumVisibleRects(frame.render_pass_list.front()->quad_list));
- EXPECT_EQ(quad_rect.ToString(), frame.render_pass_list.front()
- ->quad_list.ElementAt(0)
- ->visible_rect.ToString());
+ EXPECT_EQ(
+ quad_rect,
+ frame.render_pass_list.front()->quad_list.ElementAt(0)->visible_rect);
// For rounded rect of bounds (10, 10, 1000, 1000) and corner radius of 10,
// the occluding rect for it would be (13, 13, 994, 994).
@@ -4475,10 +4333,7 @@ class SkiaDelegatedInkRendererTest : public DisplayTest {
void SetUp() override { EnablePrediction(); }
void SetUpRenderers() {
- // First set up the display to use the Skia renderer.
- RendererSettings settings;
- settings.use_skia_renderer = true;
- SetUpGpuDisplay(settings);
+ SetUpGpuDisplay(RendererSettings());
// Initialize the renderer and create an ink renderer.
display_->Initialize(&client_, manager_.surface_manager());
@@ -5001,9 +4856,7 @@ class DelegatedInkDisplayTest
features::kUsePlatformDelegatedInk);
// Set up the display to use the Skia renderer.
- RendererSettings settings;
- settings.use_skia_renderer = true;
- SetUpGpuDisplaySkiaWithPlatformInk(settings);
+ SetUpGpuDisplaySkiaWithPlatformInk(RendererSettings());
display_->Initialize(&client_, manager_.surface_manager());
}
diff --git a/chromium/components/viz/service/display/dynamic_geometry_binding.cc b/chromium/components/viz/service/display/dynamic_geometry_binding.cc
deleted file mode 100644
index bb47dba7320..00000000000
--- a/chromium/components/viz/service/display/dynamic_geometry_binding.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/dynamic_geometry_binding.h"
-
-#include <stdint.h>
-
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace viz {
-
-DynamicGeometryBinding::DynamicGeometryBinding(gpu::gles2::GLES2Interface* gl)
- : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) {
- GLuint buffers[2];
- gl_->GenBuffers(2, buffers);
- quad_vertices_vbo_ = buffers[0];
- quad_elements_vbo_ = buffers[1];
-
- gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_);
- gl_->BufferData(GL_ARRAY_BUFFER, sizeof(GeometryBindingQuad), nullptr,
- GL_DYNAMIC_DRAW);
-
- gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_);
- gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GeometryBindingQuadIndex),
- nullptr, GL_DYNAMIC_DRAW);
-}
-
-DynamicGeometryBinding::~DynamicGeometryBinding() {
- GLuint buffers[2] = {quad_vertices_vbo_, quad_elements_vbo_};
- gl_->DeleteBuffers(2, buffers);
-}
-
-void DynamicGeometryBinding::InitializeCustomQuad(const gfx::QuadF& quad) {
- float uv[] = {0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
- InitializeCustomQuadWithUVs(quad, uv);
-}
-
-void DynamicGeometryBinding::InitializeCustomQuadWithUVs(const gfx::QuadF& quad,
- const float uv[8]) {
- GeometryBindingVertex v0 = {
- {quad.p1().x(), quad.p1().y(), 0.0f}, {uv[0], uv[1]}, 0.0f};
- GeometryBindingVertex v1 = {
- {quad.p2().x(), quad.p2().y(), 0.0f}, {uv[2], uv[3]}, 1.0f};
- GeometryBindingVertex v2 = {
- {quad.p3().x(), quad.p3().y(), 0.0f}, {uv[4], uv[5]}, 2.0f};
- GeometryBindingVertex v3 = {
- {quad.p4().x(), quad.p4().y(), 0.0f}, {uv[6], uv[7]}, 3.0f};
-
- GeometryBindingQuad local_quad = {v0, v1, v2, v3};
- GeometryBindingQuadIndex quad_index(
- static_cast<uint16_t>(0), static_cast<uint16_t>(1),
- static_cast<uint16_t>(2), static_cast<uint16_t>(3),
- static_cast<uint16_t>(0), static_cast<uint16_t>(2));
-
- gl_->BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GeometryBindingQuad),
- &local_quad);
- gl_->BufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0,
- sizeof(GeometryBindingQuadIndex), &quad_index);
-}
-
-void DynamicGeometryBinding::PrepareForDraw() {
- SetupGLContext(gl_, quad_elements_vbo_, quad_vertices_vbo_);
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/dynamic_geometry_binding.h b/chromium/components/viz/service/display/dynamic_geometry_binding.h
deleted file mode 100644
index 2d340962fad..00000000000
--- a/chromium/components/viz/service/display/dynamic_geometry_binding.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_DYNAMIC_GEOMETRY_BINDING_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_DYNAMIC_GEOMETRY_BINDING_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/service/display/geometry_binding.h"
-#include "components/viz/service/viz_service_export.h"
-
-namespace gfx {
-class QuadF;
-}
-
-namespace viz {
-
-class VIZ_SERVICE_EXPORT DynamicGeometryBinding {
- public:
- explicit DynamicGeometryBinding(gpu::gles2::GLES2Interface* gl);
-
- DynamicGeometryBinding(const DynamicGeometryBinding&) = delete;
- DynamicGeometryBinding& operator=(const DynamicGeometryBinding&) = delete;
-
- ~DynamicGeometryBinding();
-
- void PrepareForDraw();
- void InitializeCustomQuad(const gfx::QuadF& quad);
- void InitializeCustomQuadWithUVs(const gfx::QuadF& quad, const float uv[8]);
-
- private:
- raw_ptr<gpu::gles2::GLES2Interface> gl_;
-
- GLuint quad_vertices_vbo_;
- GLuint quad_elements_vbo_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DYNAMIC_GEOMETRY_BINDING_H_
diff --git a/chromium/components/viz/service/display/external_use_client.h b/chromium/components/viz/service/display/external_use_client.h
index dbac7444dfb..e37901e41c5 100644
--- a/chromium/components/viz/service/display/external_use_client.h
+++ b/chromium/components/viz/service/display/external_use_client.h
@@ -87,8 +87,10 @@ class VIZ_SERVICE_EXPORT ExternalUseClient {
void set_paint_op_buffer(const cc::PaintOpBuffer* buffer) {
paint_op_buffer_ = buffer;
}
- const absl::optional<SkColor>& clear_color() const { return clear_color_; }
- void set_clear_color(const absl::optional<SkColor>& color) {
+ const absl::optional<SkColor4f>& clear_color() const {
+ return clear_color_;
+ }
+ void set_clear_color(const absl::optional<SkColor4f>& color) {
clear_color_ = color;
}
@@ -110,7 +112,7 @@ class VIZ_SERVICE_EXPORT ExternalUseClient {
sk_sp<SkImage> image_;
GrBackendFormat backend_format_;
raw_ptr<const cc::PaintOpBuffer> paint_op_buffer_ = nullptr;
- absl::optional<SkColor> clear_color_;
+ absl::optional<SkColor4f> clear_color_;
};
// If |maybe_concurrent_reads| is true then there can be concurrent reads to
diff --git a/chromium/components/viz/service/display/frame_rate_decider_unittest.cc b/chromium/components/viz/service/display/frame_rate_decider_unittest.cc
index e9f55fa7c1e..2be3702bc4b 100644
--- a/chromium/components/viz/service/display/frame_rate_decider_unittest.cc
+++ b/chromium/components/viz/service/display/frame_rate_decider_unittest.cc
@@ -29,7 +29,9 @@ class FrameRateDeciderTest : public testing::Test,
~FrameRateDeciderTest() override = default;
void SetUp() override {
- surface_manager_ = std::make_unique<SurfaceManager>(this, absl::nullopt);
+ surface_manager_ = std::make_unique<SurfaceManager>(
+ this, /*activation_deadline_in_frames=*/absl::nullopt,
+ /*max_uncommitted_frames=*/0);
bool hw_support_for_multiple_refresh_rates = true;
frame_rate_decider_ = std::make_unique<FrameRateDecider>(
surface_manager_.get(), this, hw_support_for_multiple_refresh_rates,
diff --git a/chromium/components/viz/service/display/geometry_binding.cc b/chromium/components/viz/service/display/geometry_binding.cc
deleted file mode 100644
index e2013e1c029..00000000000
--- a/chromium/components/viz/service/display/geometry_binding.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/geometry_binding.h"
-
-#include <stdint.h>
-#include <string.h>
-
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace viz {
-
-void SetupGLContext(gpu::gles2::GLES2Interface* gl,
- GLuint quad_elements_vbo,
- GLuint quad_vertices_vbo) {
- gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo);
-
- gl->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo);
- // OpenGL defines the last parameter to VertexAttribPointer as type
- // "const GLvoid*" even though it is actually an offset into the buffer
- // object's data store and not a pointer to the client's address space.
- const void* offsets[3] = {
- nullptr, reinterpret_cast<const void*>(3 * sizeof(float)),
- reinterpret_cast<const void*>(5 * sizeof(float)),
- };
-
- gl->VertexAttribPointer(GeometryBinding::PositionAttribLocation(), 3,
- GL_FLOAT, false, 6 * sizeof(float), offsets[0]);
- gl->VertexAttribPointer(GeometryBinding::TexCoordAttribLocation(), 2,
- GL_FLOAT, false, 6 * sizeof(float), offsets[1]);
- gl->VertexAttribPointer(GeometryBinding::TriangleIndexAttribLocation(), 1,
- GL_FLOAT, false, 6 * sizeof(float), offsets[2]);
- gl->EnableVertexAttribArray(GeometryBinding::PositionAttribLocation());
- gl->EnableVertexAttribArray(GeometryBinding::TexCoordAttribLocation());
- gl->EnableVertexAttribArray(GeometryBinding::TriangleIndexAttribLocation());
-}
-
-GeometryBindingQuad::GeometryBindingQuad() {
- v0 = {{0, 0, 0}, {0, 0}, 0};
- v1 = {{0, 0, 0}, {0, 0}, 0};
- v2 = {{0, 0, 0}, {0, 0}, 0};
- v3 = {{0, 0, 0}, {0, 0}, 0};
-}
-
-GeometryBindingQuad::GeometryBindingQuad(const GeometryBindingVertex& vert0,
- const GeometryBindingVertex& vert1,
- const GeometryBindingVertex& vert2,
- const GeometryBindingVertex& vert3) {
- v0 = vert0;
- v1 = vert1;
- v2 = vert2;
- v3 = vert3;
-}
-
-GeometryBindingQuadIndex::GeometryBindingQuadIndex() {
- memset(data, 0x0, sizeof(data));
-}
-
-GeometryBindingQuadIndex::GeometryBindingQuadIndex(uint16_t index0,
- uint16_t index1,
- uint16_t index2,
- uint16_t index3,
- uint16_t index4,
- uint16_t index5) {
- data[0] = index0;
- data[1] = index1;
- data[2] = index2;
- data[3] = index3;
- data[4] = index4;
- data[5] = index5;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/geometry_binding.h b/chromium/components/viz/service/display/geometry_binding.h
deleted file mode 100644
index 64bdf0b9ae4..00000000000
--- a/chromium/components/viz/service/display/geometry_binding.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_GEOMETRY_BINDING_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_GEOMETRY_BINDING_H_
-
-#include <stdint.h>
-
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace viz {
-
-struct GeometryBindingVertex {
- float a_position[3];
- float a_texCoord[2];
- // Index of the vertex, divide by 4 to have the matrix for this quad.
- float a_index;
-};
-
-struct GeometryBindingQuad {
- GeometryBindingQuad();
- GeometryBindingQuad(const GeometryBindingVertex& vert0,
- const GeometryBindingVertex& vert1,
- const GeometryBindingVertex& vert2,
- const GeometryBindingVertex& vert3);
- GeometryBindingVertex v0, v1, v2, v3;
-};
-static_assert(sizeof(GeometryBindingQuad) == 24 * sizeof(float),
- "struct Quad should be densely packed");
-
-struct GeometryBindingQuadIndex {
- GeometryBindingQuadIndex();
- GeometryBindingQuadIndex(uint16_t index0,
- uint16_t index1,
- uint16_t index2,
- uint16_t index3,
- uint16_t index4,
- uint16_t index5);
-
- uint16_t data[6];
-};
-static_assert(sizeof(GeometryBindingQuadIndex) == 6 * sizeof(uint16_t),
- "struct QuadIndex should be densely packed");
-
-struct GeometryBinding {
- // All layer shaders share the same attribute locations for the vertex
- // positions and texture coordinates. This allows switching shaders without
- // rebinding attribute arrays.
- static int PositionAttribLocation() { return 0; }
- static int TexCoordAttribLocation() { return 1; }
- static int TriangleIndexAttribLocation() { return 2; }
-};
-
-void SetupGLContext(gpu::gles2::GLES2Interface* gl,
- GLuint quad_elements_vbo,
- GLuint quad_vertices_vbo);
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_GEOMETRY_BINDING_H_
diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc
deleted file mode 100644
index 7fb664525ba..00000000000
--- a/chromium/components/viz/service/display/gl_renderer.cc
+++ /dev/null
@@ -1,4514 +0,0 @@
-// Copyright 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/gl_renderer.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <limits>
-#include <memory>
-#include <numeric>
-#include <set>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/check_op.h"
-#include "base/containers/cxx20_erase.h"
-#include "base/feature_list.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/raw_ptr.h"
-#include "base/notreached.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
-#include "cc/base/math_util.h"
-#include "cc/debug/debug_colors.h"
-#include "cc/paint/render_surface_filters.h"
-#include "cc/raster/scoped_gpu_raster.h"
-#include "components/viz/common/display/renderer_settings.h"
-#include "components/viz/common/features.h"
-#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/quads/compositor_frame.h"
-#include "components/viz/common/quads/compositor_frame_metadata.h"
-#include "components/viz/common/quads/compositor_render_pass.h"
-#include "components/viz/common/quads/picture_draw_quad.h"
-#include "components/viz/common/quads/stream_video_draw_quad.h"
-#include "components/viz/common/quads/texture_draw_quad.h"
-#include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "components/viz/common/resources/resource_id.h"
-#include "components/viz/common/skia_helper.h"
-#include "components/viz/common/viz_utils.h"
-#include "components/viz/service/display/draw_polygon.h"
-#include "components/viz/service/display/dynamic_geometry_binding.h"
-#include "components/viz/service/display/layer_quad.h"
-#include "components/viz/service/display/output_surface.h"
-#include "components/viz/service/display/output_surface_frame.h"
-#include "components/viz/service/display/resource_fence.h"
-#include "components/viz/service/display/scoped_render_pass_texture.h"
-#include "components/viz/service/display/static_geometry_binding.h"
-#include "components/viz/service/display/texture_deleter.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/common/gpu_memory_allocation.h"
-#include "gpu/config/gpu_driver_bug_workaround_type.h"
-#include "gpu/config/gpu_feature_info.h"
-#include "third_party/abseil-cpp/absl/types/optional.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkColorFilter.h"
-#include "third_party/skia/include/core/SkImage.h"
-#include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/core/SkTypes.h"
-#include "third_party/skia/include/effects/SkShaderMaskFilter.h"
-#include "third_party/skia/include/gpu/GrBackendSurface.h"
-#include "third_party/skia/include/gpu/GrDirectContext.h"
-#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
-#include "third_party/skia/include/gpu/gl/GrGLTypes.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/color_transform.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/geometry/rrect_f.h"
-#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/geometry/skia_conversions.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/gpu_fence_handle.h"
-
-using gpu::gles2::GLES2Interface;
-
-namespace viz {
-namespace {
-
-Float4 UVTransform(const TextureDrawQuad* quad) {
- gfx::RectF uv_rect =
- gfx::BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
- gfx::RectF visible_uv_rect = cc::MathUtil::ScaleRectProportional(
- uv_rect, gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
-
- gfx::PointF uv0 = visible_uv_rect.origin();
- gfx::PointF uv1 = visible_uv_rect.bottom_right();
- Float4 xform = {{uv0.x(), uv0.y(), uv1.x() - uv0.x(), uv1.y() - uv0.y()}};
- if (quad->y_flipped) {
- xform.data[1] = 1.0f - xform.data[1];
- xform.data[3] = -xform.data[3];
- }
- return xform;
-}
-
-// To prevent sampling outside the visible rect.
-Float4 UVClampRect(gfx::RectF uv_visible_rect,
- const gfx::Size& texture_size,
- SamplerType sampler) {
- gfx::SizeF half_texel(0.5f, 0.5f);
- if (sampler != SAMPLER_TYPE_2D_RECT) {
- half_texel.Scale(1.f / texture_size.width(), 1.f / texture_size.height());
- } else {
- uv_visible_rect.Scale(texture_size.width(), texture_size.height());
- }
- uv_visible_rect.Inset(
- gfx::InsetsF::VH(half_texel.height(), half_texel.width()));
- return {{uv_visible_rect.x(), uv_visible_rect.y(), uv_visible_rect.right(),
- uv_visible_rect.bottom()}};
-}
-
-Float4 PremultipliedColor(SkColor color, float opacity) {
- const U8CPU alpha255 = SkColorGetA(color);
- const unsigned int alpha256 = alpha255 + 1;
- const unsigned int premultiplied_red = (SkColorGetR(color) * alpha256) >> 8;
- const unsigned int premultiplied_green = (SkColorGetG(color) * alpha256) >> 8;
- const unsigned int premultiplied_blue = (SkColorGetB(color) * alpha256) >> 8;
- const float factor = opacity / 255.0f;
- return {{premultiplied_red * factor, premultiplied_green * factor,
- premultiplied_blue * factor, alpha255 * factor}};
-}
-
-SamplerType SamplerTypeFromTextureTarget(GLenum target) {
- switch (target) {
- case GL_TEXTURE_2D:
- return SAMPLER_TYPE_2D;
- case GL_TEXTURE_RECTANGLE_ARB:
- return SAMPLER_TYPE_2D_RECT;
- case GL_TEXTURE_EXTERNAL_OES:
- return SAMPLER_TYPE_EXTERNAL_OES;
- default:
- NOTREACHED();
- return SAMPLER_TYPE_2D;
- }
-}
-
-BlendMode BlendModeFromSkXfermode(SkBlendMode mode) {
- switch (mode) {
- case SkBlendMode::kSrcOver:
- return BLEND_MODE_NORMAL;
- case SkBlendMode::kDstIn:
- return BLEND_MODE_DESTINATION_IN;
- case SkBlendMode::kScreen:
- return BLEND_MODE_SCREEN;
- case SkBlendMode::kOverlay:
- return BLEND_MODE_OVERLAY;
- case SkBlendMode::kDarken:
- return BLEND_MODE_DARKEN;
- case SkBlendMode::kLighten:
- return BLEND_MODE_LIGHTEN;
- case SkBlendMode::kColorDodge:
- return BLEND_MODE_COLOR_DODGE;
- case SkBlendMode::kColorBurn:
- return BLEND_MODE_COLOR_BURN;
- case SkBlendMode::kHardLight:
- return BLEND_MODE_HARD_LIGHT;
- case SkBlendMode::kSoftLight:
- return BLEND_MODE_SOFT_LIGHT;
- case SkBlendMode::kDifference:
- return BLEND_MODE_DIFFERENCE;
- case SkBlendMode::kExclusion:
- return BLEND_MODE_EXCLUSION;
- case SkBlendMode::kMultiply:
- return BLEND_MODE_MULTIPLY;
- case SkBlendMode::kHue:
- return BLEND_MODE_HUE;
- case SkBlendMode::kSaturation:
- return BLEND_MODE_SATURATION;
- case SkBlendMode::kColor:
- return BLEND_MODE_COLOR;
- case SkBlendMode::kLuminosity:
- return BLEND_MODE_LUMINOSITY;
- case SkBlendMode::kSrc:
- return BLEND_MODE_NONE;
- default:
- NOTREACHED();
- return BLEND_MODE_NONE;
- }
-}
-
-// Adds a timer query that spans all GL calls in its scope. |viz.composite_time|
-// trace category must be enabled for this to work.
-// Note:: Multiple timer queries cannot be nested.
-class ScopedTimerQuery {
- public:
- ScopedTimerQuery(bool tracing_enabled,
- gpu::gles2::GLES2Interface* gl,
- base::queue<std::pair<unsigned, std::string>>* timer_queries,
- const std::string& quad_type_str)
- : gl_(gl) {
- if (!tracing_enabled) {
- gl_ = nullptr;
- return;
- }
- unsigned timer_query;
- gl_->GenQueriesEXT(1, &timer_query);
- gl_->BeginQueryEXT(GL_TIME_ELAPSED_EXT, timer_query);
- timer_queries->emplace(timer_query, quad_type_str);
- }
-
- ~ScopedTimerQuery() {
- if (gl_)
- gl_->EndQueryEXT(GL_TIME_ELAPSED_EXT);
- }
-
- private:
- raw_ptr<gpu::gles2::GLES2Interface> gl_;
-};
-
-void AccumulateDrawRects(const gfx::Rect& quad_rect,
- const gfx::Transform& target_transform,
- std::vector<gfx::Rect>* drawn_rects) {
- gfx::RectF quad_rect_f(quad_rect);
-
- // If the transform is not axis aligned then assume the largest possible
- // bounds the quad can take in the render target. In this case, we take the
- // sum of 2 sides.
- if (!target_transform.Preserves2dAxisAlignment()) {
- // Increase the length of each side to |width + height|.
- const int total_length = quad_rect.width() + quad_rect.height();
- quad_rect_f.set_height(total_length);
- quad_rect_f.set_width(total_length);
-
- // Ensure that the increase is equally distributed on either sides of the
- // quad such that the position of the center of the quad does not change.
- const float delta_x = -(quad_rect.height() / 2.f);
- const float delta_y = -(quad_rect.width() / 2.f);
- quad_rect_f.Offset(gfx::Vector2d(delta_x, delta_y));
-
- // Apply only the scale and translation component.
- const gfx::Vector2dF& translate = target_transform.To2dTranslation();
- const gfx::Vector2dF& scale = target_transform.To2dScale();
- quad_rect_f.Scale(scale.x(), scale.y());
- quad_rect_f.Offset(translate.x(), translate.y());
- } else {
- target_transform.TransformRect(&quad_rect_f);
- }
- drawn_rects->push_back(gfx::ToRoundedRect(quad_rect_f));
-}
-
-// Smallest unit that impact anti-aliasing output. We use this to
-// determine when anti-aliasing is unnecessary.
-const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
-
-// A dummy timer query ID used to identify the beginning of a frame in the queue
-// of timer queries.
-const unsigned kTimerQueryDummy = 0;
-
-} // anonymous namespace
-
-static GLint GetActiveTextureUnit(GLES2Interface* gl) {
- GLint active_unit = 0;
- gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
- return active_unit;
-}
-
-// Parameters needed to draw a CompositorRenderPassDrawQuad.
-struct GLRenderer::DrawRenderPassDrawQuadParams {
- DrawRenderPassDrawQuadParams() {}
- ~DrawRenderPassDrawQuadParams() {
- // Don't leak the texture.
- DCHECK(!background_texture);
- }
-
- // Required inputs below.
- raw_ptr<const AggregatedRenderPassDrawQuad> quad = nullptr;
-
- // Either |contents_texture| or |bypass_quad_texture| is populated. The
- // |contents_texture| will be valid if non-null, and when null the
- // bypass_quad_texture will be valid instead.
- raw_ptr<ScopedRenderPassTexture> contents_texture = nullptr;
- struct {
- ResourceId resource_id = kInvalidResourceId;
- gfx::Size size;
- } bypass_quad_texture;
-
- raw_ptr<const gfx::QuadF> clip_region = nullptr;
- bool flip_texture = false;
-
- // |window_matrix| maps from [-1,-1]-[1,1] unit square coordinates to window
- // pixel coordinates.
- gfx::Transform window_matrix;
- // |projection_matrix| maps texture coordinates (in pixels) to the 2D plane in
- // [-1,-1]-[1,1] unit square coordinates. If FlippedFrameBuffer() is true,
- // |projection_matrix| includes this flip.
- gfx::Transform projection_matrix;
- // |quad_to_target_transform| transforms from local quad pixel coordinates to
- // target content space pixel coordinates, including scale, offset,
- // perspective, and rotation.
- gfx::Transform quad_to_target_transform;
- raw_ptr<const cc::FilterOperations> filters = nullptr;
- raw_ptr<const cc::FilterOperations> backdrop_filters = nullptr;
- absl::optional<gfx::RRectF> backdrop_filter_bounds;
-
- // Whether the texture to be sampled from needs to be flipped.
- bool source_needs_flip = false;
-
- float edge[24];
- SkScalar color_matrix[20];
-
- // Blending in the fragment shaders is used for modifications to the backdrop
- // and for supporting advanced blending equation when not available by the
- // underlying graphics API.
- bool use_shaders_for_blending = false;
- SkBlendMode blend_mode = SkBlendMode::kSrcOver;
-
- bool use_aa = false;
-
- // Some filters affect pixels outside the original contents bounds, in which
- // case ApplyImageFilter will modify this rect.
- gfx::RectF dst_rect;
-
- // A Skia image that should be sampled from instead of the original
- // contents.
- sk_sp<SkImage> filter_image;
-
- // The original contents, bound for sampling.
- std::unique_ptr<DisplayResourceProviderGL::ScopedSamplerGL>
- bypass_quad_resource_lock;
-
- // A mask to be applied when drawing the RPDQ.
- std::unique_ptr<DisplayResourceProviderGL::ScopedSamplerGL>
- mask_resource_lock;
-
- // Whether a color matrix needs to be applied by the shaders when drawing
- // the RPDQ.
- bool use_color_matrix = false;
-
- gfx::QuadF surface_quad;
-
- // |contents_device_transform| transforms from vertex geometry, which is often
- // the unit quad [-0.5, 0.5], all the way to 2D window pixel coordinates,
- // including 3D effects, frame buffer orientation, and window offset. The
- // definition of the incoming vertex geometry comes from either
- // shared_geometry_ or clipped_geometry_, which are initialized from
- // DirectRenderer::QuadVertexRect or DynamicGeometryBinding, respectively.
- // |contents_device_transform| is typically calculated as
- // |window_matrix| * |projection_matrix| * |quad_rect_matrix|
- // and then flattened with FlattenTo2d(). Here, |quad_rect_matrix| is a
- // combination of the geometry->quad transform as well as the quad->target
- // space transform. The geometry->quad is the mapping from the bound geometry,
- // often [-0.5, 0.5], to the quad, which is quad->rect.
- gfx::Transform contents_device_transform;
-
- gfx::RectF tex_coord_rect;
-
- // The color space of the texture bound for sampling (from filter_image or
- // bypass_quad_resource_lock, depending on the path taken).
- gfx::ColorSpace contents_and_bypass_color_space;
-
- // Background filters block.
- // Original background texture.
- uint32_t background_texture = 0;
- GLenum background_texture_format = 0;
- // Backdrop bounding box.
- gfx::Rect background_rect;
- // Filtered background texture.
- sk_sp<SkImage> background_image;
- GLuint background_image_id = 0;
- // A multiplier for the temporary surface we create to apply the backdrop
- // filter.
- float backdrop_filter_quality = 1.0;
- // Whether the original background texture is needed for the mask.
- bool mask_for_background = false;
-
- bool apply_shader_based_rounded_corner = true;
-};
-
-class GLRenderer::ScopedUseGrContext {
- public:
- static std::unique_ptr<ScopedUseGrContext> Create(GLRenderer* renderer) {
- // GrContext for filters is created lazily, and may fail if the context
- // is lost.
- // TODO(vmiura,bsalomon): crbug.com/487850 Ensure that
- // ContextProvider::GrContext() does not return NULL.
- GrDirectContext* direct = GrAsDirectContext(
- renderer->output_surface_->context_provider()->GrContext());
- if (direct)
- return base::WrapUnique(new ScopedUseGrContext(renderer));
- return nullptr;
- }
-
- ScopedUseGrContext(const ScopedUseGrContext&) = delete;
- ScopedUseGrContext& operator=(const ScopedUseGrContext&) = delete;
-
- ~ScopedUseGrContext() {
- // Pass context control back to GLrenderer.
- scoped_gpu_raster_ = nullptr;
- renderer_->RestoreGLStateAfterSkia();
- }
-
- GrDirectContext* context() const {
- return renderer_->output_surface_->context_provider()->GrContext();
- }
-
- private:
- explicit ScopedUseGrContext(GLRenderer* renderer)
- : scoped_gpu_raster_(new cc::ScopedGpuRaster(
- renderer->output_surface_->context_provider())),
- renderer_(renderer) {
- // scoped_gpu_raster_ passes context control to Skia.
- }
-
- std::unique_ptr<cc::ScopedGpuRaster> scoped_gpu_raster_;
- raw_ptr<GLRenderer> renderer_;
-};
-
-GLRenderer::GLRenderer(
- const RendererSettings* settings,
- const DebugRendererSettings* debug_settings,
- OutputSurface* output_surface,
- DisplayResourceProviderGL* resource_provider,
- OverlayProcessorInterface* overlay_processor,
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner)
- : DirectRenderer(settings,
- debug_settings,
- output_surface,
- resource_provider,
- overlay_processor),
- shared_geometry_quad_(QuadVertexRect()),
- gl_(output_surface->context_provider()->ContextGL()),
- context_support_(output_surface->context_provider()->ContextSupport()),
- texture_deleter_(current_task_runner),
- copier_(output_surface->context_provider(), &texture_deleter_),
- sync_queries_(gl_),
- bound_geometry_(NO_BINDING),
- current_task_runner_(std::move(current_task_runner)) {
- DCHECK(gl_);
- DCHECK(context_support_);
-
- const auto& context_caps =
- output_surface_->context_provider()->ContextCapabilities();
-
- use_discard_framebuffer_ = context_caps.discard_framebuffer;
- use_sync_query_ = context_caps.sync_query;
- use_blend_equation_advanced_ = context_caps.blend_equation_advanced;
- use_blend_equation_advanced_coherent_ =
- context_caps.blend_equation_advanced_coherent;
- use_occlusion_query_ = context_caps.occlusion_query;
- use_timer_query_ = context_caps.timer_queries;
- use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
- supports_multi_sampling_ = context_caps.max_samples > 0;
- prefer_draw_to_copy_ = output_surface_->context_provider()
- ->GetGpuFeatureInfo()
- .IsWorkaroundEnabled(gpu::PREFER_DRAW_TO_COPY);
- use_fast_path_solid_color_quad_ =
- features::IsUsingFastPathForSolidColorQuad();
- InitializeSharedObjects();
-}
-
-GLRenderer::~GLRenderer() {
- CleanupSharedObjects();
-
- auto* context_provider = output_surface_->context_provider();
- auto* cache_controller = context_provider->CacheController();
-
- if (context_busy_) {
- cache_controller->ClientBecameNotBusy(std::move(context_busy_));
- }
- if (context_visibility_) {
- cache_controller->ClientBecameNotVisibleDuringShutdown(
- std::move(context_visibility_));
- }
-}
-
-bool GLRenderer::CanPartialSwap() {
- if (use_swap_with_bounds_)
- return false;
- auto* context_provider = output_surface_->context_provider();
- return context_provider->ContextCapabilities().post_sub_buffer;
-}
-
-void GLRenderer::DidChangeVisibility() {
- if (visible_) {
- output_surface_->EnsureBackbuffer();
- } else {
- TRACE_EVENT0("viz", "GLRenderer::DidChangeVisibility dropping resources");
- ReleaseRenderPassTextures();
- output_surface_->DiscardBackbuffer();
- gl_->ReleaseShaderCompiler();
- }
-
- PrepareGeometry(NO_BINDING);
-
- auto* context_provider = output_surface_->context_provider();
- auto* cache_controller = context_provider->CacheController();
- if (visible_) {
- DCHECK(!context_visibility_);
- context_visibility_ = cache_controller->ClientBecameVisible();
- } else {
- DCHECK(context_visibility_);
- cache_controller->ClientBecameNotVisible(std::move(context_visibility_));
- }
-}
-
-void GLRenderer::ReleaseRenderPassTextures() {
- render_pass_textures_.clear();
- render_pass_backdrop_textures_.clear();
-}
-
-void GLRenderer::DiscardPixels() {
- if (!use_discard_framebuffer_)
- return;
- bool using_default_framebuffer =
- !current_framebuffer_texture_ &&
- output_surface_->capabilities().uses_default_gl_framebuffer;
- GLenum attachments[] = {static_cast<GLenum>(
- using_default_framebuffer ? GL_COLOR_EXT : GL_COLOR_ATTACHMENT0_EXT)};
- gl_->DiscardFramebufferEXT(GL_FRAMEBUFFER, std::size(attachments),
- attachments);
-}
-
-void GLRenderer::PrepareSurfaceForPass(
- SurfaceInitializationMode initialization_mode,
- const gfx::Rect& render_pass_scissor) {
- SetViewport();
-
- switch (initialization_mode) {
- case SURFACE_INITIALIZATION_MODE_PRESERVE:
- EnsureScissorTestDisabled();
- return;
- case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR:
- EnsureScissorTestDisabled();
- DiscardPixels();
- ClearFramebuffer();
- break;
- case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR:
- SetScissorTestRect(render_pass_scissor);
- ClearFramebuffer();
- break;
- }
-
- if (OverdrawTracingEnabled()) {
- gl_->GenQueriesEXT(1, &occlusion_query_);
- gl_->BeginQueryEXT(GL_SAMPLES_PASSED_ARB, occlusion_query_);
- }
-
- // For each render pass, reset the drawn region.
- drawn_rects_.clear();
-}
-
-void GLRenderer::ClearFramebuffer() {
- // On DEBUG builds, opaque render passes are cleared to blue to easily see
- // regions that were not drawn on the screen.
- if (current_frame()->current_render_pass->has_transparent_background)
- gl_->ClearColor(0, 0, 0, 0);
- else
- gl_->ClearColor(0, 0, 1, 1);
-
- gl_->ClearStencil(0);
-
- bool always_clear = overdraw_feedback_;
-#ifndef NDEBUG
- always_clear = true;
-#endif
- if (always_clear ||
- current_frame()->current_render_pass->has_transparent_background) {
- GLbitfield clear_bits = GL_COLOR_BUFFER_BIT;
- if (always_clear)
- clear_bits |= GL_STENCIL_BUFFER_BIT;
- gl_->Clear(clear_bits);
- }
-}
-
-void GLRenderer::BeginDrawingFrame() {
- TRACE_EVENT0("viz", "GLRenderer::BeginDrawingFrame");
-
- if (!context_busy_) {
- context_busy_ = output_surface_->context_provider()
- ->CacheController()
- ->ClientBecameBusy();
- }
-
- // Begin batching read of shared images.
- gl_->BeginBatchReadAccessSharedImageCHROMIUM();
-
- scoped_refptr<ResourceFence> read_lock_fence;
- if (use_sync_query_) {
- read_lock_fence = sync_queries_.StartNewFrame();
- } else {
- read_lock_fence =
- base::MakeRefCounted<DisplayResourceProviderGL::SynchronousFence>(gl_);
- }
- resource_provider()->SetReadLockFence(read_lock_fence.get());
-
- // Insert WaitSyncTokenCHROMIUM on quad resources prior to drawing the frame,
- // so that drawing can proceed without GL context switching interruptions.
- for (const auto& pass : *current_frame()->render_passes_in_draw_order) {
- for (auto* quad : pass->quad_list) {
- for (ResourceId resource_id : quad->resources)
- resource_provider()->WaitSyncToken(resource_id);
- }
- }
-
- // TODO(enne): Do we need to reinitialize all of this state per frame?
- ReinitializeGLState();
-
- // Add a dummy timer query as a fence to identify the beginning of a frame in
- // the circular queue.
- if (CompositeTimeTracingEnabled())
- timer_queries_.emplace(kTimerQueryDummy, "");
-
- num_triangles_drawn_ = 0;
-}
-
-void GLRenderer::DoDrawQuad(const DrawQuad* quad,
- const gfx::QuadF* clip_region) {
- DCHECK(quad->rect.Contains(quad->visible_rect));
- if (quad->material != DrawQuad::Material::kTextureContent) {
- FlushTextureQuadCache(SHARED_BINDING);
- }
-
- switch (quad->material) {
- case DrawQuad::Material::kInvalid:
- NOTREACHED();
- break;
- case DrawQuad::Material::kAggregatedRenderPass:
- DrawRenderPassQuad(AggregatedRenderPassDrawQuad::MaterialCast(quad),
- clip_region);
- break;
- case DrawQuad::Material::kDebugBorder:
- DrawDebugBorderQuad(DebugBorderDrawQuad::MaterialCast(quad));
- break;
- case DrawQuad::Material::kPictureContent:
- // PictureDrawQuad should only be used for resourceless software draws.
- NOTREACHED();
- break;
- case DrawQuad::Material::kCompositorRenderPass:
- // At this point, RenderPassDrawQuads should be replaced by
- // AggregatedRenderPassDrawQuad.
- NOTREACHED();
- break;
- case DrawQuad::Material::kSolidColor:
- DrawSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad), clip_region);
- break;
- case DrawQuad::Material::kStreamVideoContent:
- DrawStreamVideoQuad(StreamVideoDrawQuad::MaterialCast(quad), clip_region);
- break;
- case DrawQuad::Material::kSurfaceContent:
- // Surface content should be fully resolved to other quad types before
- // reaching a direct renderer.
- NOTREACHED();
- break;
- case DrawQuad::Material::kSharedElement:
- // Shared element should be fully resolved to other quad types before
- // reaching a direct renderer.
- NOTREACHED();
- break;
- case DrawQuad::Material::kTextureContent:
- EnqueueTextureQuad(TextureDrawQuad::MaterialCast(quad), clip_region);
- break;
- case DrawQuad::Material::kTiledContent:
- DrawTileQuad(TileDrawQuad::MaterialCast(quad), clip_region);
- break;
- case DrawQuad::Material::kYuvVideoContent:
- DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad), clip_region);
- break;
- case DrawQuad::Material::kVideoHole:
- // VideoHoleDrawQuad should only be used by Cast, and should
- // have been replaced by cast-specific OverlayProcessor before
- // reach here. In non-cast build, an untrusted render could send such
- // Quad and the quad would then reach here unexpectedly. Therefore
- // we should skip NOTREACHED() so an untrusted render is not capable
- // of causing a crash.
- break;
- }
-}
-
-// This function does not handle 3D sorting right now, since the debug border
-// quads are just drawn as their original quads and not in split pieces. This
-// results in some debug border quads drawing over foreground quads.
-void GLRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad) {
- SetBlendEnabled(quad->ShouldDrawWithBlending());
-
- SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB(),
- CurrentRenderPassColorSpace());
-
- // Use the full quad_rect for debug quads to not move the edges based on
- // partial swaps.
- gfx::Rect layer_rect = quad->rect;
- gfx::Transform render_matrix;
- QuadRectTransform(&render_matrix,
- quad->shared_quad_state->quad_to_target_transform,
- gfx::RectF(layer_rect));
- SetShaderMatrix(current_frame()->projection_matrix * render_matrix);
- SetShaderColor(quad->color, 1.f);
-
- gl_->LineWidth(quad->width);
-
- // The indices for the line are stored in the same array as the triangle
- // indices.
- gl_->DrawElements(GL_LINE_LOOP, 4, GL_UNSIGNED_SHORT, nullptr);
-}
-
-// This is a utility to convert from GrGLenum color format into the equivalent
-// skColorType format. Note: this only supports the limited set of values that
-// can get returned by GLRenderer::GetBackdropTexture().
-static SkColorType GlFormatToSkFormat(GrGLenum format) {
- switch (format) {
- case GL_RGB:
- return kRGB_888x_SkColorType;
- case GL_RGBA:
- return kRGBA_8888_SkColorType;
- case GL_BGRA_EXT:
- return kBGRA_8888_SkColorType;
- case GL_RGB10_A2_EXT:
- return kRGBA_1010102_SkColorType;
- default:
- NOTREACHED() << std::hex << std::showbase << format;
- return kN32_SkColorType;
- }
-}
-
-static GrGLenum SkFormatToGlFormat(SkColorType format) {
- switch (format) {
- case kRGB_888x_SkColorType:
- return GL_RGB8_OES;
- case kRGBA_8888_SkColorType:
- return GL_RGBA8_OES;
- case kBGRA_8888_SkColorType:
- return GL_BGRA8_EXT;
- case kRGBA_1010102_SkColorType:
- return GL_RGB10_A2_EXT;
- default:
- NOTREACHED();
- return GL_RGBA8_OES;
- }
-}
-
-// Wrap a given texture in a Ganesh backend texture.
-static sk_sp<SkImage> WrapTexture(uint32_t texture_id,
- uint32_t target,
- const gfx::Size& size,
- GrDirectContext* context,
- bool flip_texture,
- SkColorType format,
- bool adopt_texture) {
- GrGLenum texture_format = SkFormatToGlFormat(format);
- GrGLTextureInfo texture_info;
- texture_info.fTarget = target;
- texture_info.fID = texture_id;
- texture_info.fFormat = texture_format;
- GrBackendTexture backend_texture(size.width(), size.height(),
- GrMipMapped::kNo, texture_info);
- GrSurfaceOrigin origin =
- flip_texture ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin;
- if (adopt_texture) {
- return SkImage::MakeFromAdoptedTexture(
- context, backend_texture, origin, format, kPremul_SkAlphaType, nullptr);
- } else {
- return SkImage::MakeFromTexture(context, backend_texture, origin, format,
- kPremul_SkAlphaType, nullptr);
- }
-}
-
-static gfx::RectF CenteredRect(const gfx::Rect& tile_rect) {
- return gfx::RectF(
- gfx::PointF(-0.5f * tile_rect.width(), -0.5f * tile_rect.height()),
- gfx::SizeF(tile_rect.size()));
-}
-
-bool GLRenderer::CanApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode) {
- return use_blend_equation_advanced_ || blend_mode == SkBlendMode::kSrcOver ||
- blend_mode == SkBlendMode::kDstIn ||
- blend_mode == SkBlendMode::kScreen;
-}
-
-void GLRenderer::ApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode) {
- // Any modes set here must be reset in RestoreBlendFuncToDefault
- if (blend_mode == SkBlendMode::kSrcOver) {
- // Left no-op intentionally.
- } else if (blend_mode == SkBlendMode::kDstIn) {
- gl_->BlendFunc(GL_ZERO, GL_SRC_ALPHA);
- } else if (blend_mode == SkBlendMode::kDstOut) {
- gl_->BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
- } else if (blend_mode == SkBlendMode::kScreen) {
- gl_->BlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE);
- } else {
- DCHECK(use_blend_equation_advanced_);
- GLenum equation = GL_FUNC_ADD;
- switch (blend_mode) {
- case SkBlendMode::kScreen:
- equation = GL_SCREEN_KHR;
- break;
- case SkBlendMode::kOverlay:
- equation = GL_OVERLAY_KHR;
- break;
- case SkBlendMode::kDarken:
- equation = GL_DARKEN_KHR;
- break;
- case SkBlendMode::kLighten:
- equation = GL_LIGHTEN_KHR;
- break;
- case SkBlendMode::kColorDodge:
- equation = GL_COLORDODGE_KHR;
- break;
- case SkBlendMode::kColorBurn:
- equation = GL_COLORBURN_KHR;
- break;
- case SkBlendMode::kHardLight:
- equation = GL_HARDLIGHT_KHR;
- break;
- case SkBlendMode::kSoftLight:
- equation = GL_SOFTLIGHT_KHR;
- break;
- case SkBlendMode::kDifference:
- equation = GL_DIFFERENCE_KHR;
- break;
- case SkBlendMode::kExclusion:
- equation = GL_EXCLUSION_KHR;
- break;
- case SkBlendMode::kMultiply:
- equation = GL_MULTIPLY_KHR;
- break;
- case SkBlendMode::kHue:
- equation = GL_HSL_HUE_KHR;
- break;
- case SkBlendMode::kSaturation:
- equation = GL_HSL_SATURATION_KHR;
- break;
- case SkBlendMode::kColor:
- equation = GL_HSL_COLOR_KHR;
- break;
- case SkBlendMode::kLuminosity:
- equation = GL_HSL_LUMINOSITY_KHR;
- break;
- default:
- NOTREACHED() << "Unexpected blend mode: SkBlendMode::k"
- << SkBlendMode_Name(blend_mode);
- return;
- }
- gl_->BlendEquation(equation);
- }
-}
-
-void GLRenderer::RestoreBlendFuncToDefault(SkBlendMode blend_mode) {
- switch (blend_mode) {
- case SkBlendMode::kSrcOver:
- break;
- case SkBlendMode::kDstIn:
- case SkBlendMode::kDstOut:
- case SkBlendMode::kScreen:
- gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- break;
- default:
- DCHECK(use_blend_equation_advanced_);
- gl_->BlendEquation(GL_FUNC_ADD);
- }
-}
-
-bool GLRenderer::ShouldApplyBackdropFilters(
- const DrawRenderPassDrawQuadParams* params) {
- if (!params->backdrop_filters)
- return false;
- if (params->quad->shared_quad_state->opacity == 0.f)
- return false;
- DCHECK(!params->backdrop_filters->IsEmpty());
- return true;
-}
-
-gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad(
- DrawRenderPassDrawQuadParams* params,
- gfx::Transform* backdrop_filter_bounds_transform,
- absl::optional<gfx::RRectF>* backdrop_filter_bounds,
- gfx::Rect* unclipped_rect) const {
- DCHECK(backdrop_filter_bounds_transform);
- DCHECK(backdrop_filter_bounds);
- DCHECK(unclipped_rect);
-
- const auto* quad = params->quad.get();
- gfx::QuadF scaled_region;
- // |scaled_region| is a quad in [-0.5,0.5] space that represents |clip_region|
- // as a fraction of the space defined by |quad->rect|. If |clip_region| is
- // nullptr, then scaled_region is [-0.5,0.5].
- if (!GetScaledRegion(quad->rect, params->clip_region, &scaled_region)) {
- scaled_region = SharedGeometryQuad().BoundingBox();
- }
- // |backdrop_filter_bounds| is a rounded rect in [-0.5,0.5] space that
- // represents |params->backdrop_filter_bounds| as a fraction of the space
- // defined by |quad->rect|, not including its offset.
- *backdrop_filter_bounds = gfx::RRectF();
- if (!params->backdrop_filter_bounds ||
- !GetScaledRRectF(quad->rect, params->backdrop_filter_bounds.value(),
- &backdrop_filter_bounds->value())) {
- backdrop_filter_bounds->reset();
- }
-
- // |backdrop_rect| is now the bounding box of clip_region, in window pixel
- // coordinates, and with flip applied.
- gfx::Rect backdrop_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect(
- params->contents_device_transform, scaled_region.BoundingBox()));
-
- if (!backdrop_rect.IsEmpty() && (params->filters || params->use_aa)) {
- // If we have regular filters or antialiasing, grab an extra one-pixel
- // border around the background, so texture edge clamping gives us a
- // transparent border.
- backdrop_rect.Inset(-1);
- }
-
- *unclipped_rect = backdrop_rect;
- backdrop_rect.Intersect(MoveFromDrawToWindowSpace(
- current_frame()->current_render_pass->output_rect));
- if (ShouldApplyBackdropFilters(params)) {
- float max_pixel_movement = params->backdrop_filters->MaximumPixelMovement();
- gfx::Rect scissor_rect(current_window_space_viewport_);
- scissor_rect.Inset(-max_pixel_movement);
- backdrop_rect.Intersect(scissor_rect);
- }
-
- // The frame buffer flip is already included in the captured backdrop image,
- // and it is included in |contents_device_transform| (through
- // |projection_matrix|). Don't double-flip.
- *backdrop_filter_bounds_transform = params->contents_device_transform;
- float new_y = 2 * backdrop_filter_bounds_transform->To2dTranslation().y() +
- backdrop_rect.bottom() - unclipped_rect->bottom() +
- backdrop_rect.y() - unclipped_rect->y();
- backdrop_filter_bounds_transform->PostScale(1, -1);
- backdrop_filter_bounds_transform->PostTranslate(0, new_y);
-
- // Shift to the space of the captured backdrop image.
- backdrop_filter_bounds_transform->PostTranslate(-backdrop_rect.x(),
- -backdrop_rect.y());
-
- return backdrop_rect;
-}
-
-GLenum GLRenderer::GetFramebufferCopyTextureFormat() {
- // If copying a non-root renderpass then use the format of the bound
- // texture. Otherwise, we use the format of the default framebuffer. But
- // whatever the format is, convert it to a valid format for CopyTexSubImage2D.
- GLenum format;
- if (!current_framebuffer_texture_) {
- format = output_surface_->GetFramebufferCopyTextureFormat();
- } else {
- ResourceFormat resource_format = CurrentRenderPassResourceFormat();
- DCHECK(GLSupportsFormat(resource_format));
- format = GLCopyTextureInternalFormat(resource_format);
- }
- // Verify the format is valid for GLES2's glCopyTexSubImage2D.
- DCHECK(format == GL_ALPHA || format == GL_LUMINANCE ||
- format == GL_LUMINANCE_ALPHA || format == GL_RGB ||
- format == GL_RGBA ||
- (output_surface_->context_provider()
- ->ContextCapabilities()
- .texture_format_bgra8888 &&
- format == GL_BGRA_EXT) ||
- format == GL_RGB10_A2_EXT)
- << std::hex << std::showbase << format;
- return format;
-}
-
-uint32_t GLRenderer::GetBackdropTexture(const gfx::Rect& window_rect,
- float scale,
- GLenum* internal_format) {
- DCHECK(internal_format);
- DCHECK_GE(window_rect.x(), 0);
- DCHECK_GE(window_rect.y(), 0);
- DCHECK_LE(window_rect.right(), current_surface_size_.width());
- DCHECK_LE(window_rect.bottom(), current_surface_size_.height());
-
- uint32_t texture_id;
- gl_->GenTextures(1, &texture_id);
- DCHECK(texture_id);
- gl_->BindTexture(GL_TEXTURE_2D, texture_id);
-
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- ResourceFormat resource_format = CurrentRenderPassResourceFormat();
- // Get gl_format, gl_type and internal_format.
- DCHECK(GLSupportsFormat(resource_format));
- *internal_format = GLInternalFormat(resource_format);
- GLenum gl_format = GLDataFormat(resource_format);
- GLenum gl_type = GLDataType(resource_format);
-
- if (supports_multi_sampling_ && scale != 1.0f) {
- DCHECK(!prefer_draw_to_copy_ || !current_framebuffer_texture_);
-
- gfx::Size target_size = window_rect.size();
- target_size = gfx::ScaleToCeiledSize(target_size, scale);
-
- gl_->TexImage2D(GL_TEXTURE_2D, 0, *internal_format, target_size.width(),
- target_size.height(), 0, gl_format, gl_type, nullptr);
-
- unsigned fbo = 0;
- gl_->GenFramebuffers(1, &fbo);
- gl_->BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
- gl_->FramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture_id, 0);
- DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
- gl_->CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER_EXT));
-
- gl_->Scissor(0, 0, target_size.width(), target_size.height());
-
- gl_->BlitFramebufferCHROMIUM(window_rect.x(), window_rect.y(),
- window_rect.right(), window_rect.bottom(), 0,
- 0, target_size.width(), target_size.height(),
- GL_COLOR_BUFFER_BIT, GL_LINEAR);
-
- gl_->DeleteFramebuffers(1, &fbo);
- } else if (prefer_draw_to_copy_ && current_framebuffer_texture_) {
- // If there is a source texture |current_framebuffer_texture_| and the
- // workaround |prefer_draw_to_copy_| is enabled, then do texture to texture
- // copy via draw instead of glCopyTexImage2D.
-
- // Size the destination texture with empty data. This is required since
- // CopySubTextureCHROMIUM() does not sizes the texture but CopyTexImage2D
- // does.
- gl_->TexImage2D(GL_TEXTURE_2D, 0, *internal_format, window_rect.width(),
- window_rect.height(), 0, gl_format, gl_type, nullptr);
- gl_->CopySubTextureCHROMIUM(
- current_framebuffer_texture_->id(), 0, GL_TEXTURE_2D, texture_id, 0, 0,
- 0, window_rect.x(), window_rect.y(), window_rect.width(),
- window_rect.height(), GL_FALSE, GL_FALSE, GL_FALSE);
- } else {
- *internal_format = GetFramebufferCopyTextureFormat();
-
- // CopyTexImage2D requires inernalformat channels to be a subset of
- // the channels of the source texture internalformat.
- DCHECK(*internal_format == GL_RGB || *internal_format == GL_RGBA ||
- *internal_format == GL_BGRA_EXT ||
- *internal_format == GL_RGB10_A2_EXT);
- if (*internal_format == GL_BGRA_EXT)
- *internal_format = GL_RGBA;
- gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, *internal_format, window_rect.x(),
- window_rect.y(), window_rect.width(),
- window_rect.height(), 0);
- }
- gl_->BindTexture(GL_TEXTURE_2D, 0);
- return texture_id;
-}
-
-static sk_sp<SkImage> FinalizeImage(sk_sp<SkSurface> surface) {
- // Flush the drawing before source texture read lock goes out of scope.
- // Skia API does not guarantee that when the SkImage goes out of scope,
- // its externally referenced resources would force the rendering to be
- // flushed.
- surface->getCanvas()->flush();
- sk_sp<SkImage> image = surface->makeImageSnapshot();
- if (!image || !image->isTextureBacked()) {
- return nullptr;
- }
- return image;
-}
-
-sk_sp<SkImage> GLRenderer::ApplyBackdropFilters(
- DrawRenderPassDrawQuadParams* params,
- const gfx::Rect& unclipped_rect,
- const absl::optional<gfx::RRectF>& backdrop_filter_bounds,
- const gfx::Transform& backdrop_filter_bounds_transform) {
- DCHECK(ShouldApplyBackdropFilters(params));
- DCHECK(params->backdrop_filter_quality > 0.0f &&
- params->backdrop_filter_quality <= 1.0f);
- DCHECK(!params->filters)
- << "Filters should always be in a separate Effect node";
- const auto* quad = params->quad.get();
- auto use_gr_context = ScopedUseGrContext::Create(this);
-
- // Check if cached result can be used
- auto bg_texture_it =
- render_pass_backdrop_textures_.find(quad->render_pass_id);
- if (bg_texture_it != render_pass_backdrop_textures_.end()) {
- if (!quad->intersects_damage_under)
- return bg_texture_it->second;
- else
- render_pass_backdrop_textures_.erase(bg_texture_it);
- }
-
- gfx::Vector2d clipping_offset =
- (params->background_rect.top_right() - unclipped_rect.top_right()) +
- (params->background_rect.bottom_left() - unclipped_rect.bottom_left());
-
- gfx::Rect quality_adjusted_rect = ScaleToEnclosingRect(
- params->background_rect, params->backdrop_filter_quality);
-
- // When backdrop_filter_quality is less than 1.0f, scale the blur amount
- // accordingly.
- cc::FilterOperations filter_operations;
- if (params->backdrop_filter_quality < 1.0f) {
- for (const cc::FilterOperation& op :
- params->backdrop_filters->operations()) {
- if (op.type() == cc::FilterOperation::BLUR) {
- cc::FilterOperation blur_op(op);
- blur_op.set_amount(op.amount() * params->backdrop_filter_quality);
- filter_operations.Append(blur_op);
- } else {
- filter_operations.Append(op);
- }
- }
- }
- const cc::FilterOperations& filters = params->backdrop_filter_quality < 1.0f
- ? filter_operations
- : *params->backdrop_filters;
-
- auto paint_filter = cc::RenderSurfaceFilters::BuildImageFilter(
- filters, gfx::SizeF(quality_adjusted_rect.size()),
- gfx::Vector2dF(clipping_offset));
-
- // TODO(senorblanco): background filters should be moved to the
- // makeWithFilter fast-path, and go back to calling ApplyImageFilter().
- // See http://crbug.com/613233.
- if (!paint_filter || !use_gr_context)
- return nullptr;
-
- auto filter = paint_filter->cached_sk_filter_;
- sk_sp<SkImage> src_image = WrapTexture(
- params->background_texture, GL_TEXTURE_2D, quality_adjusted_rect.size(),
- use_gr_context->context(), /*flip_texture=*/true,
- GlFormatToSkFormat(params->background_texture_format),
- /*adopt_texture=*/false);
- if (!src_image) {
- TRACE_EVENT_INSTANT0("cc",
- "ApplyBackdropFilters wrap background texture failed",
- TRACE_EVENT_SCOPE_THREAD);
- return nullptr;
- }
-
- // Create surface to draw into.
- SkImageInfo dst_info = SkImageInfo::MakeN32Premul(
- quality_adjusted_rect.width(), quality_adjusted_rect.height());
- sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
- use_gr_context->context(), SkBudgeted::kYes, dst_info);
- if (!surface) {
- TRACE_EVENT_INSTANT0("viz",
- "ApplyBackdropFilters surface allocation failed",
- TRACE_EVENT_SCOPE_THREAD);
- return nullptr;
- }
-
- // Big filters can sometimes fallback to CPU. Therefore, we need
- // to disable subnormal floats for performance and security reasons.
- cc::ScopedSubnormalFloatDisabler disabler;
-
- gfx::RectF src_image_rect =
- gfx::RectF(quality_adjusted_rect.width(), quality_adjusted_rect.height());
- SkRect dest_rect = RectToSkRect(gfx::Rect(quality_adjusted_rect.size()));
-
- // If the content underneath the backdrop filter can be exposed because of
- // blending or bounds, paint the backdrop at full opacity first. The
- // backdrop-filtered content will not be blended with the backdrop later, it
- // will be rastered over the top. So we need to paint it here, unfiltered.
- if (backdrop_filter_bounds.has_value() || quad->ShouldDrawWithBlending()) {
- surface->getCanvas()->drawImageRect(
- src_image, RectFToSkRect(src_image_rect), dest_rect,
- SkSamplingOptions(), nullptr, SkCanvas::kStrict_SrcRectConstraint);
- }
-
- if (backdrop_filter_bounds.has_value()) {
- // Crop the source image to the backdrop_filter_bounds.
- gfx::Rect filter_clip = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect(
- backdrop_filter_bounds_transform, backdrop_filter_bounds->rect()));
- gfx::Rect src_rect(params->background_rect.width(),
- params->background_rect.height());
- filter_clip.Intersect(src_rect);
- if (filter_clip.IsEmpty())
- return FinalizeImage(surface);
- if (filter_clip != src_rect) {
- filter_clip = gfx::ScaleToEnclosingRect(filter_clip,
- params->backdrop_filter_quality);
- src_image = src_image->makeSubset(RectToSkIRect(filter_clip),
- use_gr_context->context());
- src_image_rect = gfx::RectF(filter_clip.width(), filter_clip.height());
- dest_rect = RectToSkRect(filter_clip);
- }
- }
-
- SkIPoint offset;
- SkIRect subset;
- sk_sp<SkImage> filtered_image = SkiaHelper::ApplyImageFilter(
- use_gr_context->context(), src_image, src_image_rect, src_image_rect,
- quad->filters_scale, std::move(filter), &offset, &subset,
- quad->filters_origin, true);
-
- // Clip the filtered image to the (rounded) bounding box of the element.
- if (backdrop_filter_bounds.has_value()) {
- surface->getCanvas()->save();
- gfx::RRectF clip_rect(backdrop_filter_bounds.value());
- surface->getCanvas()->setMatrix(
- backdrop_filter_bounds_transform.matrix().asM33());
- surface->getCanvas()->clipRRect(SkRRect(clip_rect), SkClipOp::kIntersect,
- true /* antialias */);
- surface->getCanvas()->resetMatrix();
- }
-
- SkPaint paint;
- // Paint the filtered backdrop image with opacity.
- if (quad->shared_quad_state->opacity < 1.0) {
- paint.setImageFilter(
- SkiaHelper::BuildOpacityFilter(quad->shared_quad_state->opacity));
- }
- // Now paint the pre-filtered image onto the canvas (possibly with mask
- // applied).
- surface->getCanvas()->drawImageRect(filtered_image, SkRect::Make(subset),
- dest_rect, SkSamplingOptions(), &paint,
- SkCanvas::kStrict_SrcRectConstraint);
-
- if (backdrop_filter_bounds.has_value()) {
- surface->getCanvas()->restore();
- }
-
- sk_sp<SkImage> filtered_image_texture = FinalizeImage(surface);
- if (!quad->intersects_damage_under) {
- render_pass_backdrop_textures_[params->quad->render_pass_id] =
- filtered_image_texture;
- }
- return filtered_image_texture;
-}
-
-const DrawQuad* GLRenderer::CanPassBeDrawnDirectly(
- const AggregatedRenderPass* pass) {
-#if BUILDFLAG(IS_APPLE)
- // On Macs, this path can sometimes lead to all black output.
- // TODO(enne): investigate this and remove this hack.
- return nullptr;
-#else
- // Can only collapse a single tile quad.
- if (pass->quad_list.size() != 1)
- return nullptr;
-
- const DrawQuad* quad = *pass->quad_list.BackToFrontBegin();
- // Hack: this could be supported by concatenating transforms, but
- // in practice if there is one quad, it is at the origin of the render pass
- // and has the same size as the pass.
- if (!quad->shared_quad_state->quad_to_target_transform.IsIdentity() ||
- quad->rect != pass->output_rect)
- return nullptr;
- // The quad is expected to be the entire layer so that AA edges are correct.
- if (quad->shared_quad_state->quad_layer_rect != quad->rect)
- return nullptr;
- if (quad->material != DrawQuad::Material::kTiledContent)
- return nullptr;
-
- // TODO(chrishtr): support could be added for opacity, but care needs
- // to be taken to make sure it is correct w.r.t. non-commutative filters etc.
- if (quad->shared_quad_state->opacity != 1.0f)
- return nullptr;
-
- if (quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver)
- return nullptr;
-
- const TileDrawQuad* tile_quad = TileDrawQuad::MaterialCast(quad);
- // Hack: this could be supported by passing in a subrectangle to draw
- // render pass, although in practice if there is only one quad there
- // will be no border texels on the input.
- if (tile_quad->tex_coord_rect != gfx::RectF(tile_quad->rect))
- return nullptr;
- // Tile quad features not supported in render pass shaders.
- if (tile_quad->nearest_neighbor)
- return nullptr;
- // BUG=skia:3868, Skia currently doesn't support texture rectangle inputs.
- // See also the DCHECKs about GL_TEXTURE_2D in DrawRenderPassQuad.
- GLenum target =
- resource_provider()->GetResourceTextureTarget(tile_quad->resource_id());
- if (target != GL_TEXTURE_2D)
- return nullptr;
-
- return tile_quad;
-#endif
-}
-
-void GLRenderer::DrawRenderPassQuad(const AggregatedRenderPassDrawQuad* quad,
- const gfx::QuadF* clip_region) {
- auto bypass = render_pass_bypass_quads_.find(quad->render_pass_id);
- DrawRenderPassDrawQuadParams params;
- params.quad = quad;
- params.clip_region = clip_region;
- params.window_matrix = current_frame()->window_matrix;
- params.projection_matrix = current_frame()->projection_matrix;
- params.tex_coord_rect = quad->tex_coord_rect;
- ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_,
- &timer_queries_, "kRenderPassDrawQuad");
- if (bypass != render_pass_bypass_quads_.end()) {
- DCHECK(bypass->second->material == DrawQuad::Material::kTiledContent);
- const TileDrawQuad* tile_quad = TileDrawQuad::MaterialCast(bypass->second);
- // The projection matrix used by GLRenderer has a flip. As tile texture
- // inputs are oriented opposite to framebuffer outputs, don't flip via
- // texture coords and let the projection matrix naturallyd o it.
- params.flip_texture = false;
- params.bypass_quad_texture.resource_id = tile_quad->resource_id();
- params.bypass_quad_texture.size = tile_quad->texture_size;
- DrawRenderPassQuadInternal(&params);
- } else {
- auto contents_texture_it = render_pass_textures_.find(quad->render_pass_id);
- DCHECK(contents_texture_it->second.id());
- // See above comments about texture flipping. When the input is a
- // render pass, it needs to an extra flip to be oriented correctly.
- params.flip_texture = true;
- params.contents_texture = &contents_texture_it->second;
- DrawRenderPassQuadInternal(&params);
- }
-
- if (params.background_texture) {
- gl_->DeleteTextures(1, &params.background_texture);
- params.background_texture = 0;
- }
-}
-
-void GLRenderer::DrawRenderPassQuadInternal(
- DrawRenderPassDrawQuadParams* params) {
- params->quad_to_target_transform =
- params->quad->shared_quad_state->quad_to_target_transform;
- if (!InitializeRPDQParameters(params))
- return;
-
- UpdateRPDQShadersForBlending(params);
- bool can_draw = UpdateRPDQWithSkiaFilters(params);
- // The above calls use ScopedUseGrContext which can change the bound
- // framebuffer, so we need to restore it for the current RenderPass.
- UseRenderPass(current_frame()->current_render_pass);
- // As part of restoring the framebuffer, we call SetViewport directly, rather
- // than through PrepareSurfaceForPass. PrepareSurfaceForPass also clears the
- // surface, which is not desired when restoring.
- SetViewport();
-
- if (!can_draw)
- return;
-
- UpdateRPDQTexturesForSampling(params);
- UpdateRPDQBlendMode(params);
- ChooseRPDQProgram(params, CurrentRenderPassColorSpace());
- UpdateRPDQUniforms(params);
- DrawRPDQ(*params);
-
- AccumulateDrawRects(params->quad->visible_rect,
- params->quad->shared_quad_state->quad_to_target_transform,
- &drawn_rects_);
-}
-
-bool GLRenderer::InitializeRPDQParameters(
- DrawRenderPassDrawQuadParams* params) {
- DCHECK(params);
- const auto* quad = params->quad.get();
- SkMatrix local_matrix;
- local_matrix.setTranslate(quad->filters_origin.x(), quad->filters_origin.y());
- local_matrix.postScale(quad->filters_scale.x(), quad->filters_scale.y());
- params->filters = FiltersForPass(quad->render_pass_id);
- params->backdrop_filters = BackdropFiltersForPass(quad->render_pass_id);
- if (ShouldApplyBackdropFilters(params)) {
- params->backdrop_filter_bounds =
- BackdropFilterBoundsForPass(quad->render_pass_id);
- if (params->backdrop_filter_bounds.has_value()) {
- params->backdrop_filter_bounds->Scale(quad->filters_scale.x(),
- quad->filters_scale.y());
- }
- } else {
- params->backdrop_filter_bounds.reset();
- }
- params->backdrop_filter_quality = quad->backdrop_filter_quality;
- gfx::Rect dst_rect = params->filters
- ? params->filters->MapRect(quad->rect, local_matrix)
- : quad->rect;
- params->dst_rect.SetRect(static_cast<float>(dst_rect.x()),
- static_cast<float>(dst_rect.y()),
- static_cast<float>(dst_rect.width()),
- static_cast<float>(dst_rect.height()));
- gfx::Transform quad_rect_matrix;
- gfx::Rect quad_layer_rect(quad->shared_quad_state->quad_layer_rect);
- if (params->filters)
- quad_layer_rect = params->filters->MapRect(quad_layer_rect, local_matrix);
- QuadRectTransform(&quad_rect_matrix, params->quad_to_target_transform,
- gfx::RectF(quad_layer_rect));
- params->contents_device_transform =
- params->window_matrix * params->projection_matrix * quad_rect_matrix;
- params->contents_device_transform.FlattenTo2d();
-
- // Can only draw surface if device matrix is invertible.
- if (!params->contents_device_transform.IsInvertible())
- return false;
-
- // TODO(sunxd): unify the anti-aliasing logic of RPDQ and TileDrawQuad.
- params->surface_quad = SharedGeometryQuad();
- gfx::QuadF device_layer_quad;
- if (settings_->allow_antialiasing && !quad->force_anti_aliasing_off &&
- quad->IsEdge()) {
- bool clipped = false;
- device_layer_quad = cc::MathUtil::MapQuad(params->contents_device_transform,
- params->surface_quad, &clipped);
- params->use_aa = ShouldAntialiasQuad(device_layer_quad, clipped,
- settings_->force_antialiasing);
- }
-
- const gfx::QuadF* aa_quad = params->use_aa ? &device_layer_quad : nullptr;
- SetupRenderPassQuadForClippingAndAntialiasing(
- params->contents_device_transform, quad, aa_quad, params->clip_region,
- &params->surface_quad, params->edge);
-
- return true;
-}
-
-// Get a GL texture id from an SkImage. An optional origin pointer can be
-// passed in which will be filled out with the origin for the texture
-// backing the SkImage.
-static GLuint GetGLTextureIDFromSkImage(const SkImage* image,
- GrSurfaceOrigin* origin = nullptr) {
- GrBackendTexture backend_texture = image->getBackendTexture(true, origin);
- if (!backend_texture.isValid()) {
- return 0;
- }
- GrGLTextureInfo info;
- bool result = backend_texture.getGLTextureInfo(&info);
- DCHECK(result);
- return info.fID;
-}
-
-void GLRenderer::UpdateRPDQShadersForBlending(
- DrawRenderPassDrawQuadParams* params) {
- const auto* quad = params->quad.get();
- params->blend_mode = quad->shared_quad_state->blend_mode;
- params->use_shaders_for_blending =
- !CanApplyBlendModeUsingBlendFunc(params->blend_mode) ||
- ShouldApplyBackdropFilters(params) ||
- settings_->force_blending_with_shaders;
-
- if (params->use_shaders_for_blending) {
- // Compute a bounding box around the pixels that will be visible through
- // the quad.
- absl::optional<gfx::RRectF> backdrop_filter_bounds;
- gfx::Transform backdrop_filter_bounds_transform;
- gfx::Rect unclipped_rect;
- params->background_rect = GetBackdropBoundingBoxForRenderPassQuad(
- params, &backdrop_filter_bounds_transform, &backdrop_filter_bounds,
- &unclipped_rect);
-
- if (!params->background_rect.IsEmpty()) {
- // The pixels from the filtered background should completely replace the
- // current pixel values.
- if (blend_enabled())
- SetBlendEnabled(false);
-
- // Read the pixels in the bounding box into a buffer R.
- // This function allocates a texture, which should contribute to the
- // amount of memory used by render surfaces:
- // LayerTreeHost::CalculateMemoryForRenderSurfaces.
- const auto& operations = params->backdrop_filters->operations();
- DCHECK(params->backdrop_filter_quality == 1.0f ||
- (operations.size() == 1 &&
- operations.front().type() == cc::FilterOperation::BLUR));
- params->background_texture = GetBackdropTexture(
- params->background_rect, params->backdrop_filter_quality,
- &params->background_texture_format);
-
- if (ShouldApplyBackdropFilters(params)) {
- // Apply the background filters to R, so that it is applied in the
- // pixels' coordinate space.
- params->background_image =
- ApplyBackdropFilters(params, unclipped_rect, backdrop_filter_bounds,
- backdrop_filter_bounds_transform);
- if (params->background_image) {
- params->background_image_id =
- GetGLTextureIDFromSkImage(params->background_image.get());
- DCHECK(params->background_image_id || IsContextLost());
- }
- }
- if (params->background_image_id) {
- // Reset original background texture if there is not any mask.
- if (!quad->mask_resource_id()) {
- gl_->DeleteTextures(1, &params->background_texture);
- params->background_texture = 0;
- }
- } else if (CanApplyBlendModeUsingBlendFunc(params->blend_mode) &&
- ShouldApplyBackdropFilters(params)) {
- // Something went wrong with applying backdrop filters to the
- // backdrop.
- params->use_shaders_for_blending = false;
- gl_->DeleteTextures(1, &params->background_texture);
- params->background_texture = 0;
- }
- } else { // params->background_rect.IsEmpty()
- DCHECK(!params->background_image_id);
- params->use_shaders_for_blending = false;
- params->blend_mode = SkBlendMode::kSrcOver;
- }
- }
-
- // Need original background texture for mask?
- params->mask_for_background =
- params->background_texture && // Have original background texture
- params->background_image_id; // Have mask texture
- // If we have background texture + background image, then we also have mask
- // resource.
- if (params->background_texture && params->background_image_id) {
- DCHECK(params->mask_for_background);
- DCHECK(quad->mask_resource_id());
- }
-
- DCHECK_EQ(params->background_texture || params->background_image_id,
- params->use_shaders_for_blending);
-}
-
-bool GLRenderer::UpdateRPDQWithSkiaFilters(
- DrawRenderPassDrawQuadParams* params) {
- const auto* quad = params->quad.get();
- // Apply filters to the contents texture.
- if (params->filters) {
- DCHECK(!params->filters->IsEmpty());
- gfx::Size size = params->contents_texture
- ? params->contents_texture->size()
- : params->bypass_quad_texture.size;
- auto paint_filter = cc::RenderSurfaceFilters::BuildImageFilter(
- *params->filters, gfx::SizeF(size));
- auto filter = paint_filter ? paint_filter->cached_sk_filter_ : nullptr;
- if (filter) {
- SkColorFilter* colorfilter_rawptr = nullptr;
- filter->asColorFilter(&colorfilter_rawptr);
- sk_sp<SkColorFilter> cf(colorfilter_rawptr);
-
- if (cf && cf->asAColorMatrix(params->color_matrix)) {
- // We have a color matrix at the root of the filter DAG; apply it
- // locally in the compositor and process the rest of the DAG (if any)
- // in Skia.
- params->use_color_matrix = true;
- filter = sk_ref_sp(filter->getInput(0));
- }
- if (filter) {
- gfx::Rect clip_rect =
- quad->shared_quad_state->clip_rect.value_or(current_draw_rect_);
- gfx::Transform transform = params->quad_to_target_transform;
- transform.FlattenTo2d();
- if (!transform.IsInvertible()) {
- return false;
- }
- // If the transform has perspective, there might be visible content
- // outside of the bounds of the quad.
- if (!transform.HasPerspective()) {
- gfx::QuadF clip_quad = gfx::QuadF(gfx::RectF(clip_rect));
- gfx::QuadF local_clip =
- cc::MathUtil::InverseMapQuadToLocalSpace(transform, clip_quad);
- params->dst_rect.Intersect(local_clip.BoundingBox());
- }
- // If we've been fully clipped out (by crop rect or clipping), there's
- // nothing to draw.
- if (params->dst_rect.IsEmpty()) {
- return false;
- }
- SkIPoint offset;
- SkIRect subset;
- gfx::RectF src_rect(quad->rect);
- auto use_gr_context = ScopedUseGrContext::Create(this);
- if (!use_gr_context)
- return false;
-
- if (params->contents_texture) {
- params->contents_and_bypass_color_space =
- params->contents_texture->color_space();
- sk_sp<SkImage> src_image = WrapTexture(
- params->contents_texture->id(), GL_TEXTURE_2D,
- params->contents_texture->size(), use_gr_context->context(),
- params->flip_texture, kN32_SkColorType, /*adopt_texture=*/false);
- params->filter_image = SkiaHelper::ApplyImageFilter(
- use_gr_context->context(), src_image, src_rect, params->dst_rect,
- quad->filters_scale, std::move(filter), &offset, &subset,
- quad->filters_origin, true);
- } else {
- DisplayResourceProviderGL::ScopedReadLockGL
- prefilter_bypass_quad_texture_lock(
- resource_provider(), params->bypass_quad_texture.resource_id);
- params->contents_and_bypass_color_space =
- prefilter_bypass_quad_texture_lock.color_space();
- sk_sp<SkImage> src_image =
- WrapTexture(prefilter_bypass_quad_texture_lock.texture_id(),
- prefilter_bypass_quad_texture_lock.target(),
- prefilter_bypass_quad_texture_lock.size(),
- use_gr_context->context(), params->flip_texture,
- kN32_SkColorType, /*adopt_texture=*/false);
- params->filter_image = SkiaHelper::ApplyImageFilter(
- use_gr_context->context(), src_image, src_rect, params->dst_rect,
- quad->filters_scale, std::move(filter), &offset, &subset,
- quad->filters_origin, true);
- }
-
- if (!params->filter_image)
- return false;
- params->dst_rect =
- gfx::RectF(src_rect.x() + offset.fX, src_rect.y() + offset.fY,
- subset.width(), subset.height());
- gfx::RectF tex_rect = gfx::RectF(gfx::PointF(subset.x(), subset.y()),
- params->dst_rect.size());
- params->tex_coord_rect = tex_rect;
- }
- }
- }
- return true;
-}
-
-void GLRenderer::UpdateRPDQTexturesForSampling(
- DrawRenderPassDrawQuadParams* params) {
- if (params->quad->mask_resource_id()) {
- params->mask_resource_lock =
- std::make_unique<DisplayResourceProviderGL::ScopedSamplerGL>(
-
- resource_provider(), params->quad->mask_resource_id(), GL_TEXTURE1,
- GL_LINEAR);
- }
-
- if (params->filter_image) {
- GrSurfaceOrigin origin;
- GLuint filter_image_id =
- GetGLTextureIDFromSkImage(params->filter_image.get(), &origin);
- DCHECK(filter_image_id || IsContextLost());
- DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- gl_->BindTexture(GL_TEXTURE_2D, filter_image_id);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- // |params->contents_and_bypass_color_space| was populated when
- // |params->filter_image| was populated.
- params->source_needs_flip = kBottomLeft_GrSurfaceOrigin == origin;
- } else if (params->contents_texture) {
- params->contents_texture->BindForSampling();
- params->contents_and_bypass_color_space =
- params->contents_texture->color_space();
- params->source_needs_flip = params->flip_texture;
- } else {
- params->bypass_quad_resource_lock =
- std::make_unique<DisplayResourceProviderGL::ScopedSamplerGL>(
- resource_provider(), params->bypass_quad_texture.resource_id,
- GL_LINEAR);
- DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
- params->bypass_quad_resource_lock->target());
- params->contents_and_bypass_color_space =
- params->bypass_quad_resource_lock->color_space();
- params->source_needs_flip = params->flip_texture;
- }
-}
-
-void GLRenderer::UpdateRPDQBlendMode(DrawRenderPassDrawQuadParams* params) {
- SkBlendMode blend_mode = params->blend_mode;
- SetBlendEnabled((!params->use_shaders_for_blending &&
- (params->quad->ShouldDrawWithBlending() ||
- !IsDefaultBlendMode(blend_mode))) ||
- ShouldApplyRoundedCorner(params->quad));
- if (!params->use_shaders_for_blending) {
- if (!use_blend_equation_advanced_coherent_ && use_blend_equation_advanced_)
- gl_->BlendBarrierKHR();
-
- ApplyBlendModeUsingBlendFunc(blend_mode);
- }
-}
-
-void GLRenderer::ChooseRPDQProgram(DrawRenderPassDrawQuadParams* params,
- const gfx::ColorSpace& target_color_space) {
- TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
- params->quad->shared_quad_state->visible_quad_layer_rect.size());
-
- BlendMode shader_blend_mode =
- params->use_shaders_for_blending
- ? BlendModeFromSkXfermode(params->blend_mode)
- : BLEND_MODE_NONE;
-
- SamplerType sampler_type = SAMPLER_TYPE_2D;
- MaskMode mask_mode = NO_MASK;
- bool mask_for_background = params->mask_for_background;
- if (params->mask_resource_lock) {
- mask_mode = HAS_MASK;
- sampler_type =
- SamplerTypeFromTextureTarget(params->mask_resource_lock->target());
- }
- SetUseProgram(
- ProgramKey::RenderPass(
- tex_coord_precision, sampler_type, shader_blend_mode,
- params->use_aa ? USE_AA : NO_AA, mask_mode, mask_for_background,
- params->use_color_matrix, tint_gl_composited_content_,
- params->apply_shader_based_rounded_corner &&
- ShouldApplyRoundedCorner(params->quad)),
- params->contents_and_bypass_color_space, target_color_space);
-}
-
-void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) {
- gfx::RectF tex_rect = params->tex_coord_rect;
-
- gfx::Size texture_size;
- if (params->filter_image) {
- texture_size.set_width(params->filter_image->width());
- texture_size.set_height(params->filter_image->height());
- } else if (params->contents_texture) {
- texture_size = params->contents_texture->size();
- } else {
- texture_size = params->bypass_quad_texture.size;
- }
-
- tex_rect.Scale(1.0f / texture_size.width(), 1.0f / texture_size.height());
-
- DCHECK(current_program_->vertex_tex_transform_location() != -1 ||
- IsContextLost());
- if (params->source_needs_flip) {
- // Flip the content vertically in the shader, as the RenderPass input
- // texture is already oriented the same way as the framebuffer, but the
- // projection transform does a flip.
- gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
- tex_rect.x(), 1.0f - tex_rect.y(), tex_rect.width(),
- -tex_rect.height());
- } else {
- // Tile textures are oriented opposite the framebuffer, so can use
- // the projection transform to do the flip.
- gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
- tex_rect.x(), tex_rect.y(), tex_rect.width(),
- tex_rect.height());
- }
-
- GLint last_texture_unit = 0;
- if (current_program_->mask_sampler_location() != -1) {
- DCHECK(params->mask_resource_lock);
- DCHECK_NE(current_program_->mask_tex_coord_scale_location(), 1);
- DCHECK_NE(current_program_->mask_tex_coord_offset_location(), 1);
- gl_->Uniform1i(current_program_->mask_sampler_location(), 1);
-
- gfx::RectF mask_uv_rect = params->quad->mask_uv_rect;
- if (SamplerTypeFromTextureTarget(params->mask_resource_lock->target()) !=
- SAMPLER_TYPE_2D) {
- mask_uv_rect.Scale(params->quad->mask_texture_size.width(),
- params->quad->mask_texture_size.height());
- }
-
- SkMatrix tex_to_mask = SkMatrix::RectToRect(RectFToSkRect(tex_rect),
- RectFToSkRect(mask_uv_rect));
-
- if (params->source_needs_flip) {
- // Mask textures are oriented vertically flipped relative to the
- // framebuffer and the RenderPass contents texture, so we flip the tex
- // coords from the RenderPass texture to find the mask texture coords.
- tex_to_mask.preTranslate(0, 1);
- tex_to_mask.preScale(1, -1);
- }
-
- gl_->Uniform2f(current_program_->mask_tex_coord_offset_location(),
- tex_to_mask.getTranslateX(), tex_to_mask.getTranslateY());
- gl_->Uniform2f(current_program_->mask_tex_coord_scale_location(),
- tex_to_mask.getScaleX(), tex_to_mask.getScaleY());
- last_texture_unit = 1;
- }
-
- if (current_program_->edge_location() != -1)
- gl_->Uniform3fv(current_program_->edge_location(), 8, params->edge);
-
- if (current_program_->color_matrix_location() != -1) {
- float matrix[16];
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j)
- matrix[i * 4 + j] = SkScalarToFloat(params->color_matrix[j * 5 + i]);
- }
- gl_->UniformMatrix4fv(current_program_->color_matrix_location(), 1, false,
- matrix);
- }
-
- if (current_program_->color_offset_location() != -1) {
- float offset[4];
- for (int i = 0; i < 4; ++i)
- offset[i] = params->color_matrix[i * 5 + 4];
-
- gl_->Uniform4fv(current_program_->color_offset_location(), 1, offset);
- }
-
- if (current_program_->tint_color_matrix_location() != -1) {
- auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
- gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
- false, matrix.data());
- }
-
- if (current_program_->backdrop_location() != -1) {
- DCHECK(params->background_texture || params->background_image_id);
- DCHECK_NE(current_program_->backdrop_location(), 0);
- DCHECK_NE(current_program_->backdrop_rect_location(), 0);
-
- ++last_texture_unit;
- gl_->Uniform1i(current_program_->backdrop_location(), last_texture_unit);
-
- gl_->Uniform4f(current_program_->backdrop_rect_location(),
- params->background_rect.x(), params->background_rect.y(),
- 1.0f / params->background_rect.width(),
- 1.0f / params->background_rect.height());
-
- // Either |background_image_id| or |background_texture| will be the
- // |backdrop_location| in the shader.
- if (params->background_image_id) {
- gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit);
- gl_->BindTexture(GL_TEXTURE_2D, params->background_image_id);
- if (params->backdrop_filter_quality != 1.0f)
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->ActiveTexture(GL_TEXTURE0);
- }
- // If |mask_for_background| then we have both |background_image_id| and
- // |background_texture|, and the latter will be the
- // |original_backdrop_location| in the shader.
- if (params->mask_for_background) {
- DCHECK(params->background_image_id);
- DCHECK(params->background_texture);
- ++last_texture_unit;
- gl_->Uniform1i(current_program_->original_backdrop_location(),
- last_texture_unit);
- }
- if (params->background_texture) {
- gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit);
- gl_->BindTexture(GL_TEXTURE_2D, params->background_texture);
- gl_->ActiveTexture(GL_TEXTURE0);
- }
- }
-
- SetShaderOpacity(params->quad->shared_quad_state->opacity);
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(params->quad->shared_quad_state->mask_filter_info
- .rounded_corner_bounds(),
- params->window_matrix * params->projection_matrix);
- }
- SetShaderQuadF(params->surface_quad);
-}
-
-void GLRenderer::DrawRPDQ(const DrawRenderPassDrawQuadParams& params) {
- DrawQuadGeometry(params.projection_matrix, params.quad_to_target_transform,
- params.dst_rect);
-
- // Flush the compositor context before the filter bitmap goes out of
- // scope, so the draw gets processed before the filter texture gets deleted.
- if (params.filter_image)
- gl_->Flush();
-
- if (!params.use_shaders_for_blending)
- RestoreBlendFuncToDefault(params.blend_mode);
-}
-
-namespace {
-// These functions determine if a quad, clipped by a clip_region contains
-// the entire {top|bottom|left|right} edge.
-bool is_top(const gfx::QuadF* clip_region, const DrawQuad* quad) {
- if (!quad->IsTopEdge())
- return false;
- if (!clip_region)
- return true;
-
- return std::abs(clip_region->p1().y()) < kAntiAliasingEpsilon &&
- std::abs(clip_region->p2().y()) < kAntiAliasingEpsilon;
-}
-
-bool is_bottom(const gfx::QuadF* clip_region, const DrawQuad* quad) {
- if (!quad->IsBottomEdge())
- return false;
- if (!clip_region)
- return true;
-
- return std::abs(clip_region->p3().y() -
- quad->shared_quad_state->quad_layer_rect.height()) <
- kAntiAliasingEpsilon &&
- std::abs(clip_region->p4().y() -
- quad->shared_quad_state->quad_layer_rect.height()) <
- kAntiAliasingEpsilon;
-}
-
-bool is_left(const gfx::QuadF* clip_region, const DrawQuad* quad) {
- if (!quad->IsLeftEdge())
- return false;
- if (!clip_region)
- return true;
-
- return std::abs(clip_region->p1().x()) < kAntiAliasingEpsilon &&
- std::abs(clip_region->p4().x()) < kAntiAliasingEpsilon;
-}
-
-bool is_right(const gfx::QuadF* clip_region, const DrawQuad* quad) {
- if (!quad->IsRightEdge())
- return false;
- if (!clip_region)
- return true;
-
- return std::abs(clip_region->p2().x() -
- quad->shared_quad_state->quad_layer_rect.width()) <
- kAntiAliasingEpsilon &&
- std::abs(clip_region->p3().x() -
- quad->shared_quad_state->quad_layer_rect.width()) <
- kAntiAliasingEpsilon;
-}
-} // anonymous namespace
-
-static gfx::QuadF GetDeviceQuadWithAntialiasingOnExteriorEdges(
- const LayerQuad& device_layer_edges,
- const gfx::Transform& device_transform,
- const gfx::QuadF& tile_quad,
- const gfx::QuadF* clip_region,
- const DrawQuad* quad) {
- auto tile_rect = gfx::RectF(quad->visible_rect);
-
- gfx::PointF bottom_right = tile_quad.p3();
- gfx::PointF bottom_left = tile_quad.p4();
- gfx::PointF top_left = tile_quad.p1();
- gfx::PointF top_right = tile_quad.p2();
- bool clipped = false;
-
- // Map points to device space. We ignore |clipped|, since the result of
- // |MapPoint()| still produces a valid point to draw the quad with. When
- // clipped, the point will be outside of the viewport. See crbug.com/416367.
- bottom_right =
- cc::MathUtil::MapPoint(device_transform, bottom_right, &clipped);
- bottom_left = cc::MathUtil::MapPoint(device_transform, bottom_left, &clipped);
- top_left = cc::MathUtil::MapPoint(device_transform, top_left, &clipped);
- top_right = cc::MathUtil::MapPoint(device_transform, top_right, &clipped);
-
- LayerQuad::Edge bottom_edge(bottom_right, bottom_left);
- LayerQuad::Edge left_edge(bottom_left, top_left);
- LayerQuad::Edge top_edge(top_left, top_right);
- LayerQuad::Edge right_edge(top_right, bottom_right);
-
- // Only apply anti-aliasing to edges not clipped by culling or scissoring.
- // If an edge is degenerate we do not want to replace it with a "proper" edge
- // as that will cause the quad to possibly expand in strange ways.
- if (!top_edge.degenerate() && is_top(clip_region, quad) &&
- tile_rect.y() == quad->rect.y()) {
- top_edge = device_layer_edges.top();
- }
- if (!left_edge.degenerate() && is_left(clip_region, quad) &&
- tile_rect.x() == quad->rect.x()) {
- left_edge = device_layer_edges.left();
- }
- if (!right_edge.degenerate() && is_right(clip_region, quad) &&
- tile_rect.right() == quad->rect.right()) {
- right_edge = device_layer_edges.right();
- }
- if (!bottom_edge.degenerate() && is_bottom(clip_region, quad) &&
- tile_rect.bottom() == quad->rect.bottom()) {
- bottom_edge = device_layer_edges.bottom();
- }
-
- float sign = tile_quad.IsCounterClockwise() ? -1 : 1;
- bottom_edge.scale(sign);
- left_edge.scale(sign);
- top_edge.scale(sign);
- right_edge.scale(sign);
-
- // Create device space quad.
- return LayerQuad(left_edge, top_edge, right_edge, bottom_edge).ToQuadF();
-}
-
-float GetTotalQuadError(const gfx::QuadF* clipped_quad,
- const gfx::QuadF* ideal_rect) {
- return (clipped_quad->p1() - ideal_rect->p1()).LengthSquared() +
- (clipped_quad->p2() - ideal_rect->p2()).LengthSquared() +
- (clipped_quad->p3() - ideal_rect->p3()).LengthSquared() +
- (clipped_quad->p4() - ideal_rect->p4()).LengthSquared();
-}
-
-// Attempt to rotate the clipped quad until it lines up the most
-// correctly. This is necessary because we check the edges of this
-// quad against the expected left/right/top/bottom for anti-aliasing.
-void AlignQuadToBoundingBox(gfx::QuadF* clipped_quad) {
- auto bounding_quad = gfx::QuadF(clipped_quad->BoundingBox());
- gfx::QuadF best_rotation = *clipped_quad;
- float least_error_amount = GetTotalQuadError(clipped_quad, &bounding_quad);
- for (size_t i = 1; i < 4; ++i) {
- clipped_quad->Realign(1);
- float new_error = GetTotalQuadError(clipped_quad, &bounding_quad);
- if (new_error < least_error_amount) {
- least_error_amount = new_error;
- best_rotation = *clipped_quad;
- }
- }
- *clipped_quad = best_rotation;
-}
-
-void InflateAntiAliasingDistances(const gfx::QuadF& quad,
- LayerQuad* device_layer_edges,
- float edge[24]) {
- DCHECK(!quad.BoundingBox().IsEmpty());
- LayerQuad device_layer_bounds(gfx::QuadF(quad.BoundingBox()));
-
- device_layer_edges->InflateAntiAliasingDistance();
- device_layer_edges->ToFloatArray(edge);
-
- device_layer_bounds.InflateAntiAliasingDistance();
- device_layer_bounds.ToFloatArray(&edge[12]);
-}
-
-// static
-bool GLRenderer::ShouldAntialiasQuad(const gfx::QuadF& device_layer_quad,
- bool clipped,
- bool force_aa) {
- // AAing clipped quads is not supported by the code yet.
- if (clipped)
- return false;
- if (device_layer_quad.BoundingBox().IsEmpty())
- return false;
- if (force_aa)
- return true;
-
- bool is_axis_aligned_in_target = device_layer_quad.IsRectilinear();
- bool is_nearest_rect_within_epsilon =
- is_axis_aligned_in_target &&
- gfx::IsNearestRectWithinDistance(device_layer_quad.BoundingBox(),
- kAntiAliasingEpsilon);
- return !is_nearest_rect_within_epsilon;
-}
-
-// static
-void GLRenderer::SetupQuadForClippingAndAntialiasing(
- const gfx::Transform& device_transform,
- const DrawQuad* quad,
- const gfx::QuadF* aa_quad,
- const gfx::QuadF* clip_region,
- gfx::QuadF* local_quad,
- float edge[24]) {
- gfx::QuadF rotated_clip;
- const gfx::QuadF* local_clip_region = clip_region;
- if (local_clip_region) {
- rotated_clip = *clip_region;
- AlignQuadToBoundingBox(&rotated_clip);
- local_clip_region = &rotated_clip;
- }
-
- if (!aa_quad) {
- if (local_clip_region)
- *local_quad = *local_clip_region;
- return;
- }
-
- LayerQuad device_layer_edges(*aa_quad);
- InflateAntiAliasingDistances(*aa_quad, &device_layer_edges, edge);
-
- // If we have a clip region then we are split, and therefore
- // by necessity, at least one of our edges is not an external
- // one.
- bool is_full_rect = quad->visible_rect == quad->rect;
-
- bool region_contains_all_outside_edges =
- is_full_rect &&
- (is_top(local_clip_region, quad) && is_left(local_clip_region, quad) &&
- is_bottom(local_clip_region, quad) && is_right(local_clip_region, quad));
-
- bool use_aa_on_all_four_edges =
- !local_clip_region && region_contains_all_outside_edges;
-
- gfx::QuadF device_quad;
- if (use_aa_on_all_four_edges) {
- device_quad = device_layer_edges.ToQuadF();
- } else {
- gfx::QuadF tile_quad(local_clip_region
- ? *local_clip_region
- : gfx::QuadF(gfx::RectF(quad->visible_rect)));
- device_quad = GetDeviceQuadWithAntialiasingOnExteriorEdges(
- device_layer_edges, device_transform, tile_quad, local_clip_region,
- quad);
- }
-
- *local_quad =
- cc::MathUtil::InverseMapQuadToLocalSpace(device_transform, device_quad);
-}
-
-// static
-void GLRenderer::SetupRenderPassQuadForClippingAndAntialiasing(
- const gfx::Transform& device_transform,
- const AggregatedRenderPassDrawQuad* quad,
- const gfx::QuadF* aa_quad,
- const gfx::QuadF* clip_region,
- gfx::QuadF* local_quad,
- float edge[24]) {
- gfx::QuadF rotated_clip;
- const gfx::QuadF* local_clip_region = clip_region;
- if (local_clip_region) {
- rotated_clip = *clip_region;
- AlignQuadToBoundingBox(&rotated_clip);
- local_clip_region = &rotated_clip;
- }
-
- if (!aa_quad) {
- GetScaledRegion(quad->rect, local_clip_region, local_quad);
- return;
- }
-
- LayerQuad device_layer_edges(*aa_quad);
- InflateAntiAliasingDistances(*aa_quad, &device_layer_edges, edge);
-
- gfx::QuadF device_quad;
-
- // Apply anti-aliasing only to the edges that are not being clipped
- if (local_clip_region) {
- gfx::QuadF tile_quad(gfx::RectF(quad->visible_rect));
- GetScaledRegion(quad->rect, local_clip_region, &tile_quad);
- device_quad = GetDeviceQuadWithAntialiasingOnExteriorEdges(
- device_layer_edges, device_transform, tile_quad, local_clip_region,
- quad);
- } else {
- device_quad = device_layer_edges.ToQuadF();
- }
-
- *local_quad =
- cc::MathUtil::InverseMapQuadToLocalSpace(device_transform, device_quad);
-}
-
-void GLRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad,
- const gfx::QuadF* clip_region) {
- gfx::Rect tile_rect = quad->visible_rect;
-
- SkColor color = quad->color;
- float opacity = quad->shared_quad_state->opacity;
-
- // Early out if alpha is small enough that quad doesn't contribute to output,
- // for kSrcOver blend mode.
- if (quad->shared_quad_state->blend_mode == SkBlendMode::kSrcOver) {
- float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
- if (alpha < std::numeric_limits<float>::epsilon() &&
- quad->ShouldDrawWithBlending() &&
- quad->shared_quad_state->blend_mode == SkBlendMode::kSrcOver)
- return;
- }
-
- gfx::Transform device_transform =
- current_frame()->window_matrix * current_frame()->projection_matrix *
- quad->shared_quad_state->quad_to_target_transform;
- device_transform.FlattenTo2d();
- if (!device_transform.IsInvertible())
- return;
-
- auto local_quad = gfx::QuadF(gfx::RectF(tile_rect));
-
- gfx::QuadF device_layer_quad;
- bool use_aa = false;
- bool allow_aa = settings_->allow_antialiasing &&
- !quad->force_anti_aliasing_off && quad->IsEdge();
-
- if (allow_aa) {
- bool clipped = false;
- bool force_aa = false;
- device_layer_quad = cc::MathUtil::MapQuad(
- device_transform,
- gfx::QuadF(
- gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)),
- &clipped);
- use_aa = ShouldAntialiasQuad(device_layer_quad, clipped, force_aa);
- }
-
- ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_,
- &timer_queries_,
- use_aa ? "kSolidColorAA" : "kSolidColor");
-
- float edge[24];
- const gfx::QuadF* aa_quad = use_aa ? &device_layer_quad : nullptr;
- SetupQuadForClippingAndAntialiasing(device_transform, quad, aa_quad,
- clip_region, &local_quad, edge);
-
- SetUseProgram(ProgramKey::SolidColor(use_aa ? USE_AA : NO_AA,
- tint_gl_composited_content_,
- ShouldApplyRoundedCorner(quad)),
- CurrentRenderPassColorSpace(), CurrentRenderPassColorSpace());
-
- gfx::ColorSpace quad_color_space = gfx::ColorSpace::CreateSRGB();
- SkColor4f color_f = SkColor4f::FromColor(color);
-
- // Apply color transform if the color space or source and target do not match.
- if (quad_color_space != CurrentRenderPassColorSpace()) {
- const gfx::ColorTransform* color_transform =
- GetColorTransform(quad_color_space, CurrentRenderPassColorSpace());
- gfx::ColorTransform::TriStim col(color_f.fR, color_f.fG, color_f.fB);
- color_transform->Transform(&col, 1);
- color_f.fR = col.x();
- color_f.fG = col.y();
- color_f.fB = col.z();
- color = color_f.toSkColor();
- }
-
- // Apply any color matrix that may be present.
- if (HasOutputColorMatrix()) {
- const SkM44& output_color_matrix = output_surface_->color_matrix();
- const SkV4 color_v{color_f.fR, color_f.fG, color_f.fB, color_f.fA};
- const SkV4 result = output_color_matrix * color_v;
- std::copy(result.ptr(), result.ptr() + 4, color_f.vec());
- color = color_f.toSkColor();
- }
-
- // Try using glClear to draw the solid color quad if possible. This is much
- // more performant than executing the shader pipeline.
- if (CanUseFastSolidColorDraw(quad) && !use_aa) {
- // Pre-multiply the alpha and opacity to get the correct blending in case of
- // transparent buffers. glClear does not have any alpha blending stage.
- Float4 result = PremultipliedColor(color, opacity);
- SkRGBA4f<kPremul_SkAlphaType> color_f_premul;
- std::copy(result.data, result.data + 4, color_f_premul.vec());
-
- gfx::RectF quad_rect_in_target_f(quad->visible_rect);
-
- device_transform.TransformRect(&quad_rect_in_target_f);
- gfx::Rect quad_rect_in_target = gfx::ToRoundedRect(quad_rect_in_target_f);
-
- // If we are using partial swap, make sure the new scissor rect is within
- // the partial swap bounds.
- if (!scissor_rect_.IsEmpty() && is_scissor_enabled_)
- quad_rect_in_target.Intersect(scissor_rect_);
-
- gl_->Enable(GL_SCISSOR_TEST);
- gl_->Scissor(quad_rect_in_target.x(), quad_rect_in_target.y(),
- quad_rect_in_target.width(), quad_rect_in_target.height());
-
- gl_->ClearColor(color_f_premul.fR, color_f_premul.fG, color_f_premul.fB,
- color_f_premul.fA);
- gl_->Clear(GL_COLOR_BUFFER_BIT);
-
- // Restore GL scissor state.
- if (is_scissor_enabled_)
- gl_->Enable(GL_SCISSOR_TEST);
- else
- gl_->Disable(GL_SCISSOR_TEST);
-
- gl_->Scissor(scissor_rect_.x(), scissor_rect_.y(), scissor_rect_.width(),
- scissor_rect_.height());
- } else {
- SetShaderColor(color, opacity);
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
- current_frame()->window_matrix * current_frame()->projection_matrix);
- }
-
- if (current_program_->tint_color_matrix_location() != -1) {
- auto matrix =
- cc::DebugColors::TintCompositedContentColorTransformMatrix();
- gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
- false, matrix.data());
- }
-
- if (use_aa) {
- gl_->Uniform3fv(current_program_->edge_location(), 8, edge);
- }
-
- // Enable blending when the quad properties require it or if we decided
- // to use antialiasing.
- SetBlendEnabled(quad->ShouldDrawWithBlending() || use_aa);
- ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
-
- // Antialiasing requires a normalized quad, but this could lead to floating
- // point precision errors, so only normalize when antialiasing is on.
- if (use_aa) {
- DrawQuadGeometryWithAA(quad, &local_quad, tile_rect);
- } else {
- PrepareGeometry(SHARED_BINDING);
- SetShaderQuadF(local_quad);
- SetShaderMatrix(current_frame()->projection_matrix *
- quad->shared_quad_state->quad_to_target_transform);
- gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
- num_triangles_drawn_ += 2;
- }
- RestoreBlendFuncToDefault(quad->shared_quad_state->blend_mode);
- }
-
- // Add the quad to the region that has been drawn.
- AccumulateDrawRects(quad->visible_rect,
- quad->shared_quad_state->quad_to_target_transform,
- &drawn_rects_);
-}
-
-void GLRenderer::DrawTileQuad(const TileDrawQuad* quad,
- const gfx::QuadF* clip_region) {
- DrawContentQuad(quad, quad->resource_id(), clip_region);
-}
-
-void GLRenderer::DrawContentQuad(const ContentDrawQuadBase* quad,
- ResourceId resource_id,
- const gfx::QuadF* clip_region) {
- gfx::Transform device_transform =
- current_frame()->window_matrix * current_frame()->projection_matrix *
- quad->shared_quad_state->quad_to_target_transform;
- device_transform.FlattenTo2d();
-
- gfx::QuadF device_layer_quad;
- bool use_aa = false;
- bool allow_aa = settings_->allow_antialiasing &&
- !quad->force_anti_aliasing_off && quad->IsEdge();
- if (allow_aa) {
- bool clipped = false;
- bool force_aa = false;
- device_layer_quad = cc::MathUtil::MapQuad(
- device_transform,
- gfx::QuadF(
- gfx::RectF(quad->shared_quad_state->visible_quad_layer_rect)),
- &clipped);
- use_aa = ShouldAntialiasQuad(device_layer_quad, clipped, force_aa);
- }
-
- // TODO(timav): simplify coordinate transformations in DrawContentQuadAA
- // similar to the way DrawContentQuadNoAA works and then consider
- // combining DrawContentQuadAA and DrawContentQuadNoAA into one method.
- if (use_aa)
- DrawContentQuadAA(quad, resource_id, device_transform, device_layer_quad,
- clip_region);
- else
- DrawContentQuadNoAA(quad, resource_id, clip_region);
-
- AccumulateDrawRects(quad->visible_rect,
- quad->shared_quad_state->quad_to_target_transform,
- &drawn_rects_);
-}
-
-void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad,
- ResourceId resource_id,
- const gfx::Transform& device_transform,
- const gfx::QuadF& aa_quad,
- const gfx::QuadF* clip_region) {
- if (!device_transform.IsInvertible())
- return;
-
- ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_,
- &timer_queries_, "kTiledContentAA");
-
- gfx::Rect tile_rect = quad->visible_rect;
-
- gfx::RectF tex_coord_rect = cc::MathUtil::ScaleRectProportional(
- quad->tex_coord_rect, gfx::RectF(quad->rect), gfx::RectF(tile_rect));
- float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width();
- float tex_to_geom_scale_y =
- quad->rect.height() / quad->tex_coord_rect.height();
-
- gfx::RectF clamp_geom_rect(tile_rect);
- gfx::RectF clamp_tex_rect(tex_coord_rect);
- // Clamp texture coordinates to avoid sampling outside the layer
- // by deflating the tile region half a texel or half a texel
- // minus epsilon for one pixel layers. The resulting clamp region
- // is mapped to the unit square by the vertex shader and mapped
- // back to normalized texture coordinates by the fragment shader
- // after being clamped to 0-1 range.
- float tex_clamp_x =
- std::min(0.5f, 0.5f * clamp_tex_rect.width() - kAntiAliasingEpsilon);
- float tex_clamp_y =
- std::min(0.5f, 0.5f * clamp_tex_rect.height() - kAntiAliasingEpsilon);
- float geom_clamp_x =
- std::min(tex_clamp_x * tex_to_geom_scale_x,
- 0.5f * clamp_geom_rect.width() - kAntiAliasingEpsilon);
- float geom_clamp_y =
- std::min(tex_clamp_y * tex_to_geom_scale_y,
- 0.5f * clamp_geom_rect.height() - kAntiAliasingEpsilon);
- clamp_geom_rect.Inset(gfx::InsetsF::VH(geom_clamp_y, geom_clamp_x));
- clamp_tex_rect.Inset(gfx::InsetsF::VH(tex_clamp_y, tex_clamp_x));
-
- // Map clamping rectangle to unit square.
- float vertex_tex_translate_x = -clamp_geom_rect.x() / clamp_geom_rect.width();
- float vertex_tex_translate_y =
- -clamp_geom_rect.y() / clamp_geom_rect.height();
- float vertex_tex_scale_x = tile_rect.width() / clamp_geom_rect.width();
- float vertex_tex_scale_y = tile_rect.height() / clamp_geom_rect.height();
-
- TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
- quad->texture_size);
-
- auto local_quad = gfx::QuadF(gfx::RectF(tile_rect));
- float edge[24];
- SetupQuadForClippingAndAntialiasing(device_transform, quad, &aa_quad,
- clip_region, &local_quad, edge);
- DisplayResourceProviderGL::ScopedSamplerGL quad_resource_lock(
- resource_provider(), resource_id,
- quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR);
- SamplerType sampler =
- SamplerTypeFromTextureTarget(quad_resource_lock.target());
-
- float fragment_tex_translate_x = clamp_tex_rect.x();
- float fragment_tex_translate_y = clamp_tex_rect.y();
- float fragment_tex_scale_x = clamp_tex_rect.width();
- float fragment_tex_scale_y = clamp_tex_rect.height();
-
- // Map to normalized texture coordinates.
- if (sampler != SAMPLER_TYPE_2D_RECT) {
- gfx::Size texture_size = quad->texture_size;
- DCHECK(!texture_size.IsEmpty());
- fragment_tex_translate_x /= texture_size.width();
- fragment_tex_translate_y /= texture_size.height();
- fragment_tex_scale_x /= texture_size.width();
- fragment_tex_scale_y /= texture_size.height();
- }
-
- SetUseProgram(
- ProgramKey::Tile(tex_coord_precision, sampler, USE_AA,
- quad->is_premultiplied ? PREMULTIPLIED_ALPHA
- : NON_PREMULTIPLIED_ALPHA,
- false, false, tint_gl_composited_content_,
- ShouldApplyRoundedCorner(quad)),
- quad_resource_lock.color_space(), CurrentRenderPassColorSpace());
-
- if (current_program_->tint_color_matrix_location() != -1) {
- auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
- gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
- false, matrix.data());
- }
-
- gl_->Uniform3fv(current_program_->edge_location(), 8, edge);
-
- gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
- vertex_tex_translate_x, vertex_tex_translate_y,
- vertex_tex_scale_x, vertex_tex_scale_y);
- gl_->Uniform4f(current_program_->fragment_tex_transform_location(),
- fragment_tex_translate_x, fragment_tex_translate_y,
- fragment_tex_scale_x, fragment_tex_scale_y);
-
- // Blending is required for antialiasing.
- SetBlendEnabled(true);
- SetShaderOpacity(quad->shared_quad_state->opacity);
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
- current_frame()->window_matrix * current_frame()->projection_matrix);
- }
- DCHECK(CanApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode));
- ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
-
- // Draw the quad with antialiasing.
- DrawQuadGeometryWithAA(quad, &local_quad, tile_rect);
- RestoreBlendFuncToDefault(quad->shared_quad_state->blend_mode);
-}
-
-void GLRenderer::DrawContentQuadNoAA(const ContentDrawQuadBase* quad,
- ResourceId resource_id,
- const gfx::QuadF* clip_region) {
- gfx::RectF tex_coord_rect = cc::MathUtil::ScaleRectProportional(
- quad->tex_coord_rect, gfx::RectF(quad->rect),
- gfx::RectF(quad->visible_rect));
- float tex_to_geom_scale_x = quad->rect.width() / quad->tex_coord_rect.width();
- float tex_to_geom_scale_y =
- quad->rect.height() / quad->tex_coord_rect.height();
-
- ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_,
- &timer_queries_, "kTiledContent");
-
- bool scaled = (tex_to_geom_scale_x != 1.f || tex_to_geom_scale_y != 1.f);
- GLenum filter = (scaled || !quad->shared_quad_state->quad_to_target_transform
- .IsIdentityOrIntegerTranslation()) &&
- !quad->nearest_neighbor
- ? GL_LINEAR
- : GL_NEAREST;
-
- DisplayResourceProviderGL::ScopedSamplerGL quad_resource_lock(
- resource_provider(), resource_id, filter);
- SamplerType sampler =
- SamplerTypeFromTextureTarget(quad_resource_lock.target());
-
- // Tiles are guaranteed to have been entirely filled except for the
- // bottom/right external edge tiles. Because of border texels, any
- // internal edge will have uvs that are offset from 0 and 1, so
- // clamping to tex_coord_rect in all cases would cause these border
- // texels to not be sampled. Therefore, only clamp texture coordinates
- // for external edge bottom/right tiles that don't have content all
- // the way to the edge and are using bilinear filtering.
- gfx::Size texture_size = quad->texture_size;
- bool fills_right_edge =
- !quad->IsRightEdge() || texture_size.width() == tex_coord_rect.right();
- bool fills_bottom_edge =
- !quad->IsBottomEdge() || texture_size.height() == tex_coord_rect.bottom();
- bool has_tex_clamp_rect =
- filter == GL_LINEAR && (!fills_right_edge || !fills_bottom_edge);
- gfx::SizeF tex_clamp_size(texture_size);
- // Clamp from the original tex coord rect, instead of the one that has
- // been adjusted by the visible rect.
- if (!fills_right_edge)
- tex_clamp_size.set_width(quad->tex_coord_rect.right() - 0.5f);
- if (!fills_bottom_edge)
- tex_clamp_size.set_height(quad->tex_coord_rect.bottom() - 0.5f);
-
- // Map to normalized texture coordinates.
- if (sampler != SAMPLER_TYPE_2D_RECT) {
- DCHECK(!texture_size.IsEmpty());
- tex_coord_rect.Scale(1.f / texture_size.width(),
- 1.f / texture_size.height());
- tex_clamp_size.Scale(1.f / texture_size.width(),
- 1.f / texture_size.height());
- }
-
- TexCoordPrecision tex_coord_precision =
- TexCoordPrecisionRequired(gl_, &highp_threshold_cache_,
- settings_->highp_threshold_min, texture_size);
- SetUseProgram(
- ProgramKey::Tile(tex_coord_precision, sampler, NO_AA,
- quad->is_premultiplied ? PREMULTIPLIED_ALPHA
- : NON_PREMULTIPLIED_ALPHA,
- !quad->ShouldDrawWithBlending(), has_tex_clamp_rect,
- tint_gl_composited_content_,
- ShouldApplyRoundedCorner(quad)),
- quad_resource_lock.color_space(), CurrentRenderPassColorSpace());
-
- if (current_program_->tint_color_matrix_location() != -1) {
- auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
- gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
- false, matrix.data());
- }
-
- if (has_tex_clamp_rect) {
- gl_->Uniform4f(current_program_->tex_clamp_rect_location(), 0, 0,
- tex_clamp_size.width(), tex_clamp_size.height());
- }
- gl_->Uniform4f(current_program_->vertex_tex_transform_location(),
- tex_coord_rect.x(), tex_coord_rect.y(), tex_coord_rect.width(),
- tex_coord_rect.height());
-
- DCHECK(CanApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode));
- SetBlendEnabled(quad->ShouldDrawWithBlending());
- ApplyBlendModeUsingBlendFunc(quad->shared_quad_state->blend_mode);
-
- SetShaderOpacity(quad->shared_quad_state->opacity);
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
- current_frame()->window_matrix * current_frame()->projection_matrix);
- }
-
- // Pass quad coordinates to the uniform in the same order as GeometryBinding
- // does, then vertices will match the texture mapping in the vertex buffer.
- // The method SetShaderQuadF() changes the order of vertices and so it's
- // not used here.
- auto tile_quad = gfx::QuadF(gfx::RectF(quad->visible_rect));
- float width = quad->visible_rect.width();
- float height = quad->visible_rect.height();
- auto top_left = gfx::PointF(quad->visible_rect.origin());
- if (clip_region) {
- tile_quad = *clip_region;
- float gl_uv[8] = {
- (tile_quad.p4().x() - top_left.x()) / width,
- (tile_quad.p4().y() - top_left.y()) / height,
- (tile_quad.p1().x() - top_left.x()) / width,
- (tile_quad.p1().y() - top_left.y()) / height,
- (tile_quad.p2().x() - top_left.x()) / width,
- (tile_quad.p2().y() - top_left.y()) / height,
- (tile_quad.p3().x() - top_left.x()) / width,
- (tile_quad.p3().y() - top_left.y()) / height,
- };
- PrepareGeometry(CLIPPED_BINDING);
- clipped_geometry_->InitializeCustomQuadWithUVs(
- gfx::QuadF(gfx::RectF(quad->visible_rect)), gl_uv);
- } else {
- PrepareGeometry(SHARED_BINDING);
- }
- float gl_quad[8] = {
- tile_quad.p4().x(), tile_quad.p4().y(), tile_quad.p1().x(),
- tile_quad.p1().y(), tile_quad.p2().x(), tile_quad.p2().y(),
- tile_quad.p3().x(), tile_quad.p3().y(),
- };
- gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad);
-
- SetShaderMatrix(current_frame()->projection_matrix *
- quad->shared_quad_state->quad_to_target_transform);
-
- gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
- num_triangles_drawn_ += 2;
- RestoreBlendFuncToDefault(quad->shared_quad_state->blend_mode);
-}
-
-void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
- const gfx::QuadF* clip_region) {
- std::string gpu_composite_time_string;
- if (!clip_region && quad->rect == quad->visible_rect)
- gpu_composite_time_string = "kYuvVideoContent";
- else
- gpu_composite_time_string = "kYuvVideoContentClipped";
- ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_,
- &timer_queries_,
- gpu_composite_time_string);
-
- SetBlendEnabled(quad->ShouldDrawWithBlending());
-
- TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
- quad->shared_quad_state->visible_quad_layer_rect.size());
- YUVAlphaTextureMode alpha_texture_mode = quad->a_plane_resource_id()
- ? YUV_HAS_ALPHA_TEXTURE
- : YUV_NO_ALPHA_TEXTURE;
- UVTextureMode uv_texture_mode =
- quad->v_plane_resource_id() == quad->u_plane_resource_id()
- ? UV_TEXTURE_MODE_UV
- : UV_TEXTURE_MODE_U_V;
-
- DisplayResourceProviderGL::ScopedSamplerGL y_plane_lock(
- resource_provider(), quad->y_plane_resource_id(), GL_TEXTURE1, GL_LINEAR);
- DisplayResourceProviderGL::ScopedSamplerGL u_plane_lock(
- resource_provider(), quad->u_plane_resource_id(), GL_TEXTURE2, GL_LINEAR);
- DCHECK_EQ(y_plane_lock.target(), u_plane_lock.target());
- DCHECK_EQ(y_plane_lock.color_space(), u_plane_lock.color_space());
-
- // TODO(ccameron): There are currently two sources of the color space: the
- // resource color space and quad->video_color_space. Remove one of them.
- gfx::ColorSpace src_color_space = quad->video_color_space;
- // Invalid or unspecified color spaces should be treated as REC709.
- if (!src_color_space.IsValid())
- src_color_space = gfx::ColorSpace::CreateREC709();
- else
- DCHECK_EQ(src_color_space, y_plane_lock.color_space());
- // The source color space should never be RGB.
- DCHECK_NE(src_color_space, src_color_space.GetAsFullRangeRGB());
-
- gfx::ColorSpace dst_color_space = CurrentRenderPassColorSpace();
-
-#if BUILDFLAG(IS_WIN)
- // Force sRGB output on Windows for overlay candidate video quads to match
- // DirectComposition behavior in case these switch between overlays and
- // compositing. See https://crbug.com/811118 for details.
- // Currently if HDR is supported, OverlayProcessor doesn't promote HDR video
- // frame as overlay candidate. So it's unnecessary to worry about the
- // compositing-overlay switch here. In addition drawing a HDR video using sRGB
- // can cancel the advantages of HDR.
- const bool supports_dc_layers =
- output_surface_->capabilities().supports_dc_layers;
- if (supports_dc_layers && !src_color_space.IsHDR() &&
- resource_provider()->IsOverlayCandidate(quad->y_plane_resource_id())) {
- DCHECK(
- resource_provider()->IsOverlayCandidate(quad->u_plane_resource_id()));
- dst_color_space = gfx::ColorSpace::CreateSRGB();
- }
-#endif
-
- // TODO(jbauman): Use absl::optional when available.
- std::unique_ptr<DisplayResourceProviderGL::ScopedSamplerGL> v_plane_lock;
- if (uv_texture_mode == UV_TEXTURE_MODE_U_V) {
- v_plane_lock = std::make_unique<DisplayResourceProviderGL::ScopedSamplerGL>(
- resource_provider(), quad->v_plane_resource_id(), GL_TEXTURE3,
- GL_LINEAR);
- DCHECK_EQ(y_plane_lock.target(), v_plane_lock->target());
- DCHECK_EQ(y_plane_lock.color_space(), v_plane_lock->color_space());
- }
- std::unique_ptr<DisplayResourceProviderGL::ScopedSamplerGL> a_plane_lock;
- if (alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE) {
- a_plane_lock = std::make_unique<DisplayResourceProviderGL::ScopedSamplerGL>(
- resource_provider(), quad->a_plane_resource_id(), GL_TEXTURE4,
- GL_LINEAR);
- DCHECK_EQ(y_plane_lock.target(), a_plane_lock->target());
- }
-
- // All planes must have the same sampler type.
- SamplerType sampler = SamplerTypeFromTextureTarget(y_plane_lock.target());
-
- SetUseProgram(
- ProgramKey::YUVVideo(tex_coord_precision, sampler, alpha_texture_mode,
- uv_texture_mode, tint_gl_composited_content_,
- ShouldApplyRoundedCorner(quad)),
- src_color_space, dst_color_space, /*adjust_src_white_level=*/true);
-
- if (current_program_->tint_color_matrix_location() != -1) {
- auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
- gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
- false, matrix.data());
- }
-
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
- current_frame()->window_matrix * current_frame()->projection_matrix);
- }
-
- gfx::SizeF ya_tex_scale(1.0f, 1.0f);
- gfx::SizeF uv_tex_scale(1.0f, 1.0f);
- if (sampler != SAMPLER_TYPE_2D_RECT) {
- DCHECK(!quad->ya_tex_size.IsEmpty());
- DCHECK(!quad->uv_tex_size.IsEmpty());
- ya_tex_scale = gfx::SizeF(1.0f / quad->ya_tex_size.width(),
- 1.0f / quad->ya_tex_size.height());
- uv_tex_scale = gfx::SizeF(1.0f / quad->uv_tex_size.width(),
- 1.0f / quad->uv_tex_size.height());
- }
-
- float ya_vertex_tex_translate_x =
- quad->ya_tex_coord_rect.x() * ya_tex_scale.width();
- float ya_vertex_tex_translate_y =
- quad->ya_tex_coord_rect.y() * ya_tex_scale.height();
- float ya_vertex_tex_scale_x =
- quad->ya_tex_coord_rect.width() * ya_tex_scale.width();
- float ya_vertex_tex_scale_y =
- quad->ya_tex_coord_rect.height() * ya_tex_scale.height();
-
- float uv_vertex_tex_translate_x =
- quad->uv_tex_coord_rect.x() * uv_tex_scale.width();
- float uv_vertex_tex_translate_y =
- quad->uv_tex_coord_rect.y() * uv_tex_scale.height();
- float uv_vertex_tex_scale_x =
- quad->uv_tex_coord_rect.width() * uv_tex_scale.width();
- float uv_vertex_tex_scale_y =
- quad->uv_tex_coord_rect.height() * uv_tex_scale.height();
-
- gl_->Uniform2f(current_program_->ya_tex_scale_location(),
- ya_vertex_tex_scale_x, ya_vertex_tex_scale_y);
- gl_->Uniform2f(current_program_->ya_tex_offset_location(),
- ya_vertex_tex_translate_x, ya_vertex_tex_translate_y);
- gl_->Uniform2f(current_program_->uv_tex_scale_location(),
- uv_vertex_tex_scale_x, uv_vertex_tex_scale_y);
- gl_->Uniform2f(current_program_->uv_tex_offset_location(),
- uv_vertex_tex_translate_x, uv_vertex_tex_translate_y);
-
- gfx::RectF ya_clamp_rect(ya_vertex_tex_translate_x, ya_vertex_tex_translate_y,
- ya_vertex_tex_scale_x, ya_vertex_tex_scale_y);
- ya_clamp_rect.Inset(gfx::InsetsF::VH(0.5f * ya_tex_scale.height(),
- 0.5f * ya_tex_scale.width()));
- gfx::RectF uv_clamp_rect(uv_vertex_tex_translate_x, uv_vertex_tex_translate_y,
- uv_vertex_tex_scale_x, uv_vertex_tex_scale_y);
- uv_clamp_rect.Inset(gfx::InsetsF::VH(0.5f * uv_tex_scale.height(),
- 0.5f * uv_tex_scale.width()));
- gl_->Uniform4f(current_program_->ya_clamp_rect_location(), ya_clamp_rect.x(),
- ya_clamp_rect.y(), ya_clamp_rect.right(),
- ya_clamp_rect.bottom());
- gl_->Uniform4f(current_program_->uv_clamp_rect_location(), uv_clamp_rect.x(),
- uv_clamp_rect.y(), uv_clamp_rect.right(),
- uv_clamp_rect.bottom());
-
- gl_->Uniform1i(current_program_->y_texture_location(), 1);
- if (uv_texture_mode == UV_TEXTURE_MODE_UV) {
- gl_->Uniform1i(current_program_->uv_texture_location(), 2);
- } else {
- gl_->Uniform1i(current_program_->u_texture_location(), 2);
- gl_->Uniform1i(current_program_->v_texture_location(), 3);
- }
- if (alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE)
- gl_->Uniform1i(current_program_->a_texture_location(), 4);
-
- gl_->Uniform1f(current_program_->resource_multiplier_location(),
- quad->resource_multiplier);
- gl_->Uniform1f(current_program_->resource_offset_location(),
- quad->resource_offset);
-
- // The transform and vertex data are used to figure out the extents that the
- // un-antialiased quad should have and which vertex this is and the float
- // quad passed in via uniform is the actual geometry that gets used to draw
- // it. This is why this centered rect is used and not the original quad_rect.
- auto tile_rect = gfx::RectF(quad->rect);
-
- SetShaderOpacity(quad->shared_quad_state->opacity);
- if (!clip_region && quad->rect == quad->visible_rect) {
- DrawQuadGeometry(current_frame()->projection_matrix,
- quad->shared_quad_state->quad_to_target_transform,
- tile_rect);
- } else {
- gfx::QuadF region_quad =
- clip_region ? *clip_region : gfx::QuadF(gfx::RectF(quad->visible_rect));
- float uvs[8] = {0};
- GetScaledUVs(quad->rect, &region_quad, uvs);
- region_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
- region_quad -= gfx::Vector2dF(0.5f, 0.5f);
- DrawQuadGeometryClippedByQuadF(
- quad->shared_quad_state->quad_to_target_transform, tile_rect,
- region_quad, uvs);
- }
-
- // Track the region in the current target surface that has been drawn to.
- AccumulateDrawRects(quad->visible_rect,
- quad->shared_quad_state->quad_to_target_transform,
- &drawn_rects_);
-}
-
-void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
- const gfx::QuadF* clip_region) {
- std::string gpu_composite_time_string;
- if (!clip_region && quad->rect == quad->visible_rect) {
- gpu_composite_time_string = "kStreamVideoContent";
- } else {
- gpu_composite_time_string = "kStreamVideoContentClipped";
- }
- ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_,
- &timer_queries_,
- gpu_composite_time_string);
- SetBlendEnabled(quad->ShouldDrawWithBlending());
-
- DCHECK(output_surface_->context_provider()
- ->ContextCapabilities()
- .egl_image_external);
-
- TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
- quad->shared_quad_state->visible_quad_layer_rect.size());
-
- DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider(),
- quad->resource_id());
-
- SetUseProgram(ProgramKey::VideoStream(tex_coord_precision,
- ShouldApplyRoundedCorner(quad)),
- lock.color_space(), CurrentRenderPassColorSpace());
-
- DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- gl_->BindTexture(GL_TEXTURE_EXTERNAL_OES, lock.texture_id());
-
- static float gl_matrix[16];
- gfx::Transform matrix;
- matrix.Scale(quad->uv_bottom_right.x() - quad->uv_top_left.x(),
- quad->uv_bottom_right.y() - quad->uv_top_left.y());
- matrix.Translate(quad->uv_top_left.x(), quad->uv_top_left.y());
- ToGLMatrix(&gl_matrix[0], matrix);
- gl_->UniformMatrix4fv(current_program_->tex_matrix_location(), 1, false,
- gl_matrix);
-
- SetShaderOpacity(quad->shared_quad_state->opacity);
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- quad->shared_quad_state->mask_filter_info.rounded_corner_bounds(),
- current_frame()->window_matrix * current_frame()->projection_matrix);
- }
- gfx::Size texture_size = lock.size();
- gfx::RectF uv_visible_rect(quad->uv_top_left.x(), quad->uv_top_left.y(),
- quad->uv_bottom_right.x() - quad->uv_top_left.x(),
- quad->uv_bottom_right.y() - quad->uv_top_left.y());
- const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
- Float4 tex_clamp_rect = UVClampRect(uv_visible_rect, texture_size, sampler);
- gl_->Uniform4f(current_program_->tex_clamp_rect_location(),
- tex_clamp_rect.data[0], tex_clamp_rect.data[1],
- tex_clamp_rect.data[2], tex_clamp_rect.data[3]);
-
- auto tile_rect = gfx::RectF(quad->rect);
-
- if (!clip_region && quad->rect == quad->visible_rect) {
- DrawQuadGeometry(current_frame()->projection_matrix,
- quad->shared_quad_state->quad_to_target_transform,
- tile_rect);
- } else {
- gfx::QuadF region_quad =
- clip_region ? *clip_region : gfx::QuadF(gfx::RectF(quad->visible_rect));
- float uvs[8] = {0};
- GetScaledUVs(quad->rect, &region_quad, uvs);
- region_quad.Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
- region_quad -= gfx::Vector2dF(0.5f, 0.5f);
- DrawQuadGeometryClippedByQuadF(
- quad->shared_quad_state->quad_to_target_transform, tile_rect,
- region_quad, uvs);
- }
-
- AccumulateDrawRects(quad->visible_rect,
- quad->shared_quad_state->quad_to_target_transform,
- &drawn_rects_);
-}
-
-void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
- // Check to see if we have anything to draw.
- if (draw_cache_.is_empty)
- return;
- ScopedTimerQuery scoped_timer_query(CompositeTimeTracingEnabled(), gl_,
- &timer_queries_, "kTextureContentFlush");
-
- PrepareGeometry(flush_binding);
-
- // Set the correct blending mode.
- SetBlendEnabled(draw_cache_.needs_blending);
-
- // Assume the current active textures is 0.
- DisplayResourceProviderGL::ScopedSamplerGL locked_quad(
- resource_provider(), draw_cache_.resource_id,
- draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR);
-
- // Bind the program to the GL state.
- SetUseProgram(draw_cache_.program_key, locked_quad.color_space(),
- CurrentRenderPassColorSpace(),
- /*adjust_src_white_level=*/draw_cache_.is_video_frame,
- locked_quad.hdr_metadata());
-
- if (current_program_->rounded_corner_rect_location() != -1) {
- SetShaderRoundedCorner(
- draw_cache_.mask_filter_info.rounded_corner_bounds(),
- current_frame()->window_matrix * current_frame()->projection_matrix);
- }
-
- DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- gl_->BindTexture(locked_quad.target(), locked_quad.texture_id());
-
- static_assert(sizeof(Float4) == 4 * sizeof(float),
- "Float4 struct should be densely packed");
- static_assert(sizeof(Float16) == 16 * sizeof(float),
- "Float16 struct should be densely packed");
-
- // Upload the tranforms for both points and uvs.
- gl_->UniformMatrix4fv(
- current_program_->matrix_location(),
- static_cast<int>(draw_cache_.matrix_data.size()), false,
- reinterpret_cast<float*>(&draw_cache_.matrix_data.front()));
- gl_->Uniform4fv(current_program_->vertex_tex_transform_location(),
- static_cast<int>(draw_cache_.uv_xform_data.size()),
- reinterpret_cast<float*>(&draw_cache_.uv_xform_data.front()));
-
- if (current_program_->tint_color_matrix_location() != -1) {
- auto matrix = cc::DebugColors::TintCompositedContentColorTransformMatrix();
- gl_->UniformMatrix4fv(current_program_->tint_color_matrix_location(), 1,
- false, matrix.data());
- }
-
- if (current_program_->tex_clamp_rect_location() != -1) {
- // Draw batching is not allowed with texture clamping.
- DCHECK_EQ(1u, draw_cache_.matrix_data.size());
- gl_->Uniform4f(current_program_->tex_clamp_rect_location(),
- draw_cache_.tex_clamp_rect_data.data[0],
- draw_cache_.tex_clamp_rect_data.data[1],
- draw_cache_.tex_clamp_rect_data.data[2],
- draw_cache_.tex_clamp_rect_data.data[3]);
- }
-
- if (draw_cache_.background_color != SK_ColorTRANSPARENT) {
- Float4 background_color =
- PremultipliedColor(draw_cache_.background_color, 1.f);
- gl_->Uniform4fv(current_program_->background_color_location(), 1,
- background_color.data);
- }
-
- gl_->Uniform1fv(
- current_program_->vertex_opacity_location(),
- static_cast<int>(draw_cache_.vertex_opacity_data.size()),
- static_cast<float*>(&draw_cache_.vertex_opacity_data.front()));
-
- DCHECK_LE(draw_cache_.matrix_data.size(),
- static_cast<size_t>(std::numeric_limits<int>::max()) / 6u);
-
- // Draw the quads!
- gl_->DrawElements(GL_TRIANGLES,
- 6 * static_cast<int>(draw_cache_.matrix_data.size()),
- GL_UNSIGNED_SHORT, nullptr);
- num_triangles_drawn_ += 2 * static_cast<int>(draw_cache_.matrix_data.size());
-
- // Clear the cache.
- draw_cache_.is_empty = true;
- draw_cache_.resource_id = kInvalidResourceId;
- draw_cache_.uv_xform_data.resize(0);
- draw_cache_.vertex_opacity_data.resize(0);
- draw_cache_.matrix_data.resize(0);
- draw_cache_.tex_clamp_rect_data = Float4();
- draw_cache_.is_video_frame = false;
-
- // If we had a clipped binding, prepare the shared binding for the
- // next inserts.
- if (flush_binding == CLIPPED_BINDING) {
- PrepareGeometry(SHARED_BINDING);
- }
-}
-
-void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
- const gfx::QuadF* clip_region) {
- // If we have a clip_region then we have to render the next quad
- // with dynamic geometry, therefore we must flush all pending
- // texture quads.
- if (clip_region) {
- // We send in false here because we want to flush what's currently in the
- // queue using the shared_geometry and not clipped_geometry
- FlushTextureQuadCache(SHARED_BINDING);
- }
-
- DisplayResourceProviderGL::ScopedReadLockGL lock(resource_provider(),
- quad->resource_id());
- // ScopedReadLockGL contains the correct texture size, even when
- // quad->resource_size_in_pixels() is empty.
- const gfx::Size texture_size = lock.size();
- TexCoordPrecision tex_coord_precision =
- TexCoordPrecisionRequired(gl_, &highp_threshold_cache_,
- settings_->highp_threshold_min, texture_size);
-
- const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
-
- bool need_tex_clamp_rect = !quad->resource_size_in_pixels().IsEmpty() &&
- (quad->uv_top_left != gfx::PointF(0, 0) ||
- quad->uv_bottom_right != gfx::PointF(1, 1));
-
- ProgramKey program_key = ProgramKey::Texture(
- tex_coord_precision, sampler,
- quad->premultiplied_alpha ? PREMULTIPLIED_ALPHA : NON_PREMULTIPLIED_ALPHA,
- quad->background_color != SK_ColorTRANSPARENT, need_tex_clamp_rect,
- tint_gl_composited_content_, ShouldApplyRoundedCorner(quad));
- ResourceId resource_id = quad->resource_id();
-
- size_t max_quads = StaticGeometryBinding::NUM_QUADS;
- if (draw_cache_.is_empty || draw_cache_.program_key != program_key ||
- draw_cache_.resource_id != resource_id ||
- draw_cache_.needs_blending != quad->ShouldDrawWithBlending() ||
- draw_cache_.nearest_neighbor != quad->nearest_neighbor ||
- draw_cache_.background_color != quad->background_color ||
- draw_cache_.mask_filter_info !=
- quad->shared_quad_state->mask_filter_info ||
- draw_cache_.matrix_data.size() >= max_quads ||
- draw_cache_.is_video_frame != quad->is_video_frame) {
- FlushTextureQuadCache(SHARED_BINDING);
- draw_cache_.is_empty = false;
- draw_cache_.program_key = program_key;
- draw_cache_.resource_id = resource_id;
- draw_cache_.needs_blending = quad->ShouldDrawWithBlending();
- draw_cache_.nearest_neighbor = quad->nearest_neighbor;
- draw_cache_.background_color = quad->background_color;
- draw_cache_.mask_filter_info = quad->shared_quad_state->mask_filter_info;
- draw_cache_.is_video_frame = quad->is_video_frame;
- }
-
- // Generate the uv-transform
- auto uv_transform = UVTransform(quad);
- if (sampler == SAMPLER_TYPE_2D_RECT) {
- // Un-normalize the texture coordiantes for rectangle targets.
- uv_transform.data[0] *= texture_size.width();
- uv_transform.data[2] *= texture_size.width();
- uv_transform.data[1] *= texture_size.height();
- uv_transform.data[3] *= texture_size.height();
- }
- draw_cache_.uv_xform_data.push_back(uv_transform);
-
- if (need_tex_clamp_rect) {
- DCHECK_EQ(1u, draw_cache_.uv_xform_data.size());
- DCHECK_EQ(texture_size.ToString(),
- quad->resource_size_in_pixels().ToString());
- DCHECK(!texture_size.IsEmpty());
- gfx::RectF uv_visible_rect(
- quad->uv_top_left.x(), quad->uv_top_left.y(),
- quad->uv_bottom_right.x() - quad->uv_top_left.x(),
- quad->uv_bottom_right.y() - quad->uv_top_left.y());
- Float4 tex_clamp_rect = UVClampRect(uv_visible_rect, texture_size, sampler);
- draw_cache_.tex_clamp_rect_data = tex_clamp_rect;
- }
-
- // Generate the vertex opacity
- const float opacity = quad->shared_quad_state->opacity;
- draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[0] * opacity);
- draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[1] * opacity);
- draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[2] * opacity);
- draw_cache_.vertex_opacity_data.push_back(quad->vertex_opacity[3] * opacity);
-
- // Generate the transform matrix
- gfx::Transform quad_rect_matrix;
- QuadRectTransform(&quad_rect_matrix,
- quad->shared_quad_state->quad_to_target_transform,
- gfx::RectF(quad->visible_rect));
- quad_rect_matrix = current_frame()->projection_matrix * quad_rect_matrix;
-
- Float16 m;
- quad_rect_matrix.matrix().getColMajor(m.data);
- draw_cache_.matrix_data.push_back(m);
-
- // Track the region in the current target surface that has been drawn to.
- AccumulateDrawRects(quad->visible_rect,
- quad->shared_quad_state->quad_to_target_transform,
- &drawn_rects_);
-
- if (clip_region) {
- DCHECK_EQ(quad->rect, quad->visible_rect);
- gfx::QuadF scaled_region;
- if (!GetScaledRegion(quad->rect, clip_region, &scaled_region)) {
- scaled_region = SharedGeometryQuad().BoundingBox();
- }
- // Both the scaled region and the SharedGeomtryQuad are in the space
- // -0.5->0.5. We need to move that to the space 0->1.
- float uv[8];
- uv[0] = scaled_region.p1().x() + 0.5f;
- uv[1] = scaled_region.p1().y() + 0.5f;
- uv[2] = scaled_region.p2().x() + 0.5f;
- uv[3] = scaled_region.p2().y() + 0.5f;
- uv[4] = scaled_region.p3().x() + 0.5f;
- uv[5] = scaled_region.p3().y() + 0.5f;
- uv[6] = scaled_region.p4().x() + 0.5f;
- uv[7] = scaled_region.p4().y() + 0.5f;
- PrepareGeometry(CLIPPED_BINDING);
- clipped_geometry_->InitializeCustomQuadWithUVs(scaled_region, uv);
- FlushTextureQuadCache(CLIPPED_BINDING);
- } else if (need_tex_clamp_rect) {
- FlushTextureQuadCache(SHARED_BINDING);
- }
-}
-
-void GLRenderer::FinishDrawingFrame() {
- if (use_sync_query_) {
- sync_queries_.EndCurrentFrame();
- }
-
- swap_buffer_rect_.Union(current_frame()->root_damage_rect);
-
- if (use_swap_with_bounds_)
- swap_content_bounds_ = current_frame()->root_content_bounds;
-
- copier_.FreeUnusedCachedResources();
-
- current_framebuffer_texture_ = nullptr;
-
- gl_->Disable(GL_BLEND);
- blend_shadow_ = false;
-
- // Schedule output surface as overlay first to preserve existing ordering
- // semantics during overlay refactoring.
- ScheduleOutputSurfaceAsOverlay();
-
-#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
- ScheduleOverlays();
-#elif BUILDFLAG(IS_APPLE)
- ScheduleCALayers();
-#elif BUILDFLAG(IS_WIN)
- ScheduleDCLayers();
-#endif
-
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("viz.triangles"), "Triangles Drawn",
- num_triangles_drawn_);
-
- // Mark the end of batched read of shared images.
- gl_->EndBatchReadAccessSharedImageCHROMIUM();
-}
-
-bool GLRenderer::OverdrawTracingEnabled() {
- // Only collect trace data if we select viz.overdraw.
- bool tracing_enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("viz.overdraw"),
- &tracing_enabled);
- // ARB_occlusion_query is required for tracing.
- // Trace only the root render pass.
- return tracing_enabled && use_occlusion_query_ &&
- current_frame()->current_render_pass ==
- current_frame()->root_render_pass;
-}
-
-bool GLRenderer::CompositeTimeTracingEnabled() {
- bool tracing_enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(
- TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), &tracing_enabled);
-
- return tracing_enabled && use_timer_query_;
-}
-
-void GLRenderer::AddCompositeTimeTraces(base::TimeTicks ready_timestamp) {
- DCHECK(CompositeTimeTracingEnabled());
- DCHECK_EQ(timer_queries_.front().first, kTimerQueryDummy);
-
- std::size_t count = 0;
- uint64_t duration = 0;
-
- // List of queries to delete after their results are retrieved.
- std::vector<unsigned> queries_to_delete;
-
- // Queue of durations per draw call. The |second| in the pair represents the
- // draw call type as string.
- base::queue<std::pair<uint64_t, std::string>> durations;
-
- // Pop the fence query as it does not represent a timer query.
- timer_queries_.pop();
-
- // Initialize |start_time_ticks| as the end timestamp and walk backwards to
- // find the actual timestamp.
- base::TimeTicks start_time_ticks = ready_timestamp;
-
- while (timer_queries_.size() &&
- timer_queries_.front().first != kTimerQueryDummy) {
- count++;
- gl_->GetQueryObjectui64vEXT(timer_queries_.front().first,
- GL_QUERY_RESULT_EXT, &duration);
- durations.emplace(duration, timer_queries_.front().second);
- queries_to_delete.push_back(timer_queries_.front().first);
- timer_queries_.pop();
- start_time_ticks -= base::Nanoseconds(duration);
- }
-
- // Delete all timer queries for which results have been retrieved.
- gl_->DeleteQueriesEXT(count, queries_to_delete.data());
-
- base::TimeDelta unique_id_delta = ready_timestamp - start_time_ticks;
- const int trace_unique_id = unique_id_delta.InMilliseconds() * count;
-
- TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(
- TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time",
- TRACE_ID_LOCAL(trace_unique_id), start_time_ticks);
-
- while (!durations.empty()) {
- duration = durations.front().first;
-
- // |duration| may be set to 0 if the timer query result was unavailable in
- // |GetQueryObjectui64vEXT| function call.
- if (!duration) {
- durations.pop();
- continue;
- }
- TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(
- TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time",
- TRACE_ID_LOCAL(trace_unique_id), durations.front().second.c_str(),
- start_time_ticks);
- start_time_ticks += base::Nanoseconds(duration);
- durations.pop();
- }
-
- TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(
- TRACE_DISABLED_BY_DEFAULT("viz.gpu_composite_time"), "Composite Time",
- TRACE_ID_LOCAL(trace_unique_id), ready_timestamp);
-}
-
-void GLRenderer::FinishDrawingQuadList() {
- FlushTextureQuadCache(SHARED_BINDING);
- if (occlusion_query_) {
- // Use the current surface area as max result. The effect is that overdraw
- // is reported as a percentage of the output surface size. ie. 2x overdraw
- // for the whole screen is reported as 200.
- base::CheckedNumeric<int> surface_area =
- current_surface_size_.GetCheckedArea();
- DCHECK_GT(static_cast<int>(surface_area.ValueOrDefault(INT_MAX)), 0);
-
- gl_->EndQueryEXT(GL_SAMPLES_PASSED_ARB);
- context_support_->SignalQuery(
- occlusion_query_, base::BindOnce(&GLRenderer::ProcessOverdrawFeedback,
- weak_ptr_factory_.GetWeakPtr(),
- surface_area, occlusion_query_));
- occlusion_query_ = 0;
- }
-}
-
-void GLRenderer::GenerateMipmap() {
- DCHECK(current_framebuffer_texture_);
- current_framebuffer_texture_->set_generate_mipmap();
-}
-
-bool GLRenderer::FlippedFramebuffer() const {
-#if BUILDFLAG(IS_APPLE)
- if (force_drawing_frame_framebuffer_unflipped_)
- return false;
-#endif
- if (current_frame()->current_render_pass != current_frame()->root_render_pass)
- return true;
- return FlippedRootFramebuffer();
-}
-
-bool GLRenderer::FlippedRootFramebuffer() const {
- // GL is normally flipped, so a flipped output results in an unflipping.
- return output_surface_->capabilities().output_surface_origin ==
- gfx::SurfaceOrigin::kBottomLeft;
-}
-
-void GLRenderer::EnsureScissorTestEnabled() {
- if (is_scissor_enabled_)
- return;
-
- FlushTextureQuadCache(SHARED_BINDING);
- gl_->Enable(GL_SCISSOR_TEST);
- is_scissor_enabled_ = true;
-}
-
-void GLRenderer::EnsureScissorTestDisabled() {
- if (!is_scissor_enabled_)
- return;
-
- FlushTextureQuadCache(SHARED_BINDING);
- gl_->Disable(GL_SCISSOR_TEST);
- is_scissor_enabled_ = false;
-}
-
-void GLRenderer::CopyDrawnRenderPass(
- const copy_output::RenderPassGeometry& geometry,
- std::unique_ptr<CopyOutputRequest> request) {
- TRACE_EVENT0("viz", "GLRenderer::CopyDrawnRenderPass");
-
- GLuint framebuffer_texture = 0;
- gfx::Size framebuffer_texture_size;
- if (current_framebuffer_texture_) {
- framebuffer_texture = current_framebuffer_texture_->id();
- framebuffer_texture_size = current_framebuffer_texture_->size();
- }
- copier_.CopyFromTextureOrFramebuffer(
- std::move(request), geometry, GetFramebufferCopyTextureFormat(),
- framebuffer_texture, framebuffer_texture_size, FlippedFramebuffer(),
- CurrentRenderPassColorSpace());
-
- // The copier modified texture/framebuffer bindings, shader programs, and
- // other GL state; and so this must be restored before continuing.
- RestoreGLState();
-
- // CopyDrawnRenderPass() can change the binding of the framebuffer target as
- // a part of its usual scaling and readback operations. It will break next
- // CopyDrawnRenderPass() call for the root render pass. Therefore, make sure
- // to restore the correct framebuffer between readbacks. (Even if it did
- // not, a Mac-specific bug requires this workaround: http://crbug.com/99393)
- const auto* render_pass = current_frame()->current_render_pass;
- if (render_pass == current_frame()->root_render_pass)
- BindFramebufferToOutputSurface();
-}
-
-void GLRenderer::ToGLMatrix(float* gl_matrix, const gfx::Transform& transform) {
- transform.matrix().getColMajor(gl_matrix);
-}
-
-void GLRenderer::SetShaderQuadF(const gfx::QuadF& quad) {
- if (!current_program_ || current_program_->quad_location() == -1)
- return;
- float gl_quad[8];
- gl_quad[0] = quad.p1().x();
- gl_quad[1] = quad.p1().y();
- gl_quad[2] = quad.p2().x();
- gl_quad[3] = quad.p2().y();
- gl_quad[4] = quad.p3().x();
- gl_quad[5] = quad.p3().y();
- gl_quad[6] = quad.p4().x();
- gl_quad[7] = quad.p4().y();
- gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad);
-}
-
-void GLRenderer::SetShaderOpacity(float opacity) {
- if (!current_program_ || current_program_->alpha_location() == -1)
- return;
- gl_->Uniform1f(current_program_->alpha_location(), opacity);
-}
-
-void GLRenderer::SetShaderMatrix(const gfx::Transform& transform) {
- if (!current_program_ || current_program_->matrix_location() == -1)
- return;
- float gl_matrix[16];
- ToGLMatrix(gl_matrix, transform);
- gl_->UniformMatrix4fv(current_program_->matrix_location(), 1, false,
- gl_matrix);
-}
-
-void GLRenderer::SetShaderColor(SkColor color, float opacity) {
- if (!current_program_ || current_program_->color_location() == -1)
- return;
- Float4 float_color = PremultipliedColor(color, opacity);
- gl_->Uniform4fv(current_program_->color_location(), 1, float_color.data);
-}
-
-void GLRenderer::SetStencilEnabled(bool enabled) {
- if (enabled == stencil_shadow_)
- return;
-
- if (enabled)
- gl_->Enable(GL_STENCIL_TEST);
- else
- gl_->Disable(GL_STENCIL_TEST);
- stencil_shadow_ = enabled;
-}
-
-void GLRenderer::SetBlendEnabled(bool enabled) {
- if (enabled == blend_shadow_)
- return;
-
- if (enabled)
- gl_->Enable(GL_BLEND);
- else
- gl_->Disable(GL_BLEND);
- blend_shadow_ = enabled;
-}
-
-void GLRenderer::SetShaderRoundedCorner(
- const gfx::RRectF& rounded_corner_bounds,
- const gfx::Transform& screen_transform) {
- DCHECK(current_program_);
- DCHECK(!rounded_corner_bounds.IsEmpty());
- DCHECK_NE(current_program_->rounded_corner_rect_location(), -1);
- DCHECK_NE(current_program_->rounded_corner_radius_location(), -1);
- DCHECK(screen_transform.IsScaleOrTranslation());
-
- const gfx::Vector2dF& translate = screen_transform.To2dTranslation();
- const gfx::Vector2dF& scale = screen_transform.To2dScale();
- gfx::RRectF bounds_in_screen = rounded_corner_bounds;
- bounds_in_screen.Scale(scale.x(), scale.y());
- bounds_in_screen.Offset(translate.x(), translate.y());
-
- gfx::RectF rect = bounds_in_screen.rect();
-
- gl_->Uniform4f(current_program_->rounded_corner_rect_location(), rect.x(),
- rect.y(), rect.width(), rect.height());
- gl_->Uniform4f(
- current_program_->rounded_corner_radius_location(),
- bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kUpperLeft).x(),
- bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kUpperRight).x(),
- bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kLowerRight).x(),
- bounds_in_screen.GetCornerRadii(gfx::RRectF::Corner::kLowerLeft).x());
-}
-
-void GLRenderer::DrawQuadGeometryClippedByQuadF(
- const gfx::Transform& draw_transform,
- const gfx::RectF& quad_rect,
- const gfx::QuadF& clipping_region_quad,
- const float* uvs) {
- PrepareGeometry(CLIPPED_BINDING);
- if (uvs) {
- clipped_geometry_->InitializeCustomQuadWithUVs(clipping_region_quad, uvs);
- } else {
- clipped_geometry_->InitializeCustomQuad(clipping_region_quad);
- }
- gfx::Transform quad_rect_matrix;
- QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
- SetShaderMatrix(current_frame()->projection_matrix * quad_rect_matrix);
-
- gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT,
- reinterpret_cast<const void*>(0));
- num_triangles_drawn_ += 2;
-}
-
-void GLRenderer::DrawQuadGeometry(const gfx::Transform& projection_matrix,
- const gfx::Transform& draw_transform,
- const gfx::RectF& quad_rect) {
- PrepareGeometry(SHARED_BINDING);
- gfx::Transform quad_rect_matrix;
- QuadRectTransform(&quad_rect_matrix, draw_transform, quad_rect);
- SetShaderMatrix(projection_matrix * quad_rect_matrix);
-
- gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
- num_triangles_drawn_ += 2;
-}
-
-void GLRenderer::DrawQuadGeometryWithAA(const DrawQuad* quad,
- gfx::QuadF* local_quad,
- const gfx::Rect& tile_rect) {
- DCHECK(local_quad);
- // Normalize to tile_rect.
- local_quad->Scale(1.0f / tile_rect.width(), 1.0f / tile_rect.height());
-
- SetShaderQuadF(*local_quad);
-
- // The transform and vertex data are used to figure out the extents that the
- // un-antialiased quad should have and which vertex this is and the float
- // quad passed in via uniform is the actual geometry that gets used to draw
- // it. This is why this centered rect is used and not the original quad_rect.
- DrawQuadGeometry(current_frame()->projection_matrix,
- quad->shared_quad_state->quad_to_target_transform,
- CenteredRect(tile_rect));
-}
-
-void GLRenderer::SwapBuffers(SwapFrameData swap_frame_data) {
- DCHECK(visible_);
-
- TRACE_EVENT0("viz", "GLRenderer::SwapBuffers");
- // We're done! Time to swapbuffers!
-
- gfx::Size surface_size = surface_size_for_swap_buffers();
-
- OutputSurfaceFrame output_frame;
- output_frame.latency_info = std::move(swap_frame_data.latency_info);
- output_frame.top_controls_visible_height_changed =
- swap_frame_data.top_controls_visible_height_changed;
- output_frame.size = surface_size;
-#if BUILDFLAG(IS_MAC)
- output_frame.ca_layer_error_code = swap_frame_data.ca_layer_error_code;
-#endif
-
- if (use_swap_with_bounds_) {
- output_frame.content_bounds = std::move(swap_content_bounds_);
- } else if (use_partial_swap_) {
- // If supported, we can save significant bandwidth by only swapping the
- // damaged/scissored region (clamped to the viewport).
- swap_buffer_rect_.Intersect(gfx::Rect(surface_size));
- int flipped_y_pos_of_rect_bottom = surface_size.height() -
- swap_buffer_rect_.y() -
- swap_buffer_rect_.height();
- output_frame.sub_buffer_rect =
- gfx::Rect(swap_buffer_rect_.x(),
- FlippedRootFramebuffer() ? flipped_y_pos_of_rect_bottom
- : swap_buffer_rect_.y(),
- swap_buffer_rect_.width(), swap_buffer_rect_.height());
- } else if (swap_buffer_rect_.IsEmpty() && allow_empty_swap_) {
- output_frame.sub_buffer_rect = swap_buffer_rect_;
- }
-
- // Record resources from viz clients that have been shipped as overlays to the
- // gpu together.
- swapping_overlay_resources_.push_back(std::move(pending_overlay_resources_));
- pending_overlay_resources_.clear();
- if (settings_->release_overlay_resources_after_gpu_query) {
- // Record RenderPass textures that have been shipped as overlays to the gpu
- // together.
- displayed_overlay_textures_.push_back(
- std::move(awaiting_swap_overlay_textures_));
- awaiting_swap_overlay_textures_.clear();
- } else {
- // If |displayed_overlay_textures_| is appended to in this case then
- // SwapBuffersComplete needs to be extended to handle it.
- DCHECK(awaiting_swap_overlay_textures_.empty());
- }
-
- output_surface_->SwapBuffers(std::move(output_frame));
-
- swap_buffer_rect_ = gfx::Rect();
-
- if (context_busy_) {
- output_surface_->context_provider()->CacheController()->ClientBecameNotBusy(
- std::move(context_busy_));
- }
-}
-
-void GLRenderer::SwapBuffersSkipped() {
- if (context_busy_) {
- output_surface_->context_provider()->CacheController()->ClientBecameNotBusy(
- std::move(context_busy_));
- }
-}
-
-void GLRenderer::SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {
- // Returned release fence is signalled when the latest swap is presented,
- // and tells us we can re-use the buffers from the /previous/ swap.
- if (swapping_overlay_resources_.size() > 1) {
- for (auto& lock : swapping_overlay_resources_[0]) {
- lock->SetReleaseFence(release_fence.Clone());
- }
- }
-
- if (settings_->release_overlay_resources_after_gpu_query) {
- // Once a resource has been swap-ACKed, send a query to the GPU process to
- // ask if the resource is no longer being consumed by the system compositor.
- // The response will come with the next swap-ACK.
- if (!swapping_overlay_resources_.empty()) {
- for (OverlayResourceLock& lock : swapping_overlay_resources_.front()) {
- unsigned texture = lock->texture_id();
- if (swapped_and_acked_overlay_resources_.find(texture) ==
- swapped_and_acked_overlay_resources_.end()) {
- swapped_and_acked_overlay_resources_[texture] = std::move(lock);
- }
- }
- swapping_overlay_resources_.pop_front();
- }
- if (!displayed_overlay_textures_.empty()) {
- for (auto& overlay : displayed_overlay_textures_.front())
- awaiting_release_overlay_textures_.push_back(std::move(overlay));
- displayed_overlay_textures_.erase(displayed_overlay_textures_.begin());
- }
-
- size_t query_texture_count = swapped_and_acked_overlay_resources_.size() +
- awaiting_release_overlay_textures_.size();
- if (query_texture_count) {
- std::vector<uint32_t> query_texture_ids;
- query_texture_ids.reserve(query_texture_count);
-
- for (auto& pair : swapped_and_acked_overlay_resources_)
- query_texture_ids.push_back(pair.first);
- for (auto& overlay : awaiting_release_overlay_textures_)
- query_texture_ids.push_back(overlay->texture.id());
-
- // We query for *all* outstanding texture ids, even if we previously
- // queried, as we will not hear back about things becoming available
- // until after we query again.
- gl_->ScheduleCALayerInUseQueryCHROMIUM(query_texture_count,
- query_texture_ids.data());
- }
- } else {
- // If a query is not needed to release the overlay buffers, we can assume
- // that once a swap buffer has completed we can remove the oldest buffers
- // from the queue, but only once we've swapped another frame afterward.
- if (swapping_overlay_resources_.size() > 1) {
- auto& read_lock_release_fence_overlay_locks =
- read_lock_release_fence_overlay_locks_.emplace_back();
- if (!release_fence.is_null()) {
- auto read_lock_iter = std::partition(
- swapping_overlay_resources_.front().begin(),
- swapping_overlay_resources_.front().end(),
- [](auto& lock) { return !lock->HasReadLockFence(); });
- read_lock_release_fence_overlay_locks.insert(
- read_lock_release_fence_overlay_locks.end(),
- std::make_move_iterator(read_lock_iter),
- std::make_move_iterator(swapping_overlay_resources_.front().end()));
- }
-
- DisplayResourceProviderGL::ScopedBatchReturnResources returner(
- resource_provider());
- swapping_overlay_resources_.pop_front();
- }
- // If |displayed_overlay_textures_| has a non-empty member that means we're
- // sending RenderPassDrawQuads as an overlay. This is only supported for
- // CALayers now, where |release_overlay_resources_after_gpu_query| will be
- // true. In order to support them here, the OverlayTextures would need to
- // move to |awaiting_release_overlay_textures_| and stay there until the
- // ResourceFence that was in use for the frame they were submitted is
- // passed.
- DCHECK(displayed_overlay_textures_.empty());
- }
-}
-
-void GLRenderer::BuffersPresented() {
- if (!read_lock_release_fence_overlay_locks_.empty())
- read_lock_release_fence_overlay_locks_.pop_front();
-}
-
-void GLRenderer::DidReceiveTextureInUseResponses(
- const gpu::TextureInUseResponses& responses) {
- DCHECK(settings_->release_overlay_resources_after_gpu_query);
- DisplayResourceProviderGL::ScopedBatchReturnResources returner(
- resource_provider());
- for (const gpu::TextureInUseResponse& response : responses) {
- if (response.in_use)
- continue;
-
- // Returned texture ids may be for resources from clients of the
- // display compositor, in |swapped_and_acked_overlay_resources_|. In that
- // case we remove the lock from the map, allowing them to be returned to the
- // client if the resource has been deleted from the
- // DisplayResourceProviderGL.
- if (swapped_and_acked_overlay_resources_.erase(response.texture))
- continue;
- // If not, then they would be a RenderPass copy texture, which is held in
- // |awaiting_release_overlay_textures_|. We move it back to the available
- // texture list to use it for the next frame.
- auto it = std::find_if(
- awaiting_release_overlay_textures_.begin(),
- awaiting_release_overlay_textures_.end(),
- [&response](const std::unique_ptr<OverlayTexture>& overlay) {
- return overlay->texture.id() == response.texture;
- });
- if (it != awaiting_release_overlay_textures_.end()) {
- // Mark the OverlayTexture as newly returned to the available set.
- (*it)->frames_waiting_for_reuse = 0;
- available_overlay_textures_.push_back(std::move(*it));
- awaiting_release_overlay_textures_.erase(it);
- }
- }
-}
-
-void GLRenderer::BindFramebufferToOutputSurface() {
- current_framebuffer_texture_ = nullptr;
- output_surface_->BindFramebuffer();
- tint_gl_composited_content_ = debug_settings_->tint_composited_content;
- if (overdraw_feedback_) {
- // Output surfaces that require an external stencil test should not allow
- // overdraw feedback by setting |supports_stencil| to false.
- DCHECK(!output_surface_->HasExternalStencilTest());
- SetupOverdrawFeedback();
- SetStencilEnabled(true);
- } else if (output_surface_->HasExternalStencilTest()) {
- output_surface_->ApplyExternalStencil();
- SetStencilEnabled(true);
- } else {
- SetStencilEnabled(false);
- }
-}
-
-void GLRenderer::BindFramebufferToTexture(
- const AggregatedRenderPassId render_pass_id) {
- tint_gl_composited_content_ = false;
- gl_->BindFramebuffer(GL_FRAMEBUFFER, offscreen_framebuffer_id_);
-
- auto contents_texture_it = render_pass_textures_.find(render_pass_id);
- current_framebuffer_texture_ = &contents_texture_it->second;
- GLuint texture_id = current_framebuffer_texture_->id();
- DCHECK(texture_id);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- texture_id, 0);
- if (overdraw_feedback_) {
- if (!offscreen_stencil_renderbuffer_id_)
- gl_->GenRenderbuffers(1, &offscreen_stencil_renderbuffer_id_);
- if (current_framebuffer_texture_->size() !=
- offscreen_stencil_renderbuffer_size_) {
- gl_->BindRenderbuffer(GL_RENDERBUFFER,
- offscreen_stencil_renderbuffer_id_);
- gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
- current_framebuffer_texture_->size().width(),
- current_framebuffer_texture_->size().height());
- gl_->BindRenderbuffer(GL_RENDERBUFFER, 0);
- offscreen_stencil_renderbuffer_size_ =
- current_framebuffer_texture_->size();
- }
- gl_->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER,
- offscreen_stencil_renderbuffer_id_);
- }
-
-#if EXPENSIVE_DCHECKS_ARE_ON()
- DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
- GL_FRAMEBUFFER_COMPLETE ||
- IsContextLost());
-#endif // EXPENSIVE_DCHECKS_ARE_ON()
-
- if (overdraw_feedback_) {
- SetupOverdrawFeedback();
- SetStencilEnabled(true);
- } else {
- SetStencilEnabled(false);
- }
-}
-
-void GLRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
- EnsureScissorTestEnabled();
-
- // Don't unnecessarily ask the context to change the scissor, because it
- // may cause undesired GPU pipeline flushes.
- if (scissor_rect == scissor_rect_)
- return;
-
- scissor_rect_ = scissor_rect;
- FlushTextureQuadCache(SHARED_BINDING);
- gl_->Scissor(scissor_rect.x(), scissor_rect.y(), scissor_rect.width(),
- scissor_rect.height());
-}
-
-void GLRenderer::SetViewport() {
- gl_->Viewport(current_window_space_viewport_.x(),
- current_window_space_viewport_.y(),
- current_window_space_viewport_.width(),
- current_window_space_viewport_.height());
-}
-
-void GLRenderer::InitializeSharedObjects() {
- TRACE_EVENT0("viz", "GLRenderer::InitializeSharedObjects");
-
- // Create an FBO for doing offscreen rendering.
- gl_->GenFramebuffers(1, &offscreen_framebuffer_id_);
-
- shared_geometry_ =
- std::make_unique<StaticGeometryBinding>(gl_, QuadVertexRect());
- clipped_geometry_ = std::make_unique<DynamicGeometryBinding>(gl_);
-}
-
-void GLRenderer::PrepareGeometry(BoundGeometry binding) {
- if (binding == bound_geometry_) {
- return;
- }
-
- switch (binding) {
- case SHARED_BINDING:
- shared_geometry_->PrepareForDraw();
- break;
- case CLIPPED_BINDING:
- clipped_geometry_->PrepareForDraw();
- break;
- case NO_BINDING:
- break;
- }
- bound_geometry_ = binding;
-}
-
-void GLRenderer::SetUseProgram(const ProgramKey& program_key_no_color,
- const gfx::ColorSpace& src_color_space,
- const gfx::ColorSpace& dst_color_space,
- bool adjust_src_white_level,
- absl::optional<gfx::HDRMetadata> hdr_metadata) {
- DCHECK(dst_color_space.IsValid());
- gfx::ColorSpace adjusted_src_color_space = src_color_space;
- if (adjust_src_white_level && src_color_space.IsHDR()) {
- // TODO(b/183236148): consider using the destination's HDR static metadata
- // in current_frame()->display_color_spaces.hdr_static_metadata() and the
- // color volume metadata in |src_hdr_metadata| for the tone mapping; e.g.
- // the content might be mastered in 0-1000 nits but the display only be able
- // to represent 0 to 500.
- adjusted_src_color_space = src_color_space.GetWithSDRWhiteLevel(
- current_frame()->display_color_spaces.GetSDRMaxLuminanceNits());
- }
-
- ProgramKey program_key = program_key_no_color;
- const gfx::ColorTransform* color_transform =
- GetColorTransform(adjusted_src_color_space, dst_color_space);
- program_key.SetColorTransform(color_transform);
-
- bool has_output_color_matrix = false;
- if (program_key.type() != ProgramType::PROGRAM_TYPE_SOLID_COLOR)
- has_output_color_matrix = HasOutputColorMatrix();
- program_key.set_has_output_color_matrix(has_output_color_matrix);
-
- // Create and set the program if needed.
- std::unique_ptr<Program>& program = program_cache_[program_key];
- if (!program) {
- program = std::make_unique<Program>();
- program->Initialize(output_surface_->context_provider(), program_key);
- }
- DCHECK(program);
- if (current_program_ != program.get()) {
- current_program_ = program.get();
- gl_->UseProgram(current_program_->program());
- }
- if (!current_program_->initialized()) {
- DCHECK(IsContextLost());
- return;
- }
-
- // Set uniforms that are common to all programs.
- if (current_program_->sampler_location() != -1)
- gl_->Uniform1i(current_program_->sampler_location(), 0);
- if (current_program_->viewport_location() != -1) {
- float viewport[4] = {
- static_cast<float>(current_window_space_viewport_.x()),
- static_cast<float>(current_window_space_viewport_.y()),
- static_cast<float>(current_window_space_viewport_.width()),
- static_cast<float>(current_window_space_viewport_.height()),
- };
- gl_->Uniform4fv(current_program_->viewport_location(), 1, viewport);
- }
-
- if (has_output_color_matrix) {
- DCHECK_NE(current_program_->output_color_matrix_location(), -1);
- float matrix[16];
- output_surface_->color_matrix().getColMajor(matrix);
- gl_->UniformMatrix4fv(current_program_->output_color_matrix_location(), 1,
- false, matrix);
- }
-}
-
-const Program* GLRenderer::GetProgramIfInitialized(
- const ProgramKey& desc) const {
- const auto found = program_cache_.find(desc);
- if (found == program_cache_.end())
- return nullptr;
- return found->second.get();
-}
-
-const gfx::ColorTransform* GLRenderer::GetColorTransform(
- const gfx::ColorSpace& src,
- const gfx::ColorSpace& dst) {
- ColorTransformKey key;
- key.src = src;
- key.dst = dst;
- key.sdr_max_luminance_nits =
- current_frame()->display_color_spaces.GetSDRMaxLuminanceNits();
- std::unique_ptr<gfx::ColorTransform>& transform = color_transform_cache_[key];
- if (!transform) {
- gfx::ColorTransform::Options options;
- options.tone_map_pq_and_hlg_to_sdr = !dst.IsHDR();
- options.sdr_max_luminance_nits = key.sdr_max_luminance_nits;
- transform = gfx::ColorTransform::NewColorTransform(src, dst, options);
- }
- return transform.get();
-}
-
-void GLRenderer::CleanupSharedObjects() {
- shared_geometry_ = nullptr;
-
- gl_->ReleaseShaderCompiler();
- for (auto& iter : program_cache_)
- iter.second->Cleanup(gl_);
- program_cache_.clear();
- color_transform_cache_.clear();
-
- if (offscreen_framebuffer_id_)
- gl_->DeleteFramebuffers(1, &offscreen_framebuffer_id_);
-
- if (offscreen_stencil_renderbuffer_id_)
- gl_->DeleteRenderbuffers(1, &offscreen_stencil_renderbuffer_id_);
-}
-
-void GLRenderer::ReinitializeGLState() {
- is_scissor_enabled_ = false;
- scissor_rect_ = gfx::Rect();
- stencil_shadow_ = false;
- blend_shadow_ = true;
- current_program_ = nullptr;
-
- RestoreGLState();
-}
-
-void GLRenderer::RestoreGLStateAfterSkia() {
- // After using Skia we need to disable vertex attributes we don't use
- int attribs_count = output_surface_->context_provider()
- ->ContextCapabilities()
- .max_vertex_attribs;
- for (int i = 0; i < attribs_count; i++)
- gl_->DisableVertexAttribArray(i);
-
- RestoreGLState();
-}
-
-void GLRenderer::RestoreGLState() {
- // This restores the current GLRenderer state to the GL context.
- bound_geometry_ = NO_BINDING;
- PrepareGeometry(SHARED_BINDING);
-
- gl_->Disable(GL_DEPTH_TEST);
- gl_->Disable(GL_CULL_FACE);
- gl_->ColorMask(true, true, true, true);
- gl_->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- gl_->ActiveTexture(GL_TEXTURE0);
-
- if (current_program_)
- gl_->UseProgram(current_program_->program());
-
- if (stencil_shadow_)
- gl_->Enable(GL_STENCIL_TEST);
- else
- gl_->Disable(GL_STENCIL_TEST);
-
- if (blend_shadow_)
- gl_->Enable(GL_BLEND);
- else
- gl_->Disable(GL_BLEND);
-
- if (is_scissor_enabled_)
- gl_->Enable(GL_SCISSOR_TEST);
- else
- gl_->Disable(GL_SCISSOR_TEST);
-
- gl_->Scissor(scissor_rect_.x(), scissor_rect_.y(), scissor_rect_.width(),
- scissor_rect_.height());
-}
-
-bool GLRenderer::IsContextLost() {
- return gl_->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
-}
-
-#if BUILDFLAG(IS_APPLE)
-void GLRenderer::ScheduleCALayers() {
- // The use of OverlayTextures for RenderPasses is only supported on the code
- // paths for |release_overlay_resources_after_gpu_query| at the moment. See
- // SwapBuffersComplete for notes on the missing support for other paths. This
- // method uses ScheduleRenderPassDrawQuad to send RenderPass outputs as
- // overlays, so it can only be used because this setting is true.
- if (!settings_->release_overlay_resources_after_gpu_query)
- return;
-
- scoped_refptr<CALayerOverlaySharedState> shared_state;
-
- for (const CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) {
- if (ca_layer_overlay.rpdq) {
- std::unique_ptr<OverlayTexture> overlay_texture =
- ScheduleRenderPassDrawQuad(&ca_layer_overlay);
- if (overlay_texture)
- awaiting_swap_overlay_textures_.push_back(std::move(overlay_texture));
- shared_state = nullptr;
- continue;
- }
-
- ResourceId contents_resource_id = ca_layer_overlay.contents_resource_id;
- unsigned texture_id = 0;
- if (contents_resource_id) {
- pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProviderGL::ScopedOverlayLockGL>(
- resource_provider(), contents_resource_id));
- texture_id = pending_overlay_resources_.back()->texture_id();
- }
- GLfloat contents_rect[4] = {
- ca_layer_overlay.contents_rect.x(), ca_layer_overlay.contents_rect.y(),
- ca_layer_overlay.contents_rect.width(),
- ca_layer_overlay.contents_rect.height(),
- };
- GLfloat bounds_rect[4] = {
- ca_layer_overlay.bounds_rect.x(), ca_layer_overlay.bounds_rect.y(),
- ca_layer_overlay.bounds_rect.width(),
- ca_layer_overlay.bounds_rect.height(),
- };
- GLboolean is_clipped = ca_layer_overlay.shared_state->is_clipped;
- GLfloat clip_rect[4] = {ca_layer_overlay.shared_state->clip_rect.x(),
- ca_layer_overlay.shared_state->clip_rect.y(),
- ca_layer_overlay.shared_state->clip_rect.width(),
- ca_layer_overlay.shared_state->clip_rect.height()};
-
- const gfx::RectF& rect =
- ca_layer_overlay.shared_state->rounded_corner_bounds.rect();
- GLfloat rounded_corner_bounds[5] = {
- rect.x(), rect.y(), rect.width(), rect.height(),
- ca_layer_overlay.shared_state->rounded_corner_bounds.GetSimpleRadius()};
-
- GLint sorting_context_id =
- ca_layer_overlay.shared_state->sorting_context_id;
- GLfloat transform[16];
- ca_layer_overlay.shared_state->transform.matrix().getColMajor(transform);
- unsigned filter = ca_layer_overlay.filter;
-
- if (ca_layer_overlay.shared_state != shared_state) {
- shared_state = ca_layer_overlay.shared_state;
- gl_->ScheduleCALayerSharedStateCHROMIUM(
- ca_layer_overlay.shared_state->opacity, is_clipped, clip_rect,
- rounded_corner_bounds, sorting_context_id, transform);
- }
- gl_->ScheduleCALayerCHROMIUM(
- texture_id, contents_rect, ca_layer_overlay.background_color,
- ca_layer_overlay.edge_aa_mask, bounds_rect, filter);
- }
-
- ReduceAvailableOverlayTextures();
-}
-#endif // BUILDFLAG(IS_APPLE)
-
-#if BUILDFLAG(IS_WIN)
-void GLRenderer::ScheduleDCLayers() {
- for (DCLayerOverlay& dc_layer_overlay : current_frame()->overlay_list) {
- DCHECK_EQ(DCLayerOverlay::kNumResources, 2u);
- GLuint texture_ids[DCLayerOverlay::kNumResources] = {};
- for (size_t i = 0; i < DCLayerOverlay::kNumResources; i++) {
- ResourceId resource_id = dc_layer_overlay.resources[i];
- if (resource_id == kInvalidResourceId)
- break;
- pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProviderGL::ScopedOverlayLockGL>(
- resource_provider(), resource_id));
- texture_ids[i] = pending_overlay_resources_.back()->texture_id();
- }
- DCHECK(texture_ids[0]);
- // TODO(sunnyps): Set color space in renderer like we do for tiles.
- gl_->SetColorSpaceMetadataCHROMIUM(
- texture_ids[0], dc_layer_overlay.color_space.AsGLColorSpace());
-
- int z_order = dc_layer_overlay.z_order;
- const gfx::Rect& content_rect = dc_layer_overlay.content_rect;
- const gfx::Rect& quad_rect = dc_layer_overlay.quad_rect;
- DCHECK(dc_layer_overlay.transform.IsFlat());
- const auto& matrix = dc_layer_overlay.transform.matrix();
- bool is_clipped = dc_layer_overlay.clip_rect.has_value();
- const gfx::Rect& clip_rect =
- dc_layer_overlay.clip_rect.value_or(gfx::Rect());
- unsigned protected_video_type =
- static_cast<unsigned>(dc_layer_overlay.protected_video_type);
-
- gl_->ScheduleDCLayerCHROMIUM(
- texture_ids[0], texture_ids[1], z_order, content_rect.x(),
- content_rect.y(), content_rect.width(), content_rect.height(),
- quad_rect.x(), quad_rect.y(), quad_rect.width(), quad_rect.height(),
- matrix.rc(0, 0), matrix.rc(0, 1), matrix.rc(1, 0), matrix.rc(1, 1),
- matrix.rc(0, 3), matrix.rc(1, 3), is_clipped, clip_rect.x(),
- clip_rect.y(), clip_rect.width(), clip_rect.height(),
- protected_video_type);
- }
-}
-#endif // BUILDFLAG(IS_WIN)
-
-#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
-void GLRenderer::ScheduleOverlays() {
- if (current_frame()->overlay_list.empty())
- return;
-
- OverlayCandidateList& overlays = current_frame()->overlay_list;
- for (const auto& overlay_candidate : overlays) {
- pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProviderGL::ScopedOverlayLockGL>(
- resource_provider(), overlay_candidate.resource_id));
- unsigned texture_id = pending_overlay_resources_.back()->texture_id();
-
- context_support_->ScheduleOverlayPlane(
- overlay_candidate.plane_z_order, overlay_candidate.transform,
- texture_id, ToNearestRect(overlay_candidate.display_rect),
- overlay_candidate.uv_rect, !overlay_candidate.is_opaque,
- overlay_candidate.gpu_fence_id);
- }
-}
-#endif // BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
-
-void GLRenderer::ScheduleOutputSurfaceAsOverlay() {
- if (!current_frame()->output_surface_plane)
- return;
-
- // Initialize correct values to use an output surface as overlay candidate.
- auto& overlay_candidate = *(current_frame()->output_surface_plane);
- unsigned texture_id = output_surface_->GetOverlayTextureId();
- DCHECK(texture_id || IsContextLost());
- // Output surface is also z-order 0.
- int plane_z_order = 0;
-
- context_support_->ScheduleOverlayPlane(
- plane_z_order, overlay_candidate.transform, texture_id,
- ToNearestRect(overlay_candidate.display_rect), overlay_candidate.uv_rect,
- overlay_candidate.enable_blending, overlay_candidate.gpu_fence_id);
-}
-
-#if BUILDFLAG(IS_APPLE)
-// This function draws the CompositorRenderPassDrawQuad into a temporary
-// texture/framebuffer, and then copies the result into an IOSurface. The
-// inefficient (but simple) way to do this would be to:
-// 1. Allocate a framebuffer the size of the screen.
-// 2. Draw using all the normal RPDQ draw logic.
-//
-// Instead, this method does the following:
-// 1. Configure parameters as if drawing to a framebuffer the size of the
-// screen. This reuses most of the RPDQ draw logic.
-// 2. Update parameters to draw into a framebuffer only as large as needed.
-// 3. Fix shader uniforms that were broken by (2).
-//
-// Then:
-// 4. Allocate an IOSurface as the drawing destination.
-// 5. Draw the RPDQ.
-void GLRenderer::CopyRenderPassDrawQuadToOverlayResource(
- const CALayerOverlay* ca_layer_overlay,
- std::unique_ptr<OverlayTexture>* overlay_texture,
- gfx::RectF* new_bounds) {
- // Don't carry over any GL state from previous RenderPass draw operations.
- ReinitializeGLState();
- auto contents_texture_it =
- render_pass_textures_.find(ca_layer_overlay->rpdq->render_pass_id);
- DCHECK(contents_texture_it != render_pass_textures_.end());
-
- // Configure parameters as if drawing to a framebuffer the size of the
- // screen.
- DrawRenderPassDrawQuadParams params;
- params.quad = ca_layer_overlay->rpdq;
- params.flip_texture = true;
- params.contents_texture = &contents_texture_it->second;
- params.quad_to_target_transform =
- params.quad->shared_quad_state->quad_to_target_transform;
- params.tex_coord_rect = params.quad->tex_coord_rect;
-
- // Calculate projection and window matrices using InitializeViewport(). This
- // requires creating a dummy DrawingFrame.
- {
- DrawingFrame dummy_frame;
- gfx::Rect frame_rect(current_frame()->device_viewport_size);
- force_drawing_frame_framebuffer_unflipped_ = true;
- InitializeViewport(&dummy_frame, frame_rect, frame_rect, frame_rect.size());
- force_drawing_frame_framebuffer_unflipped_ = false;
- params.projection_matrix = dummy_frame.projection_matrix;
- params.window_matrix = dummy_frame.window_matrix;
- }
-
- // Perform basic initialization with the screen-sized viewport.
- if (!InitializeRPDQParameters(&params))
- return;
-
- if (!UpdateRPDQWithSkiaFilters(&params))
- return;
-
- // |params.dst_rect| now contain values that reflect a potentially increased
- // size quad.
- gfx::RectF updated_dst_rect = params.dst_rect;
- gfx::Size dst_pixel_size = gfx::ToCeiledSize(updated_dst_rect.size());
-
- int iosurface_width = dst_pixel_size.width();
- int iosurface_height = dst_pixel_size.height();
- if (!settings_->dont_round_texture_sizes_for_pixel_tests) {
- // Round the size of the IOSurface to a multiple of 64 pixels. This reduces
- // memory fragmentation. https://crbug.com/146070. This also allows
- // IOSurfaces to be more easily reused during a resize operation.
- int iosurface_multiple = 64;
- iosurface_width =
- cc::MathUtil::CheckedRoundUp(iosurface_width, iosurface_multiple);
- iosurface_height =
- cc::MathUtil::CheckedRoundUp(iosurface_height, iosurface_multiple);
- }
-
- *overlay_texture =
- FindOrCreateOverlayTexture(params.quad->render_pass_id, iosurface_width,
- iosurface_height, RootRenderPassColorSpace());
- *new_bounds = gfx::RectF(updated_dst_rect.origin(),
- gfx::SizeF((*overlay_texture)->texture.size()));
-
- // Calculate new projection and window matrices for a minimally sized viewport
- // using InitializeViewport(). This requires creating a dummy DrawingFrame.
- {
- DrawingFrame dummy_frame;
- force_drawing_frame_framebuffer_unflipped_ = true;
- gfx::Rect frame_rect =
- gfx::Rect(0, 0, updated_dst_rect.width(), updated_dst_rect.height());
- InitializeViewport(&dummy_frame, frame_rect, frame_rect, frame_rect.size());
- force_drawing_frame_framebuffer_unflipped_ = false;
- params.projection_matrix = dummy_frame.projection_matrix;
- params.window_matrix = dummy_frame.window_matrix;
- }
-
- // Calculate a new quad_to_target_transform.
- params.quad_to_target_transform = gfx::Transform();
- params.quad_to_target_transform.Translate(-updated_dst_rect.x(),
- -updated_dst_rect.y());
-
- // Antialiasing works by fading out content that is close to the edge of the
- // viewport. All of these values need to be recalculated.
- if (params.use_aa) {
- current_window_space_viewport_ =
- gfx::Rect(0, 0, updated_dst_rect.width(), updated_dst_rect.height());
- gfx::Transform quad_rect_matrix;
- QuadRectTransform(&quad_rect_matrix, params.quad_to_target_transform,
- updated_dst_rect);
- params.contents_device_transform =
- params.window_matrix * params.projection_matrix * quad_rect_matrix;
- bool clipped = false;
- params.contents_device_transform.FlattenTo2d();
- gfx::QuadF device_layer_quad = cc::MathUtil::MapQuad(
- params.contents_device_transform, SharedGeometryQuad(), &clipped);
- LayerQuad device_layer_edges(device_layer_quad);
- InflateAntiAliasingDistances(device_layer_quad, &device_layer_edges,
- params.edge);
- }
-
- // Establish destination texture.
- GLuint temp_fbo;
- gl_->GenFramebuffers(1, &temp_fbo);
- gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- (*overlay_texture)->texture.target(),
- (*overlay_texture)->texture.id(), 0);
- DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
- GL_FRAMEBUFFER_COMPLETE ||
- IsContextLost());
-
- // Clear to 0 to ensure the background is transparent.
- gl_->ClearColor(0, 0, 0, 0);
- gl_->Clear(GL_COLOR_BUFFER_BIT);
-
- UpdateRPDQTexturesForSampling(&params);
- UpdateRPDQBlendMode(&params);
- // The code in this method (CopyRenderPassDrawQuadToOverlayResource) is
- // only called when we are drawing for the purpose of copying to
- // a CALayerOverlay. In such cases, the CALayerOverlay applies rounded
- // corners via CALayer parameters, so the shader-based rounded corners
- // should be disabled here.
- params.apply_shader_based_rounded_corner = false;
- ChooseRPDQProgram(&params, (*overlay_texture)->texture.color_space());
- UpdateRPDQUniforms(&params);
-
- // Prior to drawing, set up the destination framebuffer and viewport.
- gl_->BindFramebuffer(GL_FRAMEBUFFER, temp_fbo);
- gl_->Viewport(0, 0, updated_dst_rect.width(), updated_dst_rect.height());
-
- DrawRPDQ(params);
- if (params.background_texture) {
- gl_->DeleteTextures(1, &params.background_texture);
- params.background_texture = 0;
- }
- gl_->DeleteFramebuffers(1, &temp_fbo);
-}
-
-std::unique_ptr<GLRenderer::OverlayTexture>
-GLRenderer::FindOrCreateOverlayTexture(
- const AggregatedRenderPassId& render_pass_id,
- int width,
- int height,
- const gfx::ColorSpace& color_space) {
- // First try to use a texture for the same CompositorRenderPassId, to keep
- // things more stable and less likely to clobber each others textures.
- auto match_with_id = [&](const std::unique_ptr<OverlayTexture>& overlay) {
- return overlay->render_pass_id == render_pass_id &&
- overlay->texture.size().width() >= width &&
- overlay->texture.size().height() >= height &&
- overlay->texture.size().width() <= width * 2 &&
- overlay->texture.size().height() <= height * 2;
- };
- auto it = std::find_if(available_overlay_textures_.begin(),
- available_overlay_textures_.end(), match_with_id);
- if (it != available_overlay_textures_.end()) {
- std::unique_ptr<OverlayTexture> result = std::move(*it);
- available_overlay_textures_.erase(it);
-
- result->render_pass_id = render_pass_id;
- return result;
- }
-
- // Then fallback to trying other textures that still match.
- auto match = [&](const std::unique_ptr<OverlayTexture>& overlay) {
- return overlay->texture.size().width() >= width &&
- overlay->texture.size().height() >= height &&
- overlay->texture.size().width() <= width * 2 &&
- overlay->texture.size().height() <= height * 2;
- };
- it = std::find_if(available_overlay_textures_.begin(),
- available_overlay_textures_.end(), match);
- if (it != available_overlay_textures_.end()) {
- std::unique_ptr<OverlayTexture> result = std::move(*it);
- available_overlay_textures_.erase(it);
-
- result->render_pass_id = render_pass_id;
- return result;
- }
-
- // Make a new texture if we could not find a match. Sadtimes.
- auto result = std::make_unique<OverlayTexture>();
- result->texture = ScopedGpuMemoryBufferTexture(
- output_surface_->context_provider(),
- gfx::Size(width, height), color_space);
- result->render_pass_id = render_pass_id;
- return result;
-}
-
-void GLRenderer::ReduceAvailableOverlayTextures() {
- // Overlay resources may get returned back to the compositor at varying rates,
- // so we may get a number of resources returned at once, then none for a
- // while. As such, we want to hold onto enough resources to not have to create
- // any when none are released for a while. Emperical study by erikchen@ on
- // crbug.com/636884 found that saving 5 spare textures per RenderPass was
- // sufficient for important benchmarks. This seems to imply that the OS may
- // hold up to 5 frames of textures before releasing them.
- static const int kKeepCountPerRenderPass = 5;
-
- // In order to accomodate the above requirements, we hold any released texture
- // in the |available_overlay_textures_| set for up to 5 frames before
- // discarding it.
- for (const auto& overlay : available_overlay_textures_)
- overlay->frames_waiting_for_reuse++;
- base::EraseIf(available_overlay_textures_,
- [](const std::unique_ptr<OverlayTexture>& overlay) {
- return overlay->frames_waiting_for_reuse >=
- kKeepCountPerRenderPass;
- });
-}
-
-std::unique_ptr<GLRenderer::OverlayTexture>
-GLRenderer::ScheduleRenderPassDrawQuad(const CALayerOverlay* ca_layer_overlay) {
- DCHECK(ca_layer_overlay->rpdq);
-
- std::unique_ptr<OverlayTexture> overlay_texture;
- gfx::RectF new_bounds;
- CopyRenderPassDrawQuadToOverlayResource(ca_layer_overlay, &overlay_texture,
- &new_bounds);
- if (!overlay_texture)
- return {};
-
- GLfloat contents_rect[4] = {
- ca_layer_overlay->contents_rect.x(), ca_layer_overlay->contents_rect.y(),
- ca_layer_overlay->contents_rect.width(),
- ca_layer_overlay->contents_rect.height(),
- };
- GLfloat bounds_rect[4] = {
- new_bounds.x(), new_bounds.y(), new_bounds.width(), new_bounds.height(),
- };
- GLboolean is_clipped = ca_layer_overlay->shared_state->is_clipped;
- GLfloat clip_rect[4] = {ca_layer_overlay->shared_state->clip_rect.x(),
- ca_layer_overlay->shared_state->clip_rect.y(),
- ca_layer_overlay->shared_state->clip_rect.width(),
- ca_layer_overlay->shared_state->clip_rect.height()};
-
- const gfx::RectF& rect =
- ca_layer_overlay->shared_state->rounded_corner_bounds.rect();
- GLfloat rounded_corner_rect[5] = {
- rect.x(), rect.y(), rect.width(), rect.height(),
- ca_layer_overlay->shared_state->rounded_corner_bounds.GetSimpleRadius()};
-
- GLint sorting_context_id = ca_layer_overlay->shared_state->sorting_context_id;
- GLfloat gl_transform[16];
- ca_layer_overlay->shared_state->transform.matrix().getColMajor(gl_transform);
- unsigned filter = ca_layer_overlay->filter;
-
- // The alpha has already been applied when copying the RPDQ to an IOSurface.
- GLfloat alpha = 1;
- gl_->ScheduleCALayerSharedStateCHROMIUM(alpha, is_clipped, clip_rect,
- rounded_corner_rect,
- sorting_context_id, gl_transform);
- gl_->ScheduleCALayerCHROMIUM(overlay_texture->texture.id(), contents_rect,
- ca_layer_overlay->background_color,
- ca_layer_overlay->edge_aa_mask, bounds_rect,
- filter);
- return overlay_texture;
-}
-#endif // BUILDFLAG(IS_APPLE)
-
-void GLRenderer::SetupOverdrawFeedback() {
- gl_->StencilFunc(GL_ALWAYS, 1, 0xffffffff);
- // First two values are ignored as test always passes.
- gl_->StencilOp(GL_KEEP, GL_KEEP, GL_INCR);
- gl_->StencilMask(0xffffffff);
-}
-
-void GLRenderer::FlushOverdrawFeedback(const gfx::Rect& output_rect) {
- DCHECK(stencil_shadow_);
-
- // Test only, keep everything.
- gl_->StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
- EnsureScissorTestDisabled();
- SetBlendEnabled(true);
-
- PrepareGeometry(SHARED_BINDING);
-
- SetUseProgram(ProgramKey::DebugBorder(), gfx::ColorSpace::CreateSRGB(),
- CurrentRenderPassColorSpace());
-
- gfx::Transform render_matrix;
- render_matrix.Translate(0.5 * output_rect.width() + output_rect.x(),
- 0.5 * output_rect.height() + output_rect.y());
- render_matrix.Scale(output_rect.width(), output_rect.height());
- SetShaderMatrix(current_frame()->projection_matrix * render_matrix);
-
- // Produce hinting for the amount of overdraw on screen for each pixel by
- // drawing hint colors to the framebuffer based on the current stencil value.
- struct {
- int multiplier;
- GLenum func;
- GLint ref;
- SkColor color;
- } stencil_tests[] = {
- {1, GL_EQUAL, 2, 0x2f0000ff}, // Blue: Overdrawn once.
- {2, GL_EQUAL, 3, 0x2f00ff00}, // Green: Overdrawn twice.
- {3, GL_EQUAL, 4, 0x3fff0000}, // Pink: Overdrawn three times.
- {4, GL_LESS, 4, 0x7fff0000}, // Red: Overdrawn four or more times.
- };
-
- for (const auto& test : stencil_tests) {
- gl_->StencilFunc(test.func, test.ref, 0xffffffff);
- // Transparent color unless color-coding of overdraw is enabled.
- SetShaderColor(debug_settings_->show_overdraw_feedback ? test.color : 0,
- 1.f);
- gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, nullptr);
- }
-}
-
-void GLRenderer::ProcessOverdrawFeedback(base::CheckedNumeric<int> surface_area,
- unsigned occlusion_query) {
- unsigned result = 0;
- DCHECK(occlusion_query);
- gl_->GetQueryObjectuivEXT(occlusion_query, GL_QUERY_RESULT_EXT, &result);
- gl_->DeleteQueriesEXT(1, &occlusion_query);
-
- // Report GPU overdraw as a percentage of |surface_area|.
- TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("viz.overdraw"), "GPU Overdraw",
- (result * 100.0 /
- static_cast<int>(surface_area.ValueOrDefault(INT_MAX))));
-}
-
-void GLRenderer::UpdateRenderPassTextures(
- const AggregatedRenderPassList& render_passes_in_draw_order,
- const base::flat_map<AggregatedRenderPassId, RenderPassRequirements>&
- render_passes_in_frame) {
- // Collect RenderPass textures that should be deleted.
- std::vector<AggregatedRenderPassId> passes_to_delete;
- for (const auto& pair : render_pass_textures_) {
- auto render_pass_it = render_passes_in_frame.find(pair.first);
- if (render_pass_it == render_passes_in_frame.end()) {
- passes_to_delete.push_back(pair.first);
- continue;
- }
- const RenderPassRequirements& requirements = render_pass_it->second;
- const ScopedRenderPassTexture& texture = pair.second;
- bool size_appropriate =
- texture.size().width() >= requirements.size.width() &&
- texture.size().height() >= requirements.size.height();
- bool mipmap_appropriate = !requirements.generate_mipmap || texture.mipmap();
- if (!size_appropriate || !mipmap_appropriate)
- passes_to_delete.push_back(pair.first);
- }
- // Delete RenderPass textures from the previous frame that will not be used
- // again.
- for (auto& pass_to_delete : passes_to_delete) {
- auto rp_backdrop_texture_it =
- render_pass_backdrop_textures_.find(pass_to_delete);
- if (rp_backdrop_texture_it != render_pass_backdrop_textures_.end())
- render_pass_backdrop_textures_.erase(pass_to_delete);
- render_pass_textures_.erase(pass_to_delete);
- }
-}
-
-ResourceFormat GLRenderer::CurrentRenderPassResourceFormat() const {
- const auto& caps = output_surface_->context_provider()->ContextCapabilities();
- if (CurrentRenderPassColorSpace().IsHDR()) {
- // If a platform does not support half-float renderbuffers then it should
- // not should request HDR rendering.
- DCHECK(caps.texture_half_float_linear);
- DCHECK(caps.color_buffer_half_float_rgba);
- return RGBA_F16;
- }
- return PlatformColor::BestSupportedTextureFormat(caps);
-}
-
-bool GLRenderer::HasOutputColorMatrix() const {
- const bool is_root_render_pass =
- current_frame()->current_render_pass == current_frame()->root_render_pass;
- const SkM44& output_color_matrix = output_surface_->color_matrix();
- return is_root_render_pass && output_color_matrix != SkM44();
-}
-
-bool GLRenderer::CanUseFastSolidColorDraw(
- const SolidColorDrawQuad* quad) const {
- const SharedQuadState* sqs = quad->shared_quad_state;
-
- if (!use_fast_path_solid_color_quad_)
- return false;
-
- // Mask filters require blending with the background, which is not possible
- // with the glClear draw method.
- if (!sqs->mask_filter_info.IsEmpty())
- return false;
-
- // 3D transforms need vertex computation in 3D and cannot be handled using
- // glClear().
- if (!sqs->quad_to_target_transform.IsFlat())
- return false;
-
- // glClear ignores stencil buffer.
- if (stencil_shadow_)
- return false;
-
- // Any non axis aligned transform cannot be handled by glClear.
- if (!sqs->quad_to_target_transform.Preserves2dAxisAlignment())
- return false;
-
- // When no blending is needed, glClear can be used.
- SkBlendMode blend_mode = quad->shared_quad_state->blend_mode;
- if (blend_mode == SkBlendMode::kSrc)
- return true;
-
- if (blend_mode == SkBlendMode::kSrcOver) {
- // Blending will replace destination color and alpha if the quad is opaque.
- if (SkColorGetA(quad->color) == 255 &&
- quad->shared_quad_state->opacity >= 1.0f) {
- return true;
- }
-
- // It is safe to use glClearColor with alpha blending when the render
- // pass has transparent background and nothing has drawn to the same rect
- // area because the blending happens against (0, 0, 0, 0) which is the same
- // as replacing the destination color & alpha.
- if (!current_frame()->current_render_pass->has_transparent_background)
- return false;
-
- gfx::RectF quad_rect_in_target(quad->visible_rect);
- sqs->quad_to_target_transform.TransformRect(&quad_rect_in_target);
- const gfx::Rect quad_rect_in_target_rounded =
- gfx::ToRoundedRect(quad_rect_in_target);
-
- // If the quad does not intersect any region that has already been drawn
- // to, then blending is not an issue and fast draw path can be used.
- for (const auto& rect : drawn_rects_)
- if (quad_rect_in_target_rounded.Intersects(rect))
- return false;
- return true;
- }
-
- return false;
-}
-
-void GLRenderer::AllocateRenderPassResourceIfNeeded(
- const AggregatedRenderPassId& render_pass_id,
- const RenderPassRequirements& requirements) {
- auto contents_texture_it = render_pass_textures_.find(render_pass_id);
- if (contents_texture_it != render_pass_textures_.end()) {
- DCHECK(gfx::Rect(contents_texture_it->second.size())
- .Contains(gfx::Rect(requirements.size)));
- return;
- }
-
- ScopedRenderPassTexture contents_texture(
- output_surface_->context_provider(), requirements.size,
- CurrentRenderPassResourceFormat(), CurrentRenderPassColorSpace(),
- requirements.generate_mipmap);
- render_pass_textures_[render_pass_id] = std::move(contents_texture);
-}
-
-bool GLRenderer::IsRenderPassResourceAllocated(
- const AggregatedRenderPassId& render_pass_id) const {
- auto texture_it = render_pass_textures_.find(render_pass_id);
- return texture_it != render_pass_textures_.end();
-}
-
-gfx::Size GLRenderer::GetRenderPassBackingPixelSize(
- const AggregatedRenderPassId& render_pass_id) {
- auto texture_it = render_pass_textures_.find(render_pass_id);
- DCHECK(texture_it != render_pass_textures_.end());
- return texture_it->second.size();
-}
-
-GLRenderer::OverlayTexture::OverlayTexture() = default;
-GLRenderer::OverlayTexture::~OverlayTexture() = default;
-
-bool GLRenderer::ColorTransformKey::operator==(
- const ColorTransformKey& other) const {
- return src == other.src && dst == other.dst &&
- sdr_max_luminance_nits == other.sdr_max_luminance_nits;
-}
-
-bool GLRenderer::ColorTransformKey::operator!=(
- const ColorTransformKey& other) const {
- return !(*this == other);
-}
-
-bool GLRenderer::ColorTransformKey::operator<(
- const ColorTransformKey& other) const {
- return std::tie(src, dst, sdr_max_luminance_nits) <
- std::tie(other.src, other.dst, other.sdr_max_luminance_nits);
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h
deleted file mode 100644
index f3106e13715..00000000000
--- a/chromium/components/viz/service/display/gl_renderer.h
+++ /dev/null
@@ -1,525 +0,0 @@
-// Copyright 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include "base/cancelable_callback.h"
-#include "base/containers/circular_deque.h"
-#include "base/containers/queue.h"
-#include "base/memory/raw_ptr.h"
-#include "build/build_config.h"
-#include "components/viz/common/gpu/context_cache_controller.h"
-#include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
-#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
-#include "components/viz/common/quads/debug_border_draw_quad.h"
-#include "components/viz/common/quads/solid_color_draw_quad.h"
-#include "components/viz/common/quads/tile_draw_quad.h"
-#include "components/viz/common/quads/yuv_video_draw_quad.h"
-#include "components/viz/service/display/direct_renderer.h"
-#include "components/viz/service/display/display_resource_provider_gl.h"
-#include "components/viz/service/display/gl_renderer_copier.h"
-#include "components/viz/service/display/gl_renderer_draw_cache.h"
-#include "components/viz/service/display/program_binding.h"
-#include "components/viz/service/display/scoped_gpu_memory_buffer_texture.h"
-#include "components/viz/service/display/sync_query_collection.h"
-#include "components/viz/service/display/texture_deleter.h"
-#include "components/viz/service/viz_service_export.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/gpu_fence_handle.h"
-#include "ui/latency/latency_info.h"
-
-#if BUILDFLAG(IS_APPLE)
-#include "components/viz/service/display/ca_layer_overlay.h"
-#endif
-
-#if BUILDFLAG(IS_WIN)
-#include "components/viz/service/display/dc_layer_overlay.h"
-#endif
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-} // namespace gpu
-
-namespace gfx {
-class RRectF;
-}
-
-namespace viz {
-
-class DynamicGeometryBinding;
-class GLRendererShaderTest;
-class OutputSurface;
-class ScopedRenderPassTexture;
-class StaticGeometryBinding;
-class StreamVideoDrawQuad;
-class TextureDrawQuad;
-
-// Class that handles drawing of composited render layers using GL.
-class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
- public:
- class ScopedUseGrContext;
-
- GLRenderer(const RendererSettings* settings,
- const DebugRendererSettings* debug_settings,
- OutputSurface* output_surface,
- DisplayResourceProviderGL* resource_provider,
- OverlayProcessorInterface* overlay_processor,
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner);
-
- GLRenderer(const GLRenderer&) = delete;
- GLRenderer& operator=(const GLRenderer&) = delete;
-
- ~GLRenderer() override;
-
- bool use_swap_with_bounds() const { return use_swap_with_bounds_; }
-
- void SwapBuffers(SwapFrameData swap_frame_data) override;
- void SwapBuffersSkipped() override;
- void SwapBuffersComplete(gfx::GpuFenceHandle release_fence) override;
- void BuffersPresented() override;
-
- void DidReceiveTextureInUseResponses(
- const gpu::TextureInUseResponses& responses) override;
-
- virtual bool IsContextLost();
-
- protected:
- void DidChangeVisibility() override;
-
- bool stencil_enabled() const { return stencil_shadow_; }
-
- bool CanPartialSwap() override;
- void UpdateRenderPassTextures(
- const AggregatedRenderPassList& render_passes_in_draw_order,
- const base::flat_map<AggregatedRenderPassId, RenderPassRequirements>&
- render_passes_in_frame) override;
- void AllocateRenderPassResourceIfNeeded(
- const AggregatedRenderPassId& render_pass_id,
- const RenderPassRequirements& requirements) override;
- bool IsRenderPassResourceAllocated(
- const AggregatedRenderPassId& render_pass_id) const override;
- gfx::Size GetRenderPassBackingPixelSize(
- const AggregatedRenderPassId& render_pass_id) override;
- void BindFramebufferToOutputSurface() override;
- void BindFramebufferToTexture(
- const AggregatedRenderPassId render_pass_id) override;
- void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
- void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
- const gfx::Rect& render_pass_scissor) override;
- void DoDrawQuad(const class DrawQuad*,
- const gfx::QuadF* draw_region) override;
- void BeginDrawingFrame() override;
- void FlushOverdrawFeedback(const gfx::Rect& output_rect) override;
- void FinishDrawingFrame() override;
- bool FlippedFramebuffer() const override;
- bool FlippedRootFramebuffer() const;
- void EnsureScissorTestEnabled() override;
- void EnsureScissorTestDisabled() override;
- void CopyDrawnRenderPass(const copy_output::RenderPassGeometry& geometry,
- std::unique_ptr<CopyOutputRequest> request) override;
- void FinishDrawingQuadList() override;
- void GenerateMipmap() override;
-
- // Returns true if quad requires antialiasing and false otherwise.
- static bool ShouldAntialiasQuad(const gfx::QuadF& device_layer_quad,
- bool clipped,
- bool force_aa);
-
- // Inflate the quad and fill edge array for fragment shader.
- // |local_quad| is set to inflated quad. |edge| array is filled with
- // inflated quad's edge data.
- static void SetupQuadForClippingAndAntialiasing(
- const gfx::Transform& device_transform,
- const DrawQuad* quad,
- const gfx::QuadF* device_layer_quad,
- const gfx::QuadF* clip_region,
- gfx::QuadF* local_quad,
- float edge[24]);
- static void SetupRenderPassQuadForClippingAndAntialiasing(
- const gfx::Transform& device_transform,
- const AggregatedRenderPassDrawQuad* quad,
- const gfx::QuadF* device_layer_quad,
- const gfx::QuadF* clip_region,
- gfx::QuadF* local_quad,
- float edge[24]);
-
- private:
- friend class GLRendererCopierPixelTest;
- friend class GLRendererShaderPixelTest;
- friend class GLRendererShaderTest;
- friend class GLRendererTest;
-
- using OverlayResourceLock =
- std::unique_ptr<DisplayResourceProviderGL::ScopedOverlayLockGL>;
- using OverlayResourceLockList = std::vector<OverlayResourceLock>;
-
- // If a RenderPass is used as an overlay, we render the RenderPass with any
- // effects into a texture for overlay use. We must keep the texture alive past
- // the execution of SwapBuffers, and such textures are more expensive to make
- // so we want to reuse them.
- struct OverlayTexture {
- OverlayTexture();
- ~OverlayTexture();
-
- AggregatedRenderPassId render_pass_id;
- ScopedGpuMemoryBufferTexture texture;
- int frames_waiting_for_reuse = 0;
- };
-
- struct DrawRenderPassDrawQuadParams;
-
- // Returns the format to use for storage if copying from the current
- // framebuffer. If the root renderpass is current, it uses the best matching
- // format from the OutputSurface, otherwise it uses the best matching format
- // from the texture being drawn to as the backbuffer.
- GLenum GetFramebufferCopyTextureFormat();
- void ReleaseRenderPassTextures();
- enum BoundGeometry { NO_BINDING, SHARED_BINDING, CLIPPED_BINDING };
- void PrepareGeometry(BoundGeometry geometry_to_bind);
- void SetStencilEnabled(bool enabled);
- void SetBlendEnabled(bool enabled);
- bool blend_enabled() const { return blend_shadow_; }
-
- // If any of the following functions returns false, then it means that drawing
- // is not possible.
- bool InitializeRPDQParameters(DrawRenderPassDrawQuadParams* params);
- void UpdateRPDQShadersForBlending(DrawRenderPassDrawQuadParams* params);
- bool UpdateRPDQWithSkiaFilters(DrawRenderPassDrawQuadParams* params);
- void UpdateRPDQTexturesForSampling(DrawRenderPassDrawQuadParams* params);
- void UpdateRPDQBlendMode(DrawRenderPassDrawQuadParams* params);
- void ChooseRPDQProgram(DrawRenderPassDrawQuadParams* params,
- const gfx::ColorSpace& target_color_space);
- void UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params);
- void DrawRPDQ(const DrawRenderPassDrawQuadParams& params);
-
- static void ToGLMatrix(float* gl_matrix, const gfx::Transform& transform);
-
- void DiscardPixels();
- void ClearFramebuffer();
- void SetViewport();
-
- void DrawDebugBorderQuad(const DebugBorderDrawQuad* quad);
- static bool IsDefaultBlendMode(SkBlendMode blend_mode) {
- return blend_mode == SkBlendMode::kSrcOver;
- }
- bool CanApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode);
- void ApplyBlendModeUsingBlendFunc(SkBlendMode blend_mode);
- void RestoreBlendFuncToDefault(SkBlendMode blend_mode);
-
- // Returns the rect that should be sampled from the backdrop texture to be
- // backdrop filtered. This rect lives in window pixel space. The
- // |backdrop_filter_bounds| output lives in the space of the output rect
- // returned by this function. It will be used to clip the sampled backdrop
- // texture. The |unclipped_rect| output is the unclipped (full) rect that the
- // backdrop_filter should be applied to, in window pixel space.
- gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
- DrawRenderPassDrawQuadParams* params,
- gfx::Transform* backdrop_filter_bounds_transform,
- absl::optional<gfx::RRectF>* backdrop_filter_bounds,
- gfx::Rect* unclipped_rect) const;
-
- // Allocates and returns a texture id that contains a copy of the contents
- // of the current RenderPass being drawn.
- uint32_t GetBackdropTexture(const gfx::Rect& window_rect,
- float scale,
- GLenum* internal_format);
-
- static bool ShouldApplyBackdropFilters(
- const DrawRenderPassDrawQuadParams* params);
-
- // Applies the backdrop filters to the backdrop that has been painted to this
- // point, and returns it as an SkImage. Any opacity and/or "regular"
- // (non-backdrop) filters will also be applied directly to the backdrop-
- // filtered image at this point, so that the final result is as if the
- // filtered backdrop image was painted as the starting point for this new
- // stacking context, which would then be painted into its parent with opacity
- // and filters applied. This is an approximation, but it should be close
- // enough.
- sk_sp<SkImage> ApplyBackdropFilters(
- DrawRenderPassDrawQuadParams* params,
- const gfx::Rect& unclipped_rect,
- const absl::optional<gfx::RRectF>& backdrop_filter_bounds,
- const gfx::Transform& backdrop_filter_bounds_transform);
-
- // gl_renderer can bypass TileDrawQuads that fill the RenderPass
- const DrawQuad* CanPassBeDrawnDirectly(
- const AggregatedRenderPass* pass) override;
-
- void DrawRenderPassQuad(const AggregatedRenderPassDrawQuad* quadi,
- const gfx::QuadF* clip_region);
- void DrawRenderPassQuadInternal(DrawRenderPassDrawQuadParams* params);
- void DrawSolidColorQuad(const SolidColorDrawQuad* quad,
- const gfx::QuadF* clip_region);
- void DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
- const gfx::QuadF* clip_region);
- void EnqueueTextureQuad(const TextureDrawQuad* quad,
- const gfx::QuadF* clip_region);
- void FlushTextureQuadCache(BoundGeometry flush_binding);
- void DrawTileQuad(const TileDrawQuad* quad, const gfx::QuadF* clip_region);
- void DrawContentQuad(const ContentDrawQuadBase* quad,
- ResourceId resource_id,
- const gfx::QuadF* clip_region);
- void DrawContentQuadAA(const ContentDrawQuadBase* quad,
- ResourceId resource_id,
- const gfx::Transform& device_transform,
- const gfx::QuadF& aa_quad,
- const gfx::QuadF* clip_region);
- void DrawContentQuadNoAA(const ContentDrawQuadBase* quad,
- ResourceId resource_id,
- const gfx::QuadF* clip_region);
- void DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
- const gfx::QuadF* clip_region);
-
- void SetShaderOpacity(float opacity);
- void SetShaderQuadF(const gfx::QuadF& quad);
- void SetShaderMatrix(const gfx::Transform& transform);
- void SetShaderColor(SkColor color, float opacity);
- void SetShaderRoundedCorner(const gfx::RRectF& rounded_corner_bounds,
- const gfx::Transform& screen_transform);
- void DrawQuadGeometryClippedByQuadF(const gfx::Transform& draw_transform,
- const gfx::RectF& quad_rect,
- const gfx::QuadF& clipping_region_quad,
- const float uv[8]);
- void DrawQuadGeometry(const gfx::Transform& projection_matrix,
- const gfx::Transform& draw_transform,
- const gfx::RectF& quad_rect);
- void DrawQuadGeometryWithAA(const DrawQuad* quad,
- gfx::QuadF* local_quad,
- const gfx::Rect& tile_rect);
-
- const gfx::QuadF& SharedGeometryQuad() const { return shared_geometry_quad_; }
- const StaticGeometryBinding* SharedGeometry() const {
- return shared_geometry_.get();
- }
-
- // If |dst_color_space| is invalid, then no color conversion (apart from YUV
- // to RGB conversion) is performed. This explicit argument is available so
- // that video color conversion can be enabled separately from general color
- // conversion. If |adjust_src_white_level| is true, then the |src_color_space|
- // white levels are adjusted to the display SDR white level so that no white
- // level scaling happens. |src_hdr_metadata|, if available, is the mastering
- // metadata associated to the source quad.
- void SetUseProgram(
- const ProgramKey& program_key,
- const gfx::ColorSpace& src_color_space,
- const gfx::ColorSpace& dst_color_space,
- bool adjust_src_white_level = false,
- absl::optional<gfx::HDRMetadata> src_hdr_metadata = absl::nullopt);
-
- bool MakeContextCurrent();
-
- void InitializeSharedObjects();
- void CleanupSharedObjects();
-
- void ReinitializeGLState();
- void RestoreGLState();
- void RestoreGLStateAfterSkia();
-
- // TODO(weiliangc): Once the overlay processor could schedule overlays, remove
- // these functions.
- // Sends over output surface information as it is a overlay plane. This is
- // used for BufferQueue. For non-BufferQueue cases, this function will do
- // nothing.
- void ScheduleOutputSurfaceAsOverlay();
- // Schedule overlays sends overlay candidate to the GPU.
-#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
- void ScheduleOverlays();
-#elif BUILDFLAG(IS_APPLE)
- void ScheduleCALayers();
-
- // Schedules the |ca_layer_overlay|, which is guaranteed to have a non-null
- // |rpdq| parameter. Returns ownership of a GL texture that contains the
- // output of the CompositorRenderPassDrawQuad.
- std::unique_ptr<OverlayTexture> ScheduleRenderPassDrawQuad(
- const CALayerOverlay* ca_layer_overlay);
-
- // Copies the contents of the render pass draw quad, including filter effects,
- // to a GL texture, returned in |overlay_texture|. The resulting texture may
- // be larger than the CompositorRenderPassDrawQuad's output, in order to reuse
- // existing textures. The new size and position is placed in |new_bounds|.
- void CopyRenderPassDrawQuadToOverlayResource(
- const CALayerOverlay* ca_layer_overlay,
- std::unique_ptr<OverlayTexture>* overlay_texture,
- gfx::RectF* new_bounds);
- std::unique_ptr<OverlayTexture> FindOrCreateOverlayTexture(
- const AggregatedRenderPassId& render_pass_id,
- int width,
- int height,
- const gfx::ColorSpace& color_space);
- void ReduceAvailableOverlayTextures();
-
-#elif BUILDFLAG(IS_WIN)
- void ScheduleDCLayers();
-#endif
-
- // Setup/flush all pending overdraw feedback to framebuffer.
- void SetupOverdrawFeedback();
-
- // Process overdraw feedback from query.
- void ProcessOverdrawFeedback(base::CheckedNumeric<int> surface_area,
- unsigned query);
- bool OverdrawTracingEnabled();
-
- bool CompositeTimeTracingEnabled() override;
- void AddCompositeTimeTraces(base::TimeTicks ready_timestamp) override;
-
- ResourceFormat CurrentRenderPassResourceFormat() const;
-
- bool HasOutputColorMatrix() const;
-
- // Returns true if the given solid color draw quad can be safely drawn using
- // the glClear function call.
- bool CanUseFastSolidColorDraw(const SolidColorDrawQuad* quad) const;
-
- DisplayResourceProviderGL* resource_provider() {
- return static_cast<DisplayResourceProviderGL*>(resource_provider_);
- }
-
- // A map from RenderPass id to the texture used to draw the RenderPass from.
- base::flat_map<AggregatedRenderPassId, ScopedRenderPassTexture>
- render_pass_textures_;
-
- // A map from RenderPass id to backdrop filter cache texture.
- base::flat_map<AggregatedRenderPassId, sk_sp<SkImage>>
- render_pass_backdrop_textures_;
-
- // OverlayTextures that are free to be used in the next frame.
- std::vector<std::unique_ptr<OverlayTexture>> available_overlay_textures_;
- // OverlayTextures that have been set up for use but are waiting for
- // SwapBuffers.
- std::vector<std::unique_ptr<OverlayTexture>> awaiting_swap_overlay_textures_;
- // OverlayTextures that have been swapped for display on the gpu. Each vector
- // represents a single frame, and may be empty if none were used in that
- // frame. Ordered from oldest to most recent frame.
- std::vector<std::vector<std::unique_ptr<OverlayTexture>>>
- displayed_overlay_textures_;
- // OverlayTextures that we have replaced on the gpu but are awaiting
- // confirmation that we can reuse them.
- std::vector<std::unique_ptr<OverlayTexture>>
- awaiting_release_overlay_textures_;
-
- // Resources that have been sent to the GPU process, but not yet swapped.
- OverlayResourceLockList pending_overlay_resources_;
- // Resources that should be shortly swapped by the GPU process.
- base::circular_deque<OverlayResourceLockList> swapping_overlay_resources_;
-
- // Locks for overlays that have release fences and read lock fences.
- base::circular_deque<OverlayResourceLockList>
- read_lock_release_fence_overlay_locks_;
-
- // Resources that the GPU process has finished swapping. The key is the
- // texture id of the resource.
- std::map<unsigned, OverlayResourceLock> swapped_and_acked_overlay_resources_;
-
- // Query object, used to determine the number of sample drawn during a render
- // pass.
- unsigned occlusion_query_ = 0u;
-
- unsigned offscreen_framebuffer_id_ = 0u;
-
- std::unique_ptr<StaticGeometryBinding> shared_geometry_;
- std::unique_ptr<DynamicGeometryBinding> clipped_geometry_;
- gfx::QuadF shared_geometry_quad_;
-
- // This will return nullptr if the requested program has not yet been
- // initialized.
- const Program* GetProgramIfInitialized(const ProgramKey& key) const;
-
- std::unordered_map<ProgramKey, std::unique_ptr<Program>, ProgramKeyHash>
- program_cache_;
-
- const gfx::ColorTransform* GetColorTransform(const gfx::ColorSpace& src,
- const gfx::ColorSpace& dst);
- struct ColorTransformKey {
- gfx::ColorSpace src;
- gfx::ColorSpace dst;
- float sdr_max_luminance_nits = 0.f;
- bool operator==(const ColorTransformKey& other) const;
- bool operator!=(const ColorTransformKey& other) const;
- bool operator<(const ColorTransformKey& other) const;
- };
- std::map<ColorTransformKey, std::unique_ptr<gfx::ColorTransform>>
- color_transform_cache_;
-
- raw_ptr<gpu::gles2::GLES2Interface> gl_;
- raw_ptr<gpu::ContextSupport> context_support_;
- std::unique_ptr<ContextCacheController::ScopedVisibility> context_visibility_;
- std::unique_ptr<ContextCacheController::ScopedBusy> context_busy_;
-
- TextureDeleter texture_deleter_;
- GLRendererCopier copier_;
-
- gfx::Rect swap_buffer_rect_;
- std::vector<gfx::Rect> swap_content_bounds_;
- gfx::Rect scissor_rect_;
- bool is_scissor_enabled_ = false;
- bool stencil_shadow_ = false;
- bool blend_shadow_ = false;
- raw_ptr<const Program> current_program_ = nullptr;
- TexturedQuadDrawCache draw_cache_;
- int highp_threshold_cache_ = 0;
-
- raw_ptr<ScopedRenderPassTexture> current_framebuffer_texture_;
-
- SyncQueryCollection sync_queries_;
- bool use_discard_framebuffer_ = false;
- bool use_sync_query_ = false;
- bool use_blend_equation_advanced_ = false;
- bool use_blend_equation_advanced_coherent_ = false;
- bool use_timer_query_ = false;
- bool use_occlusion_query_ = false;
- bool use_swap_with_bounds_ = false;
- bool use_fast_path_solid_color_quad_ = false;
- bool supports_multi_sampling_ = false;
-
- // If true, tints all the composited content to red.
- bool tint_gl_composited_content_ = true;
-
-#if BUILDFLAG(IS_APPLE)
- // The method FlippedFramebuffer determines whether the framebuffer associated
- // with a DrawingFrame is flipped. It makes the assumption that the
- // DrawingFrame is being used as part of a render pass. If a DrawingFrame is
- // not being used as part of a render pass, setting it here forces
- // FlippedFramebuffer to return |true|.
- bool force_drawing_frame_framebuffer_unflipped_ = false;
-#endif
-
- BoundGeometry bound_geometry_;
-
- unsigned offscreen_stencil_renderbuffer_id_ = 0;
- gfx::Size offscreen_stencil_renderbuffer_size_;
-
- unsigned num_triangles_drawn_ = 0;
- bool prefer_draw_to_copy_ = false;
-
- // A circular queue of to keep track of timer queries and their associated
- // quad type as string.
- base::queue<std::pair<unsigned, std::string>> timer_queries_;
-
- // Keeps track of areas that have been drawn to in the current render pass.
- std::vector<gfx::Rect> drawn_rects_;
-
- // This may be null if the compositor is run on a thread without a
- // MessageLoop.
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner_;
- base::WeakPtrFactory<GLRenderer> weak_ptr_factory_{this};
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_H_
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.cc b/chromium/components/viz/service/display/gl_renderer_copier.cc
deleted file mode 100644
index bbfe5a7515c..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_copier.cc
+++ /dev/null
@@ -1,1298 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/gl_renderer_copier.h"
-
-#include <cstring>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/containers/cxx20_erase.h"
-#include "base/memory/raw_ptr.h"
-#include "base/process/memory.h"
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/common/frame_sinks/copy_output_result.h"
-#include "components/viz/common/frame_sinks/copy_output_util.h"
-#include "components/viz/common/gl_i420_converter.h"
-#include "components/viz/common/gl_nv12_converter.h"
-#include "components/viz/common/gl_scaler.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/service/display/texture_deleter.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/client/shared_image_interface.h"
-#include "gpu/command_buffer/common/mailbox.h"
-#include "gpu/command_buffer/common/shared_image_usage.h"
-#include "gpu/command_buffer/common/sync_token.h"
-#include "third_party/libyuv/include/libyuv/planar_functions.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkColorSpace.h"
-#include "third_party/skia/include/core/SkImageInfo.h"
-#include "ui/gfx/geometry/size.h"
-
-// Syntactic sugar to DCHECK that two sizes are equal.
-#define DCHECK_SIZE_EQ(a, b) \
- DCHECK((a) == (b)) << #a " != " #b ": " << (a).ToString() \
- << " != " << (b).ToString()
-
-namespace viz {
-
-using ResultFormat = CopyOutputRequest::ResultFormat;
-using ResultDestination = CopyOutputRequest::ResultDestination;
-
-namespace {
-
-constexpr int kRGBABytesPerPixel = 4;
-
-// Returns the source property of the |request|, if it is set. Otherwise,
-// returns an empty token. This is needed because CopyOutputRequest will crash
-// if source() is called when !has_source().
-base::UnguessableToken SourceOf(const CopyOutputRequest& request) {
- return request.has_source() ? request.source() : base::UnguessableToken();
-}
-
-// Creates a new texture, binds it to the GL_TEXTURE_2D target, and initializes
-// its default parameters.
-GLuint CreateDefaultTexture2D(gpu::gles2::GLES2Interface* gl) {
- GLuint result = 0;
- gl->GenTextures(1, &result);
- gl->BindTexture(GL_TEXTURE_2D, result);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- return result;
-}
-
-// Creates or re-creates a texture, only if needed, to ensure a texture of the
-// given |required| size is defined. |texture| and |size| are I/O parameters,
-// read to determine what to do and updated if any changes are made.
-void EnsureTextureDefinedWithSize(gpu::gles2::GLES2Interface* gl,
- const gfx::Size& required,
- GLuint* texture,
- gfx::Size* size) {
- if (*texture != 0 && *size == required)
- return;
- if (*texture == 0) {
- *texture = CreateDefaultTexture2D(gl);
- } else {
- gl->BindTexture(GL_TEXTURE_2D, *texture);
- }
- gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, required.width(), required.height(),
- 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
- *size = required;
-}
-
-// Returns parameters for the scaler to scale/transform the image in the source
-// framebuffer to meet the requirements of the |request|.
-GLScaler::Parameters CreateScalerParameters(
- const CopyOutputRequest& request,
- const gfx::ColorSpace& source_color_space,
- const gfx::ColorSpace& output_color_space,
- bool flipped_source) {
- GLScaler::Parameters params;
-
- params.scale_from = request.scale_from();
- params.scale_to = request.scale_to();
- params.source_color_space = source_color_space;
- params.output_color_space = output_color_space;
- // For downscaling, use the GOOD quality setting (appropriate for
- // thumbnailing); and, for upscaling, use the BEST quality.
- const bool is_downscale_in_both_dimensions =
- request.scale_to().x() < request.scale_from().x() &&
- request.scale_to().y() < request.scale_from().y();
- params.quality = is_downscale_in_both_dimensions
- ? GLScaler::Parameters::Quality::GOOD
- : GLScaler::Parameters::Quality::BEST;
- params.is_flipped_source = flipped_source;
-
- return params;
-}
-
-// Returns the specified offset in the form of a pointer for OpenGL's
-// `glReadPixels` call. This is not a valid memory address and the pointer
-// should never be dereferenced.
-uint8_t* GetOffsetPointer(int offset) {
- uint8_t* result = reinterpret_cast<uint8_t*>(0);
- result += offset;
- return result;
-}
-
-} // namespace
-
-GLRendererCopier::GLRendererCopier(ContextProvider* context_provider,
- TextureDeleter* texture_deleter)
- : context_provider_(context_provider), texture_deleter_(texture_deleter) {}
-
-GLRendererCopier::~GLRendererCopier() {
- for (auto& entry : cache_)
- entry.second->Free(context_provider_->ContextGL());
-}
-
-void GLRendererCopier::CopyFromTextureOrFramebuffer(
- std::unique_ptr<CopyOutputRequest> request,
- const copy_output::RenderPassGeometry& geometry,
- GLenum internal_format,
- GLuint framebuffer_texture,
- const gfx::Size& framebuffer_texture_size,
- bool flipped_source,
- const gfx::ColorSpace& framebuffer_color_space) {
- const gfx::Rect& result_rect = geometry.result_selection;
-
- // If we can't convert |color_space| to a SkColorSpace for SkBitmap copy
- // requests (e.g. PIECEWISE_HDR), fallback to a color transform to sRGB
- // before returning the copy result.
- gfx::ColorSpace dest_color_space = framebuffer_color_space;
- if (!framebuffer_color_space.ToSkColorSpace() &&
- request->result_format() == ResultFormat::RGBA &&
- request->result_destination() == ResultDestination::kSystemMemory) {
- dest_color_space = gfx::ColorSpace::CreateSRGB();
- }
- // Fast-Path: If no transformation is necessary and no new textures need to be
- // generated, read-back directly from the currently-bound framebuffer.
- if (request->result_format() == ResultFormat::RGBA &&
- request->result_destination() == ResultDestination::kSystemMemory &&
- framebuffer_color_space == dest_color_space && !request->is_scaled()) {
- StartReadbackFromFramebuffer(std::move(request), geometry.readback_offset,
- flipped_source, false, result_rect,
- dest_color_space);
- return;
- }
-
- gfx::Rect sampling_rect = geometry.sampling_bounds;
-
- const base::UnguessableToken requester = SourceOf(*request);
- std::unique_ptr<ReusableThings> things =
- TakeReusableThingsOrCreate(requester);
-
- // Determine the source texture: This is either the one attached to the
- // framebuffer, or a copy made from the framebuffer. Its format will be the
- // same as |internal_format|.
- //
- // TODO(crbug/767221): All of this (including some texture copies) wouldn't be
- // necessary if we could query whether the currently-bound framebuffer has a
- // texture attached to it, and just source from that texture directly (i.e.,
- // using glGetFramebufferAttachmentParameteriv() and
- // glGetTexLevelParameteriv(GL_TEXTURE_WIDTH/HEIGHT)).
- GLuint source_texture;
- gfx::Size source_texture_size;
- if (framebuffer_texture != 0) {
- source_texture = framebuffer_texture;
- source_texture_size = framebuffer_texture_size;
- } else {
- auto* const gl = context_provider_->ContextGL();
- if (things->fb_copy_texture == 0) {
- things->fb_copy_texture = CreateDefaultTexture2D(gl);
- things->fb_copy_texture_internal_format = static_cast<GLenum>(GL_NONE);
- things->fb_copy_texture_size = gfx::Size();
- } else {
- gl->BindTexture(GL_TEXTURE_2D, things->fb_copy_texture);
- }
- if (things->fb_copy_texture_internal_format == internal_format &&
- things->fb_copy_texture_size == sampling_rect.size()) {
- // Copy the framebuffer pixels without redefining the texture.
- gl->CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, sampling_rect.x(),
- sampling_rect.y(), sampling_rect.width(),
- sampling_rect.height());
- } else {
- // Copy the framebuffer pixels into a newly-defined texture.
- gl->CopyTexImage2D(GL_TEXTURE_2D, 0, internal_format, sampling_rect.x(),
- sampling_rect.y(), sampling_rect.width(),
- sampling_rect.height(), 0);
- things->fb_copy_texture_internal_format = internal_format;
- things->fb_copy_texture_size = sampling_rect.size();
- }
- source_texture = things->fb_copy_texture;
- source_texture_size = sampling_rect.size();
- sampling_rect.set_origin(gfx::Point());
- }
-
- // Revert the Y-flipping of the sampling rect coordinates for GLScaler, which
- // always assumes the source offset is assuming a origin-at-top-left
- // coordinate space.
- if (flipped_source) {
- sampling_rect.set_y(source_texture_size.height() - sampling_rect.bottom());
- }
-
- switch (request->result_format()) {
- case ResultFormat::RGBA:
-
- switch (request->result_destination()) {
- case ResultDestination::kSystemMemory:
- EnsureTextureDefinedWithSize(
- context_provider_->ContextGL(), result_rect.size(),
- &things->result_texture, &things->result_texture_size);
- RenderResultTexture(*request, flipped_source, framebuffer_color_space,
- dest_color_space, source_texture,
- source_texture_size, sampling_rect, result_rect,
- things->result_texture, things.get());
- StartReadbackFromTexture(std::move(request), result_rect,
- dest_color_space, things.get());
- break;
- case ResultDestination::kNativeTextures:
- RenderAndSendTextureResult(std::move(request), flipped_source,
- framebuffer_color_space, dest_color_space,
- source_texture, source_texture_size,
- sampling_rect, result_rect, things.get());
- break;
- }
-
- break;
-
- case ResultFormat::I420_PLANES: {
- // The optimized single-copy path, provided by GLPixelBufferI420Result,
- // requires that the result be accessed via a task in the same task runner
- // sequence as the GLRendererCopier. Since I420_PLANES requests are meant
- // to be VIZ-internal, this is an acceptable limitation to enforce.
- if (!request->SendsResultsInCurrentSequence()) {
- request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
- }
-
- const gfx::Rect aligned_rect = RenderI420Textures(
- *request, flipped_source, framebuffer_color_space, source_texture,
- source_texture_size, sampling_rect, result_rect, things.get());
- StartI420ReadbackFromTextures(std::move(request), aligned_rect,
- result_rect, things.get());
- break;
- }
-
- case ResultFormat::NV12_PLANES: {
- // The optimized single-copy path, provided by GLPixelBufferNV12Result,
- // requires that the result be accessed via a task in the same task runner
- // sequence as the GLRendererCopier. Since NV12_PLANES requests are meant
- // to be VIZ-internal, this is an acceptable limitation to enforce.
- if (!request->SendsResultsInCurrentSequence()) {
- request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
- }
-
- const gfx::Rect aligned_rect = RenderNV12Textures(
- *request, flipped_source, framebuffer_color_space, source_texture,
- source_texture_size, sampling_rect, result_rect, things.get());
- StartNV12ReadbackFromTextures(std::move(request), aligned_rect,
- result_rect, things.get());
-
- break;
- }
- }
-
- StashReusableThingsOrDelete(requester, std::move(things));
-}
-
-void GLRendererCopier::FreeUnusedCachedResources() {
- ++purge_counter_;
-
- // Purge all cache entries that should no longer be kept alive, freeing any
- // resources they held.
- const auto IsTooOld = [this](const decltype(cache_)::value_type& entry) {
- return static_cast<int32_t>(purge_counter_ -
- entry.second->purge_count_at_last_use) >=
- kKeepalivePeriod;
- };
- for (auto& entry : cache_) {
- if (IsTooOld(entry))
- entry.second->Free(context_provider_->ContextGL());
- }
- base::EraseIf(cache_, IsTooOld);
-}
-
-void GLRendererCopier::RenderResultTexture(
- const CopyOutputRequest& request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- const gfx::ColorSpace& dest_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- GLuint result_texture,
- ReusableThings* things) {
- DCHECK_EQ(request.result_format(), ResultFormat::RGBA);
-
- GLScaler::Parameters params = CreateScalerParameters(
- request, source_color_space, dest_color_space, flipped_source);
-
- if (request.result_destination() == ResultDestination::kSystemMemory) {
- // Render the result in top-down row order, and swizzle, within the GPU so
- // these things don't have to be done, less efficiently, on the CPU later.
- params.flip_output = flipped_source;
- params.swizzle[0] =
- ShouldSwapRedAndBlueForBitmapReadback() ? GL_BGRA_EXT : GL_RGBA;
- } else {
- // Texture results are always in bottom-up row order.
- DCHECK_EQ(request.result_destination(), ResultDestination::kNativeTextures);
- params.flip_output = !flipped_source;
- DCHECK_EQ(params.swizzle[0], static_cast<GLenum>(GL_RGBA));
- }
-
- if (!things->scaler)
- things->scaler = std::make_unique<GLScaler>(context_provider_);
- if (!GLScaler::ParametersAreEquivalent(params, things->scaler->params())) {
- const bool is_configured = things->scaler->Configure(params);
- // GLRendererCopier should never use illegal or unsupported options, nor
- // be using GLScaler with an invalid GL context.
- DCHECK(is_configured);
- }
-
- const bool success = things->scaler->Scale(
- source_texture, source_texture_size, sampling_rect.OffsetFromOrigin(),
- result_texture, result_rect);
- DCHECK(success);
-}
-
-gfx::Rect GLRendererCopier::RenderI420Textures(
- const CopyOutputRequest& request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things) {
- DCHECK_EQ(request.result_format(), ResultFormat::I420_PLANES);
-
- auto* const gl = context_provider_->ContextGL();
-
- // Compute required Y/U/V texture sizes and re-define them, if necessary. See
- // class comments for GLI420Converter for an explanation of how planar data is
- // packed into RGBA textures.
- const gfx::Rect aligned_rect = GLI420Converter::ToAlignedRect(result_rect);
- const gfx::Size required_luma_size(aligned_rect.width() / kRGBABytesPerPixel,
- aligned_rect.height());
- const gfx::Size required_chroma_size(required_luma_size.width() / 2,
- required_luma_size.height() / 2);
-
- EnsureTextureDefinedWithSize(gl, required_luma_size, &things->yuv_textures[0],
- &things->texture_sizes[0]);
- EnsureTextureDefinedWithSize(gl, required_chroma_size,
- &things->yuv_textures[1],
- &things->texture_sizes[1]);
- EnsureTextureDefinedWithSize(gl, required_chroma_size,
- &things->yuv_textures[2],
- &things->texture_sizes[2]);
-
- GLI420Converter::Parameters params =
- CreateScalerParameters(request, source_color_space,
- gfx::ColorSpace::CreateREC709(), flipped_source);
- // I420 readback assumes content is in top-down row order. Also, set the
- // output swizzle to match the readback format so that image bitmaps don't
- // have to be byte-order-swizzled on the CPU later.
- params.flip_output = flipped_source;
- params.swizzle[0] = GetOptimalReadbackFormat();
-
- if (!things->i420_converter) {
- things->i420_converter =
- std::make_unique<GLI420Converter>(context_provider_);
- }
- if (!GLI420Converter::ParametersAreEquivalent(
- params, things->i420_converter->params())) {
- const bool is_configured = things->i420_converter->Configure(params);
- // GLRendererCopier should never use illegal or unsupported options, nor
- // be using GLI420Converter with an invalid GL context.
- DCHECK(is_configured);
- }
-
- const bool success = things->i420_converter->Convert(
- source_texture, source_texture_size, sampling_rect.OffsetFromOrigin(),
- aligned_rect, things->yuv_textures.data());
- DCHECK(success);
-
- return aligned_rect;
-}
-
-gfx::Rect GLRendererCopier::RenderNV12Textures(
- const CopyOutputRequest& request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things) {
- DCHECK_EQ(request.result_format(), ResultFormat::NV12_PLANES);
-
- auto* const gl = context_provider_->ContextGL();
-
- // Compute required Y/UV texture sizes and re-define them, if necessary. See
- // class comments for GLNV12Converter for an explanation of how planar data is
- // packed into RGBA textures.
- const gfx::Rect aligned_rect = GLNV12Converter::ToAlignedRect(result_rect);
-
- const gfx::Size required_luma_size(aligned_rect.width() / kRGBABytesPerPixel,
- aligned_rect.height());
- const gfx::Size required_chroma_size(required_luma_size.width(),
- required_luma_size.height() / 2);
-
- EnsureTextureDefinedWithSize(gl, required_luma_size, &things->yuv_textures[0],
- &things->texture_sizes[0]);
-
- EnsureTextureDefinedWithSize(gl, required_chroma_size,
- &things->yuv_textures[1],
- &things->texture_sizes[1]);
-
- GLNV12Converter::Parameters params =
- CreateScalerParameters(request, source_color_space,
- gfx::ColorSpace::CreateREC709(), flipped_source);
-
- // NV12 readback assumes content is in top-down row order. Also, set the
- // output swizzle to match the readback format so that image bitmaps don't
- // have to be byte-order-swizzled on the CPU later.
- params.flip_output = flipped_source;
- params.swizzle[0] = GetOptimalReadbackFormat();
-
- if (!things->nv12_converter) {
- things->nv12_converter =
- std::make_unique<GLNV12Converter>(context_provider_);
- }
- if (!GLNV12Converter::ParametersAreEquivalent(
- params, things->nv12_converter->params())) {
- const bool is_configured = things->nv12_converter->Configure(params);
- // GLRendererCopier should never use illegal or unsupported options, nor
- // be using GLNV12Converter with an invalid GL context.
- DCHECK(is_configured);
- }
-
- const bool success = things->nv12_converter->Convert(
- source_texture, source_texture_size, sampling_rect.OffsetFromOrigin(),
- aligned_rect, things->yuv_textures.data());
- DCHECK(success);
-
- return aligned_rect;
-}
-
-void GLRendererCopier::StartReadbackFromTexture(
- std::unique_ptr<CopyOutputRequest> request,
- const gfx::Rect& result_rect,
- const gfx::ColorSpace& color_space,
- ReusableThings* things) {
- DCHECK_EQ(request->result_format(), ResultFormat::RGBA);
- DCHECK_EQ(request->result_destination(), ResultDestination::kSystemMemory);
-
- auto* const gl = context_provider_->ContextGL();
- if (things->readback_framebuffer == 0) {
- gl->GenFramebuffers(1, &things->readback_framebuffer);
- }
- gl->BindFramebuffer(GL_FRAMEBUFFER, things->readback_framebuffer);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- things->result_texture, 0);
- StartReadbackFromFramebuffer(std::move(request), gfx::Vector2d(), false,
- ShouldSwapRedAndBlueForBitmapReadback(),
- result_rect, color_space);
-}
-
-namespace {
-
-// This is the type of CopyOutputResult we send for RGBA readback. The
-// constructor is called during on GLRendererCopier::FinishReadPixelsWorkflow(),
-// thus it always have access to the GLContext. The ReadRGBAPlane and destructor
-// are called asynchronously, and thus might not have access to the GLContext if
-// it has been destroyed in the meantime. We use the WeakPtr to the
-// GLRendererCopier as an indicator that the GLContext is still alive. If the
-// access to the GLContext is lost, we treat the copy output as failed.
-class GLPixelBufferRGBAResult final : public CopyOutputResult {
- public:
- GLPixelBufferRGBAResult(const gfx::Rect& result_rect,
- const gfx::ColorSpace& color_space,
- base::WeakPtr<GLRendererCopier> copier_weak_ptr,
- ContextProvider* context_provider,
- GLuint transfer_buffer,
- bool is_upside_down,
- bool swap_red_and_blue)
- : CopyOutputResult(CopyOutputResult::Format::RGBA,
- CopyOutputResult::Destination::kSystemMemory,
- result_rect,
- /*needs_lock_for_bitmap=*/false),
- color_space_(color_space),
- copier_weak_ptr_(std::move(copier_weak_ptr)),
- context_provider_(std::move(context_provider)),
- transfer_buffer_(transfer_buffer),
- is_upside_down_(is_upside_down),
- swap_red_and_blue_(swap_red_and_blue) {}
-
- ~GLPixelBufferRGBAResult() final {
- if (transfer_buffer_ && copier_weak_ptr_) {
- context_provider_->ContextGL()->DeleteBuffers(1, &transfer_buffer_);
- }
- }
-
- bool ReadRGBAPlane(uint8_t* dest, int stride) const final {
- // If the GLRendererCopier is gone, this implies the display compositor
- // which contains the GLContext is gone. Regard this copy output readback as
- // failed.
- if (!copier_weak_ptr_)
- return false;
-
- const int src_bytes_per_row = size().width() * kRGBABytesPerPixel;
- DCHECK_GE(stride, src_bytes_per_row);
-
- // No need to read from GPU memory if a cached bitmap already exists.
- if (rect().IsEmpty() || cached_bitmap()->readyToDraw())
- return CopyOutputResult::ReadRGBAPlane(dest, stride);
-
- auto* const gl = context_provider_->ContextGL();
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- const uint8_t* pixels = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
- if (pixels) {
- if (is_upside_down_) {
- dest += (size().height() - 1) * stride;
- stride = -stride;
- }
- const uint8_t* src = pixels;
- if (swap_red_and_blue_) {
- for (int y = 0; y < size().height();
- ++y, src += src_bytes_per_row, dest += stride) {
- for (int x = 0; x < kRGBABytesPerPixel * size().width();
- x += kRGBABytesPerPixel) {
- dest[x + 2] = src[x + 0];
- dest[x + 1] = src[x + 1];
- dest[x + 0] = src[x + 2];
- dest[x + 3] = src[x + 3];
- }
- }
- } else {
- libyuv::CopyPlane(src, src_bytes_per_row, dest, stride,
- src_bytes_per_row, size().height());
- }
- gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
- }
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- return !!pixels;
- }
-
- gfx::ColorSpace GetRGBAColorSpace() const final { return color_space_; }
-
- // This method is always called on the same sequence as the GLRendererCopier.
- // This method will be inside Viz and has access to the WeakPtr of the
- // GLRendererCopier to check whether we still have the access to an alive
- // GLContext.
- const SkBitmap& AsSkBitmap() const final {
- if (rect().IsEmpty())
- return *cached_bitmap(); // Return "null" bitmap for empty result.
-
- if (cached_bitmap()->readyToDraw())
- return *cached_bitmap();
-
- if (!copier_weak_ptr_)
- return *cached_bitmap();
-
- SkBitmap result_bitmap;
- // size() was clamped to render pass or framebuffer size. If we can't
- // allocate it then OOM.
- auto info = SkImageInfo::MakeN32Premul(
- size().width(), size().height(), GetRGBAColorSpace().ToSkColorSpace());
- if (!result_bitmap.tryAllocPixels(info, info.minRowBytes()))
- base::TerminateBecauseOutOfMemory(info.computeMinByteSize());
-
- ReadRGBAPlane(static_cast<uint8_t*>(result_bitmap.getPixels()),
- result_bitmap.rowBytes());
- *cached_bitmap() = result_bitmap;
- // Now that we have a cached bitmap, no need to read from GPU memory
- // anymore.
- context_provider_->ContextGL()->DeleteBuffers(1, &transfer_buffer_);
- transfer_buffer_ = 0;
-
- return *cached_bitmap();
- }
-
- private:
- const gfx::ColorSpace color_space_;
- base::WeakPtr<GLRendererCopier> copier_weak_ptr_;
- raw_ptr<ContextProvider> context_provider_;
- mutable GLuint transfer_buffer_;
- const bool is_upside_down_;
- const bool swap_red_and_blue_;
-};
-} // namespace
-
-GLRendererCopier::ReadPixelsWorkflow::ReadPixelsWorkflow(
- std::unique_ptr<CopyOutputRequest> copy_request,
- const gfx::Vector2d& readback_offset,
- bool flipped_source,
- bool swap_red_and_blue,
- const gfx::Rect& result_rect,
- const gfx::ColorSpace& color_space,
- ContextProvider* context_provider,
- GLenum readback_format)
- : copy_request(std::move(copy_request)),
- flipped_source(flipped_source),
- swap_red_and_blue(swap_red_and_blue),
- result_rect(result_rect),
- color_space(color_space),
- context_provider_(context_provider) {
- DCHECK(readback_format == GL_RGBA || readback_format == GL_BGRA_EXT);
- DCHECK(context_provider_);
- auto* const gl = context_provider_->ContextGL();
-
- // Create a buffer for the pixel transfer.
- gl->GenBuffers(1, &transfer_buffer);
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer);
- gl->BufferData(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- (result_rect.size().GetCheckedArea() * kRGBABytesPerPixel).ValueOrDie(),
- nullptr, GL_STREAM_READ);
-
- // Execute an asynchronous read-pixels operation, with a query that triggers
- // when Finish() should be run.
- gl->GenQueriesEXT(1, &query_);
- gl->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, query_);
- gl->ReadPixels(readback_offset.x(), readback_offset.y(), result_rect.width(),
- result_rect.height(), readback_format, GL_UNSIGNED_BYTE,
- nullptr);
- gl->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
-}
-
-GLRendererCopier::ReadPixelsWorkflow::~ReadPixelsWorkflow() {
- auto* const gl = context_provider_->ContextGL();
- gl->DeleteQueriesEXT(1, &query_);
- if (transfer_buffer)
- gl->DeleteBuffers(1, &transfer_buffer);
-}
-
-// Callback for the asynchronous glReadPixels(). The pixels are read from the
-// transfer buffer, and a CopyOutputResult is sent to the requestor. This would
-// mark this workflow as finished, and the workflow will be cleared later.
-void GLRendererCopier::FinishReadPixelsWorkflow(ReadPixelsWorkflow* workflow) {
- auto result = std::make_unique<GLPixelBufferRGBAResult>(
- workflow->result_rect, workflow->color_space, weak_factory_.GetWeakPtr(),
- context_provider_, workflow->transfer_buffer, workflow->flipped_source,
- workflow->swap_red_and_blue);
- workflow->transfer_buffer = 0; // Ownerhip was transferred to the result.
- if (!workflow->copy_request->SendsResultsInCurrentSequence()) {
- // Force readback into a SkBitmap now, because after PostTask we don't
- // have access to |context_provider_|.
- auto scoped_bitmap = result->ScopedAccessSkBitmap();
- auto bitmap = scoped_bitmap.bitmap();
- }
- workflow->copy_request->SendResult(std::move(result));
- const auto it =
- std::find_if(read_pixels_workflows_.begin(), read_pixels_workflows_.end(),
- [workflow](auto& ptr) { return ptr.get() == workflow; });
- DCHECK(it != read_pixels_workflows_.end());
- read_pixels_workflows_.erase(it);
-}
-
-void GLRendererCopier::StartReadbackFromFramebuffer(
- std::unique_ptr<CopyOutputRequest> request,
- const gfx::Vector2d& readback_offset,
- bool flipped_source,
- bool swapped_red_and_blue,
- const gfx::Rect& result_rect,
- const gfx::ColorSpace& color_space) {
- DCHECK_EQ(request->result_format(), ResultFormat::RGBA);
- DCHECK_EQ(request->result_destination(), ResultDestination::kSystemMemory);
-
- read_pixels_workflows_.emplace_back(std::make_unique<ReadPixelsWorkflow>(
- std::move(request), readback_offset, flipped_source,
- ShouldSwapRedAndBlueForBitmapReadback() != swapped_red_and_blue,
- result_rect, color_space, context_provider_, GetOptimalReadbackFormat()));
- context_provider_->ContextSupport()->SignalQuery(
- read_pixels_workflows_.back()->query(),
- base::BindOnce(&GLRendererCopier::FinishReadPixelsWorkflow,
- weak_factory_.GetWeakPtr(),
- read_pixels_workflows_.back().get()));
-}
-
-void GLRendererCopier::RenderAndSendTextureResult(
- std::unique_ptr<CopyOutputRequest> request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- const gfx::ColorSpace& dest_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things) {
- DCHECK_EQ(request->result_format(), ResultFormat::RGBA);
- DCHECK_EQ(request->result_destination(), ResultDestination::kNativeTextures);
-
- auto* sii = context_provider_->SharedImageInterface();
- gpu::Mailbox mailbox = sii->CreateSharedImage(
- ResourceFormat::RGBA_8888, result_rect.size(), dest_color_space,
- kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
- gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
- auto* gl = context_provider_->ContextGL();
- gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
- GLuint texture = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox.name);
- gl->BeginSharedImageAccessDirectCHROMIUM(
- texture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
- RenderResultTexture(*request, flipped_source, source_color_space,
- dest_color_space, source_texture, source_texture_size,
- sampling_rect, result_rect, texture, things);
- gl->EndSharedImageAccessDirectCHROMIUM(texture);
- gl->DeleteTextures(1, &texture);
- gpu::SyncToken sync_token;
- gl->GenSyncTokenCHROMIUM(sync_token.GetData());
-
- // Create a callback that deletes what was created in this GL context.
- // Note: There's no need to try to pool/re-use the result texture from here,
- // since only clients that are trying to re-invent video capture would see any
- // significant performance benefit. Instead, such clients should use the video
- // capture services provided by VIZ.
- CopyOutputResult::ReleaseCallbacks release_callbacks;
- release_callbacks.push_back(
- texture_deleter_->GetReleaseCallback(context_provider_.get(), mailbox));
-
- request->SendResult(std::make_unique<CopyOutputTextureResult>(
- CopyOutputResult::Format::RGBA, result_rect,
- CopyOutputResult::TextureResult(mailbox, sync_token, dest_color_space),
- std::move(release_callbacks)));
-}
-
-namespace {
-
-// Specialization of CopyOutputResult which reads I420 plane data from a GL
-// pixel buffer object, and automatically deletes the pixel buffer object at
-// destruction time. This provides an optimal one-copy data flow, from the pixel
-// buffer into client-provided memory.
-class GLPixelBufferI420Result final : public CopyOutputResult {
- public:
- // |aligned_rect| identifies the region of result pixels in the pixel buffer,
- // while the |result_rect| is the subregion that is exposed to the client.
- GLPixelBufferI420Result(const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- base::WeakPtr<GLRendererCopier> copier_weak_ptr,
- ContextProvider* context_provider,
- GLuint transfer_buffer)
- : CopyOutputResult(CopyOutputResult::Format::I420_PLANES,
- CopyOutputResult::Destination::kSystemMemory,
- result_rect,
- /*needs_lock_for_bitmap=*/false),
- aligned_rect_(aligned_rect),
- copier_weak_ptr_(copier_weak_ptr),
- context_provider_(context_provider),
- transfer_buffer_(transfer_buffer) {
- auto* const gl = context_provider_->ContextGL();
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- pixels_ = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- }
-
- ~GLPixelBufferI420Result() final {
- if (copier_weak_ptr_) {
- auto* const gl = context_provider_->ContextGL();
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- gl->DeleteBuffers(1, &transfer_buffer_);
- }
- }
-
- bool ReadI420Planes(uint8_t* y_out,
- int y_out_stride,
- uint8_t* u_out,
- int u_out_stride,
- uint8_t* v_out,
- int v_out_stride) const final {
- DCHECK_GE(y_out_stride, size().width());
- const int chroma_row_bytes = (size().width() + 1) / 2;
-
- DCHECK_GE(u_out_stride, chroma_row_bytes);
- DCHECK_GE(v_out_stride, chroma_row_bytes);
- if (!copier_weak_ptr_)
- return false;
-
- uint8_t* pixels = pixels_;
- if (pixels) {
- const int y_stride = aligned_rect_.width();
- const gfx::Vector2d result_offset =
- rect().OffsetFromOrigin() - aligned_rect_.OffsetFromOrigin();
- const int y_start_offset =
- result_offset.y() * y_stride + result_offset.x();
- libyuv::CopyPlane(pixels + y_start_offset, y_stride, y_out, y_out_stride,
- size().width(), size().height());
- pixels += y_stride * aligned_rect_.height();
- const int chroma_stride = aligned_rect_.width() / 2;
- const int chroma_start_offset =
- ((result_offset.y() / 2) * chroma_stride) + (result_offset.x() / 2);
- const int chroma_height = (size().height() + 1) / 2;
- libyuv::CopyPlane(pixels + chroma_start_offset, chroma_stride, u_out,
- u_out_stride, chroma_row_bytes, chroma_height);
- pixels += chroma_stride * (aligned_rect_.height() / 2);
- libyuv::CopyPlane(pixels + chroma_start_offset, chroma_stride, v_out,
- v_out_stride, chroma_row_bytes, chroma_height);
- }
- return !!pixels;
- }
-
- private:
- const gfx::Rect aligned_rect_;
- base::WeakPtr<GLRendererCopier> copier_weak_ptr_;
- const raw_ptr<ContextProvider> context_provider_;
- const GLuint transfer_buffer_;
- raw_ptr<uint8_t> pixels_;
-};
-
-// Specialization of CopyOutputResult which reads NV12 plane data from a GL
-// pixel buffer object, and automatically deletes the pixel buffer object at
-// destruction time. This provides an optimal one-copy data flow, from the pixel
-// buffer into client-provided memory.
-class GLPixelBufferNV12Result final : public CopyOutputResult {
- public:
- // |aligned_rect| identifies the region of result pixels in the pixel buffer,
- // while the |result_rect| is the subregion that is exposed to the client.
- GLPixelBufferNV12Result(const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- base::WeakPtr<GLRendererCopier> copier_weak_ptr,
- ContextProvider* context_provider,
- GLuint transfer_buffer)
- : CopyOutputResult(CopyOutputResult::Format::NV12_PLANES,
- CopyOutputResult::Destination::kSystemMemory,
- result_rect,
- /*needs_lock_for_bitmap=*/false),
- aligned_rect_(aligned_rect),
- copier_weak_ptr_(copier_weak_ptr),
- context_provider_(context_provider),
- transfer_buffer_(transfer_buffer) {
- auto* const gl = context_provider_->ContextGL();
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- pixels_ = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- }
-
- ~GLPixelBufferNV12Result() final {
- if (copier_weak_ptr_) {
- auto* const gl = context_provider_->ContextGL();
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
- gl->DeleteBuffers(1, &transfer_buffer_);
- }
- }
-
- bool ReadNV12Planes(uint8_t* y_out,
- int y_out_stride,
- uint8_t* uv_out,
- int uv_out_stride) const final {
- DCHECK_GE(y_out_stride, size().width());
- const int chroma_row_bytes = 2 * ((size().width() + 1) / 2);
- DCHECK_GE(uv_out_stride, chroma_row_bytes);
- if (!copier_weak_ptr_)
- return false;
-
- uint8_t* pixels = pixels_;
-
- if (pixels) {
- const int y_stride = aligned_rect_.width();
- const gfx::Vector2d result_offset =
- rect().OffsetFromOrigin() - aligned_rect_.OffsetFromOrigin();
- const int y_start_offset =
- result_offset.y() * y_stride + result_offset.x();
- libyuv::CopyPlane(pixels + y_start_offset, y_stride, y_out, y_out_stride,
- size().width(), size().height());
- pixels += y_stride * aligned_rect_.height();
- const int chroma_stride = aligned_rect_.width();
- const int chroma_start_offset =
- ((result_offset.y() / 2) * chroma_stride) +
- 2 * (result_offset.x() / 2);
- const int chroma_height = (size().height() + 1) / 2;
- libyuv::CopyPlane(pixels + chroma_start_offset, chroma_stride, uv_out,
- uv_out_stride, chroma_row_bytes, chroma_height);
- }
- return !!pixels;
- }
-
- private:
- const gfx::Rect aligned_rect_;
- base::WeakPtr<GLRendererCopier> copier_weak_ptr_;
- const raw_ptr<ContextProvider> context_provider_;
- const GLuint transfer_buffer_;
- raw_ptr<uint8_t> pixels_ = nullptr;
-};
-
-} // namespace
-
-GLRendererCopier::ReadI420PlanesWorkflow::ReadI420PlanesWorkflow(
- std::unique_ptr<CopyOutputRequest> copy_request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- base::WeakPtr<GLRendererCopier> copier_weak_ptr,
- ContextProvider* context_provider)
- : copy_request(std::move(copy_request)),
- aligned_rect(aligned_rect),
- result_rect(result_rect),
- copier_weak_ptr_(copier_weak_ptr),
- context_provider_(context_provider) {
- // Create a buffer for the pixel transfer: A single buffer is used and will
- // contain the Y plane, then the U plane, then the V plane.
- auto* const gl = context_provider_->ContextGL();
- gl->GenBuffers(1, &transfer_buffer);
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer);
- base::CheckedNumeric<int> y_plane_bytes =
- y_texture_size().GetCheckedArea() * kRGBABytesPerPixel;
- base::CheckedNumeric<int> chroma_plane_bytes =
- chroma_texture_size().GetCheckedArea() * kRGBABytesPerPixel;
- gl->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- (y_plane_bytes + chroma_plane_bytes * 2).ValueOrDie(), nullptr,
- GL_STREAM_READ);
- data_offsets_ = {0, y_plane_bytes.ValueOrDie(),
- (y_plane_bytes + chroma_plane_bytes).ValueOrDie()};
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
-
- // Generate the three queries used for determining when each of the plane
- // readbacks has completed.
- gl->GenQueriesEXT(3, queries.data());
-}
-
-void GLRendererCopier::ReadI420PlanesWorkflow::BindTransferBuffer() {
- DCHECK_NE(transfer_buffer, 0u);
- context_provider_->ContextGL()->BindBuffer(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer);
-}
-
-void GLRendererCopier::ReadI420PlanesWorkflow::StartPlaneReadback(
- int plane,
- GLenum readback_format) {
- DCHECK_NE(queries[plane], 0u);
- auto* const gl = context_provider_->ContextGL();
- gl->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, queries[plane]);
- const gfx::Size& size = plane == 0 ? y_texture_size() : chroma_texture_size();
- // Note: While a PIXEL_PACK_BUFFER is bound, OpenGL interprets the last
- // argument to ReadPixels() as a byte offset within the buffer instead of
- // an actual pointer in system memory.
- uint8_t* offset_in_buffer = GetOffsetPointer(data_offsets_[plane]);
- gl->ReadPixels(0, 0, size.width(), size.height(), readback_format,
- GL_UNSIGNED_BYTE, offset_in_buffer);
- gl->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
- context_provider_->ContextSupport()->SignalQuery(
- queries[plane],
- base::BindOnce(&GLRendererCopier::FinishReadI420PlanesWorkflow,
- copier_weak_ptr_, this, plane));
-}
-
-void GLRendererCopier::ReadI420PlanesWorkflow::UnbindTransferBuffer() {
- context_provider_->ContextGL()->BindBuffer(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
-}
-
-GLRendererCopier::ReadI420PlanesWorkflow::~ReadI420PlanesWorkflow() {
- auto* const gl = context_provider_->ContextGL();
- if (transfer_buffer != 0)
- gl->DeleteBuffers(1, &transfer_buffer);
- for (GLuint& query : queries) {
- if (query != 0)
- gl->DeleteQueriesEXT(1, &query);
- }
-}
-
-gfx::Size GLRendererCopier::ReadI420PlanesWorkflow::y_texture_size() const {
- return gfx::Size(aligned_rect.width() / kRGBABytesPerPixel,
- aligned_rect.height());
-}
-
-gfx::Size GLRendererCopier::ReadI420PlanesWorkflow::chroma_texture_size()
- const {
- return gfx::Size(aligned_rect.width() / kRGBABytesPerPixel / 2,
- aligned_rect.height() / 2);
-}
-
-GLRendererCopier::ReadNV12PlanesWorkflow::ReadNV12PlanesWorkflow(
- std::unique_ptr<CopyOutputRequest> copy_request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- base::WeakPtr<GLRendererCopier> copier_weak_ptr,
- ContextProvider* context_provider)
- : copy_request_(std::move(copy_request)),
- aligned_rect_(aligned_rect),
- result_rect_(result_rect),
- copier_weak_ptr_(copier_weak_ptr),
- context_provider_(context_provider) {
- // Create a buffer for the pixel transfer: A single buffer is used and will
- // contain the Y plane, then the UV plane.
- auto* const gl = context_provider_->ContextGL();
- gl->GenBuffers(1, &transfer_buffer_);
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- base::CheckedNumeric<int> y_plane_bytes =
- y_texture_size().GetCheckedArea() * kRGBABytesPerPixel;
- base::CheckedNumeric<int> chroma_plane_bytes =
- chroma_texture_size().GetCheckedArea() * kRGBABytesPerPixel;
- gl->BufferData(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM,
- (y_plane_bytes + chroma_plane_bytes).ValueOrDie(), nullptr,
- GL_STREAM_READ);
- data_offsets_ = {0, y_plane_bytes.ValueOrDie()};
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
-
- // Generate the two queries used for determining when each of the plane
- // readbacks has completed.
- gl->GenQueriesEXT(2, queries_.data());
-}
-
-void GLRendererCopier::ReadNV12PlanesWorkflow::BindTransferBuffer() {
- DCHECK_NE(transfer_buffer_, 0u);
- context_provider_->ContextGL()->BindBuffer(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
-}
-
-void GLRendererCopier::ReadNV12PlanesWorkflow::StartPlaneReadback(
- int plane,
- GLenum readback_format) {
- DCHECK_NE(queries_[plane], 0u);
- auto* const gl = context_provider_->ContextGL();
- gl->BeginQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, queries_[plane]);
- const gfx::Size& size = plane == 0 ? y_texture_size() : chroma_texture_size();
- // Note: While a PIXEL_PACK_BUFFER is bound, OpenGL interprets the last
- // argument to ReadPixels() as a byte offset within the buffer instead of
- // an actual pointer in system memory.
- uint8_t* offset_in_buffer = GetOffsetPointer(data_offsets_[plane]);
- gl->ReadPixels(0, 0, size.width(), size.height(), readback_format,
- GL_UNSIGNED_BYTE, offset_in_buffer);
- gl->EndQueryEXT(GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM);
- context_provider_->ContextSupport()->SignalQuery(
- queries_[plane],
- base::BindOnce(&GLRendererCopier::FinishReadNV12PlanesWorkflow,
- copier_weak_ptr_, this, plane));
-}
-
-void GLRendererCopier::ReadNV12PlanesWorkflow::UnbindTransferBuffer() {
- context_provider_->ContextGL()->BindBuffer(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
-}
-
-GLRendererCopier::ReadNV12PlanesWorkflow::~ReadNV12PlanesWorkflow() {
- auto* const gl = context_provider_->ContextGL();
- if (transfer_buffer_ != 0)
- gl->DeleteBuffers(1, &transfer_buffer_);
- for (GLuint& query : queries_) {
- if (query != 0)
- gl->DeleteQueriesEXT(1, &query);
- }
-}
-
-gfx::Size GLRendererCopier::ReadNV12PlanesWorkflow::y_texture_size() const {
- return gfx::Size(aligned_rect_.width() / kRGBABytesPerPixel,
- aligned_rect_.height());
-}
-
-gfx::Size GLRendererCopier::ReadNV12PlanesWorkflow::chroma_texture_size()
- const {
- return gfx::Size(aligned_rect_.width() / kRGBABytesPerPixel,
- aligned_rect_.height() / 2);
-}
-
-void GLRendererCopier::StartI420ReadbackFromTextures(
- std::unique_ptr<CopyOutputRequest> request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things) {
- DCHECK_EQ(request->result_format(), ResultFormat::I420_PLANES);
-
- auto* const gl = context_provider_->ContextGL();
- if (things->yuv_readback_framebuffers[0] == 0) {
- gl->GenFramebuffers(3, things->yuv_readback_framebuffers.data());
- } else if (things->yuv_readback_framebuffers[2] == 0) {
- gl->GenFramebuffers(1, &things->yuv_readback_framebuffers[2]);
- }
-
- // Execute three asynchronous read-pixels operations, one for each plane. The
- // CopyOutputRequest is passed to the ReadI420PlanesWorkflow, which will send
- // the CopyOutputResult once all readback operations are complete.
- read_i420_workflows_.emplace_back(std::make_unique<ReadI420PlanesWorkflow>(
- std::move(request), aligned_rect, result_rect, weak_factory_.GetWeakPtr(),
- context_provider_));
- ReadI420PlanesWorkflow* workflow = read_i420_workflows_.back().get();
- workflow->BindTransferBuffer();
- for (int plane = 0; plane < 3; ++plane) {
- gl->BindFramebuffer(GL_FRAMEBUFFER,
- things->yuv_readback_framebuffers[plane]);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, things->yuv_textures[plane], 0);
- workflow->StartPlaneReadback(plane, GetOptimalReadbackFormat());
- }
- workflow->UnbindTransferBuffer();
-}
-
-void GLRendererCopier::FinishReadI420PlanesWorkflow(
- ReadI420PlanesWorkflow* workflow,
- int plane) {
- context_provider_->ContextGL()->DeleteQueriesEXT(1,
- &workflow->queries[plane]);
- workflow->queries[plane] = 0;
-
- // If all three readbacks have completed, send the result.
- if (workflow->queries == std::array<GLuint, 3>{{0, 0, 0}}) {
- workflow->copy_request->SendResult(
- std::make_unique<GLPixelBufferI420Result>(
- workflow->aligned_rect, workflow->result_rect,
- weak_factory_.GetWeakPtr(), context_provider_,
- workflow->transfer_buffer));
- workflow->transfer_buffer = 0; // Ownership was transferred to the result.
- const auto it =
- std::find_if(read_i420_workflows_.begin(), read_i420_workflows_.end(),
- [workflow](auto& ptr) { return ptr.get() == workflow; });
- DCHECK(it != read_i420_workflows_.end());
- read_i420_workflows_.erase(it);
- }
-}
-
-void GLRendererCopier::StartNV12ReadbackFromTextures(
- std::unique_ptr<CopyOutputRequest> request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things) {
- DCHECK_EQ(request->result_format(), ResultFormat::NV12_PLANES);
-
- auto* const gl = context_provider_->ContextGL();
- if (things->yuv_readback_framebuffers[0] == 0)
- gl->GenFramebuffers(2, things->yuv_readback_framebuffers.data());
-
- // Execute two asynchronous read-pixels operations, one for each plane. The
- // CopyOutputRequest is passed to the ReadNV12PlanesWorkflow, which will send
- // the CopyOutputResult once all readback operations are complete.
- read_nv12_workflows_.push_back(std::make_unique<ReadNV12PlanesWorkflow>(
- std::move(request), aligned_rect, result_rect, weak_factory_.GetWeakPtr(),
- context_provider_));
- ReadNV12PlanesWorkflow* workflow = read_nv12_workflows_.back().get();
- workflow->BindTransferBuffer();
- for (int plane = 0; plane < 2; ++plane) {
- gl->BindFramebuffer(GL_FRAMEBUFFER,
- things->yuv_readback_framebuffers[plane]);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, things->yuv_textures[plane], 0);
- workflow->StartPlaneReadback(plane, GetOptimalReadbackFormat());
- }
- workflow->UnbindTransferBuffer();
-}
-
-void GLRendererCopier::FinishReadNV12PlanesWorkflow(
- ReadNV12PlanesWorkflow* workflow,
- int plane) {
- GLuint query = workflow->query(plane);
- context_provider_->ContextGL()->DeleteQueriesEXT(1, &query);
- workflow->MarkQueryCompleted(plane);
-
- // If both readbacks have completed, send the result.
- if (workflow->IsCompleted()) {
- workflow->TakeRequest()->SendResult(
- std::make_unique<GLPixelBufferNV12Result>(
- workflow->aligned_rect(), workflow->result_rect(),
- weak_factory_.GetWeakPtr(), context_provider_,
- workflow->TakeTransferBuffer()));
- const auto it =
- std::find_if(read_nv12_workflows_.begin(), read_nv12_workflows_.end(),
- [workflow](auto& ptr) { return ptr.get() == workflow; });
- DCHECK(it != read_nv12_workflows_.end());
- read_nv12_workflows_.erase(it);
- }
-}
-
-std::unique_ptr<GLRendererCopier::ReusableThings>
-GLRendererCopier::TakeReusableThingsOrCreate(
- const base::UnguessableToken& requester) {
- if (!requester.is_empty()) {
- const auto it = cache_.find(requester);
- if (it != cache_.end()) {
- auto things = std::move(it->second);
- cache_.erase(it);
- return things;
- }
- }
-
- return std::make_unique<ReusableThings>();
-}
-
-void GLRendererCopier::StashReusableThingsOrDelete(
- const base::UnguessableToken& requester,
- std::unique_ptr<ReusableThings> things) {
- if (requester.is_empty()) {
- things->Free(context_provider_->ContextGL());
- } else {
- things->purge_count_at_last_use = purge_counter_;
- cache_[requester] = std::move(things);
- }
-}
-
-GLenum GLRendererCopier::GetOptimalReadbackFormat() {
- if (optimal_readback_format_ != GL_NONE)
- return optimal_readback_format_;
-
- // Preconditions: GetOptimalReadbackFormat() requires a valid context and a
- // complete framebuffer set up. The latter must be guaranteed by all possible
- // callers of this method.
- auto* const gl = context_provider_->ContextGL();
- if (gl->GetGraphicsResetStatusKHR() != GL_NO_ERROR)
- return GL_RGBA; // No context: Just return a sane default.
- DCHECK(gl->CheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
-
- // If the GL implementation internally uses the GL_BGRA_EXT+GL_UNSIGNED_BYTE
- // format+type combination, then consider that the optimal readback
- // format+type. Otherwise, use GL_RGBA+GL_UNSIGNED_BYTE, which all platforms
- // must support, per the GLES 2.0 spec.
- GLint type = 0;
- GLint readback_format = 0;
- gl->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &type);
- if (type == GL_UNSIGNED_BYTE)
- gl->GetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readback_format);
- if (readback_format != GL_BGRA_EXT)
- readback_format = GL_RGBA;
-
- optimal_readback_format_ = static_cast<GLenum>(readback_format);
- return optimal_readback_format_;
-}
-
-bool GLRendererCopier::ShouldSwapRedAndBlueForBitmapReadback() {
- const bool skbitmap_is_bgra = (kN32_SkColorType == kBGRA_8888_SkColorType);
- const bool readback_will_be_bgra =
- (GetOptimalReadbackFormat() == GL_BGRA_EXT);
- return skbitmap_is_bgra != readback_will_be_bgra;
-}
-
-GLRendererCopier::ReusableThings::ReusableThings() = default;
-
-GLRendererCopier::ReusableThings::~ReusableThings() {
- // Ensure all resources were freed by this point. Resources aren't explicity
- // freed here, in the destructor, because some require access to the GL
- // context. See Free().
- DCHECK_EQ(fb_copy_texture, 0u);
- DCHECK(!scaler);
- DCHECK_EQ(result_texture, 0u);
- DCHECK_EQ(readback_framebuffer, 0u);
- DCHECK(!i420_converter);
- constexpr std::array<GLuint, 3> kAllZeros = {0, 0, 0};
- DCHECK(yuv_textures == kAllZeros);
- DCHECK(yuv_readback_framebuffers == kAllZeros);
-}
-
-void GLRendererCopier::ReusableThings::Free(gpu::gles2::GLES2Interface* gl) {
- if (fb_copy_texture != 0) {
- gl->DeleteTextures(1, &fb_copy_texture);
- fb_copy_texture = 0;
- fb_copy_texture_internal_format = static_cast<GLenum>(GL_NONE);
- fb_copy_texture_size = gfx::Size();
- }
- scaler.reset();
- if (result_texture != 0) {
- gl->DeleteTextures(1, &result_texture);
- result_texture = 0;
- result_texture_size = gfx::Size();
- }
- if (readback_framebuffer != 0) {
- gl->DeleteFramebuffers(1, &readback_framebuffer);
- readback_framebuffer = 0;
- }
-
- i420_converter.reset();
- nv12_converter.reset();
-
- if (yuv_textures[0] != 0) {
- // We have some cached textures, check if there's 2 or 3 & delete them:
- int num_textures = yuv_textures[2] != 0 ? 3 : 2;
- gl->DeleteTextures(num_textures, yuv_textures.data());
- yuv_textures = {0, 0, 0};
- texture_sizes = {};
- }
- if (yuv_readback_framebuffers[0] != 0) {
- // We have some cached readback buffers, check if there's 2 or 3 & delete
- // them:
- int num_readback_buffers = yuv_readback_framebuffers[2] != 0 ? 3 : 2;
- gl->DeleteFramebuffers(num_readback_buffers,
- yuv_readback_framebuffers.data());
- yuv_readback_framebuffers = {0, 0, 0};
- }
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.h b/chromium/components/viz/service/display/gl_renderer_copier.h
deleted file mode 100644
index e0952de31f3..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_copier.h
+++ /dev/null
@@ -1,485 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_COPIER_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_COPIER_H_
-
-#include <stdint.h>
-
-#include <array>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/flat_map.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/task/task_runner.h"
-#include "base/unguessable_token.h"
-#include "components/viz/service/viz_service_export.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace gfx {
-class ColorSpace;
-class Rect;
-class Vector2d;
-} // namespace gfx
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-} // namespace gpu
-
-namespace viz {
-
-class ContextProvider;
-class CopyOutputRequest;
-class GLI420Converter;
-class GLNV12Converter;
-class GLScaler;
-class TextureDeleter;
-
-namespace copy_output {
-struct RenderPassGeometry;
-} // namespace copy_output
-
-// Helper class for GLRenderer that executes CopyOutputRequests using GL, to
-// perform texture copies/transformations and read back bitmaps. Also manages
-// the caching of resources needed to ensure efficient video performance.
-//
-// GLRenderer calls CopyFromTextureOrFramebuffer() to execute a
-// CopyOutputRequest. GLRendererCopier will examine the request and determine
-// the minimal amount of work needed to satisfy all the requirements of the
-// request.
-//
-// In many cases, interim GL objects (textures, framebuffers, etc.) must be
-// created as part of a multi-step process. When considering video performance
-// (i.e., a series of CopyOutputRequests from the same "source"), these interim
-// objects must be cached to prevent a significant performance penalty on some
-// GPU/drivers. GLRendererCopier manages such a cache and automatically frees
-// the objects when it detects that a stream of CopyOutputRequests from a given
-// "source" has ended.
-class VIZ_SERVICE_EXPORT GLRendererCopier {
- public:
- // Define types to avoid pulling in command buffer GL headers, which conflict
- // the ui/gl/gl_bindings.h
- using GLuint = unsigned int;
- using GLenum = unsigned int;
-
- // |context_provider| and |texture_deleter| must outlive this instance.
- GLRendererCopier(ContextProvider* context_provider,
- TextureDeleter* texture_deleter);
-
- GLRendererCopier(const GLRendererCopier&) = delete;
- GLRendererCopier& operator=(const GLRendererCopier&) = delete;
-
- ~GLRendererCopier();
-
- // Executes the |request|, copying from the currently-bound framebuffer of the
- // given |internal_format|. |output_rect| is the RenderPass's output Rect in
- // draw space, and is used to translate and clip the result selection Rect in
- // the request. |framebuffer_texture| and |framebuffer_texture_size| are
- // optional, but desired for performance: If provided, the texture might be
- // used as the source, to avoid having to make a copy of the framebuffer.
- // |flipped_source| is true (common case) if the framebuffer content is
- // vertically flipped (bottom-up row order). |framebuffer_color_space|
- // specifies the color space of the pixels in the framebuffer.
- //
- // This implementation may change a wide variety of GL state, such as texture
- // and framebuffer bindings, shader programs, and related attributes; and so
- // the caller must not make any assumptions about the state of the GL context
- // after this call.
- void CopyFromTextureOrFramebuffer(
- std::unique_ptr<CopyOutputRequest> request,
- const copy_output::RenderPassGeometry& geometry,
- GLenum internal_format,
- GLuint framebuffer_texture,
- const gfx::Size& framebuffer_texture_size,
- bool flipped_source,
- const gfx::ColorSpace& framebuffer_color_space);
-
- // Checks whether cached resources should be freed because recent copy
- // activity is no longer using them. This should be called after a frame has
- // finished drawing (after all copy requests have been executed).
- void FreeUnusedCachedResources();
-
- private:
- friend class GLRendererCopierTest;
-
- // The collection of resources that might be cached over multiple copy
- // requests from the same source. While executing a CopyOutputRequest, this
- // struct is also used to pass around intermediate objects between operations.
- struct VIZ_SERVICE_EXPORT ReusableThings {
- // This is used to determine whether these things aren't being used anymore.
- uint32_t purge_count_at_last_use = 0;
-
- // Texture containing a copy of the source framebuffer, if the source
- // framebuffer cannot be used directly.
- GLuint fb_copy_texture = 0;
- GLenum fb_copy_texture_internal_format = static_cast<GLenum>(0 /*GL_NONE*/);
- gfx::Size fb_copy_texture_size;
-
- // RGBA requests: Scaling, and texture/framebuffer for readback.
- std::unique_ptr<GLScaler> scaler;
- GLuint result_texture = 0;
- gfx::Size result_texture_size;
- GLuint readback_framebuffer = 0;
-
- // I420_PLANES & NV12_PLANES requests: I420, NV12 scaling and format
- // conversion, and textures+framebuffers for readback.
- std::unique_ptr<GLI420Converter> i420_converter;
- std::unique_ptr<GLNV12Converter> nv12_converter;
- std::array<GLuint, 3> yuv_textures = {0, 0, 0};
- std::array<gfx::Size, 3> texture_sizes;
- std::array<GLuint, 3> yuv_readback_framebuffers = {0, 0, 0};
-
- ReusableThings();
-
- ReusableThings(const ReusableThings&) = delete;
- ReusableThings& operator=(const ReusableThings&) = delete;
-
- ~ReusableThings();
-
- // Frees all the GL objects and scalers. This is in-lieu of a ReusableThings
- // destructor because a valid GL context is required to free some of the
- // objects.
- void Free(gpu::gles2::GLES2Interface* gl);
- };
-
- // Manages the execution of one asynchronous framebuffer readback and contains
- // all the relevant state needed to complete a copy request. The constructor
- // initiates the operation, and the destructor cleans up all the GL objects
- // created for this workflow. This class is owned by the GLRendererCopier, and
- // GLRendererCopier is responsible for deleting this either after the workflow
- // is finished, or when the GLRendererCopier is being destroyed.
- struct ReadPixelsWorkflow {
- public:
- // Saves all revelant state and initiates the GL asynchronous read-pixels
- // workflow.
- ReadPixelsWorkflow(std::unique_ptr<CopyOutputRequest> copy_request,
- const gfx::Vector2d& readback_offset,
- bool flipped_source,
- bool swap_red_and_blue,
- const gfx::Rect& result_rect,
- const gfx::ColorSpace& color_space,
- ContextProvider* context_provider,
- GLenum readback_format);
- ReadPixelsWorkflow(const ReadPixelsWorkflow&) = delete;
-
- // The destructor is by the GLRendererCopier, either called after the
- // workflow is finished or when GLRendererCopier is being destoryed.
- ~ReadPixelsWorkflow();
-
- GLuint query() const { return query_; }
-
- const std::unique_ptr<CopyOutputRequest> copy_request;
- const bool flipped_source;
- const bool swap_red_and_blue;
- const gfx::Rect result_rect;
- const gfx::ColorSpace color_space;
- GLuint transfer_buffer = 0;
-
- private:
- const raw_ptr<ContextProvider> context_provider_;
- GLuint query_ = 0;
- };
-
- // Renders a scaled/transformed copy of a source texture according to the
- // |request| parameters and other source characteristics. |result_texture|
- // must be allocated/sized by the caller. For RGBA requests with destination
- // set to system memory, the image content will be rendered in top-down row
- // order and maybe red-blue swapped, to support efficient readback later on.
- // For RGBA requests with ResultDestination::kNativeTextures set, the image
- // content is always rendered Y-flipped (bottom-up row order).
- void RenderResultTexture(const CopyOutputRequest& request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- const gfx::ColorSpace& dest_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- GLuint result_texture,
- ReusableThings* things);
-
- // Like the ReadPixelsWorkflow, except for I420 planes readback. Because there
- // are three separate glReadPixels operations that may complete in any order,
- // a ReadI420PlanesWorkflow will receive notifications from three separate "GL
- // query" callbacks. It is only after all three operations have completed that
- // a fully-assembled CopyOutputResult can be sent.
- //
- // See class comments for GLI420Converter for an explanation of how
- // planar data is packed into RGBA textures.
- struct ReadI420PlanesWorkflow {
- public:
- ReadI420PlanesWorkflow(std::unique_ptr<CopyOutputRequest> copy_request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- base::WeakPtr<GLRendererCopier> copier_weak_ptr,
- ContextProvider* context_provider);
-
- void BindTransferBuffer();
- void StartPlaneReadback(int plane, GLenum readback_format);
- void UnbindTransferBuffer();
-
- ~ReadI420PlanesWorkflow();
-
- const std::unique_ptr<CopyOutputRequest> copy_request;
- const gfx::Rect aligned_rect;
- const gfx::Rect result_rect;
- GLuint transfer_buffer;
- std::array<GLuint, 3> queries;
-
- private:
- gfx::Size y_texture_size() const;
- gfx::Size chroma_texture_size() const;
-
- base::WeakPtr<GLRendererCopier> copier_weak_ptr_;
- const raw_ptr<ContextProvider> context_provider_;
- std::array<int, 3> data_offsets_;
- };
-
- // Like the ReadPixelsWorkflow, except for NV12 planes readback. Because there
- // are two separate glReadPixels operations that may complete in any order,
- // a ReadNV12PlanesWorkflow will receive notifications from two separate "GL
- // query" callbacks. It is only after all two operations have completed that
- // a fully-assembled CopyOutputResult can be sent.
- //
- // See class comments for GLNV12Converter for an explanation of how planar
- // data is packed into RGBA textures.
- class ReadNV12PlanesWorkflow {
- public:
- ReadNV12PlanesWorkflow(std::unique_ptr<CopyOutputRequest> copy_request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- base::WeakPtr<GLRendererCopier> copier_weak_ptr,
- ContextProvider* context_provider);
- ~ReadNV12PlanesWorkflow();
-
- void BindTransferBuffer();
- void StartPlaneReadback(int plane, GLenum readback_format);
- void UnbindTransferBuffer();
-
- gfx::Rect aligned_rect() const { return aligned_rect_; }
-
- gfx::Rect result_rect() const { return result_rect_; }
-
- std::unique_ptr<CopyOutputRequest> TakeRequest() {
- DCHECK(copy_request_);
-
- return std::move(copy_request_);
- }
-
- GLuint TakeTransferBuffer() {
- DCHECK(transfer_buffer_);
-
- GLuint result = transfer_buffer_;
- transfer_buffer_ = 0;
- return result;
- }
-
- // Returns true if the workflow has completed (i.e. readback requests for
- // all planes have finished).
- bool IsCompleted() const {
- return queries_ == std::array<GLuint, 2>{{0, 0}};
- }
-
- GLuint query(int plane) { return queries_[plane]; }
-
- // Marks that a readback has completed for a given plane.
- void MarkQueryCompleted(int plane) { queries_[plane] = 0; }
-
- private:
- gfx::Size y_texture_size() const;
- gfx::Size chroma_texture_size() const;
-
- std::unique_ptr<CopyOutputRequest> copy_request_;
- const gfx::Rect aligned_rect_;
- const gfx::Rect result_rect_;
- GLuint transfer_buffer_;
- std::array<GLuint, 2> queries_;
-
- base::WeakPtr<GLRendererCopier> copier_weak_ptr_;
- const raw_ptr<ContextProvider> context_provider_;
- std::array<int, 2> data_offsets_;
- };
-
- // Similar to RenderResultTexture(), except also transform the image into I420
- // format (a popular video format). Three textures, representing each of the
- // Y/U/V planes (as described in GLI420Converter), are populated and their GL
- // references placed in |things|. The image content is always rendered in
- // top-down row order and swizzled (if needed), to support efficient readback
- // later on.
- //
- // For alignment reasons, sometimes a slightly larger result will be provided,
- // and the return Rect will indicate the actual bounds that were rendered
- // (|result_rect|'s coordinate system). See StartI420ReadbackFromTextures()
- // for more details.
- gfx::Rect RenderI420Textures(const CopyOutputRequest& request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things);
-
- // Similar to RenderResultTexture(), except also transform the image into NV12
- // format (a popular video format). Two textures, representing each of the
- // Y/UV planes (as described in GLNV12Converter), are populated and their GL
- // references placed in |things|. The image content is always rendered in
- // top-down row order and swizzled (if needed), to support efficient readback
- // later on.
- //
- // For alignment reasons, sometimes a slightly larger result will be provided,
- // and the return Rect will indicate the actual bounds that were rendered
- // (|result_rect|'s coordinate system). See StartNV12ReadbackFromTextures()
- // for more details.
- gfx::Rect RenderNV12Textures(const CopyOutputRequest& request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things);
-
- // Binds the |things->result_texture| to a framebuffer and calls
- // StartReadbackFromFramebuffer(). This is only for RGBA requests with
- // destination set to kSystemMemory.
- // Assumes the image content is in top-down row order (and is red-blue swapped
- // iff RenderResultTexture() would have done that).
- void StartReadbackFromTexture(std::unique_ptr<CopyOutputRequest> request,
- const gfx::Rect& result_rect,
- const gfx::ColorSpace& color_space,
- ReusableThings* things);
-
- // Processes the next phase of the copy request by starting readback from the
- // currently-bound framebuffer into a pixel transfer buffer. |readback_offset|
- // is the origin of the readback rect within the framebuffer, with
- // |result_rect| providing the size of the readback rect. |flipped_source| is
- // true if the framebuffer content is in bottom-up row order, and
- // |swapped_red_and_blue| specifies whether the red and blue channels have
- // been swapped. This method kicks-off an asynchronous glReadPixels()
- // workflow.
- void StartReadbackFromFramebuffer(std::unique_ptr<CopyOutputRequest> request,
- const gfx::Vector2d& readback_offset,
- bool flipped_source,
- bool swapped_red_and_blue,
- const gfx::Rect& result_rect,
- const gfx::ColorSpace& color_space);
-
- // Renders a scaled/transformed copy of a source texture similarly to
- // RenderResultTexture, but packages up the result in a mailbox and sends it
- // as the result to the CopyOutputRequest.
- void RenderAndSendTextureResult(std::unique_ptr<CopyOutputRequest> request,
- bool flipped_source,
- const gfx::ColorSpace& source_color_space,
- const gfx::ColorSpace& dest_color_space,
- GLuint source_texture,
- const gfx::Size& source_texture_size,
- const gfx::Rect& sampling_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things);
-
- // Like StartReadbackFromTexture(), except that this processes the three Y/U/V
- // result textures in |things| by using three framebuffers and three
- // asynchronous readback operations. A single pixel transfer buffer is used to
- // hold the results of all three readbacks (i.e., each plane starts at a
- // different offset in the transfer buffer).
- //
- // |aligned_rect| is the Rect returned from the RenderI420Textures() call, and
- // is required so that the CopyOutputResult sent at the end of this workflow
- // will access the correct region of pixels.
- void StartI420ReadbackFromTextures(std::unique_ptr<CopyOutputRequest> request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things);
-
- // Like StartReadbackFromTexture(), except that this processes the two Y/UV
- // result textures in |things| by using two framebuffers and two asynchronous
- // readback operations. A single pixel transfer buffer is used to hold the
- // results of both readbacks (i.e., each plane starts at a different offset in
- // the transfer buffer).
- //
- // |aligned_rect| is the Rect returned from the RenderNV12Textures() call, and
- // is required so that the CopyOutputResult sent at the end of this workflow
- // will access the correct region of pixels.
- void StartNV12ReadbackFromTextures(std::unique_ptr<CopyOutputRequest> request,
- const gfx::Rect& aligned_rect,
- const gfx::Rect& result_rect,
- ReusableThings* things);
-
- // Retrieves a cached ReusableThings instance for the given CopyOutputRequest
- // source, or creates a new instance.
- std::unique_ptr<ReusableThings> TakeReusableThingsOrCreate(
- const base::UnguessableToken& requester);
-
- // If |requester| is a valid UnguessableToken, this stashes the given
- // ReusableThings instance in the cache for use in future CopyOutputRequests
- // from the same requester. Otherwise, |things| is freed.
- void StashReusableThingsOrDelete(const base::UnguessableToken& requester,
- std::unique_ptr<ReusableThings> things);
-
- // Queries the GL implementation to determine which is the more performance-
- // optimal supported readback format: GL_RGBA or GL_BGRA_EXT, and memoizes the
- // result for all future calls.
- //
- // Precondition: The GL context has a complete, bound framebuffer ready for
- // readback.
- GLenum GetOptimalReadbackFormat();
-
- // Returns true if the red and blue channels should be swapped within the GPU,
- // where such an operation has negligible cost, so that later the red-blue
- // swap does not need to happen on the CPU (non-negligible cost).
- bool ShouldSwapRedAndBlueForBitmapReadback();
-
- void FinishReadPixelsWorkflow(ReadPixelsWorkflow*);
- void FinishReadI420PlanesWorkflow(ReadI420PlanesWorkflow*, int plane);
- void FinishReadNV12PlanesWorkflow(ReadNV12PlanesWorkflow* workflow,
- int plane);
-
- // Injected dependencies.
- const raw_ptr<ContextProvider> context_provider_;
- const raw_ptr<TextureDeleter> texture_deleter_;
-
- // This increments by one for every call to FreeUnusedCachedResources(). It
- // is meant to determine when cached resources should be freed because they
- // are unlikely to see further use.
- uint32_t purge_counter_ = 0;
-
- // A cache of resources recently used in the execution of a stream of copy
- // requests from the same source. Since this reflects the number of active
- // video captures, it is expected to almost always be zero or one entry in
- // size.
- base::flat_map<base::UnguessableToken, std::unique_ptr<ReusableThings>>
- cache_;
-
- // This specifies whether the GPU+driver combination executes readback more
- // efficiently using GL_RGBA or GL_BGRA_EXT format. This starts out as
- // GL_NONE, which means "unknown," and will be determined at the time the
- // first readback request is made.
- GLenum optimal_readback_format_ = static_cast<GLenum>(0 /*GL_NONE*/);
-
- // Purge cache entries that have not been used after this many calls to
- // FreeUnusedCachedResources(). The choice of 60 is arbitrary, but on most
- // platforms means that a somewhat-to-fully active compositor will cause
- // things to be auto-purged after approx. 1-2 seconds of not being used.
- static constexpr int kKeepalivePeriod = 60;
-
- std::vector<std::unique_ptr<ReadPixelsWorkflow>> read_pixels_workflows_;
- std::vector<std::unique_ptr<ReadI420PlanesWorkflow>> read_i420_workflows_;
- std::vector<std::unique_ptr<ReadNV12PlanesWorkflow>> read_nv12_workflows_;
-
- // Weak ptr to this class.
- base::WeakPtrFactory<GLRendererCopier> weak_factory_{this};
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_COPIER_H_
diff --git a/chromium/components/viz/service/display/gl_renderer_copier_perftest.cc b/chromium/components/viz/service/display/gl_renderer_copier_perftest.cc
deleted file mode 100644
index 853f61e9fe9..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_copier_perftest.cc
+++ /dev/null
@@ -1,338 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/service/display/gl_renderer_copier.h"
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/timer/lap_timer.h"
-#include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/common/frame_sinks/copy_output_result.h"
-#include "components/viz/common/frame_sinks/copy_output_util.h"
-#include "components/viz/service/display/gl_renderer.h"
-#include "components/viz/test/paths.h"
-#include "components/viz/test/test_in_process_context_provider.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_result_reporter.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace viz {
-
-namespace {
-
-// The size of the source texture or framebuffer.
-constexpr gfx::Size kSourceSize = gfx::Size(240, 120);
-
-// In order to test coordinate calculations and Y-flipping, the tests will issue
-// copy requests for a small region just to the right and below the center of
-// the entire source texture/framebuffer.
-constexpr gfx::Rect kRequestArea = gfx::Rect(kSourceSize.width() / 2,
- kSourceSize.height() / 2,
- kSourceSize.width() / 4,
- kSourceSize.height() / 4);
-
-constexpr char kMetricPrefixGLRendererCopier[] = "GLRendererCopier.";
-constexpr char kMetricReadbackThroughputRunsPerS[] = "readback_throughput";
-
-perf_test::PerfResultReporter SetUpGLRendererCopierReporter(
- const std::string& story) {
- perf_test::PerfResultReporter reporter(kMetricPrefixGLRendererCopier, story);
- reporter.RegisterImportantMetric(kMetricReadbackThroughputRunsPerS, "runs/s");
- return reporter;
-}
-
-base::FilePath GetTestFilePath(const base::FilePath::CharType* basename) {
- base::FilePath test_dir;
- base::PathService::Get(Paths::DIR_TEST_DATA, &test_dir);
- return test_dir.Append(base::FilePath(basename));
-}
-
-} // namespace
-
-class GLRendererCopierPerfTest : public testing::Test {
- public:
- GLRendererCopierPerfTest() {
- context_provider_ = base::MakeRefCounted<TestInProcessContextProvider>(
- TestContextType::kGLES2, /*support_locking=*/false);
- gpu::ContextResult result = context_provider_->BindToCurrentThread();
- DCHECK_EQ(result, gpu::ContextResult::kSuccess);
- gl_ = context_provider_->ContextGL();
- texture_deleter_ =
- std::make_unique<TextureDeleter>(base::ThreadTaskRunnerHandle::Get());
- copier_ = std::make_unique<GLRendererCopier>(context_provider_.get(),
- texture_deleter_.get());
- }
-
- GLRendererCopierPerfTest(const GLRendererCopierPerfTest&) = delete;
- GLRendererCopierPerfTest& operator=(const GLRendererCopierPerfTest&) = delete;
-
- void TearDown() override {
- DeleteSourceFramebuffer();
- DeleteSourceTexture();
- copier_.reset();
- texture_deleter_.reset();
- }
-
- gfx::Rect DrawToWindowSpace(const gfx::Rect& draw_rect, bool flipped_source) {
- gfx::Rect window_rect = draw_rect;
- if (flipped_source)
- window_rect.set_y(kSourceSize.height() - window_rect.bottom());
- return window_rect;
- }
-
- // Creates a packed RGBA (bytes_per_pixel=4) bitmap in OpenGL byte/row order
- // from the given SkBitmap.
- std::unique_ptr<uint8_t[]> CreateGLPixelsFromSkBitmap(SkBitmap bitmap,
- bool flipped_source) {
- // |bitmap| could be of any color type (and is usually BGRA). Convert it to
- // a RGBA bitmap in the GL byte order.
- SkBitmap rgba_bitmap;
- rgba_bitmap.allocPixels(SkImageInfo::Make(bitmap.width(), bitmap.height(),
- kRGBA_8888_SkColorType,
- kPremul_SkAlphaType));
- SkPixmap pixmap;
- const bool success =
- bitmap.peekPixels(&pixmap) && rgba_bitmap.writePixels(pixmap, 0, 0);
- CHECK(success);
-
- // Copy the RGBA bitmap into a raw byte array, reversing the row order and
- // maybe stripping-out the alpha channel.
- const int bytes_per_pixel = 4;
- std::unique_ptr<uint8_t[]> pixels(
- new uint8_t[rgba_bitmap.width() * rgba_bitmap.height() *
- bytes_per_pixel]);
- for (int y = 0; y < rgba_bitmap.height(); ++y) {
- const uint8_t* src = static_cast<uint8_t*>(rgba_bitmap.getAddr(0, y));
- const int flipped_y = flipped_source ? rgba_bitmap.height() - y - 1 : y;
- uint8_t* dest =
- pixels.get() + flipped_y * rgba_bitmap.width() * bytes_per_pixel;
- for (int x = 0; x < rgba_bitmap.width(); ++x) {
- *(dest++) = *(src++);
- *(dest++) = *(src++);
- *(dest++) = *(src++);
- if (bytes_per_pixel == 4)
- *(dest++) = *(src++);
- else
- ++src;
- }
- }
-
- return pixels;
- }
-
- GLuint CreateSourceTexture(bool flipped_source) {
- CHECK_EQ(0u, source_texture_);
- SkBitmap source_bitmap;
- cc::ReadPNGFile(GetTestFilePath(FILE_PATH_LITERAL("16_color_rects.png")),
- &source_bitmap);
- source_bitmap.setImmutable();
- gl_->GenTextures(1, &source_texture_);
- gl_->BindTexture(GL_TEXTURE_2D, source_texture_);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl_->TexImage2D(
- GL_TEXTURE_2D, 0, static_cast<GLenum>(GL_RGBA), kSourceSize.width(),
- kSourceSize.height(), 0, static_cast<GLenum>(GL_RGBA), GL_UNSIGNED_BYTE,
- CreateGLPixelsFromSkBitmap(source_bitmap, flipped_source).get());
- gl_->BindTexture(GL_TEXTURE_2D, 0);
- return source_texture_;
- }
-
- void DeleteSourceTexture() {
- if (source_texture_ != 0) {
- gl_->DeleteTextures(1, &source_texture_);
- source_texture_ = 0;
- }
- }
-
- void CreateAndBindSourceFramebuffer(GLuint texture) {
- ASSERT_EQ(0u, source_framebuffer_);
- gl_->GenFramebuffers(1, &source_framebuffer_);
- gl_->BindFramebuffer(GL_FRAMEBUFFER, source_framebuffer_);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture, 0);
- }
-
- void DeleteSourceFramebuffer() {
- if (source_framebuffer_ != 0) {
- gl_->DeleteFramebuffers(1, &source_framebuffer_);
- source_framebuffer_ = 0;
- }
- }
-
- void CopyFromTextureOrFramebuffer(
- bool have_source_texture,
- CopyOutputResult::Format result_format,
- CopyOutputResult::Destination result_destination,
- bool scale_by_half,
- bool flipped_source,
- const std::string& story) {
- std::unique_ptr<CopyOutputResult> result;
-
- gfx::Rect result_selection(kRequestArea);
- if (scale_by_half)
- result_selection = gfx::ScaleToEnclosingRect(result_selection, 0.5f);
-
- copy_output::RenderPassGeometry geometry;
- // geometry.result_bounds not used by GLRendererCopier
- geometry.sampling_bounds =
- DrawToWindowSpace(gfx::Rect(kSourceSize), flipped_source);
- geometry.result_selection = result_selection;
- geometry.readback_offset =
- DrawToWindowSpace(geometry.result_selection, flipped_source)
- .OffsetFromOrigin();
-
- timer_.Reset();
- do {
- base::RunLoop loop;
- auto request = std::make_unique<CopyOutputRequest>(
- result_format, result_destination,
- base::BindOnce(
- [](std::unique_ptr<CopyOutputResult>* result,
- base::OnceClosure quit_closure,
- std::unique_ptr<CopyOutputResult> result_from_copier) {
- *result = std::move(result_from_copier);
- std::move(quit_closure).Run();
- },
- &result, loop.QuitClosure()));
- if (scale_by_half)
- request->SetUniformScaleRatio(2, 1);
- const GLuint source_texture = CreateSourceTexture(flipped_source);
- CreateAndBindSourceFramebuffer(source_texture);
-
- copier_->CopyFromTextureOrFramebuffer(
- std::move(request), geometry, static_cast<GLenum>(GL_RGBA),
- have_source_texture ? source_texture : 0, kSourceSize, flipped_source,
- gfx::ColorSpace::CreateSRGB());
- loop.Run();
-
- // Check that a result was produced and is of the expected rect/size.
- ASSERT_TRUE(result);
- ASSERT_FALSE(result->IsEmpty());
- if (scale_by_half)
- ASSERT_EQ(gfx::ScaleToEnclosingRect(kRequestArea, 0.5f),
- result->rect());
- else
- ASSERT_EQ(kRequestArea, result->rect());
-
- if (result_format == CopyOutputResult::Format::RGBA &&
- result_destination == CopyOutputResult::Destination::kSystemMemory) {
- auto scoped_bitmap = result->ScopedAccessSkBitmap();
- const SkBitmap& result_bitmap = scoped_bitmap.bitmap();
- ASSERT_TRUE(result_bitmap.readyToDraw());
- } else if (result_format == CopyOutputResult::Format::I420_PLANES) {
- const int result_width = result->rect().width();
- const int result_height = result->rect().height();
- const int y_width = result_width;
- const int y_stride = y_width;
- std::unique_ptr<uint8_t[]> y_data(
- new uint8_t[y_stride * result_height]);
- const int chroma_width = (result_width + 1) / 2;
- const int u_stride = chroma_width;
- const int v_stride = chroma_width;
- const int chroma_height = (result_height + 1) / 2;
- std::unique_ptr<uint8_t[]> u_data(
- new uint8_t[u_stride * chroma_height]);
- std::unique_ptr<uint8_t[]> v_data(
- new uint8_t[v_stride * chroma_height]);
-
- const bool success =
- result->ReadI420Planes(y_data.get(), y_stride, u_data.get(),
- u_stride, v_data.get(), v_stride);
- ASSERT_TRUE(success);
- }
-
- DeleteSourceFramebuffer();
- DeleteSourceTexture();
- timer_.NextLap();
- } while (!timer_.HasTimeLimitExpired());
-
- auto reporter = SetUpGLRendererCopierReporter(story);
- reporter.AddResult(kMetricReadbackThroughputRunsPerS,
- timer_.LapsPerSecond());
- }
-
- private:
- raw_ptr<gpu::gles2::GLES2Interface> gl_ = nullptr;
- scoped_refptr<TestInProcessContextProvider> context_provider_;
- std::unique_ptr<TextureDeleter> texture_deleter_;
- std::unique_ptr<GLRendererCopier> copier_;
- GLuint source_texture_ = 0;
- GLuint source_framebuffer_ = 0;
- base::LapTimer timer_;
-};
-
-// Fast-Path: If no transformation is necessary and no new textures need to be
-// generated, read-back directly from the currently-bound framebuffer.
-TEST_F(GLRendererCopierPerfTest, NoTransformNoNewTextures) {
- CopyFromTextureOrFramebuffer(
- /*have_source_texture=*/false, CopyOutputResult::Format::RGBA,
- CopyOutputResult::Destination::kSystemMemory,
- /*scale_by_half=*/false, /*flipped_source=*/false,
- "no_transformation_and_no_new_textures");
-}
-
-// Source texture is the one attached to the framebuffer, better performance
-// than having to make a copy of the framebuffer.
-TEST_F(GLRendererCopierPerfTest, HaveTextureResultRGBABitmap) {
- CopyFromTextureOrFramebuffer(
- /*have_source_texture=*/true, CopyOutputResult::Format::RGBA,
- CopyOutputResult::Destination::kSystemMemory,
- /*scale_by_half=*/true, /*flipped_source=*/false,
- "framebuffer_has_texture_and_result_is_RGBA_BITMAP");
-}
-TEST_F(GLRendererCopierPerfTest, HaveTextureResultRGBATexture) {
- CopyFromTextureOrFramebuffer(
- /*have_source_texture=*/true, CopyOutputResult::Format::RGBA,
- CopyOutputResult::Destination::kNativeTextures,
- /*scale_by_half=*/true, /*flipped_source=*/false,
- "framebuffer_has_texture_and_result_is_RGBA_TEXTURE");
-}
-TEST_F(GLRendererCopierPerfTest, HaveTextureResultI420Planes) {
- CopyFromTextureOrFramebuffer(
- /*have_source_texture=*/true, CopyOutputResult::Format::I420_PLANES,
- CopyOutputResult::Destination::kSystemMemory,
- /*scale_by_half=*/true, /*flipped_source=*/false,
- "framebuffer_has_texture_and_result_is_I420_PLANES");
-}
-
-// Have to make a copy of the framebuffer for the source texture.
-TEST_F(GLRendererCopierPerfTest, NoTextureResultI420Planes) {
- CopyFromTextureOrFramebuffer(
- /*have_source_texture=*/false, CopyOutputResult::Format::I420_PLANES,
- CopyOutputResult::Destination::kSystemMemory,
- /*scale_by_half=*/true, /*flipped_source=*/false,
- "framebuffer_doesn't_have_texture_and_result_is_I420_PLANES");
-}
-
-// Source content is vertically flipped.
-TEST_F(GLRendererCopierPerfTest, SourceContentVerticallyFlipped) {
- CopyFromTextureOrFramebuffer(/*have_source_texture=*/true,
- CopyOutputResult::Format::I420_PLANES,
- CopyOutputResult::Destination::kSystemMemory,
- /*scale_by_half=*/true, /*flipped_source=*/true,
- "source_content_is_vertically_flipped");
-}
-
-// Result is not scaled by half.
-TEST_F(GLRendererCopierPerfTest, ResultNotScaled) {
- CopyFromTextureOrFramebuffer(/*have_source_texture=*/true,
- CopyOutputResult::Format::I420_PLANES,
- CopyOutputResult::Destination::kSystemMemory,
- /*scale_by_half=*/false, /*flipped_source=*/true,
- "result_is_not_scaled_by_half");
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc b/chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc
deleted file mode 100644
index 0f72f75a2aa..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_copier_pixeltest.cc
+++ /dev/null
@@ -1,958 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/gl_renderer_copier.h"
-
-#include <stdint.h>
-
-#include <cstring>
-#include <memory>
-#include <tuple>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/test/test_switches.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "cc/test/pixel_test.h"
-#include "cc/test/pixel_test_utils.h"
-#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/common/frame_sinks/copy_output_result.h"
-#include "components/viz/common/frame_sinks/copy_output_util.h"
-#include "components/viz/service/display/gl_renderer.h"
-#include "components/viz/test/gl_scaler_test_util.h"
-#include "components/viz/test/paths.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libyuv/include/libyuv/convert_argb.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkImageInfo.h"
-#include "third_party/skia/include/core/SkPixmap.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/color_transform.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-
-#if BUILDFLAG(IS_ANDROID)
-#include "base/android/build_info.h"
-#endif
-
-namespace viz {
-
-namespace {
-
-base::FilePath GetTestFilePath(const base::FilePath::CharType* basename) {
- base::FilePath test_dir;
- base::PathService::Get(Paths::DIR_TEST_DATA, &test_dir);
- return test_dir.Append(base::FilePath(basename));
-}
-
-// Creates a packed RGBA (bytes_per_pixel=4) or RGB (bytes_per_pixel=3) bitmap
-// in OpenGL byte/row order from the given SkBitmap.
-std::unique_ptr<uint8_t[]> CreateGLPixelsFromSkBitmap(SkBitmap bitmap,
- GLuint source_format,
- bool flip_source) {
- // |bitmap| could be of any color type (and is usually BGRA). Convert it to
- // a RGBA bitmap in the GL byte order.
- SkBitmap rgba_bitmap;
- rgba_bitmap.allocPixels(SkImageInfo::Make(bitmap.width(), bitmap.height(),
- kRGBA_8888_SkColorType,
- kPremul_SkAlphaType));
- SkPixmap pixmap;
- const bool success =
- bitmap.peekPixels(&pixmap) && rgba_bitmap.writePixels(pixmap, 0, 0);
- CHECK(success);
-
- // Copy the RGBA bitmap into a raw byte array, reversing the row order and
- // maybe stripping-out the alpha channel.
- const int bytes_per_pixel = source_format == GL_RGBA ? 4 : 3;
- std::unique_ptr<uint8_t[]> pixels(
- new uint8_t[rgba_bitmap.width() * rgba_bitmap.height() *
- bytes_per_pixel]);
- for (int y = 0; y < rgba_bitmap.height(); ++y) {
- const uint8_t* src = static_cast<uint8_t*>(rgba_bitmap.getAddr(0, y));
- const int flipped_y = flip_source ? rgba_bitmap.height() - y - 1 : y;
- uint8_t* dest =
- pixels.get() + flipped_y * rgba_bitmap.width() * bytes_per_pixel;
- for (int x = 0; x < rgba_bitmap.width(); ++x) {
- *(dest++) = *(src++);
- *(dest++) = *(src++);
- *(dest++) = *(src++);
- if (bytes_per_pixel == 4)
- *(dest++) = *(src++);
- else
- ++src;
- }
- }
-
- return pixels;
-}
-
-// Returns a SkBitmap, given a packed RGBA bitmap in OpenGL byte/row order.
-SkBitmap CreateSkBitmapFromGLPixels(const uint8_t* pixels,
- const gfx::Size& size) {
- SkBitmap bitmap;
- bitmap.allocPixels(
- SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType,
- kPremul_SkAlphaType),
- size.width() * 4);
- for (int y = 0; y < size.height(); ++y) {
- const int flipped_y = size.height() - y - 1;
- const uint8_t* const src_row = pixels + flipped_y * size.width() * 4;
- void* const dest_row = bitmap.getAddr(0, y);
- std::memcpy(dest_row, src_row, size.width() * 4);
- }
- return bitmap;
-}
-
-// Reads back the texture in the given |mailbox| to a SkBitmap in Skia-native
-// format.
-SkBitmap ReadbackToSkBitmap(gpu::gles2::GLES2Interface* gl,
- const gpu::Mailbox& mailbox,
- const gpu::SyncToken& sync_token,
- const gfx::Size& texture_size) {
- // Bind the texture to a framebuffer from which to read the pixels.
- if (sync_token.HasData())
- gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
- GLuint texture = gl->CreateAndConsumeTextureCHROMIUM(mailbox.name);
- GLuint framebuffer = 0;
- gl->GenFramebuffers(1, &framebuffer);
- gl->BindFramebuffer(GL_FRAMEBUFFER, framebuffer);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- texture, 0);
-
- // Read the pixels and convert to SkBitmap form for test comparisons.
- std::unique_ptr<uint8_t[]> pixels(new uint8_t[texture_size.GetArea() * 4]);
- gl->ReadPixels(0, 0, texture_size.width(), texture_size.height(), GL_RGBA,
- GL_UNSIGNED_BYTE, pixels.get());
- gl->DeleteFramebuffers(1, &framebuffer);
- gl->DeleteTextures(1, &texture);
- return CreateSkBitmapFromGLPixels(pixels.get(), texture_size);
-}
-
-// Validates whether all rows are identical (i.e. for each row r != 0, compares
-// it with row 0.
-void ValidateRows(uint8_t* pixel_data, size_t row_stride, size_t height) {
- for (size_t row = 1; row < height; ++row) {
- for (size_t col = 0; col < row_stride; ++col) {
- EXPECT_NEAR(pixel_data[col], pixel_data[col + row * row_stride], 1)
- << " mismatch in row " << row << ", column " << col;
- }
- }
-}
-
-// Returns maximum allowed difference between the expected and actual pixel
-// values.
-int GetTolerance() {
- return 1;
-}
-
-} // namespace
-
-//
-// All tests in this class follow roughly the same pattern::
-// - Construct a CopyOutputRequest, with arguments depending on the test
-// parameters and the specific format that is being tested.
-// - Upload source texture to GL.
-// - Invoke GLRendererCopier::CopyFromTextureOrFramebuffer(), with arguments
-// depending on the test parameters, passing the created CopyOutputRequest.
-// - Load the result into memory and compare with baseline.
-//
-// Parameters:
-// 0. GL format to use when uploading source texture.
-// 1. True if the copier will also receive the texture in a call to
-// `CopyFromTextureOrFramebuffer()`, false otherwise.
-// 2. Destiation for the CopyOutputRequest (native textures or system memory).
-// 3. True if the result should be scaled by half in each dimension, false
-// otherwise.
-// 4. True if the source texture will be flipped (bottom-up), false otherwise.
-class GLRendererCopierPixelTest
- : public cc::PixelTest,
- public testing::WithParamInterface<
- std::tuple<GLenum, bool, CopyOutputResult::Destination, bool, bool>> {
- public:
- // In order to test coordinate calculations and Y-flipping, the tests will
- // issue copy requests for a small region just to the right and below the
- // center of the entire source texture/framebuffer.
- gfx::Rect GetRequestArea() const {
- DCHECK(!source_size_.IsZero());
-
- gfx::Rect result(source_size_.width() / 2, source_size_.height() / 2,
- source_size_.width() / 4, source_size_.height() / 4);
-
- if (scale_by_half_) {
- return gfx::ScaleToEnclosingRect(result, 0.5f);
- }
-
- return result;
- }
-
- void SetUp() override {
- SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
-
- texture_deleter_ =
- std::make_unique<TextureDeleter>(base::ThreadTaskRunnerHandle::Get());
-
- source_gl_format_ = std::get<0>(GetParam());
- have_source_texture_ = std::get<1>(GetParam());
- result_destination_ = std::get<2>(GetParam());
- scale_by_half_ = std::get<3>(GetParam());
- flipped_source_ = std::get<4>(GetParam());
-
- gl_ = context_provider()->ContextGL();
- copier_ = std::make_unique<GLRendererCopier>(context_provider(),
- texture_deleter_.get());
-
- ASSERT_TRUE(cc::ReadPNGFile(
- GetTestFilePath(FILE_PATH_LITERAL("16_color_rects.png")),
- &source_bitmap_));
- source_bitmap_.setImmutable();
-
- source_size_ = gfx::Size(source_bitmap_.width(), source_bitmap_.height());
-
- source_bitmap_rgba_ =
- GLScalerTestUtil::CopyAndConvertToRGBA(source_bitmap_);
- source_bitmap_rgba_.setImmutable();
-
- source_bitmap_yuv_ = source_bitmap_rgba_;
- GLScalerTestUtil::ConvertRGBABitmapToYUV(&source_bitmap_yuv_);
- source_bitmap_yuv_.setImmutable();
- }
-
- void TearDown() override {
- DeleteSourceFramebuffer();
- DeleteSourceTexture();
- copier_.reset();
- texture_deleter_.reset();
- }
-
- gpu::gles2::GLES2Interface* gl() { return gl_; }
-
- GLRendererCopier* copier() { return copier_.get(); }
-
- gfx::Rect DrawToWindowSpace(const gfx::Size& source_size,
- const gfx::Rect& draw_rect) {
- gfx::Rect window_rect = draw_rect;
- if (flipped_source_)
- window_rect.set_y(source_size.height() - window_rect.bottom());
- return window_rect;
- }
-
- GLuint CreateSourceTexture(SkBitmap source_bitmap) {
- CHECK_EQ(0u, source_texture_);
- gl_->GenTextures(1, &source_texture_);
- gl_->BindTexture(GL_TEXTURE_2D, source_texture_);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl_->TexImage2D(GL_TEXTURE_2D, 0, source_gl_format_, source_bitmap.width(),
- source_bitmap.height(), 0, source_gl_format_,
- GL_UNSIGNED_BYTE,
- CreateGLPixelsFromSkBitmap(source_bitmap, source_gl_format_,
- flipped_source_)
- .get());
- gl_->BindTexture(GL_TEXTURE_2D, 0);
- return source_texture_;
- }
-
- void DeleteSourceTexture() {
- if (source_texture_ != 0) {
- gl_->DeleteTextures(1, &source_texture_);
- source_texture_ = 0;
- }
- }
-
- void CreateAndBindSourceFramebuffer(GLuint texture) {
- ASSERT_EQ(0u, source_framebuffer_);
- gl_->GenFramebuffers(1, &source_framebuffer_);
- gl_->BindFramebuffer(GL_FRAMEBUFFER, source_framebuffer_);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture, 0);
- }
-
- void DeleteSourceFramebuffer() {
- if (source_framebuffer_ != 0) {
- gl_->DeleteFramebuffers(1, &source_framebuffer_);
- source_framebuffer_ = 0;
- }
- }
-
- protected:
- // The size of the source texture or framebuffer.
- gfx::Size source_size_;
-
- GLenum source_gl_format_;
- bool have_source_texture_;
- CopyOutputResult::Destination result_destination_;
- bool scale_by_half_;
- bool flipped_source_;
- SkBitmap source_bitmap_;
- SkBitmap source_bitmap_rgba_;
- SkBitmap source_bitmap_yuv_;
-
- private:
- gpu::gles2::GLES2Interface* gl_ = nullptr;
- std::unique_ptr<TextureDeleter> texture_deleter_;
- std::unique_ptr<GLRendererCopier> copier_;
- GLuint source_texture_ = 0;
- GLuint source_framebuffer_ = 0;
-};
-
-// On Android KitKat bots (but not newer ones), the left column of pixels in the
-// result is off-by-one in the red channel. Use the off-by-one camparator as a
-// workaround.
-#if BUILDFLAG(IS_ANDROID)
-#define PIXEL_COMPARATOR() cc::FuzzyPixelOffByOneComparator(false)
-#else
-#define PIXEL_COMPARATOR() cc::ExactPixelComparator(false)
-#endif
-
-TEST_P(GLRendererCopierPixelTest, ExecutesCopyRequestRGBA) {
- // Create and execute a CopyOutputRequest via the GLRendererCopier.
- std::unique_ptr<CopyOutputResult> result;
- {
- base::RunLoop loop;
- auto request = std::make_unique<CopyOutputRequest>(
- CopyOutputRequest::ResultFormat::RGBA, result_destination_,
- base::BindOnce(
- [](std::unique_ptr<CopyOutputResult>* result,
- base::OnceClosure quit_closure,
- std::unique_ptr<CopyOutputResult> result_from_copier) {
- *result = std::move(result_from_copier);
- std::move(quit_closure).Run();
- },
- &result, loop.QuitClosure()));
- if (scale_by_half_) {
- request->SetUniformScaleRatio(2, 1);
- }
-
- request->set_result_selection(GetRequestArea());
-
- const GLuint source_texture = CreateSourceTexture(source_bitmap_);
- CreateAndBindSourceFramebuffer(source_texture);
-
- copy_output::RenderPassGeometry geometry;
- // geometry.result_bounds not used by GLRendererCopier
- geometry.sampling_bounds =
- DrawToWindowSpace(source_size_, gfx::Rect(source_size_));
- geometry.result_selection = request->result_selection();
- geometry.readback_offset =
- DrawToWindowSpace(source_size_, geometry.result_selection)
- .OffsetFromOrigin();
-
- copier()->CopyFromTextureOrFramebuffer(
- std::move(request), geometry, source_gl_format_,
- have_source_texture_ ? source_texture : 0, source_size_,
- flipped_source_, gfx::ColorSpace::CreateSRGB());
- loop.Run();
- }
-
- // Check that a result was produced and is of the expected rect/size.
- ASSERT_TRUE(result);
- ASSERT_FALSE(result->IsEmpty());
- ASSERT_EQ(GetRequestArea(), result->rect());
-
- // Examine the image in the |result|, and compare it to the baseline PNG file.
- absl::optional<CopyOutputResult::ScopedSkBitmap> scoped_bitmap;
- SkBitmap actual;
- if (result_destination_ == CopyOutputResult::Destination::kSystemMemory) {
- scoped_bitmap = result->ScopedAccessSkBitmap();
- actual = scoped_bitmap->bitmap();
- } else {
- actual = ReadbackToSkBitmap(
- gl(), result->GetTextureResult()->planes[0].mailbox,
- result->GetTextureResult()->planes[0].sync_token, result->size());
- }
- const auto png_file_path = GetTestFilePath(
- scale_by_half_ ? FILE_PATH_LITERAL("half_of_one_of_16_color_rects.png")
- : FILE_PATH_LITERAL("one_of_16_color_rects.png"));
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kRebaselinePixelTests))
- EXPECT_TRUE(cc::WritePNGFile(actual, png_file_path, false));
- if (!cc::MatchesPNGFile(actual, png_file_path, PIXEL_COMPARATOR())) {
- LOG(ERROR) << "Entire source: " << cc::GetPNGDataUrl(source_bitmap_);
- ADD_FAILURE();
- }
-}
-
-TEST_P(GLRendererCopierPixelTest, ExecutesCopyRequestNV12) {
- if (result_destination_ ==
- CopyOutputRequest::ResultDestination::kNativeTextures) {
- // TODO(https://crbug.com/1216287): Enable once textures are supported.
- GTEST_SKIP()
- << "Enable once the GLRenderer supports producing producing results to "
- "a texture for NV12 format.";
- }
-
- const gfx::Rect request_area = GetRequestArea();
-
- // Check if request's width and height are even (required for NV12 format).
- // The test case expects the result size to match the request size exactly,
- // which is not possible with NV12 when the request size dimensions aren't
- // even.
- ASSERT_TRUE(request_area.width() % 2 == 0 && request_area.height() % 2 == 0)
- << " request size is not even, request_area.size()="
- << request_area.size().ToString();
-
- // Additionally, the test uses helpers that assume pixel data can be packed (4
- // 8-bit values in 1 32-bit pixel).
- ASSERT_TRUE(request_area.width() % 4 == 0)
- << " request width is not divisible by 4, request_area.width()="
- << request_area.width();
-
- // Create and execute a CopyOutputRequest via the GLRendererCopier.
- std::unique_ptr<CopyOutputResult> result;
- {
- base::RunLoop loop;
- auto request = std::make_unique<CopyOutputRequest>(
- CopyOutputRequest::ResultFormat::NV12_PLANES, result_destination_,
- base::BindOnce(
- [](std::unique_ptr<CopyOutputResult>* result,
- base::OnceClosure quit_closure,
- std::unique_ptr<CopyOutputResult> result_from_copier) {
- *result = std::move(result_from_copier);
- std::move(quit_closure).Run();
- },
- &result, loop.QuitClosure()));
- if (scale_by_half_) {
- request->SetUniformScaleRatio(2, 1);
- }
-
- request->set_result_selection(request_area);
-
- // Upload source texture to GL - the texture will be converted to RGBA if
- // necessary.
- const GLuint source_texture = CreateSourceTexture(source_bitmap_);
- CreateAndBindSourceFramebuffer(source_texture);
-
- copy_output::RenderPassGeometry geometry;
- // geometry.result_bounds not used by GLRendererCopier
- geometry.sampling_bounds =
- DrawToWindowSpace(source_size_, gfx::Rect(source_size_));
- geometry.result_selection = request->result_selection();
- geometry.readback_offset =
- DrawToWindowSpace(source_size_, geometry.result_selection)
- .OffsetFromOrigin();
-
- copier()->CopyFromTextureOrFramebuffer(
- std::move(request), geometry, source_gl_format_,
- have_source_texture_ ? source_texture : 0, source_size_,
- flipped_source_, gfx::ColorSpace::CreateSRGB());
- loop.Run();
- }
-
- // Check that a result was produced and is of the expected rect/size.
- ASSERT_TRUE(result);
- ASSERT_FALSE(result->IsEmpty());
- ASSERT_EQ(request_area, result->rect());
-
- // Examine the image in the |result|, and compare it to the baseline PNG file.
- // Approach is the same as the one in GLNV12ConverterPixelTest.
-
- // Allocate new bitmap, it will then be populated with Y & UV data.
- SkBitmap actual = GLScalerTestUtil::AllocateRGBABitmap(result->size());
- actual.eraseColor(SkColorSetARGB(0xff, 0x00, 0x00, 0x00));
-
- SkBitmap luma_plane;
- SkBitmap chroma_planes;
-
- if (result_destination_ == CopyOutputResult::Destination::kSystemMemory) {
- // Create a bitmap with packed Y values:
- luma_plane = GLScalerTestUtil::AllocateRGBABitmap(
- gfx::Size(result->size().width() / 4, result->size().height()));
-
- chroma_planes = GLScalerTestUtil::AllocateRGBABitmap(
- gfx::Size(luma_plane.width(), luma_plane.height() / 2));
-
- result->ReadNV12Planes(
- reinterpret_cast<uint8_t*>(luma_plane.getAddr(0, 0)),
- result->size().width(),
- reinterpret_cast<uint8_t*>(chroma_planes.getAddr(0, 0)),
- result->size().width());
- } else {
- LOG(ERROR) << "Texture results for NV12 are not supported yet!";
- ADD_FAILURE();
- }
-
- GLScalerTestUtil::UnpackPlanarBitmap(luma_plane, 0, &actual);
- GLScalerTestUtil::UnpackUVBitmap(chroma_planes, &actual);
-
- const auto png_file_path = GetTestFilePath(
- scale_by_half_ ? FILE_PATH_LITERAL("half_of_one_of_16_color_rects.png")
- : FILE_PATH_LITERAL("one_of_16_color_rects.png"));
-
- SkBitmap expected;
- if (!cc::ReadPNGFile(png_file_path, &expected)) {
- LOG(ERROR) << "Cannot read reference image: " << png_file_path.value();
- ADD_FAILURE();
- return;
- }
-
- expected = GLScalerTestUtil::CopyAndConvertToRGBA(expected);
- GLScalerTestUtil::ConvertRGBABitmapToYUV(&expected);
-
- constexpr float kAvgAbsoluteErrorLimit = 16.f;
- constexpr int kMaxAbsoluteErrorLimit = 0x80;
- if (!cc::MatchesBitmap(
- actual, expected,
- cc::FuzzyPixelComparator(false, 100.f, 0.f, kAvgAbsoluteErrorLimit,
- kMaxAbsoluteErrorLimit, 0))) {
- ADD_FAILURE();
- return;
- }
-}
-
-#undef PIXEL_COMPARATOR
-
-// These tests work similarly to `GLRendererCopierPixelTest`, but test various
-// request dimensions in more depth.
-//
-// Parameters:
-// 0. Destiation for the CopyOutputRequest (native textures or system memory).
-// 1. True if the result should be scaled by half in each dimension, false
-// otherwise.
-// 2. True if the request should specify odd coordinates for the result
-// selection rectangle, false otherwise.
-// 3. True if the request should specify odd dimensions for the result selection
-// rectangle, false otherwise.
-class GLRendererCopierDimensionsPixelTest
- : public cc::PixelTest,
- public testing::WithParamInterface<
- std::tuple<CopyOutputResult::Destination, bool, bool>> {
- public:
- void SetUp() override {
- SetUpGLWithoutRenderer(gfx::SurfaceOrigin::kBottomLeft);
-
- texture_deleter_ =
- std::make_unique<TextureDeleter>(base::ThreadTaskRunnerHandle::Get());
-
- result_destination_ = std::get<0>(GetParam());
- scale_by_half_ = std::get<1>(GetParam());
- use_odd_offset_ = std::get<2>(GetParam());
-
- gl_ = context_provider()->ContextGL();
- copier_ = std::make_unique<GLRendererCopier>(context_provider(),
- texture_deleter_.get());
-
- // For this test, use a generated bitmap, with 4 groups of 4 pixels each.
- const std::vector<SkColor> kCycle = {
- // Red:
- SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- SkColorSetARGB(0xff, 0xff, 0x00, 0x00),
- // Green:
- SkColorSetARGB(0xff, 0x00, 0xff, 0x00),
- SkColorSetARGB(0xff, 0x00, 0xff, 0x00),
- SkColorSetARGB(0xff, 0x00, 0xff, 0x00),
- SkColorSetARGB(0xff, 0x00, 0xff, 0x00),
- // Blue:
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff),
- SkColorSetARGB(0xff, 0x00, 0x00, 0xff),
- // White:
- SkColorSetARGB(0xff, 0xff, 0xff, 0xff),
- SkColorSetARGB(0xff, 0xff, 0xff, 0xff),
- SkColorSetARGB(0xff, 0xff, 0xff, 0xff),
- SkColorSetARGB(0xff, 0xff, 0xff, 0xff),
- };
- source_bitmap_ = GLScalerTestUtil::CreateCyclicalTestImage(
- gfx::Size(800, 600), GLScalerTestUtil::VERTICAL_STRIPES, kCycle, 0);
- // source_bitmap_.setImmutable();
- source_bitmap_size_ =
- gfx::Size(source_bitmap_.width(), source_bitmap_.height());
- }
-
- void TearDown() override {
- DeleteSourceFramebuffer();
- DeleteSourceTexture();
- copier_.reset();
- texture_deleter_.reset();
- }
-
- gpu::gles2::GLES2Interface* gl() { return gl_; }
-
- GLRendererCopier* copier() { return copier_.get(); }
-
- gfx::Rect DrawToWindowSpace(const gfx::Size& source_size,
- const gfx::Rect& draw_rect) {
- gfx::Rect window_rect = draw_rect;
- if (flipped_source_)
- window_rect.set_y(source_size.height() - window_rect.bottom());
- return window_rect;
- }
-
- GLuint CreateSourceTexture(SkBitmap source_bitmap) {
- CHECK_EQ(0u, source_texture_);
- gl_->GenTextures(1, &source_texture_);
- gl_->BindTexture(GL_TEXTURE_2D, source_texture_);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- gl_->TexImage2D(GL_TEXTURE_2D, 0, source_gl_format_, source_bitmap.width(),
- source_bitmap.height(), 0, source_gl_format_,
- GL_UNSIGNED_BYTE,
- CreateGLPixelsFromSkBitmap(source_bitmap, source_gl_format_,
- flipped_source_)
- .get());
- gl_->BindTexture(GL_TEXTURE_2D, 0);
- return source_texture_;
- }
-
- void DeleteSourceTexture() {
- if (source_texture_ != 0) {
- gl_->DeleteTextures(1, &source_texture_);
- source_texture_ = 0;
- }
- }
-
- void CreateAndBindSourceFramebuffer(GLuint texture) {
- ASSERT_EQ(0u, source_framebuffer_);
- gl_->GenFramebuffers(1, &source_framebuffer_);
- gl_->BindFramebuffer(GL_FRAMEBUFFER, source_framebuffer_);
- gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture, 0);
- }
-
- void DeleteSourceFramebuffer() {
- if (source_framebuffer_ != 0) {
- gl_->DeleteFramebuffers(1, &source_framebuffer_);
- source_framebuffer_ = 0;
- }
- }
-
- protected:
- GLenum source_gl_format_ = GL_RGBA;
- bool have_source_texture_ = false;
- CopyOutputResult::Destination result_destination_;
- bool scale_by_half_;
- bool flipped_source_ = false;
- bool use_odd_offset_;
- SkBitmap source_bitmap_;
- gfx::Size source_bitmap_size_;
-
- private:
- gpu::gles2::GLES2Interface* gl_ = nullptr;
- std::unique_ptr<TextureDeleter> texture_deleter_;
- std::unique_ptr<GLRendererCopier> copier_;
- GLuint source_texture_ = 0;
- GLuint source_framebuffer_ = 0;
-};
-
-TEST_P(GLRendererCopierDimensionsPixelTest, ExecutesCopyRequestNV12) {
- if (result_destination_ ==
- CopyOutputRequest::ResultDestination::kNativeTextures) {
- // TODO(https://crbug.com/1216287): Enable once textures are supported.
- GTEST_SKIP() << "Enable once the NV12 format supports producing results to "
- "a texture.";
- }
-
- // Result should contain 1px green strip at the beginning if the offset is
- // supposed to be odd.
- const gfx::Rect request_area = [this]() {
- // Capture 2x2 or 4x4 blue strip fragment, depending on scaling.
- gfx::Rect result =
- scale_by_half_ ? gfx::Rect(4, 0, 2, 2) : gfx::Rect(8, 0, 4, 4);
-
- // If we are supposed to ask for a rect with odd offset,
- // make sure that we capture 1 green pixel.
- if (use_odd_offset_) {
- result.set_x(result.x() - 1);
- }
-
- return result;
- }();
-
- // Create and execute a CopyOutputRequest via the GLRendererCopier.
- std::unique_ptr<CopyOutputResult> result;
- {
- base::RunLoop loop;
- auto request = std::make_unique<CopyOutputRequest>(
- CopyOutputRequest::ResultFormat::NV12_PLANES, result_destination_,
- base::BindOnce(
- [](std::unique_ptr<CopyOutputResult>* result,
- base::OnceClosure quit_closure,
- std::unique_ptr<CopyOutputResult> result_from_copier) {
- *result = std::move(result_from_copier);
- std::move(quit_closure).Run();
- },
- &result, loop.QuitClosure()));
-
- if (scale_by_half_) {
- request->SetUniformScaleRatio(2, 1);
- }
-
- request->set_result_selection(gfx::Rect(request_area));
-
- // Upload source texture to GL:
- const GLuint source_texture = CreateSourceTexture(source_bitmap_);
- CreateAndBindSourceFramebuffer(source_texture);
-
- copy_output::RenderPassGeometry geometry;
- // geometry.result_bounds not used by GLRendererCopier
- geometry.sampling_bounds =
- DrawToWindowSpace(source_bitmap_size_, gfx::Rect(source_bitmap_size_));
- geometry.result_selection = request->result_selection();
- geometry.readback_offset =
- DrawToWindowSpace(source_bitmap_size_, geometry.result_selection)
- .OffsetFromOrigin();
-
- copier()->CopyFromTextureOrFramebuffer(
- std::move(request), geometry, source_gl_format_,
- have_source_texture_ ? source_texture : 0, source_bitmap_size_,
- flipped_source_, gfx::ColorSpace::CreateSRGB());
- loop.Run();
- }
-
- // Check that a result was produced and is of the expected rect/size.
- ASSERT_TRUE(result);
- ASSERT_FALSE(result->IsEmpty());
- ASSERT_EQ(request_area, result->rect());
-
- const auto luma_nbytes = copy_output::GetLumaPlaneSize(*result);
- const auto luma_stride = copy_output::GetLumaPlaneStride(*result);
-
- const auto chroma_nbytes = copy_output::GetChromaPlaneSize(*result);
- const auto chroma_stride = copy_output::GetChromaPlaneStride(*result);
-
- std::unique_ptr<uint8_t[]> luma_plane =
- std::make_unique<uint8_t[]>(luma_nbytes);
- std::unique_ptr<uint8_t[]> chroma_planes =
- std::make_unique<uint8_t[]>(chroma_nbytes);
-
- // Examine the image in the |result|, and compare it to the baseline.
- if (result_destination_ == CopyOutputResult::Destination::kSystemMemory) {
- result->ReadNV12Planes(luma_plane.get(), luma_stride, chroma_planes.get(),
- chroma_stride);
- } else {
- LOG(ERROR) << "Texture results for NV12 are not supported yet!";
- ADD_FAILURE();
- }
-
- SkBitmap source_bitmap_yuv = source_bitmap_;
- GLScalerTestUtil::ConvertRGBABitmapToYUV(&source_bitmap_yuv);
-
- // We've asked for a region that starts with one green pixel that is followed
- // by all blue pixels, grab the source colors after they have been converted
- // to YUV to have something to validate against:
- SkColor green_yuv = source_bitmap_yuv.getColor(4, 0);
- SkColor blue_yuv = source_bitmap_yuv.getColor(8, 0);
-
- // Validate first row of luma (first color channel):
- for (int col = 0; col < luma_stride; ++col) {
- if (col == 0 && use_odd_offset_) {
- EXPECT_NEAR(luma_plane[col], SkColorGetR(green_yuv), GetTolerance());
- continue;
- }
-
- EXPECT_NEAR(luma_plane[col], SkColorGetR(blue_yuv), GetTolerance());
- }
-
- // All other luma rows must match the first row:
- ValidateRows(luma_plane.get(), luma_stride, result->rect().height());
-
- // Validate first row of chroma (second and third color channel):
- for (int col = 0; col < chroma_stride; col += 2) {
- if (col == 0 && use_odd_offset_) {
- EXPECT_NEAR(chroma_planes[col], SkColorGetG(green_yuv), GetTolerance());
- EXPECT_NEAR(chroma_planes[col + 1], SkColorGetB(green_yuv),
- GetTolerance());
- continue;
- }
-
- EXPECT_NEAR(chroma_planes[col], SkColorGetG(blue_yuv), GetTolerance());
- EXPECT_NEAR(chroma_planes[col + 1], SkColorGetB(blue_yuv), GetTolerance());
- }
-
- // All other chroma rows must match the first row:
- ValidateRows(chroma_planes.get(), chroma_stride,
- (result->rect().height() + 1) / 2);
-}
-
-TEST_P(GLRendererCopierDimensionsPixelTest, ExecutesCopyRequestI420) {
- if (result_destination_ ==
- CopyOutputRequest::ResultDestination::kNativeTextures) {
- // TODO(https://crbug.com/1216287): Enable once textures are supported.
- GTEST_SKIP() << "Enable once the I420 format supports producing results to "
- "a texture.";
- }
-
- // Result should contain 1px green strip at the beginning if the offset is
- // supposed to be odd.
- const gfx::Rect request_area = [this]() {
- // Capture 2x2 or 4x4 blue strip fragment, depending on scaling.
- gfx::Rect result =
- scale_by_half_ ? gfx::Rect(4, 0, 2, 2) : gfx::Rect(8, 0, 4, 4);
-
- // If we are supposed to ask for a rect with odd offset,
- // make sure that we capture 1 green pixel.
- if (use_odd_offset_) {
- result.set_x(result.x() - 1);
- }
-
- return result;
- }();
-
- // Create and execute a CopyOutputRequest via the GLRendererCopier.
- std::unique_ptr<CopyOutputResult> result;
- {
- base::RunLoop loop;
- auto request = std::make_unique<CopyOutputRequest>(
- CopyOutputRequest::ResultFormat::I420_PLANES, result_destination_,
- base::BindOnce(
- [](std::unique_ptr<CopyOutputResult>* result,
- base::OnceClosure quit_closure,
- std::unique_ptr<CopyOutputResult> result_from_copier) {
- *result = std::move(result_from_copier);
- std::move(quit_closure).Run();
- },
- &result, loop.QuitClosure()));
-
- if (scale_by_half_) {
- request->SetUniformScaleRatio(2, 1);
- }
-
- request->set_result_selection(gfx::Rect(request_area));
-
- // Upload source texture to GL:
- const GLuint source_texture = CreateSourceTexture(source_bitmap_);
- CreateAndBindSourceFramebuffer(source_texture);
-
- copy_output::RenderPassGeometry geometry;
- // geometry.result_bounds not used by GLRendererCopier
- geometry.sampling_bounds =
- DrawToWindowSpace(source_bitmap_size_, gfx::Rect(source_bitmap_size_));
- geometry.result_selection = request->result_selection();
- geometry.readback_offset =
- DrawToWindowSpace(source_bitmap_size_, geometry.result_selection)
- .OffsetFromOrigin();
-
- copier()->CopyFromTextureOrFramebuffer(
- std::move(request), geometry, source_gl_format_,
- have_source_texture_ ? source_texture : 0, source_bitmap_size_,
- flipped_source_, gfx::ColorSpace::CreateSRGB());
- loop.Run();
- }
-
- // Check that a result was produced and is of the expected rect/size.
- ASSERT_TRUE(result);
- ASSERT_FALSE(result->IsEmpty());
- ASSERT_EQ(request_area, result->rect());
-
- // Examine the image in the |result|, and compare it to the baseline PNG file.
-
- const auto luma_nbytes = copy_output::GetLumaPlaneSize(*result);
- const auto luma_stride = copy_output::GetLumaPlaneStride(*result);
-
- const auto chroma_nbytes = copy_output::GetChromaPlaneSize(*result);
- const auto chroma_stride = copy_output::GetChromaPlaneStride(*result);
-
- std::unique_ptr<uint8_t[]> luma_plane =
- std::make_unique<uint8_t[]>(luma_nbytes);
- std::unique_ptr<uint8_t[]> chroma_plane_1 =
- std::make_unique<uint8_t[]>(chroma_nbytes);
- std::unique_ptr<uint8_t[]> chroma_plane_2 =
- std::make_unique<uint8_t[]>(chroma_nbytes);
-
- if (result_destination_ == CopyOutputResult::Destination::kSystemMemory) {
- result->ReadI420Planes(luma_plane.get(), luma_stride, chroma_plane_1.get(),
- chroma_stride, chroma_plane_2.get(), chroma_stride);
- } else {
- LOG(ERROR) << "Texture results for I420 are not supported yet!";
- ADD_FAILURE();
- }
-
- SkBitmap source_bitmap_yuv = source_bitmap_;
- GLScalerTestUtil::ConvertRGBABitmapToYUV(&source_bitmap_yuv);
-
- // We've asked for a region that starts with one green pixel that is followed
- // by all blue pixels, validate:
- SkColor green_yuv = source_bitmap_yuv.getColor(7, 0);
- SkColor blue_yuv = source_bitmap_yuv.getColor(8, 0);
-
- // Validate first row of luma (first channel):
- for (int col = 0; col < luma_stride; ++col) {
- if (col == 0 && use_odd_offset_) {
- EXPECT_NEAR(luma_plane[col], SkColorGetR(green_yuv), GetTolerance());
- continue;
- }
-
- EXPECT_NEAR(luma_plane[col], SkColorGetR(blue_yuv), GetTolerance());
- }
-
- // All other luma rows must match the first row:
- ValidateRows(luma_plane.get(), luma_stride, result->rect().height());
-
- // Validate first row of chroma_1 (second channel):
- for (int col = 0; col < chroma_stride; ++col) {
- if (col == 0 && use_odd_offset_) {
- EXPECT_NEAR(chroma_plane_1[col], SkColorGetG(green_yuv), GetTolerance());
- continue;
- }
-
- EXPECT_NEAR(chroma_plane_1[col], SkColorGetG(blue_yuv), GetTolerance());
- }
-
- // All other chroma_1 rows must match the first row:
- ValidateRows(chroma_plane_1.get(), chroma_stride,
- (result->rect().height() + 1) / 2);
-
- // Validate first row of chroma_2 (third channel):
- for (int col = 0; col < chroma_stride; ++col) {
- if (col == 0 && use_odd_offset_) {
- EXPECT_NEAR(chroma_plane_2[col], SkColorGetB(green_yuv), GetTolerance());
- continue;
- }
-
- EXPECT_NEAR(chroma_plane_2[col], SkColorGetB(blue_yuv), GetTolerance());
- }
-
- // All other chroma_2 rows must match the first row:
- ValidateRows(chroma_plane_2.get(), chroma_stride,
- (result->rect().height() + 1) / 2);
-}
-
-// Instantiate parameter sets for all possible combinations of scenarios
-// GLRendererCopier will encounter, which will cause it to follow different
-// workflows.
-INSTANTIATE_TEST_SUITE_P(
- All,
- GLRendererCopierPixelTest,
- testing::Combine(
- // Source framebuffer GL format.
- testing::Values(static_cast<GLenum>(GL_RGBA),
- static_cast<GLenum>(GL_RGB)),
- // Source: Have texture too?
- testing::Values(false, true),
- // Result destination.
- testing::Values(CopyOutputResult::Destination::kSystemMemory,
- CopyOutputResult::Destination::kNativeTextures),
- // Result scaling: Scale by half?
- testing::Values(false, true),
- // Source content is vertically flipped?
- testing::Values(false, true)));
-
-// Instantiate parameter sets for all possible combinations of scenarios
-// GLRendererCopier will encounter, which will cause it to follow different
-// workflows.
-INSTANTIATE_TEST_SUITE_P(
- All,
- GLRendererCopierDimensionsPixelTest,
- testing::Combine(
- // Result destination.
- testing::Values(CopyOutputResult::Destination::kSystemMemory,
- CopyOutputResult::Destination::kNativeTextures),
- // Result scaling: Scale by half?
- testing::Values(false, true),
- // Use odd offset?
- testing::Values(false, true)));
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc b/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
deleted file mode 100644
index 8ff8bca30b9..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/gl_renderer_copier.h"
-
-#include <stdint.h>
-
-#include <iterator>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/run_loop.h"
-#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/common/frame_sinks/copy_output_util.h"
-#include "components/viz/test/test_context_provider.h"
-#include "components/viz/test/test_gles2_interface.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/vector2d.h"
-
-namespace viz {
-
-namespace {
-
-class CopierTestGLES2Interface : public TestGLES2Interface {
- public:
- // Sets how GL will respond to queries regarding the implementation's internal
- // read-back format.
- void SetOptimalReadbackFormat(GLenum format, GLenum type) {
- format_ = format;
- type_ = type;
- }
-
- // GLES2Interface override.
- void GetIntegerv(GLenum pname, GLint* params) override {
- switch (pname) {
- case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
- ASSERT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
- CheckFramebufferStatus(GL_FRAMEBUFFER));
- params[0] = format_;
- break;
- case GL_IMPLEMENTATION_COLOR_READ_TYPE:
- ASSERT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
- CheckFramebufferStatus(GL_FRAMEBUFFER));
- params[0] = type_;
- break;
- default:
- TestGLES2Interface::GetIntegerv(pname, params);
- break;
- }
- }
-
- private:
- GLenum format_ = 0;
- GLenum type_ = 0;
-};
-
-} // namespace
-
-class GLRendererCopierTest : public testing::Test {
- public:
- using ReusableThings = GLRendererCopier::ReusableThings;
-
- void SetUp() override {
- context_provider_ = TestContextProvider::Create(
- std::make_unique<CopierTestGLES2Interface>());
- context_provider_->BindToCurrentThread();
- copier_ =
- std::make_unique<GLRendererCopier>(context_provider_.get(), nullptr);
- }
-
- void TearDown() override { copier_.reset(); }
-
- GLRendererCopier* copier() const { return copier_.get(); }
-
- CopierTestGLES2Interface* test_gl() const {
- return static_cast<CopierTestGLES2Interface*>(
- copier_->context_provider_->ContextGL());
- }
-
- // These simply forward method calls to GLRendererCopier.
- std::unique_ptr<ReusableThings> TakeReusableThingsOrCreate(
- const base::UnguessableToken& requester) {
- return copier_->TakeReusableThingsOrCreate(requester);
- }
- void StashReusableThingsOrDelete(const base::UnguessableToken& requester,
- std::unique_ptr<ReusableThings> things) {
- return copier_->StashReusableThingsOrDelete(requester, std::move(things));
- }
- ReusableThings* PeekReusableThings(const base::UnguessableToken& requester) {
- const auto it = copier_->cache_.find(requester);
- if (it == copier_->cache_.end())
- return nullptr;
- return it->second.get();
- }
- size_t GetCopierCacheSize() { return copier_->cache_.size(); }
- void FreeUnusedCachedResources() { copier_->FreeUnusedCachedResources(); }
- GLenum GetOptimalReadbackFormat() const {
- return copier_->GetOptimalReadbackFormat();
- }
-
- static constexpr int kKeepalivePeriod = GLRendererCopier::kKeepalivePeriod;
-
- private:
- scoped_refptr<ContextProvider> context_provider_;
- std::unique_ptr<GLRendererCopier> copier_;
-};
-
-// Tests that named objects, such as textures or framebuffers, are only cached
-// when the CopyOutputRequest has specified a "source" of requests.
-TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
- // With no source set in a copy request, expect to never re-use any textures
- // or framebuffers.
- const base::UnguessableToken no_source;
- EXPECT_EQ(0u, GetCopierCacheSize());
- auto things = TakeReusableThingsOrCreate(no_source);
- EXPECT_TRUE(things);
- StashReusableThingsOrDelete(no_source, std::move(things));
- EXPECT_EQ(nullptr, PeekReusableThings(no_source));
- EXPECT_EQ(0u, GetCopierCacheSize());
-
- // With a source set in the request, objects should now be cached and re-used.
- const auto source = base::UnguessableToken::Create();
- things = TakeReusableThingsOrCreate(source);
- ReusableThings* things_raw_ptr = things.get();
- EXPECT_TRUE(things_raw_ptr);
- StashReusableThingsOrDelete(source, std::move(things));
- EXPECT_EQ(things_raw_ptr, PeekReusableThings(source));
- EXPECT_EQ(1u, GetCopierCacheSize());
-
- // A second, separate source gets its own cache entry.
- const auto source2 = base::UnguessableToken::Create();
- things = TakeReusableThingsOrCreate(source2);
- things_raw_ptr = things.get();
- EXPECT_TRUE(things_raw_ptr);
- EXPECT_EQ(1u, GetCopierCacheSize());
- StashReusableThingsOrDelete(source2, std::move(things));
- EXPECT_EQ(things_raw_ptr, PeekReusableThings(source2));
- EXPECT_EQ(2u, GetCopierCacheSize());
-}
-
-// Tests that cached resources are freed if unused for a while.
-TEST_F(GLRendererCopierTest, FreesUnusedResources) {
- // Take and then stash a ReusableThings instance for a valid source.
- const base::UnguessableToken source = base::UnguessableToken::Create();
- EXPECT_EQ(0u, GetCopierCacheSize());
- StashReusableThingsOrDelete(source, TakeReusableThingsOrCreate(source));
- EXPECT_TRUE(PeekReusableThings(source));
- EXPECT_EQ(1u, GetCopierCacheSize());
-
- // Call FreesUnusedCachedResources() the maximum number of times before the
- // cache entry would be considered for freeing.
- for (int i = 0; i < kKeepalivePeriod - 1; ++i) {
- FreeUnusedCachedResources();
- EXPECT_TRUE(PeekReusableThings(source));
- EXPECT_EQ(1u, GetCopierCacheSize());
- if (HasFailure())
- break;
- }
-
- // Calling FreeUnusedCachedResources() just one more time should cause the
- // cache entry to be freed.
- FreeUnusedCachedResources();
- EXPECT_FALSE(PeekReusableThings(source));
- EXPECT_EQ(0u, GetCopierCacheSize());
-}
-
-TEST_F(GLRendererCopierTest, DetectsBGRAForReadbackFormat) {
- test_gl()->SetOptimalReadbackFormat(GL_BGRA_EXT, GL_UNSIGNED_BYTE);
- EXPECT_EQ(static_cast<GLenum>(GL_BGRA_EXT), GetOptimalReadbackFormat());
-}
-
-TEST_F(GLRendererCopierTest, DetectsRGBAForReadbackFormat) {
- test_gl()->SetOptimalReadbackFormat(GL_RGBA, GL_UNSIGNED_BYTE);
- EXPECT_EQ(static_cast<GLenum>(GL_RGBA), GetOptimalReadbackFormat());
-}
-
-TEST_F(GLRendererCopierTest, FallsBackOnRGBAForReadbackFormat_BadFormat) {
- test_gl()->SetOptimalReadbackFormat(GL_RGB, GL_UNSIGNED_BYTE);
- EXPECT_EQ(static_cast<GLenum>(GL_RGBA), GetOptimalReadbackFormat());
-}
-
-TEST_F(GLRendererCopierTest, FallsBackOnRGBAForReadbackFormat_BadType) {
- test_gl()->SetOptimalReadbackFormat(GL_BGRA_EXT, GL_UNSIGNED_SHORT);
- EXPECT_EQ(static_cast<GLenum>(GL_RGBA), GetOptimalReadbackFormat());
-}
-
-// Tests that copying from a source with a color space that can't be converted
-// to a SkColorSpace will fallback to a transform to sRGB.
-TEST_F(GLRendererCopierTest, FallsBackToSRGBForInvalidSkColorSpaces) {
- std::unique_ptr<CopyOutputResult> result;
- base::RunLoop loop;
- auto request = std::make_unique<CopyOutputRequest>(
- CopyOutputRequest::ResultFormat::RGBA,
- CopyOutputRequest::ResultDestination::kSystemMemory,
- base::BindOnce(
- [](std::unique_ptr<CopyOutputResult>* result_out,
- base::OnceClosure quit_closure,
- std::unique_ptr<CopyOutputResult> result_from_copier) {
- *result_out = std::move(result_from_copier);
- std::move(quit_closure).Run();
- },
- &result, loop.QuitClosure()));
- gfx::Rect bounds(50, 50);
- copy_output::RenderPassGeometry geometry;
- geometry.result_bounds = bounds;
- geometry.result_selection = bounds;
- geometry.sampling_bounds = bounds;
- gfx::ColorSpace hdr_color_space = gfx::ColorSpace::CreatePiecewiseHDR(
- gfx::ColorSpace::PrimaryID::BT2020, 0.5, 1.5);
-
- copier()->CopyFromTextureOrFramebuffer(std::move(request), geometry, GL_RGBA,
- 0, gfx::Size(50, 50), false, hdr_color_space);
- loop.Run();
-
- auto scoped_bitmap = result->ScopedAccessSkBitmap();
- SkBitmap result_bitmap = scoped_bitmap.bitmap();
- ASSERT_NE(nullptr, result_bitmap.colorSpace());
- EXPECT_TRUE(result_bitmap.colorSpace()->isSRGB());
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer_draw_cache.cc b/chromium/components/viz/service/display/gl_renderer_draw_cache.cc
deleted file mode 100644
index 887eec8c2af..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_draw_cache.cc
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/gl_renderer_draw_cache.h"
-
-namespace viz {
-
-TexturedQuadDrawCache::TexturedQuadDrawCache() = default;
-
-TexturedQuadDrawCache::~TexturedQuadDrawCache() = default;
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/gl_renderer_draw_cache.h b/chromium/components/viz/service/display/gl_renderer_draw_cache.h
deleted file mode 100644
index eb85528501d..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_draw_cache.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_DRAW_CACHE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_DRAW_CACHE_H_
-
-#include <vector>
-
-#include "components/viz/common/resources/resource_id.h"
-#include "components/viz/service/display/program_binding.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/mask_filter_info.h"
-
-namespace viz {
-
-// Collects 4 floats at a time for easy upload to GL.
-struct Float4 {
- float data[4];
-};
-
-// Collects 16 floats at a time for easy upload to GL.
-struct Float16 {
- float data[16];
-};
-
-// A cache for storing textured quads to be drawn. Stores the minimum required
-// data to tell if two back to back draws only differ in their transform. Quads
-// that only differ by transform may be coalesced into a single draw call.
-struct TexturedQuadDrawCache {
- TexturedQuadDrawCache();
-
- TexturedQuadDrawCache(const TexturedQuadDrawCache&) = delete;
- TexturedQuadDrawCache& operator=(const TexturedQuadDrawCache&) = delete;
-
- ~TexturedQuadDrawCache();
-
- bool is_empty = true;
-
- // Values tracked to determine if textured quads may be coalesced.
- ProgramKey program_key;
- ResourceId resource_id = kInvalidResourceId;
- bool needs_blending = false;
- bool nearest_neighbor = false;
- SkColor background_color = 0;
- gfx::MaskFilterInfo mask_filter_info;
-
- // A cache for the coalesced quad data.
- std::vector<Float4> uv_xform_data;
- std::vector<float> vertex_opacity_data;
- std::vector<Float16> matrix_data;
-
- // Don't batch if tex clamp rect is given.
- Float4 tex_clamp_rect_data;
-
- // Video frames need special white level adjustment.
- bool is_video_frame = false;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_GL_RENDERER_DRAW_CACHE_H_
diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc
deleted file mode 100644
index 7981afdac9c..00000000000
--- a/chromium/components/viz/service/display/gl_renderer_unittest.cc
+++ /dev/null
@@ -1,5195 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/gl_renderer.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <set>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback_helpers.h"
-#include "base/containers/cxx20_erase.h"
-#include "base/location.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "cc/base/math_util.h"
-#include "cc/test/fake_impl_task_runner_provider.h"
-#include "cc/test/fake_layer_tree_host_impl.h"
-#include "cc/test/fake_output_surface_client.h"
-#include "cc/test/pixel_test.h"
-#include "cc/test/render_pass_test_utils.h"
-#include "cc/test/resource_provider_test_utils.h"
-#include "components/viz/client/client_resource_provider.h"
-#include "components/viz/common/display/renderer_settings.h"
-#include "components/viz/common/features.h"
-#include "components/viz/common/frame_sinks/copy_output_request.h"
-#include "components/viz/common/frame_sinks/copy_output_result.h"
-#include "components/viz/common/quads/texture_draw_quad.h"
-#include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/resources/transferable_resource.h"
-#include "components/viz/service/display/display_resource_provider_gl.h"
-#include "components/viz/test/fake_output_surface.h"
-#include "components/viz/test/test_gles2_interface.h"
-#include "components/viz/test/viz_test_suite.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/config/gpu_finch_features.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkMatrix.h"
-#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
-#include "ui/base/ui_base_features.h"
-#include "ui/gfx/color_transform.h"
-#include "ui/gfx/geometry/transform.h"
-#include "ui/latency/latency_info.h"
-
-#if BUILDFLAG(IS_WIN)
-#include "components/viz/service/display/overlay_processor_win.h"
-#elif BUILDFLAG(IS_APPLE)
-#include "components/viz/service/display/overlay_processor_mac.h"
-#elif BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
-#include "components/viz/service/display/overlay_processor_strategy.h"
-#include "components/viz/service/display/overlay_processor_using_strategy.h"
-#include "components/viz/service/display/overlay_strategy_single_on_top.h"
-#include "components/viz/service/display/overlay_strategy_underlay.h"
-#else // Default
-#include "components/viz/service/display/overlay_processor_stub.h"
-#endif
-
-using testing::_;
-using testing::AnyNumber;
-using testing::Args;
-using testing::AtLeast;
-using testing::Contains;
-using testing::ElementsAre;
-using testing::Expectation;
-using testing::InSequence;
-using testing::Invoke;
-using testing::Mock;
-using testing::Not;
-using testing::Pointee;
-using testing::Return;
-using testing::StrictMock;
-
-namespace viz {
-
-MATCHER_P(MatchesSyncToken, sync_token, "") {
- gpu::SyncToken other;
- memcpy(&other, arg, sizeof(other));
- return other == sync_token;
-}
-
-class GLRendererTest : public testing::Test {
- protected:
- ~GLRendererTest() override {
- // Some tests create CopyOutputRequests which will PostTask ensure
- // they are all cleaned up and completed before destroying the test.
- VizTestSuite::RunUntilIdle();
- }
- AggregatedRenderPass* root_render_pass() {
- return render_passes_in_draw_order_.back().get();
- }
- void DrawFrame(GLRenderer* renderer,
- const gfx::Size& viewport_size,
- const gfx::DisplayColorSpaces& display_color_spaces =
- gfx::DisplayColorSpaces()) {
- SurfaceDamageRectList surface_damage_rect_list;
- renderer->DrawFrame(&render_passes_in_draw_order_, 1.f, viewport_size,
- display_color_spaces,
- std::move(surface_damage_rect_list));
- }
-
- static const Program* current_program(GLRenderer* renderer) {
- return renderer->current_program_;
- }
-
- static TexCoordPrecision get_cached_tex_coord_precision(
- GLRenderer* renderer) {
- return renderer->draw_cache_.program_key.tex_coord_precision();
- }
-
- DebugRendererSettings debug_settings_;
- AggregatedRenderPassList render_passes_in_draw_order_;
-};
-
-#define EXPECT_PROGRAM_VALID(program_binding) \
- do { \
- ASSERT_TRUE(program_binding); \
- EXPECT_TRUE((program_binding)->program()); \
- EXPECT_TRUE((program_binding)->initialized()); \
- } while (false)
-
-static inline SkBlendMode BlendModeToSkXfermode(BlendMode blend_mode) {
- switch (blend_mode) {
- case BLEND_MODE_NONE:
- case BLEND_MODE_NORMAL:
- return SkBlendMode::kSrcOver;
- case BLEND_MODE_DESTINATION_IN:
- return SkBlendMode::kDstIn;
- case BLEND_MODE_SCREEN:
- return SkBlendMode::kScreen;
- case BLEND_MODE_OVERLAY:
- return SkBlendMode::kOverlay;
- case BLEND_MODE_DARKEN:
- return SkBlendMode::kDarken;
- case BLEND_MODE_LIGHTEN:
- return SkBlendMode::kLighten;
- case BLEND_MODE_COLOR_DODGE:
- return SkBlendMode::kColorDodge;
- case BLEND_MODE_COLOR_BURN:
- return SkBlendMode::kColorBurn;
- case BLEND_MODE_HARD_LIGHT:
- return SkBlendMode::kHardLight;
- case BLEND_MODE_SOFT_LIGHT:
- return SkBlendMode::kSoftLight;
- case BLEND_MODE_DIFFERENCE:
- return SkBlendMode::kDifference;
- case BLEND_MODE_EXCLUSION:
- return SkBlendMode::kExclusion;
- case BLEND_MODE_MULTIPLY:
- return SkBlendMode::kMultiply;
- case BLEND_MODE_HUE:
- return SkBlendMode::kHue;
- case BLEND_MODE_SATURATION:
- return SkBlendMode::kSaturation;
- case BLEND_MODE_COLOR:
- return SkBlendMode::kColor;
- case BLEND_MODE_LUMINOSITY:
- return SkBlendMode::kLuminosity;
- }
- return SkBlendMode::kSrcOver;
-}
-
-// Explicitly named to be a friend in GLRenderer for shader access.
-class GLRendererShaderPixelTest : public cc::PixelTest {
- public:
- void SetUp() override {
- SetUpGLRenderer(gfx::SurfaceOrigin::kBottomLeft);
- ASSERT_FALSE(renderer()->IsContextLost());
- }
-
- void TearDown() override {
- cc::PixelTest::TearDown();
- ASSERT_FALSE(renderer());
- }
-
- GLRenderer* renderer() { return static_cast<GLRenderer*>(renderer_.get()); }
-
- void TestShaderWithDrawingFrame(
- const ProgramKey& program_key,
- const DirectRenderer::DrawingFrame& drawing_frame,
- bool validate_output_color_matrix) {
- renderer()->SetCurrentFrameForTesting(drawing_frame);
- const gfx::ColorSpace kSrcColorSpaces[] = {
- gfx::ColorSpace::CreateSRGB(),
- gfx::ColorSpace(gfx::ColorSpace::PrimaryID::ADOBE_RGB,
- gfx::ColorSpace::TransferID::GAMMA28),
- gfx::ColorSpace::CreateREC709(),
- gfx::ColorSpace::CreateExtendedSRGB(),
- // This will be adjusted to the display's SDR white level, because no
- // level was specified.
- gfx::ColorSpace::CreateSCRGBLinear(),
- // This won't be, because it has a set SDR white level.
- gfx::ColorSpace::CreateSCRGBLinear(123.0f),
- // This will be adjusted to the display's SDR white level, because no
- // level was specified.
- gfx::ColorSpace::CreateHDR10(),
- // This won't be, because it has a set SDR white level.
- gfx::ColorSpace::CreateHDR10(123.0f),
- };
- const gfx::ColorSpace kDstColorSpaces[] = {
- gfx::ColorSpace::CreateSRGB(),
- gfx::ColorSpace(gfx::ColorSpace::PrimaryID::ADOBE_RGB,
- gfx::ColorSpace::TransferID::GAMMA18),
- gfx::ColorSpace::CreateExtendedSRGB(),
- gfx::ColorSpace::CreateSCRGBLinear(),
- };
- // Note: Use ASSERT_XXX() and not EXPECT_XXX() below since the size of the
- // loop will lead to useless timeout failures on the bots otherwise.
- for (const auto& src_color_space : kSrcColorSpaces) {
- for (const auto& dst_color_space : kDstColorSpaces) {
- renderer()->SetUseProgram(program_key, src_color_space, dst_color_space,
- /*adjust_src_white_level=*/true);
- ASSERT_TRUE(renderer()->current_program_->initialized());
-
- if (src_color_space != dst_color_space) {
- auto adjusted_color_space = src_color_space;
- if (src_color_space.IsHDR()) {
- adjusted_color_space = src_color_space.GetWithSDRWhiteLevel(
- drawing_frame.display_color_spaces.GetSDRMaxLuminanceNits());
- }
- SCOPED_TRACE(
- base::StringPrintf("adjusted_color_space=%s, dst_color_space=%s",
- adjusted_color_space.ToString().c_str(),
- dst_color_space.ToString().c_str()));
-
- gfx::ColorTransform::Options options;
- options.tone_map_pq_and_hlg_to_sdr = !dst_color_space.IsHDR();
- options.sdr_max_luminance_nits =
- drawing_frame.display_color_spaces.GetSDRMaxLuminanceNits();
- auto color_transform = gfx::ColorTransform::NewColorTransform(
- adjusted_color_space, dst_color_space, options);
-
- ASSERT_EQ(color_transform->GetShaderSource(),
- renderer()
- ->current_program_->color_transform_for_testing()
- ->GetShaderSource());
- }
-
- if (validate_output_color_matrix) {
- if (program_key.type() == ProgramType::PROGRAM_TYPE_SOLID_COLOR) {
- ASSERT_EQ(
- -1,
- renderer()->current_program_->output_color_matrix_location());
- } else {
- ASSERT_NE(
- -1,
- renderer()->current_program_->output_color_matrix_location());
- }
- }
- }
- }
- }
-
- void TestShader(const ProgramKey& program_key) {
- TestShaderWithDrawingFrame(program_key, GLRenderer::DrawingFrame(), false);
- }
-
- void TestShadersWithOutputColorMatrix(const ProgramKey& program_key) {
- GLRenderer::DrawingFrame frame;
-
- AggregatedRenderPassList render_passes_in_draw_order;
- gfx::Size viewport_size(100, 100);
- AggregatedRenderPassId root_pass_id{1};
- auto* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
-
- frame.root_render_pass = root_pass;
- frame.current_render_pass = root_pass;
- frame.render_passes_in_draw_order = &render_passes_in_draw_order;
-
- // Set a non-identity color matrix on the output surface.
- SkM44 color_matrix;
- color_matrix.setRC(0, 0, 0.7f);
- color_matrix.setRC(1, 1, 0.4f);
- color_matrix.setRC(2, 2, 0.5f);
- renderer()->output_surface_->set_color_matrix(color_matrix);
-
- TestShaderWithDrawingFrame(program_key, frame, true);
- }
-
- void TestShadersWithSDRWhiteLevel(const ProgramKey& program_key,
- float sdr_white_level) {
- GLRenderer::DrawingFrame frame;
- frame.display_color_spaces.SetSDRMaxLuminanceNits(sdr_white_level);
- TestShaderWithDrawingFrame(program_key, frame, false);
- }
-
- void TestBasicShaders() {
- TestShader(ProgramKey::DebugBorder());
- TestShader(ProgramKey::SolidColor(NO_AA, false, false));
- TestShader(ProgramKey::SolidColor(USE_AA, false, false));
- TestShader(ProgramKey::SolidColor(NO_AA, true, false));
-
- TestShadersWithOutputColorMatrix(ProgramKey::DebugBorder());
- TestShadersWithOutputColorMatrix(
- ProgramKey::SolidColor(NO_AA, false, false));
- TestShadersWithOutputColorMatrix(
- ProgramKey::SolidColor(USE_AA, false, false));
- TestShadersWithOutputColorMatrix(
- ProgramKey::SolidColor(NO_AA, true, false));
-
- TestShadersWithSDRWhiteLevel(ProgramKey::DebugBorder(), 200.f);
- TestShadersWithSDRWhiteLevel(ProgramKey::SolidColor(NO_AA, false, false),
- 200.f);
- TestShadersWithSDRWhiteLevel(ProgramKey::SolidColor(USE_AA, false, false),
- 200.f);
- TestShadersWithSDRWhiteLevel(ProgramKey::SolidColor(NO_AA, true, false),
- 200.f);
- }
-
- void TestColorShaders() {
- const size_t kNumTransferFns = 7;
- skcms_TransferFunction transfer_fns[kNumTransferFns] = {
- // The identity.
- {1.f, 1.f, 0.f, 1.f, 0.f, 0.f, 0.f},
- // The identity, with an if statement.
- {1.f, 1.f, 0.f, 1.f, 0.5f, 0.f, 0.f},
- // Just the power function.
- {1.1f, 1.f, 0.f, 1.f, 0.f, 0.f, 0.f},
- // Everything but the power function, nonlinear only.
- {1.f, 0.9f, 0.1f, 0.9f, 0.f, 0.1f, 0.1f},
- // Everything, nonlinear only.
- {1.1f, 0.9f, 0.1f, 0.9f, 0.f, 0.1f, 0.1f},
- // Everything but the power function.
- {1.f, 0.9f, 0.1f, 0.9f, 0.5f, 0.1f, 0.1f},
- // Everything.
- {1.1f, 0.9f, 0.1f, 0.9f, 0.5f, 0.1f, 0.1f},
- };
-
- for (size_t i = 0; i < kNumTransferFns; ++i) {
- skcms_Matrix3x3 primaries;
- gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&primaries);
- gfx::ColorSpace src =
- gfx::ColorSpace::CreateCustom(primaries, transfer_fns[i]);
-
- renderer()->SetCurrentFrameForTesting(GLRenderer::DrawingFrame());
- renderer()->SetUseProgram(ProgramKey::SolidColor(NO_AA, false, false),
- src, gfx::ColorSpace::CreateXYZD50());
- EXPECT_TRUE(renderer()->current_program_->initialized());
- }
- }
-
- void TestShadersWithPrecision(TexCoordPrecision precision) {
- // This program uses external textures and sampler, so it won't compile
- // everywhere.
- if (context_provider()->ContextCapabilities().egl_image_external) {
- TestShader(ProgramKey::VideoStream(precision, false));
- }
- }
-
- void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision,
- BlendMode blend_mode) {
- TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode,
- NO_AA, NO_MASK, false, false, false,
- false));
- TestShader(ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode,
- USE_AA, NO_MASK, false, false, false,
- false));
- }
-
- void TestShadersWithPrecisionAndSampler(
- TexCoordPrecision precision,
- SamplerType sampler,
- PremultipliedAlphaMode premultipliedAlpha,
- bool has_background_color,
- bool has_tex_clamp_rect) {
- TestShader(ProgramKey::Texture(precision, sampler, premultipliedAlpha,
- has_background_color, has_tex_clamp_rect,
- false, false));
- }
-
- void TestShadersWithPrecisionAndSamplerTiledAA(
- TexCoordPrecision precision,
- SamplerType sampler,
- PremultipliedAlphaMode premultipliedAlpha) {
- TestShader(ProgramKey::Tile(precision, sampler, USE_AA, premultipliedAlpha,
- false, false, false, false));
- }
-
- void TestShadersWithPrecisionAndSamplerTiled(
- TexCoordPrecision precision,
- SamplerType sampler,
- PremultipliedAlphaMode premultipliedAlpha,
- bool is_opaque,
- bool has_tex_clamp_rect) {
- TestShader(ProgramKey::Tile(precision, sampler, NO_AA, premultipliedAlpha,
- is_opaque, has_tex_clamp_rect, false, false));
- }
-
- void TestYUVShadersWithPrecisionAndSampler(TexCoordPrecision precision,
- SamplerType sampler) {
- // Iterate over alpha plane and nv12 parameters.
- UVTextureMode uv_modes[2] = {UV_TEXTURE_MODE_UV, UV_TEXTURE_MODE_U_V};
- YUVAlphaTextureMode a_modes[2] = {YUV_NO_ALPHA_TEXTURE,
- YUV_HAS_ALPHA_TEXTURE};
- for (auto uv_mode : uv_modes) {
- SCOPED_TRACE(uv_mode);
- for (auto a_mode : a_modes) {
- SCOPED_TRACE(a_mode);
- TestShader(ProgramKey::YUVVideo(precision, sampler, a_mode, uv_mode,
- false, false));
- }
- }
- }
-
- void TestShadersWithMasks(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode,
- bool mask_for_background) {
- TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA,
- HAS_MASK, mask_for_background, false,
- false, false));
- TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA,
- HAS_MASK, mask_for_background, true,
- false, false));
- TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA,
- HAS_MASK, mask_for_background, false,
- false, false));
- TestShader(ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA,
- HAS_MASK, mask_for_background, true,
- false, false));
- }
-};
-
-namespace {
-
-#if !BUILDFLAG(IS_ANDROID)
-static const TexCoordPrecision kPrecisionList[] = {TEX_COORD_PRECISION_MEDIUM,
- TEX_COORD_PRECISION_HIGH};
-
-static const BlendMode kBlendModeList[LAST_BLEND_MODE + 1] = {
- BLEND_MODE_NONE, BLEND_MODE_NORMAL, BLEND_MODE_DESTINATION_IN,
- BLEND_MODE_SCREEN, BLEND_MODE_OVERLAY, BLEND_MODE_DARKEN,
- BLEND_MODE_LIGHTEN, BLEND_MODE_COLOR_DODGE, BLEND_MODE_COLOR_BURN,
- BLEND_MODE_HARD_LIGHT, BLEND_MODE_SOFT_LIGHT, BLEND_MODE_DIFFERENCE,
- BLEND_MODE_EXCLUSION, BLEND_MODE_MULTIPLY, BLEND_MODE_HUE,
- BLEND_MODE_SATURATION, BLEND_MODE_COLOR, BLEND_MODE_LUMINOSITY,
-};
-
-static const SamplerType kSamplerList[] = {
- SAMPLER_TYPE_2D, SAMPLER_TYPE_2D_RECT, SAMPLER_TYPE_EXTERNAL_OES,
-};
-
-static const PremultipliedAlphaMode kPremultipliedAlphaModeList[] = {
- PREMULTIPLIED_ALPHA, NON_PREMULTIPLIED_ALPHA};
-
-TEST_F(GLRendererShaderPixelTest, BasicShadersCompile) {
- TestBasicShaders();
-}
-
-TEST_F(GLRendererShaderPixelTest, TestColorShadersCompile) {
- TestColorShaders();
-}
-
-class PrecisionShaderPixelTest
- : public GLRendererShaderPixelTest,
- public ::testing::WithParamInterface<TexCoordPrecision> {};
-
-TEST_P(PrecisionShaderPixelTest, ShadersCompile) {
- TestShadersWithPrecision(GetParam());
-}
-
-INSTANTIATE_TEST_SUITE_P(PrecisionShadersCompile,
- PrecisionShaderPixelTest,
- ::testing::ValuesIn(kPrecisionList));
-
-class PrecisionBlendShaderPixelTest
- : public GLRendererShaderPixelTest,
- public ::testing::WithParamInterface<
- std::tuple<TexCoordPrecision, BlendMode>> {};
-
-TEST_P(PrecisionBlendShaderPixelTest, ShadersCompile) {
- TestShadersWithPrecisionAndBlend(std::get<0>(GetParam()),
- std::get<1>(GetParam()));
-}
-
-INSTANTIATE_TEST_SUITE_P(
- PrecisionBlendShadersCompile,
- PrecisionBlendShaderPixelTest,
- ::testing::Combine(::testing::ValuesIn(kPrecisionList),
- ::testing::ValuesIn(kBlendModeList)));
-
-class PrecisionSamplerShaderPixelTest
- : public GLRendererShaderPixelTest,
- public ::testing::WithParamInterface<
- std::tuple<TexCoordPrecision,
- SamplerType,
- PremultipliedAlphaMode,
- bool, // has_background_color
- bool>> {}; // has_tex_clamp_rect
-
-TEST_P(PrecisionSamplerShaderPixelTest, ShadersCompile) {
- SamplerType sampler = std::get<1>(GetParam());
- if (sampler != SAMPLER_TYPE_2D_RECT ||
- context_provider()->ContextCapabilities().texture_rectangle) {
- TestShadersWithPrecisionAndSampler(
- std::get<0>(GetParam()), // TexCoordPrecision
- sampler,
- std::get<2>(GetParam()), // PremultipliedAlphaMode
- std::get<3>(GetParam()), // has_background_color
- std::get<4>(GetParam())); // has_tex_clamp_rect
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(
- PrecisionSamplerShadersCompile,
- PrecisionSamplerShaderPixelTest,
- ::testing::Combine(::testing::ValuesIn(kPrecisionList),
- ::testing::ValuesIn(kSamplerList),
- ::testing::ValuesIn(kPremultipliedAlphaModeList),
- ::testing::Bool(), // has_background_color
- ::testing::Bool())); // has_tex_clamp_rect
-
-class PrecisionSamplerShaderPixelTestTiled
- : public GLRendererShaderPixelTest,
- public ::testing::WithParamInterface<
- std::tuple<TexCoordPrecision,
- SamplerType,
- PremultipliedAlphaMode,
- bool, // is_opaque
- bool>> // has_tex_clamp_rect
-{};
-
-TEST_P(PrecisionSamplerShaderPixelTestTiled, ShadersCompile) {
- SamplerType sampler = std::get<1>(GetParam());
- if (sampler != SAMPLER_TYPE_2D_RECT ||
- context_provider()->ContextCapabilities().texture_rectangle) {
- TestShadersWithPrecisionAndSamplerTiled(
- std::get<0>(GetParam()), // TexCoordPrecision
- sampler,
- std::get<2>(GetParam()), // PremultipliedAlphaMode
- std::get<3>(GetParam()), // is_opaque
- std::get<4>(GetParam())); // has_tex_clamp_rect
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(
- PrecisionSamplerShadersCompile,
- PrecisionSamplerShaderPixelTestTiled,
- ::testing::Combine(::testing::ValuesIn(kPrecisionList),
- ::testing::ValuesIn(kSamplerList),
- ::testing::ValuesIn(kPremultipliedAlphaModeList),
- ::testing::Bool(), // is_opaque
- ::testing::Bool())); // has_tex_clamp_rect
-
-class PrecisionSamplerShaderPixelTestTiledAA
- : public GLRendererShaderPixelTest,
- public ::testing::WithParamInterface<
- std::tuple<TexCoordPrecision, SamplerType, PremultipliedAlphaMode>> {
-};
-
-TEST_P(PrecisionSamplerShaderPixelTestTiledAA, ShadersCompile) {
- SamplerType sampler = std::get<1>(GetParam());
- if (sampler != SAMPLER_TYPE_2D_RECT ||
- context_provider()->ContextCapabilities().texture_rectangle) {
- TestShadersWithPrecisionAndSamplerTiledAA(
- std::get<0>(GetParam()), // TexCoordPrecision
- sampler,
- std::get<2>(GetParam())); // PremultipliedAlphaMode
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(
- PrecisionSamplerShadersCompile,
- PrecisionSamplerShaderPixelTestTiledAA,
- ::testing::Combine(::testing::ValuesIn(kPrecisionList),
- ::testing::ValuesIn(kSamplerList),
- ::testing::ValuesIn(kPremultipliedAlphaModeList)));
-
-class PrecisionSamplerYUVShaderPixelTest
- : public GLRendererShaderPixelTest,
- public ::testing::WithParamInterface<
- std::tuple<TexCoordPrecision, SamplerType>> {};
-
-TEST_P(PrecisionSamplerYUVShaderPixelTest, ShadersCompile) {
- SamplerType sampler = std::get<1>(GetParam());
- if (sampler != SAMPLER_TYPE_2D_RECT ||
- context_provider()->ContextCapabilities().texture_rectangle) {
- TestYUVShadersWithPrecisionAndSampler(
- std::get<0>(GetParam()), // TexCoordPrecision
- sampler);
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(PrecisionSamplerShadersCompile,
- PrecisionSamplerYUVShaderPixelTest,
- ::testing::Combine(::testing::ValuesIn(kPrecisionList),
- ::testing::ValuesIn(kSamplerList)));
-
-class MaskShaderPixelTest
- : public GLRendererShaderPixelTest,
- public ::testing::WithParamInterface<
- std::tuple<TexCoordPrecision, SamplerType, BlendMode, bool>> {};
-
-TEST_P(MaskShaderPixelTest, ShadersCompile) {
- SamplerType sampler = std::get<1>(GetParam());
- if (sampler != SAMPLER_TYPE_2D_RECT ||
- context_provider()->ContextCapabilities().texture_rectangle) {
- TestShadersWithMasks(std::get<0>(GetParam()), sampler,
- std::get<2>(GetParam()), std::get<3>(GetParam()));
- }
-}
-
-INSTANTIATE_TEST_SUITE_P(MaskShadersCompile,
- MaskShaderPixelTest,
- ::testing::Combine(::testing::ValuesIn(kPrecisionList),
- ::testing::ValuesIn(kSamplerList),
- ::testing::ValuesIn(kBlendModeList),
- ::testing::Bool()));
-
-#endif
-
-class FakeRendererGL : public GLRenderer {
- public:
- FakeRendererGL(const RendererSettings* settings,
- const DebugRendererSettings* debug_settings,
- OutputSurface* output_surface,
- DisplayResourceProviderGL* resource_provider)
- : GLRenderer(settings,
- debug_settings,
- output_surface,
- resource_provider,
- nullptr,
- nullptr) {}
-
- FakeRendererGL(const RendererSettings* settings,
- const DebugRendererSettings* debug_settings,
- OutputSurface* output_surface,
- DisplayResourceProviderGL* resource_provider,
- OverlayProcessorInterface* overlay_processor)
- : GLRenderer(settings,
- debug_settings,
- output_surface,
- resource_provider,
- overlay_processor,
- nullptr) {}
-
- FakeRendererGL(
- const RendererSettings* settings,
- const DebugRendererSettings* debug_settings,
- OutputSurface* output_surface,
- DisplayResourceProviderGL* resource_provider,
- OverlayProcessorInterface* overlay_processor,
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner)
- : GLRenderer(settings,
- debug_settings,
- output_surface,
- resource_provider,
- overlay_processor,
- std::move(current_task_runner)) {}
-
- // GLRenderer methods.
-
- // Changing visibility to public.
- using GLRenderer::stencil_enabled;
-};
-
-class GLRendererWithDefaultHarnessTest : public GLRendererTest {
- protected:
- GLRendererWithDefaultHarnessTest() {
- output_surface_ = FakeOutputSurface::Create3d();
- output_surface_->BindToClient(&output_surface_client_);
-
- resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
- renderer_ = std::make_unique<FakeRendererGL>(&settings_, &debug_settings_,
- output_surface_.get(),
- resource_provider_.get());
- renderer_->Initialize();
- renderer_->SetVisible(true);
- }
-
- void SwapBuffers() { renderer_->SwapBuffers({}); }
-
- RendererSettings settings_;
- cc::FakeOutputSurfaceClient output_surface_client_;
- std::unique_ptr<FakeOutputSurface> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- std::unique_ptr<FakeRendererGL> renderer_;
-};
-
-// Closing the namespace here so that GLRendererShaderTest can take advantage
-// of the friend relationship with GLRenderer and all of the mock classes
-// declared above it.
-} // namespace
-
-class GLRendererShaderTest : public GLRendererTest {
- protected:
- GLRendererShaderTest() {
- output_surface_ = FakeOutputSurface::Create3d();
- output_surface_->BindToClient(&output_surface_client_);
-
- resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
- renderer_ = std::make_unique<FakeRendererGL>(
- &settings_, &debug_settings_, output_surface_.get(),
- resource_provider_.get(), nullptr);
- renderer_->Initialize();
- renderer_->SetVisible(true);
-
- child_context_provider_ = TestContextProvider::Create();
- child_context_provider_->BindToCurrentThread();
- child_resource_provider_ = std::make_unique<ClientResourceProvider>();
- }
-
- ~GLRendererShaderTest() override {
- child_resource_provider_->ShutdownAndReleaseAllResources();
- }
-
- void TestRenderPassProgram(TexCoordPrecision precision,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA,
- NO_MASK, false, false, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestRenderPassColorMatrixProgram(TexCoordPrecision precision,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, NO_AA,
- NO_MASK, false, true, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestRenderPassMaskProgram(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, HAS_MASK,
- false, false, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, sampler, blend_mode, NO_AA, HAS_MASK,
- false, true, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestRenderPassProgramAA(TexCoordPrecision precision,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA,
- NO_MASK, false, false, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, SAMPLER_TYPE_2D, blend_mode, USE_AA,
- NO_MASK, false, true, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestRenderPassMaskProgramAA(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, HAS_MASK,
- false, false, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode) {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::RenderPass(precision, sampler, blend_mode, USE_AA, HAS_MASK,
- false, true, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- void TestSolidColorProgramAA() {
- const Program* program = renderer_->GetProgramIfInitialized(
- ProgramKey::SolidColor(USE_AA, false, false));
- EXPECT_PROGRAM_VALID(program);
- EXPECT_EQ(program, renderer_->current_program_);
- }
-
- RendererSettings settings_;
- cc::FakeOutputSurfaceClient output_surface_client_;
- std::unique_ptr<FakeOutputSurface> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- scoped_refptr<TestContextProvider> child_context_provider_;
- std::unique_ptr<ClientResourceProvider> child_resource_provider_;
- std::unique_ptr<FakeRendererGL> renderer_;
-};
-
-namespace {
-
-TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) {
- gfx::Size viewport_size(1, 1);
- EXPECT_FALSE(renderer_->stencil_enabled());
-
- output_surface_->set_has_external_stencil_test(true);
-
- auto* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
-
- DrawFrame(renderer_.get(), viewport_size);
- EXPECT_TRUE(renderer_->stencil_enabled());
-}
-
-TEST_F(GLRendererWithDefaultHarnessTest, TextureDrawQuadShaderPrecisionHigh) {
- // TestContextProvider, used inside FakeOuputSurfaceClient, redefines
- // GetShaderPrecisionFormat() and sets the resolution of mediump with
- // 10-bits (1024). So any value higher than 1024 should use highp.
- // The goal is to make sure the fragment shaders used in DoDrawQuad() use
- // the correct precision qualifier.
-
- const gfx::Size viewport_size(1, 1);
- auto* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
-
- const bool needs_blending = false;
- const bool premultiplied_alpha = false;
- const bool flipped = false;
- const bool nearest_neighbor = false;
- const float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- const gfx::PointF uv_top_left(0, 0);
- const gfx::PointF uv_bottom_right(1, 1);
-
- auto child_context_provider = TestContextProvider::Create();
- child_context_provider->BindToCurrentThread();
-
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- // Here is where the texture is created. Any value bigger than 1024 should use
- // a highp.
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
- gfx::Size(1025, 1025), true);
- ResourceId client_resource_id = child_resource_provider->ImportResource(
- transfer_resource, base::DoNothing());
-
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- cc::SendResourceAndGetChildToParentMap(
- {client_resource_id}, resource_provider_.get(),
- child_resource_provider.get(), child_context_provider.get());
- ResourceId resource_id = resource_map[client_resource_id];
-
- // The values defined here should not alter the size of the already created
- // texture.
- TextureDrawQuad* overlay_quad =
- root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(1023, 1023), gfx::MaskFilterInfo(),
- absl::nullopt, false, 1, SkBlendMode::kSrcOver, 0);
- overlay_quad->SetNew(shared_state, gfx::Rect(1023, 1023),
- gfx::Rect(1023, 1023), needs_blending, resource_id,
- premultiplied_alpha, uv_top_left, uv_bottom_right,
- SK_ColorTRANSPARENT, vertex_opacity, flipped,
- nearest_neighbor, /*secure_output_only=*/false,
- gfx::ProtectedVideoType::kClear);
-
- DrawFrame(renderer_.get(), viewport_size);
-
- TexCoordPrecision precision = get_cached_tex_coord_precision(renderer_.get());
- EXPECT_EQ(precision, TEX_COORD_PRECISION_HIGH);
-
- child_resource_provider->ShutdownAndReleaseAllResources();
-}
-
-TEST_F(GLRendererWithDefaultHarnessTest, TextureDrawQuadShaderPrecisionMedium) {
- // TestContextProvider, used inside FakeOuputSurfaceClient, redefines
- // GetShaderPrecisionFormat() and sets the resolution of mediump with
- // 10-bits (1024). So any value higher than 1024 should use highp.
- // The goal is to make sure the fragment shaders used in DoDrawQuad() use
- // the correct precision qualifier.
-
- const gfx::Size viewport_size(1, 1);
- auto* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
-
- const bool needs_blending = false;
- const bool premultiplied_alpha = false;
- const bool flipped = false;
- const bool nearest_neighbor = false;
- const float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- const gfx::PointF uv_top_left(0, 0);
- const gfx::PointF uv_bottom_right(1, 1);
-
- auto child_context_provider = TestContextProvider::Create();
- child_context_provider->BindToCurrentThread();
-
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- // Here is where the texture is created. Any value smaller than 1024 should
- // use a mediump.
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
- gfx::Size(1023, 1023), true);
- ResourceId client_resource_id = child_resource_provider->ImportResource(
- transfer_resource, base::DoNothing());
-
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- cc::SendResourceAndGetChildToParentMap(
- {client_resource_id}, resource_provider_.get(),
- child_resource_provider.get(), child_context_provider.get());
- ResourceId resource_id = resource_map[client_resource_id];
-
- // The values defined here should not alter the size of the already created
- // texture.
- TextureDrawQuad* overlay_quad =
- root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(1025, 1025), gfx::MaskFilterInfo(),
- absl::nullopt, false, 1, SkBlendMode::kSrcOver, 0);
- overlay_quad->SetNew(shared_state, gfx::Rect(1025, 1025),
- gfx::Rect(1025, 1025), needs_blending, resource_id,
- premultiplied_alpha, uv_top_left, uv_bottom_right,
- SK_ColorTRANSPARENT, vertex_opacity, flipped,
- nearest_neighbor, /*secure_output_only=*/false,
- gfx::ProtectedVideoType::kClear);
-
- DrawFrame(renderer_.get(), viewport_size);
-
- TexCoordPrecision precision = get_cached_tex_coord_precision(renderer_.get());
- EXPECT_EQ(precision, TEX_COORD_PRECISION_MEDIUM);
-
- child_resource_provider->ShutdownAndReleaseAllResources();
-}
-
-class GLRendererTextureDrawQuadHDRTest
- : public GLRendererWithDefaultHarnessTest {
- protected:
- void RunTest(bool is_video_frame) {
- const gfx::Size viewport_size(10, 10);
- auto* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
-
- const bool needs_blending = false;
- const bool premultiplied_alpha = false;
- const bool flipped = false;
- const bool nearest_neighbor = false;
- const float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- const gfx::PointF uv_top_left(0, 0);
- const gfx::PointF uv_bottom_right(1, 1);
-
- auto child_context_provider = TestContextProvider::Create();
- child_context_provider->BindToCurrentThread();
-
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- constexpr gfx::Size kTextureSize = gfx::Size(10, 10);
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
- kTextureSize, true);
- transfer_resource.color_space = gfx::ColorSpace::CreateSCRGBLinear();
- ResourceId client_resource_id = child_resource_provider->ImportResource(
- transfer_resource, base::DoNothing());
-
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- cc::SendResourceAndGetChildToParentMap(
- {client_resource_id}, resource_provider_.get(),
- child_resource_provider.get(), child_context_provider.get());
- ResourceId resource_id = resource_map[client_resource_id];
-
- TextureDrawQuad* overlay_quad =
- root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(kTextureSize), gfx::MaskFilterInfo(),
- absl::nullopt, false, 1, SkBlendMode::kSrcOver, 0);
- overlay_quad->SetNew(shared_state, gfx::Rect(kTextureSize),
- gfx::Rect(kTextureSize), needs_blending, resource_id,
- premultiplied_alpha, uv_top_left, uv_bottom_right,
- SK_ColorTRANSPARENT, vertex_opacity, flipped,
- nearest_neighbor, /*secure_output_only=*/false,
- gfx::ProtectedVideoType::kClear);
- overlay_quad->is_video_frame = is_video_frame;
-
- constexpr float kSDRWhiteLevel = 123.0f;
- gfx::DisplayColorSpaces display_color_spaces;
- display_color_spaces.SetSDRMaxLuminanceNits(kSDRWhiteLevel);
-
- DrawFrame(renderer_.get(), viewport_size, display_color_spaces);
-
- const Program* program = current_program(renderer_.get());
- DCHECK(program);
- DCHECK(program->color_transform_for_testing())
- << program->fragment_shader().GetShaderString();
-
- const gfx::ColorSpace expected_src_color_space =
- is_video_frame
- ? gfx::ColorSpace::CreateSCRGBLinear().GetWithSDRWhiteLevel(
- kSDRWhiteLevel)
- : gfx::ColorSpace::CreateSCRGBLinear();
- EXPECT_EQ(program->color_transform_for_testing()->GetSrcColorSpace(),
- expected_src_color_space);
-
- child_resource_provider->ShutdownAndReleaseAllResources();
- }
-};
-
-TEST_F(GLRendererTextureDrawQuadHDRTest, VideoFrame) {
- RunTest(/*is_video_frame=*/true);
-}
-
-TEST_F(GLRendererTextureDrawQuadHDRTest, NotVideoFrame) {
- RunTest(/*is_video_frame=*/false);
-}
-
-class ForbidSynchronousCallGLES2Interface : public TestGLES2Interface {
- public:
- ForbidSynchronousCallGLES2Interface() = default;
-
- void GetAttachedShaders(GLuint program,
- GLsizei max_count,
- GLsizei* count,
- GLuint* shaders) override {
- ADD_FAILURE();
- }
-
- GLint GetAttribLocation(GLuint program, const GLchar* name) override {
- ADD_FAILURE();
- return 0;
- }
-
- void GetBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); }
-
- void GetBufferParameteriv(GLenum target,
- GLenum pname,
- GLint* value) override {
- ADD_FAILURE();
- }
-
- GLenum GetError() override {
- ADD_FAILURE();
- return GL_NO_ERROR;
- }
-
- void GetFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); }
-
- void GetFramebufferAttachmentParameteriv(GLenum target,
- GLenum attachment,
- GLenum pname,
- GLint* value) override {
- ADD_FAILURE();
- }
-
- void GetIntegerv(GLenum pname, GLint* value) override {
- if (pname == GL_MAX_TEXTURE_SIZE) {
- // MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
- *value = 1024;
- } else {
- ADD_FAILURE();
- }
- }
-
- // We allow querying the shader compilation and program link status in debug
- // mode, but not release.
- void GetProgramiv(GLuint program, GLenum pname, GLint* value) override {
- ADD_FAILURE();
- }
-
- void GetShaderiv(GLuint shader, GLenum pname, GLint* value) override {
- ADD_FAILURE();
- }
-
- void GetRenderbufferParameteriv(GLenum target,
- GLenum pname,
- GLint* value) override {
- ADD_FAILURE();
- }
-
- void GetShaderPrecisionFormat(GLenum shadertype,
- GLenum precisiontype,
- GLint* range,
- GLint* precision) override {
- ADD_FAILURE();
- }
-
- void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override {
- ADD_FAILURE();
- }
-
- void GetTexParameteriv(GLenum target, GLenum pname, GLint* value) override {
- ADD_FAILURE();
- }
-
- void GetUniformfv(GLuint program, GLint location, GLfloat* value) override {
- ADD_FAILURE();
- }
-
- void GetUniformiv(GLuint program, GLint location, GLint* value) override {
- ADD_FAILURE();
- }
-
- GLint GetUniformLocation(GLuint program, const GLchar* name) override {
- ADD_FAILURE();
- return 0;
- }
-
- void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override {
- ADD_FAILURE();
- }
-
- void GetVertexAttribiv(GLuint index, GLenum pname, GLint* value) override {
- ADD_FAILURE();
- }
-
- void GetVertexAttribPointerv(GLuint index,
- GLenum pname,
- void** pointer) override {
- ADD_FAILURE();
- }
-};
-
-TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
- auto gl_owned = std::make_unique<ForbidSynchronousCallGLES2Interface>();
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
-}
-
-class LoseContextOnFirstGetGLES2Interface : public TestGLES2Interface {
- public:
- LoseContextOnFirstGetGLES2Interface() {}
-
- void GetProgramiv(GLuint program, GLenum pname, GLint* value) override {
- LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
- GL_INNOCENT_CONTEXT_RESET_ARB);
- *value = 0;
- }
-
- void GetShaderiv(GLuint shader, GLenum pname, GLint* value) override {
- LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
- GL_INNOCENT_CONTEXT_RESET_ARB);
- *value = 0;
- }
-};
-
-TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
- auto gl_owned = std::make_unique<LoseContextOnFirstGetGLES2Interface>();
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
-}
-
-class ClearCountingGLES2Interface : public TestGLES2Interface {
- public:
- ClearCountingGLES2Interface() = default;
-
- MOCK_METHOD3(DiscardFramebufferEXT,
- void(GLenum target,
- GLsizei numAttachments,
- const GLenum* attachments));
- MOCK_METHOD1(Clear, void(GLbitfield mask));
-};
-
-TEST_F(GLRendererTest, OpaqueBackground) {
- auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
- gl_owned->set_have_discard_framebuffer(true);
-
- auto* gl = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(1, 1);
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
-
- // On DEBUG builds, render passes with opaque background clear to blue to
- // easily see regions that were not drawn on the screen.
- EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
- .With(Args<2, 1>(ElementsAre(GL_COLOR_EXT)))
- .Times(1);
-#ifdef NDEBUG
- EXPECT_CALL(*gl, Clear(_)).Times(0);
-#else
- EXPECT_CALL(*gl, Clear(_)).Times(1);
-#endif
- DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(gl);
-}
-
-TEST_F(GLRendererTest, TransparentBackground) {
- auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
- auto* gl = gl_owned.get();
- gl_owned->set_have_discard_framebuffer(true);
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(1, 1);
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = true;
-
- EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
- EXPECT_CALL(*gl, Clear(_)).Times(1);
- DrawFrame(&renderer, viewport_size);
-
- Mock::VerifyAndClearExpectations(gl);
-}
-
-TEST_F(GLRendererTest, OffscreenOutputSurface) {
- auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
- auto* gl = gl_owned.get();
- gl_owned->set_have_discard_framebuffer(true);
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::CreateOffscreen(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(1, 1);
- cc::AddRenderPass(&render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
- .With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0)))
- .Times(1);
- EXPECT_CALL(*gl, Clear(_)).Times(AnyNumber());
- DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(gl);
-}
-
-class TextureStateTrackingGLES2Interface : public TestGLES2Interface {
- public:
- TextureStateTrackingGLES2Interface() : active_texture_(GL_INVALID_ENUM) {}
-
- MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token));
- MOCK_METHOD3(TexParameteri, void(GLenum target, GLenum pname, GLint param));
- MOCK_METHOD4(
- DrawElements,
- void(GLenum mode, GLsizei count, GLenum type, const void* indices));
-
- void ActiveTexture(GLenum texture) override {
- EXPECT_NE(texture, active_texture_);
- active_texture_ = texture;
- }
-
- GLenum active_texture() const { return active_texture_; }
-
- private:
- GLenum active_texture_;
-};
-
-#define EXPECT_FILTER_CALL(filter) \
- EXPECT_CALL(*gl, \
- TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter)); \
- EXPECT_CALL(*gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter));
-
-TEST_F(GLRendererTest, ActiveTextureState) {
- auto child_gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
- auto child_context_provider =
- TestContextProvider::Create(std::move(child_gl_owned));
- child_context_provider->BindToCurrentThread();
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
- gl_owned->set_have_extension_egl_image(true);
- auto* gl = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- // During initialization we are allowed to set any texture parameters.
- EXPECT_CALL(*gl, TexParameteri(_, _, _)).Times(AnyNumber());
-
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(100, 100), gfx::Transform(), cc::FilterOperations());
- gpu::SyncToken mailbox_sync_token;
- cc::AddOneOfEveryQuadTypeInDisplayResourceProvider(
- root_pass, resource_provider.get(), child_resource_provider.get(),
- child_context_provider.get(), AggregatedRenderPassId{0},
- &mailbox_sync_token);
-
- EXPECT_EQ(12u, resource_provider->num_resources());
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // Set up expected texture filter state transitions that match the quads
- // created in AppendOneOfEveryQuadType().
- Mock::VerifyAndClearExpectations(gl);
- {
- InSequence sequence;
- // The verified flush flag will be set by
- // ClientResourceProvider::PrepareSendToParent. Before checking if
- // the gpu::SyncToken matches, set this flag first.
- mailbox_sync_token.SetVerifyFlush();
- // In AddOneOfEveryQuadTypeInDisplayResourceProvider, resources are added
- // into RenderPass with the below order: resource6, resource1, resource8
- // (with mailbox), resource2, resource3, resource4, resource9, resource10,
- // resource11, resource12. resource8 has its own mailbox mailbox_sync_token.
- // The rest resources share a common default sync token.
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(2);
- EXPECT_CALL(*gl,
- WaitSyncTokenCHROMIUM(MatchesSyncToken(mailbox_sync_token)))
- .Times(1);
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(7);
-
- // yuv_quad is drawn with the default linear filter.
- for (int i = 0; i < 4; ++i) {
- EXPECT_FILTER_CALL(GL_LINEAR);
- }
- EXPECT_CALL(*gl, DrawElements(_, _, _, _));
-
- // tile_quad is drawn with GL_NEAREST because it is not transformed or
- // scaled.
- EXPECT_FILTER_CALL(GL_NEAREST);
- EXPECT_CALL(*gl, DrawElements(_, _, _, _));
-
- // transformed tile_quad
- EXPECT_FILTER_CALL(GL_LINEAR);
- EXPECT_CALL(*gl, DrawElements(_, _, _, _));
-
- // scaled tile_quad
- EXPECT_FILTER_CALL(GL_LINEAR);
- EXPECT_CALL(*gl, DrawElements(_, _, _, _));
-
- // texture_quad without nearest neighbor
- EXPECT_FILTER_CALL(GL_LINEAR);
- EXPECT_CALL(*gl, DrawElements(_, _, _, _));
-
- // texture_quad without nearest neighbor
- EXPECT_FILTER_CALL(GL_LINEAR);
- EXPECT_CALL(*gl, DrawElements(_, _, _, _));
-
- if (features::IsUsingFastPathForSolidColorQuad()) {
- // stream video and debug draw quads
- EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(2);
- } else {
- // stream video, solid color, and debug draw quads
- EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(3);
- }
- }
-
- gfx::Size viewport_size(100, 100);
- DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(gl);
-
- child_resource_provider->ShutdownAndReleaseAllResources();
-}
-
-class BufferSubDataTrackingGLES2Interface : public TestGLES2Interface {
- public:
- BufferSubDataTrackingGLES2Interface() = default;
- ~BufferSubDataTrackingGLES2Interface() override = default;
-
- void BufferSubData(GLenum target,
- GLintptr offset,
- GLsizeiptr size,
- const void* data) override {
- if (target != GL_ARRAY_BUFFER)
- return;
- DCHECK_EQ(0, offset);
- last_array_data.resize(size);
- memcpy(last_array_data.data(), data, size);
- }
-
- std::vector<uint8_t> last_array_data;
-};
-
-TEST_F(GLRendererTest, DrawYUVVideoDrawQuadWithVisibleRect) {
- gfx::Size viewport_size(100, 100);
-
- auto mock_gl_owned = std::make_unique<BufferSubDataTrackingGLES2Interface>();
- BufferSubDataTrackingGLES2Interface* mock_gl = mock_gl_owned.get();
- auto provider = TestContextProvider::Create(std::move(mock_gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
-
- gfx::Rect rect(viewport_size);
- gfx::Rect visible_rect(rect);
- gfx::RectF tex_coord_rect(0, 0, 1, 1);
- visible_rect.Inset(gfx::Insets::TLBR(20, 10, 40, 30));
-
- SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Rect(), rect,
- gfx::MaskFilterInfo(), absl::nullopt, false, 1,
- SkBlendMode::kSrcOver, 0);
-
- YUVVideoDrawQuad* quad =
- root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
- quad->SetNew(shared_state, rect, visible_rect, /*needs_blending=*/false,
- tex_coord_rect, tex_coord_rect, rect.size(), rect.size(),
- ResourceId(1), ResourceId(1), ResourceId(1), ResourceId(1),
- gfx::ColorSpace(), 0, 1.0, 8);
-
- DrawFrame(&renderer, viewport_size);
-
- ASSERT_EQ(96u, mock_gl->last_array_data.size());
- float* geometry_binding_vertexes =
- reinterpret_cast<float*>(mock_gl->last_array_data.data());
-
- const double kEpsilon = 1e-6;
- EXPECT_NEAR(-0.4f, geometry_binding_vertexes[0], kEpsilon);
- EXPECT_NEAR(-0.3f, geometry_binding_vertexes[1], kEpsilon);
- EXPECT_NEAR(0.1f, geometry_binding_vertexes[3], kEpsilon);
- EXPECT_NEAR(0.2f, geometry_binding_vertexes[4], kEpsilon);
-
- EXPECT_NEAR(0.2f, geometry_binding_vertexes[12], kEpsilon);
- EXPECT_NEAR(0.1f, geometry_binding_vertexes[13], kEpsilon);
- EXPECT_NEAR(0.7f, geometry_binding_vertexes[15], kEpsilon);
- EXPECT_NEAR(0.6f, geometry_binding_vertexes[16], kEpsilon);
-}
-
-class NoClearRootRenderPassMockGLES2Interface : public TestGLES2Interface {
- public:
- MOCK_METHOD1(Clear, void(GLbitfield mask));
- MOCK_METHOD4(
- DrawElements,
- void(GLenum mode, GLsizei count, GLenum type, const void* indices));
-};
-
-TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
- auto mock_gl_owned =
- std::make_unique<NoClearRootRenderPassMockGLES2Interface>();
- NoClearRootRenderPassMockGLES2Interface* mock_gl = mock_gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(mock_gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- settings.should_clear_root_render_pass = false;
-
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(10, 10);
-
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPass* child_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, child_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(child_pass, gfx::Rect(viewport_size), SK_ColorBLUE);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
-
- cc::AddRenderPassQuad(root_pass, child_pass);
-
-#ifdef NDEBUG
- GLint clear_bits = GL_COLOR_BUFFER_BIT;
-#else
- GLint clear_bits = GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
-#endif
-
- // First render pass is not the root one, clearing should happen.
- EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(AtLeast(1));
-
- Expectation first_render_pass =
- EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _)).Times(1);
-
- if (features::IsUsingFastPathForSolidColorQuad()) {
- // The second render pass is the root one, clearing should be prevented. The
- // one call is expected due to the solid color draw quad which uses glClear
- // to draw the quad.
- EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(1).After(first_render_pass);
- } else {
- // The second render pass is the root one, clearing should be prevented.
- EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(0).After(first_render_pass);
- }
-
- EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _))
- .Times(AnyNumber())
- .After(first_render_pass);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
-
- // In multiple render passes all but the root pass should clear the
- // framebuffer.
- Mock::VerifyAndClearExpectations(&mock_gl);
-}
-
-class ScissorTestOnClearCheckingGLES2Interface : public TestGLES2Interface {
- public:
- ScissorTestOnClearCheckingGLES2Interface() = default;
-
- void ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) override {
- // RGBA - {0, 0, 0, 0} is used to clear the buffer before drawing onto the
- // render target. Any other color means a solid color draw quad is being
- // drawn.
- if (features::IsUsingFastPathForSolidColorQuad())
- is_drawing_solid_color_quad_ = !(r == 0 && g == 0 && b == 0 && a == 0);
- }
-
- void Clear(GLbitfield bits) override {
- // GL clear is also used to draw solid color draw quads.
- if ((bits & GL_COLOR_BUFFER_BIT) && is_drawing_solid_color_quad_)
- return;
- EXPECT_FALSE(scissor_enabled_);
- }
-
- void Enable(GLenum cap) override {
- if (cap == GL_SCISSOR_TEST)
- scissor_enabled_ = true;
- }
-
- void Disable(GLenum cap) override {
- if (cap == GL_SCISSOR_TEST)
- scissor_enabled_ = false;
- }
-
- private:
- bool scissor_enabled_ = false;
- bool is_drawing_solid_color_quad_ = false;
-};
-
-TEST_F(GLRendererTest, ScissorTestWhenClearing) {
- auto gl_owned = std::make_unique<ScissorTestOnClearCheckingGLES2Interface>();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- EXPECT_FALSE(renderer.use_partial_swap());
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
-
- gfx::Rect grand_child_rect(25, 25);
- AggregatedRenderPassId grand_child_pass_id{3};
- AggregatedRenderPass* grand_child_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, grand_child_pass_id, grand_child_rect,
- gfx::Transform(), cc::FilterOperations());
- cc::AddClippedQuad(grand_child_pass, grand_child_rect, SK_ColorYELLOW);
-
- gfx::Rect child_rect(50, 50);
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(child_pass, child_rect, SK_ColorBLUE);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
-
- cc::AddRenderPassQuad(root_pass, child_pass);
- cc::AddRenderPassQuad(child_pass, grand_child_pass);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
-}
-
-class DiscardCheckingGLES2Interface : public TestGLES2Interface {
- public:
- DiscardCheckingGLES2Interface() = default;
-
- void DiscardFramebufferEXT(GLenum target,
- GLsizei numAttachments,
- const GLenum* attachments) override {
- ++discarded_;
- }
-
- int discarded() const { return discarded_; }
- void reset_discarded() { discarded_ = 0; }
-
- private:
- int discarded_ = 0;
-};
-
-TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
- auto gl_owned = std::make_unique<DiscardCheckingGLES2Interface>();
- gl_owned->set_have_post_sub_buffer(true);
- gl_owned->set_have_discard_framebuffer(true);
-
- auto* gl = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- auto output_surface = FakeOutputSurface::Create3d(std::move(provider));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- settings.partial_swap_enabled = true;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- EXPECT_TRUE(renderer.use_partial_swap());
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
- {
- // Draw one black frame to make sure the output surface is reshaped before
- // testes.
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorBLACK);
- root_pass->damage_rect = gfx::Rect(viewport_size);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- gl->reset_discarded();
- }
- {
- // Partial frame, should not discard.
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
- root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- EXPECT_EQ(0, gl->discarded());
- gl->reset_discarded();
- }
- {
- // Full frame, should discard.
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
- root_pass->damage_rect = root_pass->output_rect;
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- EXPECT_EQ(1, gl->discarded());
- gl->reset_discarded();
- }
- {
- // Full frame, external scissor is set, should not discard.
- output_surface->set_has_external_stencil_test(true);
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
- root_pass->damage_rect = root_pass->output_rect;
- root_pass->has_transparent_background = false;
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- EXPECT_EQ(0, gl->discarded());
- gl->reset_discarded();
- output_surface->set_has_external_stencil_test(false);
- }
-}
-
-class ResourceTrackingGLES2Interface : public TestGLES2Interface {
- public:
- ResourceTrackingGLES2Interface() = default;
- ~ResourceTrackingGLES2Interface() override { CheckNoResources(); }
-
- void CheckNoResources() {
- EXPECT_TRUE(textures_.empty());
- EXPECT_TRUE(buffers_.empty());
- EXPECT_TRUE(framebuffers_.empty());
- EXPECT_TRUE(renderbuffers_.empty());
- EXPECT_TRUE(queries_.empty());
- EXPECT_TRUE(shaders_.empty());
- EXPECT_TRUE(programs_.empty());
- }
-
- void GenTextures(GLsizei n, GLuint* textures) override {
- GenIds(&textures_, n, textures);
- }
-
- void GenBuffers(GLsizei n, GLuint* buffers) override {
- GenIds(&buffers_, n, buffers);
- }
-
- void GenFramebuffers(GLsizei n, GLuint* framebuffers) override {
- GenIds(&framebuffers_, n, framebuffers);
- }
-
- void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) override {
- GenIds(&renderbuffers_, n, renderbuffers);
- }
-
- void GenQueriesEXT(GLsizei n, GLuint* queries) override {
- GenIds(&queries_, n, queries);
- }
-
- GLuint CreateProgram() override { return GenId(&programs_); }
-
- GLuint CreateShader(GLenum type) override { return GenId(&shaders_); }
-
- void BindTexture(GLenum target, GLuint texture) override {
- CheckId(&textures_, texture);
- }
-
- void BindBuffer(GLenum target, GLuint buffer) override {
- CheckId(&buffers_, buffer);
- }
-
- void BindRenderbuffer(GLenum target, GLuint renderbuffer) override {
- CheckId(&renderbuffers_, renderbuffer);
- }
-
- void BindFramebuffer(GLenum target, GLuint framebuffer) override {
- CheckId(&framebuffers_, framebuffer);
- }
-
- void UseProgram(GLuint program) override { CheckId(&programs_, program); }
-
- void DeleteTextures(GLsizei n, const GLuint* textures) override {
- DeleteIds(&textures_, n, textures);
- }
-
- void DeleteBuffers(GLsizei n, const GLuint* buffers) override {
- DeleteIds(&buffers_, n, buffers);
- }
-
- void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) override {
- DeleteIds(&framebuffers_, n, framebuffers);
- }
-
- void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) override {
- DeleteIds(&renderbuffers_, n, renderbuffers);
- }
-
- void DeleteQueriesEXT(GLsizei n, const GLuint* queries) override {
- DeleteIds(&queries_, n, queries);
- }
-
- void DeleteProgram(GLuint program) override { DeleteId(&programs_, program); }
-
- void DeleteShader(GLuint shader) override { DeleteId(&shaders_, shader); }
-
- void BufferData(GLenum target,
- GLsizeiptr size,
- const void* data,
- GLenum usage) override {}
-
- private:
- GLuint GenId(std::set<GLuint>* resource_set) {
- GLuint id = next_id_++;
- resource_set->insert(id);
- return id;
- }
-
- void GenIds(std::set<GLuint>* resource_set, GLsizei n, GLuint* ids) {
- for (GLsizei i = 0; i < n; ++i)
- ids[i] = GenId(resource_set);
- }
-
- void CheckId(std::set<GLuint>* resource_set, GLuint id) {
- if (id == 0)
- return;
- EXPECT_TRUE(resource_set->find(id) != resource_set->end());
- }
-
- void DeleteId(std::set<GLuint>* resource_set, GLuint id) {
- if (id == 0)
- return;
- size_t num_erased = resource_set->erase(id);
- EXPECT_EQ(1u, num_erased);
- }
-
- void DeleteIds(std::set<GLuint>* resource_set, GLsizei n, const GLuint* ids) {
- for (GLsizei i = 0; i < n; ++i)
- DeleteId(resource_set, ids[i]);
- }
-
- GLuint next_id_ = 1;
- std::set<GLuint> textures_;
- std::set<GLuint> buffers_;
- std::set<GLuint> framebuffers_;
- std::set<GLuint> renderbuffers_;
- std::set<GLuint> queries_;
- std::set<GLuint> shaders_;
- std::set<GLuint> programs_;
-};
-
-TEST_F(GLRendererTest, NoResourceLeak) {
- auto gl_owned = std::make_unique<ResourceTrackingGLES2Interface>();
- auto* gl = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- auto output_surface = FakeOutputSurface::Create3d(std::move(provider));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- {
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
- root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- }
- gl->CheckNoResources();
-}
-
-class DrawElementsGLES2Interface : public TestGLES2Interface {
- public:
- MOCK_METHOD4(
- DrawElements,
- void(GLenum mode, GLsizei count, GLenum type, const void* indices));
-};
-
-class GLRendererSkipTest : public GLRendererTest {
- protected:
- GLRendererSkipTest() {
- auto gl_owned = std::make_unique<StrictMock<DrawElementsGLES2Interface>>();
- gl_owned->set_have_post_sub_buffer(true);
- gl_ = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- output_surface_ = FakeOutputSurface::Create3d(std::move(provider));
- output_surface_->BindToClient(&output_surface_client_);
-
- resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
- settings_.partial_swap_enabled = true;
- renderer_ = std::make_unique<FakeRendererGL>(&settings_, &debug_settings_,
- output_surface_.get(),
- resource_provider_.get());
- renderer_->Initialize();
- renderer_->SetVisible(true);
- }
-
- void DrawBlackFrame(const gfx::Size& viewport_size) {
- // The feature enables a faster path to draw solid color quads that does not
- // use GL draw calls but instead uses glClear.
- if (!features::IsUsingFastPathForSolidColorQuad())
- EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(viewport_size);
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorBLACK);
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- Mock::VerifyAndClearExpectations(gl_);
- }
-
- StrictMock<DrawElementsGLES2Interface>* gl_;
- RendererSettings settings_;
- cc::FakeOutputSurfaceClient output_surface_client_;
- std::unique_ptr<FakeOutputSurface> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- std::unique_ptr<FakeRendererGL> renderer_;
-};
-
-TEST_F(GLRendererSkipTest, DrawQuad) {
- gfx::Size viewport_size(100, 100);
- gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
-
- // Draw the a black frame to make sure output surface is reshaped before
- // tests.
- DrawBlackFrame(viewport_size);
-
- EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
- cc::AddQuad(root_pass, quad_rect, SK_ColorGREEN);
-
- // Add rounded corners to the solid color draw quad so that the fast path
- // of drawing using glClear is not used.
- root_pass->shared_quad_state_list.front()->mask_filter_info =
- gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 2.f));
-
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
-}
-
-TEST_F(GLRendererSkipTest, SkipVisibleRect) {
- gfx::Size viewport_size(100, 100);
- gfx::Rect quad_rect = gfx::Rect(0, 0, 40, 40);
-
- // Draw the a black frame to make sure output surface is reshaped before
- // tests.
- DrawBlackFrame(viewport_size);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(0, 0, 10, 10);
- cc::AddQuad(root_pass, quad_rect, SK_ColorGREEN);
- root_pass->shared_quad_state_list.front()->clip_rect =
- gfx::Rect(0, 0, 40, 40);
- root_pass->quad_list.front()->visible_rect = gfx::Rect(20, 20, 20, 20);
-
- // Add rounded corners to the solid color draw quad so that the fast path
- // of drawing using glClear is not used.
- root_pass->shared_quad_state_list.front()->mask_filter_info =
- gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 1.f));
-
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- // DrawElements should not be called because the visible rect is outside the
- // scissor, even though the clip rect and quad rect intersect the scissor.
-}
-
-TEST_F(GLRendererSkipTest, SkipClippedQuads) {
- gfx::Size viewport_size(100, 100);
- gfx::Rect quad_rect = gfx::Rect(25, 25, 90, 90);
-
- // Draw the a black frame to make sure output surface is reshaped before
- // tests.
- DrawBlackFrame(viewport_size);
-
- AggregatedRenderPassId root_pass_id{1};
-
- auto* root_pass = cc::AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
- cc::AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
- root_pass->quad_list.front()->rect = gfx::Rect(20, 20, 20, 20);
-
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- // DrawElements should not be called because the clip rect is outside the
- // scissor.
-}
-
-TEST_F(GLRendererTest, DrawFramePreservesFramebuffer) {
- // When using render-to-FBO to display the surface, all rendering is done
- // to a non-zero FBO. Make sure that the framebuffer is always restored to
- // the correct framebuffer during rendering, if changed.
- // Note: there is one path that will set it to 0, but that is after the render
- // has finished.
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d());
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- EXPECT_FALSE(renderer.use_partial_swap());
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
- gfx::Rect quad_rect = gfx::Rect(20, 20, 20, 20);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddClippedQuad(root_pass, quad_rect, SK_ColorGREEN);
-
- unsigned fbo;
- gpu::gles2::GLES2Interface* gl =
- output_surface->context_provider()->ContextGL();
- gl->GenFramebuffers(1, &fbo);
- output_surface->set_framebuffer(fbo, GL_RGB);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
-
- int bound_fbo;
- gl->GetIntegerv(GL_FRAMEBUFFER_BINDING, &bound_fbo);
- EXPECT_EQ(static_cast<int>(fbo), bound_fbo);
-}
-
-TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
- gfx::Size viewport_size(60, 75);
-
- gfx::Rect child_rect(50, 50);
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPass* child_pass;
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass;
-
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
- child_rect.size(), false /* is_overlay_candidate */);
- ResourceId mask = child_resource_provider_->ImportResource(transfer_resource,
- base::DoNothing());
-
- // Return the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- cc::SendResourceAndGetChildToParentMap({mask}, resource_provider_.get(),
- child_resource_provider_.get(),
- child_context_provider_.get());
- ResourceId mapped_mask = resource_map[mask];
-
- float matrix[20];
- float amount = 0.5f;
- matrix[0] = 0.213f + 0.787f * amount;
- matrix[1] = 0.715f - 0.715f * amount;
- matrix[2] = 1.f - (matrix[0] + matrix[1]);
- matrix[3] = matrix[4] = 0;
- matrix[5] = 0.213f - 0.213f * amount;
- matrix[6] = 0.715f + 0.285f * amount;
- matrix[7] = 1.f - (matrix[5] + matrix[6]);
- matrix[8] = matrix[9] = 0;
- matrix[10] = 0.213f - 0.213f * amount;
- matrix[11] = 0.715f - 0.715f * amount;
- matrix[12] = 1.f - (matrix[10] + matrix[11]);
- matrix[13] = matrix[14] = 0;
- matrix[15] = matrix[16] = matrix[17] = matrix[19] = 0;
- matrix[18] = 1;
- cc::FilterOperations filters;
- filters.Append(cc::FilterOperation::CreateReferenceFilter(
- sk_make_sp<cc::ColorFilterPaintFilter>(SkColorFilters::Matrix(matrix),
- nullptr)));
-
- gfx::Transform transform_causing_aa;
- transform_causing_aa.Rotate(20.0);
-
- for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
- BlendMode blend_mode = static_cast<BlendMode>(i);
- SkBlendMode xfer_mode = BlendModeToSkXfermode(blend_mode);
- settings_.force_blending_with_shaders = (blend_mode != BLEND_MODE_NONE);
- // RenderPassProgram
- render_passes_in_draw_order_.clear();
- child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, gfx::Transform(), cc::FilterOperations());
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
-
- // RenderPassColorMatrixProgram
- render_passes_in_draw_order_.clear();
-
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, transform_causing_aa, filters);
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
-
- // RenderPassMaskProgram
- render_passes_in_draw_order_.clear();
-
- child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, gfx::Transform(), cc::FilterOperations());
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, mapped_mask, gfx::Transform(),
- xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassMaskProgram(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
- blend_mode);
-
- // RenderPassMaskColorMatrixProgram
- render_passes_in_draw_order_.clear();
-
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, gfx::Transform(), filters);
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, mapped_mask, gfx::Transform(),
- xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassMaskColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM,
- SAMPLER_TYPE_2D, blend_mode);
-
- // RenderPassProgramAA
- render_passes_in_draw_order_.clear();
-
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, transform_causing_aa,
- cc::FilterOperations());
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- transform_causing_aa, xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
-
- // RenderPassColorMatrixProgramAA
- render_passes_in_draw_order_.clear();
-
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, transform_causing_aa, filters);
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- transform_causing_aa, xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
-
- // RenderPassMaskProgramAA
- render_passes_in_draw_order_.clear();
-
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, transform_causing_aa,
- cc::FilterOperations());
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, mapped_mask,
- transform_causing_aa, xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassMaskProgramAA(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
- blend_mode);
-
- // RenderPassMaskColorMatrixProgramAA
- render_passes_in_draw_order_.clear();
-
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, transform_causing_aa, filters);
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size),
- transform_causing_aa, cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, mapped_mask,
- transform_causing_aa, xfer_mode);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
- TestRenderPassMaskColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM,
- SAMPLER_TYPE_2D, blend_mode);
- }
-}
-
-// At this time, the AA code path cannot be taken if the surface's rect would
-// project incorrectly by the given transform, because of w<0 clipping.
-TEST_F(GLRendererShaderTest, DrawRenderPassQuadSkipsAAForClippingTransform) {
- gfx::Rect child_rect(50, 50);
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPass* child_pass;
-
- gfx::Size viewport_size(100, 100);
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass;
-
- gfx::Transform transform_preventing_aa;
- transform_preventing_aa.ApplyPerspectiveDepth(40.0);
- transform_preventing_aa.RotateAboutYAxis(-20.0);
- transform_preventing_aa.Scale(30.0, 1.0);
-
- // Verify that the test transform and test rect actually do cause the clipped
- // flag to trigger. Otherwise we are not testing the intended scenario.
- bool clipped = false;
- cc::MathUtil::MapQuad(transform_preventing_aa,
- gfx::QuadF(gfx::RectF(child_rect)), &clipped);
- ASSERT_TRUE(clipped);
-
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- child_rect, transform_preventing_aa,
- cc::FilterOperations());
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- transform_preventing_aa, SkBlendMode::kSrcOver);
-
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
-
- // If use_aa incorrectly ignores clipping, it will use the
- // RenderPassProgramAA shader instead of the RenderPassProgram.
- TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, BLEND_MODE_NONE);
-}
-
-TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
- gfx::Size viewport_size(30, 30); // Don't translate out of the viewport.
- gfx::Size quad_size(3, 3);
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass;
-
- gfx::Transform pixel_aligned_transform_causing_aa;
- pixel_aligned_transform_causing_aa.Translate(25.5f, 25.5f);
- pixel_aligned_transform_causing_aa.Scale(0.5f, 0.5f);
-
- root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
- cc::AddTransformedQuad(root_pass, gfx::Rect(quad_size), SK_ColorYELLOW,
- pixel_aligned_transform_causing_aa);
-
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(renderer_.get(), viewport_size);
-
- TestSolidColorProgramAA();
-}
-
-class OutputSurfaceMockGLES2Interface : public TestGLES2Interface {
- public:
- OutputSurfaceMockGLES2Interface() = default;
-
- // Specifically override methods even if they are unused (used in conjunction
- // with StrictMock). We need to make sure that GLRenderer does not issue
- // framebuffer-related GLuint calls directly. Instead these are supposed to go
- // through the OutputSurface abstraction.
- MOCK_METHOD2(BindFramebuffer, void(GLenum target, GLuint framebuffer));
- MOCK_METHOD5(ResizeCHROMIUM,
- void(GLuint width,
- GLuint height,
- float device_scale,
- GLcolorSpace color_space,
- GLboolean has_alpha));
- MOCK_METHOD4(
- DrawElements,
- void(GLenum mode, GLsizei count, GLenum type, const void* indices));
-};
-
-class MockOutputSurface : public OutputSurface {
- public:
- explicit MockOutputSurface(scoped_refptr<ContextProvider> provider)
- : OutputSurface(std::move(provider)) {}
- ~MockOutputSurface() override {}
-
- void BindToClient(OutputSurfaceClient*) override {}
- unsigned UpdateGpuFence() override { return 0; }
-
- MOCK_METHOD0(EnsureBackbuffer, void());
- MOCK_METHOD0(DiscardBackbuffer, void());
- MOCK_METHOD5(Reshape,
- void(const gfx::Size& size,
- float scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil));
- MOCK_METHOD0(BindFramebuffer, void());
- MOCK_METHOD1(SetDrawRectangle, void(const gfx::Rect&));
- MOCK_METHOD1(SetEnableDCLayers, void(bool));
- MOCK_METHOD0(GetFramebufferCopyTextureFormat, GLenum());
- MOCK_METHOD1(SwapBuffers_, void(OutputSurfaceFrame& frame)); // NOLINT
- void SwapBuffers(OutputSurfaceFrame frame) override { SwapBuffers_(frame); }
- MOCK_CONST_METHOD0(IsDisplayedAsOverlayPlane, bool());
- MOCK_CONST_METHOD0(GetOverlayTextureId, unsigned());
- MOCK_CONST_METHOD0(HasExternalStencilTest, bool());
- MOCK_METHOD0(ApplyExternalStencil, void());
- MOCK_METHOD1(SetUpdateVSyncParametersCallback,
- void(UpdateVSyncParametersCallback));
- MOCK_METHOD1(SetDisplayTransformHint, void(gfx::OverlayTransform));
-
- gfx::OverlayTransform GetDisplayTransform() override {
- return gfx::OVERLAY_TRANSFORM_NONE;
- }
-};
-
-class MockOutputSurfaceTest : public GLRendererTest {
- protected:
- void SetUp() override {
- auto gl = std::make_unique<StrictMock<OutputSurfaceMockGLES2Interface>>();
- gl->set_have_post_sub_buffer(true);
- gl_ = gl.get();
- auto provider = TestContextProvider::Create(std::move(gl));
- provider->BindToCurrentThread();
- output_surface_ =
- std::make_unique<StrictMock<MockOutputSurface>>(std::move(provider));
-
- output_surface_->BindToClient(&output_surface_client_);
-
- resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
-
- renderer_ = std::make_unique<FakeRendererGL>(&settings_, &debug_settings_,
- output_surface_.get(),
- resource_provider_.get());
- renderer_->Initialize();
-
- EXPECT_CALL(*output_surface_, EnsureBackbuffer()).Times(1);
- renderer_->SetVisible(true);
- Mock::VerifyAndClearExpectations(output_surface_.get());
- }
-
- void SwapBuffers() {
- renderer_->SwapBuffers(DirectRenderer::SwapFrameData());
- }
-
- void DrawFrame(float device_scale_factor,
- const gfx::Size& viewport_size,
- bool transparent) {
- gfx::BufferFormat format = transparent ? gfx::BufferFormat::RGBA_8888
- : gfx::BufferFormat::RGBX_8888;
- AggregatedRenderPassId render_pass_id{1};
- AggregatedRenderPass* render_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, render_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(render_pass, gfx::Rect(viewport_size), SK_ColorGREEN);
- render_pass->has_transparent_background = transparent;
-
- EXPECT_CALL(*output_surface_, EnsureBackbuffer()).WillRepeatedly(Return());
-
- EXPECT_CALL(*output_surface_,
- Reshape(viewport_size, device_scale_factor, _, format, _))
- .Times(1);
-
- EXPECT_CALL(*output_surface_, BindFramebuffer()).Times(1);
-
- EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
-
- renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- SurfaceDamageRectList surface_damage_rect_list;
- renderer_->DrawFrame(&render_passes_in_draw_order_, device_scale_factor,
- viewport_size, gfx::DisplayColorSpaces(),
- std::move(surface_damage_rect_list));
- }
-
- RendererSettings settings_;
- cc::FakeOutputSurfaceClient output_surface_client_;
- OutputSurfaceMockGLES2Interface* gl_ = nullptr;
- std::unique_ptr<StrictMock<MockOutputSurface>> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- std::unique_ptr<FakeRendererGL> renderer_;
-};
-
-TEST_F(MockOutputSurfaceTest, BackbufferDiscard) {
- // Drop backbuffer on hide.
- EXPECT_CALL(*output_surface_, DiscardBackbuffer()).Times(1);
- renderer_->SetVisible(false);
- Mock::VerifyAndClearExpectations(output_surface_.get());
-
- // Restore backbuffer on show.
- EXPECT_CALL(*output_surface_, EnsureBackbuffer()).Times(1);
- renderer_->SetVisible(true);
- Mock::VerifyAndClearExpectations(output_surface_.get());
-}
-
-#if BUILDFLAG(IS_WIN)
-class MockDCLayerOverlayProcessor : public DCLayerOverlayProcessor {
- public:
- MockDCLayerOverlayProcessor()
- : DCLayerOverlayProcessor(&debug_settings_,
- /*allowed_yuv_overlay_count=*/1,
- true) {}
- ~MockDCLayerOverlayProcessor() override = default;
- MOCK_METHOD8(Process,
- void(DisplayResourceProvider* resource_provider,
- const gfx::RectF& display_rect,
- const FilterOperationsMap& render_pass_filters,
- const FilterOperationsMap& render_pass_backdrop_filters,
- AggregatedRenderPassList* render_passes,
- gfx::Rect* damage_rect,
- SurfaceDamageRectList surface_damage_rect_list,
- DCLayerOverlayList* dc_layer_overlays));
-
- protected:
- DebugRendererSettings debug_settings_;
-};
-class TestOverlayProcessor : public OverlayProcessorWin {
- public:
- explicit TestOverlayProcessor(OutputSurface* output_surface)
- : OverlayProcessorWin(output_surface,
- std::make_unique<MockDCLayerOverlayProcessor>()) {}
- ~TestOverlayProcessor() override = default;
-
- MockDCLayerOverlayProcessor* GetTestProcessor() {
- return static_cast<MockDCLayerOverlayProcessor*>(GetOverlayProcessor());
- }
-};
-#elif BUILDFLAG(IS_APPLE)
-class MockCALayerOverlayProcessor : public CALayerOverlayProcessor {
- public:
- MockCALayerOverlayProcessor() : CALayerOverlayProcessor(true) {}
- ~MockCALayerOverlayProcessor() override = default;
-
- MOCK_METHOD6(
- ProcessForCALayerOverlays,
- bool(AggregatedRenderPass* render_pass,
- DisplayResourceProvider* resource_provider,
- const gfx::RectF& display_rect,
- const base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>&
- render_pass_filters,
- const base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>&
- render_pass_backdrop_filters,
- CALayerOverlayList* ca_layer_overlays));
-};
-
-class TestOverlayProcessor : public OverlayProcessorMac {
- public:
- explicit TestOverlayProcessor(OutputSurface* output_surface)
- : OverlayProcessorMac(std::make_unique<MockCALayerOverlayProcessor>()) {}
- ~TestOverlayProcessor() override = default;
-
- MockCALayerOverlayProcessor* GetTestProcessor() {
- return static_cast<MockCALayerOverlayProcessor*>(GetOverlayProcessor());
- }
-};
-
-#elif BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
-
-class TestOverlayProcessor : public OverlayProcessorUsingStrategy {
- public:
- class TestStrategy : public OverlayProcessorStrategy {
- public:
- TestStrategy() = default;
- ~TestStrategy() override = default;
-
- MOCK_METHOD8(
- Attempt,
- bool(const SkM44& output_color_matrix,
- const OverlayProcessorInterface::FilterOperationsMap&
- render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const OverlayProcessorInterface::OutputSurfaceOverlayPlane*
- primary_surface,
- OverlayCandidateList* candidates,
- std::vector<gfx::Rect>* content_bounds));
-
- void ProposePrioritized(
- const SkM44& output_color_matrix,
- const FilterOperationsMap& render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- std::vector<OverlayProposedCandidate>* candidates,
- std::vector<gfx::Rect>* content_bounds) override {
- auto* render_pass = render_pass_list->back().get();
- QuadList& quad_list = render_pass->quad_list;
- OverlayCandidate candidate;
- candidates->push_back({quad_list.end(), candidate, this});
- }
-
- MOCK_METHOD9(AttemptPrioritized,
- bool(const SkM44& output_color_matrix,
- const FilterOperationsMap& render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- OverlayCandidateList* candidates,
- std::vector<gfx::Rect>* content_bounds,
- const OverlayProposedCandidate& proposed_candidate));
-
- MOCK_METHOD2(CommitCandidate,
- void(const OverlayProposedCandidate& proposed_candidate,
- AggregatedRenderPass* render_pass));
- };
-
- bool IsOverlaySupported() const override { return true; }
-
- // A list of possible overlay candidates is presented to this function.
- // The expected result is that those candidates that can be in a separate
- // plane are marked with |overlay_handled| set to true, otherwise they are
- // to be traditionally composited. Candidates with |overlay_handled| set to
- // true must also have their |display_rect| converted to integer
- // coordinates if necessary.
- void CheckOverlaySupportImpl(
- const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
- OverlayCandidateList* surfaces) override {}
-
- TestStrategy& strategy() {
- auto* strategy = strategies_.back().get();
- return *(static_cast<TestStrategy*>(strategy));
- }
-
- MOCK_CONST_METHOD0(NeedsSurfaceDamageRectList, bool());
- explicit TestOverlayProcessor(OutputSurface* output_surface) {
- strategies_.push_back(std::make_unique<TestStrategy>());
- prioritization_config_.changing_threshold = false;
- prioritization_config_.damage_rate_threshold = false;
- }
- ~TestOverlayProcessor() override = default;
-};
-#else // Default to no overlay.
-class TestOverlayProcessor : public OverlayProcessorStub {
- public:
- explicit TestOverlayProcessor(OutputSurface* output_surface)
- : OverlayProcessorStub() {}
- ~TestOverlayProcessor() override = default;
-};
-#endif
-
-void MailboxReleased(const gpu::SyncToken& sync_token, bool lost_resource) {}
-
-static void CollectResources(std::vector<ReturnedResource>* array,
- std::vector<ReturnedResource> returned) {
- array->insert(array->end(), std::make_move_iterator(returned.begin()),
- std::make_move_iterator(returned.end()));
-}
-
-TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d());
-#if BUILDFLAG(IS_WIN)
- output_surface->set_supports_dc_layers(true);
-#endif
- output_surface->BindToClient(&output_surface_client);
-
- auto parent_resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- auto child_context_provider = TestContextProvider::Create();
- child_context_provider->BindToCurrentThread();
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
- gfx::Size(256, 256), true);
- auto release_callback = base::BindOnce(&MailboxReleased);
- ResourceId resource_id = child_resource_provider->ImportResource(
- transfer_resource, std::move(release_callback));
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = parent_resource_provider->CreateChild(
- base::BindRepeating(&CollectResources, &returned_to_child), SurfaceId());
-
- // Transfer resource to the parent.
- std::vector<ResourceId> resource_ids_to_transfer;
- resource_ids_to_transfer.push_back(resource_id);
- std::vector<TransferableResource> list;
- child_resource_provider->PrepareSendToParent(
- resource_ids_to_transfer, &list,
- static_cast<RasterContextProvider*>(child_context_provider.get()));
- parent_resource_provider->ReceiveFromChild(child_id, list);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- parent_resource_provider->GetChildToParentMap(child_id);
- ResourceId parent_resource_id = resource_map[list[0].id];
-
- auto processor = std::make_unique<TestOverlayProcessor>(output_surface.get());
-
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- parent_resource_provider.get(), processor.get(),
- base::ThreadTaskRunnerHandle::Get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
-#if BUILDFLAG(IS_APPLE)
- MockCALayerOverlayProcessor* mock_ca_processor =
- processor->GetTestProcessor();
-#elif BUILDFLAG(IS_WIN)
- MockDCLayerOverlayProcessor* dc_processor = processor->GetTestProcessor();
-#endif
-
- gfx::Size viewport_size(1, 1);
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
- root_pass->copy_requests.push_back(CopyOutputRequest::CreateStubForTesting());
-
- bool needs_blending = false;
- bool premultiplied_alpha = false;
- bool flipped = false;
- bool nearest_neighbor = false;
- float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
-
- TextureDrawQuad* overlay_quad =
- root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- overlay_quad->SetNew(
- root_pass->CreateAndAppendSharedQuadState(), gfx::Rect(viewport_size),
- gfx::Rect(viewport_size), needs_blending, parent_resource_id,
- premultiplied_alpha, gfx::PointF(0, 0), gfx::PointF(1, 1),
- SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor,
- /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
-
- // DirectRenderer::DrawFrame calls into OverlayProcessor::ProcessForOverlays.
- // Attempt will be called for each strategy in OverlayProcessor. We have
- // added a fake strategy, so checking for Attempt calls checks if there was
- // any attempt to overlay, which there shouldn't be. We can't use the quad
- // list because the render pass is cleaned up by DrawFrame.
-#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
- if (features::IsOverlayPrioritizationEnabled()) {
- EXPECT_CALL(processor->strategy(),
- AttemptPrioritized(_, _, _, _, _, _, _, _, _))
- .Times(0);
- } else {
- EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _))
- .Times(0);
- }
-#elif BUILDFLAG(IS_APPLE)
- EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _))
- .WillOnce(Return(false));
-#elif BUILDFLAG(IS_WIN)
- EXPECT_CALL(*dc_processor, Process(_, _, _, _, _, _, _, _)).Times(0);
-#endif
- DrawFrame(&renderer, viewport_size);
-#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
- Mock::VerifyAndClearExpectations(&processor->strategy());
-#elif BUILDFLAG(IS_APPLE)
- Mock::VerifyAndClearExpectations(
- const_cast<MockCALayerOverlayProcessor*>(mock_ca_processor));
-#elif BUILDFLAG(IS_WIN)
- Mock::VerifyAndClearExpectations(
- const_cast<MockDCLayerOverlayProcessor*>(dc_processor));
-#endif
-
- // Without a copy request Attempt() should be called once.
- root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
-
- overlay_quad = root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- overlay_quad->SetNew(
- root_pass->CreateAndAppendSharedQuadState(), gfx::Rect(viewport_size),
- gfx::Rect(viewport_size), needs_blending, parent_resource_id,
- premultiplied_alpha, gfx::PointF(0, 0), gfx::PointF(1, 1),
- SK_ColorTRANSPARENT, vertex_opacity, flipped, nearest_neighbor,
- /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
-#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
- if (features::IsOverlayPrioritizationEnabled()) {
- EXPECT_CALL(processor->strategy(),
- AttemptPrioritized(_, _, _, _, _, _, _, _, _))
- .Times(1);
- } else {
- EXPECT_CALL(processor->strategy(), Attempt(_, _, _, _, _, _, _, _))
- .Times(1);
- }
-#elif BUILDFLAG(IS_APPLE)
- EXPECT_CALL(*mock_ca_processor, ProcessForCALayerOverlays(_, _, _, _, _, _))
- .WillOnce(Return(true));
-#elif BUILDFLAG(IS_WIN)
- EXPECT_CALL(*dc_processor, Process(_, _, _, _, _, _, _, _)).Times(1);
-#endif
- DrawFrame(&renderer, viewport_size);
-
- // Transfer resources back from the parent to the child. Set no resources as
- // being in use.
- parent_resource_provider->DeclareUsedResourcesFromChild(child_id,
- ResourceIdSet());
-
- child_resource_provider->RemoveImportedResource(resource_id);
- child_resource_provider->ShutdownAndReleaseAllResources();
-}
-
-#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
-class SingleOverlayOnTopProcessor : public OverlayProcessorUsingStrategy {
- public:
- SingleOverlayOnTopProcessor() : OverlayProcessorUsingStrategy() {
- strategies_.push_back(std::make_unique<OverlayStrategySingleOnTop>(this));
- strategies_.push_back(std::make_unique<OverlayStrategyUnderlay>(this));
- prioritization_config_.changing_threshold = false;
- prioritization_config_.damage_rate_threshold = false;
- }
-
- bool NeedsSurfaceDamageRectList() const override { return true; }
- bool IsOverlaySupported() const override { return true; }
-
- void CheckOverlaySupportImpl(
- const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
- OverlayCandidateList* surfaces) override {
- if (!multiple_candidates_)
- ASSERT_EQ(1U, surfaces->size());
- OverlayCandidate& candidate = surfaces->back();
- candidate.overlay_handled = true;
- }
-
- void AllowMultipleCandidates() { multiple_candidates_ = true; }
-
- private:
- bool multiple_candidates_ = false;
-};
-
-class WaitSyncTokenCountingGLES2Interface : public TestGLES2Interface {
- public:
- MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token));
-};
-
-class MockOverlayScheduler {
- public:
- MOCK_METHOD7(Schedule,
- void(int plane_z_order,
- gfx::OverlayTransform plane_transform,
- unsigned overlay_texture_id,
- const gfx::Rect& display_bounds,
- const gfx::RectF& uv_rect,
- bool enable_blend,
- unsigned gpu_fence_id));
-};
-
-TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
- auto gl_owned = std::make_unique<WaitSyncTokenCountingGLES2Interface>();
- WaitSyncTokenCountingGLES2Interface* gl = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- MockOverlayScheduler overlay_scheduler;
- provider->support()->SetScheduleOverlayPlaneCallback(base::BindRepeating(
- &MockOverlayScheduler::Schedule, base::Unretained(&overlay_scheduler)));
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<OutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto parent_resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- auto child_context_provider = TestContextProvider::Create();
- child_context_provider->BindToCurrentThread();
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(0x123), 29);
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, sync_token,
- gfx::Size(256, 256), true);
- auto release_callback = base::BindOnce(&MailboxReleased);
- ResourceId resource_id = child_resource_provider->ImportResource(
- transfer_resource, std::move(release_callback));
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = parent_resource_provider->CreateChild(
- base::BindRepeating(&CollectResources, &returned_to_child), SurfaceId());
-
- // Transfer resource to the parent.
- std::vector<ResourceId> resource_ids_to_transfer;
- resource_ids_to_transfer.push_back(resource_id);
- std::vector<TransferableResource> list;
- child_resource_provider->PrepareSendToParent(
- resource_ids_to_transfer, &list,
- static_cast<RasterContextProvider*>(child_context_provider.get()));
- parent_resource_provider->ReceiveFromChild(child_id, list);
-
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- parent_resource_provider->GetChildToParentMap(child_id);
- ResourceId parent_resource_id = resource_map[list[0].id];
-
- RendererSettings settings;
- auto processor = std::make_unique<SingleOverlayOnTopProcessor>();
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- parent_resource_provider.get(), processor.get(),
- base::ThreadTaskRunnerHandle::Get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(1, 1);
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
-
- bool needs_blending = false;
- bool premultiplied_alpha = false;
- bool flipped = false;
- bool nearest_neighbor = false;
- float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- gfx::PointF uv_top_left(0, 0);
- gfx::PointF uv_bottom_right(1, 1);
-
- TextureDrawQuad* overlay_quad =
- root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(viewport_size), gfx::MaskFilterInfo(),
- absl::nullopt, false, 1, SkBlendMode::kSrcOver, 0);
- overlay_quad->SetNew(shared_state, gfx::Rect(viewport_size),
- gfx::Rect(viewport_size), needs_blending,
- parent_resource_id, premultiplied_alpha, uv_top_left,
- uv_bottom_right, SK_ColorTRANSPARENT, vertex_opacity,
- flipped, nearest_neighbor, /*secure_output_only=*/false,
- gfx::ProtectedVideoType::kClear);
-
- // The verified flush flag will be set by
- // ClientResourceProvider::PrepareSendToParent. Before checking if the
- // gpu::SyncToken matches, set this flag first.
- sync_token.SetVerifyFlush();
-
- // Verify that overlay_quad actually gets turned into an overlay, and even
- // though it's not drawn, that its sync point is waited on.
- EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(MatchesSyncToken(sync_token)))
- .Times(1);
-
- EXPECT_CALL(
- overlay_scheduler,
- Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, gfx::Rect(viewport_size),
- BoundingRect(uv_top_left, uv_bottom_right), _, _))
- .Times(1);
-
- DrawFrame(&renderer, viewport_size);
-
- // Transfer resources back from the parent to the child. Set no resources as
- // being in use.
- parent_resource_provider->DeclareUsedResourcesFromChild(child_id,
- ResourceIdSet());
-
- child_resource_provider->RemoveImportedResource(resource_id);
- child_resource_provider->ShutdownAndReleaseAllResources();
-}
-#endif // defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
-
-class OutputColorMatrixMockGLES2Interface : public TestGLES2Interface {
- public:
- OutputColorMatrixMockGLES2Interface() = default;
-
- MOCK_METHOD4(UniformMatrix4fv,
- void(GLint location,
- GLsizei count,
- GLboolean transpose,
- const GLfloat* value));
-};
-
-TEST_F(GLRendererTest, OutputColorMatrixTest) {
- // Initialize the mock GL interface, the output surface and the renderer.
- auto gl_owned = std::make_unique<OutputColorMatrixMockGLES2Interface>();
- auto* gl = gl_owned.get();
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
- std::unique_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- cc::FakeOutputSurfaceClient output_surface_client;
- output_surface->BindToClient(&output_surface_client);
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- // Set a non-identity color matrix on the output surface.
- SkM44 color_matrix;
- color_matrix.setRC(0, 0, 0.7f);
- color_matrix.setRC(1, 1, 0.4f);
- color_matrix.setRC(2, 2, 0.5f);
- output_surface->set_color_matrix(color_matrix);
-
- // Create a root and a child passes to test that the output color matrix is
- // registered only for the root pass.
- gfx::Size viewport_size(100, 100);
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(viewport_size) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
- cc::AddRenderPassQuad(root_pass, child_pass);
-
- // Verify that UniformMatrix4fv() is called only once on the root pass with
- // the correct matrix values.
- int call_count = 0;
- bool output_color_matrix_invoked = false;
- EXPECT_CALL(*gl, UniformMatrix4fv(_, 1, false, _))
- .WillRepeatedly(testing::WithArgs<0, 3>(testing::Invoke(
- [&color_matrix, &renderer, &call_count, &output_color_matrix_invoked](
- int matrix_location, const GLfloat* gl_matrix) {
- DCHECK(current_program(&renderer));
- const int color_matrix_location =
- current_program(&renderer)->output_color_matrix_location();
-
- if (matrix_location != color_matrix_location)
- return;
-
- call_count++;
- output_color_matrix_invoked = true;
- float expected_matrix[16];
- color_matrix.getColMajor(expected_matrix);
- for (int i = 0; i < 16; ++i)
- EXPECT_FLOAT_EQ(expected_matrix[i], gl_matrix[i]);
- })));
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
-
- EXPECT_EQ(1, call_count);
- EXPECT_TRUE(output_color_matrix_invoked);
-}
-
-class GenerateMipmapMockGLESInterface : public TestGLES2Interface {
- public:
- GenerateMipmapMockGLESInterface() = default;
-
- MOCK_METHOD3(TexParameteri, void(GLenum target, GLenum pname, GLint param));
- MOCK_METHOD1(GenerateMipmap, void(GLenum target));
-};
-
-// TODO(crbug.com/803286): Currently npot texture always return false on ubuntu
-// desktop. The npot texture check is probably failing on desktop GL. This test
-// crashes DCHECK npot texture to catch this. When
-// GLRendererPixelTest.DISABLED_TrilinearFiltering got passed, can remove this.
-TEST_F(GLRendererTest, GenerateMipmap) {
- // Initialize the mock GL interface, the output surface and the renderer.
- auto gl_owned = std::make_unique<GenerateMipmapMockGLESInterface>();
- gl_owned->set_support_texture_npot(true);
-
- auto* gl = gl_owned.get();
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- std::unique_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- cc::FakeOutputSurfaceClient output_surface_client;
- output_surface->BindToClient(&output_surface_client);
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
- RendererSettings settings;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
- AggregatedRenderPassId child_pass_id{2};
- // Create a child pass with mipmap to verify that npot texture is enabled.
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(viewport_size) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- child_pass->generate_mipmap = true;
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(0, 0, 25, 25);
- cc::AddRenderPassQuad(root_pass, child_pass);
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- EXPECT_CALL(*gl, TexParameteri(_, _, _)).Times(4);
- EXPECT_CALL(*gl, GenerateMipmap(GL_TEXTURE_2D)).Times(1);
- // When generate_mipmap enabled, the GL_TEXTURE_MIN_FILTER should be
- // GL_LINEAR_MIPMAP_LINEAR.
- EXPECT_CALL(*gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_LINEAR_MIPMAP_LINEAR));
- DrawFrame(&renderer, viewport_size);
-}
-
-class FastSolidColorMockGLES2Interface : public TestGLES2Interface {
- public:
- FastSolidColorMockGLES2Interface() = default;
-
- MOCK_METHOD1(Enable, void(GLenum cap));
- MOCK_METHOD1(Disable, void(GLenum cap));
- MOCK_METHOD4(ClearColor,
- void(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha));
- MOCK_METHOD4(Scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
-};
-
-class GLRendererFastSolidColorTest : public GLRendererTest {
- public:
- void SetUp() override {
- feature_list_.InitAndEnableFeature(features::kFastSolidColorDraw);
- GLRendererTest::SetUp();
-
- auto gl_owned = std::make_unique<FastSolidColorMockGLES2Interface>();
- gl_owned->set_have_post_sub_buffer(true);
- gl_ = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- output_surface_ = FakeOutputSurface::Create3d(std::move(provider));
- output_surface_->BindToClient(&output_surface_client_);
-
- resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
-
- settings_.partial_swap_enabled = true;
- settings_.slow_down_compositing_scale_factor = 1;
- settings_.allow_antialiasing = true;
-
- fake_renderer_ = std::make_unique<FakeRendererGL>(
- &settings_, &debug_settings_, output_surface_.get(),
- resource_provider_.get());
- fake_renderer_->Initialize();
- EXPECT_TRUE(fake_renderer_->use_partial_swap());
- fake_renderer_->SetVisible(true);
- }
-
- void TearDown() override {
- resource_provider_.reset();
- fake_renderer_.reset();
- output_surface_.reset();
- gl_ = nullptr;
-
- GLRendererTest::TearDown();
- }
-
- FastSolidColorMockGLES2Interface* gl_ptr() { return gl_; }
-
- FakeOutputSurface* output_surface() { return output_surface_.get(); }
-
- protected:
- void AddExpectations(bool use_fast_path,
- const gfx::Rect& scissor_rect,
- SkColor color = SK_ColorBLACK,
- bool enable_stencil = false) {
- auto* gl = gl_ptr();
-
- InSequence seq;
-
- // Restore GL state method calls
- EXPECT_CALL(*gl, Disable(GL_DEPTH_TEST));
- EXPECT_CALL(*gl, Disable(GL_CULL_FACE));
- EXPECT_CALL(*gl, Disable(GL_STENCIL_TEST));
- EXPECT_CALL(*gl, Enable(GL_BLEND));
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
-
- if (!enable_stencil)
- EXPECT_CALL(*gl, ClearColor(0, 0, 0, 0));
-
- if (use_fast_path) {
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
- scissor_rect.width(), scissor_rect.height()));
-
- SkColor4f color_f = SkColor4f::FromColor(color);
- EXPECT_CALL(*gl,
- ClearColor(color_f.fR, color_f.fG, color_f.fB, color_f.fA));
-
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
- }
-
- if (enable_stencil) {
- EXPECT_CALL(*gl, Enable(GL_STENCIL_TEST));
- EXPECT_CALL(*gl, Disable(GL_BLEND));
- }
-
- EXPECT_CALL(*gl, Disable(GL_BLEND));
- }
-
- void RunTest(const gfx::Size& viewport_size) {
- fake_renderer_->DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(fake_renderer_.get(), viewport_size);
-
- auto* gl = gl_ptr();
- ASSERT_TRUE(gl);
- Mock::VerifyAndClearExpectations(gl);
- }
-
- private:
- FastSolidColorMockGLES2Interface* gl_ = nullptr;
- std::unique_ptr<FakeRendererGL> fake_renderer_;
- std::unique_ptr<FakeOutputSurface> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- cc::FakeOutputSurfaceClient output_surface_client_;
- RendererSettings settings_;
- base::test::ScopedFeatureList feature_list_;
-};
-
-TEST_F(GLRendererFastSolidColorTest, RoundedCorners) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_output_rect(400, 400);
- gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
- gfx::Rect quad_rect(0, 50, 100, 100);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPassWithDamage(
- &render_passes_in_draw_order_, root_pass_id, root_pass_output_rect,
- root_pass_damage_rect, gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
- cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
-
- root_pass->shared_quad_state_list.front()->mask_filter_info =
- gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(quad_rect), 5.f));
-
- // Fast Solid color draw quads should not be executed.
- AddExpectations(false /*use_fast_path*/, gfx::Rect());
-
- RunTest(viewport_size);
-}
-
-TEST_F(GLRendererFastSolidColorTest, Transform3DSlowPath) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
- gfx::Rect quad_rect(0, 50, 100, 100);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
- cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
-
- gfx::Transform tm_3d;
- tm_3d.RotateAboutYAxis(30.0);
- ASSERT_FALSE(tm_3d.IsFlat());
-
- root_pass->shared_quad_state_list.front()->quad_to_target_transform = tm_3d;
-
- AddExpectations(false /*use_fast_path*/, gfx::Rect());
-
- RunTest(viewport_size);
-}
-
-TEST_F(GLRendererFastSolidColorTest, NonTransform3DFastPath) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
- gfx::Rect quad_rect(0, 0, 200, 200);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
- cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
-
- gfx::Transform tm_non_3d;
- tm_non_3d.Translate(10.f, 10.f);
- ASSERT_TRUE(tm_non_3d.IsFlat());
-
- root_pass->shared_quad_state_list.front()->quad_to_target_transform =
- tm_non_3d;
-
- AddExpectations(true /*use_fast_path*/, gfx::Rect(10, 290, 200, 200),
- SK_ColorRED);
-
- RunTest(viewport_size);
-}
-
-TEST_F(GLRendererFastSolidColorTest, NonAxisAlignSlowPath) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
- gfx::Rect quad_rect(0, 0, 200, 200);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
- cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
-
- gfx::Transform tm_non_axis_align;
- tm_non_axis_align.RotateAboutZAxis(45.0);
- ASSERT_TRUE(tm_non_axis_align.IsFlat());
-
- root_pass->shared_quad_state_list.front()->quad_to_target_transform =
- tm_non_axis_align;
-
- AddExpectations(false /*use_fast_path*/, gfx::Rect());
-
- RunTest(viewport_size);
-}
-
-TEST_F(GLRendererFastSolidColorTest, StencilSlowPath) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
- gfx::Rect quad_rect(0, 0, 200, 200);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
- root_pass->has_transparent_background = false;
-
- cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
-
- AddExpectations(false /*use_fast_path*/, gfx::Rect(), SK_ColorRED,
- true /*enable_stencil*/);
- output_surface()->set_has_external_stencil_test(true);
-
- RunTest(viewport_size);
-}
-
-TEST_F(GLRendererFastSolidColorTest, NeedsBlendingSlowPath) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_damage_rect(2, 3, 300, 200);
- gfx::Rect full_quad_rect(0, 0, 50, 50);
- gfx::Rect quad_rect_1(0, 0, 20, 20);
- gfx::Rect quad_rect_2(20, 0, 20, 20);
- gfx::Rect quad_rect_3(0, 20, 20, 20);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
-
- cc::AddQuad(root_pass, quad_rect_1, SkColorSetARGB(0x33, 0xFF, 0, 0));
-
- cc::AddQuad(root_pass, quad_rect_2, SK_ColorBLUE);
- root_pass->shared_quad_state_list.back()->opacity = 0.5f;
-
- cc::AddQuad(root_pass, quad_rect_3, SK_ColorGREEN);
- root_pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kDstIn;
-
- cc::AddQuad(root_pass, full_quad_rect, SK_ColorBLACK);
-
- // The first solid color quad would use a fast path, but the other quads that
- // require blending will use the slower method.
- AddExpectations(true /*use_fast_path*/, gfx::Rect(0, 450, 50, 50),
- SK_ColorBLACK, false /*enable_stencil*/);
-
- RunTest(viewport_size);
-}
-
-TEST_F(GLRendererFastSolidColorTest, NeedsBlendingFastPath) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_damage_rect(2, 3, 300, 200);
- gfx::Rect quad_rect_1(0, 0, 20, 20);
- gfx::Rect quad_rect_2(20, 0, 20, 20);
- gfx::Rect quad_rect_3(0, 20, 20, 20);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
-
- cc::AddQuad(root_pass, quad_rect_1, SkColorSetARGB(0x33, 0xFF, 0, 0));
-
- cc::AddQuad(root_pass, quad_rect_2, SK_ColorBLUE);
- root_pass->shared_quad_state_list.back()->opacity = 0.5f;
-
- cc::AddQuad(root_pass, quad_rect_3, SK_ColorGREEN);
- root_pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kSrc;
-
- auto* gl = gl_ptr();
-
- // The quads here despite having blend requirements can still use fast path
- // because they do not intersect with any other quad that has already been
- // drawn onto the render target.
- InSequence seq;
-
- // // Restore GL state method calls
- EXPECT_CALL(*gl, Disable(GL_DEPTH_TEST));
- EXPECT_CALL(*gl, Disable(GL_CULL_FACE));
- EXPECT_CALL(*gl, Disable(GL_STENCIL_TEST));
- EXPECT_CALL(*gl, Enable(GL_BLEND));
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
- EXPECT_CALL(*gl, ClearColor(0, 0, 0, 0));
-
- // Fast path draw used for green quad.
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 460, 20, 20));
- EXPECT_CALL(*gl, ClearColor(0, 1, 0, 1));
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
-
- // Fast path draw used for blue quad.
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(20, 480, 20, 20));
- EXPECT_CALL(*gl, ClearColor(0, 0, 0.5f, 0.5f));
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
-
- // Fast path draw used for red quad.
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 480, 20, 20));
- EXPECT_CALL(*gl, ClearColor(::testing::FloatEq(0.2f), 0, 0,
- ::testing::FloatEq(0.2f)));
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
-
- EXPECT_CALL(*gl, Disable(GL_BLEND));
-
- RunTest(viewport_size);
-}
-
-TEST_F(GLRendererFastSolidColorTest, AntiAliasSlowPath) {
- gfx::Size viewport_size(500, 500);
- gfx::Rect root_pass_damage_rect(10, 20, 300, 200);
- gfx::Rect quad_rect(0, 0, 200, 200);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = root_pass_damage_rect;
- cc::AddQuad(root_pass, quad_rect, SK_ColorRED);
-
- gfx::Transform tm_aa;
- tm_aa.Translate(0.1f, 0.1f);
- ASSERT_TRUE(tm_aa.IsFlat());
-
- root_pass->shared_quad_state_list.front()->quad_to_target_transform = tm_aa;
-
- AddExpectations(false /*use_fast_path*/, gfx::Rect());
-
- RunTest(viewport_size);
-}
-
-class PartialSwapMockGLES2Interface : public TestGLES2Interface {
- public:
- PartialSwapMockGLES2Interface() = default;
-
- MOCK_METHOD1(Enable, void(GLenum cap));
- MOCK_METHOD1(Disable, void(GLenum cap));
- MOCK_METHOD4(Scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
- MOCK_METHOD1(SetEnableDCLayersCHROMIUM, void(GLboolean enable));
-};
-
-class GLRendererPartialSwapTest : public GLRendererTest {
- public:
- void SetUp() override {
- // Force enable fast solid color draw path.
- scoped_feature_list_.InitAndEnableFeature(features::kFastSolidColorDraw);
- GLRendererTest::SetUp();
- }
-
- protected:
- void RunTest(bool partial_swap, bool set_draw_rectangle) {
- auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>();
- gl_owned->set_have_post_sub_buffer(true);
-
- auto* gl = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->set_supports_dc_layers(set_draw_rectangle);
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- settings.partial_swap_enabled = partial_swap;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- EXPECT_EQ(partial_swap, renderer.use_partial_swap());
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
- gfx::Rect root_pass_output_rect(80, 80);
- gfx::Rect root_pass_damage_rect(2, 2, 3, 3);
-
- // Draw one black frame to make sure the output surface is reshaped before
- // tests.
- EXPECT_CALL(*gl, Disable(GL_DEPTH_TEST)).Times(1);
- EXPECT_CALL(*gl, Disable(GL_CULL_FACE)).Times(1);
- EXPECT_CALL(*gl, Disable(GL_STENCIL_TEST)).Times(1);
- EXPECT_CALL(*gl, Enable(GL_BLEND)).Times(1);
-
- if (output_surface->capabilities().supports_dc_layers) {
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST)).Times(1);
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0)).Times(1);
-
- // Root render pass requires a scissor if the output surface supports
- // dc layers.
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST)).Times(3);
- EXPECT_CALL(*gl, Scissor(0, 0, 100, 100)).Times(3);
- } else {
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST)).Times(2);
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0)).Times(2);
- if (set_draw_rectangle) {
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST)).Times(2);
- EXPECT_CALL(*gl, Scissor(0, 0, 100, 100)).Times(2);
- } else {
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST)).Times(1);
- EXPECT_CALL(*gl, Scissor(0, 0, 100, 100)).Times(1);
- }
- }
-
- EXPECT_CALL(*gl, Disable(GL_BLEND)).Times(1);
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- root_pass->damage_rect = gfx::Rect(viewport_size);
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorBLACK);
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(gl);
-
- for (int i = 0; i < 2; ++i) {
- root_pass = cc::AddRenderPassWithDamage(
- &render_passes_in_draw_order_, root_pass_id, root_pass_output_rect,
- root_pass_damage_rect, gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(root_pass_output_rect), SK_ColorGREEN);
-
- InSequence seq;
-
- // A bunch of initialization that happens.
- EXPECT_CALL(*gl, Disable(GL_DEPTH_TEST));
- EXPECT_CALL(*gl, Disable(GL_CULL_FACE));
- EXPECT_CALL(*gl, Disable(GL_STENCIL_TEST));
- EXPECT_CALL(*gl, Enable(GL_BLEND));
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
-
- // Partial frame, we should use a scissor to swap only that part when
- // partial swap is enabled.
- gfx::Rect output_rectangle =
- partial_swap ? root_pass_damage_rect : gfx::Rect(viewport_size);
-
- // The scissor is flipped, so subtract the y coord and height from the
- // bottom of the GL viewport.
- gfx::Rect scissor_rect(output_rectangle.x(),
- viewport_size.height() - output_rectangle.y() -
- output_rectangle.height(),
- output_rectangle.width(),
- output_rectangle.height());
-
- // Drawing the solid color quad using glClear and scissor rect.
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
- scissor_rect.width(), scissor_rect.height()));
-
- if (partial_swap || set_draw_rectangle) {
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
- scissor_rect.width(), scissor_rect.height()));
- }
-
- // Restore GL state after solid color draw quad.
- if (partial_swap || set_draw_rectangle) {
- EXPECT_CALL(*gl, Enable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(scissor_rect.x(), scissor_rect.y(),
- scissor_rect.width(), scissor_rect.height()));
- } else {
- EXPECT_CALL(*gl, Disable(GL_SCISSOR_TEST));
- EXPECT_CALL(*gl, Scissor(0, 0, 0, 0));
- }
-
- // Blending is disabled at the end of the frame.
- EXPECT_CALL(*gl, Disable(GL_BLEND));
-
- renderer.DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
-
- if (set_draw_rectangle) {
- EXPECT_EQ(output_rectangle, output_surface->last_set_draw_rectangle());
- }
-
- Mock::VerifyAndClearExpectations(gl);
- }
- }
-
- private:
- base::test::ScopedFeatureList scoped_feature_list_;
-};
-
-TEST_F(GLRendererPartialSwapTest, PartialSwap) {
- RunTest(true, false);
-}
-
-TEST_F(GLRendererPartialSwapTest, NoPartialSwap) {
- RunTest(false, false);
-}
-
-#if BUILDFLAG(IS_WIN)
-TEST_F(GLRendererPartialSwapTest, SetDrawRectangle_PartialSwap) {
- RunTest(true, true);
-}
-
-TEST_F(GLRendererPartialSwapTest, SetDrawRectangle_NoPartialSwap) {
- RunTest(false, true);
-}
-
-// Test that SetEnableDCLayersCHROMIUM is properly called when enabling
-// and disabling DC layers.
-TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
- auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>();
- gl_owned->set_have_post_sub_buffer(true);
- auto* gl = gl_owned.get();
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->set_supports_dc_layers(true);
- output_surface->BindToClient(&output_surface_client);
-
- auto parent_resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- auto child_context_provider = TestContextProvider::Create();
- child_context_provider->BindToCurrentThread();
- auto child_resource_provider = std::make_unique<ClientResourceProvider>();
-
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
- gfx::Size(256, 256), true);
- auto release_callback = base::BindOnce(&MailboxReleased);
- ResourceId resource_id = child_resource_provider->ImportResource(
- transfer_resource, std::move(release_callback));
-
- std::vector<ReturnedResource> returned_to_child;
- int child_id = parent_resource_provider->CreateChild(
- base::BindRepeating(&CollectResources, &returned_to_child), SurfaceId());
-
- // Transfer resource to the parent.
- std::vector<ResourceId> resource_ids_to_transfer;
- resource_ids_to_transfer.push_back(resource_id);
- std::vector<TransferableResource> list;
- child_resource_provider->PrepareSendToParent(
- resource_ids_to_transfer, &list,
- static_cast<RasterContextProvider*>(child_context_provider.get()));
- parent_resource_provider->ReceiveFromChild(child_id, list);
- // In DisplayResourceProvider's namespace, use the mapped resource id.
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- parent_resource_provider->GetChildToParentMap(child_id);
- ResourceId parent_resource_id = resource_map[list[0].id];
-
- auto processor = std::make_unique<OverlayProcessorWin>(
- output_surface.get(),
- std::make_unique<DCLayerOverlayProcessor>(
- &debug_settings_, /*allowed_yuv_overlay_count=*/1, true));
-
- RendererSettings settings;
- settings.partial_swap_enabled = true;
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- parent_resource_provider.get(), processor.get());
- renderer.Initialize();
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
-
- for (int i = 0; i < 65; i++) {
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- if (i == 0) {
- gfx::Rect rect(0, 0, 100, 100);
- bool needs_blending = false;
- gfx::RectF tex_coord_rect(0, 0, 1, 1);
- SharedQuadState* shared_state =
- root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), rect, rect, gfx::MaskFilterInfo(),
- absl::nullopt, false, 1, SkBlendMode::kSrcOver, 0);
- YUVVideoDrawQuad* quad =
- root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
- quad->SetNew(shared_state, rect, rect, needs_blending, tex_coord_rect,
- tex_coord_rect, rect.size(), rect.size(), parent_resource_id,
- parent_resource_id, parent_resource_id, parent_resource_id,
- gfx::ColorSpace(), 0, 1.0, 8);
- }
-
- // A bunch of initialization that happens.
- EXPECT_CALL(*gl, Disable(_)).Times(AnyNumber());
- EXPECT_CALL(*gl, Enable(_)).Times(AnyNumber());
- EXPECT_CALL(*gl, Scissor(_, _, _, _)).Times(AnyNumber());
-
- // Partial frame, we should use a scissor to swap only that part when
- // partial swap is enabled.
- root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
- // Frame 0 should be completely damaged because it's the first.
- // Frame 1 should be because it changed. Frame 60 should be
- // because it's disabling DC layers.
- gfx::Rect output_rectangle = (i == 0 || i == 1 || i == 60)
- ? root_pass->output_rect
- : root_pass->damage_rect;
-
- // Frame 0 should have DC Layers enabled because of the overlay.
- // After 60 frames of no overlays DC layers should be disabled again.
- if (i == 0)
- EXPECT_CALL(*gl, SetEnableDCLayersCHROMIUM(GL_TRUE));
- else if (i == 60)
- EXPECT_CALL(*gl, SetEnableDCLayersCHROMIUM(GL_FALSE));
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- EXPECT_EQ(output_rectangle, output_surface->last_set_draw_rectangle());
- testing::Mock::VerifyAndClearExpectations(gl);
- }
-
- // Transfer resources back from the parent to the child. Set no resources as
- // being in use.
- parent_resource_provider->DeclareUsedResourcesFromChild(child_id,
- ResourceIdSet());
-
- child_resource_provider->RemoveImportedResource(resource_id);
- child_resource_provider->ShutdownAndReleaseAllResources();
-}
-#endif
-
-class GLRendererWithMockContextTest : public ::testing::Test {
- protected:
- class MockContextSupport : public TestContextSupport {
- public:
- MockContextSupport() {}
- MOCK_METHOD1(SetAggressivelyFreeResources,
- void(bool aggressively_free_resources));
- };
-
- void SetUp() override {
- auto context_support = std::make_unique<MockContextSupport>();
- context_support_ptr_ = context_support.get();
- auto context_provider =
- TestContextProvider::Create(std::move(context_support));
- ASSERT_EQ(context_provider->BindToCurrentThread(),
- gpu::ContextResult::kSuccess);
- output_surface_ = FakeOutputSurface::Create3d(std::move(context_provider));
- output_surface_->BindToClient(&output_surface_client_);
- resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
- renderer_ = std::make_unique<GLRenderer>(
- &settings_, &debug_settings_, output_surface_.get(),
- resource_provider_.get(), nullptr, nullptr);
- renderer_->Initialize();
- }
-
- RendererSettings settings_;
- DebugRendererSettings debug_settings_;
- cc::FakeOutputSurfaceClient output_surface_client_;
- MockContextSupport* context_support_ptr_;
- std::unique_ptr<OutputSurface> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- std::unique_ptr<GLRenderer> renderer_;
-};
-
-TEST_F(GLRendererWithMockContextTest,
- ContextPurgedWhenRendererBecomesInvisible) {
- EXPECT_CALL(*context_support_ptr_, SetAggressivelyFreeResources(false));
- renderer_->SetVisible(true);
- Mock::VerifyAndClearExpectations(context_support_ptr_);
-
- EXPECT_CALL(*context_support_ptr_, SetAggressivelyFreeResources(true));
- renderer_->SetVisible(false);
- Mock::VerifyAndClearExpectations(context_support_ptr_);
-}
-
-#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
-class ContentBoundsOverlayProcessor : public OverlayProcessorUsingStrategy {
- public:
- class TestStrategy : public OverlayProcessorStrategy {
- public:
- explicit TestStrategy(const std::vector<gfx::Rect>& content_bounds)
- : content_bounds_(content_bounds) {}
- ~TestStrategy() override = default;
-
- bool Attempt(const SkM44& output_color_matrix,
- const OverlayProcessorInterface::FilterOperationsMap&
- render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- OverlayCandidateList* candidates,
- std::vector<gfx::Rect>* content_bounds) override {
- content_bounds->insert(content_bounds->end(), content_bounds_.begin(),
- content_bounds_.end());
- return true;
- }
-
- void ProposePrioritized(
- const SkM44& output_color_matrix,
- const FilterOperationsMap& render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- std::vector<OverlayProposedCandidate>* candidates,
- std::vector<gfx::Rect>* content_bounds) override {
- auto* render_pass = render_pass_list->back().get();
- QuadList& quad_list = render_pass->quad_list;
- OverlayCandidate candidate;
- // Adding a mock candidate to the propose list so that
- // 'AttemptPrioritized' will be called.
- candidates->push_back({quad_list.end(), candidate, this});
- }
-
- bool AttemptPrioritized(
- const SkM44& output_color_matrix,
- const FilterOperationsMap& render_pass_backdrop_filters,
- DisplayResourceProvider* resource_provider,
- AggregatedRenderPassList* render_pass_list,
- SurfaceDamageRectList* surface_damage_rect_list,
- const PrimaryPlane* primary_plane,
- OverlayCandidateList* candidates,
- std::vector<gfx::Rect>* content_bounds,
- const OverlayProposedCandidate& proposed_candidate) override {
- content_bounds->insert(content_bounds->end(), content_bounds_.begin(),
- content_bounds_.end());
- return true;
- }
-
- void CommitCandidate(const OverlayProposedCandidate& proposed_candidate,
- AggregatedRenderPass* render_pass) override {}
-
- private:
- const std::vector<gfx::Rect> content_bounds_;
- };
-
- explicit ContentBoundsOverlayProcessor(
- const std::vector<gfx::Rect>& content_bounds)
- : OverlayProcessorUsingStrategy(), content_bounds_(content_bounds) {
- strategies_.push_back(
- std::make_unique<TestStrategy>(std::move(content_bounds_)));
- prioritization_config_.changing_threshold = false;
- prioritization_config_.damage_rate_threshold = false;
- }
-
- TestStrategy& strategy() {
- return static_cast<TestStrategy&>(*strategies_.back());
- }
- // Empty mock methods since this test set up uses strategies, which are only
- // for ozone and android.
- MOCK_CONST_METHOD0(NeedsSurfaceDamageRectList, bool());
- bool IsOverlaySupported() const override { return true; }
-
- // A list of possible overlay candidates is presented to this function.
- // The expected result is that those candidates that can be in a separate
- // plane are marked with |overlay_handled| set to true, otherwise they are
- // to be traditionally composited. Candidates with |overlay_handled| set to
- // true must also have their |display_rect| converted to integer
- // coordinates if necessary.
- void CheckOverlaySupportImpl(
- const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
- OverlayCandidateList* surfaces) override {}
-
- private:
- std::vector<gfx::Rect> content_bounds_;
-};
-
-class GLRendererSwapWithBoundsTest : public GLRendererTest {
- protected:
- void RunTest(const std::vector<gfx::Rect>& content_bounds) {
- auto gl_owned = std::make_unique<TestGLES2Interface>();
- gl_owned->set_have_swap_buffers_with_bounds(true);
-
- auto provider = TestContextProvider::Create(std::move(gl_owned));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- std::unique_ptr<FakeOutputSurface> output_surface(
- FakeOutputSurface::Create3d(std::move(provider)));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- RendererSettings settings;
- auto processor =
- std::make_unique<ContentBoundsOverlayProcessor>(content_bounds);
- FakeRendererGL renderer(&settings, &debug_settings_, output_surface.get(),
- resource_provider.get(), processor.get());
- renderer.Initialize();
- EXPECT_EQ(true, renderer.use_swap_with_bounds());
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
-
- {
- AggregatedRenderPassId root_pass_id{1};
- cc::AddRenderPass(&render_passes_in_draw_order_, root_pass_id,
- gfx::Rect(viewport_size), gfx::Transform(),
- cc::FilterOperations());
-
- renderer.DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
- renderer.SwapBuffers({});
-
- std::vector<gfx::Rect> expected_content_bounds;
- EXPECT_EQ(content_bounds,
- output_surface->last_sent_frame()->content_bounds);
- }
- }
-};
-
-TEST_F(GLRendererSwapWithBoundsTest, EmptyContent) {
- std::vector<gfx::Rect> content_bounds;
- RunTest(content_bounds);
-}
-
-TEST_F(GLRendererSwapWithBoundsTest, NonEmpty) {
- std::vector<gfx::Rect> content_bounds;
- content_bounds.push_back(gfx::Rect(0, 0, 10, 10));
- content_bounds.push_back(gfx::Rect(20, 20, 30, 30));
- RunTest(content_bounds);
-}
-#endif // defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
-
-#if BUILDFLAG(IS_APPLE)
-class MockCALayerGLES2Interface : public TestGLES2Interface {
- public:
- MOCK_METHOD6(ScheduleCALayerSharedStateCHROMIUM,
- void(GLfloat opacity,
- GLboolean is_clipped,
- const GLfloat* clip_rect,
- const GLfloat* rounded_corner_bounds,
- GLint sorting_context_id,
- const GLfloat* transform));
- MOCK_METHOD6(ScheduleCALayerCHROMIUM,
- void(GLuint contents_texture_id,
- const GLfloat* contents_rect,
- GLuint background_color,
- GLuint edge_aa_mask,
- const GLfloat* bounds_rect,
- GLuint filter));
- MOCK_METHOD2(ScheduleCALayerInUseQueryCHROMIUM,
- void(GLsizei count, const GLuint* textures));
- MOCK_METHOD5(
- Uniform4f,
- void(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w));
-};
-
-class CALayerGLRendererTest : public GLRendererTest {
- protected:
- void SetUp() override {
- // A mock GLES2Interface that can watch CALayer stuff happen.
- auto gles2_interface = std::make_unique<MockCALayerGLES2Interface>();
- // Support image storage for GpuMemoryBuffers, needed for
- // CALayers/IOSurfaces backed by textures.
- gles2_interface->set_support_texture_storage_image(true);
- // Allow the renderer to make an empty SwapBuffers - skipping even the
- // root RenderPass.
- gles2_interface->set_have_commit_overlay_planes(true);
-
- gl_ = gles2_interface.get();
-
- auto provider = TestContextProvider::Create(std::move(gles2_interface));
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- output_surface_ = FakeOutputSurface::Create3d(std::move(provider));
- output_surface_->BindToClient(&output_surface_client);
-
- display_resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
-
- settings_ = std::make_unique<RendererSettings>();
- // This setting is enabled to use CALayer overlays.
- settings_->release_overlay_resources_after_gpu_query = true;
- // The Mac TestOverlayProcessor default to enable CALayer overlays, then all
- // damage is removed and we can skip the root RenderPass, swapping empty.
- overlay_processor_ = std::make_unique<OverlayProcessorMac>(
- std::make_unique<CALayerOverlayProcessor>());
- renderer_ = std::make_unique<FakeRendererGL>(
- settings_.get(), &debug_settings_, output_surface_.get(),
- display_resource_provider_.get(), overlay_processor_.get(),
- base::ThreadTaskRunnerHandle::Get());
- renderer_->Initialize();
- renderer_->SetVisible(true);
- }
-
- void TearDown() override {
- renderer_.reset();
- display_resource_provider_.reset();
- output_surface_.reset();
- }
-
- void DrawBlackFrame(const gfx::Size& viewport_size) {
- AggregatedRenderPassId root_pass_id{1};
-
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorBLACK);
-
- renderer().DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
-
- DrawFrame(&renderer(), viewport_size);
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
- }
-
- MockCALayerGLES2Interface& gl() const { return *gl_; }
- FakeRendererGL& renderer() const { return *renderer_; }
- FakeOutputSurface& output_surface() const { return *output_surface_; }
-
- private:
- MockCALayerGLES2Interface* gl_;
- std::unique_ptr<FakeOutputSurface> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> display_resource_provider_;
- std::unique_ptr<RendererSettings> settings_;
- std::unique_ptr<OverlayProcessorInterface> overlay_processor_;
- std::unique_ptr<FakeRendererGL> renderer_;
-};
-
-TEST_F(CALayerGLRendererTest, CALayerOverlaysWithAllQuadsPromoted) {
- gfx::Size viewport_size(10, 10);
-
- // Draw an empty frame to make sure output surface is reshaped before tests.
- DrawBlackFrame(viewport_size);
-
- // This frame has a root pass with a CompositorRenderPassDrawQuad pointing to
- // a child pass that is at 1,2 to make it identifiable.
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPassId root_pass_id{1};
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(viewport_size) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child pass is drawn, promoted to an overlay, and scheduled as a
- // CALayer.
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
-
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // The damage was eliminated when everything was promoted to CALayers.
- ASSERT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect);
- EXPECT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect->IsEmpty());
-
- // Frame number 2. Same inputs, except...
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(viewport_size) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
-
- // Use a cached RenderPass for the child.
- child_pass->cache_render_pass = true;
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child CompositorRenderPassDrawQuad gets promoted again, but importantly
- // it did not itself have to be drawn this time as it can use the cached
- // texture. Because we can skip the child pass, and the root pass (all quads
- // were promoted), this exposes edge cases in GLRenderer if it assumes we draw
- // at least one RenderPass. This still works, doesn't crash, etc, and the
- // CompositorRenderPassDrawQuad is emitted.
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
-
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-}
-
-TEST_F(CALayerGLRendererTest, CALayerRoundRects) {
- gfx::Size viewport_size(10, 10);
-
- // Draw an empty frame to make sure output surface is reshaped before tests.
- DrawBlackFrame(viewport_size);
-
- for (size_t subtest = 0; subtest < 3; ++subtest) {
- AggregatedRenderPass* child_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(250, 250), gfx::Transform(), cc::FilterOperations());
-
- AggregatedRenderPassId root_pass_id{1};
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- auto* quad = cc::AddRenderPassQuad(root_pass, child_pass);
- SharedQuadState* sqs =
- const_cast<SharedQuadState*>(quad->shared_quad_state);
-
- sqs->clip_rect = gfx::Rect(2, 2, 6, 6);
- const float radius = 2;
- sqs->mask_filter_info =
- gfx::MaskFilterInfo(gfx::RRectF(gfx::RectF(*sqs->clip_rect), radius));
-
- switch (subtest) {
- case 0:
- // Subtest 0 is a simple round rect that matches the clip rect, and
- // should be handled by CALayers.
- EXPECT_CALL(gl(), Uniform4f(_, _, _, _, _)).Times(1);
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _))
- .Times(1);
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _)).Times(1);
- break;
- case 1:
- // Subtest 1 doesn't match clip and rounded rect, but we can still
- // use CALayers.
- sqs->clip_rect = gfx::Rect(3, 3, 4, 4);
- EXPECT_CALL(gl(), Uniform4f(_, _, _, _, _)).Times(1);
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _)).Times(1);
- break;
- case 2:
- // Subtest 2 has a non-simple rounded rect.
- gfx::RRectF rounded_corner_bounds =
- sqs->mask_filter_info.rounded_corner_bounds();
- rounded_corner_bounds.SetCornerRadii(gfx::RRectF::Corner::kUpperLeft, 1,
- 1);
- sqs->mask_filter_info = gfx::MaskFilterInfo(rounded_corner_bounds);
- // Called 2 extra times in order to set up the rounded corner
- // parameters in the shader, because the CALayer is not handling
- // the rounded corners.
- EXPECT_CALL(gl(), Uniform4f(_, _, _, _, _)).Times(3);
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _)).Times(0);
- break;
- }
-
- renderer().DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- }
-}
-
-TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) {
- gfx::Size viewport_size(300, 300);
-
- // Draw an empty frame to make sure output surface is reshaped before tests.
- DrawBlackFrame(viewport_size);
-
- // This frame has a root pass with a CompositorRenderPassDrawQuad pointing to
- // a child pass that is at 1,2 to make it identifiable. The child's size is
- // 250x251, but it will be rounded up to a multiple of 64 in order to promote
- // easier texture reuse. See https://crbug.com/146070.
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPassId root_pass_id{1};
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(250, 251) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child pass is drawn, promoted to an overlay, and scheduled as a
- // CALayer. The bounds of the texture are rounded up to 256x256. We save the
- // texture ID to make sure we reuse it correctly.
- uint32_t saved_texture_id = 0;
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- // The size is rounded to a multiple of 64.
- EXPECT_EQ(256, bounds_rect[2]);
- EXPECT_EQ(256, bounds_rect[3]);
- saved_texture_id = contents_texture_id;
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // ScheduleCALayerCHROMIUM happened and used a non-0 texture.
- EXPECT_NE(saved_texture_id, 0u);
-
- // The damage was eliminated when everything was promoted to CALayers.
- ASSERT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect);
- EXPECT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect->IsEmpty());
-
- // The texture will be checked to verify if it is free yet.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
-
- // Frame number 2. We change the size of the child RenderPass to be smaller
- // than the next multiple of 64, but larger than half the previous size so
- // that our texture reuse heuristics will reuse the texture if it is free.
- // For now, it is not.
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(190, 191) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child RenderPass will use a new 192x192 texture, since the last texture
- // is still in use.
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // New texture id.
- EXPECT_NE(saved_texture_id, contents_texture_id);
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- // The texture is 192x192 since we snap up to multiples of 64.
- EXPECT_EQ(192, bounds_rect[2]);
- EXPECT_EQ(192, bounds_rect[3]);
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // There are now 2 textures to check if they are free.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
-
- // The first (256x256) texture is returned to the GLRenderer.
- renderer().DidReceiveTextureInUseResponses({{saved_texture_id, false}});
-
- // Frame number 3 looks just like frame number 2. The child RenderPass is
- // smaller than the next multiple of 64 from the released texture, but larger
- // than half of its size so that our texture reuse heuristics will kick in.
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(190, 191) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child RenderPass would try to use a 192x192 texture, but since we have
- // an existing 256x256 texture, we can reuse that.
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // The first texture is reused.
- EXPECT_EQ(saved_texture_id, contents_texture_id);
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- // The size here is the size of the texture being used, not
- // the size we tried to use (192x192).
- EXPECT_EQ(256, bounds_rect[2]);
- EXPECT_EQ(256, bounds_rect[3]);
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-}
-
-TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) {
- gfx::Size viewport_size(300, 300);
-
- // Draw an empty frame to make sure output surface is reshaped before tests.
- DrawBlackFrame(viewport_size);
-
- // This frame has a root pass with a CompositorRenderPassDrawQuad pointing to
- // a child pass that is at 1,2 to make it identifiable. The child's size is
- // 250x251, but it will be rounded up to a multiple of 64 in order to promote
- // easier texture reuse. See https://crbug.com/146070.
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPassId root_pass_id{1};
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(250, 251) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child pass is drawn, promoted to an overlay, and scheduled as a
- // CALayer. The bounds of the texture are rounded up to 256x256. We save the
- // texture ID to make sure we reuse it correctly.
- uint32_t saved_texture_id = 0;
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- // The size is rounded to a multiple of 64.
- EXPECT_EQ(256, bounds_rect[2]);
- EXPECT_EQ(256, bounds_rect[3]);
- saved_texture_id = contents_texture_id;
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // ScheduleCALayerCHROMIUM happened and used a non-0 texture.
- EXPECT_NE(saved_texture_id, 0u);
-
- // The damage was eliminated when everything was promoted to CALayers.
- ASSERT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect);
- EXPECT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect->IsEmpty());
-
- // The texture will be checked to verify if it is free yet.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
-
- // Frame number 2. We change the size of the child RenderPass to be much
- // smaller.
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(20, 21) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child RenderPass will use a new 64x64 texture, since the last texture
- // is still in use.
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // New texture id.
- EXPECT_NE(saved_texture_id, contents_texture_id);
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- // The texture is 64x64 since we snap up to multiples of 64.
- EXPECT_EQ(64, bounds_rect[2]);
- EXPECT_EQ(64, bounds_rect[3]);
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // There are now 2 textures to check if they are free.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
-
- // The first (256x256) texture is returned to the GLRenderer.
- renderer().DidReceiveTextureInUseResponses({{saved_texture_id, false}});
-
- // Frame number 3 looks just like frame number 2. The child RenderPass is
- // too small to reuse the old texture.
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(20, 21) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child RenderPass would try to use a 64x64 texture. We have a free and
- // existing 256x256 texture, but it's too large for us to reuse it.
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // The first texture is not reused.
- EXPECT_NE(saved_texture_id, contents_texture_id);
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- // The new texture has a smaller size.
- EXPECT_EQ(64, bounds_rect[2]);
- EXPECT_EQ(64, bounds_rect[3]);
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-}
-
-TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseAfterNoSwapBuffers) {
- gfx::Size viewport_size(300, 300);
-
- // This frame has a root pass with a CompositorRenderPassDrawQuad pointing to
- // a child pass that is at 1,2 to make it identifiable.
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPassId root_pass_id{1};
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(100, 100) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The child pass is drawn, promoted to an overlay, and scheduled as a
- // CALayer. We save the texture ID to make sure we reuse it correctly.
- uint32_t saved_texture_id = 0;
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- saved_texture_id = contents_texture_id;
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
-
- // ScheduleCALayerCHROMIUM happened and used a non-0 texture.
- EXPECT_NE(saved_texture_id, 0u);
-
- // SwapBuffers() is *not* called though! Display can do this sometimes.
-
- // Frame number 2. We can not reuse the texture since the last one isn't
- // returned yet. We use a different size so we can control which texture gets
- // reused later.
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(200, 200) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- uint32_t second_saved_texture_id = 0;
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // New texture id.
- EXPECT_NE(saved_texture_id, contents_texture_id);
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- second_saved_texture_id = contents_texture_id;
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
-
- // SwapBuffers() *does* happen this time.
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // There are 2 textures to check if they are free.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
-
- // Both textures get returned and the 2nd one can be reused.
- renderer().DidReceiveTextureInUseResponses(
- {{saved_texture_id, false}, {second_saved_texture_id, false}});
-
- // Frame number 3 looks just like frame number 2.
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(200, 200) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- // The 2nd texture that we sent has been returned so we can reuse it. We
- // verify that happened.
- {
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // The second texture is reused.
- EXPECT_EQ(second_saved_texture_id, contents_texture_id);
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- }));
- }
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-}
-
-TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseManyIfReturnedSlowly) {
- gfx::Size viewport_size(300, 300);
-
- // Draw an empty frame to make sure output surface is reshaped before tests.
- DrawBlackFrame(viewport_size);
-
- // Each frame has a root pass with a CompositorRenderPassDrawQuad pointing to
- // a child pass. We generate a bunch of frames and swap them, each with a
- // different child RenderPass id, without getting any of the resources back
- // from the OS.
- AggregatedRenderPassId root_pass_id{1};
-
- // The number is at least 2 larger than the number of textures we expect to
- // reuse, so that we can leave one in the OS, and have 1 texture returned but
- // not reused.
- const int kNumSendManyTextureIds = 7;
- uint32_t sent_texture_ids[kNumSendManyTextureIds];
- for (int i = 0; i < kNumSendManyTextureIds; ++i) {
- AggregatedRenderPass* child_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{i + 2},
- gfx::Rect(250, 251) + gfx::Vector2d(1, 2), gfx::Transform(),
- cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
-
- renderer().DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
-
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- sent_texture_ids[i] = contents_texture_id;
- }));
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // ScheduleCALayerCHROMIUM happened and used a non-0 texture.
- EXPECT_NE(sent_texture_ids[i], 0u);
-
- // The damage was eliminated when everything was promoted to CALayers.
- ASSERT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect);
- EXPECT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect->IsEmpty());
-
- // All sent textures will be checked to verify if they are free yet.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(i + 1, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
- }
-
- // Now all but 1 texture get returned by the OS, so they are all inserted
- // into the cache for reuse.
- std::vector<uint32_t> returned_texture_ids;
- for (int i = 0; i < kNumSendManyTextureIds - 1; ++i) {
- uint32_t id = sent_texture_ids[i];
- renderer().DidReceiveTextureInUseResponses({{id, false}});
- returned_texture_ids.push_back(id);
- }
-
- // We should keep *some* of these textures around to reuse them across
- // multiple frames. https://crbug.com/146070 motivates this, and empirical
- // testing found 5 to be a good number.
- const int kNumSendReusedTextures = 5;
- // See comment on |kNumSendManyTextureIds|.
- ASSERT_LT(kNumSendReusedTextures, kNumSendManyTextureIds - 1);
-
- for (int i = 0; i < kNumSendReusedTextures + 1; ++i) {
- // We use different RenderPass ids to ensure that the cache allows reuse
- // even if they don't match.
- AggregatedRenderPass* child_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{i + 100},
- gfx::Rect(250, 251) + gfx::Vector2d(1, 2), gfx::Transform(),
- cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
-
- renderer().DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
-
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(Invoke([&](GLuint contents_texture_id,
- const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
-
- if (i < kNumSendReusedTextures) {
- // The texture id should be from the set of returned ones.
- EXPECT_THAT(returned_texture_ids, Contains(contents_texture_id));
- base::Erase(returned_texture_ids, contents_texture_id);
- } else {
- // More textures were returned at once than we expect to reuse
- // so eventually we should be making a new texture to show we're
- // not just keeping infinity textures in the cache.
- EXPECT_THAT(returned_texture_ids,
- Not(Contains(contents_texture_id)));
- // This shows that there was some returned id that we didn't use.
- EXPECT_FALSE(returned_texture_ids.empty());
- }
- }));
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // All sent textures will be checked to verify if they are free yet. There's
- // also 1 outstanding texture to check for that wasn't returned yet from the
- // above loop.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(i + 2, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
- }
-}
-
-TEST_F(CALayerGLRendererTest, CALayerOverlaysCachedTexturesAreFreed) {
- gfx::Size viewport_size(300, 300);
-
- // Draw an empty frame to make sure output surface is reshaped before tests.
- DrawBlackFrame(viewport_size);
-
- // Each frame has a root pass with a CompositorRenderPassDrawQuad pointing to
- // a child pass. We generate a bunch of frames and swap them, each with a
- // different child RenderPass id, without getting any of the resources back
- // from the OS.
- AggregatedRenderPassId child_pass_id{2};
- AggregatedRenderPassId root_pass_id{1};
-
- // We send a whole bunch of textures as overlays to the OS.
- const int kNumSendManyTextureIds = 7;
- uint32_t sent_texture_ids[kNumSendManyTextureIds];
- for (int i = 0; i < kNumSendManyTextureIds; ++i) {
- AggregatedRenderPass* child_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{i + 2},
- gfx::Rect(250, 251) + gfx::Vector2d(1, 2), gfx::Transform(),
- cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
-
- renderer().DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
-
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(
- Invoke([&](GLuint contents_texture_id, const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
- sent_texture_ids[i] = contents_texture_id;
- }));
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // ScheduleCALayerCHROMIUM happened and used a non-0 texture.
- EXPECT_NE(sent_texture_ids[i], 0u);
-
- // The damage was eliminated when everything was promoted to CALayers.
- ASSERT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect);
- EXPECT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect->IsEmpty());
-
- // All sent textures will be checked to verify if they are free yet.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(i + 1, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
- }
-
- // Now all but 1 texture get returned by the OS, so they are all inserted
- // into the cache for reuse.
- std::vector<uint32_t> returned_texture_ids;
- for (int i = 0; i < kNumSendManyTextureIds - 1; ++i) {
- uint32_t id = sent_texture_ids[i];
- renderer().DidReceiveTextureInUseResponses({{id, false}});
- returned_texture_ids.push_back(id);
- }
-
- // We generate a bunch of frames that don't use the cache, one less than the
- // number of textures returned.
- for (int i = 0; i < kNumSendManyTextureIds - 2; ++i) {
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(100, 100), SK_ColorRED);
-
- renderer().DecideRenderPassAllocationsForFrame(
- render_passes_in_draw_order_);
-
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _));
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-
- // There's just 1 outstanding RenderPass texture to query for.
- EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _));
- renderer().SwapBuffersComplete(/*release_fence=*/gfx::GpuFenceHandle());
- Mock::VerifyAndClearExpectations(&gl());
- }
-
- // By now the cache should be empty, to show that we don't keep cached
- // textures that won't be used forever. We generate a frame with a
- // CompositorRenderPassDrawQuad and verify that it does not reuse a texture
- // from the (empty) cache.
- {
- AggregatedRenderPass* child_pass =
- cc::AddRenderPass(&render_passes_in_draw_order_, child_pass_id,
- gfx::Rect(250, 251) + gfx::Vector2d(1, 2),
- gfx::Transform(), cc::FilterOperations());
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
- gfx::Transform(), cc::FilterOperations());
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- }
-
- renderer().DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
-
- InSequence sequence;
- EXPECT_CALL(gl(), ScheduleCALayerSharedStateCHROMIUM(_, _, _, _, _, _));
- EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _))
- .WillOnce(Invoke([&](GLuint contents_texture_id,
- const GLfloat* contents_rect,
- GLuint background_color, GLuint edge_aa_mask,
- const GLfloat* bounds_rect, GLuint filter) {
- // This is the child CompositorRenderPassDrawQuad.
- EXPECT_EQ(1, bounds_rect[0]);
- EXPECT_EQ(2, bounds_rect[1]);
-
- // More textures were returned at once than we expect to reuse
- // so eventually we should be making a new texture to show we're
- // not just keeping infinity textures in the cache.
- EXPECT_THAT(returned_texture_ids, Not(Contains(contents_texture_id)));
- // This shows that there was some returned id that we didn't use.
- EXPECT_FALSE(returned_texture_ids.empty());
- }));
- DrawFrame(&renderer(), viewport_size);
- Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(DirectRenderer::SwapFrameData());
-}
-#endif
-
-class FramebufferWatchingGLRenderer : public FakeRendererGL {
- public:
- FramebufferWatchingGLRenderer(RendererSettings* settings,
- const DebugRendererSettings* debug_settings,
- OutputSurface* output_surface,
- DisplayResourceProviderGL* resource_provider)
- : FakeRendererGL(settings,
- debug_settings,
- output_surface,
- resource_provider) {}
-
- void BindFramebufferToOutputSurface() override {
- ++bind_root_framebuffer_calls_;
- FakeRendererGL::BindFramebufferToOutputSurface();
- }
-
- void BindFramebufferToTexture(
- const AggregatedRenderPassId render_pass_id) override {
- ++bind_child_framebuffer_calls_;
- FakeRendererGL::BindFramebufferToTexture(render_pass_id);
- }
-
- int bind_root_framebuffer_calls() const {
- return bind_root_framebuffer_calls_;
- }
- int bind_child_framebuffer_calls() const {
- return bind_child_framebuffer_calls_;
- }
-
- void ResetBindCalls() {
- bind_root_framebuffer_calls_ = bind_child_framebuffer_calls_ = 0;
- }
-
- private:
- int bind_root_framebuffer_calls_ = 0;
- int bind_child_framebuffer_calls_ = 0;
-};
-
-TEST_F(GLRendererTest, UndamagedRenderPassStillDrawnWhenNoPartialSwap) {
- auto provider = TestContextProvider::Create();
- provider->UnboundTestContextGL()->set_have_post_sub_buffer(true);
- provider->BindToCurrentThread();
-
- cc::FakeOutputSurfaceClient output_surface_client;
- auto output_surface = FakeOutputSurface::Create3d(std::move(provider));
- output_surface->BindToClient(&output_surface_client);
-
- auto resource_provider = std::make_unique<DisplayResourceProviderGL>(
- output_surface->context_provider());
-
- for (int i = 0; i < 2; ++i) {
- bool use_partial_swap = i == 0;
- SCOPED_TRACE(use_partial_swap);
-
- RendererSettings settings;
- settings.partial_swap_enabled = use_partial_swap;
- FramebufferWatchingGLRenderer renderer(&settings, &debug_settings_,
- output_surface.get(),
- resource_provider.get());
- renderer.Initialize();
- EXPECT_EQ(use_partial_swap, renderer.use_partial_swap());
- renderer.SetVisible(true);
-
- gfx::Size viewport_size(100, 100);
- gfx::Rect child_rect(10, 10);
-
- // First frame, the child and root RenderPass each have damage.
- AggregatedRenderPass* child_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{2}, child_rect,
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(child_pass, child_rect, SK_ColorGREEN);
- child_pass->damage_rect = child_rect;
-
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorRED);
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- root_pass->damage_rect = gfx::Rect(viewport_size);
-
- EXPECT_EQ(0, renderer.bind_root_framebuffer_calls());
- EXPECT_EQ(0, renderer.bind_child_framebuffer_calls());
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
-
- // We had to draw the root, and the child.
- EXPECT_EQ(1, renderer.bind_child_framebuffer_calls());
- // When the CompositorRenderPassDrawQuad in the root is drawn, we may
- // re-bind the root framebuffer. So it can be bound more than once.
- EXPECT_GE(renderer.bind_root_framebuffer_calls(), 1);
-
- // Reset counting.
- renderer.ResetBindCalls();
-
- // Second frame, the child RenderPass has no damage in it.
- child_pass = cc::AddRenderPass(&render_passes_in_draw_order_,
- AggregatedRenderPassId{2}, child_rect,
- gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(child_pass, child_rect, SK_ColorGREEN);
- child_pass->damage_rect = gfx::Rect();
-
- // Root RenderPass has some damage that doesn't intersect the child.
- root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- cc::AddQuad(root_pass, gfx::Rect(viewport_size), SK_ColorRED);
- cc::AddRenderPassQuad(root_pass, child_pass, kInvalidResourceId,
- gfx::Transform(), SkBlendMode::kSrcOver);
- root_pass->damage_rect = gfx::Rect(child_rect.right(), 0, 10, 10);
-
- EXPECT_EQ(0, renderer.bind_root_framebuffer_calls());
- EXPECT_EQ(0, renderer.bind_child_framebuffer_calls());
-
- renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- DrawFrame(&renderer, viewport_size);
-
- if (use_partial_swap) {
- // Without damage overlapping the child, it didn't need to be drawn (it
- // may choose to anyway but that'd be a waste). So we don't check for
- // |bind_child_framebuffer_calls|. But the root should have been drawn.
- EXPECT_EQ(renderer.bind_root_framebuffer_calls(), 1);
- } else {
- // Without partial swap, we have to draw the child still, this means
- // the child is bound as the framebuffer.
- EXPECT_EQ(1, renderer.bind_child_framebuffer_calls());
- // When the CompositorRenderPassDrawQuad in the root is drawn, as it must
- // be since we must draw the entire output, we may re-bind the root
- // framebuffer. So it can be bound more than once.
- EXPECT_GE(renderer.bind_root_framebuffer_calls(), 1);
- }
- }
-}
-
-#if defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
-class GLRendererWithGpuFenceTest : public GLRendererTest {
- protected:
- GLRendererWithGpuFenceTest() {
- auto provider = TestContextProvider::Create();
- provider->BindToCurrentThread();
- provider->TestContextGL()->set_have_commit_overlay_planes(true);
- test_context_support_ = provider->support();
-
- output_surface_ = FakeOutputSurface::Create3d(std::move(provider));
- output_surface_->set_overlay_texture_id(kSurfaceOverlayTextureId);
- output_surface_->set_gpu_fence_id(kGpuFenceId);
- resource_provider_ = std::make_unique<DisplayResourceProviderGL>(
- output_surface_->context_provider());
- overlay_processor_ = std::make_unique<SingleOverlayOnTopProcessor>();
- overlay_processor_->AllowMultipleCandidates();
- renderer_ = std::make_unique<FakeRendererGL>(
- &settings_, &debug_settings_, output_surface_.get(),
- resource_provider_.get(), overlay_processor_.get(),
- base::ThreadTaskRunnerHandle::Get());
- renderer_->Initialize();
- renderer_->SetVisible(true);
-
- test_context_support_->SetScheduleOverlayPlaneCallback(
- base::BindRepeating(&MockOverlayScheduler::Schedule,
- base::Unretained(&overlay_scheduler_)));
- }
-
- ~GLRendererWithGpuFenceTest() override {
- if (child_resource_provider_)
- child_resource_provider_->ShutdownAndReleaseAllResources();
- }
-
- ResourceId create_overlay_resource() {
- child_context_provider_ = TestContextProvider::Create();
- child_context_provider_->BindToCurrentThread();
-
- child_resource_provider_ = std::make_unique<ClientResourceProvider>();
- auto transfer_resource = TransferableResource::MakeGL(
- gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
- gfx::Size(256, 256), true);
- ResourceId client_resource_id = child_resource_provider_->ImportResource(
- transfer_resource, base::DoNothing());
-
- std::unordered_map<ResourceId, ResourceId, ResourceIdHasher> resource_map =
- cc::SendResourceAndGetChildToParentMap(
- {client_resource_id}, resource_provider_.get(),
- child_resource_provider_.get(), child_context_provider_.get());
- return resource_map[client_resource_id];
- }
-
- static constexpr unsigned kSurfaceOverlayTextureId = 33;
- static constexpr unsigned kGpuFenceId = 66;
- static constexpr unsigned kGpuNoFenceId = 0;
-
- TestContextSupport* test_context_support_;
-
- cc::FakeOutputSurfaceClient output_surface_client_;
- std::unique_ptr<FakeOutputSurface> output_surface_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
- scoped_refptr<TestContextProvider> child_context_provider_;
- std::unique_ptr<ClientResourceProvider> child_resource_provider_;
- RendererSettings settings_;
- std::unique_ptr<SingleOverlayOnTopProcessor> overlay_processor_;
- std::unique_ptr<FakeRendererGL> renderer_;
- MockOverlayScheduler overlay_scheduler_;
-};
-
-TEST_F(GLRendererWithGpuFenceTest, GpuFenceIdIsUsedWithRootRenderPassOverlay) {
- gfx::Size viewport_size(100, 100);
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
-
- EXPECT_CALL(overlay_scheduler_,
- Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, kSurfaceOverlayTextureId,
- gfx::Rect(viewport_size), _, _, kGpuFenceId))
- .Times(1);
- DrawFrame(renderer_.get(), viewport_size);
-}
-
-TEST_F(GLRendererWithGpuFenceTest,
- GpuFenceIdIsUsedOnlyForRootRenderPassOverlay) {
- gfx::Size viewport_size(100, 100);
- AggregatedRenderPass* root_pass = cc::AddRenderPass(
- &render_passes_in_draw_order_, AggregatedRenderPassId{1},
- gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations());
- root_pass->has_transparent_background = false;
-
- bool needs_blending = false;
- bool premultiplied_alpha = false;
- bool flipped = false;
- bool nearest_neighbor = false;
- float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- gfx::PointF uv_top_left(0, 0);
- gfx::PointF uv_bottom_right(1, 1);
-
- TextureDrawQuad* overlay_quad =
- root_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
- SharedQuadState* shared_state = root_pass->CreateAndAppendSharedQuadState();
- shared_state->SetAll(gfx::Transform(), gfx::Rect(viewport_size),
- gfx::Rect(50, 50), gfx::MaskFilterInfo(), absl::nullopt,
- false, 1, SkBlendMode::kSrcOver, 0);
- overlay_quad->SetNew(
- shared_state, gfx::Rect(viewport_size), gfx::Rect(viewport_size),
- needs_blending, create_overlay_resource(), premultiplied_alpha,
- uv_top_left, uv_bottom_right, SK_ColorTRANSPARENT, vertex_opacity,
- flipped, nearest_neighbor,
- /*secure_output_only=*/false, gfx::ProtectedVideoType::kClear);
-
- EXPECT_CALL(overlay_scheduler_,
- Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, kSurfaceOverlayTextureId,
- gfx::Rect(viewport_size), _, _, kGpuFenceId))
- .Times(1);
- EXPECT_CALL(overlay_scheduler_,
- Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _,
- gfx::Rect(viewport_size), _, _, kGpuNoFenceId))
- .Times(1);
- DrawFrame(renderer_.get(), viewport_size);
-}
-#endif // defined(USE_OZONE) || BUILDFLAG(IS_ANDROID)
-
-} // namespace
-} // namespace viz
diff --git a/chromium/components/viz/service/display/layer_quad.cc b/chromium/components/viz/service/display/layer_quad.cc
deleted file mode 100644
index d7349d86d79..00000000000
--- a/chromium/components/viz/service/display/layer_quad.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/layer_quad.h"
-
-#include <stddef.h>
-
-#include "base/check.h"
-#include "ui/gfx/geometry/quad_f.h"
-
-namespace viz {
-
-LayerQuad::Edge::Edge(const gfx::PointF& p, const gfx::PointF& q) {
- if (p == q) {
- degenerate_ = true;
- return;
- }
- degenerate_ = false;
- gfx::Vector2dF tangent(p.y() - q.y(), q.x() - p.x());
- float cross2 = p.x() * q.y() - q.x() * p.y();
-
- set(tangent.x(), tangent.y(), cross2);
- scale(1.0f / tangent.Length());
-}
-
-gfx::PointF LayerQuad::Edge::Intersect(const LayerQuad::Edge& e) const {
- DCHECK(!degenerate());
- DCHECK(!e.degenerate());
-
- return gfx::PointF((y() * e.z() - e.y() * z()) / (x() * e.y() - e.x() * y()),
- (x() * e.z() - e.x() * z()) / (e.x() * y() - x() * e.y()));
-}
-
-LayerQuad::LayerQuad(const gfx::QuadF& quad) {
- // Create edges.
- left_ = Edge(quad.p4(), quad.p1());
- right_ = Edge(quad.p2(), quad.p3());
- top_ = Edge(quad.p1(), quad.p2());
- bottom_ = Edge(quad.p3(), quad.p4());
-
- float sign = quad.IsCounterClockwise() ? -1 : 1;
- left_.scale(sign);
- right_.scale(sign);
- top_.scale(sign);
- bottom_.scale(sign);
-}
-
-LayerQuad::LayerQuad(const Edge& left,
- const Edge& top,
- const Edge& right,
- const Edge& bottom)
- : left_(left), top_(top), right_(right), bottom_(bottom) {}
-
-gfx::QuadF LayerQuad::ToQuadF() const {
- size_t num_degenerate_edges = left_.degenerate() + right_.degenerate() +
- top_.degenerate() + bottom_.degenerate();
- if (num_degenerate_edges > 1) {
- return gfx::QuadF();
- }
-
- if (left_.degenerate()) {
- return gfx::QuadF(top_.Intersect(bottom_), top_.Intersect(right_),
- right_.Intersect(bottom_), bottom_.Intersect(top_));
- }
- if (right_.degenerate()) {
- return gfx::QuadF(left_.Intersect(top_), top_.Intersect(bottom_),
- bottom_.Intersect(top_), bottom_.Intersect(left_));
- }
- if (top_.degenerate()) {
- return gfx::QuadF(left_.Intersect(right_), right_.Intersect(left_),
- right_.Intersect(bottom_), bottom_.Intersect(left_));
- }
- if (bottom_.degenerate()) {
- return gfx::QuadF(left_.Intersect(top_), top_.Intersect(right_),
- right_.Intersect(left_), left_.Intersect(right_));
- }
- return gfx::QuadF(left_.Intersect(top_), top_.Intersect(right_),
- right_.Intersect(bottom_), bottom_.Intersect(left_));
-}
-
-void LayerQuad::ToFloatArray(float flattened[12]) const {
- if (left_.degenerate()) {
- flattened[0] = bottom_.x();
- flattened[1] = bottom_.y();
- flattened[2] = bottom_.z();
- } else {
- flattened[0] = left_.x();
- flattened[1] = left_.y();
- flattened[2] = left_.z();
- }
- if (top_.degenerate()) {
- flattened[3] = left_.x();
- flattened[4] = left_.y();
- flattened[5] = left_.z();
- } else {
- flattened[3] = top_.x();
- flattened[4] = top_.y();
- flattened[5] = top_.z();
- }
- if (right_.degenerate()) {
- flattened[6] = top_.x();
- flattened[7] = top_.y();
- flattened[8] = top_.z();
- } else {
- flattened[6] = right_.x();
- flattened[7] = right_.y();
- flattened[8] = right_.z();
- }
- if (bottom_.degenerate()) {
- flattened[9] = right_.x();
- flattened[10] = right_.y();
- flattened[11] = right_.z();
- } else {
- flattened[9] = bottom_.x();
- flattened[10] = bottom_.y();
- flattened[11] = bottom_.z();
- }
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/layer_quad.h b/chromium/components/viz/service/display/layer_quad.h
deleted file mode 100644
index e6cd61fa457..00000000000
--- a/chromium/components/viz/service/display/layer_quad.h
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_LAYER_QUAD_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_LAYER_QUAD_H_
-
-#include "components/viz/service/viz_service_export.h"
-#include "ui/gfx/geometry/point_f.h"
-
-namespace gfx {
-class QuadF;
-}
-
-namespace viz {
-
-constexpr float kAntiAliasingInflateDistance = 0.5f;
-
-class VIZ_SERVICE_EXPORT LayerQuad {
- public:
- class VIZ_SERVICE_EXPORT Edge {
- public:
- Edge() : x_(0), y_(0), z_(0), degenerate_(false) {}
- Edge(const gfx::PointF& p, const gfx::PointF& q);
-
- float x() const { return x_; }
- float y() const { return y_; }
- float z() const { return z_; }
-
- void set_x(float x) { x_ = x; }
- void set_y(float y) { y_ = y; }
- void set_z(float z) { z_ = z; }
- void set(float x, float y, float z) {
- x_ = x;
- y_ = y;
- z_ = z;
- }
-
- void move_x(float dx) { x_ += dx; }
- void move_y(float dy) { y_ += dy; }
- void move_z(float dz) { z_ += dz; }
- void move(float dx, float dy, float dz) {
- x_ += dx;
- y_ += dy;
- z_ += dz;
- }
-
- void scale_x(float sx) { x_ *= sx; }
- void scale_y(float sy) { y_ *= sy; }
- void scale_z(float sz) { z_ *= sz; }
- void scale(float sx, float sy, float sz) {
- x_ *= sx;
- y_ *= sy;
- z_ *= sz;
- }
- void scale(float s) { scale(s, s, s); }
-
- bool degenerate() const { return degenerate_; }
-
- gfx::PointF Intersect(const Edge& e) const;
-
- private:
- float x_;
- float y_;
- float z_;
- bool degenerate_;
- };
-
- LayerQuad(const Edge& left,
- const Edge& top,
- const Edge& right,
- const Edge& bottom);
- explicit LayerQuad(const gfx::QuadF& quad);
-
- LayerQuad(const LayerQuad&) = delete;
- LayerQuad& operator=(const LayerQuad&) = delete;
-
- Edge left() const { return left_; }
- Edge top() const { return top_; }
- Edge right() const { return right_; }
- Edge bottom() const { return bottom_; }
-
- void InflateX(float dx) {
- left_.move_z(dx);
- right_.move_z(dx);
- }
- void InflateY(float dy) {
- top_.move_z(dy);
- bottom_.move_z(dy);
- }
- void Inflate(float d) {
- InflateX(d);
- InflateY(d);
- }
- void InflateAntiAliasingDistance() { Inflate(kAntiAliasingInflateDistance); }
-
- gfx::QuadF ToQuadF() const;
-
- void ToFloatArray(float flattened[12]) const;
-
- private:
- Edge left_;
- Edge top_;
- Edge right_;
- Edge bottom_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_LAYER_QUAD_H_
diff --git a/chromium/components/viz/service/display/layer_quad_unittest.cc b/chromium/components/viz/service/display/layer_quad_unittest.cc
deleted file mode 100644
index 6de10f5b62a..00000000000
--- a/chromium/components/viz/service/display/layer_quad_unittest.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/layer_quad.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/quad_f.h"
-
-namespace viz {
-namespace {
-
-TEST(LayerQuadTest, QuadFConversion) {
- gfx::PointF p1(-0.5f, -0.5f);
- gfx::PointF p2(0.5f, -0.5f);
- gfx::PointF p3(0.5f, 0.5f);
- gfx::PointF p4(-0.5f, 0.5f);
-
- gfx::QuadF quad_cw(p1, p2, p3, p4);
- LayerQuad layer_quad_cw(quad_cw);
- EXPECT_EQ(layer_quad_cw.ToQuadF(), quad_cw);
-
- gfx::QuadF quad_ccw(p1, p4, p3, p2);
- LayerQuad layer_quad_ccw(quad_ccw);
- EXPECT_EQ(layer_quad_ccw.ToQuadF(), quad_ccw);
-}
-
-TEST(LayerQuadTest, Inflate) {
- gfx::PointF p1(-0.5f, -0.5f);
- gfx::PointF p2(0.5f, -0.5f);
- gfx::PointF p3(0.5f, 0.5f);
- gfx::PointF p4(-0.5f, 0.5f);
-
- gfx::QuadF quad(p1, p2, p3, p4);
- LayerQuad layer_quad(quad);
- quad.Scale(2.f, 2.f);
- layer_quad.Inflate(0.5f);
- EXPECT_EQ(layer_quad.ToQuadF(), quad);
-}
-
-TEST(LayerQuadTest, Degenerate) {
- gfx::QuadF quad;
- gfx::PointF p1(1.0f, 1.0f);
- gfx::PointF p2(0.0f, 1.0f);
- gfx::PointF p3(1.0f, 0.0f);
- gfx::QuadF triangle(p1, p2, p3, p1);
-
- LayerQuad::Edge e1d(p1, p1);
- LayerQuad::Edge e2d(p2, p2);
- LayerQuad::Edge e2(p1, p2);
- LayerQuad::Edge e3(p2, p3);
- LayerQuad::Edge e4(p3, p1);
- EXPECT_TRUE(e1d.degenerate());
- EXPECT_TRUE(e2d.degenerate());
- EXPECT_FALSE(e2.degenerate());
- EXPECT_FALSE(e3.degenerate());
- EXPECT_FALSE(e4.degenerate());
-
- LayerQuad degenerate_quad(e1d, e2d, e2, e3);
- // With more than one degenerate edge, we expect the quad to be zero.
- EXPECT_EQ(quad, degenerate_quad.ToQuadF());
-
- LayerQuad triangle_quad(e1d, e2, e3, e4);
- // With only one degenerate edge, we expect the quad to be a triangle.
- EXPECT_EQ(triangle, triangle_quad.ToQuadF());
-}
-
-} // namespace
-} // namespace viz
diff --git a/chromium/components/viz/service/display/null_renderer.h b/chromium/components/viz/service/display/null_renderer.h
index fa291a47ae7..99935df341c 100644
--- a/chromium/components/viz/service/display/null_renderer.h
+++ b/chromium/components/viz/service/display/null_renderer.h
@@ -45,7 +45,6 @@ class VIZ_SERVICE_EXPORT NullRenderer : public DirectRenderer {
void DoDrawQuad(const DrawQuad* quad,
const gfx::QuadF* clip_region) override {}
void BeginDrawingFrame() override;
- void FlushOverdrawFeedback(const gfx::Rect& output_rect) override {}
void FinishDrawingFrame() override {}
bool FlippedFramebuffer() const override;
void EnsureScissorTestEnabled() override {}
diff --git a/chromium/components/viz/service/display/output_surface.cc b/chromium/components/viz/service/display/output_surface.cc
index 6088ff13f26..643a191a333 100644
--- a/chromium/components/viz/service/display/output_surface.cc
+++ b/chromium/components/viz/service/display/output_surface.cc
@@ -15,8 +15,6 @@
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/swap_result.h"
@@ -30,14 +28,9 @@ OutputSurface::Capabilities& OutputSurface::Capabilities::operator=(
OutputSurface::OutputSurface(Type type) : type_(type) {}
-OutputSurface::OutputSurface(scoped_refptr<ContextProvider> context_provider)
- : context_provider_(std::move(context_provider)), type_(Type::kOpenGL) {
- DCHECK(context_provider_);
-}
-
OutputSurface::OutputSurface(
std::unique_ptr<SoftwareOutputDevice> software_device)
- : software_device_(std::move(software_device)), type_(Type::kSoftware) {
+ : type_(Type::kSoftware), software_device_(std::move(software_device)) {
DCHECK(software_device_);
}
diff --git a/chromium/components/viz/service/display/output_surface.h b/chromium/components/viz/service/display/output_surface.h
index 9c854b56b21..40a1cc2b7d1 100644
--- a/chromium/components/viz/service/display/output_surface.h
+++ b/chromium/components/viz/service/display/output_surface.h
@@ -12,7 +12,6 @@
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "components/viz/common/display/update_vsync_parameters_callback.h"
-#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/common/gpu/gpu_vsync_callback.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/resources/returned_resource.h"
@@ -20,12 +19,12 @@
#include "components/viz/service/display/software_output_device.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
-#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/gpu_task_scheduler_helper.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkM44.h"
+#include "ui/gfx/buffer_types.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/gfx/surface_origin.h"
@@ -77,10 +76,6 @@ class VIZ_SERVICE_EXPORT OutputSurface {
bool uses_default_gl_framebuffer = true;
// Where (0,0) is on this OutputSurface.
gfx::SurfaceOrigin output_surface_origin = gfx::SurfaceOrigin::kBottomLeft;
- // Whether this OutputSurface supports stencil operations or not.
- // Note: HasExternalStencilTest() must return false when an output surface
- // has been configured for stencil usage.
- bool supports_stencil = false;
// Whether this OutputSurface supports post sub buffer or not.
bool supports_post_sub_buffer = false;
// Whether this OutputSurface supports commit overlay planes.
@@ -145,8 +140,6 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// Constructor for skia-based compositing.
explicit OutputSurface(Type type);
- // Constructor for GL-based compositing.
- explicit OutputSurface(scoped_refptr<ContextProvider> context_provider);
// Constructor for software compositing.
explicit OutputSurface(std::unique_ptr<SoftwareOutputDevice> software_device);
@@ -158,11 +151,9 @@ class VIZ_SERVICE_EXPORT OutputSurface {
const Capabilities& capabilities() const { return capabilities_; }
Type type() const { return type_; }
- // Obtain the 3d context or the software device associated with this output
- // surface. Either of these may return a null pointer, but not both.
- // In the event of a lost context, the entire output surface should be
- // recreated.
- ContextProvider* context_provider() const { return context_provider_.get(); }
+ // Obtain the software device associated with this output surface. This will
+ // return non-null for a software output surface and null for skia output
+ // surface.
SoftwareOutputDevice* software_device() const {
return software_device_.get();
}
@@ -183,12 +174,14 @@ class VIZ_SERVICE_EXPORT OutputSurface {
virtual void EnsureBackbuffer() = 0;
virtual void DiscardBackbuffer() = 0;
- // Bind the default framebuffer for drawing to, only valid for GL backed
- // OutputSurfaces.
- virtual void BindFramebuffer() = 0;
-
// Marks that the given rectangle will be drawn to on the default, bound
- // framebuffer. Only valid if |capabilities().supports_dc_layers| is true.
+ // framebuffer. The contents of the framebuffer are undefined after this
+ // command and must be filled in completely before a swap happens. Drawing
+ // outside this rectangle causes undefined behavior.
+ //
+ // Note: This is only valid to call if `capabilities().supports_dc_layers` is
+ // true. It can only be called once per swap and must be called before
+ // drawing to the default framebuffer.
virtual void SetDrawRectangle(const gfx::Rect& rect);
// Enable or disable DC layers. Must be called before DC layers are scheduled.
@@ -198,24 +191,28 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// Returns true if a main image overlay plane should be scheduled.
virtual bool IsDisplayedAsOverlayPlane() const = 0;
- // Get the texture for the main image's overlay.
- virtual unsigned GetOverlayTextureId() const = 0;
-
// Returns the |mailbox| corresponding to the main image's overlay.
virtual gpu::Mailbox GetOverlayMailbox() const;
- virtual void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) = 0;
-
- virtual bool HasExternalStencilTest() const = 0;
- virtual void ApplyExternalStencil() = 0;
-
- // Gives the GL internal format that should be used for calling CopyTexImage2D
- // when the framebuffer is bound via BindFramebuffer().
- virtual uint32_t GetFramebufferCopyTextureFormat() = 0;
+ // Reshape the output surface.
+ struct ReshapeParams {
+ gfx::Size size;
+ float device_scale_factor = 1.f;
+ gfx::ColorSpace color_space;
+ float sdr_white_level = gfx::ColorSpace::kDefaultSDRWhiteLevel;
+ gfx::BufferFormat format = gfx::BufferFormat::RGBX_8888;
+
+ bool operator==(const ReshapeParams& other) const {
+ return size == other.size &&
+ device_scale_factor == other.device_scale_factor &&
+ color_space == other.color_space &&
+ sdr_white_level == other.sdr_white_level;
+ }
+ bool operator!=(const ReshapeParams& other) const {
+ return !(*this == other);
+ }
+ };
+ virtual void Reshape(const ReshapeParams& params) = 0;
// Swaps the current backbuffer to the screen. For successful swaps, the
// implementation must call OutputSurfaceClient::DidReceiveSwapBuffersAck()
@@ -232,14 +229,6 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// TODO(dcastagna): Consider making the following pure virtual.
virtual gfx::Rect GetCurrentFramebufferDamage() const;
- // Updates the GpuFence associated with this surface. The id of a newly
- // created GpuFence is returned, or if an error occurs, or fences are not
- // supported, the special id of 0 (meaning "no fence") is returned. In all
- // cases, any previously associated fence is destroyed. The returned fence id
- // corresponds to the GL id used by the CHROMIUM_gpu_fence GL extension and
- // can be passed directly to any related extension functions.
- virtual unsigned UpdateGpuFence() = 0;
-
// Sets callback to receive updated vsync parameters after SwapBuffers() if
// supported.
virtual void SetUpdateVSyncParametersCallback(
@@ -298,11 +287,10 @@ class VIZ_SERVICE_EXPORT OutputSurface {
protected:
struct OutputSurface::Capabilities capabilities_;
- scoped_refptr<ContextProvider> context_provider_;
- std::unique_ptr<SoftwareOutputDevice> software_device_;
private:
const Type type_;
+ std::unique_ptr<SoftwareOutputDevice> software_device_;
SkM44 color_matrix_;
};
diff --git a/chromium/components/viz/service/display/output_surface_client.h b/chromium/components/viz/service/display/output_surface_client.h
index 3aa54a8e1d1..505beb8c0c0 100644
--- a/chromium/components/viz/service/display/output_surface_client.h
+++ b/chromium/components/viz/service/display/output_surface_client.h
@@ -13,7 +13,6 @@
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/mailbox.h"
-#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gpu_fence_handle.h"
#include "ui/latency/latency_info.h"
@@ -37,11 +36,6 @@ class VIZ_SERVICE_EXPORT OutputSurfaceClient {
// For surfaceless/ozone implementations to create damage for the next frame.
virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0;
- // For synchronizing IOSurface use with the macOS WindowServer with
- // GLRenderer.
- virtual void DidReceiveTextureInUseResponses(
- const gpu::TextureInUseResponses& responses) = 0;
-
// For displaying a swapped frame's contents on macOS.
virtual void DidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) = 0;
diff --git a/chromium/components/viz/service/display/overlay_ca_unittest.cc b/chromium/components/viz/service/display/overlay_ca_unittest.cc
index 2a1b231bb45..b8020578253 100644
--- a/chromium/components/viz/service/display/overlay_ca_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_ca_unittest.cc
@@ -24,14 +24,15 @@
#include "components/viz/common/quads/stream_video_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/video_hole_draw_quad.h"
+#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/service/display/ca_layer_overlay.h"
-#include "components/viz/service/display/display_resource_provider_gl.h"
-#include "components/viz/service/display/gl_renderer.h"
+#include "components/viz/service/display/display_resource_provider_skia.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/overlay_processor_mac.h"
+#include "components/viz/test/fake_skia_output_surface.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
#include "gpu/config/gpu_finch_features.h"
@@ -52,45 +53,6 @@ const gfx::PointF kUVBottomRight(1.0f, 1.0f);
const gfx::Rect kRenderPassOutputRect(0, 0, 256, 256);
const gfx::Rect kOverlayDamageRect(0, 0, 100, 100);
-class OverlayOutputSurface : public OutputSurface {
- public:
- explicit OverlayOutputSurface(
- scoped_refptr<TestContextProvider> context_provider)
- : OutputSurface(std::move(context_provider)) {}
-
- // OutputSurface implementation.
- void BindToClient(OutputSurfaceClient* client) override {}
- void EnsureBackbuffer() override {}
- void DiscardBackbuffer() override {}
- void BindFramebuffer() override { bind_framebuffer_count_ += 1; }
- void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) override {}
- void SwapBuffers(OutputSurfaceFrame frame) override {}
- uint32_t GetFramebufferCopyTextureFormat() override {
- // TestContextProvider has no real framebuffer, just use RGB.
- return GL_RGB;
- }
- bool HasExternalStencilTest() const override { return false; }
- void ApplyExternalStencil() override {}
- bool IsDisplayedAsOverlayPlane() const override { return false; }
- unsigned GetOverlayTextureId() const override { return 10000; }
- unsigned UpdateGpuFence() override { return 0; }
- void SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback) override {}
- void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
- gfx::OverlayTransform GetDisplayTransform() override {
- return gfx::OVERLAY_TRANSFORM_NONE;
- }
-
- unsigned bind_framebuffer_count() const { return bind_framebuffer_count_; }
-
- private:
- unsigned bind_framebuffer_count_ = 0;
-};
-
class CATestOverlayProcessor : public OverlayProcessorMac {
public:
CATestOverlayProcessor() : OverlayProcessorMac() {}
@@ -211,13 +173,12 @@ SkM44 GetIdentityColorMatrix() {
class CALayerOverlayTest : public testing::Test {
protected:
void SetUp() override {
- provider_ = TestContextProvider::Create();
- provider_->BindToCurrentThread();
- output_surface_ = std::make_unique<OverlayOutputSurface>(provider_);
- output_surface_->BindToClient(&client_);
+ output_surface_ = FakeSkiaOutputSurface::Create3d();
+ output_surface_->BindToClient(&output_surface_client_);
- resource_provider_ =
- std::make_unique<DisplayResourceProviderGL>(provider_.get());
+ resource_provider_ = std::make_unique<DisplayResourceProviderSkia>();
+ lock_set_for_external_use_.emplace(resource_provider_.get(),
+ output_surface_.get());
child_provider_ = TestContextProvider::Create();
child_provider_->BindToCurrentThread();
@@ -231,15 +192,16 @@ class CALayerOverlayTest : public testing::Test {
child_resource_provider_->ShutdownAndReleaseAllResources();
child_resource_provider_ = nullptr;
child_provider_ = nullptr;
+ lock_set_for_external_use_.reset();
resource_provider_ = nullptr;
output_surface_ = nullptr;
- provider_ = nullptr;
}
- scoped_refptr<TestContextProvider> provider_;
- std::unique_ptr<OverlayOutputSurface> output_surface_;
- cc::FakeOutputSurfaceClient client_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
+ std::unique_ptr<SkiaOutputSurface> output_surface_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ std::unique_ptr<DisplayResourceProviderSkia> resource_provider_;
+ absl::optional<DisplayResourceProviderSkia::LockSetForExternalUse>
+ lock_set_for_external_use_;
scoped_refptr<TestContextProvider> child_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::unique_ptr<CATestOverlayProcessor> overlay_processor_;
@@ -271,7 +233,6 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
EXPECT_EQ(1U, ca_layer_list.size());
gfx::Rect overlay_damage = overlay_processor_->GetAndResetOverlayDamage();
EXPECT_EQ(kRenderPassOutputRect, overlay_damage);
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, ThreeDTransform) {
@@ -301,7 +262,6 @@ TEST_F(CALayerOverlayTest, ThreeDTransform) {
expected_transform.RotateAboutXAxis(45.f);
gfx::Transform actual_transform(ca_layer_list.back().shared_state->transform);
EXPECT_EQ(expected_transform.ToString(), actual_transform.ToString());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, AllowContainingClip) {
@@ -325,7 +285,6 @@ TEST_F(CALayerOverlayTest, AllowContainingClip) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(1U, ca_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, NontrivialClip) {
@@ -351,7 +310,6 @@ TEST_F(CALayerOverlayTest, NontrivialClip) {
EXPECT_EQ(1U, ca_layer_list.size());
EXPECT_EQ(gfx::RectF(64, 64, 128, 128),
ca_layer_list.back().shared_state->clip_rect);
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, SkipTransparent) {
@@ -375,7 +333,6 @@ TEST_F(CALayerOverlayTest, SkipTransparent) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(0U, ca_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, SkipNonVisible) {
@@ -399,7 +356,6 @@ TEST_F(CALayerOverlayTest, SkipNonVisible) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(0U, ca_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
TEST_F(CALayerOverlayTest, YUVDrawQuadOverlay) {
@@ -484,7 +440,6 @@ TEST_F(CALayerOverlayTest, YUVDrawQuadOverlay) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(gfx::Rect(), damage_rect_);
EXPECT_EQ(0U, ca_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
}
}
diff --git a/chromium/components/viz/service/display/overlay_candidate.cc b/chromium/components/viz/service/display/overlay_candidate.cc
index 41ae9ef7547..c33317bc9d0 100644
--- a/chromium/components/viz/service/display/overlay_candidate.cc
+++ b/chromium/components/viz/service/display/overlay_candidate.cc
@@ -93,39 +93,6 @@ gfx::OverlayTransform GetOverlayTransform(const gfx::Transform& quad_transform,
return gfx::OVERLAY_TRANSFORM_INVALID;
}
-gfx::Rect GetDamageRect(const DrawQuad* quad,
- SurfaceDamageRectList* surface_damage_rect_list) {
- const SharedQuadState* sqs = quad->shared_quad_state;
- auto& transform = sqs->quad_to_target_transform;
- gfx::RectF display_rect = gfx::RectF(quad->rect);
- transform.TransformRect(&display_rect);
- if (!sqs->overlay_damage_index.has_value()) {
- gfx::Rect display_rect_int = gfx::ToRoundedRect(display_rect);
- // This is a special case where an overlay candidate may have damage but it
- // does not have a damage index since it was not the only quad in the
- // original surface. Here the union of all |surface_damage_rect_list| will
- // be in effect the full damage for this display.
- auto full_display_damage = gfx::Rect();
- for (auto& each : *surface_damage_rect_list) {
- full_display_damage.Union(each);
- }
-
- // We limit the damage to the candidates quad rect in question.
- gfx::Rect intersection = display_rect_int;
- intersection.Intersect(full_display_damage);
- return intersection;
- }
-
- size_t overlay_damage_index = sqs->overlay_damage_index.value();
- // Invalid index.
- if (overlay_damage_index >= surface_damage_rect_list->size()) {
- DCHECK(false);
- return gfx::Rect();
- }
-
- return (*surface_damage_rect_list)[overlay_damage_index];
-}
-
} // namespace
OverlayCandidate::OverlayCandidate() = default;
@@ -134,19 +101,13 @@ OverlayCandidate::OverlayCandidate(const OverlayCandidate& other) = default;
OverlayCandidate::~OverlayCandidate() = default;
-// static
-OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const SkM44& output_color_matrix,
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromDrawQuad(
const DrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate,
- bool is_delegated_context) {
+ OverlayCandidate& candidate) const {
// It is currently not possible to set a color conversion matrix on an HW
// overlay plane.
// TODO(https://crbug.com/792757): Remove this check once the bug is resolved.
- if (output_color_matrix != SkM44())
+ if (*output_color_matrix_ != SkM44())
return CandidateStatus::kFailColorMatrix;
const SharedQuadState* sqs = quad->shared_quad_state;
@@ -154,12 +115,12 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuad(
// We don't support an opacity value different than one for an overlay plane.
// Render pass quads should have their |sqs| opacity integrated directly into
// their final output buffers.
- if (!cc::MathUtil::IsWithinEpsilon(sqs->opacity, 1.0f) &&
- !is_delegated_context) {
+ if (!is_delegated_context_ &&
+ !cc::MathUtil::IsWithinEpsilon(sqs->opacity, 1.0f)) {
return CandidateStatus::kFailOpacity;
}
- candidate->opacity = sqs->opacity;
- candidate->rounded_corners = sqs->mask_filter_info.rounded_corner_bounds();
+ candidate.opacity = sqs->opacity;
+ candidate.rounded_corners = sqs->mask_filter_info.rounded_corner_bounds();
// We support only kSrc (no blending) and kSrcOver (blending with premul).
if (!(sqs->blend_mode == SkBlendMode::kSrc ||
@@ -167,43 +128,33 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuad(
return CandidateStatus::kFailBlending;
}
- candidate->requires_overlay =
- OverlayCandidate::RequiresOverlay(quad);
- candidate->overlay_damage_index =
- sqs->overlay_damage_index.value_or(kInvalidDamageIndex);
+ candidate.requires_overlay = OverlayCandidate::RequiresOverlay(quad);
+ candidate.overlay_damage_index =
+ sqs->overlay_damage_index.value_or(OverlayCandidate::kInvalidDamageIndex);
switch (quad->material) {
case DrawQuad::Material::kTextureContent:
- return FromTextureQuad(resource_provider, surface_damage_rect_list,
- TextureDrawQuad::MaterialCast(quad), primary_rect,
- candidate, is_delegated_context);
+ return FromTextureQuad(TextureDrawQuad::MaterialCast(quad), candidate);
case DrawQuad::Material::kVideoHole:
- return FromVideoHoleQuad(resource_provider, surface_damage_rect_list,
- VideoHoleDrawQuad::MaterialCast(quad),
+ return FromVideoHoleQuad(VideoHoleDrawQuad::MaterialCast(quad),
candidate);
case DrawQuad::Material::kStreamVideoContent:
- return FromStreamVideoQuad(resource_provider, surface_damage_rect_list,
- StreamVideoDrawQuad::MaterialCast(quad),
- candidate, is_delegated_context, primary_rect);
+ return FromStreamVideoQuad(StreamVideoDrawQuad::MaterialCast(quad),
+ candidate);
case DrawQuad::Material::kSolidColor:
- if (!is_delegated_context)
+ if (!is_delegated_context_)
return CandidateStatus::kFailQuadNotSupported;
- return candidate->FromSolidColorQuad(
- resource_provider, surface_damage_rect_list,
- SolidColorDrawQuad::MaterialCast(quad), primary_rect, candidate);
+ return FromSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad),
+ candidate);
case DrawQuad::Material::kAggregatedRenderPass:
- if (!is_delegated_context)
+ if (!is_delegated_context_)
return CandidateStatus::kFailQuadNotSupported;
- return candidate->FromAggregateQuad(
- resource_provider, surface_damage_rect_list,
- AggregatedRenderPassDrawQuad::MaterialCast(quad), primary_rect,
- candidate);
+ return FromAggregateQuad(AggregatedRenderPassDrawQuad::MaterialCast(quad),
+ candidate);
case DrawQuad::Material::kTiledContent:
- if (!is_delegated_context)
+ if (!is_delegated_context_)
return CandidateStatus::kFailQuadNotSupported;
- return candidate->FromTileQuad(
- resource_provider, surface_damage_rect_list,
- TileDrawQuad::MaterialCast(quad), primary_rect, candidate);
+ return FromTileQuad(TileDrawQuad::MaterialCast(quad), candidate);
default:
break;
}
@@ -218,8 +169,8 @@ bool OverlayCandidate::IsInvisibleQuad(const DrawQuad* quad) {
return true;
if (quad->material != DrawQuad::Material::kSolidColor)
return false;
- const SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
- const float alpha = (SkColorGetA(color) * (1.f / 255.f)) * opacity;
+ const float alpha =
+ SolidColorDrawQuad::MaterialCast(quad)->color.fA * opacity;
return quad->ShouldDrawWithBlending() &&
cc::MathUtil::IsWithinEpsilon(alpha, 0.f);
}
@@ -247,17 +198,52 @@ bool OverlayCandidate::IsOccluded(const OverlayCandidate& candidate,
return false;
}
-// static
-int OverlayCandidate::EstimateVisibleDamage(
+OverlayCandidateFactory::OverlayCandidateFactory(
+ const AggregatedRenderPass* render_pass,
+ DisplayResourceProvider* resource_provider,
+ const SurfaceDamageRectList* surface_damage_rect_list,
+ const SkM44* output_color_matrix,
+ const gfx::RectF primary_rect,
+ bool is_delegated_context)
+ : render_pass_(render_pass),
+ resource_provider_(resource_provider),
+ surface_damage_rect_list_(surface_damage_rect_list),
+ output_color_matrix_(output_color_matrix),
+ primary_rect_(primary_rect),
+ is_delegated_context_(is_delegated_context) {
+ // TODO(crbug.com/1323002): Replace this set with a simple ordered linear
+ // search when this bug is resolved.
+ base::flat_set<size_t> indices_with_quad_damage;
+ for (auto* sqs : render_pass_->shared_quad_state_list) {
+ // If a |sqs| has a damage index it will only be associated with a single
+ // draw quad.
+ if (sqs->overlay_damage_index.has_value()) {
+ indices_with_quad_damage.insert(sqs->overlay_damage_index.value());
+ }
+ }
+
+ for (size_t i = 0; i < (*surface_damage_rect_list_).size(); i++) {
+ // Add this damage only if it does not correspond to a specific quad.
+ // Ideally any damage that we might want to separate out (think overlays)
+ // will not end up in this |unassigned_surface_damage_| rect.
+ if (!indices_with_quad_damage.contains(i)) {
+ unassigned_surface_damage_.Union((*surface_damage_rect_list_)[i]);
+ }
+ }
+}
+
+OverlayCandidateFactory::~OverlayCandidateFactory() = default;
+
+float OverlayCandidateFactory::EstimateVisibleDamage(
const DrawQuad* quad,
- SurfaceDamageRectList* surface_damage_rect_list,
+ const OverlayCandidate& candidate,
QuadList::ConstIterator quad_list_begin,
- QuadList::ConstIterator quad_list_end) {
- gfx::Rect quad_damage = GetDamageRect(quad, surface_damage_rect_list);
- int occluded_damage_estimate_total = 0;
+ QuadList::ConstIterator quad_list_end) const {
+ gfx::Rect quad_damage = gfx::ToEnclosingRect(GetDamageRect(quad, candidate));
+ float occluded_damage_estimate_total = 0.f;
for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
++overlap_iter) {
- gfx::Rect overlap_rect = gfx::ToRoundedRect(cc::MathUtil::MapClippedRect(
+ gfx::Rect overlap_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect(
overlap_iter->shared_quad_state->quad_to_target_transform,
gfx::RectF(overlap_iter->rect)));
@@ -273,7 +259,7 @@ int OverlayCandidate::EstimateVisibleDamage(
// reason why this computation is an estimate and why we have the max clamping
// below.
return std::max(
- 0, quad_damage.size().GetArea() - occluded_damage_estimate_total);
+ 0.f, quad_damage.size().GetArea() - occluded_damage_estimate_total);
}
// static
@@ -295,13 +281,12 @@ bool OverlayCandidate::RequiresOverlay(const DrawQuad* quad) {
}
}
-// static
-bool OverlayCandidate::IsOccludedByFilteredQuad(
+bool OverlayCandidateFactory::IsOccludedByFilteredQuad(
const OverlayCandidate& candidate,
QuadList::ConstIterator quad_list_begin,
QuadList::ConstIterator quad_list_end,
const base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>&
- render_pass_backdrop_filters) {
+ render_pass_backdrop_filters) const {
for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
++overlap_iter) {
if (overlap_iter->material == DrawQuad::Material::kAggregatedRenderPass) {
@@ -320,29 +305,24 @@ bool OverlayCandidate::IsOccludedByFilteredQuad(
return false;
}
-// static
-OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuadResource(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromDrawQuadResource(
const DrawQuad* quad,
ResourceId resource_id,
bool y_flipped,
- OverlayCandidate* candidate,
- bool is_delegated_context,
- const gfx::RectF& primary_rect) {
+ OverlayCandidate& candidate) const {
if (resource_id != kInvalidResourceId &&
- !resource_provider->IsOverlayCandidate(resource_id))
+ !resource_provider_->IsOverlayCandidate(resource_id))
return CandidateStatus::kFailNotOverlay;
if (quad->visible_rect.IsEmpty())
return CandidateStatus::kFailVisible;
if (resource_id != kInvalidResourceId) {
- candidate->format = resource_provider->GetBufferFormat(resource_id);
- candidate->color_space = resource_provider->GetColorSpace(resource_id);
- candidate->hdr_metadata = resource_provider->GetHDRMetadata(resource_id);
+ candidate.format = resource_provider_->GetBufferFormat(resource_id);
+ candidate.color_space = resource_provider_->GetColorSpace(resource_id);
+ candidate.hdr_metadata = resource_provider_->GetHDRMetadata(resource_id);
- if (!base::Contains(kOverlayFormats, candidate->format))
+ if (!base::Contains(kOverlayFormats, candidate.format))
return CandidateStatus::kFailBufferFormat;
}
@@ -352,28 +332,28 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuadResource(
GetOverlayTransform(sqs->quad_to_target_transform, y_flipped);
if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
return CandidateStatus::kFailNotAxisAligned;
- candidate->transform = overlay_transform;
+ candidate.transform = overlay_transform;
auto& transform = sqs->quad_to_target_transform;
- candidate->display_rect = gfx::RectF(quad->rect);
- transform.TransformRect(&candidate->display_rect);
+ candidate.display_rect = gfx::RectF(quad->rect);
+ transform.TransformRect(&candidate.display_rect);
- candidate->clip_rect = sqs->clip_rect;
- candidate->is_opaque =
+ candidate.clip_rect = sqs->clip_rect;
+ candidate.is_opaque =
!quad->ShouldDrawWithBlendingForReasonOtherThanMaskFilter();
- candidate->has_mask_filter = !sqs->mask_filter_info.IsEmpty();
+ candidate.has_mask_filter = !sqs->mask_filter_info.IsEmpty();
if (resource_id != kInvalidResourceId) {
- candidate->resource_size_in_pixels =
- resource_provider->GetResourceBackedSize(resource_id);
+ candidate.resource_size_in_pixels =
+ resource_provider_->GetResourceBackedSize(resource_id);
} else {
- candidate->resource_size_in_pixels =
- gfx::Size(candidate->display_rect.size().width(),
- candidate->display_rect.size().height());
+ candidate.resource_size_in_pixels =
+ gfx::Size(candidate.display_rect.size().width(),
+ candidate.display_rect.size().height());
}
- AssignDamage(quad, surface_damage_rect_list, candidate);
- candidate->resource_id = resource_id;
+ AssignDamage(quad, candidate);
+ candidate.resource_id = resource_id;
struct TrackingIdData {
gfx::Rect rect;
@@ -382,118 +362,106 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromDrawQuadResource(
TrackingIdData track_data{quad->rect, FrameSinkId()};
if (resource_id != kInvalidResourceId) {
- candidate->mailbox = resource_provider->GetMailbox(resource_id);
+ candidate.mailbox = resource_provider_->GetMailbox(resource_id);
track_data.frame_sink_id =
- resource_provider->GetSurfaceId(resource_id).frame_sink_id();
+ resource_provider_->GetSurfaceId(resource_id).frame_sink_id();
}
// Delegated compositing does not yet support |clip_rect| so it is applied
// here to the |display_rect| and |uv_rect| directly.
- if (is_delegated_context) {
- if (candidate->clip_rect.has_value())
- ApplyClip(candidate, gfx::RectF(*candidate->clip_rect));
+ if (is_delegated_context_) {
+ if (candidate.clip_rect.has_value())
+ OverlayCandidate::ApplyClip(candidate, gfx::RectF(*candidate.clip_rect));
+
+ if (quad->visible_rect != quad->rect) {
+ auto visible_rect = gfx::RectF(quad->visible_rect);
+ transform.TransformRect(&visible_rect);
+ OverlayCandidate::ApplyClip(candidate, gfx::RectF(visible_rect));
+ }
// TODO(https://crbug.com/1300552) : Tile quads can overlay other quads and
// the window by one pixel. Exo does not yet clip these quads so we need to
// clip here with the |primary_rect|.
- ApplyClip(candidate, primary_rect);
+ OverlayCandidate::ApplyClip(candidate, primary_rect_);
+
+ if (candidate.display_rect.IsEmpty())
+ return CandidateStatus::kFailVisible;
}
- candidate->tracking_id = base::Hash(&track_data, sizeof(track_data));
+ candidate.tracking_id = base::Hash(&track_data, sizeof(track_data));
return CandidateStatus::kSuccess;
}
-// static
-OverlayCandidate::CandidateStatus OverlayCandidate::FromAggregateQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromAggregateQuad(
const AggregatedRenderPassDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate) {
- auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, kInvalidResourceId, false, candidate,
- true, primary_rect);
+ OverlayCandidate& candidate) const {
+ auto rtn = FromDrawQuadResource(quad, kInvalidResourceId, false, candidate);
if (rtn == CandidateStatus::kSuccess) {
- candidate->rpdq = quad;
+ candidate.rpdq = quad;
}
return rtn;
}
-// static
-OverlayCandidate::CandidateStatus OverlayCandidate::FromSolidColorQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromSolidColorQuad(
const SolidColorDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate) {
- auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, kInvalidResourceId, false, candidate,
- true, primary_rect);
+ OverlayCandidate& candidate) const {
+ auto rtn = FromDrawQuadResource(quad, kInvalidResourceId, false, candidate);
if (rtn == CandidateStatus::kSuccess) {
- candidate->solid_color = quad->color;
+ // TODO(crbug/1308932) remove toSkColor and make all SkColor4f
+ candidate.color = quad->color.toSkColor();
+ // Mark this candidate a solid color as the |color| member can be either a
+ // background of the overlay or a color of the solid color quad.
+ candidate.is_solid_color = true;
}
return rtn;
}
-// static
-// For VideoHoleDrawQuad, only calculate geometry information
-// and put it in the |candidate|.
-OverlayCandidate::CandidateStatus OverlayCandidate::FromVideoHoleQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
+// For VideoHoleDrawQuad, only calculate geometry information and put it in the
+// |candidate|.
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromVideoHoleQuad(
const VideoHoleDrawQuad* quad,
- OverlayCandidate* candidate) {
+ OverlayCandidate& candidate) const {
gfx::OverlayTransform overlay_transform = GetOverlayTransform(
quad->shared_quad_state->quad_to_target_transform, false);
if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
return CandidateStatus::kFailNotAxisAligned;
auto& transform = quad->shared_quad_state->quad_to_target_transform;
- candidate->display_rect = gfx::RectF(quad->rect);
- transform.TransformRect(&candidate->display_rect);
- candidate->transform = overlay_transform;
- candidate->is_opaque =
+ candidate.display_rect = gfx::RectF(quad->rect);
+ transform.TransformRect(&candidate.display_rect);
+ candidate.transform = overlay_transform;
+ candidate.is_opaque =
!quad->ShouldDrawWithBlendingForReasonOtherThanMaskFilter();
- candidate->has_mask_filter =
+ candidate.has_mask_filter =
!quad->shared_quad_state->mask_filter_info.IsEmpty();
- AssignDamage(quad, surface_damage_rect_list, candidate);
- candidate->tracking_id = base::FastHash(quad->overlay_plane_id.AsBytes());
+ AssignDamage(quad, candidate);
+ candidate.tracking_id = base::FastHash(quad->overlay_plane_id.AsBytes());
return CandidateStatus::kSuccess;
}
-OverlayCandidate::CandidateStatus OverlayCandidate::FromTileQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromTileQuad(
const TileDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate) {
+ OverlayCandidate& candidate) const {
if (quad->nearest_neighbor)
return CandidateStatus::kFailNearFilter;
- candidate->resource_size_in_pixels =
- resource_provider->GetResourceBackedSize(quad->resource_id());
- candidate->uv_rect = gfx::ScaleRect(
- quad->tex_coord_rect, 1.f / candidate->resource_size_in_pixels.width(),
- 1.f / candidate->resource_size_in_pixels.height());
+ candidate.resource_size_in_pixels =
+ resource_provider_->GetResourceBackedSize(quad->resource_id());
+ candidate.uv_rect = gfx::ScaleRect(
+ quad->tex_coord_rect, 1.f / candidate.resource_size_in_pixels.width(),
+ 1.f / candidate.resource_size_in_pixels.height());
- auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, quad->resource_id(), false, candidate,
- true, primary_rect);
+ auto rtn = FromDrawQuadResource(quad, quad->resource_id(), false, candidate);
return rtn;
}
-// static
-OverlayCandidate::CandidateStatus OverlayCandidate::FromTextureQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromTextureQuad(
const TextureDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate,
- bool is_delegated_context) {
- if (!is_delegated_context &&
+ OverlayCandidate& candidate) const {
+ if (!is_delegated_context_ &&
quad->overlay_priority_hint == OverlayPriority::kLow) {
// For current implementation low priority means this does not promote to
// overlay.
@@ -503,91 +471,88 @@ OverlayCandidate::CandidateStatus OverlayCandidate::FromTextureQuad(
if (quad->nearest_neighbor)
return CandidateStatus::kFailNearFilter;
- if (quad->background_color != SK_ColorTRANSPARENT &&
- (quad->background_color != SK_ColorBLACK ||
- quad->ShouldDrawWithBlending()))
- return CandidateStatus::kFailBlending;
+ if (quad->background_color != SkColors::kTransparent &&
+ (quad->background_color != SkColors::kBlack ||
+ quad->ShouldDrawWithBlending())) {
+ // This path can also be used by other platforms like Ash/Chrome, which does
+ // not support overlays with background color. Only LaCros/Wayland supports
+ // that.
+ if (!is_delegated_context_)
+ return CandidateStatus::kFailBlending;
+ // TODO(crbug/1308932) remove toSkColor and make all SkColor4f
+ candidate.color = quad->background_color.toSkColor();
+ }
- candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
+ candidate.uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
- auto rtn = FromDrawQuadResource(
- resource_provider, surface_damage_rect_list, quad, quad->resource_id(),
- quad->y_flipped, candidate, is_delegated_context, primary_rect);
+ auto rtn = FromDrawQuadResource(quad, quad->resource_id(), quad->y_flipped,
+ candidate);
if (rtn == CandidateStatus::kSuccess) {
// Only handle clip rect for required overlays
- if (!is_delegated_context && candidate->requires_overlay)
- HandleClipAndSubsampling(candidate, primary_rect);
+ if (!is_delegated_context_ && candidate.requires_overlay)
+ HandleClipAndSubsampling(candidate);
// Texture quads for UI elements like scroll bars have empty
// |size_in_pixels| as 'set_resource_size_in_pixels' is not called as these
// quads are not intended to become overlays.
if (!quad->resource_size_in_pixels().IsEmpty())
- candidate->priority_hint = gfx::OverlayPriorityHint::kRegular;
+ candidate.priority_hint = gfx::OverlayPriorityHint::kRegular;
}
return rtn;
}
-// static
-OverlayCandidate::CandidateStatus OverlayCandidate::FromStreamVideoQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
+OverlayCandidate::CandidateStatus OverlayCandidateFactory::FromStreamVideoQuad(
const StreamVideoDrawQuad* quad,
- OverlayCandidate* candidate,
- bool is_delegated_context,
- const gfx::RectF& primary_rect) {
- auto rtn = FromDrawQuadResource(resource_provider, surface_damage_rect_list,
- quad, quad->resource_id(), false, candidate,
- is_delegated_context, primary_rect);
+ OverlayCandidate& candidate) const {
+ auto rtn = FromDrawQuadResource(quad, quad->resource_id(), false, candidate);
if (rtn == CandidateStatus::kSuccess) {
- candidate->resource_size_in_pixels = quad->resource_size_in_pixels();
- candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
+ candidate.resource_size_in_pixels = quad->resource_size_in_pixels();
+ candidate.uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
#if BUILDFLAG(IS_ANDROID)
- candidate->is_backed_by_surface_texture =
- resource_provider->IsBackedBySurfaceTexture(quad->resource_id());
+ candidate.is_backed_by_surface_texture =
+ resource_provider_->IsBackedBySurfaceTexture(quad->resource_id());
#endif
}
return rtn;
}
-// static
-void OverlayCandidate::HandleClipAndSubsampling(
- OverlayCandidate* candidate,
- const gfx::RectF& primary_rect) {
+void OverlayCandidateFactory::HandleClipAndSubsampling(
+ OverlayCandidate& candidate) const {
// The purpose of this is to enable overlays that are required (i.e. protected
// content) to be able to be shown in all cases. This will allow them to pass
// the clipping check and also the 2x alignment requirement for subsampling in
// the Intel DRM driver. This should not be used in cases where the surface
// will not always be promoted to an overlay as it will lead to shifting of
// the content when it switches between composition and overlay.
- if (!candidate->clip_rect)
+ if (!candidate.clip_rect)
return;
// Make sure it's in a format we can deal with, we only support YUV and P010.
- if (candidate->format != gfx::BufferFormat::YUV_420_BIPLANAR &&
- candidate->format != gfx::BufferFormat::P010) {
+ if (candidate.format != gfx::BufferFormat::YUV_420_BIPLANAR &&
+ candidate.format != gfx::BufferFormat::P010) {
return;
}
// Clip the clip rect to the primary plane. An overlay will only be shown on
// a single display, so we want to perform our calculations within the bounds
// of that display.
- if (!primary_rect.IsEmpty())
- candidate->clip_rect->Intersect(gfx::ToNearestRect(primary_rect));
+ if (!primary_rect_.IsEmpty())
+ candidate.clip_rect->Intersect(gfx::ToNearestRect(primary_rect_));
// Calculate |uv_rect| of |clip_rect| in |display_rect|
gfx::RectF uv_rect = cc::MathUtil::ScaleRectProportional(
- candidate->uv_rect, candidate->display_rect,
- gfx::RectF(*candidate->clip_rect));
+ candidate.uv_rect, candidate.display_rect,
+ gfx::RectF(*candidate.clip_rect));
// In case that |uv_rect| of candidate is not (0, 0, 1, 1)
- candidate->uv_rect.Intersect(uv_rect);
+ candidate.uv_rect.Intersect(uv_rect);
// Update |display_rect| to avoid unexpected scaling and the candidate should
// not be regarded as clippped after this.
- candidate->display_rect.Intersect(gfx::RectF(*candidate->clip_rect));
- candidate->clip_rect.reset();
- gfx::Rect rounded_display_rect = gfx::ToRoundedRect(candidate->display_rect);
- candidate->display_rect.SetRect(
+ candidate.display_rect.Intersect(gfx::RectF(*candidate.clip_rect));
+ candidate.clip_rect.reset();
+ gfx::Rect rounded_display_rect = gfx::ToRoundedRect(candidate.display_rect);
+ candidate.display_rect.SetRect(
rounded_display_rect.x(), rounded_display_rect.y(),
rounded_display_rect.width(), rounded_display_rect.height());
@@ -596,8 +561,8 @@ void OverlayCandidate::HandleClipAndSubsampling(
// Get the rect for the source coordinates.
gfx::RectF src_rect = gfx::ScaleRect(
- candidate->uv_rect, candidate->resource_size_in_pixels.width(),
- candidate->resource_size_in_pixels.height());
+ candidate.uv_rect, candidate.resource_size_in_pixels.width(),
+ candidate.resource_size_in_pixels.height());
// Make it an integral multiple of the subsampling factor.
auto subsample_round = [](float val) {
constexpr int kSubsamplingFactor = 2;
@@ -609,19 +574,16 @@ void OverlayCandidate::HandleClipAndSubsampling(
src_rect.set_width(subsample_round(src_rect.width()));
src_rect.set_height(subsample_round(src_rect.height()));
// Scale it back into UV space and set it in the candidate.
- candidate->uv_rect = gfx::ScaleRect(
- src_rect, 1.0f / candidate->resource_size_in_pixels.width(),
- 1.0f / candidate->resource_size_in_pixels.height());
+ candidate.uv_rect =
+ gfx::ScaleRect(src_rect, 1.0f / candidate.resource_size_in_pixels.width(),
+ 1.0f / candidate.resource_size_in_pixels.height());
}
-// static
-void OverlayCandidate::AssignDamage(
- const DrawQuad* quad,
- SurfaceDamageRectList* surface_damage_rect_list,
- OverlayCandidate* candidate) {
+void OverlayCandidateFactory::AssignDamage(const DrawQuad* quad,
+ OverlayCandidate& candidate) const {
auto& transform = quad->shared_quad_state->quad_to_target_transform;
- const auto damage_rect = GetDamageRect(quad, surface_damage_rect_list);
- auto transformed_damage = gfx::RectF(damage_rect);
+ auto damage_rect = GetDamageRect(quad, candidate);
+ auto transformed_damage = damage_rect;
gfx::Transform inv;
if (transform.GetInverse(&inv)) {
inv.TransformRect(&transformed_damage);
@@ -640,37 +602,65 @@ void OverlayCandidate::AssignDamage(
// The normalization above is not enough if the |uv_rect| is not 0,0-1x1.
// This is because texture uvs can effectively magnify damage.
- if (!candidate->uv_rect.IsEmpty()) {
- transformed_damage.Scale(candidate->uv_rect.width(),
- candidate->uv_rect.height());
- transformed_damage.Offset(candidate->uv_rect.OffsetFromOrigin());
+ if (!candidate.uv_rect.IsEmpty()) {
+ transformed_damage.Scale(candidate.uv_rect.width(),
+ candidate.uv_rect.height());
+ transformed_damage.Offset(candidate.uv_rect.OffsetFromOrigin());
}
// Buffer damage is in texels not UVs so scale by resource size.
- transformed_damage.Scale(candidate->resource_size_in_pixels.width(),
- candidate->resource_size_in_pixels.height());
+ transformed_damage.Scale(candidate.resource_size_in_pixels.width(),
+ candidate.resource_size_in_pixels.height());
} else {
// If not invertible, set to full damage.
// TODO(https://crbug.com/1279965): |resource_size_in_pixels| might not be
// properly initialized at this stage.
transformed_damage =
- gfx::RectF(gfx::SizeF(candidate->resource_size_in_pixels));
+ gfx::RectF(gfx::SizeF(candidate.resource_size_in_pixels));
}
// For underlays the function 'EstimateVisibleDamage()' is called to update
// |damage_area_estimate| to more accurately reflect the actual visible
// damage.
- candidate->damage_area_estimate = damage_rect.size().GetArea();
- candidate->damage_rect = transformed_damage;
+ candidate.damage_area_estimate = damage_rect.size().GetArea();
+ candidate.damage_rect = transformed_damage;
}
-void OverlayCandidate::ApplyClip(OverlayCandidate* candidate,
+// static
+void OverlayCandidate::ApplyClip(OverlayCandidate& candidate,
const gfx::RectF& clip_rect) {
- gfx::RectF intersect_clip_display = clip_rect;
- intersect_clip_display.Intersect(candidate->display_rect);
- gfx::RectF uv_rect = cc::MathUtil::ScaleRectProportional(
- candidate->uv_rect, candidate->display_rect, intersect_clip_display);
- candidate->display_rect = intersect_clip_display;
- candidate->uv_rect = uv_rect;
+ if (!clip_rect.Contains(candidate.display_rect)) {
+ gfx::RectF intersect_clip_display = clip_rect;
+ intersect_clip_display.Intersect(candidate.display_rect);
+ gfx::RectF uv_rect = cc::MathUtil::ScaleRectProportional(
+ candidate.uv_rect, candidate.display_rect, intersect_clip_display);
+ candidate.display_rect = intersect_clip_display;
+ candidate.uv_rect = uv_rect;
+ }
+}
+
+gfx::RectF OverlayCandidateFactory::GetDamageRect(
+ const DrawQuad* quad,
+ const OverlayCandidate& candidate) const {
+ const SharedQuadState* sqs = quad->shared_quad_state;
+ if (!sqs->overlay_damage_index.has_value()) {
+ // This is a special case where an overlay candidate may have damage but it
+ // does not have a damage index since it was not the only quad in the
+ // original surface. Here the |unassigned_surface_damage_| will contain all
+ // unassigned damage and we use it to conservatively estimate the damage for
+ // this quad. We limit the damage to the candidates quad rect in question.
+ gfx::RectF intersection = candidate.display_rect;
+ intersection.Intersect(gfx::RectF(unassigned_surface_damage_));
+ return intersection;
+ }
+
+ size_t overlay_damage_index = sqs->overlay_damage_index.value();
+ // Invalid index.
+ if (overlay_damage_index >= surface_damage_rect_list_->size()) {
+ DCHECK(false);
+ return gfx::RectF();
+ }
+
+ return gfx::RectF((*surface_damage_rect_list_)[overlay_damage_index]);
}
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_candidate.h b/chromium/components/viz/service/display/overlay_candidate.h
index 2585bd1f4a7..a205623d385 100644
--- a/chromium/components/viz/service/display/overlay_candidate.h
+++ b/chromium/components/viz/service/display/overlay_candidate.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/containers/flat_map.h"
+#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "components/viz/common/quads/aggregated_render_pass.h"
#include "components/viz/common/quads/tile_draw_quad.h"
@@ -60,17 +61,6 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
using TrackingId = uint32_t;
static constexpr TrackingId kDefaultTrackingId{0};
- // Returns true and fills in |candidate| if |draw_quad| is of a known quad
- // type and contains an overlayable resource. |primary_rect| can be empty in
- // the case of a null primary plane.
- static CandidateStatus FromDrawQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const SkM44& output_color_matrix,
- const DrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate,
- bool is_delegated_context = false);
// Returns true if |quad| will not block quads underneath from becoming
// an overlay.
static bool IsInvisibleQuad(const DrawQuad* quad);
@@ -81,25 +71,11 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
QuadList::ConstIterator quad_list_begin,
QuadList::ConstIterator quad_list_end);
- // Returns an estimate of this |quad|'s actual visible damage area. This
- // visible damage is computed by combining from input
- // |surface_damage_rect_list| with the occluding rects in the quad_list.
- // This is an estimate since the occluded damage area is calculated on a per
- // quad basis.
- static int EstimateVisibleDamage(
- const DrawQuad* quad,
- SurfaceDamageRectList* surface_damage_rect_list,
- QuadList::ConstIterator quad_list_begin,
- QuadList::ConstIterator quad_list_end);
-
- // Returns true if any of the quads in the list given by |quad_list_begin|
- // and |quad_list_end| have a filter associated and occlude |candidate|.
- static bool IsOccludedByFilteredQuad(
- const OverlayCandidate& candidate,
- QuadList::ConstIterator quad_list_begin,
- QuadList::ConstIterator quad_list_end,
- const base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>&
- render_pass_backdrop_filters);
+ // Modifies the |candidate|'s |display_rect| to be clipped within |clip_rect|.
+ // This function will also update the |uv_rect| based on what clipping was
+ // applied to |display_rect|.
+ static void ApplyClip(OverlayCandidate& candidate,
+ const gfx::RectF& clip_rect);
// Returns true if the |quad| cannot be displayed on the main plane. This is
// used in conjuction with protected content that can't be GPU composited and
@@ -163,7 +139,7 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// The total area in square pixels of damage for this candidate's quad. This
// is an estimate when 'EstimateOccludedDamage' function is used.
- int damage_area_estimate = 0;
+ float damage_area_estimate = 0.f;
// Damage in buffer space (extents bound by |resource_size_in_pixels|).
gfx::RectF damage_rect;
@@ -175,8 +151,12 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// Is true if an HW overlay is required for the quad content.
bool requires_overlay = false;
- // for solid color quads only
- absl::optional<SkColor> solid_color;
+ // Represents either a background of this overlay candidate or a color of a
+ // solid color quad, which can be checked via the |is_solid_color|.
+ absl::optional<SkColor> color;
+
+ // Helps to identify whether this is a solid color quad or not.
+ bool is_solid_color = false;
// If |rpdq| is present, then the renderer must draw the filter effects and
// copy the result into the buffer backing of a render pass.
@@ -207,72 +187,103 @@ class VIZ_SERVICE_EXPORT OverlayCandidate {
// surface and have the same |DrawQuad::rect| they will have the same
// |tracking_id|.
TrackingId tracking_id = kDefaultTrackingId;
-
- private:
- static CandidateStatus FromDrawQuadResource(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const DrawQuad* quad,
- ResourceId resource_id,
- bool y_flipped,
- OverlayCandidate* candidate,
- bool is_delegated_context,
- const gfx::RectF& primary_rect);
-
- static CandidateStatus FromTextureQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const TextureDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate,
- bool is_delegated_context);
-
- static CandidateStatus FromTileQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const TileDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate);
-
- static CandidateStatus FromAggregateQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const AggregatedRenderPassDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate);
-
- static CandidateStatus FromSolidColorQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const SolidColorDrawQuad* quad,
- const gfx::RectF& primary_rect,
- OverlayCandidate* candidate);
-
- static CandidateStatus FromStreamVideoQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const StreamVideoDrawQuad* quad,
- OverlayCandidate* candidate,
- bool is_delegated_context,
- const gfx::RectF& primary_rect);
-
- static CandidateStatus FromVideoHoleQuad(
- DisplayResourceProvider* resource_provider,
- SurfaceDamageRectList* surface_damage_rect_list,
- const VideoHoleDrawQuad* quad,
- OverlayCandidate* candidate);
- static void HandleClipAndSubsampling(OverlayCandidate* candidate,
- const gfx::RectF& primary_rect);
- static void AssignDamage(const DrawQuad* quad,
- SurfaceDamageRectList* surface_damage_rect_list,
- OverlayCandidate* candidate);
-
- static void ApplyClip(OverlayCandidate* candidate,
- const gfx::RectF& clip_rect);
};
using OverlayCandidateList = std::vector<OverlayCandidate>;
+// This is a factory to help with the creation of |OverlayCandidates|. On
+// construction, this factory captures the required objects to create candidates
+// from a draw quad. Common computations for all possible candidates can be
+// made at construction time. This class is const after construction and not
+// copy/moveable to avoid capture ownership issues.
+class VIZ_SERVICE_EXPORT OverlayCandidateFactory {
+ public:
+ using CandidateStatus = OverlayCandidate::CandidateStatus;
+
+ OverlayCandidateFactory(const AggregatedRenderPass* render_pass,
+ DisplayResourceProvider* resource_provider,
+ const SurfaceDamageRectList* surface_damage_rect_list,
+ const SkM44* output_color_matrix,
+ const gfx::RectF primary_rect,
+ bool is_delegated_context = false);
+
+ OverlayCandidateFactory(const OverlayCandidateFactory&) = delete;
+ OverlayCandidateFactory& operator=(const OverlayCandidateFactory&) = delete;
+
+ ~OverlayCandidateFactory();
+
+ // Returns |kSuccess| and fills in |candidate| if |draw_quad| is of a known
+ // quad type and contains an overlayable resource. |primary_rect| can be empty
+ // in the case of a null primary plane. |candidate| is expected to be a
+ // freshly constructed |OverlayCandidate| object.
+ CandidateStatus FromDrawQuad(const DrawQuad* quad,
+ OverlayCandidate& candidate) const;
+
+ // Returns an estimate of this |quad|'s actual visible damage area as float
+ // pixels squared. This visible damage is computed by combining from input
+ // |surface_damage_rect_list_| with the occluding rects in the quad_list. This
+ // is an estimate since the occluded damage area is calculated on a per quad
+ // basis. The |quad_list_begin| and |quad_list_end| provide the range of valid
+ // occluders of this |candidate|.
+ // TODO(petermcneeley): Can we replace this with |visible_rect| in |DrawQuad|?
+ float EstimateVisibleDamage(const DrawQuad* quad,
+ const OverlayCandidate& candidate,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end) const;
+
+ // Returns true if any of the quads in the list given by |quad_list_begin|
+ // and |quad_list_end| have an associated filter and occlude |candidate|.
+ bool IsOccludedByFilteredQuad(
+ const OverlayCandidate& candidate,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end,
+ const base::flat_map<AggregatedRenderPassId, cc::FilterOperations*>&
+ render_pass_backdrop_filters) const;
+
+ private:
+ CandidateStatus FromDrawQuadResource(const DrawQuad* quad,
+ ResourceId resource_id,
+ bool y_flipped,
+ OverlayCandidate& candidate) const;
+
+ CandidateStatus FromTextureQuad(const TextureDrawQuad* quad,
+ OverlayCandidate& candidate) const;
+
+ CandidateStatus FromTileQuad(const TileDrawQuad* quad,
+ OverlayCandidate& candidate) const;
+
+ CandidateStatus FromAggregateQuad(const AggregatedRenderPassDrawQuad* quad,
+ OverlayCandidate& candidate) const;
+
+ CandidateStatus FromSolidColorQuad(const SolidColorDrawQuad* quad,
+ OverlayCandidate& candidate) const;
+
+ CandidateStatus FromStreamVideoQuad(const StreamVideoDrawQuad* quad,
+ OverlayCandidate& candidate) const;
+
+ CandidateStatus FromVideoHoleQuad(const VideoHoleDrawQuad* quad,
+ OverlayCandidate& candidate) const;
+
+ void HandleClipAndSubsampling(OverlayCandidate& candidate) const;
+
+ void AssignDamage(const DrawQuad* quad, OverlayCandidate& candidate) const;
+
+ // Damage returned from this function is in target content space.
+ gfx::RectF GetDamageRect(const DrawQuad* quad,
+ const OverlayCandidate& candidate) const;
+
+ raw_ptr<const AggregatedRenderPass> render_pass_;
+ raw_ptr<DisplayResourceProvider> resource_provider_;
+ raw_ptr<const SurfaceDamageRectList> surface_damage_rect_list_;
+ raw_ptr<const SkM44> output_color_matrix_;
+ const gfx::RectF primary_rect_;
+ bool is_delegated_context_;
+
+ // The union of all surface damages that are not specifically assigned to a
+ // draw quad.
+ gfx::Rect unassigned_surface_damage_;
+};
+
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_H_
diff --git a/chromium/components/viz/service/display/overlay_dc_unittest.cc b/chromium/components/viz/service/display/overlay_dc_unittest.cc
index d49769e18ef..8f7fd805e74 100644
--- a/chromium/components/viz/service/display/overlay_dc_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_dc_unittest.cc
@@ -4,6 +4,7 @@
#include <stddef.h>
+#include <memory>
#include <utility>
#include <vector>
@@ -22,14 +23,15 @@
#include "components/viz/common/quads/stream_video_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/video_hole_draw_quad.h"
+#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/service/display/dc_layer_overlay.h"
-#include "components/viz/service/display/display_resource_provider_gl.h"
-#include "components/viz/service/display/gl_renderer.h"
+#include "components/viz/service/display/display_resource_provider_skia.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/overlay_processor_win.h"
+#include "components/viz/test/fake_skia_output_surface.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
#include "gpu/config/gpu_finch_features.h"
@@ -48,47 +50,21 @@ namespace {
const gfx::Rect kOverlayRect(0, 0, 256, 256);
const gfx::Rect kOverlayBottomRightRect(128, 128, 128, 128);
-class OverlayOutputSurface : public OutputSurface {
+class MockDCLayerOutputSurface : public FakeSkiaOutputSurface {
public:
- explicit OverlayOutputSurface(
- scoped_refptr<TestContextProvider> context_provider)
- : OutputSurface(std::move(context_provider)) {
+ static std::unique_ptr<MockDCLayerOutputSurface> Create() {
+ auto provider = TestContextProvider::Create();
+ provider->BindToCurrentThread();
+ return std::make_unique<MockDCLayerOutputSurface>(std::move(provider));
+ }
+
+ explicit MockDCLayerOutputSurface(scoped_refptr<ContextProvider> provider)
+ : FakeSkiaOutputSurface(std::move(provider)) {
capabilities_.supports_dc_layers = true;
}
// OutputSurface implementation.
- void BindToClient(OutputSurfaceClient* client) override {}
- void EnsureBackbuffer() override {}
- void DiscardBackbuffer() override {}
- void BindFramebuffer() override { bind_framebuffer_count_ += 1; }
- void SetDrawRectangle(const gfx::Rect& rect) override {}
MOCK_METHOD1(SetEnableDCLayers, void(bool));
- void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) override {}
- void SwapBuffers(OutputSurfaceFrame frame) override {}
- uint32_t GetFramebufferCopyTextureFormat() override {
- // TestContextProvider has no real framebuffer, just use RGB.
- return GL_RGB;
- }
- bool HasExternalStencilTest() const override { return false; }
- void ApplyExternalStencil() override {}
- bool IsDisplayedAsOverlayPlane() const override { return false; }
- unsigned GetOverlayTextureId() const override { return 10000; }
- unsigned UpdateGpuFence() override { return 0; }
- void SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback) override {}
- void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
- gfx::OverlayTransform GetDisplayTransform() override {
- return gfx::OVERLAY_TRANSFORM_NONE;
- }
-
- unsigned bind_framebuffer_count() const { return bind_framebuffer_count_; }
-
- private:
- unsigned bind_framebuffer_count_ = 0;
};
class DCTestOverlayProcessor : public OverlayProcessorWin {
@@ -223,13 +199,12 @@ SkM44 GetIdentityColorMatrix() {
class DCLayerOverlayTest : public testing::Test {
protected:
void SetUp() override {
- provider_ = TestContextProvider::Create();
- provider_->BindToCurrentThread();
- output_surface_ = std::make_unique<OverlayOutputSurface>(provider_);
- output_surface_->BindToClient(&client_);
+ output_surface_ = MockDCLayerOutputSurface::Create();
+ output_surface_->BindToClient(&output_surface_client_);
- resource_provider_ =
- std::make_unique<DisplayResourceProviderGL>(provider_.get());
+ resource_provider_ = std::make_unique<DisplayResourceProviderSkia>();
+ lock_set_for_external_use_.emplace(resource_provider_.get(),
+ output_surface_.get());
child_provider_ = TestContextProvider::Create();
child_provider_->BindToCurrentThread();
@@ -247,15 +222,16 @@ class DCLayerOverlayTest : public testing::Test {
child_resource_provider_->ShutdownAndReleaseAllResources();
child_resource_provider_ = nullptr;
child_provider_ = nullptr;
+ lock_set_for_external_use_.reset();
resource_provider_ = nullptr;
output_surface_ = nullptr;
- provider_ = nullptr;
}
- scoped_refptr<TestContextProvider> provider_;
- std::unique_ptr<OverlayOutputSurface> output_surface_;
- cc::FakeOutputSurfaceClient client_;
- std::unique_ptr<DisplayResourceProviderGL> resource_provider_;
+ std::unique_ptr<MockDCLayerOutputSurface> output_surface_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ std::unique_ptr<DisplayResourceProviderSkia> resource_provider_;
+ absl::optional<DisplayResourceProviderSkia::LockSetForExternalUse>
+ lock_set_for_external_use_;
scoped_refptr<TestContextProvider> child_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::unique_ptr<OverlayProcessorWin> overlay_processor_;
@@ -310,7 +286,6 @@ TEST_F(DCLayerOverlayTest, Occluded) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(2U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.front().z_order);
EXPECT_EQ(-2, dc_layer_list.back().z_order);
// Entire underlay rect must be redrawn.
@@ -361,7 +336,6 @@ TEST_F(DCLayerOverlayTest, Occluded) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(2U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.front().z_order);
EXPECT_EQ(-2, dc_layer_list.back().z_order);
@@ -412,7 +386,6 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
&damage_rect_, &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// All rects must be redrawn at the first frame.
EXPECT_EQ(gfx::Rect(0, 0, 230, 230), damage_rect_);
@@ -456,7 +429,6 @@ TEST_F(DCLayerOverlayTest, DamageRectWithoutVideoDamage) {
std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
&damage_rect_, &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// Only the non-overlay damaged rect need to be drawn by the gl compositor
EXPECT_EQ(gfx::Rect(210, 210, 20, 20), damage_rect_);
@@ -486,7 +458,6 @@ TEST_F(DCLayerOverlayTest, DamageRect) {
std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
&damage_rect_, &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(1, dc_layer_list.back().z_order);
// Damage rect should be unchanged on initial frame because of resize, but
// should be empty on the second frame because everything was put in a
@@ -613,7 +584,6 @@ TEST_F(DCLayerOverlayTest, UnderlayDamageRectWithQuadOnTopUnchanged) {
std::move(surface_damage_rect_list), nullptr, &dc_layer_list,
&damage_rect_, &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(-1, dc_layer_list.back().z_order);
// Damage rect should be unchanged on initial frame, but should be reduced
// to the size of quad on top, and empty on the third frame.
@@ -675,7 +645,7 @@ TEST_F(DCLayerOverlayTest, RoundedCorners) {
// rounded corner mask filter for the replaced solid quad.
EXPECT_EQ(replaced_sqs->blend_mode, SkBlendMode::kDstOut);
EXPECT_EQ(SolidColorDrawQuad::MaterialCast(replaced_quad)->color,
- SK_ColorBLACK);
+ SkColors::kBlack);
EXPECT_TRUE(replaced_sqs->mask_filter_info.HasRoundedCorners());
// The whole frame is damaged.
@@ -733,7 +703,7 @@ TEST_F(DCLayerOverlayTest, RoundedCorners) {
// rounded corner mask filter for the replaced solid quad.
EXPECT_EQ(replaced_sqs->blend_mode, SkBlendMode::kDstOut);
EXPECT_EQ(SolidColorDrawQuad::MaterialCast(replaced_quad)->color,
- SK_ColorBLACK);
+ SkColors::kBlack);
EXPECT_TRUE(replaced_sqs->mask_filter_info.HasRoundedCorners());
// Only the UI is damaged.
@@ -791,7 +761,7 @@ TEST_F(DCLayerOverlayTest, RoundedCorners) {
// solid quad.
EXPECT_EQ(replaced_sqs->blend_mode, SkBlendMode::kDstOut);
EXPECT_EQ(SolidColorDrawQuad::MaterialCast(replaced_quad)->color,
- SK_ColorBLACK);
+ SkColors::kBlack);
EXPECT_TRUE(replaced_sqs->mask_filter_info.HasRoundedCorners());
// Zero root damage rect.
@@ -839,7 +809,6 @@ TEST_F(DCLayerOverlayTest, MultipleYUVOverlay) {
// Skip overlays.
EXPECT_EQ(0U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(gfx::Rect(0, 0, 220, 220), damage_rect_);
// Check whether all 3 quads including two YUV quads are still in the render
@@ -887,7 +856,6 @@ TEST_F(DCLayerOverlayTest, SetEnableDCLayers) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(1U, dc_layer_list.size());
- EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
EXPECT_EQ(1, dc_layer_list.back().z_order);
EXPECT_EQ(damage_rect_, expected_damage);
@@ -932,7 +900,6 @@ TEST_F(DCLayerOverlayTest, SetEnableDCLayers) {
&damage_rect_, &content_bounds_);
EXPECT_EQ(0u, dc_layer_list.size());
- EXPECT_EQ(0u, output_surface_->bind_framebuffer_count());
EXPECT_EQ(damage_rect_, expected_damage);
Mock::VerifyAndClearExpectations(output_surface_.get());
diff --git a/chromium/components/viz/service/display/overlay_processor_delegated.cc b/chromium/components/viz/service/display/overlay_processor_delegated.cc
index ca130dab48b..b124668c2fa 100644
--- a/chromium/components/viz/service/display/overlay_processor_delegated.cc
+++ b/chromium/components/viz/service/display/overlay_processor_delegated.cc
@@ -100,9 +100,11 @@ OverlayProcessorDelegated::OverlayProcessorDelegated(
OverlayProcessorDelegated::~OverlayProcessorDelegated() = default;
+DBG_FLAG_FBOOL("delegated.enable.quad_split", quad_split)
+
bool OverlayProcessorDelegated::DisableSplittingQuads() const {
- // If there is quads to split these will happen delegee side.
- return true;
+ // This determines if we will split quads on delegation or on delegee side.
+ return !quad_split();
}
constexpr size_t kTooManyQuads = 64;
@@ -132,6 +134,11 @@ bool OverlayProcessorDelegated::AttemptWithStrategies(
!render_pass_backdrop_filters.empty())
return false;
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane),
+ is_delegated_context);
+
std::vector<QuadList::Iterator> candidate_quads;
int num_quads_skipped = 0;
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
@@ -144,10 +151,7 @@ bool OverlayProcessorDelegated::AttemptWithStrategies(
gfx::Vector2dF(display_rect.origin().x(), display_rect.origin().y()),
base::StringPrintf("m=%d rid=%d", static_cast<int>(it->material),
it->resources.begin()->value()));
- auto candidate_status = OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix, *it,
- GetPrimaryPlaneDisplayRect(primary_plane), &candidate,
- is_delegated_context);
+ auto candidate_status = candidate_factory.FromDrawQuad(*it, candidate);
if (candidate_status == OverlayCandidate::CandidateStatus::kSuccess) {
if (it->material == DrawQuad::Material::kSolidColor) {
DBG_DRAW_RECT("delegated.overlay.color", candidate.display_rect);
@@ -196,6 +200,8 @@ bool OverlayProcessorDelegated::AttemptWithStrategies(
candidates->clear();
delegated_status_ = DelegationStatus::kCompositedCheckOverlayFail;
DBG_DRAW_RECT("delegated.handled.failed", each.display_rect);
+ DBG_LOG("delegated.handled.failed", "Handled failed %s",
+ each.display_rect.ToString().c_str());
return false;
}
}
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.h b/chromium/components/viz/service/display/overlay_processor_interface.h
index 22cb824f084..2d4c5ff010c 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.h
+++ b/chromium/components/viz/service/display/overlay_processor_interface.h
@@ -33,6 +33,10 @@ namespace cc {
class DisplayResourceProvider;
}
+namespace gpu {
+class SharedImageInterface;
+}
+
namespace viz {
struct DebugRendererSettings;
class OutputSurface;
@@ -95,9 +99,6 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
// Opacity of the overlay independent of buffer alpha. When rendered:
// src-alpha = |opacity| * buffer-component-alpha.
float opacity;
- // TODO(weiliangc): Should be replaced by SharedImage mailbox.
- // Gpu fence to wait for before overlay is ready for display.
- unsigned gpu_fence_id;
// Mailbox corresponding to the buffer backing the primary plane.
gpu::Mailbox mailbox;
// Hints for overlay prioritization.
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.cc b/chromium/components/viz/service/display/overlay_processor_ozone.cc
index ead3abb6834..3ae5364b310 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.cc
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.cc
@@ -61,6 +61,9 @@ void ConvertToOzoneOverlaySurface(
ozone_candidate->requires_overlay = overlay_candidate.requires_overlay;
ozone_candidate->priority_hint = overlay_candidate.priority_hint;
ozone_candidate->rounded_corners = overlay_candidate.rounded_corners;
+ // That can be a solid color quad.
+ if (!overlay_candidate.is_solid_color)
+ ozone_candidate->background_color = overlay_candidate.color;
}
uint32_t MailboxToUInt32(const gpu::Mailbox& mailbox) {
@@ -68,13 +71,6 @@ uint32_t MailboxToUInt32(const gpu::Mailbox& mailbox) {
(mailbox.name[2] << 8) + mailbox.name[3];
}
-void ReportSharedImageExists(bool exists) {
- UMA_HISTOGRAM_BOOLEAN(
- "Compositing.Display.OverlayProcessorOzone."
- "SharedImageExists",
- exists);
-}
-
#if BUILDFLAG(IS_CHROMEOS_ASH)
bool AllowColorSpaceCombination(
const gfx::ColorSpace& source_color_space,
@@ -132,7 +128,6 @@ OverlayProcessorOzone::OverlayProcessorOzone(
NOTREACHED();
}
}
- MaybeObserveHardwareCapabilities();
}
OverlayProcessorOzone::~OverlayProcessorOzone() = default;
@@ -148,6 +143,8 @@ bool OverlayProcessorOzone::NeedsSurfaceDamageRectList() const {
void OverlayProcessorOzone::CheckOverlaySupportImpl(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane* primary_plane,
OverlayCandidateList* surfaces) {
+ MaybeObserveHardwareCapabilities();
+
auto full_size = surfaces->size();
if (primary_plane)
full_size += 1;
@@ -256,27 +253,42 @@ void OverlayProcessorOzone::CheckOverlaySupportImpl(
}
void OverlayProcessorOzone::MaybeObserveHardwareCapabilities() {
+ if (tried_observing_hardware_capabilities_) {
+ return;
+ }
+ tried_observing_hardware_capabilities_ = true;
+
// HardwareCapabilities isn't necessary unless attempting multiple overlays.
if (max_overlays_config_ <= 1) {
return;
}
- overlay_candidates_->ObserveHardwareCapabilities(
- base::BindRepeating(&OverlayProcessorOzone::ReceiveHardwareCapabilities,
- weak_ptr_factory_.GetWeakPtr()));
+ if (overlay_candidates_) {
+ overlay_candidates_->ObserveHardwareCapabilities(
+ base::BindRepeating(&OverlayProcessorOzone::ReceiveHardwareCapabilities,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
}
void OverlayProcessorOzone::ReceiveHardwareCapabilities(
ui::HardwareCapabilities hardware_capabilities) {
- // Subtract 1 because one of these overlay capable planes will be needed for
- // the primary plane.
- int max_overlays_supported =
- hardware_capabilities.num_overlay_capable_planes - 1;
- max_overlays_considered_ =
- std::min(max_overlays_supported, max_overlays_config_);
-
- UMA_HISTOGRAM_COUNTS_100(
- "Compositing.Display.OverlayProcessorOzone.MaxOverlaysSupported",
- max_overlays_supported);
+ UMA_HISTOGRAM_BOOLEAN(
+ "Compositing.Display.OverlayProcessorOzone.HardwareCapabilitiesIsValid",
+ hardware_capabilities.is_valid);
+ if (hardware_capabilities.is_valid) {
+ // Subtract 1 because one of these overlay capable planes will be needed for
+ // the primary plane.
+ int max_overlays_supported =
+ hardware_capabilities.num_overlay_capable_planes - 1;
+ max_overlays_considered_ =
+ std::min(max_overlays_supported, max_overlays_config_);
+
+ UMA_HISTOGRAM_COUNTS_100(
+ "Compositing.Display.OverlayProcessorOzone.MaxPlanesSupported",
+ hardware_capabilities.num_overlay_capable_planes);
+ } else {
+ // Default to attempting 1 overlay if we get an invalid response.
+ max_overlays_considered_ = 1;
+ }
// Different hardware capabilities may mean a different result for a specific
// combination of overlays, so clear this cache.
@@ -300,11 +312,6 @@ bool OverlayProcessorOzone::SetNativePixmapForCandidate(
bool is_primary) {
DCHECK(shared_image_interface_);
- UMA_HISTOGRAM_BOOLEAN(
- "Compositing.Display.OverlayProcessorOzone."
- "IsCandidateSharedImage",
- mailbox.IsSharedImage());
-
if (!mailbox.IsSharedImage())
return false;
@@ -318,10 +325,8 @@ bool OverlayProcessorOzone::SetNativePixmapForCandidate(
// candidate. We will try again next frame.
DLOG(ERROR) << "Unable to find the NativePixmap corresponding to the "
"overlay candidate";
- ReportSharedImageExists(false);
return false;
}
- ReportSharedImageExists(true);
if (is_primary && (candidate->buffer_size != native_pixmap->GetBufferSize() ||
candidate->format != native_pixmap->GetBufferFormat())) {
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.h b/chromium/components/viz/service/display/overlay_processor_ozone.h
index 5809388e329..b0ecacb1bb9 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.h
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.h
@@ -56,9 +56,11 @@ class VIZ_SERVICE_EXPORT OverlayProcessorOzone
const gpu::Mailbox& mailbox,
bool is_primary);
+ bool tried_observing_hardware_capabilities_ = false;
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates_;
const std::vector<OverlayStrategy> available_strategies_;
gpu::SharedImageInterface* const shared_image_interface_;
+
base::WeakPtrFactory<OverlayProcessorOzone> weak_ptr_factory_{this};
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc b/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc
index b8b5d5d914b..d8c9251261a 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_processor_ozone_unittest.cc
@@ -261,22 +261,29 @@ class TestOverlayProcessorOzone : public OverlayProcessorOzone {
};
TEST(OverlayProcessorOzoneTest, ObserveHardwareCapabilites) {
+ OverlayCandidateList candidates;
// Enable 4 overlays
const std::vector<base::test::ScopedFeatureList::FeatureAndParams>
feature_and_params_list = {{features::kEnableOverlayPrioritization, {}},
{features::kUseMultipleOverlays,
{{features::kMaxOverlaysParam, "4"}}}};
- base::test::ScopedFeatureList features;
- features.InitWithFeaturesAndParameters(feature_and_params_list, {});
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitWithFeaturesAndParameters(feature_and_params_list, {});
+ // When overlay prioritization is explicitly disabled (Lacros) we should
+ // skip multiple overlays tests.
+ if (!features::IsOverlayPrioritizationEnabled()) {
+ GTEST_SKIP();
+ }
auto fake_candidates_unique = std::make_unique<FakeOverlayCandidatesOzone>();
auto* fake_candidates = fake_candidates_unique.get();
+ TestOverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
+ nullptr);
// No receive_callback yet.
EXPECT_TRUE(fake_candidates->receive_callback().is_null());
- TestOverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
- nullptr);
+ processor.CheckOverlaySupport(nullptr, &candidates);
// Receive callback is set.
EXPECT_FALSE(fake_candidates->receive_callback().is_null());
@@ -284,32 +291,44 @@ TEST(OverlayProcessorOzoneTest, ObserveHardwareCapabilites) {
EXPECT_EQ(processor.MaxOverlaysConsidered(), 1);
ui::HardwareCapabilities hc;
+ hc.is_valid = true;
hc.num_overlay_capable_planes = 6;
fake_candidates->receive_callback().Run(hc);
// Uses max_overlays_config_ = 4.
EXPECT_EQ(processor.MaxOverlaysConsidered(), 4);
+ hc.is_valid = true;
hc.num_overlay_capable_planes = 4;
fake_candidates->receive_callback().Run(hc);
// Uses (num_overlay_capable_planes - 1) = 3.
EXPECT_EQ(processor.MaxOverlaysConsidered(), 3);
+
+ hc.is_valid = false;
+ hc.num_overlay_capable_planes = 0;
+ fake_candidates->receive_callback().Run(hc);
+
+ // Defaults to 1 overlay when receiving an invalid response.
+ EXPECT_EQ(processor.MaxOverlaysConsidered(), 1);
}
TEST(OverlayProcessorOzoneTest, NoObserveHardwareCapabilites) {
+ OverlayCandidateList candidates;
// Multiple overlays disabled.
- base::test::ScopedFeatureList features;
- features.InitAndDisableFeature(features::kUseMultipleOverlays);
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndDisableFeature(features::kUseMultipleOverlays);
auto fake_candidates_unique = std::make_unique<FakeOverlayCandidatesOzone>();
auto* fake_candidates = fake_candidates_unique.get();
+ OverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
+ nullptr);
+
// No receive_callback yet.
EXPECT_TRUE(fake_candidates->receive_callback().is_null());
- TestOverlayProcessorOzone processor(std::move(fake_candidates_unique), {},
- nullptr);
+ processor.CheckOverlaySupport(nullptr, &candidates);
// Receive callback is still unset because multiple overlays is disabled.
EXPECT_TRUE(fake_candidates->receive_callback().is_null());
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
index e85914bee01..b42bc066367 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -47,7 +47,7 @@ namespace {
// or why we aren't.
enum class AttemptingMultipleOverlays {
kYes = 0,
- kNoTooFewMaxOverlaysConsidered = 1,
+ kNoFeatureDisabled = 1,
kNoRequiredOverlay = 2,
kNoUnsupportedStrategy = 3,
kMaxValue = kNoUnsupportedStrategy,
@@ -56,10 +56,10 @@ enum class AttemptingMultipleOverlays {
constexpr char kShouldAttemptMultipleOverlaysHistogramName[] =
"Compositing.Display.OverlayProcessorUsingStrategy."
"ShouldAttemptMultipleOverlays";
-constexpr char kNumOverlaysAttemptedHistogramName[] =
- "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysAttempted";
constexpr char kNumOverlaysPromotedHistogramName[] =
"Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysPromoted";
+constexpr char kNumOverlaysAttemptedHistogramName[] =
+ "Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysAttempted";
constexpr char kNumOverlaysFailedHistogramName[] =
"Compositing.Display.OverlayProcessorUsingStrategy.NumOverlaysFailed";
@@ -161,6 +161,10 @@ void OverlayProcessorUsingStrategy::ProcessForOverlays(
auto* render_pass = render_passes->back().get();
bool success = false;
+ UMA_HISTOGRAM_COUNTS_1000(
+ "Compositing.Display.OverlayProcessorUsingStrategy.NumQuadsConsidered",
+ render_pass->quad_list.size());
+
DBG_DRAW_RECT("overlay.incoming.damage", (*damage_rect));
for (auto&& each : surface_damage_rect_list) {
DBG_DRAW_RECT("overlay.surface.damage", each);
@@ -185,6 +189,8 @@ void OverlayProcessorUsingStrategy::ProcessForOverlays(
LogCheckOverlaySupportMetrics();
DCHECK(candidates->empty() || success);
+ UMA_HISTOGRAM_COUNTS_100(kNumOverlaysPromotedHistogramName,
+ candidates->size());
UpdateOverlayStatusMap(*candidates);
UpdateDamageRect(surface_damage_rect_list, *damage_rect);
@@ -413,7 +419,7 @@ void OverlayProcessorUsingStrategy::UpdateDamageRect(
const auto& status = it.second;
if (status.plane_z_order != 0) {
RecordOverlayDamageRectHistograms(status.plane_z_order > 0,
- status.damage_area_estimate != 0,
+ status.damage_area_estimate != 0.f,
damage_rect.IsEmpty());
}
}
@@ -496,11 +502,11 @@ void OverlayProcessorUsingStrategy::SortProposedOverlayCandidatesPrioritized(
// for low latency surfaces (inking like in the google keeps application).
const bool force_update = it->candidate.overlay_damage_index !=
OverlayCandidate::kInvalidDamageIndex &&
- it->candidate.damage_area_estimate != 0;
- track_data.AddRecord(
- frame_sequence_number_,
- static_cast<float>(it->candidate.damage_area_estimate) / display_area,
- it->candidate.resource_id, tracker_config_, force_update);
+ it->candidate.damage_area_estimate != 0.f;
+ track_data.AddRecord(frame_sequence_number_,
+ it->candidate.damage_area_estimate / display_area,
+ it->candidate.resource_id, tracker_config_,
+ force_update);
// Here a series of criteria are considered for wholesale rejection of a
// candidate. The rational for rejection is usually power improvements but
// this can indirectly reallocate limited overlay resources to another
@@ -585,6 +591,11 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized(
num_proposed_pre_sort);
SortProposedOverlayCandidatesPrioritized(&proposed_candidates);
+ if (proposed_candidates.size() == 0) {
+ LogStrategyEnumUMA(num_proposed_pre_sort != 0
+ ? OverlayStrategy::kNoStrategyFailMin
+ : OverlayStrategy::kNoStrategyUsed);
+ }
if (ShouldAttemptMultipleOverlays(proposed_candidates)) {
auto* render_pass = render_pass_list->back().get();
@@ -665,11 +676,7 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized(
}
RegisterOverlayRequirement(has_required_overlay);
- if (proposed_candidates.size() == 0) {
- LogStrategyEnumUMA(num_proposed_pre_sort != 0
- ? OverlayStrategy::kNoStrategyFailMin
- : OverlayStrategy::kNoStrategyUsed);
- } else {
+ if (proposed_candidates.size() != 0) {
LogStrategyEnumUMA(OverlayStrategy::kNoStrategyAllFail);
}
OnOverlaySwitchUMA(ProposedCandidateKey());
@@ -678,10 +685,9 @@ bool OverlayProcessorUsingStrategy::AttemptWithStrategiesPrioritized(
bool OverlayProcessorUsingStrategy::ShouldAttemptMultipleOverlays(
const std::vector<OverlayProposedCandidate>& sorted_candidates) {
- if (max_overlays_considered_ <= 1) {
- UMA_HISTOGRAM_ENUMERATION(
- kShouldAttemptMultipleOverlaysHistogramName,
- AttemptingMultipleOverlays::kNoTooFewMaxOverlaysConsidered);
+ if (max_overlays_config_ <= 1) {
+ UMA_HISTOGRAM_ENUMERATION(kShouldAttemptMultipleOverlaysHistogramName,
+ AttemptingMultipleOverlays::kNoFeatureDisabled);
return false;
}
@@ -718,6 +724,7 @@ bool OverlayProcessorUsingStrategy::AttemptMultipleOverlays(
OverlayCandidateList& candidates) {
if (sorted_candidates.empty()) {
UMA_HISTOGRAM_COUNTS_100(kNumOverlaysAttemptedHistogramName, 0);
+ UMA_HISTOGRAM_COUNTS_100(kNumOverlaysFailedHistogramName, 0);
return false;
}
@@ -796,12 +803,11 @@ bool OverlayProcessorUsingStrategy::AttemptMultipleOverlays(
UMA_HISTOGRAM_COUNTS_100(kNumOverlaysAttemptedHistogramName,
num_overlays_attempted);
- UMA_HISTOGRAM_COUNTS_100(kNumOverlaysPromotedHistogramName,
- num_overlays_promoted);
UMA_HISTOGRAM_COUNTS_100(kNumOverlaysFailedHistogramName,
num_overlays_attempted - num_overlays_promoted);
if (candidates.empty()) {
+ LogStrategyEnumUMA(OverlayStrategy::kNoStrategyAllFail);
return false;
}
@@ -825,6 +831,7 @@ bool OverlayProcessorUsingStrategy::AttemptMultipleOverlays(
// Commit successful candidates.
for (auto& test_candidate : test_candidates) {
test_candidate.strategy->CommitCandidate(test_candidate, render_pass);
+ LogStrategyEnumUMA(test_candidate.strategy->GetUMAEnum());
}
return true;
diff --git a/chromium/components/viz/service/display/overlay_processor_using_strategy.h b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
index 0a76a92ba9f..e355e7e624f 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.h
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
@@ -154,7 +154,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
gfx::Rect overlay_rect;
gfx::RectF damage_rect;
uint32_t damage_index;
- int damage_area_estimate;
+ float damage_area_estimate;
bool has_mask_filter;
int plane_z_order;
bool is_underlay;
diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
index 9deafb078e0..8899c3e3b57 100644
--- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
@@ -51,10 +51,11 @@ bool OverlayStrategyFullscreen::Attempt(
return false;
OverlayCandidate candidate;
- if (OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- quad, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) != OverlayCandidate::CandidateStatus::kSuccess) {
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
+ if (candidate_factory.FromDrawQuad(quad, candidate) !=
+ OverlayCandidate::CandidateStatus::kSuccess) {
return false;
}
@@ -108,10 +109,11 @@ void OverlayStrategyFullscreen::ProposePrioritized(
return;
OverlayCandidate candidate;
- if (OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- quad, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) != OverlayCandidate::CandidateStatus::kSuccess) {
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
+ if (candidate_factory.FromDrawQuad(quad, candidate) !=
+ OverlayCandidate::CandidateStatus::kSuccess) {
return;
}
diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
index df36ded05b5..78612ba8c17 100644
--- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
@@ -35,13 +35,15 @@ bool OverlayStrategySingleOnTop::Attempt(
QuadList* quad_list = &render_pass->quad_list;
// Build a list of candidates with the associated quad.
OverlayCandidate best_candidate;
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
+
auto best_quad_it = quad_list->end();
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
OverlayCandidate candidate;
- if (OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- *it, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) == OverlayCandidate::CandidateStatus::kSuccess &&
+ if (candidate_factory.FromDrawQuad(*it, candidate) ==
+ OverlayCandidate::CandidateStatus::kSuccess &&
!candidate.has_mask_filter &&
!OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) {
// If the candidate has been promoted previously and has not changed
@@ -92,12 +94,14 @@ void OverlayStrategySingleOnTop::ProposePrioritized(
auto* render_pass = render_pass_list->back().get();
QuadList* quad_list = &render_pass->quad_list;
// Build a list of candidates with the associated quad.
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
+
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
OverlayCandidate candidate;
- if (OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- *it, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) == OverlayCandidate::CandidateStatus::kSuccess &&
+ if (candidate_factory.FromDrawQuad(*it, candidate) ==
+ OverlayCandidate::CandidateStatus::kSuccess &&
!candidate.has_mask_filter &&
!OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) {
candidates->push_back({it, candidate, this});
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.cc b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
index c7aa14df543..145eaffe805 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
@@ -36,13 +36,14 @@ bool OverlayStrategyUnderlay::Attempt(
DCHECK(candidate_list->empty());
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
+ auto candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
OverlayCandidate candidate;
- if (OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- *it, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) != OverlayCandidate::CandidateStatus::kSuccess ||
+ if (candidate_factory.FromDrawQuad(*it, candidate) !=
+ OverlayCandidate::CandidateStatus::kSuccess ||
(opaque_mode_ == OpaqueMode::RequireOpaqueCandidates &&
!candidate.is_opaque)) {
continue;
@@ -51,7 +52,7 @@ bool OverlayStrategyUnderlay::Attempt(
// Filters read back the framebuffer to get the pixel values that need to
// be filtered. This is a problem when there are hardware planes because
// the planes are not composited until they are on the display controller.
- if (OverlayCandidate::IsOccludedByFilteredQuad(
+ if (candidate_factory.IsOccludedByFilteredQuad(
candidate, quad_list.begin(), it, render_pass_backdrop_filters)) {
continue;
}
@@ -101,14 +102,14 @@ void OverlayStrategyUnderlay::ProposePrioritized(
std::vector<gfx::Rect>* content_bounds) {
auto* render_pass = render_pass_list->back().get();
QuadList& quad_list = render_pass->quad_list;
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
OverlayCandidate candidate;
-
- if (OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- *it, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) != OverlayCandidate::CandidateStatus::kSuccess ||
+ if (candidate_factory.FromDrawQuad(*it, candidate) !=
+ OverlayCandidate::CandidateStatus::kSuccess ||
(opaque_mode_ == OpaqueMode::RequireOpaqueCandidates &&
!candidate.is_opaque)) {
continue;
@@ -120,13 +121,13 @@ void OverlayStrategyUnderlay::ProposePrioritized(
// If we are requiring an overlay, then we should not block it due to this
// condition.
if (!candidate.requires_overlay &&
- OverlayCandidate::IsOccludedByFilteredQuad(
+ candidate_factory.IsOccludedByFilteredQuad(
candidate, quad_list.begin(), it, render_pass_backdrop_filters)) {
continue;
}
- candidate.damage_area_estimate = OverlayCandidate::EstimateVisibleDamage(
- *it, surface_damage_rect_list, quad_list.begin(), it);
+ candidate.damage_area_estimate = candidate_factory.EstimateVisibleDamage(
+ *it, candidate, quad_list.begin(), it);
candidates->push_back({it, candidate, this});
}
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
index 7746bf26d3d..db9fe19c0df 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -60,6 +60,10 @@ bool OverlayStrategyUnderlayCast::Attempt(
QuadList& quad_list = render_pass->quad_list;
bool found_underlay = false;
gfx::Rect content_rect;
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
+
for (const auto* quad : base::Reversed(quad_list)) {
if (OverlayCandidate::IsInvisibleQuad(quad))
continue;
@@ -79,18 +83,15 @@ bool OverlayStrategyUnderlayCast::Attempt(
// quad is supposed to be to replace it with a transparent quad to allow
// the underlay to be visible.
// VIDEO_HOLE implies it requires overlay.
- is_underlay =
- quad->material == DrawQuad::Material::kVideoHole &&
- OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- quad, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) == OverlayCandidate::CandidateStatus::kSuccess;
+ is_underlay = quad->material == DrawQuad::Material::kVideoHole &&
+ candidate_factory.FromDrawQuad(quad, candidate) ==
+ OverlayCandidate::CandidateStatus::kSuccess;
found_underlay = is_underlay;
}
if (!found_underlay && quad->material == DrawQuad::Material::kSolidColor) {
const SolidColorDrawQuad* solid = SolidColorDrawQuad::MaterialCast(quad);
- if (solid->color == SK_ColorBLACK)
+ if (solid->color == SkColors::kBlack)
continue;
}
@@ -110,10 +111,8 @@ bool OverlayStrategyUnderlayCast::Attempt(
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
OverlayCandidate candidate;
if (it->material != DrawQuad::Material::kVideoHole ||
- OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- *it, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) != OverlayCandidate::CandidateStatus::kSuccess) {
+ candidate_factory.FromDrawQuad(*it, candidate) !=
+ OverlayCandidate::CandidateStatus::kSuccess) {
continue;
}
@@ -145,6 +144,10 @@ void OverlayStrategyUnderlayCast::ProposePrioritized(
QuadList& quad_list = render_pass->quad_list;
OverlayCandidate candidate;
auto overlay_iter = quad_list.end();
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
+
// Original code did reverse iteration.
// Here we do forward but find the last one. which should be the same thing.
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
@@ -160,10 +163,8 @@ void OverlayStrategyUnderlayCast::ProposePrioritized(
// the underlay to be visible.
// VIDEO_HOLE implies it requires overlay.
if (it->material == DrawQuad::Material::kVideoHole &&
- OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- *it, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) == OverlayCandidate::CandidateStatus::kSuccess) {
+ candidate_factory.FromDrawQuad(*it, candidate) ==
+ OverlayCandidate::CandidateStatus::kSuccess) {
overlay_iter = it;
}
}
@@ -190,6 +191,10 @@ bool OverlayStrategyUnderlayCast::AttemptPrioritized(
QuadList& quad_list = render_pass->quad_list;
bool found_underlay = false;
gfx::Rect content_rect;
+ OverlayCandidateFactory candidate_factory = OverlayCandidateFactory(
+ render_pass, resource_provider, surface_damage_rect_list,
+ &output_color_matrix, GetPrimaryPlaneDisplayRect(primary_plane));
+
for (const auto* quad : base::Reversed(quad_list)) {
if (OverlayCandidate::IsInvisibleQuad(quad))
continue;
@@ -209,18 +214,15 @@ bool OverlayStrategyUnderlayCast::AttemptPrioritized(
// quad is supposed to be to replace it with a transparent quad to allow
// the underlay to be visible.
// VIDEO_HOLE implies it requires overlay.
- is_underlay =
- quad->material == DrawQuad::Material::kVideoHole &&
- OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- quad, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) == OverlayCandidate::CandidateStatus::kSuccess;
+ is_underlay = quad->material == DrawQuad::Material::kVideoHole &&
+ candidate_factory.FromDrawQuad(quad, candidate) ==
+ OverlayCandidate::CandidateStatus::kSuccess;
found_underlay = is_underlay;
}
if (!found_underlay && quad->material == DrawQuad::Material::kSolidColor) {
const SolidColorDrawQuad* solid = SolidColorDrawQuad::MaterialCast(quad);
- if (solid->color == SK_ColorBLACK)
+ if (solid->color == SkColors::kBlack)
continue;
}
@@ -240,10 +242,8 @@ bool OverlayStrategyUnderlayCast::AttemptPrioritized(
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
OverlayCandidate candidate;
if (it->material != DrawQuad::Material::kVideoHole ||
- OverlayCandidate::FromDrawQuad(
- resource_provider, surface_damage_rect_list, output_color_matrix,
- *it, GetPrimaryPlaneDisplayRect(primary_plane),
- &candidate) != OverlayCandidate::CandidateStatus::kSuccess) {
+ candidate_factory.FromDrawQuad(*it, candidate) !=
+ OverlayCandidate::CandidateStatus::kSuccess) {
continue;
}
diff --git a/chromium/components/viz/service/display/overlay_unittest.cc b/chromium/components/viz/service/display/overlay_unittest.cc
index e5a1102403b..954d384fa24 100644
--- a/chromium/components/viz/service/display/overlay_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_unittest.cc
@@ -22,6 +22,7 @@
#include "cc/test/resource_provider_test_utils.h"
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/features.h"
+#include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
@@ -31,8 +32,7 @@
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/service/display/ca_layer_overlay.h"
-#include "components/viz/service/display/display_resource_provider_gl.h"
-#include "components/viz/service/display/gl_renderer.h"
+#include "components/viz/service/display/display_resource_provider_skia.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
@@ -44,6 +44,7 @@
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
#include "components/viz/service/display/overlay_strategy_underlay_cast.h"
+#include "components/viz/test/fake_skia_output_surface.h"
#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
#include "gpu/config/gpu_finch_features.h"
@@ -392,60 +393,6 @@ class FullThresholdUnderlayOverlayProcessor : public DefaultOverlayProcessor {
}
};
-class OverlayOutputSurface : public OutputSurface {
- public:
- explicit OverlayOutputSurface(
- scoped_refptr<TestContextProvider> context_provider)
- : OutputSurface(std::move(context_provider)) {
- is_displayed_as_overlay_plane_ = true;
- capabilities_.supports_viewporter = true;
- }
-
- // OutputSurface implementation.
- void BindToClient(OutputSurfaceClient* client) override {}
- void EnsureBackbuffer() override {}
- void DiscardBackbuffer() override {}
- void BindFramebuffer() override { bind_framebuffer_count_ += 1; }
- void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) override {
- size_ = size;
- }
- void SwapBuffers(OutputSurfaceFrame frame) override {}
- uint32_t GetFramebufferCopyTextureFormat() override {
- // TestContextProvider has no real framebuffer, just use RGB.
- return GL_RGB;
- }
- bool HasExternalStencilTest() const override { return false; }
- void ApplyExternalStencil() override {}
- bool IsDisplayedAsOverlayPlane() const override {
- return is_displayed_as_overlay_plane_;
- }
- unsigned GetOverlayTextureId() const override { return 10000; }
- unsigned UpdateGpuFence() override { return 0; }
- void SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback) override {}
- void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
- gfx::OverlayTransform GetDisplayTransform() override {
- return gfx::OVERLAY_TRANSFORM_NONE;
- }
-
- void set_is_displayed_as_overlay_plane(bool value) {
- is_displayed_as_overlay_plane_ = value;
- }
-
- unsigned bind_framebuffer_count() const { return bind_framebuffer_count_; }
- void clear_bind_framebuffer_count() { bind_framebuffer_count_ = 0; }
- gfx::Size size() const { return size_; }
-
- private:
- gfx::Size size_;
- bool is_displayed_as_overlay_plane_;
- unsigned bind_framebuffer_count_ = 0;
-};
-
std::unique_ptr<AggregatedRenderPass> CreateRenderPass() {
AggregatedRenderPassId render_pass_id{1};
gfx::Rect output_rect(0, 0, 256, 256);
@@ -741,13 +688,12 @@ template <typename OverlayProcessorType>
class OverlayTest : public testing::Test {
protected:
void SetUp() override {
- provider_ = TestContextProvider::Create();
- provider_->BindToCurrentThread();
- output_surface_ = std::make_unique<OverlayOutputSurface>(provider_);
- output_surface_->BindToClient(&client_);
+ output_surface_ = FakeSkiaOutputSurface::Create3d();
+ output_surface_->BindToClient(&output_surface_client_);
- resource_provider_ =
- std::make_unique<DisplayResourceProviderGL>(provider_.get());
+ resource_provider_ = std::make_unique<DisplayResourceProviderSkia>();
+ lock_set_for_external_use_.emplace(resource_provider_.get(),
+ output_surface_.get());
child_provider_ = TestContextProvider::Create();
child_provider_->BindToCurrentThread();
@@ -761,9 +707,9 @@ class OverlayTest : public testing::Test {
child_resource_provider_->ShutdownAndReleaseAllResources();
child_resource_provider_ = nullptr;
child_provider_ = nullptr;
+ lock_set_for_external_use_.reset();
resource_provider_ = nullptr;
output_surface_ = nullptr;
- provider_ = nullptr;
}
void AddExpectedRectToOverlayProcessor(const gfx::RectF& rect) {
@@ -774,10 +720,11 @@ class OverlayTest : public testing::Test {
overlay_processor_->AddScalingSequence(scaling, uses_overlay);
}
- scoped_refptr<TestContextProvider> provider_;
- std::unique_ptr<OverlayOutputSurface> output_surface_;
- cc::FakeOutputSurfaceClient client_;
- std::unique_ptr<DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<SkiaOutputSurface> output_surface_;
+ cc::FakeOutputSurfaceClient output_surface_client_;
+ std::unique_ptr<DisplayResourceProviderSkia> resource_provider_;
+ absl::optional<DisplayResourceProviderSkia::LockSetForExternalUse>
+ lock_set_for_external_use_;
scoped_refptr<TestContextProvider> child_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::unique_ptr<OverlayProcessorType> overlay_processor_;
@@ -794,11 +741,21 @@ class UseMultipleOverlaysTest : public OverlayTest<OverlayProcessorType> {
featureAndParamsList = {{features::kEnableOverlayPrioritization, {}},
{features::kUseMultipleOverlays,
{{features::kMaxOverlaysParam, "4"}}}};
- features.InitWithFeaturesAndParameters(featureAndParamsList, {});
+ scoped_features.InitWithFeaturesAndParameters(featureAndParamsList, {});
+ }
+
+ protected:
+ void SetUp() override {
+ OverlayTest<OverlayProcessorType>::SetUp();
+ // When overlay prioritization is explicitly disabled (Lacros) we should
+ // skip multiple overlays tests.
+ if (!features::IsOverlayPrioritizationEnabled()) {
+ GTEST_SKIP();
+ }
}
private:
- base::test::ScopedFeatureList features;
+ base::test::ScopedFeatureList scoped_features;
};
using FullscreenOverlayTest = OverlayTest<FullscreenOverlayProcessor>;
@@ -817,15 +774,6 @@ using SizeSortedMultiOverlayTest =
UseMultipleOverlaysTest<SizeSortedMultiOverlayProcessor>;
TEST(OverlayTest, OverlaysProcessorHasStrategy) {
- scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
- provider->BindToCurrentThread();
- OverlayOutputSurface output_surface(provider);
- cc::FakeOutputSurfaceClient client;
- output_surface.BindToClient(&client);
-
- auto resource_provider =
- std::make_unique<DisplayResourceProviderGL>(provider.get());
-
auto overlay_processor = std::make_unique<TestOverlayProcessor>();
EXPECT_GE(2U, overlay_processor->GetStrategyCount());
}
@@ -1186,14 +1134,13 @@ TEST_F(SingleOverlayOnTopTest, CandidateIdCollision) {
// Code to make sure the 'unique' tracking ids are actually identical.
OverlayCandidate candidate_a;
- SkM44 ident;
- auto ret_a = OverlayCandidate::FromDrawQuad(
- resource_provider_.get(), &surface_damage_rect_list, ident, quad_a,
- gfx::RectF(pass->output_rect), &candidate_a);
+ auto color_mat = GetIdentityColorMatrix();
+ auto candidate_factory = OverlayCandidateFactory(
+ pass.get(), resource_provider_.get(), &surface_damage_rect_list,
+ &color_mat, gfx::RectF(pass->output_rect));
+ auto ret_a = candidate_factory.FromDrawQuad(quad_a, candidate_a);
OverlayCandidate candidate_b;
- auto ret_b = OverlayCandidate::FromDrawQuad(
- resource_provider_.get(), &surface_damage_rect_list, ident, quad_b,
- gfx::RectF(pass->output_rect), &candidate_b);
+ auto ret_b = candidate_factory.FromDrawQuad(quad_b, candidate_b);
EXPECT_EQ(OverlayCandidate::CandidateStatus::kSuccess, ret_a);
EXPECT_EQ(OverlayCandidate::CandidateStatus::kSuccess, ret_b);
@@ -1203,10 +1150,9 @@ TEST_F(SingleOverlayOnTopTest, CandidateIdCollision) {
pass_list.push_back(std::move(pass));
overlay_processor_->SetFrameSequenceNumber(1);
overlay_processor_->ProcessForOverlays(
- resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
- render_pass_filters, render_pass_backdrop_filters,
- std::move(surface_damage_rect_list), nullptr, &candidate_list,
- &damage_rect_, &content_bounds_);
+ resource_provider_.get(), &pass_list, color_mat, render_pass_filters,
+ render_pass_backdrop_filters, std::move(surface_damage_rect_list),
+ nullptr, &candidate_list, &damage_rect_, &content_bounds_);
ASSERT_EQ(1U, candidate_list.size());
// Check that one quad is gone.
@@ -1235,15 +1181,14 @@ TEST_F(SingleOverlayOnTopTest, CandidateTrackIdUniqueSurface) {
kCandidateRect, SurfaceId(FrameSinkId(2, 2), LocalSurfaceId()));
// Code to make sure the 'unique' tracking ids are actually different.
OverlayCandidate candidate_a;
- SkM44 ident;
SurfaceDamageRectList surface_damage_rect_list;
- auto ret_a = OverlayCandidate::FromDrawQuad(
- resource_provider_.get(), &surface_damage_rect_list, ident, quad_a,
- gfx::RectF(pass->output_rect), &candidate_a);
+ auto color_mat = GetIdentityColorMatrix();
+ auto candidate_factory = OverlayCandidateFactory(
+ pass.get(), resource_provider_.get(), &surface_damage_rect_list,
+ &color_mat, gfx::RectF(pass->output_rect));
+ auto ret_a = candidate_factory.FromDrawQuad(quad_a, candidate_a);
OverlayCandidate candidate_b;
- auto ret_b = OverlayCandidate::FromDrawQuad(
- resource_provider_.get(), &surface_damage_rect_list, ident, quad_b,
- gfx::RectF(pass->output_rect), &candidate_b);
+ auto ret_b = candidate_factory.FromDrawQuad(quad_b, candidate_b);
EXPECT_EQ(OverlayCandidate::CandidateStatus::kSuccess, ret_a);
EXPECT_EQ(OverlayCandidate::CandidateStatus::kSuccess, ret_b);
@@ -1728,7 +1673,7 @@ TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) {
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
- quad->background_color = SK_ColorRED;
+ quad->background_color = SkColors::kRed;
OverlayCandidateList candidate_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
@@ -1750,7 +1695,7 @@ TEST_F(SingleOverlayOnTopTest, AcceptBlackBackgroundColor) {
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
- quad->background_color = SK_ColorBLACK;
+ quad->background_color = SkColors::kBlack;
OverlayCandidateList candidate_list;
OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
@@ -1772,7 +1717,7 @@ TEST_F(SingleOverlayOnTopTest, RejectBlackBackgroundColorWithBlending) {
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
- quad->background_color = SK_ColorBLACK;
+ quad->background_color = SkColors::kBlack;
quad->needs_blending = true;
OverlayCandidateList candidate_list;
@@ -1922,9 +1867,9 @@ TEST_F(UnderlayTest, ReplacementQuad) {
&damage_rect_, &content_bounds_);
ASSERT_EQ(1U, pass_list.size());
ASSERT_EQ(1U, pass_list.front()->quad_list.size());
- EXPECT_EQ(SK_ColorTRANSPARENT, static_cast<SolidColorDrawQuad*>(
- pass_list.front()->quad_list.front())
- ->color);
+ EXPECT_EQ(SkColors::kTransparent, static_cast<SolidColorDrawQuad*>(
+ pass_list.front()->quad_list.front())
+ ->color);
EXPECT_FALSE(pass_list.front()->quad_list.front()->ShouldDrawWithBlending());
EXPECT_FALSE(pass_list.front()
->quad_list.front()
@@ -2764,7 +2709,7 @@ TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) {
auto* quad = static_cast<SolidColorDrawQuad*>(main_pass->quad_list.back());
EXPECT_EQ(quad->rect, quad->visible_rect);
EXPECT_EQ(false, quad->needs_blending);
- EXPECT_EQ(SK_ColorTRANSPARENT, quad->color);
+ EXPECT_EQ(SkColors::kTransparent, quad->color);
}
TEST_F(UnderlayTest, AllowOnTop) {
@@ -2797,7 +2742,7 @@ TEST_F(UnderlayTest, AllowOnTop) {
auto* quad = static_cast<SolidColorDrawQuad*>(main_pass->quad_list.front());
EXPECT_EQ(quad->rect, quad->visible_rect);
EXPECT_EQ(false, quad->needs_blending);
- EXPECT_EQ(SK_ColorTRANSPARENT, quad->color);
+ EXPECT_EQ(SkColors::kTransparent, quad->color);
}
// Pure overlays have a very specific optimization that does not produce damage
@@ -2985,9 +2930,9 @@ TEST_F(TransitionOverlayTypeTest, MaskFilterBringsUnderlay) {
ASSERT_EQ(1U, pass_list.size());
ASSERT_EQ(2U, pass_list.front()->quad_list.size());
- EXPECT_EQ(SK_ColorBLACK, static_cast<SolidColorDrawQuad*>(
- pass_list.front()->quad_list.front())
- ->color);
+ EXPECT_EQ(SkColors::kBlack, static_cast<SolidColorDrawQuad*>(
+ pass_list.front()->quad_list.front())
+ ->color);
EXPECT_FALSE(pass_list.front()
->quad_list.front()
->shared_quad_state->are_contents_opaque);
@@ -3750,9 +3695,9 @@ TEST_F(UnderlayCastTest, ReplacementQuad) {
&damage_rect_, &content_bounds_);
ASSERT_EQ(1U, pass_list.size());
ASSERT_EQ(1U, pass_list.front()->quad_list.size());
- EXPECT_EQ(SK_ColorTRANSPARENT, static_cast<SolidColorDrawQuad*>(
- pass_list.front()->quad_list.front())
- ->color);
+ EXPECT_EQ(SkColors::kTransparent, static_cast<SolidColorDrawQuad*>(
+ pass_list.front()->quad_list.front())
+ ->color);
EXPECT_FALSE(pass_list.front()->quad_list.front()->ShouldDrawWithBlending());
EXPECT_FALSE(pass_list.front()
->quad_list.front()
@@ -4009,9 +3954,9 @@ TEST_F(UnderlayCastTest, OverlayPromotionWithMaskFilter) {
ASSERT_EQ(1U, pass_list.size());
ASSERT_EQ(1U, pass_list.front()->quad_list.size());
- EXPECT_EQ(SK_ColorBLACK, static_cast<SolidColorDrawQuad*>(
- pass_list.front()->quad_list.front())
- ->color);
+ EXPECT_EQ(SkColors::kBlack, static_cast<SolidColorDrawQuad*>(
+ pass_list.front()->quad_list.front())
+ ->color);
EXPECT_FALSE(pass_list.front()
->quad_list.front()
->shared_quad_state->are_contents_opaque);
@@ -4296,11 +4241,12 @@ TEST_F(SingleOverlayOnTopTest, IsOverlayRequiredBasic) {
child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
kSmallCandidateRect);
SurfaceDamageRectList surface_damage_rect_list;
- SkM44 default_color = GetIdentityColorMatrix();
OverlayCandidate candidate;
- OverlayCandidate::FromDrawQuad(resource_provider_.get(),
- &surface_damage_rect_list, default_color,
- new_quad, gfx::RectF(), &candidate);
+ auto color_mat = GetIdentityColorMatrix();
+ auto candidate_factory = OverlayCandidateFactory(
+ pass.get(), resource_provider_.get(), &surface_damage_rect_list,
+ &color_mat, gfx::RectF(pass->output_rect));
+ candidate_factory.FromDrawQuad(new_quad, candidate);
// Verify that a default candidate is not a required overlay.
EXPECT_FALSE(candidate.requires_overlay);
@@ -4318,11 +4264,12 @@ TEST_F(SingleOverlayOnTopTest, IsOverlayRequiredHwProtectedVideo) {
kSmallCandidateRect, gfx::ProtectedVideoType::kHardwareProtected,
YUV_420_BIPLANAR);
SurfaceDamageRectList surface_damage_rect_list;
- SkM44 default_color = GetIdentityColorMatrix();
OverlayCandidate candidate;
- OverlayCandidate::FromDrawQuad(resource_provider_.get(),
- &surface_damage_rect_list, default_color,
- new_quad, gfx::RectF(), &candidate);
+ auto color_mat = GetIdentityColorMatrix();
+ auto candidate_factory = OverlayCandidateFactory(
+ pass.get(), resource_provider_.get(), &surface_damage_rect_list,
+ &color_mat, gfx::RectF(pass->output_rect));
+ candidate_factory.FromDrawQuad(new_quad, candidate);
// Verify that a HW protected video candidate requires overlay.
EXPECT_TRUE(candidate.requires_overlay);
@@ -4341,11 +4288,12 @@ TEST_F(SingleOverlayOnTopTest, RequiredOverlayClippingAndSubsampling) {
YUV_420_BIPLANAR);
pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect;
SurfaceDamageRectList surface_damage_rect_list;
- SkM44 default_color = GetIdentityColorMatrix();
OverlayCandidate candidate;
- OverlayCandidate::FromDrawQuad(resource_provider_.get(),
- &surface_damage_rect_list, default_color,
- new_quad, gfx::RectF(), &candidate);
+ auto color_mat = GetIdentityColorMatrix();
+ auto candidate_factory = OverlayCandidateFactory(
+ pass.get(), resource_provider_.get(), &surface_damage_rect_list,
+ &color_mat, gfx::RectF(pass->output_rect));
+ candidate_factory.FromDrawQuad(new_quad, candidate);
// Default uv rect is 0.1, 0.2, 1.0, 1.0 which in the 320x240 buffer
// corresponds to 32, 48, 288x192. That maps to |kVideoCandidateRect| in the
@@ -4374,13 +4322,14 @@ TEST_F(SingleOverlayOnTopTest,
YUV_420_BIPLANAR);
pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect;
SurfaceDamageRectList surface_damage_rect_list;
- SkM44 default_color = GetIdentityColorMatrix();
gfx::RectF primary_rect(0, 0, 100, 120);
OverlayProcessorInterface::OutputSurfaceOverlayPlane primary_plane;
OverlayCandidate candidate;
- OverlayCandidate::FromDrawQuad(resource_provider_.get(),
- &surface_damage_rect_list, default_color,
- new_quad, primary_rect, &candidate);
+ auto color_mat = GetIdentityColorMatrix();
+ auto candidate_factory = OverlayCandidateFactory(
+ pass.get(), resource_provider_.get(), &surface_damage_rect_list,
+ &color_mat, primary_rect);
+ candidate_factory.FromDrawQuad(new_quad, candidate);
// Default uv rect is 0.1, 0.2, 1.0, 1.0 which in the 320x240 buffer
// corresponds to 32, 48, 288x192. That maps to |kVideoCandidateRect| in the
@@ -4449,7 +4398,7 @@ TEST_F(UnderlayTest, EstimateOccludedDamage) {
kCandidateSmall * kCandidateSmall,
kCandidateSmall * kCandidateSmall - kOccluderWidth * kOccluderWidth,
kCandidateLarge * kCandidateLarge - kOccluderWidth * kOccluderWidth * 2,
- kCandidateLarge * kCandidateLarge * 4 -
+ kOverlayRect.width() * kOverlayRect.height() -
kOccluderWidth * kOccluderWidth * 2};
static_assert(
@@ -4477,21 +4426,22 @@ TEST_F(UnderlayTest, EstimateOccludedDamage) {
if (kCandidateUseSurfaceIndex[i]) {
damaged_shared_quad_state->overlay_damage_index =
surface_damage_rect_list.size();
- surface_damage_rect_list.emplace_back(kCandidateRects[i]);
} else {
damaged_shared_quad_state->overlay_damage_index.reset();
}
+ surface_damage_rect_list.emplace_back(kCandidateRects[i]);
auto* quad_candidate = CreateCandidateQuadAt(
resource_provider_.get(), child_resource_provider_.get(),
child_provider_.get(), damaged_shared_quad_state, pass.get(),
kCandidateRects[i]);
- SkM44 default_color = GetIdentityColorMatrix();
OverlayCandidate candidate;
- OverlayCandidate::FromDrawQuad(resource_provider_.get(),
- &surface_damage_rect_list, default_color,
- quad_candidate, gfx::RectF(), &candidate);
+ auto color_mat = GetIdentityColorMatrix();
+ auto candidate_factory = OverlayCandidateFactory(
+ pass.get(), resource_provider_.get(), &surface_damage_rect_list,
+ &color_mat, gfx::RectF());
+ candidate_factory.FromDrawQuad(quad_candidate, candidate);
// Before the 'EstimateOccludedDamage' function is called the damage area
// will just be whatever comes from the |surface_damage_rect_list|.
@@ -4508,8 +4458,8 @@ TEST_F(UnderlayTest, EstimateOccludedDamage) {
// Now we test the opaque occlusion provided by 'EstimateOccludedDamage'
// function.
- candidate.damage_area_estimate = OverlayCandidate::EstimateVisibleDamage(
- quad_candidate, &surface_damage_rect_list, quad_list.begin(),
+ candidate.damage_area_estimate = candidate_factory.EstimateVisibleDamage(
+ quad_candidate, candidate, quad_list.begin(),
std::next(quad_list.begin(), occluder_iter_count));
ASSERT_EQ(kExpectedDamages[i], candidate.damage_area_estimate);
@@ -4710,6 +4660,41 @@ TEST_F(DelegatedTest, TestClipHandCrafted) {
EXPECT_RECTF_NEAR(uv_rect, candidate_list[0].uv_rect, 0.01f);
}
+TEST_F(DelegatedTest, TestVisibleRectClip) {
+ auto pass = CreateRenderPass();
+ const auto kSmallCandidateRect = gfx::Rect(0, 0, 100, 100);
+ const auto kTestClip = gfx::Rect(0, 50, 50, 50);
+ auto* tex_rect = CreateCandidateQuadAt(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
+ tex_rect->uv_bottom_right = gfx::PointF(1, 1);
+ tex_rect->uv_top_left = gfx::PointF(0, 0);
+ tex_rect->visible_rect = kTestClip;
+ // Check for potential candidates.
+ OverlayCandidateList candidate_list;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_filters;
+ OverlayProcessorInterface::FilterOperationsMap render_pass_backdrop_filters;
+ AggregatedRenderPassList pass_list;
+ // AggregatedRenderPass* main_pass = pass.get();
+ SurfaceDamageRectList surface_damage_rect_list;
+ // Simplify by adding full root damage.
+ surface_damage_rect_list.push_back(pass->output_rect);
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_backdrop_filters,
+ std::move(surface_damage_rect_list),
+ overlay_processor_->GetDefaultPrimaryPlane(), &candidate_list,
+ &damage_rect_, &content_bounds_);
+
+ const auto uv_rect = gfx::RectF(0, 0.5f, 0.5f, 0.5f);
+ EXPECT_EQ(1U, candidate_list.size());
+ EXPECT_RECTF_NEAR(gfx::RectF(kTestClip), candidate_list[0].display_rect,
+ 0.01f);
+ EXPECT_RECTF_NEAR(uv_rect, candidate_list[0].uv_rect, 0.01f);
+}
+
TEST_F(DelegatedTest, TestClipComputed) {
auto pass = CreateRenderPass();
const auto kSmallCandidateRect = gfx::Rect(5, 10, 128, 64);
@@ -4821,7 +4806,8 @@ TEST_F(DelegatedTest, ScaledBufferDamage) {
overlay_processor_->ProcessForOverlays(
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_backdrop_filters,
- std::move(surface_damage_rect_list), nullptr, &candidate_list,
+ std::move(surface_damage_rect_list),
+ overlay_processor_->GetDefaultPrimaryPlane(), &candidate_list,
&damage_rect_, &content_bounds_);
// Expected damage is basically the intersection of the rect with the screen
diff --git a/chromium/components/viz/service/display/program_binding.cc b/chromium/components/viz/service/display/program_binding.cc
deleted file mode 100644
index 488151c3587..00000000000
--- a/chromium/components/viz/service/display/program_binding.cc
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/program_binding.h"
-
-#include "base/logging.h"
-#include "base/trace_event/trace_event.h"
-#include "components/viz/service/display/geometry_binding.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/gfx/color_transform.h"
-
-using gpu::gles2::GLES2Interface;
-
-namespace viz {
-
-ProgramKey::ProgramKey() = default;
-
-ProgramKey::ProgramKey(const ProgramKey& other) = default;
-
-ProgramKey::~ProgramKey() = default;
-
-bool ProgramKey::operator==(const ProgramKey& other) const {
- return type_ == other.type_ && precision_ == other.precision_ &&
- sampler_ == other.sampler_ && blend_mode_ == other.blend_mode_ &&
- aa_mode_ == other.aa_mode_ && is_opaque_ == other.is_opaque_ &&
- premultiplied_alpha_ == other.premultiplied_alpha_ &&
- has_background_color_ == other.has_background_color_ &&
- has_tex_clamp_rect_ == other.has_tex_clamp_rect_ &&
- mask_mode_ == other.mask_mode_ &&
- mask_for_background_ == other.mask_for_background_ &&
- has_color_matrix_ == other.has_color_matrix_ &&
- yuv_alpha_texture_mode_ == other.yuv_alpha_texture_mode_ &&
- uv_texture_mode_ == other.uv_texture_mode_ &&
- color_conversion_mode_ == other.color_conversion_mode_ &&
- color_transform_ == other.color_transform_ &&
- has_output_color_matrix_ == other.has_output_color_matrix_ &&
- has_rounded_corner_ == other.has_rounded_corner_;
-}
-
-bool ProgramKey::operator!=(const ProgramKey& other) const {
- return !(*this == other);
-}
-
-// static
-ProgramKey ProgramKey::DebugBorder() {
- ProgramKey result;
- result.type_ = PROGRAM_TYPE_DEBUG_BORDER;
- return result;
-}
-
-// static
-ProgramKey ProgramKey::SolidColor(AAMode aa_mode,
- bool tint_color,
- bool rounded_corner) {
- ProgramKey result;
- result.type_ = PROGRAM_TYPE_SOLID_COLOR;
- result.aa_mode_ = aa_mode;
- result.has_tint_color_matrix_ = tint_color;
- result.has_rounded_corner_ = rounded_corner;
- return result;
-}
-
-// static
-ProgramKey ProgramKey::Tile(TexCoordPrecision precision,
- SamplerType sampler,
- AAMode aa_mode,
- PremultipliedAlphaMode premultiplied_alpha,
- bool is_opaque,
- bool has_tex_clamp_rect,
- bool tint_color,
- bool rounded_corner) {
- ProgramKey result;
- result.type_ = PROGRAM_TYPE_TILE;
- result.precision_ = precision;
- result.sampler_ = sampler;
- result.aa_mode_ = aa_mode;
- result.is_opaque_ = is_opaque;
- result.has_tex_clamp_rect_ = has_tex_clamp_rect;
- result.has_tint_color_matrix_ = tint_color;
- result.premultiplied_alpha_ = premultiplied_alpha;
- result.has_rounded_corner_ = rounded_corner;
- return result;
-}
-
-// static
-ProgramKey ProgramKey::Texture(TexCoordPrecision precision,
- SamplerType sampler,
- PremultipliedAlphaMode premultiplied_alpha,
- bool has_background_color,
- bool has_tex_clamp_rect,
- bool tint_color,
- bool rounded_corner) {
- ProgramKey result;
- result.type_ = PROGRAM_TYPE_TEXTURE;
- result.precision_ = precision;
- result.sampler_ = sampler;
- result.premultiplied_alpha_ = premultiplied_alpha;
- result.has_background_color_ = has_background_color;
- result.has_tex_clamp_rect_ = has_tex_clamp_rect;
- result.has_tint_color_matrix_ = tint_color;
- result.has_rounded_corner_ = rounded_corner;
- return result;
-}
-
-// static
-ProgramKey ProgramKey::RenderPass(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode,
- AAMode aa_mode,
- MaskMode mask_mode,
- bool mask_for_background,
- bool has_color_matrix,
- bool tint_color,
- bool rounded_corner) {
- ProgramKey result;
- result.type_ = PROGRAM_TYPE_RENDER_PASS;
- result.precision_ = precision;
- result.sampler_ = sampler;
- result.blend_mode_ = blend_mode;
- result.aa_mode_ = aa_mode;
- result.mask_mode_ = mask_mode;
- result.mask_for_background_ = mask_for_background;
- result.has_color_matrix_ = has_color_matrix;
- result.has_tint_color_matrix_ = tint_color;
- result.has_rounded_corner_ = rounded_corner;
- return result;
-}
-
-// static
-ProgramKey ProgramKey::VideoStream(TexCoordPrecision precision,
- bool rounded_corner) {
- ProgramKey result;
- result.type_ = PROGRAM_TYPE_VIDEO_STREAM;
- result.precision_ = precision;
- result.sampler_ = SAMPLER_TYPE_EXTERNAL_OES;
- result.has_rounded_corner_ = rounded_corner;
- return result;
-}
-
-// static
-ProgramKey ProgramKey::YUVVideo(TexCoordPrecision precision,
- SamplerType sampler,
- YUVAlphaTextureMode yuv_alpha_texture_mode,
- UVTextureMode uv_texture_mode,
- bool tint_color,
- bool rounded_corner) {
- ProgramKey result;
- result.type_ = PROGRAM_TYPE_YUV_VIDEO;
- result.precision_ = precision;
- result.sampler_ = sampler;
- result.yuv_alpha_texture_mode_ = yuv_alpha_texture_mode;
- DCHECK(yuv_alpha_texture_mode == YUV_NO_ALPHA_TEXTURE ||
- yuv_alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE);
- result.uv_texture_mode_ = uv_texture_mode;
- DCHECK(uv_texture_mode == UV_TEXTURE_MODE_UV ||
- uv_texture_mode == UV_TEXTURE_MODE_U_V);
- result.has_tint_color_matrix_ = tint_color;
- result.has_rounded_corner_ = rounded_corner;
- return result;
-}
-
-void ProgramKey::SetColorTransform(const gfx::ColorTransform* transform) {
- color_transform_ = nullptr;
- if (transform->IsIdentity()) {
- color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
- } else {
- color_conversion_mode_ = COLOR_CONVERSION_MODE_SHADER;
- color_transform_ = transform;
- }
-}
-
-ProgramBindingBase::ProgramBindingBase()
- : program_(0),
- vertex_shader_id_(0),
- fragment_shader_id_(0),
- initialized_(false) {}
-
-ProgramBindingBase::~ProgramBindingBase() {
- // If you hit these asserts, you initialized but forgot to call Cleanup().
- DCHECK(!program_);
- DCHECK(!vertex_shader_id_);
- DCHECK(!fragment_shader_id_);
- DCHECK(!initialized_);
-}
-
-bool ProgramBindingBase::Init(GLES2Interface* context,
- const std::string& vertex_shader,
- const std::string& fragment_shader) {
- TRACE_EVENT0("viz", "ProgramBindingBase::init");
- vertex_shader_id_ = LoadShader(context, GL_VERTEX_SHADER, vertex_shader);
- if (!vertex_shader_id_)
- return false;
-
- fragment_shader_id_ =
- LoadShader(context, GL_FRAGMENT_SHADER, fragment_shader);
- if (!fragment_shader_id_) {
- context->DeleteShader(vertex_shader_id_);
- vertex_shader_id_ = 0;
- return false;
- }
-
- program_ =
- CreateShaderProgram(context, vertex_shader_id_, fragment_shader_id_);
- return !!program_;
-}
-
-bool ProgramBindingBase::Link(GLES2Interface* context) {
- context->LinkProgram(program_);
- CleanupShaders(context);
- if (!program_)
- return false;
-#ifndef NDEBUG
- int linked = 0;
- context->GetProgramiv(program_, GL_LINK_STATUS, &linked);
- if (!linked) {
- char buffer[1024] = "";
- context->GetProgramInfoLog(program_, sizeof(buffer), nullptr, buffer);
- DLOG(ERROR) << "Error compiling shader: " << buffer;
- return false;
- }
-#endif
- return true;
-}
-
-void ProgramBindingBase::Cleanup(GLES2Interface* context) {
- initialized_ = false;
- if (!program_)
- return;
-
- DCHECK(context);
- context->DeleteProgram(program_);
- program_ = 0;
-
- CleanupShaders(context);
-}
-
-unsigned ProgramBindingBase::LoadShader(GLES2Interface* context,
- unsigned type,
- const std::string& shader_source) {
- unsigned shader = context->CreateShader(type);
- if (!shader)
- return 0u;
-
- const char* shader_source_str[] = {shader_source.data()};
- int shader_length[] = {static_cast<int>(shader_source.length())};
- context->ShaderSource(shader, 1, shader_source_str, shader_length);
- context->CompileShader(shader);
-#if EXPENSIVE_DCHECKS_ARE_ON()
- int compiled = 0;
- context->GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- char buffer[1024] = "";
- context->GetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
- DLOG(ERROR) << "Error compiling shader: " << buffer
- << "\n shader program: " << shader_source;
- return 0u;
- }
-#endif // EXPENSIVE_DCHECKS_ARE_ON()
- return shader;
-}
-
-unsigned ProgramBindingBase::CreateShaderProgram(GLES2Interface* context,
- unsigned vertex_shader,
- unsigned fragment_shader) {
- unsigned program_object = context->CreateProgram();
- if (!program_object)
- return 0;
-
- context->AttachShader(program_object, vertex_shader);
- context->AttachShader(program_object, fragment_shader);
-
- // Bind the common attrib locations.
- context->BindAttribLocation(
- program_object, GeometryBinding::PositionAttribLocation(), "a_position");
- context->BindAttribLocation(
- program_object, GeometryBinding::TexCoordAttribLocation(), "a_texCoord");
- context->BindAttribLocation(program_object,
- GeometryBinding::TriangleIndexAttribLocation(),
- "a_index");
-
- return program_object;
-}
-
-void ProgramBindingBase::CleanupShaders(GLES2Interface* context) {
- if (vertex_shader_id_) {
- context->DeleteShader(vertex_shader_id_);
- vertex_shader_id_ = 0;
- }
- if (fragment_shader_id_) {
- context->DeleteShader(fragment_shader_id_);
- fragment_shader_id_ = 0;
- }
-}
-
-bool ProgramBindingBase::IsContextLost(GLES2Interface* context) {
- return context->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/program_binding.h b/chromium/components/viz/service/display/program_binding.h
deleted file mode 100644
index b03673f9266..00000000000
--- a/chromium/components/viz/service/display/program_binding.h
+++ /dev/null
@@ -1,480 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
-
-#include <string>
-
-#include "base/check_op.h"
-#include "base/memory/raw_ptr.h"
-#include "build/build_config.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/service/display/shader.h"
-#include "components/viz/service/viz_service_export.h"
-
-namespace gfx {
-class ColorTransform;
-}
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-} // namespace gpu
-
-namespace viz {
-
-class VIZ_SERVICE_EXPORT ProgramBindingBase {
- public:
- ProgramBindingBase();
-
- ProgramBindingBase(const ProgramBindingBase&) = delete;
- ProgramBindingBase& operator=(const ProgramBindingBase&) = delete;
-
- ~ProgramBindingBase();
-
- bool Init(gpu::gles2::GLES2Interface* context,
- const std::string& vertex_shader,
- const std::string& fragment_shader);
- bool Link(gpu::gles2::GLES2Interface* context);
- void Cleanup(gpu::gles2::GLES2Interface* context);
-
- unsigned program() const { return program_; }
- bool initialized() const { return initialized_; }
-
- protected:
- unsigned LoadShader(gpu::gles2::GLES2Interface* context,
- unsigned type,
- const std::string& shader_source);
- unsigned CreateShaderProgram(gpu::gles2::GLES2Interface* context,
- unsigned vertex_shader,
- unsigned fragment_shader);
- void CleanupShaders(gpu::gles2::GLES2Interface* context);
-
- bool IsContextLost(gpu::gles2::GLES2Interface* context);
-
- unsigned program_;
- unsigned vertex_shader_id_;
- unsigned fragment_shader_id_;
- bool initialized_;
-};
-
-enum ProgramType {
- PROGRAM_TYPE_DEBUG_BORDER,
- PROGRAM_TYPE_SOLID_COLOR,
- PROGRAM_TYPE_TILE,
- PROGRAM_TYPE_TEXTURE,
- PROGRAM_TYPE_RENDER_PASS,
- PROGRAM_TYPE_VIDEO_STREAM,
- PROGRAM_TYPE_YUV_VIDEO,
-};
-
-class VIZ_SERVICE_EXPORT ProgramKey {
- public:
- ProgramKey();
- ProgramKey(const ProgramKey& other);
- ~ProgramKey();
-
- static ProgramKey DebugBorder();
- static ProgramKey SolidColor(AAMode aa_mode,
- bool tint_color,
- bool rounded_corner);
- static ProgramKey Tile(TexCoordPrecision precision,
- SamplerType sampler,
- AAMode aa_mode,
- PremultipliedAlphaMode premultiplied_alpha,
- bool is_opaque,
- bool has_tex_clamp_rect,
- bool tint_color,
- bool rounded_corner);
- static ProgramKey Texture(TexCoordPrecision precision,
- SamplerType sampler,
- PremultipliedAlphaMode premultiplied_alpha,
- bool has_background_color,
- bool has_tex_clamp_rect,
- bool tint_color,
- bool rounded_corner);
-
- // TODO(ccameron): Merge |mask_for_background| into MaskMode.
- static ProgramKey RenderPass(TexCoordPrecision precision,
- SamplerType sampler,
- BlendMode blend_mode,
- AAMode aa_mode,
- MaskMode mask_mode,
- bool mask_for_background,
- bool has_color_matrix,
- bool tint_color,
- bool rounded_corner);
- static ProgramKey VideoStream(TexCoordPrecision precision,
- bool rounded_corner);
- static ProgramKey YUVVideo(TexCoordPrecision precision,
- SamplerType sampler,
- YUVAlphaTextureMode yuv_alpha_texture_mode,
- UVTextureMode uv_texture_mode,
- bool tint_color,
- bool rounded_corner);
-
- bool operator==(const ProgramKey& other) const;
- bool operator!=(const ProgramKey& other) const;
-
- void SetColorTransform(const gfx::ColorTransform* transform);
-
- bool has_output_color_matrix() const { return has_output_color_matrix_; }
- void set_has_output_color_matrix(bool value) {
- has_output_color_matrix_ = value;
- }
- TexCoordPrecision tex_coord_precision() const { return precision_; }
-
- ProgramType type() const { return type_; }
-
- private:
- friend struct ProgramKeyHash;
- friend class Program;
-
- ProgramType type_ = PROGRAM_TYPE_DEBUG_BORDER;
- TexCoordPrecision precision_ = TEX_COORD_PRECISION_NA;
- SamplerType sampler_ = SAMPLER_TYPE_NA;
- BlendMode blend_mode_ = BLEND_MODE_NONE;
- AAMode aa_mode_ = NO_AA;
- bool is_opaque_ = false;
-
- PremultipliedAlphaMode premultiplied_alpha_ = PREMULTIPLIED_ALPHA;
- bool has_background_color_ = false;
-
- MaskMode mask_mode_ = NO_MASK;
- bool mask_for_background_ = false;
- bool has_color_matrix_ = false;
-
- YUVAlphaTextureMode yuv_alpha_texture_mode_ = YUV_NO_ALPHA_TEXTURE;
- UVTextureMode uv_texture_mode_ = UV_TEXTURE_MODE_NA;
-
- ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
- raw_ptr<const gfx::ColorTransform> color_transform_ = nullptr;
-
- bool has_tex_clamp_rect_ = false;
-
- bool has_output_color_matrix_ = false;
- bool has_tint_color_matrix_ = false;
- bool has_rounded_corner_ = false;
-};
-
-struct ProgramKeyHash {
- size_t operator()(const ProgramKey& key) const {
- return (static_cast<size_t>(key.type_) << 0) ^
- (static_cast<size_t>(key.precision_) << 3) ^
- (static_cast<size_t>(key.sampler_) << 6) ^
- (static_cast<size_t>(key.blend_mode_) << 9) ^
- (static_cast<size_t>(key.aa_mode_) << 15) ^
- (static_cast<size_t>(key.is_opaque_) << 17) ^
- (static_cast<size_t>(key.premultiplied_alpha_) << 19) ^
- (static_cast<size_t>(key.has_background_color_) << 20) ^
- (static_cast<size_t>(key.mask_mode_) << 21) ^
- (static_cast<size_t>(key.mask_for_background_) << 22) ^
- (static_cast<size_t>(key.has_color_matrix_) << 23) ^
- (static_cast<size_t>(key.yuv_alpha_texture_mode_) << 24) ^
- (static_cast<size_t>(key.uv_texture_mode_) << 25) ^
- (static_cast<size_t>(key.color_conversion_mode_) << 26) ^
- (static_cast<size_t>(key.has_tex_clamp_rect_) << 28) ^
- (static_cast<size_t>(key.has_output_color_matrix_) << 29) ^
- (static_cast<size_t>(key.has_tint_color_matrix_) << 30) ^
- (static_cast<size_t>(key.has_rounded_corner_) << 31);
- }
-};
-
-class VIZ_SERVICE_EXPORT Program : public ProgramBindingBase {
- public:
- Program() {}
-
- Program(const Program&) = delete;
- Program& operator=(const Program&) = delete;
-
- void Initialize(ContextProvider* context_provider, const ProgramKey& key) {
- // Set parameters that are common to all sub-classes.
- vertex_shader_.aa_mode_ = key.aa_mode_;
- fragment_shader_.aa_mode_ = key.aa_mode_;
- fragment_shader_.blend_mode_ = key.blend_mode_;
- fragment_shader_.tex_coord_precision_ = key.precision_;
- fragment_shader_.sampler_type_ = key.sampler_;
- fragment_shader_.premultiply_alpha_mode_ = key.premultiplied_alpha_;
- fragment_shader_.mask_mode_ = key.mask_mode_;
- fragment_shader_.mask_for_background_ = key.mask_for_background_;
- fragment_shader_.color_conversion_mode_ = key.color_conversion_mode_;
- fragment_shader_.color_transform_ = key.color_transform_;
- fragment_shader_.has_output_color_matrix_ = key.has_output_color_matrix_;
- fragment_shader_.has_tint_color_matrix_ = key.has_tint_color_matrix_;
- fragment_shader_.has_rounded_corner_ = key.has_rounded_corner_;
-
- switch (key.type_) {
- case PROGRAM_TYPE_DEBUG_BORDER:
- InitializeDebugBorderProgram();
- break;
- case PROGRAM_TYPE_SOLID_COLOR:
- InitializeSolidColorProgram(key);
- break;
- case PROGRAM_TYPE_TILE:
- InitializeTileProgram(key);
- break;
- case PROGRAM_TYPE_TEXTURE:
- InitializeTextureProgram(key);
- break;
- case PROGRAM_TYPE_RENDER_PASS:
- InitializeRenderPassProgram(key);
- break;
- case PROGRAM_TYPE_VIDEO_STREAM:
- InitializeVideoStreamProgram(key);
- break;
- case PROGRAM_TYPE_YUV_VIDEO:
- InitializeYUVVideo(key);
- break;
- }
- InitializeInternal(context_provider);
- }
-
- const VertexShader& vertex_shader() const { return vertex_shader_; }
- const FragmentShader& fragment_shader() const { return fragment_shader_; }
-
- // Functions for querying uniform locations.
- int vertex_tex_transform_location() const {
- return vertex_shader_.vertex_tex_transform_location_;
- }
- int tex_matrix_location() const {
- return vertex_shader_.tex_matrix_location_;
- }
- int ya_tex_scale_location() const {
- return vertex_shader_.ya_tex_scale_location_;
- }
- int ya_tex_offset_location() const {
- return vertex_shader_.ya_tex_offset_location_;
- }
- int uv_tex_scale_location() const {
- return vertex_shader_.uv_tex_scale_location_;
- }
- int uv_tex_offset_location() const {
- return vertex_shader_.uv_tex_offset_location_;
- }
- int matrix_location() const { return vertex_shader_.matrix_location_; }
- int vertex_opacity_location() const {
- return vertex_shader_.vertex_opacity_location_;
- }
- int viewport_location() const { return vertex_shader_.viewport_location_; }
- int edge_location() const { return vertex_shader_.edge_location_; }
- int quad_location() const { return vertex_shader_.quad_location_; }
-
- int sampler_location() const { return fragment_shader_.sampler_location_; }
- int alpha_location() const { return fragment_shader_.alpha_location_; }
- int color_location() const { return fragment_shader_.color_location_; }
- int background_color_location() const {
- return fragment_shader_.background_color_location_;
- }
- int fragment_tex_transform_location() const {
- return fragment_shader_.fragment_tex_transform_location_;
- }
- int backdrop_location() const { return fragment_shader_.backdrop_location_; }
- int backdrop_rect_location() const {
- return fragment_shader_.backdrop_rect_location_;
- }
- int original_backdrop_location() const {
- return fragment_shader_.original_backdrop_location_;
- }
- int mask_sampler_location() const {
- return fragment_shader_.mask_sampler_location_;
- }
- int mask_tex_coord_scale_location() const {
- return fragment_shader_.mask_tex_coord_scale_location_;
- }
- int mask_tex_coord_offset_location() const {
- return fragment_shader_.mask_tex_coord_offset_location_;
- }
- int color_matrix_location() const {
- return fragment_shader_.color_matrix_location_;
- }
- int color_offset_location() const {
- return fragment_shader_.color_offset_location_;
- }
- int tex_clamp_rect_location() const {
- return fragment_shader_.tex_clamp_rect_location_;
- }
- int y_texture_location() const {
- return fragment_shader_.y_texture_location_;
- }
- int u_texture_location() const {
- return fragment_shader_.u_texture_location_;
- }
- int v_texture_location() const {
- return fragment_shader_.v_texture_location_;
- }
- int uv_texture_location() const {
- return fragment_shader_.uv_texture_location_;
- }
- int a_texture_location() const {
- return fragment_shader_.a_texture_location_;
- }
- int resource_multiplier_location() const {
- return fragment_shader_.resource_multiplier_location_;
- }
- int resource_offset_location() const {
- return fragment_shader_.resource_offset_location_;
- }
- int ya_clamp_rect_location() const {
- return fragment_shader_.ya_clamp_rect_location_;
- }
- int uv_clamp_rect_location() const {
- return fragment_shader_.uv_clamp_rect_location_;
- }
- int output_color_matrix_location() const {
- return fragment_shader_.output_color_matrix_location_;
- }
- int tint_color_matrix_location() const {
- return fragment_shader_.tint_color_matrix_location_;
- }
- int rounded_corner_rect_location() const {
- return fragment_shader_.rounded_corner_rect_location_;
- }
- int rounded_corner_radius_location() const {
- return fragment_shader_.rounded_corner_radius_location_;
- }
-
- const gfx::ColorTransform* color_transform_for_testing() const {
- return fragment_shader_.color_transform_;
- }
-
- private:
- void InitializeDebugBorderProgram() {
- // Initialize fragment program.
- fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_UNIFORM;
- fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
- }
-
- void InitializeSolidColorProgram(const ProgramKey& key) {
- // Initialize vertex program.
- vertex_shader_.position_source_ = POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
-#if BUILDFLAG(IS_ANDROID)
- if (key.aa_mode_ == NO_AA)
- vertex_shader_.has_dummy_variables_ = true;
-#endif
-
- // Initialize fragment program.
- fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_UNIFORM;
- fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
- }
-
- void InitializeTileProgram(const ProgramKey& key) {
- // Initialize vertex program.
- vertex_shader_.position_source_ = POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
- vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
- vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
-
- // Initialize fragment program.
- fragment_shader_.has_tex_clamp_rect_ = key.has_tex_clamp_rect_;
- if (key.is_opaque_) {
- DCHECK_EQ(key.aa_mode_, NO_AA);
- fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_OPAQUE;
- } else {
- // TODO(ccameron): This branch shouldn't be needed (this is always
- // BLEND_MODE_NONE).
- if (key.aa_mode_ == NO_AA)
- fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_APPLY_BLEND_MODE;
- fragment_shader_.has_uniform_alpha_ = true;
- }
- // AA changes the texture coordinate mode (affecting both shaders).
- if (key.aa_mode_ == USE_AA) {
- vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_POSITION;
- vertex_shader_.aa_mode_ = USE_AA;
- fragment_shader_.has_rgba_fragment_tex_transform_ = true;
- // Tiles that have AA do their own clamping.
- DCHECK(!fragment_shader_.has_tex_clamp_rect_);
- }
- }
-
- void InitializeTextureProgram(const ProgramKey& key) {
- // Initialize vertex program.
- vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
- vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
- vertex_shader_.has_vertex_opacity_ = true;
- vertex_shader_.use_uniform_arrays_ = !key.has_tex_clamp_rect_;
-
- // Initialize fragment program.
- fragment_shader_.has_varying_alpha_ = true;
- fragment_shader_.has_background_color_ = key.has_background_color_;
- fragment_shader_.has_tex_clamp_rect_ = key.has_tex_clamp_rect_;
- }
-
- void InitializeRenderPassProgram(const ProgramKey& key) {
- // Initialize vertex program.
- if (key.aa_mode_ == NO_AA) {
- vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
- vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_VEC4;
- vertex_shader_.has_vertex_opacity_ = true;
- vertex_shader_.use_uniform_arrays_ = true;
- } else {
- vertex_shader_.position_source_ =
- POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM;
- vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_POSITION;
- vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_TRANSLATED_VEC4;
- }
-
- // Initialize fragment program.
- fragment_shader_.frag_color_mode_ = FRAG_COLOR_MODE_APPLY_BLEND_MODE;
- fragment_shader_.has_uniform_alpha_ = true;
- fragment_shader_.has_color_matrix_ = key.has_color_matrix_;
- if (key.mask_mode_ == HAS_MASK) {
- fragment_shader_.ignore_sampler_type_ = true;
- } else {
- DCHECK(!key.mask_for_background_);
- }
- }
-
- void InitializeVideoStreamProgram(const ProgramKey& key) {
- vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
- vertex_shader_.tex_coord_transform_ = TEX_COORD_TRANSFORM_MATRIX;
- DCHECK_EQ(key.sampler_, SAMPLER_TYPE_EXTERNAL_OES);
- }
-
- void InitializeYUVVideo(const ProgramKey& key) {
- vertex_shader_.tex_coord_source_ = TEX_COORD_SOURCE_ATTRIBUTE;
- vertex_shader_.is_ya_uv_ = true;
-
- fragment_shader_.input_color_type_ = INPUT_COLOR_SOURCE_YUV_TEXTURES;
- fragment_shader_.has_uniform_alpha_ = true;
- fragment_shader_.yuv_alpha_texture_mode_ = key.yuv_alpha_texture_mode_;
- fragment_shader_.uv_texture_mode_ = key.uv_texture_mode_;
- }
-
- void InitializeInternal(ContextProvider* context_provider) {
- DCHECK(context_provider);
- DCHECK(!initialized_);
-
- if (IsContextLost(context_provider->ContextGL()))
- return;
-
- if (!ProgramBindingBase::Init(context_provider->ContextGL(),
- vertex_shader_.GetShaderString(),
- fragment_shader_.GetShaderString())) {
- DCHECK(IsContextLost(context_provider->ContextGL()));
- return;
- }
-
- int base_uniform_index = 0;
- vertex_shader_.Init(context_provider->ContextGL(), program_,
- &base_uniform_index);
- fragment_shader_.Init(context_provider->ContextGL(), program_,
- &base_uniform_index);
-
- // Link after binding uniforms
- if (!Link(context_provider->ContextGL())) {
- DCHECK(IsContextLost(context_provider->ContextGL()));
- return;
- }
-
- initialized_ = true;
- }
-
- VertexShader vertex_shader_;
- FragmentShader fragment_shader_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_PROGRAM_BINDING_H_
diff --git a/chromium/components/viz/service/display/renderer_perftest.cc b/chromium/components/viz/service/display/renderer_perftest.cc
index 827da3a6da0..1ff1f6f4406 100644
--- a/chromium/components/viz/service/display/renderer_perftest.cc
+++ b/chromium/components/viz/service/display/renderer_perftest.cc
@@ -4,12 +4,11 @@
// This perf test measures the time from when the display compositor starts
// drawing on the compositor thread to when a swap buffers occurs on the
-// GPU main thread. It tests both GLRenderer and SkiaRenderer under
-// simple work loads.
+// GPU main thread.
//
// Example usage:
//
-// $ out/release/viz_perftests --gtest_filter="*RendererPerfTest*" \
+// $ out/release/viz_perftests --gtest_filter="RendererPerfTest*" \
// --use-gpu-in-tests --test-launcher-timeout=300000 \
// --perf-test-time-ms=240000 --disable_discard_framebuffer=1 \
// --use_virtualized_gl_contexts=1
@@ -26,24 +25,22 @@
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "components/viz/service/display/display.h"
-#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/overlay_processor_stub.h"
#include "components/viz/service/display/skia_renderer.h"
#include "components/viz/service/display/viz_perftest.h"
-#include "components/viz/service/display_embedder/gl_output_surface_offscreen.h"
-#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
-#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/test_gpu_service_holder.h"
+#include "components/viz/test/test_in_process_context_provider.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -229,7 +226,6 @@ void CreateTestTileDrawQuad(ResourceId resource_id,
} // namespace
-template <typename RendererType>
class RendererPerfTest : public VizPerfTest {
public:
RendererPerfTest()
@@ -243,19 +239,15 @@ class RendererPerfTest : public VizPerfTest {
RendererPerfTest(const RendererPerfTest&) = delete;
RendererPerfTest& operator=(const RendererPerfTest&) = delete;
- // Overloaded for concrete RendererType below.
- std::unique_ptr<OutputSurface> CreateOutputSurface(
+ std::unique_ptr<SkiaOutputSurface> CreateOutputSurface(
GpuServiceImpl* gpu_service,
- DisplayCompositorMemoryAndTaskController* display_controller);
+ DisplayCompositorMemoryAndTaskController* display_controller) {
+ return SkiaOutputSurfaceImpl::Create(display_controller, renderer_settings_,
+ &debug_settings_);
+ }
void SetUp() override {
enable_pixel_output_ = std::make_unique<gl::DisableNullDrawGLBindings>();
- renderer_settings_.use_skia_renderer =
- std::is_base_of<SkiaRenderer, RendererType>::value;
- if (renderer_settings_.use_skia_renderer)
- printf("Using SkiaRenderer\n");
- else
- printf("Using GLRenderer\n");
#if BUILDFLAG(IS_ANDROID)
renderer_settings_.color_space = gfx::ColorSpace::CreateSRGB();
@@ -264,42 +256,18 @@ class RendererPerfTest : public VizPerfTest {
auto* gpu_service = TestGpuServiceHolder::GetInstance()->gpu_service();
- gpu_memory_buffer_manager_ =
- std::make_unique<InProcessGpuMemoryBufferManager>(
- gpu_service->gpu_memory_buffer_factory(),
- gpu_service->sync_point_manager());
- gpu::ImageFactory* image_factory = gpu_service->gpu_image_factory();
- auto* gpu_channel_manager_delegate =
- gpu_service->gpu_channel_manager()->delegate();
- auto child_task_scheduler = std::make_unique<gpu::GpuTaskSchedulerHelper>(
- TestGpuServiceHolder::GetInstance()->task_executor());
- child_gpu_dependency_ =
- std::make_unique<DisplayCompositorMemoryAndTaskController>(
- TestGpuServiceHolder::GetInstance()->task_executor(),
- image_factory);
- child_context_provider_ = base::MakeRefCounted<VizProcessContextProvider>(
- TestGpuServiceHolder::GetInstance()->task_executor(),
- gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(),
- image_factory, gpu_channel_manager_delegate,
- child_gpu_dependency_.get(), renderer_settings_);
+ child_context_provider_ =
+ base::MakeRefCounted<TestInProcessContextProvider>(
+ TestContextType::kGLES2, /*support_locking=*/false);
child_context_provider_->BindToCurrentThread();
child_resource_provider_ = std::make_unique<ClientResourceProvider>();
- std::unique_ptr<DisplayCompositorMemoryAndTaskController>
- display_controller;
- if (renderer_settings_.use_skia_renderer) {
- auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
- gpu_service, gpu::kNullSurfaceHandle);
- display_controller =
- std::make_unique<DisplayCompositorMemoryAndTaskController>(
- std::move(skia_deps));
- } else {
- auto* task_executor =
- TestGpuServiceHolder::GetInstance()->task_executor();
- display_controller =
- std::make_unique<DisplayCompositorMemoryAndTaskController>(
- task_executor, image_factory);
- }
+ auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
+ gpu_service, gpu::kNullSurfaceHandle);
+ auto display_controller =
+ std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ std::move(skia_deps));
+
auto output_surface =
CreateOutputSurface(gpu_service, display_controller.get());
// WaitForSwapDisplayClient depends on this.
@@ -320,8 +288,7 @@ class RendererPerfTest : public VizPerfTest {
void TearDown() override {
std::string story =
- renderer_settings_.use_skia_renderer ? "SkiaRenderer_" : "GLRenderer_";
- story += ::testing::UnitTest::GetInstance()->current_test_info()->name();
+ ::testing::UnitTest::GetInstance()->current_test_info()->name();
auto reporter = SetUpRendererReporter(story);
reporter.AddResult(kMetricFps, timer_.LapsPerSecond());
@@ -358,8 +325,6 @@ class RendererPerfTest : public VizPerfTest {
child_resource_provider_->ShutdownAndReleaseAllResources();
child_resource_provider_.reset();
child_context_provider_.reset();
- child_gpu_dependency_.reset();
- gpu_memory_buffer_manager_.reset();
display_.reset();
}
@@ -661,69 +626,37 @@ class RendererPerfTest : public VizPerfTest {
ServerSharedBitmapManager shared_bitmap_manager_;
FrameSinkManagerImpl manager_;
std::unique_ptr<CompositorFrameSinkSupport> support_;
- std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
RendererSettings renderer_settings_;
DebugRendererSettings debug_settings_;
std::unique_ptr<Display> display_;
- std::unique_ptr<DisplayCompositorMemoryAndTaskController>
- child_gpu_dependency_;
scoped_refptr<ContextProvider> child_context_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::vector<TransferableResource> resource_list_;
std::unique_ptr<gl::DisableNullDrawGLBindings> enable_pixel_output_;
};
-template <>
-std::unique_ptr<OutputSurface>
-RendererPerfTest<SkiaRenderer>::CreateOutputSurface(
- GpuServiceImpl* gpu_service,
- DisplayCompositorMemoryAndTaskController* display_controller) {
- return SkiaOutputSurfaceImpl::Create(
- display_controller, renderer_settings_, &debug_settings_);
-}
-
-template <>
-std::unique_ptr<OutputSurface>
-RendererPerfTest<GLRenderer>::CreateOutputSurface(
- GpuServiceImpl* gpu_service,
- DisplayCompositorMemoryAndTaskController* display_controller) {
- gpu::ImageFactory* image_factory = gpu_service->gpu_image_factory();
- auto* gpu_channel_manager_delegate =
- gpu_service->gpu_channel_manager()->delegate();
- auto context_provider = base::MakeRefCounted<VizProcessContextProvider>(
- TestGpuServiceHolder::GetInstance()->task_executor(),
- gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(), image_factory,
- gpu_channel_manager_delegate, display_controller, renderer_settings_);
- context_provider->BindToCurrentThread();
- return std::make_unique<GLOutputSurfaceOffscreen>(
- std::move(context_provider));
-}
-
-using RendererTypes = ::testing::Types<GLRenderer, SkiaRenderer>;
-TYPED_TEST_SUITE(RendererPerfTest, RendererTypes);
-
-TYPED_TEST(RendererPerfTest, SingleTextureQuad) {
+TEST_F(RendererPerfTest, SingleTextureQuad) {
this->RunSingleTextureQuad();
}
-TYPED_TEST(RendererPerfTest, TextureQuads5x5) {
+TEST_F(RendererPerfTest, TextureQuads5x5) {
this->RunTextureQuads5x5();
}
-TYPED_TEST(RendererPerfTest, TextureQuads5x5SameTex) {
+TEST_F(RendererPerfTest, TextureQuads5x5SameTex) {
this->RunTextureQuads5x5SameTex();
}
-TYPED_TEST(RendererPerfTest, RotatedTileQuadsShared) {
+TEST_F(RendererPerfTest, RotatedTileQuadsShared) {
this->RunRotatedTileQuadsShared();
}
-TYPED_TEST(RendererPerfTest, RotatedTileQuads) {
+TEST_F(RendererPerfTest, RotatedTileQuads) {
this->RunRotatedTileQuads();
}
#define TOP_REAL_WORLD_DESKTOP_RENDERER_PERF_TEST(SITE, FRAME) \
- TYPED_TEST(RendererPerfTest, SITE) { \
+ TEST_F(RendererPerfTest, SITE) { \
this->RunSingleRenderPassListFromJSON(/*tag=*/"top_real_world_desktop", \
/*site=*/#SITE, /*year=*/2018, \
/*frame_index=*/FRAME); \
diff --git a/chromium/components/viz/service/display/renderer_pixeltest.cc b/chromium/components/viz/service/display/renderer_pixeltest.cc
index 15651bf9388..32312f8cd58 100644
--- a/chromium/components/viz/service/display/renderer_pixeltest.cc
+++ b/chromium/components/viz/service/display/renderer_pixeltest.cc
@@ -29,20 +29,22 @@
#include "cc/test/test_types.h"
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/features.h"
+#include "components/viz/common/quads/aggregated_render_pass_draw_quad.h"
+#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
#include "components/viz/common/quads/picture_draw_quad.h"
+#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/switches.h"
#include "components/viz/service/display/delegated_ink_point_pixel_test_helper.h"
-#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/service/display/software_renderer.h"
#include "components/viz/service/display/viz_pixel_test.h"
#include "components/viz/test/buildflags.h"
#include "components/viz/test/test_in_process_context_provider.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
#include "components/viz/test/test_types.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "media/base/video_frame.h"
@@ -58,8 +60,6 @@
#include "ui/gfx/geometry/mask_filter_info.h"
#include "ui/gfx/test/icc_profiles.h"
-using gpu::gles2::GLES2Interface;
-
namespace viz {
namespace {
@@ -905,27 +905,6 @@ INSTANTIATE_TEST_SUITE_P(,
// GetGpuRendererTypesNoDawn() can return an empty list, e.g. on Fuchsia ARM64.
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GPURendererPixelTest);
-// Provides an exact comparator for GLRenderer and fuzzy comparator for Skia
-// based (eg. SoftwareRenderer and SkiaRenderer).
-class FuzzyForSkiaOnlyPixelComparator : public cc::PixelComparator {
- public:
- explicit FuzzyForSkiaOnlyPixelComparator(RendererType type) {
- if (type == RendererType::kGL) {
- comparator_ = std::make_unique<cc::ExactPixelComparator>(false);
- } else {
- comparator_ = std::make_unique<cc::FuzzyPixelOffByOneComparator>(false);
- }
- }
-
- bool Compare(const SkBitmap& actual_bmp,
- const SkBitmap& expected_bmp) const override {
- return comparator_->Compare(actual_bmp, expected_bmp);
- }
-
- private:
- std::unique_ptr<cc::PixelComparator> comparator_;
-};
-
TEST_P(RendererPixelTest, SimpleGreenRect) {
gfx::Rect rect(this->device_viewport_size_);
@@ -1123,6 +1102,13 @@ TEST_P(RendererPixelTest,
}
TEST_P(RendererPixelTest, TextureDrawQuadVisibleRectInsetBottomRight) {
+#if BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER)
+ // Test is flaking with failed large allocations under TSAN when using
+ // SkiaRenderer with GL backend. See https://crbug.com/1320955.
+ if (renderer_type() == RendererType::kSkiaGL)
+ return;
+#endif
+
gfx::Rect rect(this->device_viewport_size_);
AggregatedRenderPassId id{1};
@@ -1781,25 +1767,16 @@ class VideoRendererPixelTestBase : public VizPixelTest {
};
#if BUILDFLAG(ENABLE_GL_BACKEND_TESTS)
-class VideoRendererPixelHiLoTest
- : public VideoRendererPixelTestBase,
- public testing::WithParamInterface<std::tuple<RendererType, bool>> {
+class VideoRendererPixelHiLoTest : public VideoRendererPixelTestBase,
+ public testing::WithParamInterface<bool> {
public:
VideoRendererPixelHiLoTest()
- : VideoRendererPixelTestBase(std::get<0>(GetParam())) {}
+ : VideoRendererPixelTestBase(RendererType::kSkiaGL) {}
- bool IsHighbit() const { return std::get<1>(GetParam()); }
+ bool IsHighbit() const { return GetParam(); }
};
-INSTANTIATE_TEST_SUITE_P(,
- VideoRendererPixelHiLoTest,
- testing::Combine(testing::Values(
-#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS)
- RendererType::kGL,
-#endif
- RendererType::kSkiaGL),
- testing::Bool()),
- cc::PrintTupleToStringParamName());
+INSTANTIATE_TEST_SUITE_P(, VideoRendererPixelHiLoTest, testing::Bool());
TEST_P(VideoRendererPixelHiLoTest, SimpleYUVRect) {
gfx::Rect rect(this->device_viewport_size_);
@@ -2215,7 +2192,7 @@ TEST_P(RendererPixelTest, FastPassColorFilterAlpha) {
// renderer so use a fuzzy comparator.
EXPECT_TRUE(this->RunPixelTest(
&pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
- FuzzyForSkiaOnlyPixelComparator(renderer_type())));
+ cc::FuzzyPixelOffByOneComparator(false)));
}
TEST_P(RendererPixelTest, FastPassSaturateFilter) {
@@ -2275,7 +2252,7 @@ TEST_P(RendererPixelTest, FastPassSaturateFilter) {
// renderer so use a fuzzy comparator.
EXPECT_TRUE(this->RunPixelTest(
&pass_list, base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha.png")),
- FuzzyForSkiaOnlyPixelComparator(renderer_type())));
+ cc::FuzzyPixelOffByOneComparator(false)));
}
TEST_P(RendererPixelTest, FastPassFilterChain) {
@@ -2337,7 +2314,7 @@ TEST_P(RendererPixelTest, FastPassFilterChain) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_filter_chain.png")),
- FuzzyForSkiaOnlyPixelComparator(renderer_type())));
+ cc::FuzzyPixelOffByOneComparator(false)));
}
TEST_P(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
@@ -2420,7 +2397,7 @@ TEST_P(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
base::FilePath(FILE_PATH_LITERAL("blue_yellow_alpha_translate.png")),
- FuzzyForSkiaOnlyPixelComparator(renderer_type())));
+ cc::FuzzyPixelOffByOneComparator(false)));
}
TEST_P(RendererPixelTest, EnlargedRenderPassTexture) {
@@ -3083,11 +3060,6 @@ TEST_P(RendererPixelTestWithBackdropFilter, InvertFilter) {
}
TEST_P(RendererPixelTestWithBackdropFilter, InvertFilterWithMask) {
- // TODO(crbug.com/989312): Delete this condition with GLRendere. The mask
- // appears to be offset from the correct location but this isn't relevant.
- if (is_gl_renderer())
- return;
-
this->backdrop_filters_.Append(cc::FilterOperation::CreateInvertFilter(1.f));
this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_);
this->filter_pass_layer_rect_.Inset(gfx::Insets::TLBR(14, 12, 18, 16));
@@ -3105,170 +3077,6 @@ TEST_P(RendererPixelTestWithBackdropFilter, InvertFilterWithMask) {
cc::FuzzyPixelOffByOneComparator(false)));
}
-#if BUILDFLAG(ENABLE_GL_RENDERER_TESTS)
-class GLRendererPixelTestWithBackdropFilter : public VizPixelTest {
- public:
- GLRendererPixelTestWithBackdropFilter() : VizPixelTest(RendererType::kGL) {}
-
- protected:
- void SetUpRenderPassList() {
- pass_list_.clear();
- gfx::Rect device_viewport_rect(this->device_viewport_size_);
-
- AggregatedRenderPassId root_id{1};
- auto root_pass = CreateTestRootRenderPass(root_id, device_viewport_rect);
- root_pass->has_transparent_background = false;
-
- gfx::Transform identity_quad_to_target_transform;
-
- AggregatedRenderPassId filter_pass_id{2};
- gfx::Transform transform_to_root;
- auto filter_pass = CreateTestRenderPass(
- filter_pass_id, filter_pass_layer_rect_, transform_to_root);
- filter_pass->backdrop_filters = this->backdrop_filters_;
- filter_pass->backdrop_filter_bounds = this->backdrop_filter_bounds_;
-
- // A non-visible quad in the filtering render pass.
- {
- SharedQuadState* shared_state = CreateTestSharedQuadState(
- identity_quad_to_target_transform, filter_pass_layer_rect_,
- filter_pass.get(), gfx::MaskFilterInfo());
- auto* color_quad =
- filter_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- color_quad->SetNew(shared_state, filter_pass_layer_rect_,
- filter_pass_layer_rect_, SK_ColorTRANSPARENT, false);
- }
-
- {
- SharedQuadState* shared_state = CreateTestSharedQuadState(
- filter_pass_to_target_transform_, filter_pass_layer_rect_,
- filter_pass.get(), gfx::MaskFilterInfo());
- auto* filter_pass_quad =
- root_pass->CreateAndAppendDrawQuad<AggregatedRenderPassDrawQuad>();
- filter_pass_quad->SetAll(
- shared_state, filter_pass_layer_rect_, filter_pass_layer_rect_,
- /*needs_blending=*/true, filter_pass_id, kInvalidResourceId,
- gfx::RectF(), gfx::Size(),
- gfx::Vector2dF(1.0f, 1.0f), // filters_scale
- gfx::PointF(), // filters_origin
- gfx::RectF(), // tex_coord_rect
- false, // force_anti_aliasing_off
- backdrop_filter_quality_, // backdrop_filter_quality
- intersects_damage_under_);
- }
-
- const int kGridWidth = device_viewport_rect.width() / 3;
- const int kGridHeight = device_viewport_rect.height() / 3;
- gfx::Rect left_rect =
- gfx::Rect(kGridWidth / 2, kGridHeight, kGridWidth, kGridHeight);
-
- SharedQuadState* shared_state = CreateTestSharedQuadState(
- identity_quad_to_target_transform, left_rect, root_pass.get(),
- gfx::MaskFilterInfo());
- auto* color_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- color_quad->SetNew(shared_state, left_rect, left_rect, SK_ColorGREEN,
- false);
-
- gfx::Rect right_rect =
- gfx::Rect(kGridWidth * 3 / 2, kGridHeight, kGridWidth, kGridHeight);
- shared_state = CreateTestSharedQuadState(
- identity_quad_to_target_transform, right_rect, root_pass.get(),
- gfx::MaskFilterInfo());
- color_quad = root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- color_quad->SetNew(shared_state, right_rect, right_rect, SK_ColorRED,
- false);
-
- shared_state = CreateTestSharedQuadState(
- identity_quad_to_target_transform, device_viewport_rect,
- root_pass.get(), gfx::MaskFilterInfo());
- auto* background_quad =
- root_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- background_quad->SetNew(shared_state, device_viewport_rect,
- device_viewport_rect, SK_ColorWHITE, false);
-
- pass_list_.push_back(std::move(filter_pass));
- pass_list_.push_back(std::move(root_pass));
- }
-
- AggregatedRenderPassList pass_list_;
- cc::FilterOperations backdrop_filters_;
- absl::optional<gfx::RRectF> backdrop_filter_bounds_;
- float backdrop_filter_quality_ = 1.0f;
- bool intersects_damage_under_ = true;
- gfx::Transform filter_pass_to_target_transform_;
- gfx::Rect filter_pass_layer_rect_;
-};
-
-TEST_F(GLRendererPixelTestWithBackdropFilter, FilterQuality) {
- this->backdrop_filters_.Append(cc::FilterOperation::CreateBlurFilter(2.0f));
- this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_);
- this->backdrop_filter_bounds_ =
- gfx::RRectF(gfx::RectF(this->filter_pass_layer_rect_));
- this->backdrop_filter_quality_ = 1.0f;
- this->SetUpRenderPassList();
- EXPECT_TRUE(this->RunPixelTest(
- &this->pass_list_,
- base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
- cc::FuzzyPixelOffByOneComparator(true)));
-
- if (this->context_provider()->ContextCapabilities().major_version < 3)
- return;
- this->backdrop_filter_quality_ = 0.33f;
- this->SetUpRenderPassList();
- EXPECT_TRUE(this->RunPixelTest(
- &this->pass_list_,
- base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_2.png")),
- cc::FuzzyPixelOffByOneComparator(true)));
-}
-
-TEST_F(GLRendererPixelTestWithBackdropFilter, CachedResultOfBackdropFilter) {
- this->backdrop_filters_.Append(cc::FilterOperation::CreateBlurFilter(2.0f));
- this->filter_pass_layer_rect_ = gfx::Rect(this->device_viewport_size_);
- this->backdrop_filter_bounds_ =
- gfx::RRectF(gfx::RectF(this->filter_pass_layer_rect_));
- // Set the flag to use cached backdrop filtered texture. This makes the
- // GLRenderer cache backdrop filtered result.
- this->intersects_damage_under_ = false;
- this->SetUpRenderPassList();
-
- EXPECT_TRUE(this->RunPixelTest(
- &this->pass_list_,
- base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
- cc::FuzzyPixelOffByOneComparator(true)));
-
- // Same render pass list makes the GLRenderer to skip backdrop filter
- // calculation and use cached texture. This should correctly produce the
- // same output image.
- this->SetUpRenderPassList();
- EXPECT_TRUE(this->RunPixelTest(
- &this->pass_list_,
- base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
- cc::FuzzyPixelOffByOneComparator(true)));
-
- // To prove the cached texture is used, change a quad on the root pass which
- // is beneath the backdrop filter. The output image should still be the same
- // as before.
- this->SetUpRenderPassList();
- DrawQuad* background_quad = *pass_list_.back()->quad_list.rbegin();
- static_cast<SolidColorDrawQuad*>(background_quad)->color = SK_ColorYELLOW;
- EXPECT_TRUE(this->RunPixelTest(
- &this->pass_list_,
- base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_1.png")),
- cc::FuzzyPixelOffByOneComparator(true)));
-
- // Set |intersects_damage_under_| to true to make GLRenderer re-run the
- // backdrop filter calculation
- this->intersects_damage_under_ = true;
- this->SetUpRenderPassList();
- background_quad = *pass_list_.back()->quad_list.rbegin();
- static_cast<SolidColorDrawQuad*>(background_quad)->color = SK_ColorYELLOW;
- EXPECT_TRUE(this->RunPixelTest(
- &this->pass_list_,
- base::FilePath(FILE_PATH_LITERAL("gl_backdrop_filter_3.png")),
- cc::FuzzyPixelOffByOneComparator(true)));
-}
-#endif
-
// Software renderer does not support anti-aliased edges.
TEST_P(GPURendererPixelTest, AntiAliasing) {
gfx::Rect rect(this->device_viewport_size_);
@@ -4590,21 +4398,10 @@ TEST_P(RendererPixelTest, RoundedCornerSimpleSolidDrawQuad) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(root_pass));
- if (is_gl_renderer()) {
- // GL Renderer should have an exact match as that is the reference point.
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
- cc::ExactPixelComparator(true)));
- } else {
- // Software/skia renderer uses skia rrect to create rounded corner clip.
- // This results in a different corner path due to a different anti aliasing
- // approach than the fragment shader in gl renderer.
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
- cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
- }
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
+ cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
}
TEST_P(GPURendererPixelTest, RoundedCornerSimpleTextureDrawQuad) {
@@ -4659,21 +4456,10 @@ TEST_P(GPURendererPixelTest, RoundedCornerSimpleTextureDrawQuad) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(root_pass));
- if (is_gl_renderer()) {
- // GL Renderer should have an exact match as that is the reference point.
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
- cc::ExactPixelComparator(true)));
- } else {
- // SkiaRenderer uses skia rrect to create rounded corner clip. This results
- // in a different corner path due to a different anti aliasing approach than
- // the fragment shader in gl renderer.
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
- cc::FuzzyPixelComparator(true, 0.6f, 0.f, 255.f, 255, 0)));
- }
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("rounded_corner_simple.png")),
+ cc::FuzzyPixelComparator(true, 0.6f, 0.f, 255.f, 255, 0)));
}
TEST_P(RendererPixelTest, RoundedCornerOnRenderPass) {
@@ -4774,21 +4560,13 @@ TEST_P(RendererPixelTest, RoundedCornerMultiRadii) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(root_pass));
- if (is_gl_renderer()) {
- // GL Renderer should have an exact match as that is the reference point.
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
- cc::ExactPixelComparator(true)));
- } else {
- // Software/skia renderer uses skia rrect to create rounded corner clip.
- // This results in a different corner path due to a different anti aliasing
- // approach than the fragment shader in gl renderer.
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
- cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
- }
+ // Software/skia renderer uses skia rrect to create rounded corner clip.
+ // This results in a different corner path due to a different anti aliasing
+ // approach than the fragment shader in gl renderer.
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_radii.png")),
+ cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
}
TEST_P(RendererPixelTest, RoundedCornerMultipleQads) {
@@ -4867,21 +4645,11 @@ TEST_P(RendererPixelTest, RoundedCornerMultipleQads) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(root_pass));
- // GL Renderer should have an exact match as that is the reference point.
- // Software/skia renderer use skia rrect to create rounded corner clip.
- // This results in a different corner path due to a different anti aliasing
- // approach than the fragment shader in gl renderer.
- std::unique_ptr<cc::PixelComparator> comparator;
- comparator.reset(
- is_gl_renderer()
- ? static_cast<cc::PixelComparator*>(
- new cc::ExactPixelComparator(true))
- : static_cast<cc::PixelComparator*>(
- new cc::FuzzyPixelComparator(true, 0.55f, 0.f, 255.f, 255, 0)));
+ cc::FuzzyPixelComparator comparator(true, 0.55f, 0.f, 255.f, 255, 0);
EXPECT_TRUE(this->RunPixelTest(
&pass_list,
base::FilePath(FILE_PATH_LITERAL("rounded_corner_multi_quad.png")),
- *comparator));
+ comparator));
}
class RendererPixelTestWithOverdrawFeedback : public VizPixelTestWithParam {
@@ -4913,19 +4681,12 @@ TEST_P(RendererPixelTestWithOverdrawFeedback, TranslucentRectangles) {
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
- if (is_gl_renderer()) {
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("translucent_rectangles.png")),
- cc::ExactPixelComparator(true)));
- } else {
- // TODO(xing.xu): investigate why overdraw feedback has small difference
- // (http://crbug.com/909971)
- EXPECT_TRUE(this->RunPixelTest(
- &pass_list,
- base::FilePath(FILE_PATH_LITERAL("skia_translucent_rectangles.png")),
- cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f)));
- }
+ // TODO(xing.xu): investigate why overdraw feedback has small difference
+ // (http://crbug.com/909971)
+ EXPECT_TRUE(this->RunPixelTest(
+ &pass_list,
+ base::FilePath(FILE_PATH_LITERAL("translucent_rectangles.png")),
+ cc::FuzzyPixelComparator(false, 2.f, 0.f, 256.f, 256, 0.f)));
}
INSTANTIATE_TEST_SUITE_P(,
@@ -4962,28 +4723,13 @@ class ColorTransformPixelTest
}
this->display_color_spaces_ =
gfx::DisplayColorSpaces(this->dst_color_space_);
- float sdr_max_luminance_nits =
- this->display_color_spaces_.GetSDRMaxLuminanceNits();
- if (src_color_space_.GetSDRWhiteLevel(&sdr_max_luminance_nits)) {
- this->display_color_spaces_.SetSDRMaxLuminanceNits(
- sdr_max_luminance_nits);
- }
this->premultiplied_alpha_ = std::get<3>(GetParam());
}
void Basic() {
- // Skip piecewise transfer functions because SkColorSpace (needed for
- // CopyOutputResult::AsSkBitmap) doesn't support them..
- if ((src_color_space_.GetTransferID() == TransferID::PIECEWISE_HDR ||
- dst_color_space_.GetTransferID() == TransferID::PIECEWISE_HDR)) {
- LOG(ERROR) << "Skipping piecewise HDR function";
- return;
- }
-
if (src_color_space_.GetTransferID() == TransferID::PQ &&
!dst_color_space_.IsHDR()) {
- LOG(ERROR) << "Skipping tonemapped output";
- return;
+ GTEST_SKIP() << "Skipping tonemapped output";
}
gfx::Rect rect(this->device_viewport_size_);
@@ -5018,8 +4764,7 @@ class ColorTransformPixelTest
}
gfx::ColorTransform::Options options;
- options.sdr_max_luminance_nits =
- display_color_spaces_.GetSDRMaxLuminanceNits();
+ options.sdr_max_luminance_nits = gfx::ColorSpace::kDefaultSDRWhiteLevel;
std::unique_ptr<gfx::ColorTransform> transform =
gfx::ColorTransform::NewColorTransform(this->src_color_space_,
this->dst_color_space_, options);
@@ -5086,9 +4831,19 @@ class ColorTransformPixelTest
AggregatedRenderPassList pass_list;
pass_list.push_back(std::move(pass));
- // Allow a difference of 2 bytes in comparison for shader-based transforms,
- // and 4 bytes for LUT-based transforms (determined empirically).
- cc::FuzzyPixelComparator comparator(false, 100.f, 0.f, 2.f, 2, 0);
+ // Allow a difference of 2 bytes in comparison for most cases.
+ float avg_abs_error_limit = 2.0f;
+ int max_abs_error_limit = 2;
+#if BUILDFLAG(IS_FUCHSIA)
+ if (src_color_space_.GetTransferID() == TransferID::PQ) {
+ // Fuchsia+SwiftShader/Vulkan has higher error on some pixels with HDR
+ // color spaces. See https://crbug.com/1312141.
+ max_abs_error_limit = 5;
+ }
+#endif
+
+ cc::FuzzyPixelComparator comparator(false, 100.f, 0.f, avg_abs_error_limit,
+ max_abs_error_limit, 0);
EXPECT_TRUE(
this->RunPixelTest(&pass_list, &expected_output_colors, comparator))
<< " src:" << src_color_space_ << ", dst:" << dst_color_space_;
@@ -5099,13 +4854,14 @@ class ColorTransformPixelTest
bool premultiplied_alpha_ = false;
};
-// crbug.com/1312043 Disable the test due to flaky.
-#if (BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER)) || BUILDFLAG(IS_FUCHSIA)
-#define MAYBE_Basic DISABLED_Basic
-#else
-#define MAYBE_Basic Basic
+TEST_P(ColorTransformPixelTest, Basic) {
+#if BUILDFLAG(IS_LINUX) && defined(THREAD_SANITIZER)
+ // Test is flaking with failed large allocations under TSAN when using
+ // SkiaRenderer with GL backend. See https://crbug.com/1320955.
+ if (renderer_type() == RendererType::kSkiaGL)
+ return;
#endif
-TEST_P(ColorTransformPixelTest, MAYBE_Basic) {
+
Basic();
}
@@ -5121,10 +4877,7 @@ gfx::ColorSpace src_color_spaces[] = {
gfx::ColorSpace(PrimaryID::BT709, TransferID::SMPTEST428_1),
gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR),
gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
- // Piecewise HDR transfer functions skipped with SkiaRenderer.
- gfx::ColorSpace::CreatePiecewiseHDR(PrimaryID::BT709, 0.5, 1.5),
- gfx::ColorSpace::CreateHDR10(50.f),
- gfx::ColorSpace::CreateHDR10(250.f),
+ gfx::ColorSpace::CreateHDR10(),
};
gfx::ColorSpace dst_color_spaces[] = {
@@ -5138,8 +4891,6 @@ gfx::ColorSpace dst_color_spaces[] = {
gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB),
gfx::ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR),
gfx::ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR),
- // Piecewise HDR transfer functions are skipped with SkiaRenderer.
- gfx::ColorSpace::CreatePiecewiseHDR(PrimaryID::BT709, 0.25, 2.5),
};
gfx::ColorSpace intermediate_color_spaces[] = {
diff --git a/chromium/components/viz/service/display/resource_fence.h b/chromium/components/viz/service/display/resource_fence.h
index dc4153ea490..59e1101247e 100644
--- a/chromium/components/viz/service/display/resource_fence.h
+++ b/chromium/components/viz/service/display/resource_fence.h
@@ -7,6 +7,8 @@
#include "base/memory/ref_counted.h"
+#include "ui/gfx/gpu_fence_handle.h"
+
namespace viz {
// An abstract interface used to ensure reading from resources passed between
@@ -16,8 +18,16 @@ class ResourceFence : public base::RefCountedThreadSafe<ResourceFence> {
ResourceFence(const ResourceFence&) = delete;
ResourceFence& operator=(const ResourceFence&) = delete;
+ // Notifies the fence is needed.
virtual void Set() = 0;
+ // Tells if the fence is ready.
virtual bool HasPassed() = 0;
+ // A release fence which availability depends on the type of resource fence
+ // (managed by DisplayResourceProvider and
+ // TransferableResource::synchronization_type). The client must ensure that
+ // HasPassed is true before trying to access the release fence handle.
+ // Otherwise, it's not guaranteed that the fence handle is valid.
+ virtual gfx::GpuFenceHandle GetGpuFenceHandle() = 0;
protected:
friend class base::RefCountedThreadSafe<ResourceFence>;
diff --git a/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc b/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc
deleted file mode 100644
index e7968ed7377..00000000000
--- a/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/scoped_gpu_memory_buffer_texture.h"
-
-#include "base/check.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
-
-namespace viz {
-
-ScopedGpuMemoryBufferTexture::ScopedGpuMemoryBufferTexture(
- ContextProvider* context_provider,
- const gfx::Size& size,
- const gfx::ColorSpace& color_space)
- : context_provider_(context_provider),
- size_(size),
- color_space_(color_space) {
- DCHECK(context_provider_);
-
- const auto& caps = context_provider->ContextCapabilities();
- // This capability is needed to use TexStorage2DImageCHROMIUM, and should be
- // known to be enabled before using an object of this type.
- DCHECK(caps.texture_storage_image);
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- gl->GenTextures(1, &gl_id_);
-
- gfx::BufferUsage usage = gfx::BufferUsage::SCANOUT;
- ResourceFormat format = RGBA_8888;
- gfx::BufferFormat buffer_format = BufferFormat(format);
-
- target_ = gpu::GetBufferTextureTarget(usage, buffer_format, caps);
-
- gl->BindTexture(target_, gl_id_);
- gl->TexParameteri(target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl->TexParameteri(target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl->TexParameteri(target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri(target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- gl->TexStorage2DImageCHROMIUM(
- target_, TextureStorageFormat(format, caps.angle_rgbx_internal_format),
- GL_SCANOUT_CHROMIUM, size_.width(), size_.height());
- if (color_space_.IsValid()) {
- gl->SetColorSpaceMetadataCHROMIUM(gl_id_, color_space_.AsGLColorSpace());
- }
- gl->BindTexture(target_, 0);
-}
-
-ScopedGpuMemoryBufferTexture::ScopedGpuMemoryBufferTexture() = default;
-
-ScopedGpuMemoryBufferTexture::~ScopedGpuMemoryBufferTexture() {
- Free();
-}
-
-ScopedGpuMemoryBufferTexture::ScopedGpuMemoryBufferTexture(
- ScopedGpuMemoryBufferTexture&& other)
- : context_provider_(other.context_provider_),
- gl_id_(other.gl_id_),
- target_(other.target_),
- size_(other.size_),
- color_space_(other.color_space_) {
- other.gl_id_ = 0;
-}
-
-ScopedGpuMemoryBufferTexture& ScopedGpuMemoryBufferTexture::operator=(
- ScopedGpuMemoryBufferTexture&& other) {
- DCHECK(!context_provider_ || !other.context_provider_ ||
- context_provider_ == other.context_provider_);
- if (this != &other) {
- Free();
- context_provider_ = other.context_provider_;
- gl_id_ = other.gl_id_;
- target_ = other.target_;
- size_ = other.size_;
- color_space_ = other.color_space_;
-
- other.gl_id_ = 0;
- }
- return *this;
-}
-
-void ScopedGpuMemoryBufferTexture::Free() {
- if (!gl_id_)
- return;
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- gl->DeleteTextures(1, &gl_id_);
- gl_id_ = 0;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.h b/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.h
deleted file mode 100644
index 1711224bcb1..00000000000
--- a/chromium/components/viz/service/display/scoped_gpu_memory_buffer_texture.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SCOPED_GPU_MEMORY_BUFFER_TEXTURE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_SCOPED_GPU_MEMORY_BUFFER_TEXTURE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/service/viz_service_export.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace viz {
-class ContextProvider;
-
-// ScopedGpuMemoryBufferTexture is a GL texture backed by a GL image and a
-// GpuMemoryBuffer, so that it can be used as an overlay.
-class VIZ_SERVICE_EXPORT ScopedGpuMemoryBufferTexture {
- public:
- explicit ScopedGpuMemoryBufferTexture(ContextProvider* context_provider,
- const gfx::Size& size,
- const gfx::ColorSpace& color_space);
-
- ScopedGpuMemoryBufferTexture();
- ~ScopedGpuMemoryBufferTexture();
-
- ScopedGpuMemoryBufferTexture(ScopedGpuMemoryBufferTexture&& other);
- ScopedGpuMemoryBufferTexture& operator=(ScopedGpuMemoryBufferTexture&& other);
-
- uint32_t id() const { return gl_id_; }
- uint32_t target() const { return target_; }
- const gfx::Size& size() const { return size_; }
- const gfx::ColorSpace& color_space() const { return color_space_; }
-
- private:
- void Free();
-
- // The ContextProvider used to free the texture when this object is destroyed,
- // so it must outlive this object.
- raw_ptr<ContextProvider> context_provider_ = nullptr;
- uint32_t gl_id_ = 0;
- uint32_t target_ = 0;
- gfx::Size size_;
- gfx::ColorSpace color_space_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SCOPED_GPU_MEMORY_BUFFER_TEXTURE_H_
diff --git a/chromium/components/viz/service/display/scoped_render_pass_texture.cc b/chromium/components/viz/service/display/scoped_render_pass_texture.cc
deleted file mode 100644
index 9a668018e08..00000000000
--- a/chromium/components/viz/service/display/scoped_render_pass_texture.cc
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/scoped_render_pass_texture.h"
-
-#include <algorithm>
-
-#include "base/bits.h"
-#include "base/check.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-
-namespace viz {
-
-ScopedRenderPassTexture::ScopedRenderPassTexture() = default;
-
-ScopedRenderPassTexture::ScopedRenderPassTexture(
- ContextProvider* context_provider,
- const gfx::Size& size,
- ResourceFormat format,
- const gfx::ColorSpace& color_space,
- bool mipmap)
- : context_provider_(context_provider),
- size_(size),
- mipmap_(mipmap),
- color_space_(color_space) {
- DCHECK(context_provider_);
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- const gpu::Capabilities& caps = context_provider_->ContextCapabilities();
- gl->GenTextures(1, &gl_id_);
-
- gl->BindTexture(GL_TEXTURE_2D, gl_id_);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- // This texture will be bound as a framebuffer, so optimize for that.
- if (caps.texture_usage) {
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_USAGE_ANGLE,
- GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
- }
-
- if (caps.texture_storage) {
- GLint levels = 1;
- if (caps.texture_npot && mipmap_)
- levels += base::bits::Log2Floor(std::max(size_.width(), size_.height()));
-
- gl->TexStorage2DEXT(
- GL_TEXTURE_2D, levels,
- TextureStorageFormat(format, context_provider_->ContextCapabilities()
- .angle_rgbx_internal_format),
- size_.width(), size_.height());
- } else {
- DCHECK(GLSupportsFormat(format));
- gl->TexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(format), size_.width(),
- size_.height(), 0, GLDataFormat(format), GLDataType(format),
- nullptr);
- }
-}
-
-ScopedRenderPassTexture::~ScopedRenderPassTexture() {
- Free();
-}
-
-ScopedRenderPassTexture::ScopedRenderPassTexture(
- ScopedRenderPassTexture&& other) {
- context_provider_ = other.context_provider_;
- size_ = other.size_;
- mipmap_ = other.mipmap_;
- color_space_ = other.color_space_;
- gl_id_ = other.gl_id_;
- mipmap_state_ = other.mipmap_state_;
-
- // When being moved, other will no longer hold this gl_id_.
- other.gl_id_ = 0;
-}
-
-ScopedRenderPassTexture& ScopedRenderPassTexture::operator=(
- ScopedRenderPassTexture&& other) {
- if (this != &other) {
- Free();
- context_provider_ = other.context_provider_;
- size_ = other.size_;
- mipmap_ = other.mipmap_;
- color_space_ = other.color_space_;
- gl_id_ = other.gl_id_;
- mipmap_state_ = other.mipmap_state_;
-
- // When being moved, other will no longer hold this gl_id_.
- other.gl_id_ = 0;
- }
- return *this;
-}
-
-void ScopedRenderPassTexture::Free() {
- if (!gl_id_)
- return;
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- gl->DeleteTextures(1, &gl_id_);
- gl_id_ = 0;
-}
-
-void ScopedRenderPassTexture::BindForSampling() {
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- gl->BindTexture(GL_TEXTURE_2D, gl_id_);
- switch (mipmap_state_) {
- case INVALID:
- break;
- case GENERATE:
- // TODO(crbug.com/803286): npot texture always return false on ubuntu
- // desktop. The npot texture check is probably failing on desktop GL.
- DCHECK(context_provider_->ContextCapabilities().texture_npot);
- gl->GenerateMipmap(GL_TEXTURE_2D);
- mipmap_state_ = VALID;
- [[fallthrough]];
- case VALID:
- gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_LINEAR_MIPMAP_LINEAR);
- break;
- }
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/scoped_render_pass_texture.h b/chromium/components/viz/service/display/scoped_render_pass_texture.h
deleted file mode 100644
index da29d49b70b..00000000000
--- a/chromium/components/viz/service/display/scoped_render_pass_texture.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SCOPED_RENDER_PASS_TEXTURE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_SCOPED_RENDER_PASS_TEXTURE_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/common/resources/resource_format.h"
-#include "components/viz/service/viz_service_export.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace viz {
-class ContextProvider;
-
-// ScopedRenderPassTexture is resource used inside the same GL context and will
-// not being sent into another process. So no need to create fence and mailbox
-// for these resources.
-class VIZ_SERVICE_EXPORT ScopedRenderPassTexture {
- public:
- ScopedRenderPassTexture();
- ScopedRenderPassTexture(ContextProvider* context_provider,
- const gfx::Size& size,
- ResourceFormat format,
- const gfx::ColorSpace& color_space,
- bool mipmap);
- ~ScopedRenderPassTexture();
-
- ScopedRenderPassTexture(ScopedRenderPassTexture&& other);
- ScopedRenderPassTexture& operator=(ScopedRenderPassTexture&& other);
- void BindForSampling();
-
- GLuint id() const { return gl_id_; }
- const gfx::Size& size() const { return size_; }
- bool mipmap() const { return mipmap_; }
- const gfx::ColorSpace& color_space() const { return color_space_; }
- void set_generate_mipmap() { mipmap_state_ = GENERATE; }
-
- private:
- void Free();
-
- raw_ptr<ContextProvider> context_provider_ = nullptr;
- // The GL texture id.
- GLuint gl_id_ = 0;
- // Size of the resource in pixels.
- gfx::Size size_;
- // When true, and immutable textures are used, this specifies to
- // generate mipmaps at powers of 2.
- bool mipmap_ = false;
- // TODO(xing.xu): Remove this and set the color space when we draw the
- // CompositorRenderPassDrawQuad.
- gfx::ColorSpace color_space_;
- enum MipmapState { INVALID, GENERATE, VALID };
- MipmapState mipmap_state_ = INVALID;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SCOPED_RENDER_PASS_TEXTURE_H_
diff --git a/chromium/components/viz/service/display/shader.cc b/chromium/components/viz/service/display/shader.cc
deleted file mode 100644
index ac9e11564f7..00000000000
--- a/chromium/components/viz/service/display/shader.cc
+++ /dev/null
@@ -1,1168 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/shader.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-#include "base/check_op.h"
-#include "base/notreached.h"
-#include "base/strings/char_traits.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "components/viz/service/display/static_geometry_binding.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/gfx/color_transform.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/size.h"
-
-constexpr base::StringPiece StripLambda(base::StringPiece shader) {
- // Must contain at least "[]() {}".
- DCHECK_EQ(shader.substr(0, 6), "[]() {");
- DCHECK_EQ(shader.back(), '}');
- shader.remove_prefix(6);
- shader.remove_suffix(1);
- return shader;
-}
-
-// Shaders are passed in with lambda syntax, which tricks clang-format into
-// handling them correctly. StripLambda removes this.
-#define SHADER0(Src) StripLambda(#Src)
-
-#define HDR(x) \
- do { \
- header += x "\n"; \
- } while (0)
-#define SRC(x) \
- do { \
- source += " " x "\n"; \
- } while (0)
-
-using gpu::gles2::GLES2Interface;
-
-namespace viz {
-
-namespace {
-
-static void GetProgramUniformLocations(GLES2Interface* context,
- unsigned program,
- size_t count,
- const char** uniforms,
- int* locations,
- int* base_uniform_index) {
- for (size_t i = 0; i < count; i++) {
- locations[i] = (*base_uniform_index)++;
- context->BindUniformLocationCHROMIUM(program, locations[i], uniforms[i]);
- }
-}
-
-static void SetFragmentTexCoordPrecision(TexCoordPrecision requested_precision,
- std::string* shader_string) {
- const char* prefix = "";
- switch (requested_precision) {
- case TEX_COORD_PRECISION_HIGH:
- DCHECK_NE(shader_string->find("TexCoordPrecision"), std::string::npos);
- prefix =
- "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
- " #define TexCoordPrecision highp\n"
- "#else\n"
- " #define TexCoordPrecision mediump\n"
- "#endif\n";
- break;
- case TEX_COORD_PRECISION_MEDIUM:
- DCHECK_NE(shader_string->find("TexCoordPrecision"), std::string::npos);
- prefix = "#define TexCoordPrecision mediump\n";
- break;
- case TEX_COORD_PRECISION_NA:
- DCHECK_EQ(shader_string->find("TexCoordPrecision"), std::string::npos);
- DCHECK_EQ(shader_string->find("texture2D"), std::string::npos);
- DCHECK_EQ(shader_string->find("texture2DRect"), std::string::npos);
- break;
- default:
- NOTREACHED();
- break;
- }
- const char* lut_prefix = "#define LutLookup texture2D\n";
- shader_string->insert(0, prefix);
- shader_string->insert(0, lut_prefix);
-}
-
-TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
- int* highp_threshold_cache,
- int highp_threshold_min,
- int x,
- int y) {
- if (*highp_threshold_cache == 0) {
- // Initialize range and precision with minimum spec values for when
- // GetShaderPrecisionFormat is a test stub.
- // TODO(brianderson): Implement better stubs of GetShaderPrecisionFormat
- // everywhere.
- GLint range[2] = {14, 14};
- GLint precision = 10;
- context->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
- range, &precision);
- *highp_threshold_cache = 1 << precision;
- }
-
- int highp_threshold = std::max(*highp_threshold_cache, highp_threshold_min);
- if (x > highp_threshold || y > highp_threshold)
- return TEX_COORD_PRECISION_HIGH;
- return TEX_COORD_PRECISION_MEDIUM;
-}
-
-void SetFragmentSamplerType(SamplerType requested_type,
- std::string* shader_string) {
- const char* prefix = nullptr;
- switch (requested_type) {
- case SAMPLER_TYPE_2D:
- DCHECK_NE(shader_string->find("SamplerType"), std::string::npos);
- DCHECK_NE(shader_string->find("TextureLookup"), std::string::npos);
- prefix =
- "#define SamplerType sampler2D\n"
- "#define TextureLookup texture2D\n";
- break;
- case SAMPLER_TYPE_2D_RECT:
- DCHECK_NE(shader_string->find("SamplerType"), std::string::npos);
- DCHECK_NE(shader_string->find("TextureLookup"), std::string::npos);
- prefix =
- "#extension GL_ARB_texture_rectangle : require\n"
- "#define SamplerType sampler2DRect\n"
- "#define TextureLookup texture2DRect\n";
- break;
- case SAMPLER_TYPE_EXTERNAL_OES:
- DCHECK_NE(shader_string->find("SamplerType"), std::string::npos);
- DCHECK_NE(shader_string->find("TextureLookup"), std::string::npos);
- prefix =
- "#extension GL_OES_EGL_image_external : enable\n"
- "#extension GL_NV_EGL_stream_consumer_external : enable\n"
- "#define SamplerType samplerExternalOES\n"
- "#define TextureLookup texture2D\n";
- break;
- case SAMPLER_TYPE_NA:
- DCHECK_EQ(shader_string->find("SamplerType"), std::string::npos);
- DCHECK_EQ(shader_string->find("TextureLookup"), std::string::npos);
- return;
- default:
- NOTREACHED();
- return;
- }
- shader_string->insert(0, prefix);
-}
-
-} // namespace
-
-TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
- int* highp_threshold_cache,
- int highp_threshold_min,
- const gfx::Point& max_coordinate) {
- return TexCoordPrecisionRequired(context, highp_threshold_cache,
- highp_threshold_min, max_coordinate.x(),
- max_coordinate.y());
-}
-
-TexCoordPrecision TexCoordPrecisionRequired(GLES2Interface* context,
- int* highp_threshold_cache,
- int highp_threshold_min,
- const gfx::Size& max_size) {
- return TexCoordPrecisionRequired(context, highp_threshold_cache,
- highp_threshold_min, max_size.width(),
- max_size.height());
-}
-
-VertexShader::VertexShader() {}
-
-void VertexShader::Init(GLES2Interface* context,
- unsigned program,
- int* base_uniform_index) {
- std::vector<const char*> uniforms;
- std::vector<int> locations;
-
- switch (tex_coord_transform_) {
- case TEX_COORD_TRANSFORM_NONE:
- break;
- case TEX_COORD_TRANSFORM_VEC4:
- case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
- uniforms.push_back("vertexTexTransform");
- break;
- case TEX_COORD_TRANSFORM_MATRIX:
- uniforms.push_back("texMatrix");
- break;
- }
- if (is_ya_uv_) {
- uniforms.push_back("yaTexScale");
- uniforms.push_back("yaTexOffset");
- uniforms.push_back("uvTexScale");
- uniforms.push_back("uvTexOffset");
- }
- uniforms.push_back("matrix");
- if (has_vertex_opacity_)
- uniforms.push_back("opacity");
- if (aa_mode_ == USE_AA) {
- uniforms.push_back("viewport");
- uniforms.push_back("edge");
- }
- if (position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM)
- uniforms.push_back("quad");
-
- locations.resize(uniforms.size());
-
- GetProgramUniformLocations(context, program, uniforms.size(), uniforms.data(),
- locations.data(), base_uniform_index);
-
- size_t index = 0;
- switch (tex_coord_transform_) {
- case TEX_COORD_TRANSFORM_NONE:
- break;
- case TEX_COORD_TRANSFORM_VEC4:
- case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
- vertex_tex_transform_location_ = locations[index++];
- break;
- case TEX_COORD_TRANSFORM_MATRIX:
- tex_matrix_location_ = locations[index++];
- break;
- }
- if (is_ya_uv_) {
- ya_tex_scale_location_ = locations[index++];
- ya_tex_offset_location_ = locations[index++];
- uv_tex_scale_location_ = locations[index++];
- uv_tex_offset_location_ = locations[index++];
- }
- matrix_location_ = locations[index++];
- if (has_vertex_opacity_)
- vertex_opacity_location_ = locations[index++];
- if (aa_mode_ == USE_AA) {
- viewport_location_ = locations[index++];
- edge_location_ = locations[index++];
- }
- if (position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM)
- quad_location_ = locations[index++];
-}
-
-std::string VertexShader::GetShaderString() const {
- // We unconditionally use highp in the vertex shader since
- // we are unlikely to be vertex shader bound when drawing large quads.
- // Also, some vertex shaders mutate the texture coordinate in such a
- // way that the effective precision might be lower than expected.
- std::string header = "#define TexCoordPrecision highp\n";
- std::string source = "void main() {\n";
-
- // Define the size of quads for attribute indexed uniform arrays.
- if (use_uniform_arrays_) {
- header += base::StringPrintf("#define NUM_QUADS %d\n",
- StaticGeometryBinding::NUM_QUADS);
- }
-
- // Read the index variables.
- if (use_uniform_arrays_ || has_vertex_opacity_ ||
- position_source_ == POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM) {
- HDR("attribute float a_index;");
- SRC("// Compute indices for uniform arrays.");
- SRC("int vertex_index = int(a_index);");
- if (use_uniform_arrays_)
- SRC("int quad_index = int(a_index * 0.25);");
- SRC("");
- }
-
- // Read the position and compute gl_Position.
- HDR("attribute TexCoordPrecision vec4 a_position;");
- SRC("// Compute the position.");
- switch (position_source_) {
- case POSITION_SOURCE_ATTRIBUTE:
- SRC("vec4 pos = a_position;");
- break;
- case POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM:
- HDR("uniform TexCoordPrecision vec2 quad[4];");
- SRC("vec4 pos = vec4(quad[vertex_index], a_position.z, a_position.w);");
- break;
- }
- if (use_uniform_arrays_) {
- HDR("uniform mat4 matrix[NUM_QUADS];");
- SRC("gl_Position = matrix[quad_index] * pos;");
- } else {
- HDR("uniform mat4 matrix;");
- SRC("gl_Position = matrix * pos;");
- }
-
- // Compute the anti-aliasing edge distances.
- if (aa_mode_ == USE_AA) {
- HDR("uniform TexCoordPrecision vec3 edge[8];");
- HDR("uniform vec4 viewport;");
- HDR("varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.");
- SRC("// Compute anti-aliasing properties.\n");
- SRC("vec2 ndc_pos = 0.5 * (1.0 + gl_Position.xy / gl_Position.w);");
- SRC("vec3 screen_pos = vec3(viewport.xy + viewport.zw * ndc_pos, 1.0);");
- SRC("edge_dist[0] = vec4(dot(edge[0], screen_pos),");
- SRC(" dot(edge[1], screen_pos),");
- SRC(" dot(edge[2], screen_pos),");
- SRC(" dot(edge[3], screen_pos)) * gl_Position.w;");
- SRC("edge_dist[1] = vec4(dot(edge[4], screen_pos),");
- SRC(" dot(edge[5], screen_pos),");
- SRC(" dot(edge[6], screen_pos),");
- SRC(" dot(edge[7], screen_pos)) * gl_Position.w;");
- }
-
- // Read, transform, and write texture coordinates.
- if (tex_coord_source_ != TEX_COORD_SOURCE_NONE) {
- if (is_ya_uv_) {
- HDR("varying TexCoordPrecision vec2 v_uvTexCoord;");
- HDR("varying TexCoordPrecision vec2 v_yaTexCoord;");
- } else {
- HDR("varying TexCoordPrecision vec2 v_texCoord;");
- }
-
- SRC("// Compute texture coordinates.");
- // Read coordinates.
- switch (tex_coord_source_) {
- case TEX_COORD_SOURCE_NONE:
- break;
- case TEX_COORD_SOURCE_POSITION:
- SRC("vec2 texCoord = pos.xy;");
- break;
- case TEX_COORD_SOURCE_ATTRIBUTE:
- HDR("attribute TexCoordPrecision vec2 a_texCoord;");
- SRC("vec2 texCoord = a_texCoord;");
- break;
- }
- // Transform coordinates (except YUV).
- switch (tex_coord_transform_) {
- case TEX_COORD_TRANSFORM_NONE:
- break;
- case TEX_COORD_TRANSFORM_TRANSLATED_VEC4:
- SRC("texCoord = texCoord + vec2(0.5);");
- [[fallthrough]];
- case TEX_COORD_TRANSFORM_VEC4:
- if (use_uniform_arrays_) {
- HDR("uniform TexCoordPrecision vec4 vertexTexTransform[NUM_QUADS];");
- SRC("TexCoordPrecision vec4 texTrans =");
- SRC(" vertexTexTransform[quad_index];");
- SRC("texCoord = texCoord * texTrans.zw + texTrans.xy;");
- } else {
- HDR("uniform TexCoordPrecision vec4 vertexTexTransform;");
- SRC("texCoord = texCoord * vertexTexTransform.zw +");
- SRC(" vertexTexTransform.xy;");
- }
- break;
- case TEX_COORD_TRANSFORM_MATRIX:
- HDR("uniform TexCoordPrecision mat4 texMatrix;");
- SRC("texCoord = (texMatrix * vec4(texCoord.xy, 0.0, 1.0)).xy;");
- break;
- }
- // Write the output texture coordinates.
- if (is_ya_uv_) {
- HDR("uniform TexCoordPrecision vec2 uvTexOffset;");
- HDR("uniform TexCoordPrecision vec2 uvTexScale;");
- HDR("uniform TexCoordPrecision vec2 yaTexOffset;");
- HDR("uniform TexCoordPrecision vec2 yaTexScale;");
- SRC("v_yaTexCoord = texCoord * yaTexScale + yaTexOffset;");
- SRC("v_uvTexCoord = texCoord * uvTexScale + uvTexOffset;");
- } else {
- SRC("v_texCoord = texCoord;");
- }
- }
-
- // Write varying vertex opacity.
- if (has_vertex_opacity_) {
- HDR("varying float v_alpha;");
- if (use_uniform_arrays_) {
- HDR("uniform float opacity[NUM_QUADS * 4];");
- } else {
- HDR("uniform float opacity[4];");
- }
- SRC("v_alpha = opacity[vertex_index];");
- }
-
- // Add cargo-culted dummy variables for Android.
- if (has_dummy_variables_) {
- HDR("uniform TexCoordPrecision vec2 dummy_uniform;");
- HDR("varying TexCoordPrecision vec2 dummy_varying;");
- SRC("dummy_varying = dummy_uniform;");
- }
-
- source += "}\n";
- return header + source;
-}
-
-FragmentShader::FragmentShader() {}
-
-std::string FragmentShader::GetShaderString() const {
- TexCoordPrecision precision = tex_coord_precision_;
- // The AA shader values will use TexCoordPrecision.
- if (aa_mode_ == USE_AA && precision == TEX_COORD_PRECISION_NA)
- precision = TEX_COORD_PRECISION_MEDIUM;
- std::string shader = GetShaderSource();
- SetBlendModeFunctions(&shader);
- SetRoundedCornerFunctions(&shader);
- SetFragmentSamplerType(sampler_type_, &shader);
- SetFragmentTexCoordPrecision(precision, &shader);
- return shader;
-}
-
-void FragmentShader::Init(GLES2Interface* context,
- unsigned program,
- int* base_uniform_index) {
- std::vector<const char*> uniforms;
- std::vector<int> locations;
- if (has_blend_mode()) {
- uniforms.push_back("s_backdropTexture");
- uniforms.push_back("s_originalBackdropTexture");
- uniforms.push_back("backdropRect");
- }
- if (mask_mode_ != NO_MASK) {
- uniforms.push_back("s_mask");
- uniforms.push_back("maskTexCoordScale");
- uniforms.push_back("maskTexCoordOffset");
- }
- if (has_color_matrix_) {
- uniforms.push_back("colorMatrix");
- uniforms.push_back("colorOffset");
- }
- if (has_uniform_alpha_)
- uniforms.push_back("alpha");
- if (has_background_color_)
- uniforms.push_back("background_color");
- if (has_tex_clamp_rect_)
- uniforms.push_back("tex_clamp_rect");
- switch (input_color_type_) {
- case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
- uniforms.push_back("s_texture");
- if (has_rgba_fragment_tex_transform_)
- uniforms.push_back("fragmentTexTransform");
- break;
- case INPUT_COLOR_SOURCE_YUV_TEXTURES:
- uniforms.push_back("y_texture");
- if (uv_texture_mode_ == UV_TEXTURE_MODE_UV)
- uniforms.push_back("uv_texture");
- if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
- uniforms.push_back("u_texture");
- uniforms.push_back("v_texture");
- }
- if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
- uniforms.push_back("a_texture");
- uniforms.push_back("ya_clamp_rect");
- uniforms.push_back("uv_clamp_rect");
- uniforms.push_back("resource_multiplier");
- uniforms.push_back("resource_offset");
- break;
- case INPUT_COLOR_SOURCE_UNIFORM:
- uniforms.push_back("color");
- break;
- }
- if (has_output_color_matrix_)
- uniforms.emplace_back("output_color_matrix");
-
- if (has_tint_color_matrix_)
- uniforms.emplace_back("tint_color_matrix");
-
- if (has_rounded_corner_) {
- uniforms.emplace_back("roundedCornerRect");
- uniforms.emplace_back("roundedCornerRadius");
- }
-
- locations.resize(uniforms.size());
-
- GetProgramUniformLocations(context, program, uniforms.size(), uniforms.data(),
- locations.data(), base_uniform_index);
-
- size_t index = 0;
- if (has_blend_mode()) {
- backdrop_location_ = locations[index++];
- original_backdrop_location_ = locations[index++];
- backdrop_rect_location_ = locations[index++];
- }
- if (mask_mode_ != NO_MASK) {
- mask_sampler_location_ = locations[index++];
- mask_tex_coord_scale_location_ = locations[index++];
- mask_tex_coord_offset_location_ = locations[index++];
- }
- if (has_color_matrix_) {
- color_matrix_location_ = locations[index++];
- color_offset_location_ = locations[index++];
- }
- if (has_uniform_alpha_)
- alpha_location_ = locations[index++];
- if (has_background_color_)
- background_color_location_ = locations[index++];
- if (has_tex_clamp_rect_)
- tex_clamp_rect_location_ = locations[index++];
- switch (input_color_type_) {
- case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
- sampler_location_ = locations[index++];
- if (has_rgba_fragment_tex_transform_)
- fragment_tex_transform_location_ = locations[index++];
- break;
- case INPUT_COLOR_SOURCE_YUV_TEXTURES:
- y_texture_location_ = locations[index++];
- if (uv_texture_mode_ == UV_TEXTURE_MODE_UV)
- uv_texture_location_ = locations[index++];
- if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
- u_texture_location_ = locations[index++];
- v_texture_location_ = locations[index++];
- }
- if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
- a_texture_location_ = locations[index++];
- ya_clamp_rect_location_ = locations[index++];
- uv_clamp_rect_location_ = locations[index++];
- resource_multiplier_location_ = locations[index++];
- resource_offset_location_ = locations[index++];
- break;
- case INPUT_COLOR_SOURCE_UNIFORM:
- color_location_ = locations[index++];
- break;
- }
-
- if (has_output_color_matrix_)
- output_color_matrix_location_ = locations[index++];
-
- if (has_tint_color_matrix_)
- tint_color_matrix_location_ = locations[index++];
-
- if (has_rounded_corner_) {
- rounded_corner_rect_location_ = locations[index++];
- rounded_corner_radius_location_ = locations[index++];
- }
-
- DCHECK_EQ(index, locations.size());
-}
-
-void FragmentShader::SetRoundedCornerFunctions(
- std::string* shader_string) const {
- if (!has_rounded_corner_)
- return;
-
- static constexpr base::StringPiece kUniforms = SHADER0([]() {
- uniform vec4 roundedCornerRect;
- uniform vec4 roundedCornerRadius;
- });
-
- static constexpr base::StringPiece kFunctionRcUtility = SHADER0([]() {
- // Returns a vector of size 4. Each component of a vector is set to 1 or 0
- // representing whether |rcCoord| is a part of the respective corner or
- // not.
- // The component ordering is:
- // [Top left, Top right, Bottom right, Bottom left]
- vec4 IsCorner(vec2 rcCoord) {
- // Top left corner
- if (rcCoord.x < roundedCornerRadius.x &&
- rcCoord.y < roundedCornerRadius.x) {
- return vec4(1.0, 0.0, 0.0, 0.0);
- }
-
- // Top right corner
- if (rcCoord.x > roundedCornerRect.z - roundedCornerRadius.y &&
- rcCoord.y < roundedCornerRadius.y) {
- return vec4(0.0, 1.0, 0.0, 0.0);
- }
-
- // Bottom right corner
- if (rcCoord.x > roundedCornerRect.z - roundedCornerRadius.z &&
- rcCoord.y > roundedCornerRect.w - roundedCornerRadius.z) {
- return vec4(0.0, 0.0, 1.0, 0.0);
- }
-
- // Bottom left corner
- if (rcCoord.x < roundedCornerRadius.w &&
- rcCoord.y > roundedCornerRect.w - roundedCornerRadius.w) {
- return vec4(0.0, 0.0, 0.0, 1.0);
- }
- return vec4(0.0, 0.0, 0.0, 0.0);
- }
-
- // Returns the center of the rounded corner. |corner| holds the info on
- // which corner the center is requested for.
- vec2 GetCenter(vec4 corner, float radius) {
- if (corner.x == 1.0) {
- // Top left corner
- return vec2(radius, radius);
- } else if (corner.y == 1.0) {
- // Top right corner
- return vec2(roundedCornerRect.z - radius, radius);
- } else if (corner.z == 1.0) {
- // Bottom right corner
- return vec2(roundedCornerRect.z - radius, roundedCornerRect.w - radius);
- } else {
- // Bottom left corner
- return vec2(radius, roundedCornerRect.w - radius);
- }
- }
- });
-
- static constexpr base::StringPiece kFunctionApplyRoundedCorner =
- SHADER0([]() {
- vec4 ApplyRoundedCorner(vec4 src) {
- vec2 rcCoord = gl_FragCoord.xy - roundedCornerRect.xy;
-
- vec4 isCorner = IsCorner(rcCoord);
-
- // Get the radius to use based on the corner this fragment lies in.
- float r = dot(isCorner, roundedCornerRadius);
-
- // If the radius is 0, then there is no rounded corner here. We can do
- // an early return.
- if (r == 0.0)
- return src;
-
- // Vector to the corner's center this fragment is in.
- // Due to precision errors on android, this variable requires a highp.
- // See https://crbug.com/1009322
- RoundedCornerPrecision vec2 cornerCenter = GetCenter(isCorner, r);
-
- // Vector from the center of the corner to the current fragment center
- vec2 cxy = rcCoord - cornerCenter;
-
- // Compute the distance of the fragment's center from the corner's
- // center.
- float fragDst = length(cxy);
-
- float alpha = smoothstep(r - 1.0, r + 1.0, fragDst);
- return vec4(0.0) * alpha + src * (1.0 - alpha);
- }
- });
-
- std::string shader;
- shader.reserve(shader_string->size() + 2048);
- shader += "precision mediump float;";
- shader +=
- "\n#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
- " #define RoundedCornerPrecision highp\n"
- "#else\n"
- " #define RoundedCornerPrecision mediump\n"
- "#endif\n";
- base::StrAppend(&shader, {kUniforms, kFunctionRcUtility,
- kFunctionApplyRoundedCorner, *shader_string});
- *shader_string = std::move(shader);
-}
-
-void FragmentShader::SetBlendModeFunctions(std::string* shader_string) const {
- if (!has_blend_mode()) {
- return;
- }
-
- static constexpr base::StringPiece kUniforms = SHADER0([]() {
- uniform sampler2D s_backdropTexture;
- uniform sampler2D s_originalBackdropTexture;
- uniform TexCoordPrecision vec4 backdropRect;
- });
-
- base::StringPiece function_apply_blend_mode;
- if (mask_for_background_) {
- static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() {
- vec4 ApplyBlendMode(vec4 src, float mask) {
- TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
- bgTexCoord *= backdropRect.zw;
- vec4 backdrop = texture2D(s_backdropTexture, bgTexCoord);
- vec4 original_backdrop =
- texture2D(s_originalBackdropTexture, bgTexCoord);
- vec4 dst = mix(original_backdrop, backdrop, mask);
- return Blend(src, dst);
- }
- });
- function_apply_blend_mode = kFunctionApplyBlendMode;
- } else {
- static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() {
- vec4 ApplyBlendMode(vec4 src) {
- TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
- bgTexCoord *= backdropRect.zw;
- vec4 dst = texture2D(s_backdropTexture, bgTexCoord);
- return Blend(src, dst);
- }
- });
- function_apply_blend_mode = kFunctionApplyBlendMode;
- }
-
- std::string shader;
- shader.reserve(shader_string->size() + 1024);
- shader += "precision mediump float;";
- AppendHelperFunctions(&shader);
- AppendBlendFunction(&shader);
- base::StrAppend(&shader,
- {kUniforms, function_apply_blend_mode, *shader_string});
- *shader_string = std::move(shader);
-}
-
-void FragmentShader::AppendHelperFunctions(std::string* buffer) const {
- static constexpr base::StringPiece kFunctionHardLight = SHADER0([]() {
- vec3 hardLight(vec4 src, vec4 dst) {
- vec3 result;
- result.r =
- (2.0 * src.r <= src.a)
- ? (2.0 * src.r * dst.r)
- : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
- result.g =
- (2.0 * src.g <= src.a)
- ? (2.0 * src.g * dst.g)
- : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
- result.b =
- (2.0 * src.b <= src.a)
- ? (2.0 * src.b * dst.b)
- : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
- result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
- return result;
- }
- });
-
- static constexpr base::StringPiece kFunctionColorDodgeComponent =
- SHADER0([]() {
- float getColorDodgeComponent(float srcc, float srca, float dstc,
- float dsta) {
- if (0.0 == dstc)
- return srcc * (1.0 - dsta);
- float d = srca - srcc;
- if (0.0 == d)
- return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- d = min(dsta, dstc * srca / d);
- return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- }
- });
-
- static constexpr base::StringPiece kFunctionColorBurnComponent =
- SHADER0([]() {
- float getColorBurnComponent(float srcc, float srca, float dstc,
- float dsta) {
- if (dsta == dstc)
- return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- if (0.0 == srcc)
- return dstc * (1.0 - srca);
- float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
- return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
- }
- });
-
- static constexpr base::StringPiece kFunctionSoftLightComponentPosDstAlpha =
- SHADER0([]() {
- float getSoftLightComponent(float srcc, float srca, float dstc,
- float dsta) {
- if (2.0 * srcc <= srca) {
- return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
- (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
- } else if (4.0 * dstc <= dsta) {
- float DSqd = dstc * dstc;
- float DCub = DSqd * dstc;
- float DaSqd = dsta * dsta;
- float DaCub = DaSqd * dsta;
- return (-DaCub * srcc +
- DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
- 12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
- 16.0 * DCub * (srca - 2.0 * srcc)) /
- DaSqd;
- } else {
- return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
- dstc * (srca - 2.0 * srcc + 1.0) + srcc;
- }
- }
- });
-
- static constexpr base::StringPiece kFunctionLum = SHADER0([]() {
- float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
-
- vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
- float diff = luminance(lumColor - hueSat);
- vec3 outColor = hueSat + diff;
- float outLum = luminance(outColor);
- float minComp = min(min(outColor.r, outColor.g), outColor.b);
- float maxComp = max(max(outColor.r, outColor.g), outColor.b);
- if (minComp < 0.0 && outLum != minComp) {
- outColor =
- outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
- (outLum - minComp);
- }
- if (maxComp > alpha && maxComp != outLum) {
- outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) *
- (alpha - outLum)) /
- (maxComp - outLum);
- }
- return outColor;
- }
- });
-
- static constexpr base::StringPiece kFunctionSat = SHADER0([]() {
- float saturation(vec3 color) {
- return max(max(color.r, color.g), color.b) -
- min(min(color.r, color.g), color.b);
- }
-
- vec3 set_saturation_helper(float minComp, float midComp, float maxComp,
- float sat) {
- if (minComp < maxComp) {
- vec3 result;
- result.r = 0.0;
- result.g = sat * (midComp - minComp) / (maxComp - minComp);
- result.b = sat;
- return result;
- } else {
- return vec3(0, 0, 0);
- }
- }
-
- vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
- float sat = saturation(satColor);
- if (hueLumColor.r <= hueLumColor.g) {
- if (hueLumColor.g <= hueLumColor.b) {
- hueLumColor.rgb = set_saturation_helper(hueLumColor.r, hueLumColor.g,
- hueLumColor.b, sat);
- } else if (hueLumColor.r <= hueLumColor.b) {
- hueLumColor.rbg = set_saturation_helper(hueLumColor.r, hueLumColor.b,
- hueLumColor.g, sat);
- } else {
- hueLumColor.brg = set_saturation_helper(hueLumColor.b, hueLumColor.r,
- hueLumColor.g, sat);
- }
- } else if (hueLumColor.r <= hueLumColor.b) {
- hueLumColor.grb = set_saturation_helper(hueLumColor.g, hueLumColor.r,
- hueLumColor.b, sat);
- } else if (hueLumColor.g <= hueLumColor.b) {
- hueLumColor.gbr = set_saturation_helper(hueLumColor.g, hueLumColor.b,
- hueLumColor.r, sat);
- } else {
- hueLumColor.bgr = set_saturation_helper(hueLumColor.b, hueLumColor.g,
- hueLumColor.r, sat);
- }
- return hueLumColor;
- }
- });
-
- switch (blend_mode_) {
- case BLEND_MODE_OVERLAY:
- case BLEND_MODE_HARD_LIGHT:
- buffer->append(kFunctionHardLight.data(), kFunctionHardLight.size());
- return;
- case BLEND_MODE_COLOR_DODGE:
- buffer->append(kFunctionColorDodgeComponent.data(),
- kFunctionColorDodgeComponent.size());
- return;
- case BLEND_MODE_COLOR_BURN:
- buffer->append(kFunctionColorBurnComponent.data(),
- kFunctionColorBurnComponent.size());
- return;
- case BLEND_MODE_SOFT_LIGHT:
- buffer->append(kFunctionSoftLightComponentPosDstAlpha.data(),
- kFunctionSoftLightComponentPosDstAlpha.size());
- return;
- case BLEND_MODE_HUE:
- case BLEND_MODE_SATURATION:
- base::StrAppend(buffer, {kFunctionLum, kFunctionSat});
- return;
- case BLEND_MODE_COLOR:
- case BLEND_MODE_LUMINOSITY:
- buffer->append(kFunctionLum.data(), kFunctionLum.size());
- return;
- default:
- return;
- }
-}
-
-void FragmentShader::AppendBlendFunction(std::string* buffer) const {
- *buffer +=
- "vec4 Blend(vec4 src, vec4 dst) {"
- " vec4 result;";
- base::StrAppend(
- buffer, {GetBlendFunctionBodyForAlpha(), GetBlendFunctionBodyForRGB()});
- *buffer +=
- " return result;"
- "}";
-}
-
-base::StringPiece FragmentShader::GetBlendFunctionBodyForAlpha() const {
- if (blend_mode_ == BLEND_MODE_DESTINATION_IN)
- return "result.a = src.a * dst.a;";
- else
- return "result.a = src.a + (1.0 - src.a) * dst.a;";
-}
-
-base::StringPiece FragmentShader::GetBlendFunctionBodyForRGB() const {
- switch (blend_mode_) {
- case BLEND_MODE_NORMAL:
- return "result.rgb = src.rgb + dst.rgb * (1.0 - src.a);";
- case BLEND_MODE_DESTINATION_IN:
- return "result.rgb = dst.rgb * src.a;";
- case BLEND_MODE_SCREEN:
- return "result.rgb = src.rgb + (1.0 - src.rgb) * dst.rgb;";
- case BLEND_MODE_LIGHTEN:
- return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
- " (1.0 - dst.a) * src.rgb + dst.rgb);";
- case BLEND_MODE_OVERLAY:
- return "result.rgb = hardLight(dst, src);";
- case BLEND_MODE_DARKEN:
- return "result.rgb = min((1.0 - src.a) * dst.rgb + src.rgb,"
- " (1.0 - dst.a) * src.rgb + dst.rgb);";
- case BLEND_MODE_COLOR_DODGE:
- return "result.r = getColorDodgeComponent(src.r, src.a, dst.r, dst.a);"
- "result.g = getColorDodgeComponent(src.g, src.a, dst.g, dst.a);"
- "result.b = getColorDodgeComponent(src.b, src.a, dst.b, dst.a);";
- case BLEND_MODE_COLOR_BURN:
- return "result.r = getColorBurnComponent(src.r, src.a, dst.r, dst.a);"
- "result.g = getColorBurnComponent(src.g, src.a, dst.g, dst.a);"
- "result.b = getColorBurnComponent(src.b, src.a, dst.b, dst.a);";
- case BLEND_MODE_HARD_LIGHT:
- return "result.rgb = hardLight(src, dst);";
- case BLEND_MODE_SOFT_LIGHT:
- return "if (0.0 == dst.a) {"
- " result.rgb = src.rgb;"
- "} else {"
- " result.r = getSoftLightComponent(src.r, src.a, dst.r, dst.a);"
- " result.g = getSoftLightComponent(src.g, src.a, dst.g, dst.a);"
- " result.b = getSoftLightComponent(src.b, src.a, dst.b, dst.a);"
- "}";
- case BLEND_MODE_DIFFERENCE:
- return "result.rgb = src.rgb + dst.rgb -"
- " 2.0 * min(src.rgb * dst.a, dst.rgb * src.a);";
- case BLEND_MODE_EXCLUSION:
- return "result.rgb = dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb;";
- case BLEND_MODE_MULTIPLY:
- return "result.rgb = (1.0 - src.a) * dst.rgb +"
- " (1.0 - dst.a) * src.rgb + src.rgb * dst.rgb;";
- case BLEND_MODE_HUE:
- return "vec4 dstSrcAlpha = dst * src.a;"
- "result.rgb ="
- " set_luminance(set_saturation(src.rgb * dst.a,"
- " dstSrcAlpha.rgb),"
- " dstSrcAlpha.a,"
- " dstSrcAlpha.rgb);"
- "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BLEND_MODE_SATURATION:
- return "vec4 dstSrcAlpha = dst * src.a;"
- "result.rgb = set_luminance(set_saturation(dstSrcAlpha.rgb,"
- " src.rgb * dst.a),"
- " dstSrcAlpha.a,"
- " dstSrcAlpha.rgb);"
- "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BLEND_MODE_COLOR:
- return "vec4 srcDstAlpha = src * dst.a;"
- "result.rgb = set_luminance(srcDstAlpha.rgb,"
- " srcDstAlpha.a,"
- " dst.rgb * src.a);"
- "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BLEND_MODE_LUMINOSITY:
- return "vec4 srcDstAlpha = src * dst.a;"
- "result.rgb = set_luminance(dst.rgb * src.a,"
- " srcDstAlpha.a,"
- " srcDstAlpha.rgb);"
- "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BLEND_MODE_NONE:
- NOTREACHED();
- }
- return "result = vec4(1.0, 0.0, 0.0, 1.0);";
-}
-
-std::string FragmentShader::GetShaderSource() const {
- std::string header = "precision mediump float;\n";
- std::string source = "void main() {\n";
-
- // Read the input into vec4 texColor.
- switch (input_color_type_) {
- case INPUT_COLOR_SOURCE_RGBA_TEXTURE:
- if (ignore_sampler_type_)
- HDR("uniform sampler2D s_texture;");
- else
- HDR("uniform SamplerType s_texture;");
- HDR("varying TexCoordPrecision vec2 v_texCoord;");
- if (has_rgba_fragment_tex_transform_) {
- HDR("uniform TexCoordPrecision vec4 fragmentTexTransform;");
- SRC("// Transformed texture lookup");
- SRC("TexCoordPrecision vec2 texCoord =");
- SRC(" clamp(v_texCoord, 0.0, 1.0) * fragmentTexTransform.zw +");
- SRC(" fragmentTexTransform.xy;");
- SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
- DCHECK(!ignore_sampler_type_);
- DCHECK(!has_tex_clamp_rect_);
- } else {
- SRC("// Texture lookup");
- if (ignore_sampler_type_) {
- SRC("vec4 texColor = texture2D(s_texture, v_texCoord);");
- DCHECK(!has_tex_clamp_rect_);
- } else {
- SRC("TexCoordPrecision vec2 texCoord = v_texCoord;");
- if (has_tex_clamp_rect_) {
- HDR("uniform vec4 tex_clamp_rect;");
- SRC("texCoord = max(tex_clamp_rect.xy,");
- SRC(" min(tex_clamp_rect.zw, texCoord));");
- }
- SRC("vec4 texColor = TextureLookup(s_texture, texCoord);");
- }
- }
- break;
- case INPUT_COLOR_SOURCE_YUV_TEXTURES:
- DCHECK(!has_tex_clamp_rect_);
- // Compute the clamped texture coordinates for the YA and UV textures.
- HDR("uniform SamplerType y_texture;");
- SRC("// YUV texture lookup and conversion to RGB.");
- SRC("vec2 ya_clamped =");
- SRC(" max(ya_clamp_rect.xy, min(ya_clamp_rect.zw, v_yaTexCoord));");
- SRC("vec2 uv_clamped =");
- SRC(" max(uv_clamp_rect.xy, min(uv_clamp_rect.zw, v_uvTexCoord));");
- // Read the Y and UV or U and V textures into |yuv|.
- SRC("vec4 texColor;");
- SRC("texColor.w = 1.0;");
- SRC("texColor.x = TextureLookup(y_texture, ya_clamped).x;");
- if (uv_texture_mode_ == UV_TEXTURE_MODE_UV) {
- HDR("uniform SamplerType uv_texture;");
- SRC("texColor.yz = TextureLookup(uv_texture, uv_clamped).xy;");
- }
- if (uv_texture_mode_ == UV_TEXTURE_MODE_U_V) {
- HDR("uniform SamplerType u_texture;");
- HDR("uniform SamplerType v_texture;");
- SRC("texColor.y = TextureLookup(u_texture, uv_clamped).x;");
- SRC("texColor.z = TextureLookup(v_texture, uv_clamped).x;");
- }
- if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
- HDR("uniform SamplerType a_texture;");
- HDR("uniform vec4 ya_clamp_rect;");
- HDR("uniform vec4 uv_clamp_rect;");
- HDR("uniform float resource_multiplier;");
- HDR("uniform float resource_offset;");
- HDR("varying TexCoordPrecision vec2 v_yaTexCoord;");
- HDR("varying TexCoordPrecision vec2 v_uvTexCoord;");
- SRC("texColor.xyz -= vec3(resource_offset);");
- SRC("texColor.xyz *= resource_multiplier;");
- break;
- case INPUT_COLOR_SOURCE_UNIFORM:
- DCHECK(!ignore_sampler_type_);
- DCHECK(!has_rgba_fragment_tex_transform_);
- DCHECK(!has_tex_clamp_rect_);
- HDR("uniform vec4 color;");
- SRC("// Uniform color");
- SRC("vec4 texColor = color;");
- break;
- }
-
- // Apply color conversion.
- switch (color_conversion_mode_) {
- case COLOR_CONVERSION_MODE_SHADER:
- header += color_transform_->GetShaderSource();
- // Un-premultiply by alpha.
- if (premultiply_alpha_mode_ != NON_PREMULTIPLIED_ALPHA) {
- SRC("// un-premultiply alpha");
- SRC("if (texColor.a > 0.0) texColor.rgb /= texColor.a;");
- }
- SRC("texColor.rgb = DoColorConversion(texColor.xyz);");
- SRC("texColor.rgb *= texColor.a;");
- break;
- case COLOR_CONVERSION_MODE_NONE:
- // Premultiply by alpha.
- if (premultiply_alpha_mode_ == NON_PREMULTIPLIED_ALPHA) {
- SRC("// Premultiply alpha");
- SRC("texColor.rgb *= texColor.a;");
- }
- break;
- }
-
- // Apply the color matrix to texColor.
- if (has_color_matrix_) {
- HDR("uniform mat4 colorMatrix;");
- HDR("uniform vec4 colorOffset;");
- SRC("// Apply color matrix");
- SRC("float nonZeroAlpha = max(texColor.a, 0.00001);");
- SRC("texColor = vec4(texColor.rgb / nonZeroAlpha, nonZeroAlpha);");
- SRC("texColor = colorMatrix * texColor + colorOffset;");
- SRC("texColor.rgb *= texColor.a;");
- SRC("texColor = clamp(texColor, 0.0, 1.0);");
- }
-
- // Read the mask texture.
- if (mask_mode_ != NO_MASK) {
- HDR("uniform SamplerType s_mask;");
- HDR("uniform vec2 maskTexCoordScale;");
- HDR("uniform vec2 maskTexCoordOffset;");
- SRC("// Read the mask");
- SRC("TexCoordPrecision vec2 maskTexCoord =");
- SRC(" vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,");
- SRC(" maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);");
- SRC("vec4 maskColor = TextureLookup(s_mask, maskTexCoord);");
- }
-
- // Compute AA.
- if (aa_mode_ == USE_AA) {
- HDR("varying TexCoordPrecision vec4 edge_dist[2]; // 8 edge distances.");
- SRC("// Compute AA");
- SRC("vec4 d4 = min(edge_dist[0], edge_dist[1]);");
- SRC("vec2 d2 = min(d4.xz, d4.yw);");
- SRC("float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);");
- }
-
- // Apply background texture.
- if (has_background_color_) {
- HDR("uniform vec4 background_color;");
- SRC("// Apply uniform background color blending");
- SRC("texColor += background_color * (1.0 - texColor.a);");
- }
-
- // Finally apply the output color matrix to texColor.
- if (has_output_color_matrix_) {
- HDR("uniform mat4 output_color_matrix;");
- SRC("// Apply the output color matrix");
- SRC("texColor = output_color_matrix * texColor;");
- }
-
- // Tint the final color. Used for debugging composited content.
- if (has_tint_color_matrix_) {
- HDR("uniform mat4 tint_color_matrix;");
- SRC("// Apply the tint color matrix");
- SRC("texColor = tint_color_matrix * texColor;");
- }
-
- // Include header text for alpha.
- if (has_uniform_alpha_) {
- HDR("uniform float alpha;");
- }
- if (has_varying_alpha_) {
- HDR("varying float v_alpha;");
- }
-
- // Apply uniform alpha, aa, varying alpha, and the mask.
- if (has_varying_alpha_ || aa_mode_ == USE_AA || has_uniform_alpha_ ||
- mask_mode_ != NO_MASK) {
- SRC("// Apply alpha from uniform, varying, aa, and mask.");
- std::string line = " texColor = texColor";
- if (has_varying_alpha_)
- line += " * v_alpha";
- if (has_uniform_alpha_)
- line += " * alpha";
- if (aa_mode_ == USE_AA)
- line += " * aa";
- if (mask_mode_ != NO_MASK)
- line += " * maskColor.a";
- if (yuv_alpha_texture_mode_ == YUV_HAS_ALPHA_TEXTURE)
- line += " * TextureLookup(a_texture, ya_clamped).x";
- line += ";\n";
- source += line;
- }
-
- // Write the fragment color.
- SRC("// Write the fragment color");
- switch (frag_color_mode_) {
- case FRAG_COLOR_MODE_DEFAULT:
- DCHECK_EQ(blend_mode_, BLEND_MODE_NONE);
- SRC("gl_FragColor = texColor;");
- break;
- case FRAG_COLOR_MODE_OPAQUE:
- DCHECK_EQ(blend_mode_, BLEND_MODE_NONE);
- SRC("gl_FragColor = vec4(texColor.rgb, 1.0);");
- break;
- case FRAG_COLOR_MODE_APPLY_BLEND_MODE:
- if (!has_blend_mode()) {
- SRC("gl_FragColor = texColor;");
- } else if (mask_mode_ != NO_MASK) {
- if (mask_for_background_)
- SRC("gl_FragColor = ApplyBlendMode(texColor, maskColor.w);");
- else
- SRC("gl_FragColor = ApplyBlendMode(texColor);");
- } else {
- SRC("gl_FragColor = ApplyBlendMode(texColor);");
- }
- break;
- }
-
- if (has_rounded_corner_)
- SRC("gl_FragColor = ApplyRoundedCorner(gl_FragColor);");
-
- source += "}\n";
-
- return header + source;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/shader.h b/chromium/components/viz/service/display/shader.h
deleted file mode 100644
index 41d6a000d66..00000000000
--- a/chromium/components/viz/service/display/shader.h
+++ /dev/null
@@ -1,324 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SHADER_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_SHADER_H_
-
-#include <string>
-
-#include "base/memory/raw_ptr.h"
-#include "base/strings/string_piece.h"
-#include "components/viz/service/viz_service_export.h"
-
-namespace gfx {
-class ColorTransform;
-class Point;
-class Size;
-} // namespace gfx
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-} // namespace gpu
-
-namespace viz {
-
-enum TexCoordPrecision {
- TEX_COORD_PRECISION_NA = 0,
- TEX_COORD_PRECISION_MEDIUM = 1,
- TEX_COORD_PRECISION_HIGH = 2,
-};
-
-// Texture coordinate sources for the vertex shader.
-enum TexCoordSource {
- // Vertex shader does not populate a texture coordinate.
- TEX_COORD_SOURCE_NONE,
- // Texture coordinate is set to the untransformed position.
- TEX_COORD_SOURCE_POSITION,
- // Texture coordinate has its own attribute.
- TEX_COORD_SOURCE_ATTRIBUTE,
-};
-
-// Texture coordinate transformation modes for the vertex shader.
-enum TexCoordTransform {
- // Texture coordinates are not transformed.
- TEX_COORD_TRANSFORM_NONE,
- // Texture coordinates are transformed by a uniform vec4, scaling by zw and
- // then translating by xy.
- TEX_COORD_TRANSFORM_VEC4,
- // Same as the above, but add vec2(0.5) to the texture coordinate first.
- TEX_COORD_TRANSFORM_TRANSLATED_VEC4,
- // Texture coordiantes are transformed by a uniform mat4.
- TEX_COORD_TRANSFORM_MATRIX,
-};
-
-// Position source for the vertex shader.
-enum PositionSource {
- // The position is read directly from the position attribute.
- POSITION_SOURCE_ATTRIBUTE,
- // The position is read by attribute index into a uniform array for xy, and
- // getting zw from the attribute.
- POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM,
-};
-
-enum AAMode {
- NO_AA = 0,
- USE_AA = 1,
-};
-
-enum PremultipliedAlphaMode {
- PREMULTIPLIED_ALPHA = 0,
- NON_PREMULTIPLIED_ALPHA = 1,
-};
-
-enum SamplerType {
- SAMPLER_TYPE_NA = 0,
- SAMPLER_TYPE_2D = 1,
- SAMPLER_TYPE_2D_RECT = 2,
- SAMPLER_TYPE_EXTERNAL_OES = 3,
-};
-
-enum BlendMode {
- BLEND_MODE_NONE,
- BLEND_MODE_NORMAL,
- BLEND_MODE_DESTINATION_IN,
- BLEND_MODE_SCREEN,
- BLEND_MODE_OVERLAY,
- BLEND_MODE_DARKEN,
- BLEND_MODE_LIGHTEN,
- BLEND_MODE_COLOR_DODGE,
- BLEND_MODE_COLOR_BURN,
- BLEND_MODE_HARD_LIGHT,
- BLEND_MODE_SOFT_LIGHT,
- BLEND_MODE_DIFFERENCE,
- BLEND_MODE_EXCLUSION,
- BLEND_MODE_MULTIPLY,
- BLEND_MODE_HUE,
- BLEND_MODE_SATURATION,
- BLEND_MODE_COLOR,
- BLEND_MODE_LUMINOSITY,
- LAST_BLEND_MODE = BLEND_MODE_LUMINOSITY
-};
-
-enum InputColorSource {
- // This includes RGB and RGBA textures.
- INPUT_COLOR_SOURCE_RGBA_TEXTURE,
- // This includes Y and either UV or U-and-V textures.
- INPUT_COLOR_SOURCE_YUV_TEXTURES,
- // A solid color specified as a uniform value.
- INPUT_COLOR_SOURCE_UNIFORM,
-};
-
-enum UVTextureMode {
- // Shader does not use YUV textures.
- UV_TEXTURE_MODE_NA,
- // UV plane is a single texture.
- UV_TEXTURE_MODE_UV,
- // U and V planes have separate textures.
- UV_TEXTURE_MODE_U_V,
-};
-
-enum YUVAlphaTextureMode {
- YUV_ALPHA_TEXTURE_MODE_NA,
- YUV_NO_ALPHA_TEXTURE,
- YUV_HAS_ALPHA_TEXTURE,
-};
-
-enum ColorConversionMode {
- // No color conversion is performed.
- COLOR_CONVERSION_MODE_NONE,
- // Conversion is done analytically in the shader.
- COLOR_CONVERSION_MODE_SHADER,
-};
-
-// TODO(ccameron): Merge this with BlendMode.
-enum FragColorMode {
- FRAG_COLOR_MODE_DEFAULT,
- FRAG_COLOR_MODE_OPAQUE,
- FRAG_COLOR_MODE_APPLY_BLEND_MODE,
-};
-
-enum MaskMode {
- NO_MASK = 0,
- HAS_MASK = 1,
-};
-
-// Note: The highp_threshold_cache must be provided by the caller to make
-// the caching multi-thread/context safe in an easy low-overhead manner.
-// The caller must make sure to clear highp_threshold_cache to 0, so it can be
-// reinitialized, if a new or different context is used.
-VIZ_SERVICE_EXPORT TexCoordPrecision
-TexCoordPrecisionRequired(gpu::gles2::GLES2Interface* context,
- int* highp_threshold_cache,
- int highp_threshold_min,
- const gfx::Point& max_coordinate);
-
-VIZ_SERVICE_EXPORT TexCoordPrecision
-TexCoordPrecisionRequired(gpu::gles2::GLES2Interface* context,
- int* highp_threshold_cache,
- int highp_threshold_min,
- const gfx::Size& max_size);
-
-class VIZ_SERVICE_EXPORT VertexShader {
- public:
- VertexShader();
- void Init(gpu::gles2::GLES2Interface* context,
- unsigned program,
- int* base_uniform_index);
- std::string GetShaderString() const;
-
- protected:
- friend class Program;
-
- // Use arrays of uniforms for matrix, texTransform, and opacity.
- bool use_uniform_arrays_ = false;
-
- PositionSource position_source_ = POSITION_SOURCE_ATTRIBUTE;
- TexCoordSource tex_coord_source_ = TEX_COORD_SOURCE_NONE;
- TexCoordTransform tex_coord_transform_ = TEX_COORD_TRANSFORM_NONE;
-
- // Used only with TEX_COORD_TRANSFORM_VEC4.
- int vertex_tex_transform_location_ = -1;
-
- // Used only with TEX_COORD_TRANSFORM_MATRIX.
- int tex_matrix_location_ = -1;
-
- // Uniforms for YUV textures.
- bool is_ya_uv_ = false;
- int ya_tex_scale_location_ = -1;
- int ya_tex_offset_location_ = -1;
- int uv_tex_scale_location_ = -1;
- int uv_tex_offset_location_ = -1;
-
- // Matrix to transform the position.
- int matrix_location_ = -1;
-
- // Used only with POSITION_SOURCE_ATTRIBUTE_INDEXED_UNIFORM.
- int quad_location_ = -1;
-
- // Extra dummy variables to work around bugs on Android.
- // TODO(ccameron): This is likley unneeded cargo-culting.
- // http://crbug.com/240602
- bool has_dummy_variables_ = false;
-
- bool has_vertex_opacity_ = false;
- int vertex_opacity_location_ = -1;
-
- AAMode aa_mode_ = NO_AA;
- int viewport_location_ = -1;
- int edge_location_ = -1;
-};
-
-class VIZ_SERVICE_EXPORT FragmentShader {
- public:
- FragmentShader(const FragmentShader&) = delete;
- FragmentShader& operator=(const FragmentShader&) = delete;
-
- virtual void Init(gpu::gles2::GLES2Interface* context,
- unsigned program,
- int* base_uniform_index);
- std::string GetShaderString() const;
-
- protected:
- FragmentShader();
- virtual std::string GetShaderSource() const;
- bool has_blend_mode() const { return blend_mode_ != BLEND_MODE_NONE; }
-
- void SetBlendModeFunctions(std::string* shader_string) const;
- void SetRoundedCornerFunctions(std::string* shader_string) const;
-
- // Settings that are modified by sub-classes.
- AAMode aa_mode_ = NO_AA;
- bool has_varying_alpha_ = false;
- PremultipliedAlphaMode premultiply_alpha_mode_ = PREMULTIPLIED_ALPHA;
- FragColorMode frag_color_mode_ = FRAG_COLOR_MODE_DEFAULT;
- InputColorSource input_color_type_ = INPUT_COLOR_SOURCE_RGBA_TEXTURE;
-
- // Used only if |blend_mode_| is not BLEND_MODE_NONE.
- int backdrop_location_ = -1;
- int original_backdrop_location_ = -1;
- int backdrop_rect_location_ = -1;
-
- // Used only if |input_color_type_| is INPUT_COLOR_SOURCE_RGBA_TEXTURE.
- bool has_rgba_fragment_tex_transform_ = false;
- int sampler_location_ = -1;
- int fragment_tex_transform_location_ = -1;
-
- // Always use sampler2D and texture2D for the RGBA texture, regardless of the
- // specified SamplerType.
- // TODO(ccameron): Change GLRenderer to always specify the correct
- // SamplerType.
- bool ignore_sampler_type_ = false;
-
- // Used only if |input_color_type_| is INPUT_COLOR_SOURCE_UNIFORM.
- int color_location_ = -1;
-
- MaskMode mask_mode_ = NO_MASK;
- int mask_sampler_location_ = -1;
- int mask_tex_coord_scale_location_ = -1;
- int mask_tex_coord_offset_location_ = -1;
-
- bool has_color_matrix_ = false;
- int color_matrix_location_ = -1;
- int color_offset_location_ = -1;
-
- bool has_uniform_alpha_ = false;
- int alpha_location_ = -1;
-
- bool has_background_color_ = false;
- int background_color_location_ = -1;
-
- bool has_tex_clamp_rect_ = false;
- int tex_clamp_rect_location_ = -1;
-
- TexCoordPrecision tex_coord_precision_ = TEX_COORD_PRECISION_NA;
- SamplerType sampler_type_ = SAMPLER_TYPE_NA;
-
- BlendMode blend_mode_ = BLEND_MODE_NONE;
- bool mask_for_background_ = false;
-
- // YUV-only parameters.
- YUVAlphaTextureMode yuv_alpha_texture_mode_ = YUV_ALPHA_TEXTURE_MODE_NA;
- UVTextureMode uv_texture_mode_ = UV_TEXTURE_MODE_UV;
-
- ColorConversionMode color_conversion_mode_ = COLOR_CONVERSION_MODE_NONE;
- raw_ptr<const gfx::ColorTransform> color_transform_ = nullptr;
-
- bool has_output_color_matrix_ = false;
- int output_color_matrix_location_ = -1;
-
- bool has_tint_color_matrix_ = false;
- int tint_color_matrix_location_ = -1;
-
- // YUV uniform locations.
- int y_texture_location_ = -1;
- int u_texture_location_ = -1;
- int v_texture_location_ = -1;
- int uv_texture_location_ = -1;
- int a_texture_location_ = -1;
- int ya_clamp_rect_location_ = -1;
- int uv_clamp_rect_location_ = -1;
-
- // Rounded corner locations
- bool has_rounded_corner_ = false;
- int rounded_corner_rect_location_ = -1;
- int rounded_corner_radius_location_ = -1;
-
- // The resource offset and multiplier to adjust for bit depth.
- int resource_multiplier_location_ = -1;
- int resource_offset_location_ = -1;
-
- private:
- friend class Program;
-
- void AppendHelperFunctions(std::string* buffer) const;
- void AppendBlendFunction(std::string* buffer) const;
- base::StringPiece GetBlendFunctionBodyForAlpha() const;
- base::StringPiece GetBlendFunctionBodyForRGB() const;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SHADER_H_
diff --git a/chromium/components/viz/service/display/shader_unittest.cc b/chromium/components/viz/service/display/shader_unittest.cc
deleted file mode 100644
index 6990cbf14de..00000000000
--- a/chromium/components/viz/service/display/shader_unittest.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/shader.h"
-
-#include "components/viz/test/test_context_provider.h"
-#include "components/viz/test/test_gles2_interface.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace viz {
-
-TEST(ShaderTest, HighpThresholds) {
- // The test gl always uses a mediump precision of 10 bits which
- // corresponds to a native highp threshold of 2^10 = 1024
- scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
- provider->BindToCurrentThread();
- gpu::gles2::GLES2Interface* test_gl = provider->ContextGL();
-
- int threshold_cache = 0;
- int threshold_min;
- gfx::Point closePoint(512, 512);
- gfx::Size smallSize(512, 512);
- gfx::Point farPoint(2560, 2560);
- gfx::Size bigSize(2560, 2560);
-
- threshold_min = 0;
- EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- closePoint));
- EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- smallSize));
- EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- farPoint));
- EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- bigSize));
-
- threshold_min = 3000;
- EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- closePoint));
- EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- smallSize));
- EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- farPoint));
- EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
- bigSize));
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/skia_output_surface.h b/chromium/components/viz/service/display/skia_output_surface.h
index 635a9e0a6b3..a6557e31d0c 100644
--- a/chromium/components/viz/service/display/skia_output_surface.h
+++ b/chromium/components/viz/service/display/skia_output_surface.h
@@ -17,6 +17,7 @@
#include "components/viz/service/display/overlay_processor_interface.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
+#include "ui/gfx/gpu_fence_handle.h"
#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display/dc_layer_overlay.h"
@@ -29,14 +30,14 @@
class SkCanvas;
class SkImage;
-#if BUILDFLAG(IS_APPLE)
-class SkDeferredDisplayList;
-#endif
-
namespace gfx {
class ColorSpace;
} // namespace gfx
+namespace gpu {
+class SharedImageInterface;
+}
+
namespace viz {
class OverlayCandidate;
@@ -121,6 +122,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space,
+ bool is_overlay,
const gpu::Mailbox& mailbox) = 0;
// Finish painting the current frame or current render pass, depends on which
@@ -128,8 +130,13 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
// play the DDL back on GPU thread on a cached SkSurface.
// Optionally the caller may specify |on_finished| callback to be called after
// the GPU has finished processing all submitted commands. The callback may be
- // called on a different thread.
- virtual void EndPaint(base::OnceClosure on_finished) = 0;
+ // called on a different thread. The caller may also specify
+ // |return_release_fence_cb| callback to be called after all commands are
+ // submitted. The callback will return the release fence which will be
+ // signaled once the submitted commands are processed.
+ virtual void EndPaint(base::OnceClosure on_finished,
+ base::OnceCallback<void(gfx::GpuFenceHandle)>
+ return_release_fence_cb) = 0;
// Make a promise SkImage from a render pass id. The render pass has been
// painted with BeginPaintRenderPass and FinishPaintRenderPass. The format
@@ -162,8 +169,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
// the GPU has finished processing all submitted commands. The callback may be
// called on a different thread.
virtual void ScheduleOverlays(OverlayList overlays,
- std::vector<gpu::SyncToken> sync_tokens,
- base::OnceClosure on_finished) = 0;
+ std::vector<gpu::SyncToken> sync_tokens) = 0;
// Add context lost observer.
virtual void AddContextLostObserver(ContextLostObserver* observer) = 0;
@@ -194,15 +200,6 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
// 0 < n <= capabilities_.number_of_buffers.
// Return true if new buffers are allocated.
virtual bool EnsureMinNumberOfBuffers(int n) = 0;
-
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- virtual SkCanvas* BeginPaintRenderPassOverlay(
- const gfx::Size& size,
- ResourceFormat format,
- bool mipmap,
- sk_sp<SkColorSpace> color_space) = 0;
- virtual sk_sp<SkDeferredDisplayList> EndPaintRenderPassOverlay() = 0;
-#endif
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/skia_readback_pixeltest.cc b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
index c3bffea471f..db740b2c878 100644
--- a/chromium/components/viz/service/display/skia_readback_pixeltest.cc
+++ b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
@@ -17,9 +17,11 @@
#include "cc/test/pixel_test.h"
#include "cc/test/pixel_test_utils.h"
#include "cc/test/resource_provider_test_utils.h"
+#include "components/viz/common/frame_sinks/blit_request.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/frame_sinks/copy_output_util.h"
+#include "components/viz/common/gpu/context_provider.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "components/viz/test/gl_scaler_test_util.h"
@@ -572,7 +574,8 @@ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SkiaReadbackPixelTestNV12);
class SkiaReadbackPixelTestNV12WithBlit
: public SkiaReadbackPixelTest,
- public testing::WithParamInterface<bool> {
+ public testing::WithParamInterface<
+ std::tuple<bool, LetterboxingBehavior, bool>> {
public:
CopyOutputResult::Destination RequestDestination() const {
return CopyOutputResult::Destination::kNativeTextures;
@@ -583,8 +586,17 @@ class SkiaReadbackPixelTestNV12WithBlit
}
void SetUp() override {
- SkiaReadbackPixelTest::SetUpReadbackPixeltest(GetParam());
+ SkiaReadbackPixelTest::SetUpReadbackPixeltest(std::get<0>(GetParam()));
+ }
+
+ LetterboxingBehavior GetLetterboxingBehavior() const {
+ return std::get<1>(GetParam());
}
+
+ // Test parameter that will return `true` if we'll claim that the textures we
+ // create come from GpuMemoryBuffer, `false` otherwise. This exercises a
+ // different code path in SkiaRenderer.
+ bool populates_gpu_memory_buffer() const { return std::get<2>(GetParam()); }
};
// Test that SkiaRenderer readback works correctly. This test will use the
@@ -625,8 +637,7 @@ TEST_P(SkiaReadbackPixelTestNV12WithBlit, ExecutesCopyRequestWithBlit) {
<< " The test case expects the blit region's origin to be even for NV12 "
"blit requests";
- const SkColor rgba_red = SkColorSetARGB(0xff, 0xff, 0, 0);
- const SkColor yuv_red = GLScalerTestUtil::ConvertRGBAColorToYUV(rgba_red);
+ const SkColor yuv_red = GLScalerTestUtil::ConvertRGBAColorToYUV(SK_ColorRED);
const std::vector<uint8_t> luma_pattern = {
static_cast<uint8_t>(SkColorGetR(yuv_red))};
@@ -669,8 +680,9 @@ TEST_P(SkiaReadbackPixelTestNV12WithBlit, ExecutesCopyRequestWithBlit) {
request.set_result_selection(result_selection);
- request.set_blit_request(
- BlitRequest(destination_subregion.origin(), mailboxes));
+ request.set_blit_request(BlitRequest(
+ destination_subregion.origin(), GetLetterboxingBehavior(),
+ mailboxes, populates_gpu_memory_buffer()));
}));
// Check that a result was produced and is of the expected rect/size.
@@ -716,7 +728,18 @@ TEST_P(SkiaReadbackPixelTestNV12WithBlit, ExecutesCopyRequestWithBlit) {
// The textures that we passed in to BlitRequest contained NV12 plane data for
// an all-red image, let's re-create such a bitmap:
SkBitmap expected = GLScalerTestUtil::AllocateRGBABitmap(source_size);
- expected.eraseColor(rgba_red);
+
+ if (GetLetterboxingBehavior() == LetterboxingBehavior::kLetterbox) {
+ // We have requested the results to be letterboxed, so everything that
+ // CopyOutputRequest is not populating w/ render pass contents should be
+ // black:
+ expected.eraseColor(SK_ColorBLACK);
+ } else {
+ // We have requested the results to not be letterboxed, so everything that
+ // CopyOutputRequest is not populating w/ render pass will have original
+ // contents (red in our case):
+ expected.eraseColor(SK_ColorRED);
+ }
// Blit request should "stitch" the pixels from the source image into a
// sub-region of caller-provided texture - let's write our expected pixels
@@ -732,10 +755,15 @@ TEST_P(SkiaReadbackPixelTestNV12WithBlit, ExecutesCopyRequestWithBlit) {
}
#if !BUILDFLAG(IS_ANDROID) || !defined(ARCH_CPU_X86_FAMILY)
-INSTANTIATE_TEST_SUITE_P(,
- SkiaReadbackPixelTestNV12WithBlit,
- // Result scaling: Scale by half?
- testing::Values(true, false));
+INSTANTIATE_TEST_SUITE_P(
+ ,
+ SkiaReadbackPixelTestNV12WithBlit,
+ testing::Combine(
+ testing::Bool(), // Result scaling: Scale by half?
+ testing::Values(LetterboxingBehavior::kDoNotLetterbox,
+ LetterboxingBehavior::kLetterbox),
+ testing::Bool() // Should behave as if COR is populating a GMB?
+ ));
#else
// Don't instantiate the NV12 tests when run on Android emulator, they won't
// work since the SkiaRenderer currently does not support CopyOutputRequests
diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc
index 5a6eb5feb46..1b0a7116b73 100644
--- a/chromium/components/viz/service/display/skia_renderer.cc
+++ b/chromium/components/viz/service/display/skia_renderer.cc
@@ -45,7 +45,6 @@
#include "components/viz/service/display/renderer_utils.h"
#include "components/viz/service/display/resource_fence.h"
#include "components/viz/service/display/skia_output_surface.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"
@@ -575,8 +574,7 @@ class SkiaRenderer::ScopedSkImageBuilder {
bool maybe_concurrent_reads,
SkAlphaType alpha_type = kPremul_SkAlphaType,
GrSurfaceOrigin origin = kTopLeft_GrSurfaceOrigin,
- const absl::optional<gfx::ColorSpace>&
- override_colorspace = absl::nullopt,
+ sk_sp<SkColorSpace> override_color_space = nullptr,
bool raw_draw_if_possible = false);
ScopedSkImageBuilder(const ScopedSkImageBuilder&) = delete;
@@ -586,12 +584,12 @@ class SkiaRenderer::ScopedSkImageBuilder {
const SkImage* sk_image() const { return sk_image_; }
const cc::PaintOpBuffer* paint_op_buffer() const { return paint_op_buffer_; }
- const absl::optional<SkColor>& clear_color() const { return clear_color_; }
+ const absl::optional<SkColor4f>& clear_color() const { return clear_color_; }
private:
raw_ptr<const SkImage> sk_image_ = nullptr;
raw_ptr<const cc::PaintOpBuffer> paint_op_buffer_ = nullptr;
- absl::optional<SkColor> clear_color_;
+ absl::optional<SkColor4f> clear_color_;
};
SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder(
@@ -600,7 +598,7 @@ SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder(
bool maybe_concurrent_reads,
SkAlphaType alpha_type,
GrSurfaceOrigin origin,
- const absl::optional<gfx::ColorSpace>& override_color_space,
+ sk_sp<SkColorSpace> override_color_space,
bool raw_draw_if_possible) {
if (!resource_id)
return;
@@ -702,22 +700,30 @@ class SkiaRenderer::ScopedYUVSkImageBuilder {
sk_sp<SkImage> sk_image_;
};
-class SkiaRenderer::FrameResourceFence : public ResourceFence {
+// A read lock based fence that is signaled after gpu commands are completed
+// meaning the resource has been read.
+class SkiaRenderer::FrameResourceGpuCommandsCompletedFence
+ : public ResourceFence {
public:
- FrameResourceFence() = default;
-
- FrameResourceFence(const FrameResourceFence&) = delete;
- FrameResourceFence& operator=(const FrameResourceFence&) = delete;
+ FrameResourceGpuCommandsCompletedFence() = default;
+ FrameResourceGpuCommandsCompletedFence(
+ const FrameResourceGpuCommandsCompletedFence&) = delete;
+ FrameResourceGpuCommandsCompletedFence& operator=(
+ const FrameResourceGpuCommandsCompletedFence&) = delete;
// ResourceFence implementation.
void Set() override { set_ = true; }
bool HasPassed() override { return event_.IsSignaled(); }
+ gfx::GpuFenceHandle GetGpuFenceHandle() override {
+ NOTREACHED();
+ return gfx::GpuFenceHandle();
+ }
bool WasSet() { return set_; }
void Signal() { event_.Signal(); }
private:
- ~FrameResourceFence() override = default;
+ ~FrameResourceGpuCommandsCompletedFence() override = default;
// Accessed only from compositor thread.
bool set_ = false;
@@ -725,6 +731,41 @@ class SkiaRenderer::FrameResourceFence : public ResourceFence {
base::WaitableEvent event_;
};
+// FrameResourceFence that gets a ReleaseFence which is later set to returned
+// resources.
+class SkiaRenderer::FrameResourceReleaseFence : public ResourceFence {
+ public:
+ FrameResourceReleaseFence() = default;
+ FrameResourceReleaseFence(const FrameResourceReleaseFence&) = delete;
+ FrameResourceReleaseFence& operator=(const FrameResourceReleaseFence&) =
+ delete;
+
+ // ResourceFence implementation:
+ void Set() override { set_ = true; }
+ // If the fence handle has been set, |this| has passed aka the callback has
+ // been called.
+ bool HasPassed() override { return release_fence_.has_value(); }
+ gfx::GpuFenceHandle GetGpuFenceHandle() override {
+ return HasPassed() ? release_fence_.value().Clone() : gfx::GpuFenceHandle();
+ }
+
+ bool WasSet() { return set_; }
+ void SetReleaseFenceCallback(gfx::GpuFenceHandle release_fence) {
+ release_fence_ = std::move(release_fence);
+ }
+
+ private:
+ ~FrameResourceReleaseFence() override = default;
+
+ // Accessed only from compositor thread.
+ bool set_ = false;
+
+ // This is made optional so that the value is set after
+ // SetReleaseFenceCallback is called. Otherwise, there is no way to know if
+ // the fence has been set and a null handle is a "valid" handle.
+ absl::optional<gfx::GpuFenceHandle> release_fence_;
+};
+
SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
const DebugRendererSettings* debug_settings,
OutputSurface* output_surface,
@@ -741,9 +782,17 @@ SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
DCHECK(skia_output_surface_);
lock_set_for_external_use_.emplace(resource_provider, skia_output_surface_);
- current_frame_resource_fence_ = base::MakeRefCounted<FrameResourceFence>();
- this->resource_provider()->SetReadLockFence(
- current_frame_resource_fence_.get());
+ // There can be different synchronization types requested for different
+ // resources. Some of them may require SyncToken, others - ReadLockFence, and
+ // others may need ReleaseFence. SyncTokens are set when the output surface
+ // is flushed and external resources are released. However, other resources
+ // require additional setup, which helps to handle that.
+ current_gpu_commands_completed_fence_ =
+ base::MakeRefCounted<FrameResourceGpuCommandsCompletedFence>();
+ current_release_fence_ = base::MakeRefCounted<FrameResourceReleaseFence>();
+ this->resource_provider()->SetGpuCommandsCompletedFence(
+ current_gpu_commands_completed_fence_.get());
+ this->resource_provider()->SetReleaseFence(current_release_fence_.get());
#if OS_ANDROID
use_real_color_space_for_stream_video_ =
@@ -760,7 +809,8 @@ bool SkiaRenderer::CanPartialSwap() {
void SkiaRenderer::BeginDrawingFrame() {
TRACE_EVENT0("viz", "SkiaRenderer::BeginDrawingFrame");
- DCHECK(!current_frame_resource_fence_->WasSet());
+ DCHECK(!current_gpu_commands_completed_fence_->WasSet());
+ DCHECK(!current_release_fence_->WasSet());
}
void SkiaRenderer::FinishDrawingFrame() {
@@ -808,6 +858,16 @@ void SkiaRenderer::SwapBuffers(SwapFrameData swap_frame_data) {
swap_buffer_rect_ = gfx::Rect();
FlushOutputSurface();
+
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+ // Delete render pass overlay backings from the previous frame that will not
+ // be used again.
+ for (auto& backing : available_render_pass_overlay_backings_) {
+ skia_output_surface_->GetSharedImageInterface()->DestroySharedImage(
+ gpu::SyncToken(), backing.mailbox);
+ }
+ available_render_pass_overlay_backings_.clear();
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
}
void SkiaRenderer::SwapBuffersSkipped() {
@@ -828,13 +888,13 @@ void SkiaRenderer::SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {
auto read_fence_lock_iter = committed_overlay_locks_.end();
if (!release_fence.is_null()) {
- // Set release fences for returning for last frame overlay resources.
+ // Set release fences to return overlay resources for last frame.
for (auto& lock : committed_overlay_locks_) {
lock.SetReleaseFence(release_fence.Clone());
}
- // Find all locks that have a read-lock fence associated with them.
- // If we have a release fence, it's not safe to release them here.
- // Release them later in BuffersPresented.
+ // Find all locks that have a read-lock fence associated with them and move
+ // them to the back of locks. If we have a release fence, it's not safe to
+ // release them here. Release them later in BuffersPresented().
read_fence_lock_iter = std::partition(
committed_overlay_locks_.begin(), committed_overlay_locks_.end(),
[](auto& lock) { return !lock.HasReadLockFence(); });
@@ -846,7 +906,7 @@ void SkiaRenderer::SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {
// Right now, only macOS and Ozone need to return mailboxes of released
// overlays, so we should not release |committed_overlay_locks_| here. The
- // resources in it will be released by DidReceiveReleasedOverlays() later.
+ // resources in it will be released in DidReceiveReleasedOverlays() later.
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
for (auto lock_iter = committed_overlay_locks_.begin();
lock_iter != read_fence_lock_iter; ++lock_iter) {
@@ -854,6 +914,8 @@ void SkiaRenderer::SwapBuffersComplete(gfx::GpuFenceHandle release_fence) {
}
#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+ // Current pending locks should have been committed by the next time
+ // SwapBuffers() is completed.
committed_overlay_locks_.clear();
std::swap(committed_overlay_locks_, pending_overlay_locks_.front());
pending_overlay_locks_.pop_front();
@@ -869,19 +931,38 @@ void SkiaRenderer::DidReceiveReleasedOverlays(
// This method is only called on macOS and Ozone right now.
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
for (const auto& mailbox : released_overlays) {
- auto it = awaiting_release_overlay_locks_.find(mailbox);
- if (it == awaiting_release_overlay_locks_.end()) {
- // TODO(crbug.com/1299794): Re-enable this DCHECK on Ozone.
+ // If this mailbox is for render pass overlay, mark the released render pass
+ // overlay backing as available to be re-used.
+ auto backing_iter =
+ std::find_if(in_flight_render_pass_overlay_backings_.begin(),
+ in_flight_render_pass_overlay_backings_.end(),
+ [&mailbox](const RenderPassBacking& backing) {
+ return backing.mailbox == mailbox;
+ });
+ if (backing_iter != in_flight_render_pass_overlay_backings_.end()) {
+ available_render_pass_overlay_backings_.push_back(
+ std::move(*backing_iter));
+ in_flight_render_pass_overlay_backings_.erase(backing_iter);
+ }
+
+ auto iter = std::find_if(awaiting_release_overlay_locks_.begin(),
+ awaiting_release_overlay_locks_.end(),
+ [&mailbox](const OverlayLock& lock) {
+ return lock.mailbox() == mailbox;
+ });
+ if (iter == awaiting_release_overlay_locks_.end()) {
+// TODO(crbug.com/1299794): Re-enable this DCHECK on Ozone.
#if !defined(USE_OZONE)
+ // The released overlay should always be found as awaiting to be released.
DLOG(FATAL) << "Got an unexpected mailbox";
#endif // !defined(USE_OZONE)
continue;
}
- awaiting_release_overlay_locks_.erase(it);
+ awaiting_release_overlay_locks_.erase(iter);
}
#else
NOTREACHED();
-#endif // !(BUILDFLAG(IS_APPLE) || defined (USE_OZONE))
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
}
bool SkiaRenderer::FlippedFramebuffer() const {
@@ -899,8 +980,6 @@ void SkiaRenderer::EnsureScissorTestDisabled() {
}
void SkiaRenderer::BindFramebufferToOutputSurface() {
- DCHECK(!output_surface_->HasExternalStencilTest());
-
root_canvas_ = skia_output_surface_->BeginPaintCurrentFrame();
current_canvas_ = root_canvas_;
current_surface_ = root_surface_.get();
@@ -915,7 +994,8 @@ void SkiaRenderer::BindFramebufferToTexture(
RenderPassBacking& backing = iter->second;
current_canvas_ = skia_output_surface_->BeginPaintRenderPass(
render_pass_id, backing.size, backing.format, backing.generate_mipmap,
- backing.color_space.ToSkColorSpace(), backing.mailbox);
+ RenderPassBackingSkColorSpace(backing), /*is_overlay=*/false,
+ backing.mailbox);
}
void SkiaRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
@@ -941,9 +1021,13 @@ void SkiaRenderer::ClearFramebuffer() {
if (current_frame()->current_render_pass->has_transparent_background) {
ClearCanvas(SkColorSetARGB(0, 0, 0, 0));
} else {
-#if DCHECK_IS_ON()
+#if DCHECK_IS_ON() && !BUILDFLAG(IS_LINUX)
// On DEBUG builds, opaque render passes are cleared to blue
// to easily see regions that were not drawn on the screen.
+ // ClearCavas() call causes slight pixel difference, so linux-ref and
+ // linux-blink-ref bots cannot share the same baseline for webtest.
+ // So remove this ClearCanvas() call for dcheck on build for now.
+ // TODO(crbug.com/1330278): add it back.
ClearCanvas(SkColorSetARGB(255, 0, 0, 255));
#endif
}
@@ -1889,10 +1973,11 @@ void SkiaRenderer::DrawSingleImage(const SkImage* image,
constraint);
}
-void SkiaRenderer::DrawPaintOpBuffer(const cc::PaintOpBuffer* buffer,
- const absl::optional<SkColor>& clear_color,
- const TileDrawQuad* quad,
- const DrawQuadParams* params) {
+void SkiaRenderer::DrawPaintOpBuffer(
+ const cc::PaintOpBuffer* buffer,
+ const absl::optional<SkColor4f>& clear_color,
+ const TileDrawQuad* quad,
+ const DrawQuadParams* params) {
TRACE_EVENT0("viz", "SkiaRenderer::DrawPaintOpBuffer");
if (!batched_quads_.empty())
FlushBatchedQuads();
@@ -2024,7 +2109,7 @@ void SkiaRenderer::DrawPictureQuad(const PictureDrawQuad* quad,
void SkiaRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad,
const DrawRPDQParams* rpdq_params,
DrawQuadParams* params) {
- DrawColoredQuad(SkColor4f::FromColor(quad->color), rpdq_params, params);
+ DrawColoredQuad(quad->color, rpdq_params, params);
}
void SkiaRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
@@ -2033,13 +2118,12 @@ void SkiaRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
TRACE_EVENT0("viz", "SkiaRenderer::DrawStreamVideoQuad");
DCHECK(!MustFlushBatchedQuads(quad, rpdq_params, *params));
- absl::optional<gfx::ColorSpace> override_color_space;
+ sk_sp<SkColorSpace> override_color_space;
// Force SRGB color space if we don't want real color space from media
// decoder.
- if (!use_real_color_space_for_stream_video_) {
- override_color_space = gfx::ColorSpace::CreateSRGB();
- }
+ if (!use_real_color_space_for_stream_video_)
+ override_color_space = SkColorSpace::MakeSRGB();
ScopedSkImageBuilder builder(this, quad->resource_id(),
/*maybe_concurrent_reads=*/true,
@@ -2079,17 +2163,17 @@ void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
const bool needs_color_conversion_filter =
quad->is_video_frame && src_color_space.IsHDR();
- absl::optional<gfx::ColorSpace> override_color_space;
+ sk_sp<SkColorSpace> override_color_space;
if (needs_color_conversion_filter)
- override_color_space = CurrentRenderPassColorSpace();
+ override_color_space = CurrentRenderPassSkColorSpace();
- // TODO(b/221643955): Some Chrome OS tests rely on the old GLRenderer
- // behavior of skipping color space conversions if the quad's color space is
- // invalid. Once these tests are migrated, we can remove the override here
- // and revert to Skia's default behavior of assuming sRGB on invalid.
+ // TODO(b/221643955): Some Chrome OS tests rely on the old GLRenderer
+ // behavior of skipping color space conversions if the quad's color space is
+ // invalid. Once these tests are migrated, we can remove the override here
+ // and revert to Skia's default behavior of assuming sRGB on invalid.
#if BUILDFLAG(IS_CHROMEOS_ASH)
if (!src_color_space.IsValid())
- override_color_space = CurrentRenderPassColorSpace();
+ override_color_space = CurrentRenderPassSkColorSpace();
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
ScopedSkImageBuilder builder(
@@ -2118,7 +2202,7 @@ void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
// 2. The vertex opacities are not all 1s.
// 3. The quad contains video which might need special white level adjustment.
const bool blend_background =
- quad->background_color != SK_ColorTRANSPARENT && !image->isOpaque();
+ quad->background_color != SkColors::kTransparent && !image->isOpaque();
const bool vertex_alpha =
quad->vertex_opacity[0] < 1.f || quad->vertex_opacity[1] < 1.f ||
quad->vertex_opacity[2] < 1.f || quad->vertex_opacity[3] < 1.f;
@@ -2204,8 +2288,9 @@ void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
if (blend_background) {
// Add a color filter that does DstOver blending between texture and the
// background color. Then, modulate by quad's opacity *after* blending.
- sk_sp<SkColorFilter> cf =
- SkColorFilters::Blend(quad->background_color, SkBlendMode::kDstOver);
+ // TODO(crbug/1308932) remove toSkColor and make all SkColor4f
+ sk_sp<SkColorFilter> cf = SkColorFilters::Blend(
+ quad->background_color.toSkColor(), SkBlendMode::kDstOver);
if (quad_alpha < 1.f) {
cf = MakeOpacityFilter(quad_alpha, std::move(cf));
quad_alpha = 1.f;
@@ -2220,7 +2305,7 @@ void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad,
// Skia won't perform color conversion.
const gfx::ColorSpace dst_color_space = CurrentRenderPassColorSpace();
DCHECK(SkColorSpace::Equals(image->colorSpace(),
- dst_color_space.ToSkColorSpace().get()));
+ CurrentRenderPassSkColorSpace().get()));
sk_sp<SkColorFilter> color_filter =
GetColorSpaceConversionFilter(src_color_space, dst_color_space);
paint.setColorFilter(color_filter->makeComposed(paint.refColorFilter()));
@@ -2254,7 +2339,7 @@ void SkiaRenderer::DrawTileDrawQuad(const TileDrawQuad* quad,
this, quad->resource_id(), /*maybe_concurrent_reads=*/false,
quad->is_premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType,
/*origin=*/kTopLeft_GrSurfaceOrigin,
- /*override_colorspace=*/absl::nullopt, raw_draw_if_possible);
+ /*override_color_space=*/nullptr, raw_draw_if_possible);
params->vis_tex_coords = cc::MathUtil::ScaleRectProportional(
quad->tex_coord_rect, gfx::RectF(quad->rect), params->visible_rect);
@@ -2322,8 +2407,7 @@ void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
// color space we lie and say the SkImage destination color space is always
// the same as the rest of the frame. Otherwise the two color space
// adjustments combined will produce the wrong result.
- const gfx::ColorSpace& frame_color_space = CurrentRenderPassColorSpace();
- gfx::ColorSpace dst_color_space = frame_color_space;
+ gfx::ColorSpace dst_color_space = CurrentRenderPassColorSpace();
#if BUILDFLAG(IS_WIN)
// Force sRGB output on Windows for overlay candidate video quads to match
@@ -2344,12 +2428,11 @@ void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
#endif
DCHECK(resource_provider());
- // Pass in |frame_color_space| here instead of |dst_color_space| so the color
- // space transform going from SkImage to SkSurface is identity. The
- // SkColorFilter already handles color space conversion so this avoids
+ // Pass in |CurrentRenderPassSkColorSpace()| here instead of |dst_color_space|
+ // so the color space transform going from SkImage to SkSurface is identity.
+ // The SkColorFilter already handles color space conversion so this avoids
// applying the conversion twice.
- ScopedYUVSkImageBuilder builder(this, quad,
- frame_color_space.ToSkColorSpace());
+ ScopedYUVSkImageBuilder builder(this, quad, CurrentRenderPassSkColorSpace());
const SkImage* image = builder.sk_image();
if (!image)
return;
@@ -2384,9 +2467,14 @@ void SkiaRenderer::DrawUnsupportedQuad(const DrawQuad* quad,
}
void SkiaRenderer::ScheduleOverlays() {
- DCHECK(!current_frame_resource_fence_->WasSet());
+ DCHECK(!current_gpu_commands_completed_fence_->WasSet());
+ DCHECK(!current_release_fence_->WasSet());
+ // Always add an empty set of locks to be used in either SwapBuffersSkipped()
+ // or SwapBuffersComplete().
pending_overlay_locks_.emplace_back();
+ [[maybe_unused]] auto& locks = pending_overlay_locks_.back();
+
if (current_frame()->overlay_list.empty())
return;
@@ -2401,7 +2489,6 @@ void SkiaRenderer::ScheduleOverlays() {
// switched over to OverlayProcessor.
// TODO(weiliangc): Remove this when CrOS and Android SurfaceControl switch
// to OverlayProcessor as well.
- auto& locks = pending_overlay_locks_.back();
for (auto& overlay : current_frame()->overlay_list) {
// Resources will be unlocked after the next SwapBuffers() is completed.
locks.emplace_back(resource_provider(), overlay.resource_id);
@@ -2416,7 +2503,6 @@ void SkiaRenderer::ScheduleOverlays() {
DCHECK(!overlay.mailbox.IsZero());
}
#elif BUILDFLAG(IS_WIN)
- auto& locks = pending_overlay_locks_.back();
for (auto& dc_layer_overlay : current_frame()->overlay_list) {
for (size_t i = 0; i < DCLayerOverlay::kNumResources; ++i) {
ResourceId resource_id = dc_layer_overlay.resources[i];
@@ -2437,10 +2523,10 @@ void SkiaRenderer::ScheduleOverlays() {
DCHECK(!dc_layer_overlay.mailbox[0].IsZero());
}
#elif BUILDFLAG(IS_APPLE)
- auto& locks = pending_overlay_locks_.back();
for (CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) {
if (ca_layer_overlay.rpdq) {
PrepareRenderPassOverlay(&ca_layer_overlay);
+ locks.emplace_back(ca_layer_overlay.mailbox);
continue;
}
// Some overlays are for solid-color layers.
@@ -2465,15 +2551,14 @@ void SkiaRenderer::ScheduleOverlays() {
}
#elif defined(USE_OZONE)
// Only Wayland uses this code path.
- auto& locks = pending_overlay_locks_.back();
for (auto& overlay : current_frame()->overlay_list) {
if (overlay.rpdq) {
PrepareRenderPassOverlay(&overlay);
- // The output will be attached via mailbox when overlays are scheduled.
+ locks.emplace_back(overlay.mailbox);
continue;
}
// Solid Color quads do not have associated resource buffers.
- if (overlay.solid_color.has_value())
+ if (overlay.is_solid_color)
continue;
// Resources will be unlocked after the next SwapBuffers() is completed.
@@ -2495,17 +2580,11 @@ void SkiaRenderer::ScheduleOverlays() {
NOTREACHED();
#endif // BUILDFLAG(IS_ANDROID)
- base::OnceClosure on_finished_callback;
- if (current_frame_resource_fence_->WasSet()) {
- on_finished_callback = base::BindOnce(
- &FrameResourceFence::Signal, std::move(current_frame_resource_fence_));
- current_frame_resource_fence_ = base::MakeRefCounted<FrameResourceFence>();
- resource_provider()->SetReadLockFence(current_frame_resource_fence_.get());
- }
+ DCHECK(!current_gpu_commands_completed_fence_->WasSet());
+ DCHECK(!current_release_fence_->WasSet());
skia_output_surface_->ScheduleOverlays(
- std::move(current_frame()->overlay_list), std::move(sync_tokens),
- std::move(on_finished_callback));
+ std::move(current_frame()->overlay_list), std::move(sync_tokens));
}
sk_sp<SkColorFilter> SkiaRenderer::GetColorSpaceConversionFilter(
@@ -2513,13 +2592,8 @@ sk_sp<SkColorFilter> SkiaRenderer::GetColorSpaceConversionFilter(
const gfx::ColorSpace& dst,
float resource_offset,
float resource_multiplier) {
- // If the input color space is HDR, and it did not specify a white level,
- // override it with the frame's white level.
- gfx::ColorSpace adjusted_src = src.GetWithSDRWhiteLevel(
- current_frame()->display_color_spaces.GetSDRMaxLuminanceNits());
-
return color_filter_cache_.Get(
- adjusted_src, dst, resource_offset, resource_multiplier,
+ src, dst, resource_offset, resource_multiplier,
current_frame()->display_color_spaces.GetSDRMaxLuminanceNits(),
current_frame()->display_color_spaces.GetHDRMaxLuminanceRelative());
}
@@ -2768,7 +2842,7 @@ void SkiaRenderer::DrawRenderPassQuad(const AggregatedRenderPassDrawQuad* quad,
sk_sp<SkImage> content_image =
skia_output_surface_->MakePromiseSkImageFromRenderPass(
quad->render_pass_id, backing.size, backing.format,
- backing.generate_mipmap, backing.color_space.ToSkColorSpace(),
+ backing.generate_mipmap, RenderPassBackingSkColorSpace(backing),
backing.mailbox);
DLOG_IF(ERROR, !content_image)
<< "MakePromiseSkImageFromRenderPass() failed for render pass";
@@ -2852,16 +2926,7 @@ void SkiaRenderer::FinishDrawingQuadList() {
if (is_root_render_pass && UsingSkiaForDelegatedInk())
DrawDelegatedInkTrail();
- base::OnceClosure on_finished_callback;
- // Signal |current_frame_resource_fence_| when the root render pass is
- // finished.
- if (current_frame_resource_fence_->WasSet()) {
- on_finished_callback = base::BindOnce(
- &FrameResourceFence::Signal, std::move(current_frame_resource_fence_));
- current_frame_resource_fence_ = base::MakeRefCounted<FrameResourceFence>();
- resource_provider()->SetReadLockFence(current_frame_resource_fence_.get());
- }
- skia_output_surface_->EndPaint(std::move(on_finished_callback));
+ EndPaint(/*failed=*/false);
// Defer flushing drawing task for root render pass, to avoid extra
// MakeCurrent() call. It is expensive on GL.
@@ -2927,9 +2992,17 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
// TODO(penghuang): check supported format correctly.
gpu::Capabilities caps;
caps.texture_format_bgra8888 = true;
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+ // TODO(crbug.com/1317015): add support RGBA_F16 in LaCrOS.
+ auto format = color_space.IsHDR()
+ ? RGBA_1010102
+ : PlatformColor::BestSupportedTextureFormat(caps);
+#else
auto format = color_space.IsHDR()
? RGBA_F16
: PlatformColor::BestSupportedTextureFormat(caps);
+#endif
uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY;
if (requirements.generate_mipmap)
usage |= gpu::SHARED_IMAGE_USAGE_MIPMAP;
@@ -3058,7 +3131,7 @@ void SkiaRenderer::PrepareRenderPassOverlay(
ResourceFormat buffer_format{};
gfx::ColorSpace color_space;
- RenderPassBacking* backing = nullptr;
+ RenderPassBacking* src_quad_backing = nullptr;
auto bypass = render_pass_bypass_quads_.find(quad->render_pass_id);
BypassMode bypass_mode = BypassMode::kSkip;
// When Render Pass has a single quad inside we would draw that directly.
@@ -3077,9 +3150,9 @@ void SkiaRenderer::PrepareRenderPassOverlay(
DCHECK(render_pass_backings_.end() != it);
// This function is called after AllocateRenderPassResourceIfNeeded, so
// there should be backing ready.
- backing = &it->second;
- buffer_format = backing->format;
- color_space = backing->color_space;
+ src_quad_backing = &it->second;
+ buffer_format = src_quad_backing->format;
+ color_space = src_quad_backing->color_space;
}
// Adjust the overlay |buffer_size| to reduce memory fragmentation. It also
@@ -3090,16 +3163,50 @@ void SkiaRenderer::PrepareRenderPassOverlay(
// TODO(petermcneeley) : Support buffer rounding by dynamically changing
// texture uvs.
constexpr int kBufferMultiple = 1;
-#endif
+#endif // BUILDFLAG(IS_APPLE)
gfx::Size buffer_size(
cc::MathUtil::CheckedRoundUp(filter_bounds.width(), kBufferMultiple),
cc::MathUtil::CheckedRoundUp(filter_bounds.height(), kBufferMultiple));
- current_canvas_ = skia_output_surface_->BeginPaintRenderPassOverlay(
- buffer_size, buffer_format, /*mipmap=*/false,
- color_space.ToSkColorSpace());
+ auto it = std::find_if(available_render_pass_overlay_backings_.begin(),
+ available_render_pass_overlay_backings_.end(),
+ [&buffer_format, &buffer_size,
+ &color_space](const RenderPassBacking& backing) {
+ return backing.format == buffer_format &&
+ backing.size == buffer_size &&
+ backing.color_space == color_space;
+ });
+
+ if (it == available_render_pass_overlay_backings_.end()) {
+ // Allocate the image for render pass overlay if there is no existing
+ // available one.
+ constexpr auto kOverlayUsage = gpu::SHARED_IMAGE_USAGE_SCANOUT |
+ gpu::SHARED_IMAGE_USAGE_DISPLAY |
+ gpu::SHARED_IMAGE_USAGE_RASTER;
+ auto mailbox =
+ skia_output_surface_->GetSharedImageInterface()->CreateSharedImage(
+ buffer_format, buffer_size, color_space, kTopLeft_GrSurfaceOrigin,
+ kPremul_SkAlphaType, kOverlayUsage, gpu::kNullSurfaceHandle);
+ in_flight_render_pass_overlay_backings_.push_back(
+ RenderPassBacking{buffer_size, /*generate_mipmap=*/false, color_space,
+ buffer_format, mailbox});
+ overlay->mailbox = std::move(mailbox);
+ } else {
+ overlay->mailbox = std::move(it->mailbox);
+ in_flight_render_pass_overlay_backings_.push_back(std::move(*it));
+ available_render_pass_overlay_backings_.erase(it);
+ }
+ const RenderPassBacking& dst_overlay_backing =
+ in_flight_render_pass_overlay_backings_.back();
+
+ current_canvas_ = skia_output_surface_->BeginPaintRenderPass(
+ quad->render_pass_id, dst_overlay_backing.size,
+ dst_overlay_backing.format, /*mipmap=*/false,
+ RenderPassBackingSkColorSpace(dst_overlay_backing), /*is_overlay=*/true,
+ overlay->mailbox);
if (!current_canvas_) {
- DLOG(ERROR) << "BeginPaintRenderPassOverlay() failed.";
+ DLOG(ERROR)
+ << "BeginPaintRenderPass() in PrepareRenderPassOverlay() failed.";
return;
}
@@ -3126,19 +3233,20 @@ void SkiaRenderer::PrepareRenderPassOverlay(
NOTREACHED();
}
} else {
- DCHECK(backing);
+ DCHECK(src_quad_backing);
auto content_image = skia_output_surface_->MakePromiseSkImageFromRenderPass(
- quad->render_pass_id, backing->size, backing->format,
- backing->generate_mipmap, backing->color_space.ToSkColorSpace(),
- backing->mailbox);
+ quad->render_pass_id, src_quad_backing->size, src_quad_backing->format,
+ src_quad_backing->generate_mipmap,
+ RenderPassBackingSkColorSpace(*src_quad_backing),
+ src_quad_backing->mailbox);
if (!content_image) {
- DLOG(ERROR)
- << "MakePromiseSkImageFromRenderPass() failed for render pass";
- skia_output_surface_->EndPaintRenderPassOverlay();
+ DLOG(ERROR) << "MakePromiseSkImageFromRenderPass() in "
+ "PrepareRenderPassOverlay() failed.";
+ EndPaint(/*failed=*/true);
return;
}
- if (backing->generate_mipmap)
+ if (src_quad_backing->generate_mipmap)
params.sampling =
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
@@ -3153,19 +3261,47 @@ void SkiaRenderer::PrepareRenderPassOverlay(
}
current_canvas_ = nullptr;
- auto ddl = skia_output_surface_->EndPaintRenderPassOverlay();
- DCHECK(ddl);
- // Put overlay related information in CALayerOverlay,
- // so SkiaOutputSurfaceImplOnGpu can use the DDL to create overlay buffer and
- // play the DDL back to it accordingly.
- overlay->ddl = std::move(ddl);
+ EndPaint(/*failed=*/false);
// Adjust |bounds_rect| to contain the whole buffer and at the right location.
overlay->bounds_rect.set_origin(gfx::PointF(filter_bounds.origin()));
overlay->bounds_rect.set_size(gfx::SizeF(buffer_size));
}
-#endif
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+
+void SkiaRenderer::EndPaint(bool failed) {
+ base::OnceClosure on_finished_callback;
+ base::OnceCallback<void(gfx::GpuFenceHandle)> on_return_release_fence_cb;
+ // If SkiaRenderer has not failed, prepare callbacks and pass them to
+ // SkiaOutputSurface.
+ if (!failed) {
+ // Signal |current_frame_resource_fence_| when the root render pass is
+ // finished.
+ if (current_gpu_commands_completed_fence_->WasSet()) {
+ on_finished_callback =
+ base::BindOnce(&FrameResourceGpuCommandsCompletedFence::Signal,
+ std::move(current_gpu_commands_completed_fence_));
+ current_gpu_commands_completed_fence_ =
+ base::MakeRefCounted<FrameResourceGpuCommandsCompletedFence>();
+ resource_provider()->SetGpuCommandsCompletedFence(
+ current_gpu_commands_completed_fence_.get());
+ }
+
+ // Return a release fence to the |current_release_fence_|
+ // when the root render pass is finished.
+ if (current_release_fence_->WasSet()) {
+ on_return_release_fence_cb =
+ base::BindOnce(&FrameResourceReleaseFence::SetReleaseFenceCallback,
+ std::move(current_release_fence_));
+ current_release_fence_ =
+ base::MakeRefCounted<FrameResourceReleaseFence>();
+ resource_provider()->SetReleaseFence(current_release_fence_.get());
+ }
+ }
+ skia_output_surface_->EndPaint(std::move(on_finished_callback),
+ std::move(on_return_release_fence_cb));
+}
bool SkiaRenderer::IsRenderPassResourceAllocated(
const AggregatedRenderPassId& render_pass_id) const {
@@ -3223,23 +3359,42 @@ bool SkiaRenderer::UsingSkiaForDelegatedInk() const {
return delegated_ink_handler_ && delegated_ink_handler_->GetInkRenderer();
}
+SkiaRenderer::OverlayLock::OverlayLock(
+ DisplayResourceProvider* resource_provider,
+ ResourceId resource_id) {
+ resource_lock.emplace(resource_provider, resource_id);
+}
+
+SkiaRenderer::OverlayLock::~OverlayLock() = default;
+
+SkiaRenderer::OverlayLock::OverlayLock(SkiaRenderer::OverlayLock&& other) {
+ resource_lock = std::move(other.resource_lock);
+
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
-bool SkiaRenderer::ScopedReadLockComparator::operator()(
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& lhs,
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& rhs) const {
- return lhs.mailbox() < rhs.mailbox();
+ render_pass_lock = std::move(other.render_pass_lock);
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
}
-bool SkiaRenderer::ScopedReadLockComparator::operator()(
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& lhs,
- const gpu::Mailbox& rhs) const {
- return lhs.mailbox() < rhs;
+SkiaRenderer::OverlayLock& SkiaRenderer::OverlayLock::OverlayLock::operator=(
+ SkiaRenderer::OverlayLock&& other) {
+ resource_lock = std::move(other.resource_lock);
+
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+ render_pass_lock = std::move(other.render_pass_lock);
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+
+ return *this;
}
-bool SkiaRenderer::ScopedReadLockComparator::operator()(
- const gpu::Mailbox& lhs,
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& rhs) const {
- return lhs < rhs.mailbox();
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+SkiaRenderer::OverlayLock::OverlayLock(gpu::Mailbox mailbox) {
+ render_pass_lock.emplace(mailbox);
+}
+
+bool SkiaRenderer::OverlayLockComparator::operator()(
+ const OverlayLock& lhs,
+ const OverlayLock& rhs) const {
+ return lhs.mailbox() < rhs.mailbox();
}
#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
diff --git a/chromium/components/viz/service/display/skia_renderer.h b/chromium/components/viz/service/display/skia_renderer.h
index d8912a61296..7922aee3b61 100644
--- a/chromium/components/viz/service/display/skia_renderer.h
+++ b/chromium/components/viz/service/display/skia_renderer.h
@@ -7,6 +7,7 @@
#include <memory>
#include <tuple>
+#include <utility>
#include <vector>
#include "base/containers/flat_map.h"
@@ -16,7 +17,6 @@
#include "cc/cc_export.h"
#include "components/viz/service/display/direct_renderer.h"
#include "components/viz/service/display/display_resource_provider_skia.h"
-#include "components/viz/service/display/sync_query_collection.h"
#include "components/viz/service/viz_service_export.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/color_conversion_sk_filter_cache.h"
@@ -195,7 +195,7 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
DrawQuadParams* params);
void DrawPaintOpBuffer(const cc::PaintOpBuffer* buffer,
- const absl::optional<SkColor>& clear_color,
+ const absl::optional<SkColor4f>& clear_color,
const TileDrawQuad* quad,
const DrawQuadParams* params);
@@ -264,6 +264,11 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
OverlayProcessorInterface::PlatformOverlayCandidate* overlay);
#endif
+ // Sets up callbacks for frame resource fences and passes them to
+ // SkiaOutputSurface by calling EndPaint on that. If |failed|,
+ // SkiaOutputSurface::EndPaint will be called with null callbacks.
+ void EndPaint(bool failed);
+
DisplayResourceProviderSkia* resource_provider() {
return static_cast<DisplayResourceProviderSkia*>(resource_provider_);
}
@@ -278,14 +283,22 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
};
base::flat_map<AggregatedRenderPassId, RenderPassBacking>
render_pass_backings_;
+ sk_sp<SkColorSpace> RenderPassBackingSkColorSpace(
+ const RenderPassBacking& backing) {
+ return backing.color_space.ToSkColorSpace(CurrentFrameSDRWhiteLevel());
+ }
// Interface used for drawing. Common among different draw modes.
sk_sp<SkSurface> root_surface_;
raw_ptr<SkCanvas> root_canvas_ = nullptr;
raw_ptr<SkCanvas> current_canvas_ = nullptr;
raw_ptr<SkSurface> current_surface_ = nullptr;
- class FrameResourceFence;
- scoped_refptr<FrameResourceFence> current_frame_resource_fence_;
+
+ class FrameResourceGpuCommandsCompletedFence;
+ scoped_refptr<FrameResourceGpuCommandsCompletedFence>
+ current_gpu_commands_completed_fence_;
+ class FrameResourceReleaseFence;
+ scoped_refptr<FrameResourceReleaseFence> current_release_fence_;
bool disable_picture_quad_image_filtering_ = false;
bool is_scissor_enabled_ = false;
@@ -326,42 +339,88 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
absl::optional<DisplayResourceProviderSkia::LockSetForExternalUse>
lock_set_for_external_use_;
- // Locks for overlays are pending for swapbuffers.
- base::circular_deque<
- std::vector<DisplayResourceProviderSkia::ScopedReadLockSharedImage>>
- pending_overlay_locks_;
+ struct OverlayLock {
+ OverlayLock(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id);
+
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+ explicit OverlayLock(gpu::Mailbox mailbox);
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+
+ ~OverlayLock();
+
+ OverlayLock(OverlayLock&& other);
+ OverlayLock& operator=(OverlayLock&& other);
+
+ OverlayLock(const OverlayLock&) = delete;
+ OverlayLock& operator=(const OverlayLock&) = delete;
+
+ const gpu::Mailbox& mailbox() const {
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+ if (render_pass_lock.has_value()) {
+ return *render_pass_lock;
+ }
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+
+ DCHECK(resource_lock.has_value());
+ return resource_lock->mailbox();
+ }
+
+ const gpu::SyncToken& sync_token() const {
+ DCHECK(resource_lock.has_value());
+ return resource_lock->sync_token();
+ }
+
+ void SetReleaseFence(gfx::GpuFenceHandle release_fence) {
+ if (resource_lock.has_value()) {
+ resource_lock->SetReleaseFence(std::move(release_fence));
+ }
+ }
+
+ bool HasReadLockFence() {
+ if (resource_lock.has_value()) {
+ return resource_lock->HasReadLockFence();
+ }
+ return false;
+ }
+
+ // Either resource_lock is set for non render pass overlays (i.e. videos),
+ // or render_pass_lock is set for render pass overlays.
+ absl::optional<DisplayResourceProviderSkia::ScopedReadLockSharedImage>
+ resource_lock;
+
+#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+ absl::optional<gpu::Mailbox> render_pass_lock;
+#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
+ };
+
+ // Locks for overlays that are pending for SwapBuffers().
+ base::circular_deque<std::vector<OverlayLock>> pending_overlay_locks_;
- // Locks for overlays have been committed. |pending_overlay_locks_| will
- // be moved to |committed_overlay_locks_| after SwapBuffers() completed.
- std::vector<DisplayResourceProviderSkia::ScopedReadLockSharedImage>
- committed_overlay_locks_;
+ // Locks for overlays that have been committed. |pending_overlay_locks_| will
+ // be moved to |committed_overlay_locks_| after SwapBuffers() is completed.
+ std::vector<OverlayLock> committed_overlay_locks_;
// Locks for overlays that have release fences and read lock fences.
- base::circular_deque<
- std::vector<DisplayResourceProviderSkia::ScopedReadLockSharedImage>>
+ base::circular_deque<std::vector<OverlayLock>>
read_lock_release_fence_overlay_locks_;
#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- class ScopedReadLockComparator {
+ class OverlayLockComparator {
public:
using is_transparent = void;
- bool operator()(
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& lhs,
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& rhs)
- const;
- bool operator()(
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& lhs,
- const gpu::Mailbox& rhs) const;
- bool operator()(
- const gpu::Mailbox& lhs,
- const DisplayResourceProviderSkia::ScopedReadLockSharedImage& rhs)
- const;
+ bool operator()(const OverlayLock& lhs, const OverlayLock& rhs) const;
};
- // a set for locks of overlays which are waiting for releasing.
- // The set is using lock.mailbox() as the unique key.
- base::flat_set<DisplayResourceProviderSkia::ScopedReadLockSharedImage,
- ScopedReadLockComparator>
+
+ // A set for locks of overlays which are waiting to be released, using
+ // mailbox() as the unique key.
+ base::flat_set<OverlayLock, OverlayLockComparator>
awaiting_release_overlay_locks_;
+
+ // Tracks render pass overlay backings that are currently in use and available
+ // for re-using via mailboxes. RenderPassBacking.generate_mipmap is not used.
+ std::vector<RenderPassBacking> in_flight_render_pass_overlay_backings_;
+ std::vector<RenderPassBacking> available_render_pass_overlay_backings_;
#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
gfx::ColorConversionSkFilterCache color_filter_cache_;
diff --git a/chromium/components/viz/service/display/software_renderer.cc b/chromium/components/viz/service/display/software_renderer.cc
index 945245b1299..7ee2ca60256 100644
--- a/chromium/components/viz/service/display/software_renderer.cc
+++ b/chromium/components/viz/service/display/software_renderer.cc
@@ -134,7 +134,6 @@ void SoftwareRenderer::EnsureScissorTestDisabled() {
}
void SoftwareRenderer::BindFramebufferToOutputSurface() {
- DCHECK(!output_surface_->HasExternalStencilTest());
DCHECK(!root_canvas_);
current_framebuffer_canvas_.reset();
@@ -367,21 +366,20 @@ void SoftwareRenderer::DoDrawQuad(const DrawQuad* quad,
}
void SoftwareRenderer::DrawDebugBorderQuad(const DebugBorderDrawQuad* quad) {
- // We need to apply the matrix manually to have pixel-sized stroke width.
- SkPoint vertices[4];
- gfx::RectFToSkRect(QuadVertexRect()).toQuad(vertices);
- SkPoint transformed_vertices[4];
- current_canvas_->getTotalMatrix().mapPoints(transformed_vertices, vertices,
- 4);
+ SkMatrix m = current_canvas_->getTotalMatrix();
current_canvas_->resetMatrix();
+ SkPath path;
+ path.addRect(gfx::RectFToSkRect(QuadVertexRect()));
+ path.transform(m);
+
current_paint_.setColor(quad->color);
- current_paint_.setAlpha(quad->shared_quad_state->opacity *
- SkColorGetA(quad->color));
+ current_paint_.setAlphaf(quad->shared_quad_state->opacity * quad->color.fA);
current_paint_.setStyle(SkPaint::kStroke_Style);
+ current_paint_.setStrokeJoin(SkPaint::kMiter_Join);
current_paint_.setStrokeWidth(quad->width);
- current_canvas_->drawPoints(SkCanvas::kPolygon_PointMode, 4,
- transformed_vertices, current_paint_);
+
+ current_canvas_->drawPath(path, current_paint_);
}
void SoftwareRenderer::DrawPictureQuad(const PictureDrawQuad* quad) {
@@ -429,8 +427,7 @@ void SoftwareRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad) {
gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
current_paint_.setColor(quad->color);
- current_paint_.setAlpha(quad->shared_quad_state->opacity *
- SkColorGetA(quad->color));
+ current_paint_.setAlphaf(quad->shared_quad_state->opacity * quad->color.fA);
current_canvas_->drawRect(gfx::RectFToSkRect(visible_quad_vertex_rect),
current_paint_);
}
@@ -462,7 +459,7 @@ void SoftwareRenderer::DrawTextureQuad(const TextureDrawQuad* quad) {
current_canvas_->scale(1, -1);
bool blend_background =
- quad->background_color != SK_ColorTRANSPARENT && !image->isOpaque();
+ quad->background_color != SkColors::kTransparent && !image->isOpaque();
bool needs_layer = blend_background && (current_paint_.getAlpha() != 0xFF);
if (needs_layer) {
current_canvas_->saveLayerAlpha(&quad_rect, current_paint_.getAlpha());
@@ -592,9 +589,9 @@ void SoftwareRenderer::DrawRenderPassQuad(
void SoftwareRenderer::DrawUnsupportedQuad(const DrawQuad* quad) {
#ifdef NDEBUG
- current_paint_.setColor(SK_ColorWHITE);
+ current_paint_.setColor(SkColors::kWhite);
#else
- current_paint_.setColor(SK_ColorMAGENTA);
+ current_paint_.setColor(SkColors::kMagenta);
#endif
current_paint_.setAlpha(quad->shared_quad_state->opacity * 255);
current_canvas_->drawRect(gfx::RectFToSkRect(QuadVertexRect()),
@@ -604,8 +601,7 @@ void SoftwareRenderer::DrawUnsupportedQuad(const DrawQuad* quad) {
void SoftwareRenderer::CopyDrawnRenderPass(
const copy_output::RenderPassGeometry& geometry,
std::unique_ptr<CopyOutputRequest> request) {
- sk_sp<SkColorSpace> color_space =
- CurrentRenderPassColorSpace().ToSkColorSpace();
+ sk_sp<SkColorSpace> color_space = CurrentRenderPassSkColorSpace();
DCHECK(color_space);
SkBitmap bitmap;
diff --git a/chromium/components/viz/service/display/software_renderer_unittest.cc b/chromium/components/viz/service/display/software_renderer_unittest.cc
index f706e41e9f1..521d833e6b9 100644
--- a/chromium/components/viz/service/display/software_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/software_renderer_unittest.cc
@@ -25,6 +25,7 @@
#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/compositor_render_pass_draw_quad.h"
+#include "components/viz/common/quads/debug_border_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/tile_draw_quad.h"
#include "components/viz/common/resources/bitmap_allocation.h"
@@ -46,8 +47,8 @@ class SoftwareRendererTest : public testing::Test {
public:
void InitializeRenderer(
std::unique_ptr<SoftwareOutputDevice> software_output_device) {
- output_surface_ =
- FakeOutputSurface::CreateSoftware(std::move(software_output_device));
+ output_surface_ = std::make_unique<FakeSoftwareOutputSurface>(
+ std::move(software_output_device));
output_surface_->BindToClient(&output_surface_client_);
shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>();
@@ -134,7 +135,7 @@ class SoftwareRendererTest : public testing::Test {
RendererSettings settings_;
DebugRendererSettings debug_settings_;
cc::FakeOutputSurfaceClient output_surface_client_;
- std::unique_ptr<FakeOutputSurface> output_surface_;
+ std::unique_ptr<FakeSoftwareOutputSurface> output_surface_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
std::unique_ptr<DisplayResourceProviderSoftware> resource_provider_;
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
@@ -187,6 +188,78 @@ TEST_F(SoftwareRendererTest, SolidColorQuad) {
output->getColor(inner_size.width() - 1, inner_size.height() - 1));
}
+TEST_F(SoftwareRendererTest, DebugBorderDrawQuad) {
+ gfx::Size rect_size(10, 10);
+ gfx::Size full_size(100, 100);
+ gfx::Rect screen_rect(full_size);
+ gfx::Rect rect_1(rect_size);
+ gfx::Rect rect_2(gfx::Point(1, 1), rect_size);
+ gfx::Rect rect_3(gfx::Point(2, 2), rect_size);
+ gfx::Rect rect_4(gfx::Point(3, 3), rect_size);
+
+ InitializeRenderer(std::make_unique<SoftwareOutputDevice>());
+
+ AggregatedRenderPassId root_render_pass_id{1};
+ auto root_render_pass = std::make_unique<AggregatedRenderPass>();
+ root_render_pass->SetNew(root_render_pass_id, screen_rect, screen_rect,
+ gfx::Transform());
+ SharedQuadState* shared_quad_state =
+ root_render_pass->CreateAndAppendSharedQuadState();
+ shared_quad_state->SetAll(gfx::Transform(), screen_rect, screen_rect,
+ gfx::MaskFilterInfo(), absl::nullopt, true, 1.0,
+ SkBlendMode::kSrcOver, 0);
+
+ auto* quad_1 =
+ root_render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
+ quad_1->SetNew(shared_quad_state, rect_1, rect_1, SK_ColorCYAN, false);
+ auto* quad_2 =
+ root_render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
+ quad_2->SetNew(shared_quad_state, rect_2, rect_2, SK_ColorMAGENTA, false);
+
+ auto* quad_3 =
+ root_render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
+ quad_3->SetNew(shared_quad_state, rect_3, rect_3, SK_ColorYELLOW, false);
+
+ // Test one non-opaque color
+ SkColor semi_transparent_white = SkColorSetARGB(127, 255, 255, 255);
+ auto* quad_4 =
+ root_render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
+ quad_4->SetNew(shared_quad_state, rect_4, rect_4, semi_transparent_white,
+ false);
+
+ AggregatedRenderPassList list;
+ list.push_back(std::move(root_render_pass));
+
+ float device_scale_factor = 1.f;
+ std::unique_ptr<SkBitmap> output =
+ DrawAndCopyOutput(&list, device_scale_factor, full_size);
+ EXPECT_EQ(screen_rect.width(), output->info().width());
+ EXPECT_EQ(screen_rect.height(), output->info().height());
+
+ // Top left corners
+ EXPECT_EQ(SK_ColorCYAN, output->getColor(0, 0));
+ EXPECT_EQ(SK_ColorMAGENTA, output->getColor(1, 1));
+ EXPECT_EQ(SK_ColorYELLOW, output->getColor(2, 2));
+ // The corners end up being more opaque due to the miter, go one to the right
+ EXPECT_EQ(semi_transparent_white, output->getColor(3, 4));
+
+ // Un-drawn pixels as the quads are just outlines
+ EXPECT_EQ(SK_ColorTRANSPARENT, output->getColor(4, 4));
+ EXPECT_EQ(SK_ColorTRANSPARENT,
+ output->getColor(rect_size.width() - 2, rect_size.height() - 2));
+
+ // The bottom rightmost pixel of these quads are not filled because of the
+ // SkPaint::kMiter_Join StrokeJoin, go one pixel to the left
+ EXPECT_EQ(SK_ColorCYAN,
+ output->getColor(rect_size.width() - 1, rect_size.height()));
+ EXPECT_EQ(SK_ColorMAGENTA,
+ output->getColor(rect_size.width(), rect_size.height() + 1));
+ EXPECT_EQ(SK_ColorYELLOW,
+ output->getColor(rect_size.width() + 1, rect_size.height() + 2));
+ EXPECT_EQ(semi_transparent_white,
+ output->getColor(rect_size.width() + 2, rect_size.height() + 3));
+}
+
TEST_F(SoftwareRendererTest, TileQuad) {
gfx::Size outer_size(100, 100);
gfx::Size inner_size(98, 98);
diff --git a/chromium/components/viz/service/display/static_geometry_binding.cc b/chromium/components/viz/service/display/static_geometry_binding.cc
deleted file mode 100644
index 1dc0e9b717a..00000000000
--- a/chromium/components/viz/service/display/static_geometry_binding.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/static_geometry_binding.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace viz {
-
-StaticGeometryBinding::StaticGeometryBinding(gpu::gles2::GLES2Interface* gl,
- const gfx::RectF& quad_vertex_rect)
- : gl_(gl), quad_vertices_vbo_(0), quad_elements_vbo_(0) {
- GeometryBindingQuad quads[NUM_QUADS];
- GeometryBindingQuadIndex quad_indices[NUM_QUADS];
-
- static_assert(sizeof(GeometryBindingQuad) == 24 * sizeof(float),
- "struct Quad should be densely packed");
- static_assert(sizeof(GeometryBindingQuadIndex) == 6 * sizeof(uint16_t),
- "struct QuadIndex should be densely packed");
-
- for (size_t i = 0; i < NUM_QUADS; i++) {
- GeometryBindingVertex v0 = {
- {quad_vertex_rect.x(), quad_vertex_rect.bottom(), 0.0f},
- {0.0f, 1.0f},
- i * 4.0f + 0.0f};
- GeometryBindingVertex v1 = {
- {quad_vertex_rect.x(), quad_vertex_rect.y(), 0.0f},
- {0.0f, 0.0f},
- i * 4.0f + 1.0f};
- GeometryBindingVertex v2 = {
- {quad_vertex_rect.right(), quad_vertex_rect.y(), 0.0f},
- {1.0f, 0.0f},
- i * 4.0f + 2.0f};
- GeometryBindingVertex v3 = {
- {quad_vertex_rect.right(), quad_vertex_rect.bottom(), 0.0f},
- {1.0f, 1.0f},
- i * 4.0f + 3.0f};
- GeometryBindingQuad x(v0, v1, v2, v3);
- quads[i] = x;
- GeometryBindingQuadIndex y(
- static_cast<uint16_t>(0 + 4 * i), static_cast<uint16_t>(1 + 4 * i),
- static_cast<uint16_t>(2 + 4 * i), static_cast<uint16_t>(3 + 4 * i),
- static_cast<uint16_t>(0 + 4 * i), static_cast<uint16_t>(2 + 4 * i));
- quad_indices[i] = y;
- }
-
- gl_->GenBuffers(1, &quad_vertices_vbo_);
- gl_->GenBuffers(1, &quad_elements_vbo_);
-
- gl_->BindBuffer(GL_ARRAY_BUFFER, quad_vertices_vbo_);
- gl_->BufferData(GL_ARRAY_BUFFER, sizeof(GeometryBindingQuad) * NUM_QUADS,
- quads, GL_STATIC_DRAW);
-
- gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, quad_elements_vbo_);
- gl_->BufferData(GL_ELEMENT_ARRAY_BUFFER,
- sizeof(GeometryBindingQuadIndex) * NUM_QUADS, &quad_indices,
- GL_STATIC_DRAW);
-}
-
-StaticGeometryBinding::~StaticGeometryBinding() {
- gl_->DeleteBuffers(1, &quad_vertices_vbo_);
- gl_->DeleteBuffers(1, &quad_elements_vbo_);
-}
-
-void StaticGeometryBinding::PrepareForDraw() {
- SetupGLContext(gl_, quad_elements_vbo_, quad_vertices_vbo_);
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/static_geometry_binding.h b/chromium/components/viz/service/display/static_geometry_binding.h
deleted file mode 100644
index 2a09459426c..00000000000
--- a/chromium/components/viz/service/display/static_geometry_binding.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_STATIC_GEOMETRY_BINDING_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_STATIC_GEOMETRY_BINDING_H_
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/service/display/geometry_binding.h"
-#include "components/viz/service/viz_service_export.h"
-
-using gpu::gles2::GLES2Interface;
-
-namespace viz {
-
-class VIZ_SERVICE_EXPORT StaticGeometryBinding {
- public:
- StaticGeometryBinding(gpu::gles2::GLES2Interface* gl,
- const gfx::RectF& quad_vertex_rect);
-
- StaticGeometryBinding(const StaticGeometryBinding&) = delete;
- StaticGeometryBinding& operator=(const StaticGeometryBinding&) = delete;
-
- ~StaticGeometryBinding();
-
- void PrepareForDraw();
-
- enum {
- NUM_QUADS = 9,
- };
-
- private:
- raw_ptr<gpu::gles2::GLES2Interface> gl_;
-
- GLuint quad_vertices_vbo_;
- GLuint quad_elements_vbo_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_STATIC_GEOMETRY_BINDING_H_
diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc
index 8d8eec8d786..24d580b44ba 100644
--- a/chromium/components/viz/service/display/surface_aggregator.cc
+++ b/chromium/components/viz/service/display/surface_aggregator.cc
@@ -302,16 +302,19 @@ SurfaceAggregator::SurfaceAggregator(
aggregate_only_damaged_(aggregate_only_damaged),
needs_surface_damage_rect_list_(needs_surface_damage_rect_list),
de_jelly_enabled_(DeJellyEnabled()),
- clip_prewalk_damage_(features::IsClipPrewalkDamageEnabled()),
extra_pass_for_readback_option_(extra_pass_option) {
DCHECK(manager_);
DCHECK(provider_);
+ manager_->AddObserver(this);
}
SurfaceAggregator::~SurfaceAggregator() {
- // Notify client of all surfaces being removed.
+ manager_->RemoveObserver(this);
+
contained_surfaces_.clear();
contained_frame_sinks_.clear();
+
+ // Notify client of all surfaces being removed.
ProcessAddedAndRemovedSurfaces();
}
@@ -534,10 +537,21 @@ bool SurfaceAggregator::CanPotentiallyMergePass(
sqs->de_jelly_delta_y == 0;
}
+void SurfaceAggregator::OnSurfaceDestroyed(const SurfaceId& surface_id) {
+ DCHECK(!is_inside_aggregate_);
+
+ auto iter = resolved_frames_.find(surface_id);
+ if (iter != resolved_frames_.end()) {
+ TRACE_EVENT0("viz", "SurfaceAggregator::SurfaceDestroyed");
+ ReleaseResources(surface_id);
+ resolved_frames_.erase(iter);
+ }
+}
+
const ResolvedFrameData* SurfaceAggregator::GetLatestFrameData(
const SurfaceId& surface_id) {
- auto* surface = manager_->GetSurfaceForId(surface_id);
- return GetResolvedFrame(surface, /*inside_aggregation=*/false);
+ DCHECK(!is_inside_aggregate_);
+ return GetResolvedFrame(surface_id);
}
ResolvedFrameData* SurfaceAggregator::GetResolvedFrame(
@@ -546,59 +560,51 @@ ResolvedFrameData* SurfaceAggregator::GetResolvedFrame(
// this aggregation, then find ResolvedFrameData for that surface.
auto iter = resolved_surface_ranges_.find(range);
if (iter == resolved_surface_ranges_.end()) {
- iter = resolved_surface_ranges_
- .emplace(range, manager_->GetLatestInFlightSurface(range))
- .first;
+ auto* surface = manager_->GetLatestInFlightSurface(range);
+ SurfaceId surface_id = surface ? surface->surface_id() : SurfaceId();
+ iter = resolved_surface_ranges_.emplace(range, surface_id).first;
}
- return GetResolvedFrame(iter->second, /*inside_aggregation=*/true);
-}
+ if (!iter->second.is_valid()) {
+ // There is no surface for `range`.
+ return nullptr;
+ }
-ResolvedFrameData* SurfaceAggregator::GetResolvedFrame(
- const SurfaceId& surface_id) {
- return GetResolvedFrame(manager_->GetSurfaceForId(surface_id),
- /*inside_aggregation=*/true);
+ return GetResolvedFrame(iter->second);
}
ResolvedFrameData* SurfaceAggregator::GetResolvedFrame(
- Surface* surface,
- bool inside_aggregation) {
- if (!surface || !surface->HasActiveFrame()) {
- // If there is no resolved surface or the surface has no active frame there
- // is no resolved frame data to return.
- return nullptr;
- }
+ const SurfaceId& surface_id) {
+ DCHECK(surface_id.is_valid());
- auto iter = resolved_frames_.find(surface);
+ auto iter = resolved_frames_.find(surface_id);
if (iter == resolved_frames_.end()) {
- iter =
- resolved_frames_
- .emplace(std::piecewise_construct, std::forward_as_tuple(surface),
- std::forward_as_tuple(surface->surface_id(), surface))
- .first;
+ auto* surface = manager_->GetSurfaceForId(surface_id);
+ if (!surface || !surface->HasActiveFrame()) {
+ // If there is no resolved surface or the surface has no active frame
+ // there is no resolved frame data to return.
+ return nullptr;
+ }
+
+ iter = resolved_frames_
+ .emplace(std::piecewise_construct,
+ std::forward_as_tuple(surface_id),
+ std::forward_as_tuple(surface->surface_id(), surface))
+ .first;
}
ResolvedFrameData& resolved_frame = iter->second;
- DCHECK_EQ(resolved_frame.surface(), surface);
-
- // Verify that a new surface wasn't created at the same address as a deleted
- // surface with a different SurfaceId.
- // TODO(kylechar): Invalidate cached resolved frame data when
- // SurfaceObserver signals the surface has been destroyed instead.
- if (resolved_frame.surface_id() != surface->surface_id()) {
- resolved_frames_.erase(iter);
- return GetResolvedFrame(surface, inside_aggregation);
- }
+ Surface* surface = resolved_frame.surface();
// Mark the frame as used this aggregation so it persists.
- bool first_use = inside_aggregation ? resolved_frame.MarkAsUsed() : true;
+ bool first_use = is_inside_aggregate_ ? resolved_frame.MarkAsUsed() : true;
if (first_use) {
// If there is a new CompositorFrame for `surface` compute resolved frame
// data for the new resolved CompositorFrame.
if (resolved_frame.frame_index() != surface->GetActiveFrameIndex() ||
surface->HasSurfaceAnimationDamage()) {
- DCHECK(inside_aggregation);
+ DCHECK(is_inside_aggregate_);
base::ElapsedTimer timer;
ProcessResolvedFrame(resolved_frame);
stats_->declare_resources_time += timer.Elapsed();
@@ -969,15 +975,17 @@ void SurfaceAggregator::EmitDefaultBackgroundColorQuad(
// No matching surface was found so create a SolidColorDrawQuad with the
// SurfaceDrawQuad default background color.
- SkColor background_color = surface_quad->default_background_color;
+ SkColor4f background_color = surface_quad->default_background_color;
auto* shared_quad_state =
CopySharedQuadState(surface_quad->shared_quad_state, target_transform,
clip_rect, mask_filter_info, dest_pass);
auto* solid_color_quad =
dest_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ // TODO(crbug/1308932) remove toSkColor and make all SkColor4f
solid_color_quad->SetNew(shared_quad_state, surface_quad->rect,
- surface_quad->visible_rect, background_color, false);
+ surface_quad->visible_rect,
+ background_color.toSkColor(), false);
}
void SurfaceAggregator::EmitGutterQuadsIfNecessary(
@@ -1262,6 +1270,9 @@ void SurfaceAggregator::CopyQuadsToPass(
const DrawQuad* quad_with_overlay_damage_index = nullptr;
if (needs_surface_damage_rect_list_ &&
resolved_pass.aggregation().will_draw) {
+ // TODO(crbug.com/1323002): If there is one specific quad for this pass's
+ // damage we should move the allocation of the damage index below to be
+ // consistent with quad ordering.
quad_with_overlay_damage_index =
FindQuadWithOverlayDamage(source_pass, dest_pass, target_transform,
surface, &overlay_damage_index);
@@ -1727,13 +1738,11 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
}
}
- if (clip_prewalk_damage_) {
- // Clip the quad damage to the quad visible before converting back to
- // render pass coordinate space. Expanded damage outside the quad rect for
- // filters are added to |damage_rect| directly so this only clips damage
- // from drawing the quad itself.
- quad_damage_rect.Intersect(quad->visible_rect);
- }
+ // Clip the quad damage to the quad visible before converting back to
+ // render pass coordinate space. Expanded damage outside the quad rect for
+ // filters are added to |damage_rect| directly so this only clips damage
+ // from drawing the quad itself.
+ quad_damage_rect.Intersect(quad->visible_rect);
if (!quad_damage_rect.IsEmpty()) {
// Convert the quad damage rect into its target space and clip it if
@@ -1758,15 +1767,13 @@ gfx::Rect SurfaceAggregator::PrewalkRenderPass(
damage_rect.Union(render_pass.output_rect);
}
- if (clip_prewalk_damage_) {
- // The added damage from quads in the render pass is transformed back
- // into the render pass coordinate space without clipping, so it can
- // extend beyond the edge of the current render pass. Coordinates outside
- // the output_rect are invalid in this render passes coordinate space but
- // they may be valid coordinates in the embedder coordinate space, causing
- // unnecessary damage expansion.
- damage_rect.Intersect(render_pass.output_rect);
- }
+ // The added damage from quads in the render pass is transformed back into
+ // the render pass coordinate space without clipping, so it can extend
+ // beyond the edge of the current render pass. Coordinates outside the
+ // output_rect are invalid in this render passes coordinate space but they
+ // may be valid coordinates in the embedder coordinate space, causing
+ // unnecessary damage expansion.
+ damage_rect.Intersect(render_pass.output_rect);
}
return damage_rect;
@@ -1982,23 +1989,26 @@ AggregatedFrame SurfaceAggregator::Aggregate(
const gfx::Rect& target_damage,
int64_t display_trace_id) {
DCHECK(!expected_display_time.is_null());
-
- root_surface_id_ = surface_id;
- Surface* surface = manager_->GetSurfaceForId(surface_id);
- DCHECK(surface);
DCHECK(contained_surfaces_.empty());
- CheckFrameSinksChanged(surface);
+ DCHECK(!is_inside_aggregate_);
+ is_inside_aggregate_ = true;
+
+ root_surface_id_ = surface_id;
// Start recording new stats for this aggregation.
stats_.emplace();
base::ElapsedTimer prewalk_timer;
- ResolvedFrameData* resolved_frame =
- GetResolvedFrame(surface, /*inside_aggregation=*/true);
+ ResolvedFrameData* resolved_frame = GetResolvedFrame(surface_id);
- if (!resolved_frame || !resolved_frame->is_valid())
+ if (!resolved_frame || !resolved_frame->is_valid()) {
+ ResetAfterAggregate();
return {};
+ }
+
+ Surface* surface = resolved_frame->surface();
+ CheckFrameSinksChanged(surface);
display_trace_id_ = display_trace_id;
expected_display_time_ = expected_display_time;
@@ -2162,6 +2172,9 @@ void SurfaceAggregator::RecordStatHistograms() {
}
void SurfaceAggregator::ResetAfterAggregate() {
+ DCHECK(is_inside_aggregate_);
+
+ is_inside_aggregate_ = false;
dest_pass_list_ = nullptr;
surface_damage_rect_list_ = nullptr;
current_zero_damage_rect_is_not_recorded_ = false;
diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h
index 338dc871b87..03482fd6129 100644
--- a/chromium/components/viz/service/display/surface_aggregator.h
+++ b/chromium/components/viz/service/display/surface_aggregator.h
@@ -23,6 +23,7 @@
#include "components/viz/common/surfaces/surface_range.h"
#include "components/viz/service/display/aggregated_frame.h"
#include "components/viz/service/display/resolved_frame_data.h"
+#include "components/viz/service/surfaces/surface_observer.h"
#include "components/viz/service/viz_service_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/delegated_ink_metadata.h"
@@ -37,7 +38,7 @@ class SurfaceManager;
struct MaskFilterInfoExt;
-class VIZ_SERVICE_EXPORT SurfaceAggregator {
+class VIZ_SERVICE_EXPORT SurfaceAggregator : public SurfaceObserver {
public:
using SurfaceIndexMap = base::flat_map<SurfaceId, uint64_t>;
using FrameSinkIdMap = base::flat_map<FrameSinkId, LocalSurfaceId>;
@@ -73,7 +74,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
SurfaceAggregator(const SurfaceAggregator&) = delete;
SurfaceAggregator& operator=(const SurfaceAggregator&) = delete;
- ~SurfaceAggregator();
+ ~SurfaceAggregator() override;
// These constants are used for all time related metrics recorded in
// SurfaceAggregator.
@@ -96,7 +97,6 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// Aggregate() to make sure no CompositorFrame did arrive between the calls.
const ResolvedFrameData* GetLatestFrameData(const SurfaceId& surface_id);
- void ReleaseResources(const SurfaceId& surface_id);
const SurfaceIndexMap& previous_contained_surfaces() const {
return previous_contained_surfaces_;
}
@@ -135,13 +135,16 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
base::TimeDelta declare_resources_time;
};
+ // SurfaceObserver implementation.
+ void OnSurfaceDestroyed(const SurfaceId& surface_id) override;
+
+ void ReleaseResources(const SurfaceId& surface_id);
+
// Get resolved frame data for the resolved surfaces active frame. Returns
// null if there is no matching surface or the surface doesn't have an active
// CompositorFrame.
ResolvedFrameData* GetResolvedFrame(const SurfaceRange& range);
ResolvedFrameData* GetResolvedFrame(const SurfaceId& surface_id);
- ResolvedFrameData* GetResolvedFrame(Surface* surface,
- bool inside_aggregation);
// - |source_pass| is the render pass that contains |surface_quad|.
// - |target_transform| is the transform from the coordinate space of
@@ -386,10 +389,11 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// Whether de-jelly may be active.
const bool de_jelly_enabled_;
- const bool clip_prewalk_damage_;
-
const ExtraPassForReadbackOption extra_pass_for_readback_option_;
+ // Will be true for duration of Aggregate() function.
+ bool is_inside_aggregate_ = false;
+
bool output_is_secure_ = false;
// Whether |CopyOutputRequests| should be moved over to the aggregated frame.
@@ -410,6 +414,9 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// The id for the optional render pass used to apply the display transform.
AggregatedRenderPassId display_transform_render_pass_id_;
+ // Persistent storage for ResolvedFrameData.
+ std::map<SurfaceId, ResolvedFrameData> resolved_frames_;
+
base::flat_map<SurfaceId, int> surface_id_to_resource_child_id_;
// The following state is only valid for the duration of one Aggregate call
@@ -439,8 +446,8 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
base::TimeTicks expected_display_time_;
int64_t display_trace_id_ = -1;
- // Map from SurfaceRange to Surface for current aggregation.
- base::flat_map<SurfaceRange, Surface*> resolved_surface_ranges_;
+ // Map from SurfaceRange to SurfaceId for current aggregation.
+ base::flat_map<SurfaceRange, SurfaceId> resolved_surface_ranges_;
// The root damage rect of the currently-aggregating frame.
gfx::Rect root_damage_rect_;
@@ -503,9 +510,6 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// by FindQuadWithOverlayDamage().
bool current_zero_damage_rect_is_not_recorded_ = false;
- // Persistent storage for ResolvedFrameData.
- std::map<Surface*, ResolvedFrameData> resolved_frames_;
-
// Used to generate new unique render pass ids in the aggregated namespace.
AggregatedRenderPassId::Generator render_pass_id_generator_;
};
diff --git a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
index 07e18febf5c..aa9f8cdac09 100644
--- a/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_pixeltest.cc
@@ -339,10 +339,6 @@ TEST_P(SurfaceAggregatorPixelTest, DrawAggregatedFrameWithSurfaceTransforms) {
// Draw a simple frame with a delegated ink trail on top of it, then confirm
// that it is erased by the next aggregation.
TEST_P(SurfaceAggregatorPixelTest, DrawAndEraseDelegatedInkTrail) {
- // DelegatedInkTrail isn't supported on non-Skia renderers.
- if (renderer_type() == RendererType::kGL)
- return;
-
DelegatedInkPointPixelTestHelper delegated_ink_helper(renderer_.get());
// Create and send metadata and points to the renderer that will be drawn.
diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
index 4e454627318..481853d3eda 100644
--- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
@@ -341,7 +341,8 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
const auto* solid_color_quad = SolidColorDrawQuad::MaterialCast(quad);
- EXPECT_EQ(expected_quad.color, solid_color_quad->color);
+ EXPECT_EQ(SkColor4f::FromColor(expected_quad.color),
+ solid_color_quad->color);
EXPECT_EQ(expected_quad.rect, solid_color_quad->rect);
break;
}
@@ -6000,13 +6001,13 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, ColorSpaceTestWin) {
gfx::BufferFormat::RGBA_8888);
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kWideColorGamut, true /* needs_alpha */,
- gfx::ColorSpace::CreateSCRGBLinear(), gfx::BufferFormat::RGBA_8888);
+ gfx::ColorSpace::CreateSRGBLinear(), gfx::BufferFormat::RGBA_8888);
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kHDR, false /* needs_alpha */,
gfx::ColorSpace::CreateHDR10(), gfx::BufferFormat::BGRA_1010102);
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kHDR, true /* needs_alpha */,
- gfx::ColorSpace::CreateSCRGBLinear(), gfx::BufferFormat::RGBA_F16);
+ gfx::ColorSpace::CreateSRGBLinear(), gfx::BufferFormat::RGBA_F16);
std::vector<Pass> passes = {
Pass(quads[0], CompositorRenderPassId{2}, kSurfaceSize),
@@ -6085,7 +6086,7 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, ColorSpaceTestWin) {
gfx::BufferFormat::BGRA_1010102);
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kHDR, true /* needs_alpha */,
- gfx::ColorSpace::CreateSCRGBLinear(), gfx::BufferFormat::RGBA_F16);
+ gfx::ColorSpace::CreateSRGBLinear(), gfx::BufferFormat::RGBA_F16);
// Opaque content renders to the appropriate space directly.
passes[1].has_transparent_background = false;
diff --git a/chromium/components/viz/service/display/sync_query_collection.cc b/chromium/components/viz/service/display/sync_query_collection.cc
deleted file mode 100644
index 51a85c415da..00000000000
--- a/chromium/components/viz/service/display/sync_query_collection.cc
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/sync_query_collection.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "cc/base/container_util.h"
-#include "components/viz/service/display/resource_fence.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-
-namespace viz {
-namespace {
-// Block or crash if the number of pending sync queries reach this high as
-// something is seriously wrong on the service side if this happens.
-const size_t kMaxPendingSyncQueries = 16;
-} // anonymous namespace
-
-class SyncQuery {
- public:
- explicit SyncQuery(gpu::gles2::GLES2Interface* gl)
- : gl_(gl), query_id_(0u), is_pending_(false) {
- gl_->GenQueriesEXT(1, &query_id_);
- }
-
- SyncQuery(const SyncQuery&) = delete;
- SyncQuery& operator=(const SyncQuery&) = delete;
-
- virtual ~SyncQuery() { gl_->DeleteQueriesEXT(1, &query_id_); }
-
- scoped_refptr<ResourceFence> Begin() {
- DCHECK(!IsPending());
- // Invalidate weak pointer held by old fence.
- weak_ptr_factory_.InvalidateWeakPtrs();
- // Note: In case the set of drawing commands issued before End() do not
- // depend on the query, defer BeginQueryEXT call until Set() is called and
- // query is required.
- return base::MakeRefCounted<Fence>(weak_ptr_factory_.GetWeakPtr());
- }
-
- void Set() {
- if (is_pending_)
- return;
-
- // Note: BeginQueryEXT on GL_COMMANDS_COMPLETED_CHROMIUM is effectively a
- // noop relative to GL, so it doesn't matter where it happens but we still
- // make sure to issue this command when Set() is called (prior to issuing
- // any drawing commands that depend on query), in case some future extension
- // can take advantage of this.
- gl_->BeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query_id_);
- is_pending_ = true;
- }
-
- void End() {
- if (!is_pending_)
- return;
-
- gl_->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
- }
-
- bool IsPending() {
- if (!is_pending_)
- return false;
-
- unsigned result_available = 1;
- gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_AVAILABLE_EXT,
- &result_available);
- is_pending_ = !result_available;
- return is_pending_;
- }
-
- void Wait() {
- if (!is_pending_)
- return;
-
- unsigned result = 0;
- gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
- is_pending_ = false;
- }
-
- private:
- class Fence : public ResourceFence {
- public:
- explicit Fence(base::WeakPtr<SyncQuery> query) : query_(query) {}
-
- Fence(const Fence&) = delete;
- Fence& operator=(const Fence&) = delete;
-
- // ResourceFence implementation.
- void Set() override {
- DCHECK(query_);
- query_->Set();
- }
- bool HasPassed() override { return !query_ || !query_->IsPending(); }
-
- private:
- ~Fence() override {}
-
- base::WeakPtr<SyncQuery> query_;
- };
-
- raw_ptr<gpu::gles2::GLES2Interface> gl_;
- unsigned query_id_;
- bool is_pending_;
- base::WeakPtrFactory<SyncQuery> weak_ptr_factory_{this};
-};
-
-SyncQueryCollection::SyncQueryCollection(gpu::gles2::GLES2Interface* gl)
- : gl_(gl) {}
-
-SyncQueryCollection::~SyncQueryCollection() = default;
-SyncQueryCollection::SyncQueryCollection(SyncQueryCollection&&) = default;
-SyncQueryCollection& SyncQueryCollection::operator=(SyncQueryCollection&&) =
- default;
-
-scoped_refptr<ResourceFence> SyncQueryCollection::StartNewFrame() {
- // Block until oldest sync query has passed if the number of pending queries
- // ever reach kMaxPendingSyncQueries.
- if (pending_sync_queries_.size() >= kMaxPendingSyncQueries) {
- LOG(ERROR) << "Reached limit of pending sync queries.";
-
- pending_sync_queries_.front()->Wait();
- DCHECK(!pending_sync_queries_.front()->IsPending());
- }
-
- while (!pending_sync_queries_.empty()) {
- if (pending_sync_queries_.front()->IsPending())
- break;
-
- available_sync_queries_.push_back(cc::PopFront(&pending_sync_queries_));
- }
-
- current_sync_query_ = available_sync_queries_.empty()
- ? std::make_unique<SyncQuery>(gl_)
- : cc::PopFront(&available_sync_queries_);
-
- return current_sync_query_->Begin();
-}
-
-void SyncQueryCollection::EndCurrentFrame() {
- DCHECK(current_sync_query_);
- current_sync_query_->End();
- pending_sync_queries_.push_back(std::move(current_sync_query_));
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/sync_query_collection.h b/chromium/components/viz/service/display/sync_query_collection.h
deleted file mode 100644
index fd09cbba6d4..00000000000
--- a/chromium/components/viz/service/display/sync_query_collection.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SYNC_QUERY_COLLECTION_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_SYNC_QUERY_COLLECTION_H_
-
-#include <memory>
-
-#include "base/containers/circular_deque.h"
-#include "base/memory/raw_ptr.h"
-#include "base/memory/ref_counted.h"
-
-namespace gpu {
-namespace gles2 {
-class GLES2Interface;
-}
-} // namespace gpu
-
-namespace viz {
-class SyncQuery;
-class ResourceFence;
-
-class SyncQueryCollection {
- public:
- explicit SyncQueryCollection(gpu::gles2::GLES2Interface* gl);
- SyncQueryCollection(SyncQueryCollection&&);
- SyncQueryCollection& operator=(SyncQueryCollection&&);
- ~SyncQueryCollection();
- scoped_refptr<ResourceFence> StartNewFrame();
- void EndCurrentFrame();
-
- private:
- base::circular_deque<std::unique_ptr<SyncQuery>> pending_sync_queries_;
- base::circular_deque<std::unique_ptr<SyncQuery>> available_sync_queries_;
- std::unique_ptr<SyncQuery> current_sync_query_;
- raw_ptr<gpu::gles2::GLES2Interface> gl_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SYNC_QUERY_COLLECTION_H_
diff --git a/chromium/components/viz/service/display/texture_deleter.cc b/chromium/components/viz/service/display/texture_deleter.cc
deleted file mode 100644
index 76e2cf0b0f8..00000000000
--- a/chromium/components/viz/service/display/texture_deleter.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/texture_deleter.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/memory/weak_ptr.h"
-#include "base/task/bind_post_task.h"
-#include "base/task/single_thread_task_runner.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "gpu/command_buffer/client/shared_image_interface.h"
-#include "gpu/command_buffer/common/mailbox.h"
-#include "gpu/command_buffer/common/sync_token.h"
-
-namespace viz {
-
-static void DeleteTextureOnImplThread(
- const scoped_refptr<ContextProvider>& context_provider,
- const gpu::Mailbox& mailbox,
- const gpu::SyncToken& sync_token,
- bool is_lost) {
- context_provider->SharedImageInterface()->DestroySharedImage(sync_token,
- mailbox);
-}
-
-TextureDeleter::TextureDeleter(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : impl_task_runner_(std::move(task_runner)) {}
-
-TextureDeleter::~TextureDeleter() {
- for (auto& callback : impl_callbacks_)
- std::move(*callback).Run(gpu::SyncToken(), /*is_lost=*/true);
-}
-
-ReleaseCallback TextureDeleter::GetReleaseCallback(
- scoped_refptr<ContextProvider> context_provider,
- const gpu::Mailbox& mailbox) {
- // This callback owns the |context_provider|. It must be destroyed on the impl
- // thread. Upon destruction of this class, the callback must immediately be
- // destroyed.
- auto impl_callback = std::make_unique<ReleaseCallback>(base::BindOnce(
- &DeleteTextureOnImplThread, std::move(context_provider), mailbox));
-
- impl_callbacks_.push_back(std::move(impl_callback));
-
- // The raw pointer to the impl-side callback is valid as long as this
- // class is alive. So we guard it with a WeakPtr.
- ReleaseCallback run_impl_callback = base::BindOnce(
- &TextureDeleter::RunDeleteTextureOnImplThread,
- weak_ptr_factory_.GetWeakPtr(), impl_callbacks_.back().get());
-
- // Provide a callback for the main thread that posts back to the impl
- // thread.
- ReleaseCallback main_callback;
- if (impl_task_runner_) {
- main_callback =
- base::BindPostTask(impl_task_runner_, std::move(run_impl_callback));
- } else {
- main_callback = std::move(run_impl_callback);
- }
-
- return main_callback;
-}
-
-void TextureDeleter::RunDeleteTextureOnImplThread(
- ReleaseCallback* impl_callback,
- const gpu::SyncToken& sync_token,
- bool is_lost) {
- for (size_t i = 0; i < impl_callbacks_.size(); ++i) {
- if (impl_callbacks_[i].get() == impl_callback) {
- // Run the callback, then destroy it here on the impl thread.
- std::move(*impl_callbacks_[i]).Run(sync_token, is_lost);
- impl_callbacks_.erase(impl_callbacks_.begin() + i);
- return;
- }
- }
-
- NOTREACHED() << "The Callback returned by GetDeleteCallback() was called "
- << "more than once.";
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display/texture_deleter.h b/chromium/components/viz/service/display/texture_deleter.h
deleted file mode 100644
index eadcd3dbcc2..00000000000
--- a/chromium/components/viz/service/display/texture_deleter.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_TEXTURE_DELETER_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_TEXTURE_DELETER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "components/viz/common/resources/release_callback.h"
-#include "components/viz/service/viz_service_export.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace gpu {
-struct Mailbox;
-struct SyncToken;
-}
-
-namespace viz {
-class ContextProvider;
-
-class VIZ_SERVICE_EXPORT TextureDeleter {
- public:
- // task_runner corresponds with the thread the delete task should be posted
- // to. If null, the delete will happen on the calling thread.
- explicit TextureDeleter(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner);
-
- TextureDeleter(const TextureDeleter&) = delete;
- TextureDeleter& operator=(const TextureDeleter&) = delete;
-
- ~TextureDeleter();
-
- // Returns a Callback that can be used as the ReleaseCallback for a
- // |texture_id|. The ReleaseCallback can be passed to other threads and will
- // destroy the texture, once it is run, on the impl thread. If the
- // TextureDeleter is destroyed due to the compositor shutting down, then the
- // ReleaseCallback will become a no-op and the texture will be deleted
- // immediately on the impl thread, along with dropping the reference to the
- // ContextProvider.
- ReleaseCallback GetReleaseCallback(
- scoped_refptr<ContextProvider> context_provider,
- const gpu::Mailbox& mailbox);
-
- private:
- // Runs the |impl_callback| to delete the texture and removes the callback
- // from the |impl_callbacks_| list.
- void RunDeleteTextureOnImplThread(ReleaseCallback* impl_callback,
- const gpu::SyncToken& sync_token,
- bool is_lost);
-
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
- std::vector<std::unique_ptr<ReleaseCallback>> impl_callbacks_;
- base::WeakPtrFactory<TextureDeleter> weak_ptr_factory_{this};
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_TEXTURE_DELETER_H_
diff --git a/chromium/components/viz/service/display/texture_deleter_unittest.cc b/chromium/components/viz/service/display/texture_deleter_unittest.cc
deleted file mode 100644
index e1df0821e0c..00000000000
--- a/chromium/components/viz/service/display/texture_deleter_unittest.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/texture_deleter.h"
-
-#include <utility>
-
-#include "base/task/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/viz/common/resources/release_callback.h"
-#include "components/viz/test/test_context_provider.h"
-#include "gpu/command_buffer/client/shared_image_interface.h"
-#include "gpu/command_buffer/common/shared_image_usage.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/color_space.h"
-
-namespace viz {
-namespace {
-
-TEST(TextureDeleterTest, Destroy) {
- auto deleter =
- std::make_unique<TextureDeleter>(base::ThreadTaskRunnerHandle::Get());
-
- scoped_refptr<TestContextProvider> context_provider =
- TestContextProvider::Create();
- context_provider->BindToCurrentThread();
-
- auto* sii = context_provider->SharedImageInterface();
-
- gpu::Mailbox mailbox = sii->CreateSharedImage(
- ResourceFormat::RGBA_8888, gfx::Size(1, 1), gfx::ColorSpace(),
- kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
- gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
-
- EXPECT_TRUE(context_provider->HasOneRef());
- EXPECT_EQ(1u, sii->shared_image_count());
-
- ReleaseCallback cb = deleter->GetReleaseCallback(context_provider, mailbox);
- EXPECT_FALSE(context_provider->HasOneRef());
- EXPECT_EQ(1u, sii->shared_image_count());
-
- // When the deleter is destroyed, it immediately drops its ref on the
- // ContextProvider, and deletes the shared image.
- deleter = nullptr;
- EXPECT_TRUE(context_provider->HasOneRef());
- EXPECT_EQ(0u, sii->shared_image_count());
-
- // Run the scoped release callback before destroying it, but it won't do
- // anything.
- std::move(cb).Run(gpu::SyncToken(), false);
-}
-
-TEST(TextureDeleterTest, NullTaskRunner) {
- auto deleter = std::make_unique<TextureDeleter>(nullptr);
-
- scoped_refptr<TestContextProvider> context_provider =
- TestContextProvider::Create();
- context_provider->BindToCurrentThread();
-
- auto* sii = context_provider->SharedImageInterface();
-
- gpu::Mailbox mailbox = sii->CreateSharedImage(
- ResourceFormat::RGBA_8888, gfx::Size(1, 1), gfx::ColorSpace(),
- kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType,
- gpu::SHARED_IMAGE_USAGE_GLES2, gpu::kNullSurfaceHandle);
-
- EXPECT_TRUE(context_provider->HasOneRef());
- EXPECT_EQ(1u, sii->shared_image_count());
-
- ReleaseCallback cb = deleter->GetReleaseCallback(context_provider, mailbox);
- EXPECT_FALSE(context_provider->HasOneRef());
- EXPECT_EQ(1u, sii->shared_image_count());
-
- std::move(cb).Run(gpu::SyncToken(), false);
-
- // With no task runner the callback will immediately drops its ref on the
- // ContextProvider and delete the shared image.
- EXPECT_TRUE(context_provider->HasOneRef());
- EXPECT_EQ(0u, sii->shared_image_count());
-}
-
-} // namespace
-} // namespace viz
diff --git a/chromium/components/viz/service/display/viz_pixel_test.cc b/chromium/components/viz/service/display/viz_pixel_test.cc
index c68d0e6448d..c3076fa3b23 100644
--- a/chromium/components/viz/service/display/viz_pixel_test.cc
+++ b/chromium/components/viz/service/display/viz_pixel_test.cc
@@ -30,9 +30,6 @@ void VizPixelTest::SetUp() {
case RendererType::kSoftware:
SetUpSoftwareRenderer();
break;
- case RendererType::kGL:
- SetUpGLRenderer(GetSurfaceOrigin());
- break;
case RendererType::kSkiaGL:
case RendererType::kSkiaVk:
case RendererType::kSkiaDawn:
diff --git a/chromium/components/viz/service/display/viz_pixel_test.h b/chromium/components/viz/service/display/viz_pixel_test.h
index ee041e7fe54..5a3ca05d8b6 100644
--- a/chromium/components/viz/service/display/viz_pixel_test.h
+++ b/chromium/components/viz/service/display/viz_pixel_test.h
@@ -33,8 +33,6 @@ class VizPixelTest : public cc::PixelTest {
switch (renderer_type_) {
case RendererType::kSoftware:
return "software";
- case RendererType::kGL:
- return "gl";
case RendererType::kSkiaGL:
case RendererType::kSkiaVk:
return "skia";
@@ -47,8 +45,6 @@ class VizPixelTest : public cc::PixelTest {
return renderer_type_ == RendererType::kSoftware;
}
- bool is_gl_renderer() const { return renderer_type_ == RendererType::kGL; }
-
protected:
static GraphicsBackend RenderTypeToBackend(RendererType renderer_type);
diff --git a/chromium/components/viz/service/display_embedder/DEPS b/chromium/components/viz/service/display_embedder/DEPS
index 4988c8b24d6..c8b25c28439 100644
--- a/chromium/components/viz/service/display_embedder/DEPS
+++ b/chromium/components/viz/service/display_embedder/DEPS
@@ -19,7 +19,9 @@ include_rules = [
"+components/viz/service/display/skia_output_surface.h",
"+components/viz/service/display/software_output_device.h",
"+components/viz/service/gl/gpu_service_impl.h",
- "+gpu/command_buffer/client",
+ "+gpu/command_buffer/client/gpu_memory_buffer_manager.h",
+ "+gpu/command_buffer/client/shared_image_interface.h",
+ "+gpu/command_buffer/client/shared_memory_limits.h",
"+gpu/command_buffer/common",
"+gpu/command_buffer/service",
"+gpu/config",
@@ -45,14 +47,12 @@ include_rules = [
"+ui/ozone/public",
# TODO(danakj): Double check the layering for these dependencies.
- "+components/viz/service/display/gl_renderer_copier.h",
"+components/viz/service/display/overlay_processor.h",
"+components/viz/service/display/overlay_processor_interface.h",
"+components/viz/service/display/overlay_strategy_fullscreen.h",
"+components/viz/service/display/overlay_strategy_single_on_top.h",
"+components/viz/service/display/overlay_strategy_underlay_cast.h",
"+components/viz/service/display/overlay_strategy_underlay.h",
- "+components/viz/service/display/texture_deleter.h",
]
specific_include_rules = {
diff --git a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc
index 6e5914b1614..02db4e3c66c 100644
--- a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc
+++ b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.cc
@@ -47,7 +47,8 @@ std::unique_ptr<CompositorGpuThread> CompositorGpuThread::Create(
// currently always enables this extension, we are adding DCHECK() to ensure
// that instead of enabling/disabling DrDc based on the extension.
if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE)
- DCHECK(gl::GLSurfaceEGL::IsANGLEContextVirtualizationSupported());
+ DCHECK(gl::GLSurfaceEGL::GetGLDisplayEGL()
+ ->IsANGLEContextVirtualizationSupported());
#endif
scoped_refptr<VulkanContextProvider> vulkan_context_provider;
@@ -113,8 +114,12 @@ CompositorGpuThread::GetSharedContextState() {
const bool use_passthrough_decoder =
gpu::gles2::PassthroughCommandDecoderSupported() &&
gpu_preferences.use_passthrough_cmd_decoder;
+ gpu::ContextCreationAttribs attribs_helper;
+ attribs_helper.context_type = features::UseGles2ForOopR()
+ ? gpu::CONTEXT_TYPE_OPENGLES2
+ : gpu::CONTEXT_TYPE_OPENGLES3;
gl::GLContextAttribs attribs = gpu::gles2::GenerateGLContextAttribs(
- gpu::ContextCreationAttribs(), use_passthrough_decoder);
+ attribs_helper, use_passthrough_decoder);
attribs.angle_context_virtualization_group_number =
gl::AngleContextVirtualizationGroup::kDrDc;
@@ -186,6 +191,17 @@ bool CompositorGpuThread::Initialize() {
return init_succeded_;
}
+void CompositorGpuThread::HandleMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+ DCHECK(task_runner()->BelongsToCurrentThread());
+
+ // Context should be current for cache/memory cleanup.
+ if (shared_context_state_ &&
+ shared_context_state_->MakeCurrent(nullptr, /*needs_gl=*/true)) {
+ shared_context_state_->PurgeMemory(memory_pressure_level);
+ }
+}
+
void CompositorGpuThread::Init() {
const auto& gpu_preferences = gpu_channel_manager_->gpu_preferences();
if (enable_watchdog_) {
@@ -196,10 +212,20 @@ void CompositorGpuThread::Init() {
if (!watchdog_thread_)
return;
watchdog_thread_->OnInitComplete();
+
+ // Making sure to create the |memory_pressure_listener_| on
+ // CompositorGpuThread since this callback will be called on the thread it was
+ // created on.
+ memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
+ FROM_HERE, base::BindRepeating(&CompositorGpuThread::HandleMemoryPressure,
+ base::Unretained(this))),
init_succeded_ = true;
}
void CompositorGpuThread::CleanUp() {
+ // Destroying |memory_pressure_listener_| here to ensure its destroyed on the
+ // same thread on which it was created on.
+ memory_pressure_listener_.reset();
if (watchdog_thread_)
watchdog_thread_->OnGpuProcessTearDown();
diff --git a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h
index 7ca40835ddf..f23c4e05233 100644
--- a/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h
+++ b/chromium/components/viz/service/display_embedder/compositor_gpu_thread.h
@@ -7,6 +7,7 @@
#include <memory>
+#include "base/memory/memory_pressure_listener.h"
#include "base/memory/raw_ptr.h"
#include "base/threading/thread.h"
#include "components/viz/service/viz_service_export.h"
@@ -67,6 +68,9 @@ class VIZ_SERVICE_EXPORT CompositorGpuThread
bool Initialize();
+ void HandleMemoryPressure(
+ base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
raw_ptr<gpu::GpuChannelManager> gpu_channel_manager_;
const bool enable_watchdog_;
bool init_succeded_ = false;
@@ -80,6 +84,14 @@ class VIZ_SERVICE_EXPORT CompositorGpuThread
std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread_;
scoped_refptr<gpu::SharedContextState> shared_context_state_;
+ // To start listening memory pressure signals from the platform, we create a
+ // new instance of MemoryPressureListener, passing a callback to a
+ // function that takes a MemoryPressureLevel parameter.To stop listening,
+ // simply delete the listener object. The implementation guarantees
+ // that the callback will always be called on the thread that created
+ // the listener.
+ std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
base::WeakPtrFactory<CompositorGpuThread> weak_ptr_factory_;
};
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.cc b/chromium/components/viz/service/display_embedder/gl_output_surface.cc
deleted file mode 100644
index 182bfc70aa9..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface.cc
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "cc/base/math_util.h"
-#include "components/viz/common/frame_sinks/begin_frame_source.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/service/display/output_surface_client.h"
-#include "components/viz/service/display/output_surface_frame.h"
-#include "components/viz/service/display/renderer_utils.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
-#include "gpu/command_buffer/common/swap_buffers_flags.h"
-#include "gpu/config/gpu_feature_info.h"
-#include "ui/gfx/buffer_format_util.h"
-#include "ui/gfx/overlay_transform_utils.h"
-
-namespace viz {
-
-GLOutputSurface::GLOutputSurface(
- scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle)
- : OutputSurface(context_provider),
- viz_context_provider_(context_provider),
- surface_handle_(surface_handle),
- use_gpu_fence_(
- context_provider->ContextCapabilities().chromium_gpu_fence &&
- context_provider->ContextCapabilities()
- .use_gpu_fences_for_overlay_planes) {
- const auto& context_capabilities = context_provider->ContextCapabilities();
- capabilities_.output_surface_origin = context_capabilities.surface_origin;
- capabilities_.supports_stencil = context_capabilities.num_stencil_bits > 0;
- // Since one of the buffers is used by the surface for presentation, there can
- // be at most |num_surface_buffers - 1| pending buffers that the compositor
- // can use.
- capabilities_.pending_swap_params.max_pending_swaps =
- context_capabilities.num_surface_buffers - 1;
- capabilities_.supports_gpu_vsync = context_capabilities.gpu_vsync;
- capabilities_.supports_dc_layers = context_capabilities.dc_layers;
- capabilities_.supports_surfaceless = context_capabilities.surfaceless;
- capabilities_.android_surface_control_feature_enabled =
- context_provider->GetGpuFeatureInfo()
- .status_values[gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] ==
- gpu::kGpuFeatureStatusEnabled;
- capabilities_.max_render_target_size = context_capabilities.max_texture_size;
-}
-
-GLOutputSurface::~GLOutputSurface() {
- viz_context_provider_->SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback());
- viz_context_provider_->SetGpuVSyncCallback(GpuVSyncCallback());
- if (gpu_fence_id_ > 0)
- context_provider()->ContextGL()->DestroyGpuFenceCHROMIUM(gpu_fence_id_);
-}
-
-void GLOutputSurface::BindToClient(OutputSurfaceClient* client) {
- DCHECK(client);
- DCHECK(!client_);
- client_ = client;
-}
-
-void GLOutputSurface::EnsureBackbuffer() {}
-
-void GLOutputSurface::DiscardBackbuffer() {
- context_provider()->ContextGL()->DiscardBackbufferCHROMIUM();
-}
-
-void GLOutputSurface::BindFramebuffer() {
- context_provider()->ContextGL()->BindFramebuffer(GL_FRAMEBUFFER, 0);
-}
-
-void GLOutputSurface::SetDrawRectangle(const gfx::Rect& rect) {
- DCHECK(capabilities_.supports_dc_layers);
-
- if (set_draw_rectangle_for_frame_)
- return;
- DCHECK(gfx::Rect(size_).Contains(rect));
- DCHECK(has_set_draw_rectangle_since_last_resize_ ||
- (gfx::Rect(size_) == rect));
- set_draw_rectangle_for_frame_ = true;
- has_set_draw_rectangle_since_last_resize_ = true;
- context_provider()->ContextGL()->SetDrawRectangleCHROMIUM(
- rect.x(), rect.y(), rect.width(), rect.height());
-}
-
-void GLOutputSurface::SetEnableDCLayers(bool enable) {
- DCHECK(capabilities_.supports_dc_layers);
- context_provider()->ContextGL()->SetEnableDCLayersCHROMIUM(enable);
-}
-
-void GLOutputSurface::Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) {
- size_ = size;
- has_set_draw_rectangle_since_last_resize_ = false;
- set_draw_rectangle_for_frame_ = false;
- context_provider()->ContextGL()->ResizeCHROMIUM(
- size.width(), size.height(), device_scale_factor,
- color_space.AsGLColorSpace(), gfx::AlphaBitsForBufferFormat(format));
-}
-
-void GLOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
- DCHECK(context_provider_);
-
- uint32_t flags = 0;
- if (wants_vsync_parameter_updates_)
- flags |= gpu::SwapBuffersFlags::kVSyncParams;
-
- // The |swap_size| here should always be in the UI's logical screen space
- // since it is forwarded to the client code which is unaware of the display
- // transform optimization.
- gfx::Size swap_size = ApplyDisplayInverse(gfx::Rect(size_)).size();
- auto swap_callback = base::BindOnce(
- &GLOutputSurface::OnGpuSwapBuffersCompleted,
- weak_ptr_factory_.GetWeakPtr(), std::move(frame.latency_info),
- frame.top_controls_visible_height_changed, swap_size);
- gpu::ContextSupport::PresentationCallback presentation_callback;
- presentation_callback = base::BindOnce(&GLOutputSurface::OnPresentation,
- weak_ptr_factory_.GetWeakPtr());
-
- set_draw_rectangle_for_frame_ = false;
- if (frame.sub_buffer_rect) {
- HandlePartialSwap(*frame.sub_buffer_rect, flags, std::move(swap_callback),
- std::move(presentation_callback));
- } else if (!frame.content_bounds.empty()) {
- context_provider_->ContextSupport()->SwapWithBounds(
- frame.content_bounds, flags, std::move(swap_callback),
- std::move(presentation_callback));
- } else {
- context_provider_->ContextSupport()->Swap(flags, std::move(swap_callback),
- std::move(presentation_callback));
- }
-}
-
-uint32_t GLOutputSurface::GetFramebufferCopyTextureFormat() {
- auto* gl = static_cast<VizProcessContextProvider*>(context_provider());
- return gl->GetCopyTextureInternalFormat();
-}
-
-bool GLOutputSurface::IsDisplayedAsOverlayPlane() const {
- return false;
-}
-
-unsigned GLOutputSurface::GetOverlayTextureId() const {
- return 0;
-}
-
-bool GLOutputSurface::HasExternalStencilTest() const {
- return false;
-}
-
-void GLOutputSurface::ApplyExternalStencil() {}
-
-void GLOutputSurface::DidReceiveSwapBuffersAck(
- const gfx::SwapResponse& response,
- gfx::GpuFenceHandle release_fence) {
- client_->DidReceiveSwapBuffersAck(response.timings, std::move(release_fence));
-}
-
-void GLOutputSurface::HandlePartialSwap(
- const gfx::Rect& sub_buffer_rect,
- uint32_t flags,
- gpu::ContextSupport::SwapCompletedCallback swap_callback,
- gpu::ContextSupport::PresentationCallback presentation_callback) {
- context_provider_->ContextSupport()->PartialSwapBuffers(
- sub_buffer_rect, flags, std::move(swap_callback),
- std::move(presentation_callback));
-}
-
-void GLOutputSurface::OnGpuSwapBuffersCompleted(
- std::vector<ui::LatencyInfo> latency_info,
- bool top_controls_visible_height_changed,
- const gfx::Size& pixel_size,
- const gpu::SwapBuffersCompleteParams& params,
- gfx::GpuFenceHandle release_fence) {
- if (!params.texture_in_use_responses.empty())
- client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses);
- if (!params.ca_layer_params.is_empty)
- client_->DidReceiveCALayerParams(params.ca_layer_params);
- DidReceiveSwapBuffersAck(params.swap_response, std::move(release_fence));
-
- UpdateLatencyInfoOnSwap(params.swap_response, &latency_info);
- latency_tracker_.OnGpuSwapBuffersCompleted(
- std::move(latency_info), top_controls_visible_height_changed);
-
- if (needs_swap_size_notifications_)
- client_->DidSwapWithSize(pixel_size);
-}
-
-void GLOutputSurface::OnPresentation(
- const gfx::PresentationFeedback& feedback) {
- client_->DidReceivePresentationFeedback(feedback);
-}
-
-unsigned GLOutputSurface::UpdateGpuFence() {
- if (!use_gpu_fence_)
- return 0;
-
- if (gpu_fence_id_ > 0)
- context_provider()->ContextGL()->DestroyGpuFenceCHROMIUM(gpu_fence_id_);
-
- gpu_fence_id_ = context_provider()->ContextGL()->CreateGpuFenceCHROMIUM();
-
- return gpu_fence_id_;
-}
-
-void GLOutputSurface::SetNeedsSwapSizeNotifications(
- bool needs_swap_size_notifications) {
- needs_swap_size_notifications_ = needs_swap_size_notifications;
-}
-
-void GLOutputSurface::SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback) {
- wants_vsync_parameter_updates_ = !callback.is_null();
- viz_context_provider_->SetUpdateVSyncParametersCallback(std::move(callback));
-}
-
-void GLOutputSurface::SetGpuVSyncCallback(GpuVSyncCallback callback) {
- DCHECK(capabilities_.supports_gpu_vsync);
- viz_context_provider_->SetGpuVSyncCallback(std::move(callback));
-}
-
-void GLOutputSurface::SetGpuVSyncEnabled(bool enabled) {
- DCHECK(capabilities_.supports_gpu_vsync);
- viz_context_provider_->SetGpuVSyncEnabled(enabled);
-}
-
-gfx::OverlayTransform GLOutputSurface::GetDisplayTransform() {
- return gfx::OVERLAY_TRANSFORM_NONE;
-}
-
-gfx::Rect GLOutputSurface::ApplyDisplayInverse(const gfx::Rect& input) {
- gfx::Transform display_inverse = gfx::OverlayTransformToTransform(
- gfx::InvertOverlayTransform(GetDisplayTransform()), gfx::SizeF(size_));
- return cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
- display_inverse, input);
-}
-
-base::ScopedClosureRunner GLOutputSurface::GetCacheBackBufferCb() {
- return viz_context_provider_->GetCacheBackBufferCb();
-}
-
-gpu::SurfaceHandle GLOutputSurface::GetSurfaceHandle() const {
- return surface_handle_;
-}
-
-void GLOutputSurface::SetFrameRate(float frame_rate) {
- viz_context_provider_->ContextSupport()->SetFrameRate(frame_rate);
-}
-
-void GLOutputSurface::SetNeedsMeasureNextDrawLatency() {
- viz_context_provider_->SetNeedsMeasureNextDrawLatency();
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.h b/chromium/components/viz/service/display_embedder/gl_output_surface.h
deleted file mode 100644
index c611894a647..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/callback_helpers.h"
-#include "base/memory/raw_ptr.h"
-#include "components/viz/common/display/update_vsync_parameters_callback.h"
-#include "components/viz/service/display/output_surface.h"
-#include "components/viz/service/display_embedder/viz_process_context_provider.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "ui/latency/latency_tracker.h"
-
-namespace viz {
-
-// An OutputSurface implementation that directly draws and
-// swaps to an actual GL surface.
-class GLOutputSurface : public OutputSurface {
- public:
- GLOutputSurface(scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle);
- ~GLOutputSurface() override;
-
- // OutputSurface implementation
- void BindToClient(OutputSurfaceClient* client) override;
- void EnsureBackbuffer() override;
- void DiscardBackbuffer() override;
- void BindFramebuffer() override;
- void SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
- void SetEnableDCLayers(bool enabled) override;
- void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) override;
- void SwapBuffers(OutputSurfaceFrame frame) override;
- uint32_t GetFramebufferCopyTextureFormat() override;
- bool IsDisplayedAsOverlayPlane() const override;
- unsigned GetOverlayTextureId() const override;
- bool HasExternalStencilTest() const override;
- void ApplyExternalStencil() override;
- unsigned UpdateGpuFence() override;
- void SetNeedsSwapSizeNotifications(
- bool needs_swap_size_notifications) override;
- void SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback) override;
- void SetGpuVSyncCallback(GpuVSyncCallback callback) override;
- void SetGpuVSyncEnabled(bool enabled) override;
- void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
- gfx::OverlayTransform GetDisplayTransform() override;
- base::ScopedClosureRunner GetCacheBackBufferCb() override;
-
- gpu::SurfaceHandle GetSurfaceHandle() const override;
- void SetFrameRate(float frame_rate) override;
- void SetNeedsMeasureNextDrawLatency() override;
-
- protected:
- OutputSurfaceClient* client() const { return client_; }
- ui::LatencyTracker* latency_tracker() { return &latency_tracker_; }
- bool needs_swap_size_notifications() {
- return needs_swap_size_notifications_;
- }
-
- // Called when a swap completion is signaled from ImageTransportSurface.
- virtual void DidReceiveSwapBuffersAck(const gfx::SwapResponse& response,
- gfx::GpuFenceHandle release_fence);
-
- // Called in SwapBuffers() when a swap is determined to be partial. Subclasses
- // might override this method because different platforms handle partial swaps
- // differently.
- virtual void HandlePartialSwap(
- const gfx::Rect& sub_buffer_rect,
- uint32_t flags,
- gpu::ContextSupport::SwapCompletedCallback swap_callback,
- gpu::ContextSupport::PresentationCallback presentation_callback);
-
- private:
- // Called when a swap completion is signaled from ImageTransportSurface.
- void OnGpuSwapBuffersCompleted(std::vector<ui::LatencyInfo> latency_info,
- bool top_controls_visible_height_changed,
- const gfx::Size& pixel_size,
- const gpu::SwapBuffersCompleteParams& params,
- gfx::GpuFenceHandle release_fence);
- void OnPresentation(const gfx::PresentationFeedback& feedback);
- void OnGpuVSync(base::TimeTicks vsync_time, base::TimeDelta vsync_interval);
- gfx::Rect ApplyDisplayInverse(const gfx::Rect& input);
-
- scoped_refptr<VizProcessContextProvider> viz_context_provider_;
- raw_ptr<OutputSurfaceClient> client_ = nullptr;
- bool wants_vsync_parameter_updates_ = false;
- ui::LatencyTracker latency_tracker_;
-
- const gpu::SurfaceHandle surface_handle_;
-
- bool set_draw_rectangle_for_frame_ = false;
- // True if the draw rectangle has been set at all since the last resize.
- bool has_set_draw_rectangle_since_last_resize_ = false;
- gfx::Size size_;
- bool use_gpu_fence_;
- unsigned gpu_fence_id_ = 0;
- // Whether to send OutputSurfaceClient::DidSwapWithSize notifications.
- bool needs_swap_size_notifications_ = false;
-
- base::WeakPtrFactory<GLOutputSurface> weak_ptr_factory_{this};
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_H_
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_android.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_android.cc
deleted file mode 100644
index 741facb6742..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_android.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface_android.h"
-
-namespace viz {
-
-GLOutputSurfaceAndroid::GLOutputSurfaceAndroid(
- scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle)
- : GLOutputSurface(context_provider, surface_handle) {}
-
-GLOutputSurfaceAndroid::~GLOutputSurfaceAndroid() = default;
-
-void GLOutputSurfaceAndroid::HandlePartialSwap(
- const gfx::Rect& sub_buffer_rect,
- uint32_t flags,
- gpu::ContextSupport::SwapCompletedCallback swap_callback,
- gpu::ContextSupport::PresentationCallback presentation_callback) {
- DCHECK(sub_buffer_rect.IsEmpty());
- context_provider_->ContextSupport()->CommitOverlayPlanes(
- flags, std::move(swap_callback), std::move(presentation_callback));
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_android.h b/chromium/components/viz/service/display_embedder/gl_output_surface_android.h
deleted file mode 100644
index 8ad4a4326a9..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_android.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_ANDROID_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_ANDROID_H_
-
-#include "components/viz/service/display_embedder/gl_output_surface.h"
-
-namespace viz {
-class GLOutputSurfaceAndroid : public GLOutputSurface {
- public:
- GLOutputSurfaceAndroid(
- scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle);
-
- GLOutputSurfaceAndroid(const GLOutputSurfaceAndroid&) = delete;
- GLOutputSurfaceAndroid& operator=(const GLOutputSurfaceAndroid&) = delete;
-
- ~GLOutputSurfaceAndroid() override;
-
- // GLOutputSurface implementation:
- void HandlePartialSwap(
- const gfx::Rect& sub_buffer_rect,
- uint32_t flags,
- gpu::ContextSupport::SwapCompletedCallback swap_callback,
- gpu::ContextSupport::PresentationCallback presentation_callback) override;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_ANDROID_H_
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
deleted file mode 100644
index 6641808ac3e..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
+++ /dev/null
@@ -1,314 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/logging.h"
-#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
-#include "components/viz/common/frame_sinks/begin_frame_source.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/switches.h"
-#include "components/viz/service/display/output_surface_client.h"
-#include "components/viz/service/display/output_surface_frame.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
-#include "gpu/command_buffer/common/sync_token.h"
-#include "ui/gl/buffer_format_utils.h"
-#include "ui/gl/gl_enums.h"
-#include "ui/gl/gl_fence.h"
-
-namespace viz {
-
-GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue(
- scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle,
- std::unique_ptr<BufferQueue> buffer_queue)
- : GLOutputSurface(context_provider, surface_handle),
- buffer_queue_(std::move(buffer_queue)) {
- capabilities_.only_invalidates_damage_rect = false;
- capabilities_.uses_default_gl_framebuffer = false;
- capabilities_.output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
- // Set |max_pending_swaps| to 2 for buffer_queue, which aligns scheduling
- // more closely with the previous surfaced behavior.
- // With a surface, swap buffer ack used to return early, before actually
- // presenting the back buffer, enabling the browser compositor to run ahead.
- // BufferQueue implementation acks at the time of actual buffer swap, which
- // shifts the start of the new frame forward relative to the old
- // implementation.
- capabilities_.pending_swap_params.max_pending_swaps = 2;
- // GetCurrentFramebufferDamage will return an upper bound of the part of the
- // buffer that needs to be recomposited.
-#if BUILDFLAG(IS_APPLE)
- capabilities_.supports_target_damage = false;
-#else
- capabilities_.supports_target_damage = true;
-#endif
- // Force the number of max pending frames to one when the switch
- // "double-buffer-compositing" is passed.
- // This will keep compositing in double buffered mode assuming |buffer_queue_|
- // allocates at most one additional buffer.
- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
- if (command_line->HasSwitch(switches::kDoubleBufferCompositing)) {
- capabilities_.pending_swap_params.max_pending_swaps = 1;
- buffer_queue_->SetMaxBuffers(2);
- }
-
- // It is safe to pass a raw pointer to *this because |buffer_queue_| is fully
- // owned and it doesn't use the SyncTokenProvider after it's destroyed.
- DCHECK(buffer_queue_);
- buffer_queue_->SetSyncTokenProvider(this);
- context_provider_->ContextGL()->GenFramebuffers(1, &fbo_);
-}
-
-GLOutputSurfaceBufferQueue::~GLOutputSurfaceBufferQueue() {
- auto* gl = context_provider_->ContextGL();
- DCHECK_NE(0u, fbo_);
- gl->DeleteFramebuffers(1, &fbo_);
- if (stencil_buffer_)
- gl->DeleteRenderbuffers(1, &stencil_buffer_);
- for (const auto& buffer_texture : buffer_queue_textures_)
- gl->DeleteTextures(1u, &buffer_texture.second);
- buffer_queue_textures_.clear();
- current_texture_ = 0u;
- last_bound_texture_ = 0u;
- last_bound_mailbox_.SetZero();
-
- // Freeing the BufferQueue here ensures that *this is fully alive in case the
- // BufferQueue needs the SyncTokenProvider functionality.
- buffer_queue_.reset();
- fbo_ = 0u;
- stencil_buffer_ = 0u;
-}
-
-void GLOutputSurfaceBufferQueue::BindFramebuffer() {
- auto* gl = context_provider_->ContextGL();
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
-
- // If we have a |current_texture_|, it means we haven't swapped the buffer, so
- // we're just wanting to rebind the GL framebuffer.
- if (current_texture_)
- return;
-
- DCHECK(buffer_queue_);
- gpu::SyncToken creation_sync_token;
- gfx::GpuFenceHandle release_fence;
- const gpu::Mailbox current_buffer =
- buffer_queue_->GetCurrentBuffer(&creation_sync_token, &release_fence);
- if (current_buffer.IsZero())
- return;
- gl->WaitSyncTokenCHROMIUM(creation_sync_token.GetConstData());
- if (!release_fence.is_null()) {
- auto fence = gfx::GpuFence(std::move(release_fence));
- if (gl::GLFence::IsGpuFenceSupported()) {
- auto id = gl->CreateClientGpuFenceCHROMIUM(fence.AsClientGpuFence());
- gl->WaitGpuFenceCHROMIUM(id);
- gl->DestroyGpuFenceCHROMIUM(id);
- } else {
- fence.Wait();
- }
- }
- unsigned& buffer_texture = buffer_queue_textures_[current_buffer];
- if (!buffer_texture) {
- buffer_texture =
- gl->CreateAndTexStorage2DSharedImageCHROMIUM(current_buffer.name);
- }
- current_texture_ = buffer_texture;
- gl->BeginSharedImageAccessDirectCHROMIUM(
- current_texture_, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- texture_target_, current_texture_, 0);
- last_bound_texture_ = current_texture_;
- last_bound_mailbox_ = current_buffer;
-
-#if DCHECK_IS_ON() && BUILDFLAG(IS_CHROMEOS_ASH)
- const GLenum result = gl->CheckFramebufferStatus(GL_FRAMEBUFFER);
- if (result != GL_FRAMEBUFFER_COMPLETE)
- DLOG(ERROR) << " Incomplete fb: " << gl::GLEnums::GetStringError(result);
-#endif
-
- // Reshape() must be called to go from using a stencil buffer to not using it.
- DCHECK(use_stencil_ || !stencil_buffer_);
- if (use_stencil_ && !stencil_buffer_) {
- gl->GenRenderbuffers(1, &stencil_buffer_);
- CHECK_NE(stencil_buffer_, 0u);
- gl->BindRenderbuffer(GL_RENDERBUFFER, stencil_buffer_);
- gl->RenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
- reshape_size_.width(), reshape_size_.height());
- gl->BindRenderbuffer(GL_RENDERBUFFER, 0);
- gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, stencil_buffer_);
- }
-}
-
-// We call this on every frame that a value changes, but changing the size once
-// we've allocated backing NativePixmapBufferQueue instances will cause a DCHECK
-// because Chrome never Reshape(s) after the first one from (0,0). NB: this
-// implies that screen size changes need to be plumbed differently. In
-// particular, we must create the native window in the size that the hardware
-// reports.
-void GLOutputSurfaceBufferQueue::Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) {
- reshape_size_ = size;
- use_stencil_ = use_stencil;
- GLOutputSurface::Reshape(size, device_scale_factor, color_space, format,
- use_stencil);
- DCHECK(buffer_queue_);
- const bool may_have_freed_buffers =
- buffer_queue_->Reshape(size, color_space, format);
- if (may_have_freed_buffers || (stencil_buffer_ && !use_stencil)) {
- auto* gl = context_provider_->ContextGL();
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
- if (stencil_buffer_) {
- gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, 0);
- gl->DeleteRenderbuffers(1, &stencil_buffer_);
- stencil_buffer_ = 0u;
- }
-
- // Note that |texture_target_| is initially set to 0, and so if it has not
- // been set to a valid value, then no buffers have been allocated.
- if (texture_target_ && may_have_freed_buffers) {
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- texture_target_, 0, 0);
- for (const auto& buffer_texture : buffer_queue_textures_)
- gl->DeleteTextures(1u, &buffer_texture.second);
- buffer_queue_textures_.clear();
- current_texture_ = 0u;
- last_bound_texture_ = 0u;
- last_bound_mailbox_.SetZero();
- }
- }
-
- texture_target_ =
- gpu::GetBufferTextureTarget(gfx::BufferUsage::SCANOUT, format,
- context_provider_->ContextCapabilities());
-}
-
-void GLOutputSurfaceBufferQueue::SwapBuffers(OutputSurfaceFrame frame) {
- DCHECK(buffer_queue_);
-
- // TODO(rjkroege): What if swap happens again before DidReceiveSwapBuffersAck
- // then it would see the wrong size?
- DCHECK(reshape_size_ == frame.size);
- swap_size_ = reshape_size_;
-
- gfx::Rect damage_rect =
- frame.sub_buffer_rect ? *frame.sub_buffer_rect : gfx::Rect(swap_size_);
-
- // If the client is currently drawing, we first end access to the
- // corresponding shared image. Then, we can swap the buffers. That way, we
- // know that whatever GL commands GLOutputSurface::SwapBuffers() emits can
- // access the shared image.
- auto* gl = context_provider_->ContextGL();
- if (current_texture_) {
- gl->EndSharedImageAccessDirectCHROMIUM(current_texture_);
- gl->BindFramebuffer(GL_FRAMEBUFFER, 0u);
- current_texture_ = 0u;
- }
- buffer_queue_->SwapBuffers(damage_rect);
- GLOutputSurface::SwapBuffers(std::move(frame));
-}
-
-gfx::Rect GLOutputSurfaceBufferQueue::GetCurrentFramebufferDamage() const {
- return buffer_queue_->CurrentBufferDamage();
-}
-
-uint32_t GLOutputSurfaceBufferQueue::GetFramebufferCopyTextureFormat() {
- return base::strict_cast<GLenum>(
- gl::BufferFormatToGLInternalFormat(buffer_queue_->buffer_format()));
-}
-
-bool GLOutputSurfaceBufferQueue::IsDisplayedAsOverlayPlane() const {
- return true;
-}
-
-unsigned GLOutputSurfaceBufferQueue::GetOverlayTextureId() const {
- DCHECK(last_bound_texture_);
- return last_bound_texture_;
-}
-
-gpu::Mailbox GLOutputSurfaceBufferQueue::GetOverlayMailbox() const {
- return last_bound_mailbox_;
-}
-
-void GLOutputSurfaceBufferQueue::DidReceiveSwapBuffersAck(
- const gfx::SwapResponse& response,
- gfx::GpuFenceHandle release_fence) {
- bool force_swap = false;
- if (response.result == gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS) {
- // Even through the swap failed, this is a fixable error so we can pretend
- // it succeeded to the rest of the system.
- buffer_queue_->FreeAllSurfaces();
-
- // TODO(andrescj): centralize the logic that deletes the stencil buffer and
- // the textures since we do this in multiple places.
- auto* gl = context_provider_->ContextGL();
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
- if (stencil_buffer_) {
- gl->FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, 0);
- gl->DeleteRenderbuffers(1, &stencil_buffer_);
- stencil_buffer_ = 0u;
- }
-
- // Reshape() must have been called before we got here, so |texture_target_|
- // should contain a valid value.
- DCHECK(texture_target_);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- texture_target_, 0, 0);
- for (const auto& buffer_texture : buffer_queue_textures_)
- gl->DeleteTextures(1u, &buffer_texture.second);
- buffer_queue_textures_.clear();
- current_texture_ = 0u;
- last_bound_texture_ = 0u;
- last_bound_mailbox_.SetZero();
-
- force_swap = true;
- }
-
- buffer_queue_->PageFlipComplete(release_fence.Clone());
- client()->DidReceiveSwapBuffersAck(response.timings,
- std::move(release_fence));
-
- if (force_swap)
- client()->SetNeedsRedrawRect(gfx::Rect(swap_size_));
-}
-
-gpu::SyncToken GLOutputSurfaceBufferQueue::GenSyncToken() {
- // This should only be called as long as the BufferQueue is alive. We cannot
- // use |buffer_queue_| to detect this because in the dtor, |buffer_queue_|
- // becomes nullptr before BufferQueue's dtor is called, so GenSyncToken()
- // would be called after |buffer_queue_| is nullptr when in fact, the
- // BufferQueue is still alive. Hence, we use |fbo_| to detect that the
- // BufferQueue is still alive.
- DCHECK(fbo_);
- gpu::SyncToken sync_token;
- context_provider_->ContextGL()->GenUnverifiedSyncTokenCHROMIUM(
- sync_token.GetData());
- return sync_token;
-}
-
-void GLOutputSurfaceBufferQueue::SetDisplayTransformHint(
- gfx::OverlayTransform transform) {
- display_transform_ = transform;
-
- if (context_provider_)
- context_provider_->ContextSupport()->SetDisplayTransform(transform);
-}
-
-gfx::OverlayTransform GLOutputSurfaceBufferQueue::GetDisplayTransform() {
- return display_transform_;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h
deleted file mode 100644
index 73bcccc0e45..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/containers/flat_map.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/weak_ptr.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/service/display/output_surface.h"
-#include "components/viz/service/display_embedder/buffer_queue.h"
-#include "components/viz/service/display_embedder/gl_output_surface.h"
-#include "components/viz/service/display_embedder/viz_process_context_provider.h"
-#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/common/mailbox.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/swap_result.h"
-#include "ui/gl/gl_surface.h"
-
-namespace viz {
-
-// An OutputSurface implementation that directly draws and swap to a GL
-// "buffer_queue" surface (aka one backed by a buffer managed explicitly).
-class VIZ_SERVICE_EXPORT GLOutputSurfaceBufferQueue
- : public GLOutputSurface,
- public BufferQueue::SyncTokenProvider {
- public:
- GLOutputSurfaceBufferQueue(
- scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle,
- std::unique_ptr<BufferQueue> buffer_queue);
-
- GLOutputSurfaceBufferQueue(const GLOutputSurfaceBufferQueue&) = delete;
- GLOutputSurfaceBufferQueue& operator=(const GLOutputSurfaceBufferQueue&) =
- delete;
-
- ~GLOutputSurfaceBufferQueue() override;
-
- // BufferQueue::SyncTokenProvider implementation.
- gpu::SyncToken GenSyncToken() override;
-
- protected:
- // OutputSurface implementation.
- void SetDisplayTransformHint(gfx::OverlayTransform transform) override;
- gfx::OverlayTransform GetDisplayTransform() override;
- void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) override;
-
- private:
- FRIEND_TEST_ALL_PREFIXES(GLOutputSurfaceBufferQueueTest, HandleSwapNAK);
-
- // OutputSurface implementation.
- void BindFramebuffer() override;
- void SwapBuffers(OutputSurfaceFrame frame) override;
- gfx::Rect GetCurrentFramebufferDamage() const override;
- uint32_t GetFramebufferCopyTextureFormat() override;
- bool IsDisplayedAsOverlayPlane() const override;
- unsigned GetOverlayTextureId() const override;
- gpu::Mailbox GetOverlayMailbox() const override;
-
- // GLOutputSurface:
- void DidReceiveSwapBuffersAck(const gfx::SwapResponse& response,
- gfx::GpuFenceHandle release_fence) override;
-
- std::unique_ptr<BufferQueue> buffer_queue_;
-
- // |buffer_queue_textures_| caches the textures generated by consuming the
- // SharedImage mailboxes from the |buffer_queue_| so that we don't have to
- // generate a new texture every time a shared image is re-used.
- base::flat_map<gpu::Mailbox, unsigned> buffer_queue_textures_;
-
- // |current_texture_| is the texture currently being drawn to. It's one of
- // |buffer_queue_textures_| or 0 if the client is not currently drawing (i.e.,
- // we're not currently in between a BindFramebuffer()/SwapBuffers() pair).
- // |last_bound_texture_| is the texture that was last bound to |fbo_|. It's
- // also one of |buffer_queue_textures_| or 0 if no texture has been bound to
- // |fbo_| or all the buffers in the buffer queue have been freed.
- // |last_bound_mailbox_| is the mailbox corresponding to
- // |last_bound_texture_|.
- //
- // TODO(andrescj): use an RAII pattern to scope access to |current_texture_|
- // because it requires Begin/EndSharedImageAccessDirectCHROMIUM().
- unsigned current_texture_ = 0u;
- unsigned last_bound_texture_ = 0u;
- gpu::Mailbox last_bound_mailbox_;
- unsigned texture_target_ = 0u;
-
- unsigned fbo_ = 0u;
-
- bool use_stencil_ = false;
- unsigned stencil_buffer_ = 0u;
-
- gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
- gfx::Size reshape_size_;
- gfx::Size swap_size_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_H_
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc
deleted file mode 100644
index 3876eadb8fd..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue_unittest.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
-
-#include <utility>
-#include <vector>
-
-#include "base/memory/raw_ptr.h"
-#include "components/viz/service/display/output_surface_client.h"
-#include "components/viz/service/display/output_surface_frame.h"
-#include "components/viz/service/display_embedder/buffer_queue.h"
-#include "components/viz/test/test_context_provider.h"
-#include "components/viz/test/test_context_support.h"
-#include "components/viz/test/test_gles2_interface.h"
-#include "gpu/command_buffer/common/command_buffer_id.h"
-#include "gpu/command_buffer/common/constants.h"
-#include "gpu/command_buffer/common/mailbox.h"
-#include "gpu/command_buffer/common/sync_token.h"
-#include "gpu/ipc/common/surface_handle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/buffer_types.h"
-#include "ui/gfx/swap_result.h"
-
-using testing::_;
-using testing::DoAll;
-using testing::Eq;
-using testing::InSequence;
-using testing::Mock;
-using testing::Ne;
-using testing::NotNull;
-using testing::Pointee;
-using testing::Return;
-using testing::SetArgPointee;
-using testing::StrictMock;
-
-namespace viz {
-namespace {
-
-class TestVizProcessContextProvider : public VizProcessContextProvider {
- public:
- TestVizProcessContextProvider(std::unique_ptr<TestContextSupport> support,
- std::unique_ptr<TestGLES2Interface> gl)
- : support_(std::move(support)), context_gl_(std::move(gl)) {}
- TestVizProcessContextProvider(const TestVizProcessContextProvider&) = delete;
- TestVizProcessContextProvider& operator=(
- const TestVizProcessContextProvider&) = delete;
-
- // ContextProvider implementation.
- gpu::gles2::GLES2Interface* ContextGL() override { return context_gl_.get(); }
- gpu::ContextSupport* ContextSupport() override { return support_.get(); }
- const gpu::Capabilities& ContextCapabilities() const override {
- return gpu_capabilities_;
- }
-
- const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override {
- return gpu_feature_info_;
- }
-
- void SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback) override {}
- void SetGpuVSyncCallback(GpuVSyncCallback callback) override {}
- void SetGpuVSyncEnabled(bool enabled) override {}
- bool UseRGB565PixelFormat() const override { return false; }
- uint32_t GetCopyTextureInternalFormat() override { return 0u; }
- base::ScopedClosureRunner GetCacheBackBufferCb() override {
- return base::ScopedClosureRunner(base::DoNothing());
- }
-
- protected:
- ~TestVizProcessContextProvider() override = default;
-
- private:
- std::unique_ptr<TestContextSupport> support_;
- std::unique_ptr<TestGLES2Interface> context_gl_;
- gpu::Capabilities gpu_capabilities_;
- gpu::GpuFeatureInfo gpu_feature_info_;
-};
-
-class MockGLES2Interface : public TestGLES2Interface {
- public:
- MockGLES2Interface() = default;
- ~MockGLES2Interface() override = default;
-
- MOCK_METHOD2(DeleteTextures, void(GLsizei, const GLuint*));
- MOCK_METHOD2(BindFramebuffer, void(GLenum, GLuint));
- MOCK_METHOD2(GenRenderbuffers, void(GLsizei, GLuint*));
- MOCK_METHOD2(BindRenderbuffer, void(GLenum, GLuint));
- MOCK_METHOD2(DeleteRenderbuffers, void(GLsizei n, const GLuint*));
- MOCK_METHOD1(CreateAndTexStorage2DSharedImageCHROMIUM, GLuint(const GLbyte*));
- MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte*));
- MOCK_METHOD2(BeginSharedImageAccessDirectCHROMIUM, void(GLuint, GLenum));
- MOCK_METHOD1(EndSharedImageAccessDirectCHROMIUM, void(GLuint));
-};
-
-class MockBufferQueue : public BufferQueue {
- public:
- MockBufferQueue() : BufferQueue(/*sii_=*/nullptr, gpu::kNullSurfaceHandle) {}
- ~MockBufferQueue() override = default;
-
- MOCK_METHOD2(GetCurrentBuffer,
- gpu::Mailbox(gpu::SyncToken*, gfx::GpuFenceHandle*));
- MOCK_CONST_METHOD0(CurrentBufferDamage, gfx::Rect());
- MOCK_METHOD1(SwapBuffers, void(const gfx::Rect&));
- MOCK_METHOD1(PageFlipComplete, void(gfx::GpuFenceHandle));
- MOCK_METHOD0(FreeAllSurfaces, void());
- MOCK_METHOD3(Reshape,
- bool(const gfx::Size&,
- const gfx::ColorSpace&,
- gfx::BufferFormat));
-
- MOCK_METHOD0(DoSetSyncTokenProvider, void());
- void SetSyncTokenProvider(SyncTokenProvider* sync_token_provider) override {
- BufferQueue::SetSyncTokenProvider(sync_token_provider);
- DoSetSyncTokenProvider();
- }
-};
-
-} // namespace
-
-class GLOutputSurfaceBufferQueueTest : public ::testing::Test,
- public OutputSurfaceClient {
- public:
- GLOutputSurfaceBufferQueueTest() = default;
- ~GLOutputSurfaceBufferQueueTest() override = default;
-
- void SetUp() override {
- auto buffer_queue = std::make_unique<StrictMock<MockBufferQueue>>();
- buffer_queue_ = buffer_queue.get();
-
- auto gles2_interface = std::make_unique<StrictMock<MockGLES2Interface>>();
- gles2_interface_ = gles2_interface.get();
-
- EXPECT_CALL(*buffer_queue_, DoSetSyncTokenProvider());
- surface_ = std::make_unique<GLOutputSurfaceBufferQueue>(
- base::MakeRefCounted<TestVizProcessContextProvider>(
- std::make_unique<TestContextSupport>(), std::move(gles2_interface)),
- gpu::kNullSurfaceHandle, std::move(buffer_queue));
- surface_->BindToClient(this);
-
- Mock::VerifyAndClearExpectations(gles2_interface_);
- Mock::VerifyAndClearExpectations(buffer_queue_);
- }
-
- // OutputSurfaceClient implementation.
- void DidReceiveSwapBuffersAck(const gfx::SwapTimings& timings,
- gfx::GpuFenceHandle release_fence) override {}
- void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
- void DidReceiveTextureInUseResponses(
- const gpu::TextureInUseResponses& responses) override {}
- void DidReceiveCALayerParams(
- const gfx::CALayerParams& ca_layer_params) override {}
- void DidSwapWithSize(const gfx::Size& pixel_size) override {}
- void DidReceivePresentationFeedback(
- const gfx::PresentationFeedback& feedback) override {}
- void DidReceiveReleasedOverlays(
- const std::vector<gpu::Mailbox>& released_overlays) override {}
-
- protected:
- std::unique_ptr<OutputSurface> surface_;
- raw_ptr<StrictMock<MockGLES2Interface>> gles2_interface_;
- raw_ptr<StrictMock<MockBufferQueue>> buffer_queue_;
-};
-
-MATCHER_P(SyncTokenEqualTo, expected_sync_token, "") {
- auto* actual_sync_token = reinterpret_cast<const gpu::SyncToken*>(arg);
- return expected_sync_token == *actual_sync_token;
-}
-
-MATCHER_P(SharedImageEqualTo, expected_shared_image, "") {
- gpu::Mailbox actual_shared_image;
- actual_shared_image.SetName(arg);
- return expected_shared_image == actual_shared_image;
-}
-
-// Make sure that the surface uses the buffer queue and the GL context correctly
-// when we request it to bind the framebuffer twice and then swap the buffer.
-TEST_F(GLOutputSurfaceBufferQueueTest, BindFramebufferAndSwap) {
- const gpu::SyncToken fake_sync_token(
- gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(567u),
- /*release_count=*/5u);
- const gpu::Mailbox fake_shared_image = gpu::Mailbox::GenerateForSharedImage();
- constexpr GLuint kFakeTexture = 123u;
- {
- InSequence dummy_sequence;
-
- // The first call to |surface_|->BindFramebuffer() should result in binding
- // the GL framebuffer, requesting a new buffer, waiting on the corresponding
- // sync token, and beginning read/write access to the shared image.
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
- EXPECT_CALL(*buffer_queue_, GetCurrentBuffer(NotNull(), NotNull()))
- .WillOnce(DoAll(SetArgPointee<0>(fake_sync_token),
- Return(fake_shared_image)));
- EXPECT_CALL(*gles2_interface_,
- WaitSyncTokenCHROMIUM(SyncTokenEqualTo(fake_sync_token)));
- EXPECT_CALL(*gles2_interface_, CreateAndTexStorage2DSharedImageCHROMIUM(
- SharedImageEqualTo(fake_shared_image)))
- .WillOnce(Return(kFakeTexture));
- EXPECT_CALL(
- *gles2_interface_,
- BeginSharedImageAccessDirectCHROMIUM(
- kFakeTexture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM));
-
- // The second call to |surface_|->BindFramebuffer() should only result in
- // binding the GL framebuffer because the underlying buffer hasn't been
- // swapped.
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
-
- // Calling |surface_|->SwapBuffers() should result in ending read/write
- // access to the underlying buffer and unbinding the GL framebuffer.
- EXPECT_CALL(*gles2_interface_,
- EndSharedImageAccessDirectCHROMIUM(kFakeTexture));
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Eq(0u)));
- EXPECT_CALL(*buffer_queue_, SwapBuffers(_));
-
- // Destroying |surface_| should result in the deletion of the texture
- // obtained from consuming the shared image.
- EXPECT_CALL(*gles2_interface_,
- DeleteTextures(1u, Pointee(Eq(kFakeTexture))));
- }
-
- surface_->BindFramebuffer();
- surface_->BindFramebuffer();
- surface_->SwapBuffers(OutputSurfaceFrame());
-}
-
-TEST_F(GLOutputSurfaceBufferQueueTest, EmptySwap) {
- const gpu::SyncToken fake_sync_token(
- gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(567u),
- /*release_count=*/5u);
- const gpu::Mailbox fake_shared_image = gpu::Mailbox::GenerateForSharedImage();
- constexpr GLuint kFakeTexture = 123u;
- {
- InSequence dummy_sequence;
-
- // The call to |surface_|->BindFramebuffer() should result in binding the GL
- // framebuffer, requesting a new buffer, waiting on the corresponding sync
- // token, and beginning read/write access to the shared image.
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
- EXPECT_CALL(*buffer_queue_, GetCurrentBuffer(NotNull(), NotNull()))
- .WillOnce(DoAll(SetArgPointee<0>(fake_sync_token),
- Return(fake_shared_image)));
- EXPECT_CALL(*gles2_interface_,
- WaitSyncTokenCHROMIUM(SyncTokenEqualTo(fake_sync_token)));
- EXPECT_CALL(*gles2_interface_, CreateAndTexStorage2DSharedImageCHROMIUM(
- SharedImageEqualTo(fake_shared_image)))
- .WillOnce(Return(kFakeTexture));
- EXPECT_CALL(
- *gles2_interface_,
- BeginSharedImageAccessDirectCHROMIUM(
- kFakeTexture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM));
-
- // The first call to |surface_|->SwapBuffers() should result in ending
- // read/write access to the underlying buffer and unbinding the GL
- // framebuffer.
- EXPECT_CALL(*gles2_interface_,
- EndSharedImageAccessDirectCHROMIUM(kFakeTexture));
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Eq(0u)));
- EXPECT_CALL(*buffer_queue_, SwapBuffers(_));
-
- // The two empty swaps should only result in telling the buffer queue to
- // swap the buffers.
- EXPECT_CALL(*buffer_queue_, SwapBuffers(_)).Times(2);
-
- // Destroying |surface_| should result in the deletion of the texture
- // obtained from consuming the shared image.
- EXPECT_CALL(*gles2_interface_,
- DeleteTextures(1u, Pointee(Eq(kFakeTexture))));
- }
- surface_->BindFramebuffer();
- unsigned texture_for_first_buffer = surface_->GetOverlayTextureId();
- EXPECT_GT(texture_for_first_buffer, 0u);
- surface_->SwapBuffers(OutputSurfaceFrame());
-
- // Now do two empty swaps (which don't call BindFramebuffer()).
- EXPECT_EQ(texture_for_first_buffer, surface_->GetOverlayTextureId());
- surface_->SwapBuffers(OutputSurfaceFrame());
- EXPECT_EQ(texture_for_first_buffer, surface_->GetOverlayTextureId());
- surface_->SwapBuffers(OutputSurfaceFrame());
-}
-
-// Make sure that receiving a swap NAK doesn't cause us to leak resources.
-TEST_F(GLOutputSurfaceBufferQueueTest, HandleSwapNAK) {
- const gpu::SyncToken fake_sync_token(
- gpu::CommandBufferNamespace::GPU_IO,
- gpu::CommandBufferId::FromUnsafeValue(567u),
- /*release_count=*/5u);
- constexpr gfx::Size kBufferSize(100, 100);
- const gpu::Mailbox fake_shared_image = gpu::Mailbox::GenerateForSharedImage();
- constexpr GLuint kFakeTexture = 123u;
- constexpr GLuint kFakeStencilBuffer = 456u;
- {
- InSequence dummy_sequence;
-
- EXPECT_CALL(*buffer_queue_, Reshape(_, _, _)).WillOnce(Return(true));
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
-
- // The call to |surface_|->BindFramebuffer() should result in binding the GL
- // framebuffer, requesting a new buffer, waiting on the corresponding sync
- // token, beginning read/write access to the shared image, and creating a
- // stencil buffer.
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
- EXPECT_CALL(*buffer_queue_, GetCurrentBuffer(NotNull(), NotNull()))
- .WillOnce(DoAll(SetArgPointee<0>(fake_sync_token),
- Return(fake_shared_image)));
-
- EXPECT_CALL(*gles2_interface_,
- WaitSyncTokenCHROMIUM(SyncTokenEqualTo(fake_sync_token)));
- EXPECT_CALL(*gles2_interface_, CreateAndTexStorage2DSharedImageCHROMIUM(
- SharedImageEqualTo(fake_shared_image)))
- .WillOnce(Return(kFakeTexture));
- EXPECT_CALL(
- *gles2_interface_,
- BeginSharedImageAccessDirectCHROMIUM(
- kFakeTexture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM));
- EXPECT_CALL(*gles2_interface_, GenRenderbuffers(1u, NotNull()))
- .WillOnce(SetArgPointee<1>(kFakeStencilBuffer));
- EXPECT_CALL(*gles2_interface_,
- BindRenderbuffer(GL_RENDERBUFFER, kFakeStencilBuffer));
- EXPECT_CALL(*gles2_interface_, BindRenderbuffer(GL_RENDERBUFFER, 0u));
-
- // Calling |surface_|->SwapBuffers() should result in ending read/write
- // access to the underlying buffer and unbinding the GL framebuffer.
- EXPECT_CALL(*gles2_interface_,
- EndSharedImageAccessDirectCHROMIUM(kFakeTexture));
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Eq(0u)));
- EXPECT_CALL(*buffer_queue_, SwapBuffers(_));
-
- // Receiving a swap NAK should result in the deletion of the texture
- // obtained from consuming the shared image. It should also result in the
- // deletion of the stencil buffer.
- EXPECT_CALL(*buffer_queue_, FreeAllSurfaces());
- EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
- EXPECT_CALL(*gles2_interface_,
- DeleteRenderbuffers(1u, Pointee(Eq(kFakeStencilBuffer))));
- EXPECT_CALL(*gles2_interface_,
- DeleteTextures(1u, Pointee(Eq(kFakeTexture))));
- EXPECT_CALL(*buffer_queue_, PageFlipComplete(_));
- }
-
- surface_->Reshape(kBufferSize, /*device_scale_factor=*/1.0,
- gfx::ColorSpace::CreateSRGB(), gfx::BufferFormat::BGRA_8888,
- /*use_stencil=*/true);
- surface_->BindFramebuffer();
- OutputSurfaceFrame frame;
- frame.size = kBufferSize;
- surface_->SwapBuffers(std::move(frame));
- gfx::SwapResponse swap_response{};
- swap_response.result = gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS;
- (static_cast<GLOutputSurfaceBufferQueue*>(surface_.get()))
- ->DidReceiveSwapBuffersAck(swap_response,
- /*release_fence=*/gfx::GpuFenceHandle());
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.cc
deleted file mode 100644
index d3cc8558658..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface_chromeos.h"
-
-namespace viz {
-
-GLOutputSurfaceChromeOS::GLOutputSurfaceChromeOS(
- scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle)
- : GLOutputSurface(context_provider, surface_handle) {}
-
-GLOutputSurfaceChromeOS::~GLOutputSurfaceChromeOS() = default;
-
-void GLOutputSurfaceChromeOS::SetDisplayTransformHint(
- gfx::OverlayTransform transform) {
- display_transform_ = transform;
-}
-
-gfx::OverlayTransform GLOutputSurfaceChromeOS::GetDisplayTransform() {
- return display_transform_;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.h b/chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.h
deleted file mode 100644
index 63ad613a96d..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_chromeos.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_CHROMEOS_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_CHROMEOS_H_
-
-#include "components/viz/service/display_embedder/gl_output_surface.h"
-
-namespace viz {
-
-class GLOutputSurfaceChromeOS : public GLOutputSurface {
- public:
- GLOutputSurfaceChromeOS(
- scoped_refptr<VizProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle);
-
- GLOutputSurfaceChromeOS(const GLOutputSurfaceChromeOS&) = delete;
- GLOutputSurfaceChromeOS& operator=(const GLOutputSurfaceChromeOS&) = delete;
-
- ~GLOutputSurfaceChromeOS() override;
-
- // GLOutputSurface:
- void SetDisplayTransformHint(gfx::OverlayTransform transform) override;
- gfx::OverlayTransform GetDisplayTransform() override;
-
- private:
- gfx::OverlayTransform display_transform_ = gfx::OVERLAY_TRANSFORM_NONE;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_CHROMEOS_H_
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
deleted file mode 100644
index 9e7190ad7b0..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.cc
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/gl_output_surface_offscreen.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "components/viz/service/display/output_surface_client.h"
-#include "components/viz/service/display/output_surface_frame.h"
-#include "gpu/command_buffer/client/context_support.h"
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "gpu/command_buffer/client/shared_image_interface.h"
-#include "gpu/command_buffer/common/shared_image_usage.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-#include "ui/gfx/swap_result.h"
-#include "ui/gl/gl_utils.h"
-
-namespace viz {
-namespace {
-
-constexpr ResourceFormat kFboTextureFormat = RGBA_8888;
-
-} // namespace
-
-GLOutputSurfaceOffscreen::GLOutputSurfaceOffscreen(
- scoped_refptr<VizProcessContextProvider> context_provider)
- : GLOutputSurface(context_provider, gpu::kNullSurfaceHandle) {}
-
-GLOutputSurfaceOffscreen::~GLOutputSurfaceOffscreen() {
- DiscardBackbuffer();
-}
-
-void GLOutputSurfaceOffscreen::EnsureBackbuffer() {
- if (size_.IsEmpty())
- return;
-
- if (!texture_id_) {
- gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
- const int max_texture_size =
- context_provider_->ContextCapabilities().max_texture_size;
- gfx::Size texture_size(std::min(size_.width(), max_texture_size),
- std::min(size_.height(), max_texture_size));
-
- const uint32_t flags = gpu::SHARED_IMAGE_USAGE_GLES2 |
- gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT |
- gpu::SHARED_IMAGE_USAGE_DISPLAY;
-
- mailbox_ = sii->CreateSharedImage(
- kFboTextureFormat, texture_size, color_space_, kTopLeft_GrSurfaceOrigin,
- kPremul_SkAlphaType, flags, gpu::kNullSurfaceHandle);
-
- // Ensure mailbox is valid before using it.
- gl->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
-
- texture_id_ = gl->CreateAndTexStorage2DSharedImageCHROMIUM(mailbox_.name);
-
- gl->GenFramebuffers(1, &fbo_);
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
- gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture_id_, 0);
- }
-}
-
-void GLOutputSurfaceOffscreen::DiscardBackbuffer() {
- if (fbo_) {
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
- gl->DeleteFramebuffers(1, &fbo_);
- fbo_ = 0;
- }
-
- if (texture_id_) {
- gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
- sii->DestroySharedImage(gpu::SyncToken(), mailbox_);
- mailbox_.SetZero();
- texture_id_ = 0;
- }
-}
-
-void GLOutputSurfaceOffscreen::BindFramebuffer() {
- if (!texture_id_) {
- EnsureBackbuffer();
- } else {
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
- gl->BindFramebuffer(GL_FRAMEBUFFER, fbo_);
- }
-}
-
-void GLOutputSurfaceOffscreen::Reshape(const gfx::Size& size,
- float scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool stencil) {
- size_ = size;
- color_space_ = color_space;
- DiscardBackbuffer();
- EnsureBackbuffer();
-}
-
-void GLOutputSurfaceOffscreen::SwapBuffers(OutputSurfaceFrame frame) {
- DCHECK_EQ(frame.size, size_);
-
- gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
-
- gpu::SyncToken sync_token;
- gl->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
- context_provider_->ContextSupport()->SignalSyncToken(
- sync_token,
- base::BindOnce(&GLOutputSurfaceOffscreen::OnSwapBuffersComplete,
- weak_ptr_factory_.GetWeakPtr(),
- std::move(frame.latency_info)));
-}
-
-void GLOutputSurfaceOffscreen::OnSwapBuffersComplete(
- std::vector<ui::LatencyInfo> latency_info) {
- latency_tracker()->OnGpuSwapBuffersCompleted(std::move(latency_info));
- // Swap timings are not available since for offscreen there is no Swap, just a
- // SignalSyncToken. We use base::TimeTicks::Now() as an overestimate.
- auto now = base::TimeTicks::Now();
- client()->DidReceiveSwapBuffersAck({.swap_start = now},
- /*release_fence=*/gfx::GpuFenceHandle());
- client()->DidReceivePresentationFeedback(
- gfx::PresentationFeedback(now, base::Milliseconds(16), /*flags=*/0));
-
- if (needs_swap_size_notifications())
- client()->DidSwapWithSize(size_);
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.h b/chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.h
deleted file mode 100644
index e769f1254ed..00000000000
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_offscreen.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OFFSCREEN_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OFFSCREEN_H_
-
-#include <memory>
-
-#include "components/viz/common/frame_sinks/begin_frame_source.h"
-#include "components/viz/service/display_embedder/gl_output_surface.h"
-#include "components/viz/service/display_embedder/viz_process_context_provider.h"
-#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/common/mailbox.h"
-#include "ui/gfx/color_space.h"
-
-namespace viz {
-
-// An OutputSurface implementation that draws and swaps to an offscreen GL
-// framebuffer.
-class VIZ_SERVICE_EXPORT GLOutputSurfaceOffscreen : public GLOutputSurface {
- public:
- explicit GLOutputSurfaceOffscreen(
- scoped_refptr<VizProcessContextProvider> context_provider);
-
- GLOutputSurfaceOffscreen(const GLOutputSurfaceOffscreen&) = delete;
- GLOutputSurfaceOffscreen& operator=(const GLOutputSurfaceOffscreen&) = delete;
-
- ~GLOutputSurfaceOffscreen() override;
-
- // OutputSurface implementation.
- void EnsureBackbuffer() override;
- void DiscardBackbuffer() override;
- void BindFramebuffer() override;
- void Reshape(const gfx::Size& size,
- float scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool stencil) override;
- void SwapBuffers(OutputSurfaceFrame frame) override;
-
- private:
- void OnSwapBuffersComplete(std::vector<ui::LatencyInfo> latency_info);
-
- gpu::Mailbox mailbox_;
-
- uint32_t fbo_ = 0;
- uint32_t texture_id_ = 0;
- gfx::Size size_;
- gfx::ColorSpace color_space_;
-
- base::WeakPtrFactory<GLOutputSurfaceOffscreen> weak_ptr_factory_{this};
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_OFFSCREEN_H_
diff --git a/chromium/components/viz/service/display_embedder/image_context_impl.h b/chromium/components/viz/service/display_embedder/image_context_impl.h
index 00a51c95254..79e45adbc33 100644
--- a/chromium/components/viz/service/display_embedder/image_context_impl.h
+++ b/chromium/components/viz/service/display_embedder/image_context_impl.h
@@ -73,9 +73,9 @@ class ImageContextImpl final : public ExternalUseClient::ImageContext {
SkPromiseImageTexture* promise_image_texture() const {
return promise_image_texture_;
}
- GrBackendSurfaceMutableState* end_access_state() const {
+ std::unique_ptr<GrBackendSurfaceMutableState> TakeAccessEndState() const {
return representation_scoped_read_access_
- ? representation_scoped_read_access_->end_state()
+ ? representation_scoped_read_access_->TakeEndState()
: nullptr;
}
diff --git a/chromium/components/viz/service/display_embedder/output_presenter.cc b/chromium/components/viz/service/display_embedder/output_presenter.cc
index 0209a8bac21..0c9aced7778 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter.cc
@@ -84,12 +84,13 @@ void OutputPresenter::Image::EndWriteSkia(bool force_flush) {
// The Flush now takes place in finishPaintCurrentBuffer on the CPU side.
// check if end_semaphores is not empty then flush here
DCHECK(scoped_skia_write_access_);
- if (!end_semaphores_.empty() || force_flush) {
+ auto end_state = scoped_skia_write_access_->TakeEndState();
+ if (!end_semaphores_.empty() || end_state || force_flush) {
GrFlushInfo flush_info = {
.fNumSemaphores = end_semaphores_.size(),
.fSignalSemaphores = end_semaphores_.data(),
};
- scoped_skia_write_access_->surface()->flush(flush_info);
+ scoped_skia_write_access_->surface()->flush(flush_info, end_state.get());
auto* direct_context = scoped_skia_write_access_->surface()
->recordingContext()
->asDirectContext();
@@ -105,9 +106,8 @@ void OutputPresenter::Image::EndWriteSkia(bool force_flush) {
void OutputPresenter::Image::PreGrContextSubmit() {
DCHECK(scoped_skia_write_access_);
- if (scoped_skia_write_access_->end_state()) {
- scoped_skia_write_access_->surface()->flush(
- {}, scoped_skia_write_access_->end_state());
+ if (auto end_state = scoped_skia_write_access_->TakeEndState()) {
+ scoped_skia_write_access_->surface()->flush({}, end_state.get());
}
}
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_gl.cc b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
index 40790839cd5..5faa7dafe5d 100644
--- a/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
+++ b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -224,7 +224,8 @@ std::unique_ptr<OutputPresenterGL> OutputPresenterGL::Create(
return nullptr;
// TODO(https://crbug.com/1012401): don't depend on GL.
auto gl_surface = base::MakeRefCounted<gl::GLSurfaceEGLSurfaceControl>(
- window, base::ThreadTaskRunnerHandle::Get());
+ gl::GLSurfaceEGL::GetGLDisplayEGL(), window,
+ base::ThreadTaskRunnerHandle::Get());
if (!gl_surface->Initialize(gl::GLSurfaceFormat())) {
LOG(ERROR) << "Failed to initialize GLSurfaceEGLSurfaceControl.";
return nullptr;
@@ -416,8 +417,14 @@ void OutputPresenterGL::ScheduleOneOverlay(const OverlayCandidate& overlay,
ScopedOverlayAccess* access) {
#if BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
auto* gl_image = access ? access->gl_image() : nullptr;
- if (gl_image || overlay.solid_color.has_value()) {
- DCHECK(!overlay.gpu_fence_id);
+ if (gl_image || overlay.is_solid_color) {
+#if DCHECK_IS_ON()
+ if (overlay.is_solid_color) {
+ LOG_IF(FATAL, !overlay.color.has_value())
+ << "Solid color quads must have color set.";
+ }
+ CHECK(!overlay.gpu_fence_id);
+#endif
gl_surface_->ScheduleOverlayPlane(
gl_image, access ? TakeGpuFence(access->TakeAcquireFences()) : nullptr,
gfx::OverlayPlaneData(
@@ -425,7 +432,7 @@ void OutputPresenterGL::ScheduleOneOverlay(const OverlayCandidate& overlay,
overlay.uv_rect, !overlay.is_opaque,
ToEnclosingRect(overlay.damage_rect), overlay.opacity,
overlay.priority_hint, overlay.rounded_corners, overlay.color_space,
- overlay.hdr_metadata, overlay.solid_color));
+ overlay.hdr_metadata, overlay.color, overlay.is_solid_color));
}
#else // BUILDFLAG(IS_ANDROID) || defined(USE_OZONE)
NOTREACHED();
@@ -477,8 +484,14 @@ void OutputPresenterGL::ScheduleOverlays(
// may have a protocol that asks Wayland compositor to create a solid color
// buffer for a client. OverlayProcessorDelegated decides if a solid color
// overlay is an overlay candidate and should be scheduled.
- if (gl_image || overlay.solid_color.has_value()) {
- DCHECK(!overlay.gpu_fence_id);
+ if (gl_image || overlay.is_solid_color) {
+#if DCHECK_IS_ON()
+ if (overlay.is_solid_color) {
+ LOG_IF(FATAL, !overlay.color.has_value())
+ << "Solid color quads must have color set.";
+ }
+ CHECK(!overlay.gpu_fence_id);
+#endif
gl_surface_->ScheduleOverlayPlane(
gl_image,
TakeGpuFenceForOverlay(dependency_, accesses[i], current_frame_fence),
@@ -487,12 +500,10 @@ void OutputPresenterGL::ScheduleOverlays(
overlay.uv_rect, !overlay.is_opaque,
ToEnclosingRect(overlay.damage_rect), overlay.opacity,
overlay.priority_hint, overlay.rounded_corners,
- overlay.color_space, overlay.hdr_metadata, overlay.solid_color));
+ overlay.color_space, overlay.hdr_metadata, overlay.color,
+ overlay.is_solid_color));
}
#elif BUILDFLAG(IS_APPLE)
- // For RenderPassDrawQuad the ddl is not nullptr, and the opacity is applied
- // when the ddl is recorded, so the content already is with opacity applied.
- float opacity = overlay.ddl ? 1.0 : overlay.shared_state->opacity;
gl_surface_->ScheduleCALayer(ui::CARendererLayerParams(
overlay.shared_state->is_clipped,
gfx::ToEnclosingRect(overlay.shared_state->clip_rect),
@@ -500,8 +511,8 @@ void OutputPresenterGL::ScheduleOverlays(
overlay.shared_state->sorting_context_id,
gfx::Transform(overlay.shared_state->transform), gl_image,
overlay.contents_rect, gfx::ToEnclosingRect(overlay.bounds_rect),
- overlay.background_color, overlay.edge_aa_mask, opacity, overlay.filter,
- overlay.protected_video_type));
+ overlay.background_color.toSkColor(), overlay.edge_aa_mask,
+ overlay.opacity, overlay.filter, overlay.protected_video_type));
#endif
}
#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider.h b/chromium/components/viz/service/display_embedder/output_surface_provider.h
index 77d463e683d..2e9453c18f2 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider.h
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider.h
@@ -28,8 +28,7 @@ class OutputSurfaceProvider {
// of this should feed into the CreateOutputSurface function.
virtual std::unique_ptr<DisplayCompositorMemoryAndTaskController>
CreateGpuDependency(bool gpu_compositing,
- gpu::SurfaceHandle surface_handle,
- const RendererSettings& renderer_settings) = 0;
+ gpu::SurfaceHandle surface_handle) = 0;
// Creates a new OutputSurface for |surface_handle|. If creating an
// OutputSurface fails this function will return null.
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
index 8a277c6337d..85857907957 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc
@@ -20,37 +20,21 @@
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
-#include "components/viz/service/display_embedder/gl_output_surface.h"
-#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
-#include "components/viz/service/display_embedder/gl_output_surface_offscreen.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
#include "components/viz/service/display_embedder/software_output_surface.h"
-#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "components/viz/service/gl/gpu_service_impl.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/command_buffer/service/image_factory.h"
-#include "gpu/command_buffer/service/mailbox_manager_factory.h"
#include "gpu/config/gpu_finch_features.h"
-#include "gpu/ipc/command_buffer_task_executor.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/scheduler_sequence.h"
-#include "gpu/ipc/service/gpu_channel_manager_delegate.h"
-#include "gpu/ipc/service/image_transport_surface.h"
#include "ui/base/ui_base_switches.h"
-#include "ui/gl/gl_context.h"
-#include "ui/gl/init/gl_factory.h"
#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display_embedder/software_output_device_win.h"
#endif
-#if BUILDFLAG(IS_ANDROID)
-#include "components/viz/service/display_embedder/gl_output_surface_android.h"
-#endif
-
#if BUILDFLAG(IS_APPLE)
#include "components/viz/service/display_embedder/software_output_device_mac.h"
#include "ui/base/cocoa/remote_layer_api.h"
@@ -66,7 +50,6 @@
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
-#include "components/viz/service/display_embedder/gl_output_surface_chromeos.h"
#include "components/viz/service/display_embedder/output_surface_unified.h"
#endif
@@ -74,26 +57,14 @@ namespace viz {
OutputSurfaceProviderImpl::OutputSurfaceProviderImpl(
GpuServiceImpl* gpu_service_impl,
- gpu::CommandBufferTaskExecutor* task_executor,
- gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
bool headless)
: gpu_service_impl_(gpu_service_impl),
- task_executor_(task_executor),
- gpu_channel_manager_delegate_(gpu_channel_manager_delegate),
- gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
- image_factory_(image_factory),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
headless_(headless) {}
OutputSurfaceProviderImpl::OutputSurfaceProviderImpl(bool headless)
: OutputSurfaceProviderImpl(
/*gpu_service_impl=*/nullptr,
- /*task_executor=*/nullptr,
- /*gpu_channel_manager_delegate=*/nullptr,
- /*gpu_memory_buffer_manager=*/nullptr,
- /*image_factory=*/nullptr,
headless) {}
OutputSurfaceProviderImpl::~OutputSurfaceProviderImpl() = default;
@@ -101,23 +72,15 @@ OutputSurfaceProviderImpl::~OutputSurfaceProviderImpl() = default;
std::unique_ptr<DisplayCompositorMemoryAndTaskController>
OutputSurfaceProviderImpl::CreateGpuDependency(
bool gpu_compositing,
- gpu::SurfaceHandle surface_handle,
- const RendererSettings& renderer_settings) {
+ gpu::SurfaceHandle surface_handle) {
if (!gpu_compositing)
return nullptr;
- if (renderer_settings.use_skia_renderer) {
- gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
- auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
- gpu_service_impl_, surface_handle);
- return std::make_unique<DisplayCompositorMemoryAndTaskController>(
- std::move(skia_deps));
- } else {
- DCHECK(task_executor_);
- gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
- return std::make_unique<DisplayCompositorMemoryAndTaskController>(
- task_executor_, image_factory_);
- }
+ gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
+ auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
+ gpu_service_impl_, surface_handle);
+ return std::make_unique<DisplayCompositorMemoryAndTaskController>(
+ std::move(skia_deps));
}
std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
@@ -139,7 +102,7 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
if (!gpu_compositing) {
output_surface = std::make_unique<SoftwareOutputSurface>(
CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client));
- } else if (renderer_settings.use_skia_renderer) {
+ } else {
DCHECK(gpu_dependency);
{
gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
@@ -167,74 +130,6 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
#endif
return nullptr;
}
- } else {
- DCHECK(task_executor_);
- DCHECK(gpu_dependency);
-
- scoped_refptr<VizProcessContextProvider> context_provider;
-
- // Retry creating and binding |context_provider| on transient failures.
- gpu::ContextResult context_result = gpu::ContextResult::kTransientFailure;
- while (context_result != gpu::ContextResult::kSuccess) {
- // We are about to exit the GPU process so don't try to create a context.
- // It will be recreated after the GPU process restarts. The same check
- // also happens on the GPU thread before the context gets initialized
- // there. If GPU process starts to exit after this check but before
- // context initialization we'll encounter a transient error, loop and hit
- // this check again.
- if (gpu_channel_manager_delegate_->IsExiting())
- return nullptr;
-
- context_provider = base::MakeRefCounted<VizProcessContextProvider>(
- task_executor_, surface_handle, gpu_memory_buffer_manager_.get(),
- image_factory_, gpu_channel_manager_delegate_, gpu_dependency,
- renderer_settings);
- context_result = context_provider->BindToCurrentThread();
-
-#if BUILDFLAG(IS_ANDROID)
- display_client->OnContextCreationResult(context_result);
-#endif
-
- if (IsFatalOrSurfaceFailure(context_result)) {
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMECAST)
- // GL compositing is expected to always work on Chrome OS so we should
- // never encounter fatal context error. This could be an unrecoverable
- // hardware error or a bug.
- LOG(FATAL) << "Unexpected fatal context error";
-#elif !BUILDFLAG(IS_ANDROID)
- gpu_service_impl_->DisableGpuCompositing();
-#endif
- return nullptr;
- }
- }
-
- if (surface_handle == gpu::kNullSurfaceHandle) {
- output_surface = std::make_unique<GLOutputSurfaceOffscreen>(
- std::move(context_provider));
- } else if (context_provider->ContextCapabilities().surfaceless) {
-#if defined(USE_OZONE) || BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_ANDROID)
- output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
- std::move(context_provider), surface_handle,
- std::make_unique<BufferQueue>(
- context_provider->SharedImageInterface(), surface_handle));
-#else
- NOTREACHED();
-#endif
- } else {
-#if BUILDFLAG(IS_WIN)
- output_surface = std::make_unique<GLOutputSurface>(
- std::move(context_provider), surface_handle);
-#elif BUILDFLAG(IS_ANDROID)
- output_surface = std::make_unique<GLOutputSurfaceAndroid>(
- std::move(context_provider), surface_handle);
-#elif BUILDFLAG(IS_CHROMEOS_ASH)
- output_surface = std::make_unique<GLOutputSurfaceChromeOS>(
- std::move(context_provider), surface_handle);
-#else
- output_surface = std::make_unique<GLOutputSurface>(
- std::move(context_provider), surface_handle);
-#endif
- }
}
return output_surface;
diff --git a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
index fa9bc45b5c1..be10797e6f5 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
+++ b/chromium/components/viz/service/display_embedder/output_surface_provider_impl.h
@@ -14,22 +14,12 @@
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/service/display_embedder/output_surface_provider.h"
#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "gpu/ipc/common/surface_handle.h"
-#include "gpu/ipc/in_process_command_buffer.h"
#if BUILDFLAG(IS_WIN)
#include "components/viz/service/display_embedder/output_device_backing.h"
#endif
-namespace gpu {
-class CommandBufferTaskExecutor;
-class GpuChannelManagerDelegate;
-class GpuMemoryBufferManager;
-class ImageFactory;
-class SharedContextState;
-} // namespace gpu
-
namespace viz {
class GpuServiceImpl;
class SoftwareOutputDevice;
@@ -38,13 +28,7 @@ class SoftwareOutputDevice;
class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl
: public OutputSurfaceProvider {
public:
- OutputSurfaceProviderImpl(
- GpuServiceImpl* gpu_service_impl,
- gpu::CommandBufferTaskExecutor* task_executor,
- gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
- bool headless);
+ OutputSurfaceProviderImpl(GpuServiceImpl* gpu_service_impl, bool headless);
// Software compositing only.
explicit OutputSurfaceProviderImpl(bool headless);
@@ -56,8 +40,7 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl
std::unique_ptr<DisplayCompositorMemoryAndTaskController> CreateGpuDependency(
bool gpu_compositing,
- gpu::SurfaceHandle surface_handle,
- const RendererSettings& renderer_settings) override;
+ gpu::SurfaceHandle surface_handle) override;
// OutputSurfaceProvider implementation.
std::unique_ptr<OutputSurface> CreateOutputSurface(
@@ -74,10 +57,6 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl
mojom::DisplayClient* display_client);
const raw_ptr<GpuServiceImpl> gpu_service_impl_;
- const raw_ptr<gpu::CommandBufferTaskExecutor> task_executor_;
- const raw_ptr<gpu::GpuChannelManagerDelegate> gpu_channel_manager_delegate_;
- const raw_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
- const raw_ptr<gpu::ImageFactory> image_factory_;
#if BUILDFLAG(IS_WIN)
// Used for software compositing output on Windows.
@@ -86,11 +65,6 @@ class VIZ_SERVICE_EXPORT OutputSurfaceProviderImpl
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- // A shared context which will be used on display compositor thread.
- scoped_refptr<gpu::SharedContextState> shared_context_state_;
- std::unique_ptr<gpu::MailboxManager> mailbox_manager_;
- std::unique_ptr<gpu::SyncPointManager> sync_point_manager_;
-
const bool headless_;
};
diff --git a/chromium/components/viz/service/display_embedder/output_surface_unified.cc b/chromium/components/viz/service/display_embedder/output_surface_unified.cc
index f01790c3016..a5c52de25f7 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_unified.cc
+++ b/chromium/components/viz/service/display_embedder/output_surface_unified.cc
@@ -29,22 +29,6 @@ bool OutputSurfaceUnified::IsDisplayedAsOverlayPlane() const {
return false;
}
-unsigned OutputSurfaceUnified::GetOverlayTextureId() const {
- return 0;
-}
-
-bool OutputSurfaceUnified::HasExternalStencilTest() const {
- return false;
-}
-
-uint32_t OutputSurfaceUnified::GetFramebufferCopyTextureFormat() {
- return 0;
-}
-
-unsigned OutputSurfaceUnified::UpdateGpuFence() {
- return 0;
-}
-
gfx::OverlayTransform OutputSurfaceUnified::GetDisplayTransform() {
return gfx::OVERLAY_TRANSFORM_NONE;
}
diff --git a/chromium/components/viz/service/display_embedder/output_surface_unified.h b/chromium/components/viz/service/display_embedder/output_surface_unified.h
index 62b6ef6a8df..8d9d4deb688 100644
--- a/chromium/components/viz/service/display_embedder/output_surface_unified.h
+++ b/chromium/components/viz/service/display_embedder/output_surface_unified.h
@@ -34,19 +34,9 @@ class OutputSurfaceUnified : public OutputSurface {
void BindToClient(OutputSurfaceClient* client) override {}
void EnsureBackbuffer() override {}
void DiscardBackbuffer() override {}
- void BindFramebuffer() override {}
- void Reshape(const gfx::Size& size,
- float scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool stencil) override {}
+ void Reshape(const ReshapeParams& params) override {}
void SwapBuffers(OutputSurfaceFrame frame) override;
bool IsDisplayedAsOverlayPlane() const override;
- unsigned GetOverlayTextureId() const override;
- bool HasExternalStencilTest() const override;
- void ApplyExternalStencil() override {}
- uint32_t GetFramebufferCopyTextureFormat() override;
- unsigned UpdateGpuFence() override;
void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) override {}
void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device.cc b/chromium/components/viz/service/display_embedder/skia_output_device.cc
index 1c28222954f..bbc98d2edf7 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device.cc
@@ -9,7 +9,9 @@
#include "base/bind.h"
#include "base/check_op.h"
+#include "base/feature_list.h"
#include "base/notreached.h"
+#include "base/task/task_features.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/task/thread_pool/thread_pool_instance.h"
@@ -27,11 +29,18 @@
namespace viz {
namespace {
+const base::Feature kAsyncGpuLatencyReporting CONSTINIT{
+ "AsyncGpuLatencyReporting", base::FEATURE_ENABLED_BY_DEFAULT};
+
using ::perfetto::protos::pbzero::ChromeLatencyInfo;
scoped_refptr<base::SequencedTaskRunner> CreateLatencyTracerRunner() {
if (!base::ThreadPoolInstance::Get())
return nullptr;
+
+ if (!base::FeatureList::IsEnabled(kAsyncGpuLatencyReporting))
+ return nullptr;
+
return base::ThreadPool::CreateSequencedTaskRunner(
{base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
index e788908ffd5..f5ea153eaa7 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc
@@ -394,11 +394,12 @@ void SkiaOutputDeviceBufferQueue::ScheduleOverlays(
auto& overlay = overlays[i];
#if defined(USE_OZONE)
- if (overlay.solid_color.has_value()) {
+ if (overlay.is_solid_color) {
+ DCHECK(overlay.color.has_value());
// TODO(msisov): reconsider this once Linux Wayland compositors also
// support that. See https://bit.ly/2ZqUO0w.
if (!supports_non_backed_solid_color_images_) {
- overlay.mailbox = GetImageMailboxForColor(overlay.solid_color.value());
+ overlay.mailbox = GetImageMailboxForColor(overlay.color.value());
} else {
accesses[i] = nullptr;
continue;
@@ -704,12 +705,13 @@ void SkiaOutputDeviceBufferQueue::MaybeScheduleBackgroundImage() {
OverlayCandidate candidate;
candidate.color_space = color_space_;
candidate.display_rect = gfx::RectF(gfx::SizeF(viewport_size_));
- candidate.solid_color = SK_ColorTRANSPARENT;
+ candidate.color = SK_ColorTRANSPARENT;
candidate.plane_z_order = INT32_MIN;
+ candidate.is_solid_color = supports_non_backed_solid_color_images_;
#if defined(USE_OZONE)
if (!supports_non_backed_solid_color_images_) {
- auto mailbox = GetImageMailboxForColor(candidate.solid_color.value());
+ auto mailbox = GetImageMailboxForColor(candidate.color.value());
DCHECK(mailbox.IsSharedImage());
auto* overlay_data = GetOrCreateOverlayData(mailbox);
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc b/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
index 3f1a3b254d0..3f63127fe35 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_gl.cc
@@ -269,7 +269,7 @@ bool SkiaOutputDeviceGL::Reshape(
: kBottomLeft_GrSurfaceOrigin;
sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
context_state_->gr_context(), render_target, origin, color_type,
- color_space.ToSkColorSpace(), &surface_props);
+ characterization.refColorSpace(), &surface_props);
if (!sk_surface_) {
LOG(ERROR) << "Couldn't create surface:"
<< "\n abandoned()="
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc b/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc
index cb385a7d589..8a450b991bb 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_webview.cc
@@ -65,7 +65,7 @@ bool SkiaOutputDeviceWebView::Reshape(
}
size_ = size;
- color_space_ = color_space;
+ sk_color_space_ = characterization.refColorSpace();
InitSkiaSurface(gl_surface_->GetBackingFramebufferObject());
return !!sk_surface_;
}
@@ -115,14 +115,13 @@ void SkiaOutputDeviceWebView::InitSkiaSurface(unsigned int fbo) {
SkSurfaceProps surface_props{0, kUnknown_SkPixelGeometry};
sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
context_state_->gr_context(), render_target, origin, color_type,
- color_space_.ToSkColorSpace(), &surface_props);
+ sk_color_space_, &surface_props);
if (!sk_surface_) {
LOG(ERROR) << "Couldn't create surface: "
<< context_state_->gr_context()->abandoned() << " " << color_type
<< " " << framebuffer_info.fFBOID << " "
- << framebuffer_info.fFormat << " " << color_space_.ToString()
- << " " << size_.ToString();
+ << framebuffer_info.fFormat << " " << size_.ToString();
}
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_webview.h b/chromium/components/viz/service/display_embedder/skia_output_device_webview.h
index 024727a2155..944310366a5 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_webview.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_webview.h
@@ -54,7 +54,7 @@ class SkiaOutputDeviceWebView : public SkiaOutputDevice {
sk_sp<SkSurface> sk_surface_;
gfx::Size size_;
- gfx::ColorSpace color_space_;
+ sk_sp<SkColorSpace> sk_color_space_;
unsigned int last_frame_buffer_object_ = -1;
base::WeakPtrFactory<SkiaOutputDeviceWebView> weak_ptr_factory_{this};
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
index f53ec05511e..74fd2601377 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -82,18 +82,16 @@ OutputSurface::Type GetOutputSurfaceType(SkiaOutputSurfaceDependency* deps) {
SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
SkDeferredDisplayListRecorder* root_recorder)
- : recorder_(root_recorder), render_pass_id_(0) {}
+ : recorder_(root_recorder) {}
SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
SkSurfaceCharacterization characterization)
- : ScopedPaint(characterization, AggregatedRenderPassId(0), gpu::Mailbox()) {
-}
+ : ScopedPaint(characterization, gpu::Mailbox()) {}
SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
SkSurfaceCharacterization characterization,
- AggregatedRenderPassId render_pass_id,
gpu::Mailbox mailbox)
- : render_pass_id_(render_pass_id), mailbox_(mailbox) {
+ : mailbox_(mailbox) {
recorder_storage_.emplace(characterization);
recorder_ = &recorder_storage_.value();
}
@@ -236,10 +234,6 @@ void SkiaOutputSurfaceImpl::BindToClient(OutputSurfaceClient* client) {
client_ = client;
}
-void SkiaOutputSurfaceImpl::BindFramebuffer() {
- // TODO(penghuang): remove this method when GLRenderer is removed.
-}
-
void SkiaOutputSurfaceImpl::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(capabilities().supports_dc_layers);
@@ -290,21 +284,17 @@ void SkiaOutputSurfaceImpl::RecreateRootRecorder() {
std::ignore = root_recorder_->getCanvas();
}
-void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) {
+void SkiaOutputSurfaceImpl::Reshape(const ReshapeParams& params) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(!size.IsEmpty());
+ DCHECK(!params.size.IsEmpty());
// SetDrawRectangle() will need to be called at the new size.
has_set_draw_rectangle_for_frame_ = false;
if (use_damage_area_from_skia_output_device_) {
- damage_of_current_buffer_ = gfx::Rect(size);
+ damage_of_current_buffer_ = gfx::Rect(params.size);
} else if (frame_buffer_damage_tracker_) {
- frame_buffer_damage_tracker_->FrameBuffersChanged(size);
+ frame_buffer_damage_tracker_->FrameBuffersChanged(params.size);
}
if (is_using_raw_draw_ && is_raw_draw_using_msaa_) {
@@ -312,34 +302,35 @@ void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
// On "low-end" devices use 4 samples per pixel to save memory.
sample_count_ = 4;
} else {
- sample_count_ = device_scale_factor >= 2.0f ? 4 : 8;
+ sample_count_ = params.device_scale_factor >= 2.0f ? 4 : 8;
}
} else {
sample_count_ = 1;
}
- const auto format_index = static_cast<int>(format);
+ const auto format_index = static_cast<int>(params.format);
const auto& color_type = capabilities_.sk_color_types[format_index];
DCHECK(color_type != kUnknown_SkColorType)
<< "SkColorType is invalid for buffer format_index: " << format_index;
- auto sk_color_space = color_space.ToSkColorSpace();
+ auto sk_color_space =
+ params.color_space.ToSkColorSpace(params.sdr_white_level);
characterization_ = CreateSkSurfaceCharacterization(
- size, color_type, /*mipmap=*/false, std::move(sk_color_space),
+ params.size, color_type, /*mipmap=*/false, std::move(sk_color_space),
/*is_root_render_pass=*/true, /*is_overlay=*/false);
// impl_on_gpu_ is released on the GPU thread by a posted task from
// SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
- auto task =
- base::BindOnce(&SkiaOutputSurfaceImplOnGpu::Reshape,
- base::Unretained(impl_on_gpu_.get()), characterization_,
- color_space, device_scale_factor, GetDisplayTransform());
+ auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::Reshape,
+ base::Unretained(impl_on_gpu_.get()),
+ characterization_, params.color_space,
+ params.device_scale_factor, GetDisplayTransform());
EnqueueGpuTask(std::move(task), {}, /*make_current=*/true,
/*need_framebuffer=*/!dependency_->IsOffscreen());
FlushGpuTasks(SyncMode::kNoWait);
- size_ = size;
- format_ = format;
+ size_ = params.size;
+ format_ = params.format;
RecreateRootRecorder();
}
@@ -604,6 +595,7 @@ SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space,
+ bool is_overlay,
const gpu::Mailbox& mailbox) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Make sure there is no unsubmitted PaintFrame or PaintRenderPass.
@@ -611,78 +603,39 @@ SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
DCHECK(resource_sync_tokens_.empty());
SkColorType color_type =
- ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format);
+ ResourceFormatToClosestSkColorType(/*gpu_compositing=*/true, format);
SkSurfaceCharacterization characterization = CreateSkSurfaceCharacterization(
surface_size, color_type, mipmap, std::move(color_space),
- /*is_root_render_pass=*/false, /*is_overlay=*/false);
+ /*is_root_render_pass=*/false, /*is_overlay=*/is_overlay);
if (!characterization.isValid())
return nullptr;
- current_paint_.emplace(characterization, id, mailbox);
- return current_paint_->recorder()->getCanvas();
-}
-
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
-SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPassOverlay(
- const gfx::Size& size,
- ResourceFormat format,
- bool mipmap,
- sk_sp<SkColorSpace> color_space) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Make sure there is no unsubmitted PaintFrame or PaintRenderPass.
- DCHECK(!current_paint_);
- SkColorType color_type =
- ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format);
- SkSurfaceCharacterization characterization = CreateSkSurfaceCharacterization(
- size, color_type, mipmap, std::move(color_space),
- /*is_root_render_pass=*/false, /*is_overlay=*/true);
- if (!characterization.isValid())
- return nullptr;
+ // We are going to overwrite the render pass when it is not for overlay, so we
+ // need to reset the image_context and a new promise image will be created
+ // when MakePromiseSkImageFromRenderPass() is called.
+ if (!is_overlay) {
+ auto it = render_pass_image_cache_.find(id);
+ if (it != render_pass_image_cache_.end()) {
+ it->second->clear_image();
+ }
+ }
- current_paint_.emplace(characterization);
+ current_paint_.emplace(characterization, mailbox);
return current_paint_->recorder()->getCanvas();
}
-sk_sp<SkDeferredDisplayList>
-SkiaOutputSurfaceImpl::EndPaintRenderPassOverlay() {
+void SkiaOutputSurfaceImpl::EndPaint(
+ base::OnceClosure on_finished,
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(current_paint_);
-
auto ddl = current_paint_->recorder()->detach();
- current_paint_.reset();
- return ddl;
-}
-#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
-
-void SkiaOutputSurfaceImpl::EndPaint(base::OnceClosure on_finished) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(current_paint_);
- // If current_render_pass_id_ is not null, we are painting a render pass.
- // Otherwise we are painting a frame.
-
- bool painting_render_pass = !current_paint_->render_pass_id().is_null();
- auto ddl = current_paint_->recorder()->detach();
-
- // impl_on_gpu_ is released on the GPU thread by a posted task from
- // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
- if (painting_render_pass) {
- auto it = render_pass_image_cache_.find(current_paint_->render_pass_id());
- if (it != render_pass_image_cache_.end()) {
- // We are going to overwrite the render pass, so we need reset the
- // image_context, so a new promise image will be created when the
- // MakePromiseSkImageFromRenderPass() is called.
- it->second->clear_image();
- }
-
- auto task = base::BindOnce(
- &SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass,
- base::Unretained(impl_on_gpu_.get()), current_paint_->mailbox(),
- std::move(ddl), std::move(images_in_current_paint_),
- resource_sync_tokens_, std::move(on_finished));
- EnqueueGpuTask(std::move(task), std::move(resource_sync_tokens_),
- /*make_current=*/true, /*need_framebuffer=*/false);
- } else {
+ // If the current paint mailbox is empty, we are painting a frame, otherwise
+ // we are painting a render pass. impl_on_gpu_ is released on the GPU thread
+ // by a posted task from SkiaOutputSurfaceImpl::dtor, so it is safe to use
+ // base::Unretained.
+ if (current_paint_->mailbox().IsZero()) {
// Draw on the root render pass.
current_buffer_modified_ = true;
sk_sp<SkDeferredDisplayList> overdraw_ddl;
@@ -698,10 +651,20 @@ void SkiaOutputSurfaceImpl::EndPaint(base::OnceClosure on_finished) {
&SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame,
base::Unretained(impl_on_gpu_.get()), std::move(ddl),
std::move(overdraw_ddl), std::move(images_in_current_paint_),
- resource_sync_tokens_, std::move(on_finished), draw_rectangle_);
+ resource_sync_tokens_, std::move(on_finished),
+ std::move(return_release_fence_cb), draw_rectangle_);
EnqueueGpuTask(std::move(task), std::move(resource_sync_tokens_),
/*make_current=*/true, /*need_framebuffer=*/true);
draw_rectangle_.reset();
+ } else {
+ auto task = base::BindOnce(
+ &SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass,
+ base::Unretained(impl_on_gpu_.get()), current_paint_->mailbox(),
+ std::move(ddl), std::move(images_in_current_paint_),
+ resource_sync_tokens_, std::move(on_finished),
+ std::move(return_release_fence_cb));
+ EnqueueGpuTask(std::move(task), std::move(resource_sync_tokens_),
+ /*make_current=*/true, /*need_framebuffer=*/false);
}
images_in_current_paint_.clear();
current_paint_.reset();
@@ -802,30 +765,12 @@ void SkiaOutputSurfaceImpl::CopyOutput(
void SkiaOutputSurfaceImpl::ScheduleOverlays(
OverlayList overlays,
- std::vector<gpu::SyncToken> sync_tokens,
- base::OnceClosure on_finished) {
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- // If there are render pass overlays, then a gl context is needed for drawing
- // the overlay render passes to a backing for being scanned out.
- bool make_current =
- std::find_if(overlays.begin(), overlays.end(), [](const auto& overlay) {
- return !!overlay.ddl;
- }) != overlays.end();
- // Append |resource_sync_tokens_| which are depended by drawing render passes
- // to overlay backings.
- std::move(resource_sync_tokens_.begin(), resource_sync_tokens_.end(),
- std::back_inserter(sync_tokens));
- resource_sync_tokens_.clear();
-#else
- bool make_current = false;
-#endif
- auto task = base::BindOnce(
- &SkiaOutputSurfaceImplOnGpu::ScheduleOverlays,
- base::Unretained(impl_on_gpu_.get()), std::move(overlays),
- std::move(images_in_current_paint_), std::move(on_finished));
- EnqueueGpuTask(std::move(task), std::move(sync_tokens), make_current,
- /*need_framebuffer=*/false);
- images_in_current_paint_.clear();
+ std::vector<gpu::SyncToken> sync_tokens) {
+ auto task =
+ base::BindOnce(&SkiaOutputSurfaceImplOnGpu::ScheduleOverlays,
+ base::Unretained(impl_on_gpu_.get()), std::move(overlays));
+ EnqueueGpuTask(std::move(task), std::move(sync_tokens),
+ /*make_current=*/false, /*need_framebuffer=*/false);
}
void SkiaOutputSurfaceImpl::SetFrameRate(float frame_rate) {
@@ -1050,9 +995,6 @@ void SkiaOutputSurfaceImpl::DidSwapBuffersComplete(
DCHECK(damage_of_current_buffer_);
}
- // texture_in_use_responses is used for GLRenderer only.
- DCHECK(params.texture_in_use_responses.empty());
-
if (!params.ca_layer_params.is_empty)
client_->DidReceiveCALayerParams(params.ca_layer_params);
client_->DidReceiveSwapBuffersAck(params.swap_response.timings,
@@ -1231,40 +1173,15 @@ GrBackendFormat SkiaOutputSurfaceImpl::GetGrBackendFormatForTexture(
return GrBackendFormat();
}
-uint32_t SkiaOutputSurfaceImpl::GetFramebufferCopyTextureFormat() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- return GL_RGB;
-}
-
bool SkiaOutputSurfaceImpl::IsDisplayedAsOverlayPlane() const {
return is_displayed_as_overlay_;
}
-unsigned SkiaOutputSurfaceImpl::GetOverlayTextureId() const {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return 0;
-}
-
gpu::Mailbox SkiaOutputSurfaceImpl::GetOverlayMailbox() const {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
return last_swapped_mailbox_;
}
-bool SkiaOutputSurfaceImpl::HasExternalStencilTest() const {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
- return false;
-}
-
-void SkiaOutputSurfaceImpl::ApplyExternalStencil() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-unsigned SkiaOutputSurfaceImpl::UpdateGpuFence() {
- return 0;
-}
-
void SkiaOutputSurfaceImpl::SetNeedsSwapSizeNotifications(
bool needs_swap_size_notifications) {
needs_swap_size_notifications_ = needs_swap_size_notifications;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
index be279278a47..685a7003fee 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -38,7 +38,8 @@ class DelegatedInkPointRenderer;
namespace gpu {
class SharedImageRepresentationFactory;
-}
+struct SwapBuffersCompleteParams;
+} // namespace gpu
namespace viz {
@@ -76,16 +77,11 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
// OutputSurface implementation:
gpu::SurfaceHandle GetSurfaceHandle() const override;
void BindToClient(OutputSurfaceClient* client) override;
- void BindFramebuffer() override;
void SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
void SetEnableDCLayers(bool enable) override;
void EnsureBackbuffer() override;
void DiscardBackbuffer() override;
- void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) override;
+ void Reshape(const ReshapeParams& params) override;
void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) override;
void SetGpuVSyncEnabled(bool enabled) override;
@@ -93,13 +89,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
void SetDisplayTransformHint(gfx::OverlayTransform transform) override;
gfx::OverlayTransform GetDisplayTransform() override;
void SwapBuffers(OutputSurfaceFrame frame) override;
- uint32_t GetFramebufferCopyTextureFormat() override;
bool IsDisplayedAsOverlayPlane() const override;
- unsigned GetOverlayTextureId() const override;
gpu::Mailbox GetOverlayMailbox() const override;
- bool HasExternalStencilTest() const override;
- void ApplyExternalStencil() override;
- unsigned UpdateGpuFence() override;
void SetNeedsSwapSizeNotifications(
bool needs_swap_size_notifications) override;
base::ScopedClosureRunner GetCacheBackBufferCb() override;
@@ -124,8 +115,11 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space,
+ bool is_overlay,
const gpu::Mailbox& mailbox) override;
- void EndPaint(base::OnceClosure on_finished) override;
+ void EndPaint(base::OnceClosure on_finished,
+ base::OnceCallback<void(gfx::GpuFenceHandle)>
+ return_release_fence_cb) override;
void MakePromiseSkImage(ImageContext* image_context) override;
sk_sp<SkImage> MakePromiseSkImageFromRenderPass(
const AggregatedRenderPassId& id,
@@ -138,8 +132,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
void RemoveRenderPassResource(
std::vector<AggregatedRenderPassId> ids) override;
void ScheduleOverlays(OverlayList overlays,
- std::vector<gpu::SyncToken> sync_tokens,
- base::OnceClosure on_finished) override;
+ std::vector<gpu::SyncToken> sync_tokens) override;
void CopyOutput(AggregatedRenderPassId id,
const copy_output::RenderPassGeometry& geometry,
@@ -153,15 +146,6 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
gpu::SyncToken Flush() override;
bool EnsureMinNumberOfBuffers(int n) override;
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- SkCanvas* BeginPaintRenderPassOverlay(
- const gfx::Size& size,
- ResourceFormat format,
- bool mipmap,
- sk_sp<SkColorSpace> color_space) override;
- sk_sp<SkDeferredDisplayList> EndPaintRenderPassOverlay() override;
-#endif
-
// ExternalUseClient implementation:
gpu::SyncToken ReleaseImageContexts(
std::vector<std::unique_ptr<ImageContext>> image_contexts) override;
@@ -255,21 +239,18 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
explicit ScopedPaint(SkDeferredDisplayListRecorder* root_recorder);
explicit ScopedPaint(SkSurfaceCharacterization characterization);
ScopedPaint(SkSurfaceCharacterization characterization,
- AggregatedRenderPassId render_pass_id,
gpu::Mailbox mailbox);
~ScopedPaint();
SkDeferredDisplayListRecorder* recorder() { return recorder_; }
- AggregatedRenderPassId render_pass_id() { return render_pass_id_; }
gpu::Mailbox mailbox() { return mailbox_; }
private:
// This is recorder being used for current paint
SkDeferredDisplayListRecorder* recorder_;
- // If we need new recorder for this Paint (i.e it's not root render pass),
+ // If we need new recorder for this Paint (i.e. it's not root render pass),
// it's stored here
absl::optional<SkDeferredDisplayListRecorder> recorder_storage_;
- const AggregatedRenderPassId render_pass_id_;
const gpu::Mailbox mailbox_;
};
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index 620942a9ec8..dcca5fa92f6 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -12,6 +12,8 @@
#include "base/callback_helpers.h"
#include "base/debug/crash_logging.h"
#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/notreached.h"
#include "base/task/bind_post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
@@ -37,7 +39,10 @@
#include "components/viz/service/display_embedder/skia_output_device_webview.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
#include "components/viz/service/display_embedder/skia_render_copy_results.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
+#include "gpu/command_buffer/common/sync_token.h"
+#include "gpu/command_buffer/service/external_semaphore.h"
#include "gpu/command_buffer/service/gr_shader_cache.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "gpu/command_buffer/service/scheduler.h"
@@ -64,14 +69,19 @@
#include "third_party/skia/include/core/SkSamplingOptions.h"
#include "third_party/skia/include/core/SkSize.h"
#include "third_party/skia/include/core/SkYUVAInfo.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/gpu_fence_handle.h"
+#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_surface.h"
#if BUILDFLAG(ENABLE_VULKAN)
#include "components/viz/service/display_embedder/skia_output_device_vulkan.h"
+#include "gpu/vulkan/vulkan_device_queue.h"
+#include "gpu/vulkan/vulkan_function_pointers.h"
+#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_util.h"
#if BUILDFLAG(IS_ANDROID)
#include "components/viz/service/display_embedder/skia_output_device_vulkan_secondary_cb.h"
@@ -357,6 +367,11 @@ SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() {
// before deleting ImplOnGpu's other member variables.
shared_image_factory_.reset();
if (has_context) {
+ absl::optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
+ if (dependency_->GetGrShaderCache()) {
+ cache_use.emplace(dependency_->GetGrShaderCache(),
+ gpu::kDisplayCompositorClientId);
+ }
// This ensures any outstanding callbacks for promise images are
// performed.
gr_context()->flushAndSubmit();
@@ -393,6 +408,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
base::OnceClosure on_finished,
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb,
absl::optional<gfx::Rect> draw_rectangle) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -445,7 +461,12 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
// Draw will only fail if the SkSurface and SkDDL are incompatible.
bool draw_success = scoped_output_device_paint_->Draw(ddl);
+#if defined(USE_OZONE)
+ if (!draw_success)
+ DLOG(ERROR) << "output_sk_surface()->draw() failed.";
+#else
DCHECK(draw_success);
+#endif // USE_OZONE
destroy_after_swap_.emplace_back(std::move(ddl));
@@ -470,7 +491,24 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
end_semaphores.insert(end_semaphores.end(), end_paint_semaphores.begin(),
end_paint_semaphores.end());
+#if BUILDFLAG(ENABLE_VULKAN)
+ // Semaphores for release fences for vulkan should be created before flush.
+ if (!return_release_fence_cb.is_null() && is_using_vulkan()) {
+ const bool result = CreateAndStoreExternalSemaphoreVulkan(end_semaphores);
+ // A release fence will be created on submit as some platforms may use
+ // VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT handle types for their
+ // external semaphore. That handle type has COPY transference. Vulkan spec
+ // says that semaphore has to be signaled, or have an associated semaphore
+ // signal operation pending execution. Thus, delay importing the handle
+ // and creating the fence until commands are submitted.
+ pending_release_fence_cbs_.emplace_back(
+ result ? end_semaphores.back() : GrBackendSemaphore(),
+ std::move(return_release_fence_cb));
+ }
+#endif
+
const bool end_semaphores_empty = end_semaphores.empty();
+
auto result = scoped_output_device_paint_->Flush(vulkan_context_provider_,
std::move(end_semaphores),
std::move(on_finished));
@@ -481,6 +519,22 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
FailedSkiaFlush("output_sk_surface()->flush() failed.");
return;
}
+
+ gfx::GpuFenceHandle release_fence;
+ if (!return_release_fence_cb.is_null() && is_using_gl()) {
+ DCHECK(release_fence.is_null());
+ release_fence = CreateReleaseFenceForGL();
+ }
+
+ if (!return_release_fence_cb.is_null() && is_using_dawn())
+ NOTIMPLEMENTED() << "Release fences with dawn are not supported.";
+
+ if (!return_release_fence_cb.is_null()) {
+ // Returning fences for Vulkan is delayed. See the comment above.
+ DCHECK(!is_using_vulkan());
+ PostTaskToClientThread(base::BindOnce(std::move(return_release_fence_cb),
+ std::move(release_fence)));
+ }
}
}
@@ -525,7 +579,8 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
sk_sp<SkDeferredDisplayList> ddl,
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
- base::OnceClosure on_finished) {
+ base::OnceClosure on_finished,
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(ddl);
@@ -576,6 +631,22 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
backing_representation->SetCleared();
destroy_after_swap_.emplace_back(std::move(ddl));
+#if BUILDFLAG(ENABLE_VULKAN)
+ // Semaphores for release fences for vulkan should be created before flush.
+ if (!return_release_fence_cb.is_null() && is_using_vulkan()) {
+ const bool result = CreateAndStoreExternalSemaphoreVulkan(end_semaphores);
+ // A release fence will be created on submit as some platforms may use
+ // VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT handle types for their
+ // external semaphore. That handle type has COPY transference. Vulkan spec
+ // says that semaphore has to be signaled, or have an associated semaphore
+ // signal operation pending execution. Thus, delay importing the handle
+ // and creating the fence until commands are submitted.
+ pending_release_fence_cbs_.emplace_back(
+ result ? end_semaphores.back() : GrBackendSemaphore(),
+ std::move(return_release_fence_cb));
+ }
+#endif
+
GrFlushInfo flush_info = {
.fNumSemaphores = end_semaphores.size(),
.fSignalSemaphores = end_semaphores.data(),
@@ -584,6 +655,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
&flush_info);
if (on_finished)
gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info);
+
auto result = surface->flush(flush_info);
if (result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
@@ -591,6 +663,24 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
FailedSkiaFlush("offscreen.surface()->flush() failed.");
return;
}
+
+ // If GL is used, create the release fence after flush.
+ gfx::GpuFenceHandle release_fence;
+ if (!return_release_fence_cb.is_null() && is_using_gl()) {
+ DCHECK(release_fence.is_null());
+ release_fence = CreateReleaseFenceForGL();
+ }
+
+ if (!return_release_fence_cb.is_null() && is_using_dawn())
+ NOTIMPLEMENTED() << "Release fences with dawn are not supported.";
+
+ if (!return_release_fence_cb.is_null()) {
+ // Returning fences for Vulkan is delayed. See the comment above.
+ DCHECK(!is_using_vulkan());
+ PostTaskToClientThread(base::BindOnce(std::move(return_release_fence_cb),
+ std::move(release_fence)));
+ }
+
bool sync_cpu =
gpu::ShouldVulkanSyncCpuForSkiaSubmit(vulkan_context_provider_);
if (sync_cpu) {
@@ -701,12 +791,24 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputRGBA(
request->scale_from().y());
}
- bool success = RenderSurface(surface, src_rect, scaling,
- is_downscale_or_identity_in_both_dimensions,
- scoped_write->surface(), begin_semaphores,
- end_semaphores);
- if (!success) {
- DLOG(ERROR) << "failed to render surface.";
+ scoped_write->surface()->wait(begin_semaphores.size(),
+ begin_semaphores.data());
+
+ RenderSurface(surface, src_rect, scaling,
+ is_downscale_or_identity_in_both_dimensions,
+ scoped_write->surface());
+
+ bool should_submit = !end_semaphores.empty();
+
+ if (!FlushSurface(scoped_write->surface(), end_semaphores,
+ scoped_write->TakeEndState())) {
+ // TODO(penghuang): handle vulkan device lost.
+ FailedSkiaFlush("CopyOutputRGBA dest_surface->flush()");
+ return;
+ }
+
+ if (should_submit && !gr_context()->submit()) {
+ DLOG(ERROR) << "CopyOutputRGBA gr_context->submit() failed";
return;
}
@@ -730,16 +832,12 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputRGBA(
}
}
-bool SkiaOutputSurfaceImplOnGpu::RenderSurface(
+void SkiaOutputSurfaceImplOnGpu::RenderSurface(
SkSurface* surface,
const SkIRect& source_selection,
absl::optional<SkVector> scaling,
bool is_downscale_or_identity_in_both_dimensions,
- SkSurface* dest_surface,
- std::vector<GrBackendSemaphore>& begin_semaphores,
- std::vector<GrBackendSemaphore>& end_semaphores) {
- dest_surface->wait(begin_semaphores.size(), begin_semaphores.data());
-
+ SkSurface* dest_surface) {
SkCanvas* dest_canvas = dest_surface->getCanvas();
int state_depth = dest_canvas->save();
@@ -765,21 +863,23 @@ bool SkiaOutputSurfaceImplOnGpu::RenderSurface(
sampling, /*paint=*/nullptr);
dest_canvas->restoreToCount(state_depth);
+}
+bool SkiaOutputSurfaceImplOnGpu::FlushSurface(
+ SkSurface* surface,
+ std::vector<GrBackendSemaphore>& end_semaphores,
+ std::unique_ptr<GrBackendSurfaceMutableState> end_state,
+ GrGpuFinishedProc finished_proc,
+ GrGpuFinishedContext finished_context) {
GrFlushInfo flush_info;
flush_info.fNumSemaphores = end_semaphores.size();
flush_info.fSignalSemaphores = end_semaphores.data();
+ flush_info.fFinishedProc = finished_proc;
+ flush_info.fFinishedContext = finished_context;
gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_, &flush_info);
- GrSemaphoresSubmitted flush_result = dest_surface->flush(
- SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
- if (flush_result != GrSemaphoresSubmitted::kYes &&
- !(begin_semaphores.empty() && end_semaphores.empty())) {
- // TODO(penghuang): handle vulkan device lost.
- FailedSkiaFlush("dest_surface->flush() failed.");
- return false;
- }
-
- return true;
+ GrSemaphoresSubmitted flush_result =
+ surface->flush(flush_info, end_state.get());
+ return flush_result == GrSemaphoresSubmitted::kYes || end_semaphores.empty();
}
SkiaOutputSurfaceImplOnGpu::PlaneAccessData::PlaneAccessData() = default;
@@ -838,8 +938,8 @@ bool SkiaOutputSurfaceImplOnGpu::ImportSurfacesForNV12Planes(
for (size_t i = 0; i < CopyOutputResult::kNV12MaxPlanes; ++i) {
const gpu::MailboxHolder& mailbox_holder = blit_request.mailbox(i);
- // Should never happen, maiboxes are validated when setting blit request on
- // a CopyOutputResult.
+ // Should never happen, mailboxes are validated when setting blit request on
+ // a CopyOutputResult and we only access `kNV12MaxPlanes` mailboxes.
DCHECK(!mailbox_holder.mailbox.IsZero());
PlaneAccessData& plane_data = plane_access_datas[i];
@@ -901,6 +1001,9 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
CopyOutputRequest::ResultDestination::kNativeTextures)
<< "Only CopyOutputRequests that hand out native textures support blit "
"requests!";
+ DCHECK(!request->has_blit_request() || request->has_result_selection())
+ << "Only CopyOutputRequests that specify result selection support blit "
+ "requests!";
// Overview:
// 1. Try to create surfaces for NV12 planes (we know the needed size in
@@ -917,22 +1020,39 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
// - pass ownership of the textures to the caller (native textures result)
// - schedule a read-back & expose its results to the caller (system memory
// result)
+ //
+ // Note: in case the blit request populates the GMBs, the flow stays the same,
+ // but we need to ensure that the results are only sent out after the
+ // GpuMemoryBuffer is safe to map into system memory.
// The size of the destination is passed in via `geometry.result_selection` -
// it already takes into account the rect of the render pass that is being
// copied, as well as area, scaling & result_selection of the `request`.
// This represents the size of the intermediate texture that will be then
// blitted to the destination textures.
- const gfx::Size destination_size = geometry.result_selection.size();
+ const gfx::Size intermediate_dst_size = geometry.result_selection.size();
std::array<PlaneAccessData, CopyOutputResult::kNV12MaxPlanes>
plane_access_datas;
SkYUVAInfo yuva_info;
- bool destination_surfaces_created = false;
+ bool destination_surfaces_ready = false;
if (request->has_blit_request()) {
- destination_surfaces_created = ImportSurfacesForNV12Planes(
+ if (request->result_selection().size() != intermediate_dst_size) {
+ DLOG(WARNING)
+ << __func__
+ << ": result selection is different than render pass output, "
+ "geometry="
+ << geometry.ToString() << ", request=" << request->ToString();
+ // Send empty result, we have a blit request that asks for a different
+ // size than what we have available - the behavior in this case is
+ // currently unspecified as we'd have to leave parts of the caller's
+ // region unpopulated.
+ return;
+ }
+
+ destination_surfaces_ready = ImportSurfacesForNV12Planes(
request->blit_request(), plane_access_datas);
// The entire destination image size is the same as the size of the luma
@@ -943,7 +1063,8 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
// Check if the destination will fit in the blit target:
const gfx::Rect blit_destination_rect(
- request->blit_request().destination_region_offset(), destination_size);
+ request->blit_request().destination_region_offset(),
+ intermediate_dst_size);
const gfx::Rect blit_target_image_rect(
gfx::SkISizeToSize(plane_access_datas[0].size));
@@ -953,24 +1074,25 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
return;
}
} else {
- yuva_info = SkYUVAInfo(
- gfx::SizeToSkISize(destination_size), SkYUVAInfo::PlaneConfig::kY_UV,
- SkYUVAInfo::Subsampling::k420, kRec709_Limited_SkYUVColorSpace);
+ yuva_info = SkYUVAInfo(gfx::SizeToSkISize(intermediate_dst_size),
+ SkYUVAInfo::PlaneConfig::kY_UV,
+ SkYUVAInfo::Subsampling::k420,
+ kRec709_Limited_SkYUVColorSpace);
- destination_surfaces_created =
+ destination_surfaces_ready =
CreateSurfacesForNV12Planes(yuva_info, color_space, plane_access_datas);
}
- if (!destination_surfaces_created) {
- DVLOG(1) << "failed to create destination surfaces";
+ if (!destination_surfaces_ready) {
+ DVLOG(1) << "failed to create / import destination surfaces";
// Send empty result.
return;
}
// Create a destination for the scaled & clipped result:
- auto representation = CreateSharedImageRepresentationSkia(
- ResourceFormat::RGBA_8888, destination_size, color_space);
- if (!representation) {
+ auto intermediate_representation = CreateSharedImageRepresentationSkia(
+ ResourceFormat::RGBA_8888, intermediate_dst_size, color_space);
+ if (!intermediate_representation) {
DVLOG(1) << "failed to create shared image representation for the "
"intermediate surface";
// Send empty result.
@@ -981,9 +1103,11 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
std::vector<GrBackendSemaphore> begin_semaphores;
std::vector<GrBackendSemaphore> end_semaphores;
- auto scoped_write = representation->BeginScopedWriteAccess(
- /*final_msaa_count=*/1, surface_props, &begin_semaphores, &end_semaphores,
- gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
+ auto intermediate_scoped_write =
+ intermediate_representation->BeginScopedWriteAccess(
+ /*final_msaa_count=*/1, surface_props, &begin_semaphores,
+ &end_semaphores,
+ gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
absl::optional<SkVector> scaling;
if (request->is_scaled()) {
@@ -993,24 +1117,22 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
request->scale_from().y());
}
- bool success = RenderSurface(
- surface, src_rect, scaling, is_downscale_or_identity_in_both_dimensions,
- scoped_write->surface(), begin_semaphores, end_semaphores);
- if (!success) {
- DLOG(ERROR) << "failed to render surface.";
- return;
- }
+ intermediate_scoped_write->surface()->wait(begin_semaphores.size(),
+ begin_semaphores.data());
- representation->SetCleared();
+ RenderSurface(surface, src_rect, scaling,
+ is_downscale_or_identity_in_both_dimensions,
+ intermediate_scoped_write->surface());
if (request->has_blit_request()) {
- BlendBitmapOverlays(scoped_write->surface()->getCanvas(),
+ BlendBitmapOverlays(intermediate_scoped_write->surface()->getCanvas(),
request->blit_request());
}
- auto source_image = scoped_write->surface()->makeImageSnapshot();
- if (!source_image) {
- DLOG(ERROR) << "failed to retrieve source_image.";
+ auto intermediate_image =
+ intermediate_scoped_write->surface()->makeImageSnapshot();
+ if (!intermediate_image) {
+ DLOG(ERROR) << "failed to retrieve `intermediate_image`.";
return;
}
@@ -1022,60 +1144,137 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutputNV12(
plane_access_datas[1].scoped_write->surface(), nullptr, nullptr};
// The region to be populated in caller's textures is derived from blit
- // request's |destination_region_offset|, and from COR's |result_selection|.
- // If we have a blit request, use it. Otherwise, use an
+ // request's |destination_region_offset()|, and from COR's
+ // |result_selection()|. If we have a blit request, use it. Otherwise, use an
// empty rect (which means that entire image will be used as the target of the
// blit - this will not result in rescaling since w/o blit request present,
- // the image size matches the |result_selection|).
- SkRect dst_region =
+ // the destination image size matches the |geometry.result_selection|).
+ const SkRect dst_region =
request->has_blit_request()
? gfx::RectToSkRect(
gfx::Rect(request->blit_request().destination_region_offset(),
- destination_size))
+ intermediate_dst_size))
: SkRect::MakeEmpty();
- skia::BlitRGBAToYUVA(source_image.get(), plane_surfaces.data(), yuva_info,
- dst_region);
+ // We should clear destination if BlitRequest asked to letterbox everything
+ // outside of intended destination region:
+ const bool clear_destination =
+ request->has_blit_request()
+ ? request->blit_request().letterboxing_behavior() ==
+ LetterboxingBehavior::kLetterbox
+ : false;
+ skia::BlitRGBAToYUVA(intermediate_image.get(), plane_surfaces.data(),
+ yuva_info, dst_region, clear_destination);
+
+ // Collect mailbox holders for the destination textures. They will be needed
+ // in case the result is kNativeTextures. It happens here in order to simplify
+ // the code in case we are populating the GpuMemoryBuffer-backed textures.
+ std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes>
+ plane_mailbox_holders = {
+ gpu::MailboxHolder(plane_access_datas[0].mailbox, gpu::SyncToken(),
+ GL_TEXTURE_2D),
+ gpu::MailboxHolder(plane_access_datas[1].mailbox, gpu::SyncToken(),
+ GL_TEXTURE_2D),
+ gpu::MailboxHolder(),
+ };
+
+ // If we are not the ones allocating the textures, they may come from a GMB,
+ // in which case we need to delay sending the results until we receive a
+ // callback that the GPU work has completed - otherwise, memory-mapping the
+ // GMB may not yield the latest version of the contents.
+ const bool should_wait_for_gpu_work =
+ request->result_destination() ==
+ CopyOutputRequest::ResultDestination::kNativeTextures &&
+ request->has_blit_request() &&
+ request->blit_request().populates_gpu_memory_buffer();
+
+ scoped_refptr<NV12PlanesReadyContext> nv12_planes_ready = nullptr;
+ if (should_wait_for_gpu_work) {
+ // Prepare a per-CopyOutputRequest context that will be responsible for
+ // sending the CopyOutputResult:
+ nv12_planes_ready = base::MakeRefCounted<NV12PlanesReadyContext>(
+ weak_ptr_, std::move(request), geometry.result_selection,
+ plane_mailbox_holders, color_space);
+ }
+
+ bool should_submit = false;
for (size_t i = 0; i < CopyOutputResult::kNV12MaxPlanes; ++i) {
plane_access_datas[i].representation->SetCleared();
- GrFlushInfo flush_info;
- flush_info.fNumSemaphores = plane_access_datas[i].end_semaphores.size();
- flush_info.fSignalSemaphores = plane_access_datas[i].end_semaphores.data();
-
- gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_,
- &flush_info);
+ should_submit |= !plane_access_datas[i].end_semaphores.empty();
+
+ // Prepare a per-plane context that will notify the per-request context that
+ // GPU work that produces the contents of a plane that the GPU-side of the
+ // work has completed.
+ std::unique_ptr<NV12SinglePlaneReadyContext> nv12_plane_ready =
+ should_wait_for_gpu_work
+ ? std::make_unique<NV12SinglePlaneReadyContext>(nv12_planes_ready)
+ : nullptr;
+
+ if (should_wait_for_gpu_work) {
+ // Treat the fact that we're waiting for GPU work to finish the same way
+ // as a readback request. This would allow us to nudge Skia to fire the
+ // callbacks. See `SkiaOutputSurfaceImplOnGpu::CheckReadbackCompletion()`.
+ ++num_readbacks_pending_;
+ }
- auto flush_result = plane_surfaces[i]->flush(
- SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
- if (flush_result != GrSemaphoresSubmitted::kYes &&
- !(begin_semaphores.empty() && end_semaphores.empty())) {
+ if (!FlushSurface(
+ plane_surfaces[i], plane_access_datas[i].end_semaphores,
+ plane_access_datas[i].scoped_write->TakeEndState(),
+ should_wait_for_gpu_work
+ ? &NV12SinglePlaneReadyContext::OnNV12PlaneReady
+ : nullptr,
+ should_wait_for_gpu_work ? nv12_plane_ready.release() : nullptr)) {
// TODO(penghuang): handle vulkan device lost.
- FailedSkiaFlush("plane_surfaces[i]->flush()");
+ FailedSkiaFlush("CopyOutputNV12 plane_surfaces[i]->flush()");
return;
}
}
+ should_submit |= !end_semaphores.empty();
+
+ intermediate_representation->SetCleared();
+ if (!FlushSurface(intermediate_scoped_write->surface(), end_semaphores,
+ intermediate_scoped_write->TakeEndState())) {
+ // TODO(penghuang): handle vulkan device lost.
+ FailedSkiaFlush("CopyOutputNV12 dest_surface->flush()");
+ return;
+ }
+
+ if (should_submit && !gr_context()->submit()) {
+ DLOG(ERROR) << "CopyOutputNV12 gr_context->submit() failed";
+ return;
+ }
+
+ if (should_wait_for_gpu_work) {
+ // Flow will continue after GPU work is done - see
+ // `NV12PlanesReadyContext::OnNV12PlaneReady()` that eventually gets called.
+ return;
+ }
+
+ // We conditionally move from request (if `should_wait_for_gpu_work` is true),
+ // DCHECK that we don't accidentally enter this codepath after the request was
+ // moved from.
+ DCHECK(request);
+
switch (request->result_destination()) {
case CopyOutputRequest::ResultDestination::kNativeTextures: {
CopyOutputResult::ReleaseCallbacks release_callbacks;
- std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes> planes;
- for (size_t i = 0; i < CopyOutputResult::kNV12MaxPlanes; ++i) {
- if (!request->has_blit_request()) {
- // In blit requests, we are not responsible for releasing the textures
- // (the issuer of the request owns them), do not create the callbacks.
+ if (!request->has_blit_request()) {
+ // In blit requests, we are not responsible for releasing the textures
+ // (the issuer of the request owns them), create the callbacks only if
+ // we don't have blit request:
+ for (size_t i = 0; i < CopyOutputResult::kNV12MaxPlanes; ++i) {
release_callbacks.push_back(
CreateDestroyCopyOutputResourcesOnGpuThreadCallback(
std::move(plane_access_datas[i].representation)));
}
-
- planes[i].mailbox = plane_access_datas[i].mailbox;
}
request->SendResult(std::make_unique<CopyOutputTextureResult>(
CopyOutputResult::Format::NV12_PLANES, geometry.result_selection,
- CopyOutputResult::TextureResult(planes, color_space),
+ CopyOutputResult::TextureResult(plane_mailbox_holders, color_space),
std::move(release_callbacks)));
break;
@@ -1148,6 +1347,7 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
scoped_access;
std::vector<GrBackendSemaphore> begin_semaphores;
std::vector<GrBackendSemaphore> end_semaphores;
+ std::unique_ptr<GrBackendSurfaceMutableState> end_state;
if (from_framebuffer) {
surface = scoped_output_device_paint_->sk_surface();
} else {
@@ -1162,6 +1362,7 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
&end_semaphores,
gpu::SharedImageRepresentation::AllowUnclearedAccess::kNo);
surface = scoped_access->surface();
+ end_state = scoped_access->TakeEndState();
if (!begin_semaphores.empty()) {
auto result =
surface->wait(begin_semaphores.size(), begin_semaphores.data(),
@@ -1269,20 +1470,10 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
}
}
- if (!end_semaphores.empty()) {
- GrFlushInfo flush_info;
- flush_info.fNumSemaphores = end_semaphores.size();
- flush_info.fSignalSemaphores = end_semaphores.data();
- gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_,
- &flush_info);
- auto flush_result =
- surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
- if (flush_result != GrSemaphoresSubmitted::kYes &&
- !(begin_semaphores.empty() && end_semaphores.empty())) {
- // TODO(penghuang): handle vulkan device lost.
- FailedSkiaFlush("surface->flush() failed.");
- return;
- }
+ if (!FlushSurface(surface, end_semaphores, std::move(end_state))) {
+ // TODO(penghuang): handle vulkan device lost.
+ FailedSkiaFlush("surface->flush() failed.");
+ return;
}
ScheduleCheckReadbackCompletion();
@@ -1326,8 +1517,9 @@ void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
context->BeginAccessIfNecessary(
context_state_.get(), shared_image_representation_factory_.get(),
dependency_->GetMailboxManager(), begin_semaphores, end_semaphores);
- if (context->end_access_state())
- image_contexts_with_end_access_state_.emplace(context);
+ if (auto end_state = context->TakeAccessEndState())
+ image_contexts_with_end_access_state_.emplace(context,
+ std::move(end_state));
// Texture parameters can be modified by concurrent reads so reset them
// before compositing from the texture. See https://crbug.com/1092080.
@@ -1342,11 +1534,10 @@ void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
}
void SkiaOutputSurfaceImplOnGpu::ResetStateOfImages() {
- for (auto* context : image_contexts_with_end_access_state_) {
- DCHECK(context->end_access_state());
+ for (auto& context : image_contexts_with_end_access_state_) {
if (!gr_context()->setBackendTextureState(
- context->promise_image_texture()->backendTexture(),
- *context->end_access_state())) {
+ context.first->promise_image_texture()->backendTexture(),
+ *context.second)) {
DLOG(ERROR) << "setBackendTextureState() failed.";
}
}
@@ -1382,73 +1573,21 @@ void SkiaOutputSurfaceImplOnGpu::ReleaseImageContexts(
}
void SkiaOutputSurfaceImplOnGpu::ScheduleOverlays(
- SkiaOutputSurface::OverlayList overlays,
- std::vector<ImageContextImpl*> image_contexts,
- base::OnceClosure on_finished) {
+ SkiaOutputSurface::OverlayList overlays) {
TRACE_EVENT1("viz", "SkiaOutputSurfaceImplOnGpu::ScheduleOverlays",
"num_overlays", overlays.size());
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- if (context_is_lost_)
- return;
-
- bool have_image_contexts = !image_contexts.empty();
- if (have_image_contexts) {
- DCHECK(context_state_->GrContextIsGL());
-
- // GL doesn't use semaphores.
- promise_image_access_helper_.BeginAccess(std::move(image_contexts),
- /*begin_semaphores=*/nullptr,
- /*end_semaphores=*/nullptr);
- }
-
- using ScopedWriteAccess =
- std::unique_ptr<gpu::SharedImageRepresentationSkia::ScopedWriteAccess>;
- std::vector<ScopedWriteAccess> scoped_write_accesses;
- for (auto& overlay : overlays) {
- if (!overlay.ddl)
- continue;
- const auto& characterization = overlay.ddl->characterization();
- auto backing = GetOrCreateRenderPassOverlayBacking(characterization);
- if (!backing)
- break;
- DCHECK(overlay.mailbox.IsZero());
- overlay.mailbox = backing->mailbox();
- auto scoped_access = backing->BeginScopedWriteAccess(
- characterization.sampleCount(), characterization.surfaceProps(),
- /*begin_semaphores=*/nullptr,
- /*end_semaphores=*/nullptr,
- gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
- bool result = scoped_access->surface()->draw(overlay.ddl);
- DCHECK(result);
- scoped_write_accesses.push_back(std::move(scoped_access));
- backing->SetCleared();
- in_flight_render_pass_overlay_backings_.insert(std::move(backing));
- }
-
- if (!scoped_write_accesses.empty()) {
- absl::optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
- if (dependency_->GetGrShaderCache()) {
- cache_use.emplace(dependency_->GetGrShaderCache(),
- gpu::kDisplayCompositorClientId);
- }
-
- GrFlushInfo flush_info = {};
- if (on_finished)
- gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info);
- context_state_->gr_context()->flush(flush_info);
- context_state_->gr_context()->submit();
- scoped_write_accesses.clear();
- }
-
- if (have_image_contexts)
- promise_image_access_helper_.EndAccess();
+ constexpr base::TimeDelta kHistogramMinTime = base::Microseconds(5);
+ constexpr base::TimeDelta kHistogramMaxTime = base::Milliseconds(16);
+ constexpr int kHistogramTimeBuckets = 50;
+ base::TimeTicks start_time = base::TimeTicks::Now();
output_device_->ScheduleOverlays(std::move(overlays));
-#else
- DCHECK(image_contexts.empty());
- output_device_->ScheduleOverlays(std::move(overlays));
-#endif
+
+ UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+ "Gpu.OutputSurface.ScheduleOverlaysUs",
+ base::TimeTicks::Now() - start_time, kHistogramMinTime, kHistogramMaxTime,
+ kHistogramTimeBuckets);
}
void SkiaOutputSurfaceImplOnGpu::SetEnableDCLayers(bool enable) {
@@ -1769,17 +1908,6 @@ void SkiaOutputSurfaceImplOnGpu::SwapBuffersInternal(
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(output_device_);
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- // Release any backings which are not reused by the current frame, probably
- // because the properties of render passes are changed or render passes are
- // removed
- if (context_is_lost_) {
- for (auto& image : available_render_pass_overlay_backings_)
- image->OnContextLost();
- }
- available_render_pass_overlay_backings_.clear();
-#endif
-
if (context_is_lost_)
return;
@@ -1806,6 +1934,20 @@ void SkiaOutputSurfaceImplOnGpu::PostSubmit(
promise_image_access_helper_.EndAccess();
scoped_output_device_paint_.reset();
+#if BUILDFLAG(ENABLE_VULKAN)
+ while (!pending_release_fence_cbs_.empty()) {
+ auto& item = pending_release_fence_cbs_.front();
+ auto release_fence = CreateReleaseFenceForVulkan(item.first);
+ if (release_fence.is_null())
+ LOG(ERROR) << "Unable to create a release fence for Vulkan.";
+ PostTaskToClientThread(
+ base::BindOnce(std::move(item.second), std::move(release_fence)));
+ pending_release_fence_cbs_.pop_front();
+ }
+#else
+ DCHECK(pending_release_fence_cbs_.empty());
+#endif
+
if (frame) {
if (waiting_for_full_damage_) {
// If we're using partial swap, we need to check whether the sub-buffer
@@ -1901,17 +2043,6 @@ base::TimeDelta SkiaOutputSurfaceImplOnGpu::GetGpuBlockedTimeSinceLastSwap() {
return dependency_->GetGpuBlockedTimeSinceLastSwap();
}
-void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersComplete(
- gpu::SwapBuffersCompleteParams params,
- gfx::GpuFenceHandle release_fence) {
- // Handled by SkiaOutputDevice already.
-}
-
-void SkiaOutputSurfaceImplOnGpu::BufferPresented(
- const gfx::PresentationFeedback& feedback) {
- // Handled by SkiaOutputDevice already.
-}
-
void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal(
gpu::SwapBuffersCompleteParams params,
const gfx::Size& pixel_size,
@@ -1935,36 +2066,6 @@ void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal(
waiting_for_full_damage_ = true;
}
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- // |available_render_pass_overlay_backings_| are used or released in
- // SwapBuffers() for every frames. For Ozone-Wayland
- // |available_render_pass_overlay_backings_| is not always empty because the
- // buffer management in 'GbmSurfacelessWayland::SwapBuffersAsync' will cause
- // an accumulation of unsubmitted frames in |unsubmitted_frames_|. These are
- // submitted in 'GbmSurfacelessWayland::MaybeSubmitFrames'. Later
- // 'GbmSurfacelessWayland::OnSubmission' will then call the callback of these
- // |submitted_frames| more than once. This means that this function
- // 'DidSwapBuffersCompleteInternal' will get executed again before the
- // corresponding 'SkiaOutputSurfaceImplOnGpu::SwapBuffersInternal' has cleared
- // 'available_render_pass_overlay_backings_'.
-#if !defined(USE_OZONE)
- DCHECK(available_render_pass_overlay_backings_.empty());
-#endif
- // Erase mailboxes of render pass overlays from |params.released_overlays| and
- // move released backings for those render pass overlays from
- // |in_flight_render_pass_overlay_backings_| to
- // |available_render_pass_overlay_backings_| for reusing.
- base::EraseIf(params.released_overlays, [this](const gpu::Mailbox& mailbox) {
- auto it = in_flight_render_pass_overlay_backings_.find(mailbox);
- if (it == in_flight_render_pass_overlay_backings_.end())
- return false;
- available_render_pass_overlay_backings_.push_back(std::move(*it));
- in_flight_render_pass_overlay_backings_.erase(it);
- return true;
- });
-
-#endif
-
PostTaskToClientThread(base::BindOnce(did_swap_buffer_complete_callback_,
params, pixel_size,
std::move(release_fence)));
@@ -2024,76 +2125,6 @@ void SkiaOutputSurfaceImplOnGpu::PreserveChildSurfaceControls() {
gl_surface_->PreserveChildSurfaceControls();
}
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
-std::unique_ptr<gpu::SharedImageRepresentationSkia>
-SkiaOutputSurfaceImplOnGpu::GetOrCreateRenderPassOverlayBacking(
- const SkSurfaceCharacterization& characterization) {
- ResourceFormat resource_format;
- switch (characterization.colorType()) {
- case kRGBA_8888_SkColorType:
- resource_format = ResourceFormat::RGBA_8888;
- break;
- case kBGRA_8888_SkColorType:
- resource_format = ResourceFormat::BGRA_8888;
- break;
- case kRGBA_F16_SkColorType:
- resource_format = ResourceFormat::RGBA_F16;
- break;
- default:
- resource_format = ResourceFormat::RGBA_8888;
- NOTREACHED();
- }
-
- gfx::Size size(characterization.width(), characterization.height());
- gfx::ColorSpace color_space;
- if (characterization.colorSpace())
- color_space = gfx::ColorSpace(*characterization.colorSpace());
- auto it = std::find_if(
- available_render_pass_overlay_backings_.begin(),
- available_render_pass_overlay_backings_.end(),
- [&characterization, &resource_format, &size, &color_space](
- const std::unique_ptr<gpu::SharedImageRepresentationSkia>& backing) {
- return backing->format() == resource_format &&
- backing->size() == size &&
- backing->color_space() == color_space &&
- backing->surface_origin() == characterization.origin() &&
- backing->alpha_type() ==
- characterization.imageInfo().alphaType();
- });
-
- if (it != available_render_pass_overlay_backings_.end()) {
- auto backing = std::move(*it);
- available_render_pass_overlay_backings_.erase(it);
- return backing;
- }
-
- auto mailbox = gpu::Mailbox::GenerateForSharedImage();
- constexpr auto kOverlayUsage = gpu::SHARED_IMAGE_USAGE_SCANOUT |
- gpu::SHARED_IMAGE_USAGE_DISPLAY |
- gpu::SHARED_IMAGE_USAGE_RASTER;
-
- bool result = shared_image_factory_->CreateSharedImage(
- mailbox, resource_format, size, color_space, characterization.origin(),
- characterization.imageInfo().alphaType(), gpu::kNullSurfaceHandle,
- kOverlayUsage);
- if (!result) {
- LOG(ERROR) << "CreateSharedImage() failed.";
- MarkContextLost(CONTEXT_LOST_OUT_OF_MEMORY);
- return nullptr;
- }
-
- auto backing = shared_image_representation_factory_->ProduceSkia(
- mailbox, context_state_.get());
- DCHECK(backing);
-
- // The |backing| will keep a ref on the shared image, so the image will not be
- // released until |backing| is released.
- shared_image_factory_->DestroySharedImage(mailbox);
-
- return backing;
-}
-#endif // BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
-
void SkiaOutputSurfaceImplOnGpu::InitDelegatedInkPointRendererReceiver(
mojo::PendingReceiver<gfx::mojom::DelegatedInkPointRenderer>
pending_receiver) {
@@ -2138,4 +2169,57 @@ void SkiaOutputSurfaceImplOnGpu::DiscardBackbuffer() {
output_device_->DiscardBackbuffer();
}
+#if BUILDFLAG(ENABLE_VULKAN)
+gfx::GpuFenceHandle SkiaOutputSurfaceImplOnGpu::CreateReleaseFenceForVulkan(
+ const GrBackendSemaphore& semaphore) {
+ DCHECK(is_using_vulkan());
+
+ if (semaphore.vkSemaphore() == VK_NULL_HANDLE)
+ return {};
+
+ auto* implementation = vulkan_context_provider_->GetVulkanImplementation();
+ VkDevice device =
+ vulkan_context_provider_->GetDeviceQueue()->GetVulkanDevice();
+
+ auto handle =
+ implementation->GetSemaphoreHandle(device, semaphore.vkSemaphore());
+ if (!handle.is_valid()) {
+ vkDestroySemaphore(device, semaphore.vkSemaphore(),
+ /*pAllocator=*/nullptr);
+ LOG(ERROR) << "Failed to create a release fence for Vulkan.";
+ return {};
+ }
+ return std::move(handle).ToGpuFenceHandle();
+}
+
+bool SkiaOutputSurfaceImplOnGpu::CreateAndStoreExternalSemaphoreVulkan(
+ std::vector<GrBackendSemaphore>& end_semaphores) {
+ DCHECK(is_using_vulkan());
+
+ auto* implementation = vulkan_context_provider_->GetVulkanImplementation();
+ VkDevice device =
+ vulkan_context_provider_->GetDeviceQueue()->GetVulkanDevice();
+
+ VkSemaphore semaphore = implementation->CreateExternalSemaphore(device);
+ if (semaphore == VK_NULL_HANDLE) {
+ LOG(ERROR)
+ << "Creation of an external semaphore for a release fence failed.";
+ return false;
+ }
+
+ end_semaphores.emplace_back();
+ end_semaphores.back().initVulkan(semaphore);
+ return true;
+}
+#endif
+
+gfx::GpuFenceHandle SkiaOutputSurfaceImplOnGpu::CreateReleaseFenceForGL() {
+ if (gl::GLFence::IsGpuFenceSupported()) {
+ auto fence = gl::GLFence::CreateForGpuFence();
+ if (fence)
+ return fence->GetGpuFence()->GetGpuFenceHandle().Clone();
+ }
+ return {};
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 20fd2f418d8..204eebdc080 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_
+#include <deque>
#include <map>
#include <memory>
#include <utility>
@@ -41,6 +42,8 @@
#include "third_party/skia/include/core/SkPromiseImageTexture.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
+#include "ui/gfx/gpu_fence_handle.h"
namespace gfx {
namespace mojom {
@@ -137,12 +140,14 @@ class SkiaOutputSurfaceImplOnGpu
const gfx::ColorSpace& color_space,
float device_scale_factor,
gfx::OverlayTransform transform);
- void FinishPaintCurrentFrame(sk_sp<SkDeferredDisplayList> ddl,
- sk_sp<SkDeferredDisplayList> overdraw_ddl,
- std::vector<ImageContextImpl*> image_contexts,
- std::vector<gpu::SyncToken> sync_tokens,
- base::OnceClosure on_finished,
- absl::optional<gfx::Rect> draw_rectangle);
+ void FinishPaintCurrentFrame(
+ sk_sp<SkDeferredDisplayList> ddl,
+ sk_sp<SkDeferredDisplayList> overdraw_ddl,
+ std::vector<ImageContextImpl*> image_contexts,
+ std::vector<gpu::SyncToken> sync_tokens,
+ base::OnceClosure on_finished,
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb,
+ absl::optional<gfx::Rect> draw_rectangle);
void ScheduleOutputSurfaceAsOverlay(
const OverlayProcessorInterface::OutputSurfaceOverlayPlane&
output_surface_plane);
@@ -157,11 +162,13 @@ class SkiaOutputSurfaceImplOnGpu
void SwapBuffersSkipped();
void EnsureBackbuffer();
void DiscardBackbuffer();
- void FinishPaintRenderPass(const gpu::Mailbox& mailbox,
- sk_sp<SkDeferredDisplayList> ddl,
- std::vector<ImageContextImpl*> image_contexts,
- std::vector<gpu::SyncToken> sync_tokens,
- base::OnceClosure on_finished);
+ void FinishPaintRenderPass(
+ const gpu::Mailbox& mailbox,
+ sk_sp<SkDeferredDisplayList> ddl,
+ std::vector<ImageContextImpl*> image_contexts,
+ std::vector<gpu::SyncToken> sync_tokens,
+ base::OnceClosure on_finished,
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb);
// Deletes resources for RenderPasses in |ids|. Also takes ownership of
// |images_contexts| and destroys them on GPU thread.
void RemoveRenderPassResource(
@@ -184,9 +191,7 @@ class SkiaOutputSurfaceImplOnGpu
void ReleaseImageContexts(
std::vector<std::unique_ptr<ExternalUseClient::ImageContext>>
image_contexts);
- void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays,
- std::vector<ImageContextImpl*> image_contexts,
- base::OnceClosure on_finished);
+ void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays);
void SetEnableDCLayers(bool enable);
void SetGpuVSyncEnabled(bool enabled);
@@ -210,9 +215,6 @@ class SkiaOutputSurfaceImplOnGpu
#endif
const gpu::gles2::FeatureInfo* GetFeatureInfo() const override;
const gpu::GpuPreferences& GetGpuPreferences() const override;
- void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params,
- gfx::GpuFenceHandle release_fence) override;
- void BufferPresented(const gfx::PresentationFeedback& feedback) override;
GpuVSyncCallback GetGpuVSyncCallback() override;
base::TimeDelta GetGpuBlockedTimeSinceLastSwap() override;
@@ -301,6 +303,8 @@ class SkiaOutputSurfaceImplOnGpu
gpu_preferences_.gr_context_type == gpu::GrContextType::kDawn;
}
+ bool is_using_gl() const { return !is_using_vulkan() && !is_using_dawn(); }
+
// Helper for `CopyOutput()` method, handles the RGBA format.
void CopyOutputRGBA(SkSurface* surface,
copy_output::RenderPassGeometry geometry,
@@ -336,17 +340,19 @@ class SkiaOutputSurfaceImplOnGpu
// |surface| into |dest_surface|'s canvas, cropping and scaling the results
// appropriately. |source_selection| is the area of the |surface| that will be
// rendered to the destination.
- // |begin_semaphores| will be submitted to the GPU backend prior to issuing
- // draw calls to the |dest_surface|.
- // |end_semaphores| will be submitted to the GPU backend alongside the draw
- // calls to the |dest_surface|.
- bool RenderSurface(SkSurface* surface,
+ void RenderSurface(SkSurface* surface,
const SkIRect& source_selection,
absl::optional<SkVector> scaling,
bool is_downscale_or_identity_in_both_dimensions,
- SkSurface* dest_surface,
- std::vector<GrBackendSemaphore>& begin_semaphores,
- std::vector<GrBackendSemaphore>& end_semaphores);
+ SkSurface* dest_surface);
+
+ // Helper for `CopyOutputNV12()` & `CopyOutputRGBA()` methods, flushes writes
+ // to |surface| with |end_semaphores| and |end_state|.
+ bool FlushSurface(SkSurface* surface,
+ std::vector<GrBackendSemaphore>& end_semaphores,
+ std::unique_ptr<GrBackendSurfaceMutableState> end_state,
+ GrGpuFinishedProc finished_proc = nullptr,
+ GrGpuFinishedContext finished_context = nullptr);
// Creates surfaces needed to store the data in NV12 format.
// |plane_access_datas| will be populated with information needed to access
@@ -382,11 +388,18 @@ class SkiaOutputSurfaceImplOnGpu
void ReleaseAsyncReadResultHelpers();
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- std::unique_ptr<gpu::SharedImageRepresentationSkia>
- GetOrCreateRenderPassOverlayBacking(
- const SkSurfaceCharacterization& characterization);
+#if BUILDFLAG(ENABLE_VULKAN)
+ // Creates a release fence. The semaphore is an external semaphore created
+ // by CreateAndStoreExternalSemaphoreVulkan(). May destroy VkSemaphore that
+ // the |semaphore| stores if creation of a release fence fails. In this case,
+ // invalid fence handle is returned.
+ gfx::GpuFenceHandle CreateReleaseFenceForVulkan(
+ const GrBackendSemaphore& semaphore);
+ // Returns true if succeess.
+ bool CreateAndStoreExternalSemaphoreVulkan(
+ std::vector<GrBackendSemaphore>& end_semaphores);
#endif
+ gfx::GpuFenceHandle CreateReleaseFenceForGL();
class ReleaseCurrent {
public:
@@ -466,7 +479,9 @@ class SkiaOutputSurfaceImplOnGpu
base::flat_set<ImageContextImpl*> image_contexts_;
};
PromiseImageAccessHelper promise_image_access_helper_{this};
- base::flat_set<ImageContextImpl*> image_contexts_with_end_access_state_;
+ base::flat_set<std::pair<ImageContextImpl*,
+ std::unique_ptr<GrBackendSurfaceMutableState>>>
+ image_contexts_with_end_access_state_;
std::unique_ptr<SkiaOutputDevice> output_device_;
std::unique_ptr<SkiaOutputDevice::ScopedPaint> scoped_output_device_paint_;
@@ -488,33 +503,12 @@ class SkiaOutputSurfaceImplOnGpu
// Tracking for ongoing AsyncReadResults.
base::flat_set<AsyncReadResultHelper*> async_read_result_helpers_;
-#if BUILDFLAG(IS_APPLE) || defined(USE_OZONE)
- using UniqueBackingPtr = std::unique_ptr<gpu::SharedImageRepresentationSkia>;
- class BackingComparator {
- public:
- using is_transparent = void;
- bool operator()(const UniqueBackingPtr& lhs,
- const UniqueBackingPtr& rhs) const {
- return lhs->mailbox() < rhs->mailbox();
- }
- bool operator()(const UniqueBackingPtr& lhs,
- const gpu::Mailbox& rhs) const {
- return lhs->mailbox() < rhs;
- }
- bool operator()(const gpu::Mailbox& lhs,
- const UniqueBackingPtr& rhs) const {
- return lhs < rhs->mailbox();
- }
- };
- // Render pass overlay backings are in flight.
- // The base::flat_set uses backing->mailbox() as the unique key.
- base::flat_set<UniqueBackingPtr, BackingComparator>
- in_flight_render_pass_overlay_backings_;
-
- // Render pass overlay backings are available for reusing.
- std::vector<std::unique_ptr<gpu::SharedImageRepresentationSkia>>
- available_render_pass_overlay_backings_;
-#endif
+ // Pending release fence callbacks. These callbacks can be delayed if Vulkan
+ // external semaphore type has copy transference, which means importing
+ // semaphores has to be delayed until submission.
+ std::deque<std::pair<GrBackendSemaphore,
+ base::OnceCallback<void(gfx::GpuFenceHandle)>>>
+ pending_release_fence_cbs_;
THREAD_CHECKER(thread_checker_);
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
index 88dd8eab89f..8d694407870 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback_forward.h"
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "cc/test/fake_output_surface_client.h"
@@ -23,6 +24,7 @@
#include "gpu/command_buffer/service/service_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/gpu_fence_handle.h"
#include "ui/gl/gl_implementation.h"
namespace viz {
@@ -45,8 +47,10 @@ class SkiaOutputSurfaceImplTest : public testing::Test {
void SetUpSkiaOutputSurfaceImpl();
// Paints and submits root RenderPass with a solid color rect of |size|.
- gpu::SyncToken PaintRootRenderPass(const gfx::Rect& output_rect,
- base::OnceClosure closure);
+ gpu::SyncToken PaintRootRenderPass(
+ const gfx::Rect& output_rect,
+ base::OnceClosure closure,
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence);
void CheckSyncTokenOnGpuThread(const gpu::SyncToken& sync_token);
void CopyRequestCallbackOnGpuThread(const gfx::Rect& output_rect,
@@ -75,27 +79,27 @@ SkiaOutputSurfaceImplTest::~SkiaOutputSurfaceImplTest() {
}
void SkiaOutputSurfaceImplTest::SetUpSkiaOutputSurfaceImpl() {
- RendererSettings settings;
- settings.use_skia_renderer = true;
auto skia_deps = std::make_unique<SkiaOutputSurfaceDependencyImpl>(
GetGpuService(), gpu::kNullSurfaceHandle);
display_controller_ =
std::make_unique<DisplayCompositorMemoryAndTaskController>(
std::move(skia_deps));
- output_surface_ = SkiaOutputSurfaceImpl::Create(display_controller_.get(),
- settings, &debug_settings_);
+ output_surface_ = SkiaOutputSurfaceImpl::Create(
+ display_controller_.get(), RendererSettings(), &debug_settings_);
output_surface_->BindToClient(&output_surface_client_);
}
gpu::SyncToken SkiaOutputSurfaceImplTest::PaintRootRenderPass(
const gfx::Rect& rect,
- base::OnceClosure closure) {
+ base::OnceClosure closure,
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence) {
SkPaint paint;
paint.setColor(kOutputColor);
SkCanvas* root_canvas = output_surface_->BeginPaintCurrentFrame();
root_canvas->drawRect(
SkRect::MakeXYWH(rect.x(), rect.y(), rect.height(), rect.width()), paint);
- output_surface_->EndPaint(std::move(closure));
+ output_surface_->EndPaint(std::move(closure),
+ std::move(return_release_fence));
return output_surface_->Flush();
}
@@ -136,16 +140,22 @@ void SkiaOutputSurfaceImplTest::CopyRequestCallbackOnGpuThread(
}
TEST_F(SkiaOutputSurfaceImplTest, EndPaint) {
- output_surface_->Reshape(kSurfaceRect.size(), 1, gfx::ColorSpace(),
- gfx::BufferFormat::RGBX_8888, /*use_stencil=*/false);
+ OutputSurface::ReshapeParams reshape_params;
+ reshape_params.size = kSurfaceRect.size();
+ output_surface_->Reshape(reshape_params);
constexpr gfx::Rect output_rect(0, 0, 10, 10);
bool on_finished_called = false;
base::OnceClosure on_finished =
base::BindOnce([](bool* result) { *result = true; }, &on_finished_called);
+ bool on_return_release_fence_called = false;
+ base::OnceCallback<void(gfx::GpuFenceHandle)> return_release_fence_cb =
+ base::BindOnce(
+ [](bool* result, gfx::GpuFenceHandle handle) { *result = true; },
+ &on_return_release_fence_called);
- gpu::SyncToken sync_token =
- PaintRootRenderPass(output_rect, std::move(on_finished));
+ gpu::SyncToken sync_token = PaintRootRenderPass(
+ output_rect, std::move(on_finished), std::move(return_release_fence_cb));
EXPECT_TRUE(sync_token.HasData());
// Copy the output
@@ -177,19 +187,25 @@ TEST_F(SkiaOutputSurfaceImplTest, EndPaint) {
output_surface_->ScheduleGpuTaskForTesting(std::move(closure), {sync_token});
BlockMainThread();
EXPECT_TRUE(on_finished_called);
+
+ // Let the cb to come back.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(on_return_release_fence_called);
}
// Draws two frames and calls Reshape() between the two frames changing the
// color space. Verifies draw after color space change is successful.
TEST_F(SkiaOutputSurfaceImplTest, SupportsColorSpaceChange) {
for (auto& color_space : {gfx::ColorSpace(), gfx::ColorSpace::CreateSRGB()}) {
- output_surface_->Reshape(kSurfaceRect.size(), 1, color_space,
- gfx::BufferFormat::RGBX_8888,
- /*use_stencil=*/false);
+ OutputSurface::ReshapeParams reshape_params;
+ reshape_params.size = kSurfaceRect.size();
+ reshape_params.color_space = color_space;
+ output_surface_->Reshape(reshape_params);
// Draw something, it's not important what.
base::RunLoop run_loop;
- PaintRootRenderPass(kSurfaceRect, run_loop.QuitClosure());
+ PaintRootRenderPass(kSurfaceRect, run_loop.QuitClosure(),
+ base::DoNothing());
OutputSurfaceFrame frame;
frame.size = kSurfaceRect.size();
@@ -203,8 +219,9 @@ TEST_F(SkiaOutputSurfaceImplTest, SupportsColorSpaceChange) {
// Tests that the destination color space is preserved across a CopyOutput for
// ColorSpaces supported by SkColorSpace.
TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapSupportedColorSpace) {
- output_surface_->Reshape(kSurfaceRect.size(), 1, gfx::ColorSpace(),
- gfx::BufferFormat::RGBX_8888, /*use_stencil=*/false);
+ OutputSurface::ReshapeParams reshape_params;
+ reshape_params.size = kSurfaceRect.size();
+ output_surface_->Reshape(reshape_params);
constexpr gfx::Rect output_rect(0, 0, 10, 10);
const gfx::ColorSpace color_space = gfx::ColorSpace(
@@ -230,7 +247,7 @@ TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapSupportedColorSpace) {
geometry.sampling_bounds = output_rect;
geometry.readback_offset = gfx::Vector2d(0, 0);
- PaintRootRenderPass(kSurfaceRect, base::DoNothing());
+ PaintRootRenderPass(kSurfaceRect, base::DoNothing(), base::DoNothing());
output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
std::move(request), gpu::Mailbox());
output_surface_->SwapBuffersSkipped(kSurfaceRect);
@@ -243,8 +260,9 @@ TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapSupportedColorSpace) {
// Tests that copying from a source with a color space that can't be converted
// to a SkColorSpace will fallback to a transform to sRGB.
TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapUnsupportedColorSpace) {
- output_surface_->Reshape(kSurfaceRect.size(), 1, gfx::ColorSpace(),
- gfx::BufferFormat::RGBX_8888, /*use_stencil=*/false);
+ OutputSurface::ReshapeParams reshape_params;
+ reshape_params.size = kSurfaceRect.size();
+ output_surface_->Reshape(reshape_params);
constexpr gfx::Rect output_rect(0, 0, 10, 10);
const gfx::ColorSpace color_space = gfx::ColorSpace::CreatePiecewiseHDR(
@@ -270,7 +288,7 @@ TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapUnsupportedColorSpace) {
geometry.sampling_bounds = output_rect;
geometry.readback_offset = gfx::Vector2d(0, 0);
- PaintRootRenderPass(kSurfaceRect, base::DoNothing());
+ PaintRootRenderPass(kSurfaceRect, base::DoNothing(), base::DoNothing());
output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
std::move(request), gpu::Mailbox());
output_surface_->SwapBuffersSkipped(kSurfaceRect);
diff --git a/chromium/components/viz/service/display_embedder/skia_render_copy_results.cc b/chromium/components/viz/service/display_embedder/skia_render_copy_results.cc
index 7c400b6d1bb..20541a6144a 100644
--- a/chromium/components/viz/service/display_embedder/skia_render_copy_results.cc
+++ b/chromium/components/viz/service/display_embedder/skia_render_copy_results.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/memory/ptr_util.h"
+#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h"
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/skia/include/core/SkPixelRef.h"
@@ -322,4 +323,49 @@ void CopyOutputResultSkiaNV12::OnNV12PlaneReadbackDone(
std::move(async_result));
}
+NV12PlanesReadyContext::NV12PlanesReadyContext(
+ base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
+ std::unique_ptr<CopyOutputRequest> request,
+ const gfx::Rect& result_rect,
+ const std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes>&
+ plane_mailbox_holders,
+ const gfx::ColorSpace& color_space)
+ : request_(std::move(request)),
+ result_rect_(result_rect),
+ plane_mailbox_holders_(plane_mailbox_holders),
+ color_space_(color_space) {}
+
+NV12PlanesReadyContext::~NV12PlanesReadyContext() {
+ DCHECK_EQ(outstanding_planes_, 0);
+}
+
+void NV12PlanesReadyContext::OnNV12PlaneReady() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (impl_on_gpu_) {
+ impl_on_gpu_->ReadbackDone();
+ }
+
+ outstanding_planes_--;
+ if (outstanding_planes_ == 0) {
+ request_->SendResult(std::make_unique<CopyOutputTextureResult>(
+ CopyOutputResult::Format::NV12_PLANES, result_rect_,
+ CopyOutputResult::TextureResult(plane_mailbox_holders_, color_space_),
+ CopyOutputResult::ReleaseCallbacks()));
+ }
+}
+
+NV12SinglePlaneReadyContext::NV12SinglePlaneReadyContext(
+ scoped_refptr<NV12PlanesReadyContext> nv12_planes_flushed)
+ : nv12_planes_flushed(nv12_planes_flushed) {}
+
+NV12SinglePlaneReadyContext::~NV12SinglePlaneReadyContext() = default;
+
+// static
+void NV12SinglePlaneReadyContext::OnNV12PlaneReady(GrGpuFinishedContext c) {
+ auto context = base::WrapUnique(static_cast<NV12SinglePlaneReadyContext*>(c));
+
+ context->nv12_planes_flushed->OnNV12PlaneReady();
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_render_copy_results.h b/chromium/components/viz/service/display_embedder/skia_render_copy_results.h
index f305a081177..5c056688d2f 100644
--- a/chromium/components/viz/service/display_embedder/skia_render_copy_results.h
+++ b/chromium/components/viz/service/display_embedder/skia_render_copy_results.h
@@ -16,6 +16,8 @@
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/skia/include/core/SkPixelRef.h"
#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrTypes.h"
+#include "ui/gfx/color_space.h"
namespace viz {
@@ -174,6 +176,70 @@ struct NV12PlanePixelReadContext {
int plane_index;
};
+// Context that is responsible for sending a CopyOutputResult once the GPU work
+// that populates the GpuMemoryBuffer for the NV12 planes has completed. It will
+// be notified by multiple `NV12SinglePlaneReadyContext`s that the plane has
+// been populated, and once all planes have been completed, it will send the
+// CopyOutputResult.
+class NV12PlanesReadyContext : public base::RefCounted<NV12PlanesReadyContext> {
+ public:
+ NV12PlanesReadyContext(
+ base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
+ std::unique_ptr<CopyOutputRequest> request,
+ const gfx::Rect& result_rect,
+ const std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes>&
+ plane_mailbox_holders,
+ const gfx::ColorSpace& color_space);
+
+ NV12PlanesReadyContext(const NV12PlanesReadyContext& other) = delete;
+ NV12PlanesReadyContext& operator=(const NV12PlanesReadyContext& other) =
+ delete;
+
+ void OnNV12PlaneReady();
+
+ private:
+ friend class base::RefCounted<NV12PlanesReadyContext>;
+ ~NV12PlanesReadyContext();
+
+ // Needed to notify `SkiaOutputSurfaceImplOnGpu` that readback has completed.
+ // GPU work is not a readback, but we rely on the same mechanism for nudging
+ // Skia to periodically check for asynchronous event completion.
+ base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_;
+ // Request that we will send a response to:
+ std::unique_ptr<CopyOutputRequest> request_;
+
+ // Data needed to create a response to `request_`:
+ gfx::Rect result_rect_;
+ std::array<gpu::MailboxHolder, CopyOutputResult::kMaxPlanes>
+ plane_mailbox_holders_;
+ gfx::ColorSpace color_space_;
+
+ // Number of planes that still need to report completion:
+ int outstanding_planes_ = CopyOutputResult::kNV12MaxPlanes;
+
+ THREAD_CHECKER(thread_checker_);
+};
+
+// Context that is responsible for notifying `NV12PlanesReadyContext` that GPU
+// side of populating the GpuMemoryBuffer has completed.
+struct NV12SinglePlaneReadyContext {
+ explicit NV12SinglePlaneReadyContext(
+ scoped_refptr<NV12PlanesReadyContext> nv12_planes_flushed);
+
+ NV12SinglePlaneReadyContext(const NV12SinglePlaneReadyContext& other) =
+ delete;
+ NV12SinglePlaneReadyContext& operator=(
+ const NV12SinglePlaneReadyContext& other) = delete;
+
+ ~NV12SinglePlaneReadyContext();
+
+ // Will be called with `NV12PlaneFlushedContext*`:
+ static void OnNV12PlaneReady(GrGpuFinishedContext context);
+
+ // Context to be notified that a plane has been populated.
+ scoped_refptr<NV12PlanesReadyContext> nv12_planes_flushed;
+};
+
class CopyOutputResultSkiaNV12 : public CopyOutputResult {
public:
CopyOutputResultSkiaNV12(
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.cc b/chromium/components/viz/service/display_embedder/software_output_surface.cc
index 35b4b9dd371..0fe3318ef87 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.cc
@@ -24,12 +24,12 @@
namespace viz {
SoftwareOutputSurface::SoftwareOutputSurface(
- std::unique_ptr<SoftwareOutputDevice> software_device)
- : OutputSurface(std::move(software_device)) {
+ std::unique_ptr<SoftwareOutputDevice> device)
+ : OutputSurface(std::move(device)) {
capabilities_.pending_swap_params.max_pending_swaps =
- software_device_->MaxFramesPending();
+ software_device()->MaxFramesPending();
capabilities_.resize_based_on_root_surface =
- software_device_->SupportsOverridePlatformSize();
+ software_device()->SupportsOverridePlatformSize();
}
SoftwareOutputSurface::~SoftwareOutputSurface() = default;
@@ -48,17 +48,8 @@ void SoftwareOutputSurface::DiscardBackbuffer() {
software_device()->DiscardBackbuffer();
}
-void SoftwareOutputSurface::BindFramebuffer() {
- // Not used for software surfaces.
- NOTREACHED();
-}
-
-void SoftwareOutputSurface::Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) {
- software_device()->Resize(size, device_scale_factor);
+void SoftwareOutputSurface::Reshape(const ReshapeParams& params) {
+ software_device()->Resize(params.size, params.device_scale_factor);
}
void SoftwareOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
@@ -89,22 +80,6 @@ bool SoftwareOutputSurface::IsDisplayedAsOverlayPlane() const {
return false;
}
-unsigned SoftwareOutputSurface::GetOverlayTextureId() const {
- return 0;
-}
-
-bool SoftwareOutputSurface::HasExternalStencilTest() const {
- return false;
-}
-
-void SoftwareOutputSurface::ApplyExternalStencil() {}
-
-uint32_t SoftwareOutputSurface::GetFramebufferCopyTextureFormat() {
- // Not used for software surfaces.
- NOTREACHED();
- return 0;
-}
-
void SoftwareOutputSurface::SwapBuffersCallback(base::TimeTicks swap_time,
const gfx::Size& pixel_size) {
latency_tracker_.OnGpuSwapBuffersCompleted(
@@ -134,10 +109,6 @@ void SoftwareOutputSurface::UpdateVSyncParameters(base::TimeTicks timebase,
update_vsync_parameters_callback_.Run(timebase, interval);
}
-unsigned SoftwareOutputSurface::UpdateGpuFence() {
- return 0;
-}
-
void SoftwareOutputSurface::SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) {
update_vsync_parameters_callback_ = std::move(callback);
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.h b/chromium/components/viz/service/display_embedder/software_output_surface.h
index 4425e9f28a6..a7127891314 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.h
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.h
@@ -38,19 +38,9 @@ class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
void BindToClient(OutputSurfaceClient* client) override;
void EnsureBackbuffer() override;
void DiscardBackbuffer() override;
- void BindFramebuffer() override;
- void Reshape(const gfx::Size& size,
- float device_scale_factor,
- const gfx::ColorSpace& color_space,
- gfx::BufferFormat format,
- bool use_stencil) override;
+ void Reshape(const ReshapeParams& params) override;
void SwapBuffers(OutputSurfaceFrame frame) override;
bool IsDisplayedAsOverlayPlane() const override;
- unsigned GetOverlayTextureId() const override;
- bool HasExternalStencilTest() const override;
- void ApplyExternalStencil() override;
- uint32_t GetFramebufferCopyTextureFormat() override;
- unsigned UpdateGpuFence() override;
void SetUpdateVSyncParametersCallback(
UpdateVSyncParametersCallback callback) override;
void SetDisplayTransformHint(gfx::OverlayTransform transform) override {}
diff --git a/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
deleted file mode 100644
index ed33d5f717f..00000000000
--- a/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/viz_process_context_provider.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/observer_list.h"
-#include "base/system/sys_info.h"
-#include "base/task/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
-#include "components/viz/common/display/renderer_settings.h"
-#include "components/viz/common/gpu/context_lost_observer.h"
-#include "components/viz/common/gpu/context_lost_reason.h"
-#include "components/viz/common/resources/platform_color.h"
-#include "components/viz/common/viz_utils.h"
-#include "components/viz/service/display/display_compositor_memory_and_task_controller.h"
-#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/client/gles2_cmd_helper.h"
-#include "gpu/command_buffer/client/gles2_implementation.h"
-#include "gpu/command_buffer/client/raster_implementation_gles.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/command_buffer/client/transfer_buffer.h"
-#include "gpu/config/gpu_feature_info.h"
-#include "gpu/config/gpu_preferences.h"
-#include "gpu/config/skia_limits.h"
-#include "gpu/ipc/common/surface_handle.h"
-#include "gpu/ipc/in_process_command_buffer.h"
-#include "gpu/skia_bindings/gles2_implementation_with_grcontext_support.h"
-#include "gpu/skia_bindings/grcontext_for_gles2_interface.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "third_party/khronos/GLES2/gl2ext.h"
-#include "third_party/skia/include/gpu/GrDirectContext.h"
-#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
-
-namespace viz {
-
-namespace {
-
-gpu::ContextCreationAttribs CreateAttributes(
- bool requires_alpha_channel,
- const RendererSettings& renderer_settings) {
- gpu::ContextCreationAttribs attributes;
- attributes.alpha_size = requires_alpha_channel ? 8 : -1;
- attributes.depth_size = 0;
-#if BUILDFLAG(IS_CHROMEOS_ASH)
- // Chrome OS uses surfaceless when running on a real device and stencil
- // buffers can then be added dynamically so supporting them does not have an
- // impact on normal usage. If we are not running on a real Chrome OS device
- // but instead on a workstation for development, then stencil support is
- // useful as it allows the overdraw feedback debugging feature to be used.
- attributes.stencil_size = 8;
-#else
- attributes.stencil_size = 0;
-#endif
- attributes.samples = 0;
- attributes.sample_buffers = 0;
- attributes.bind_generates_resource = false;
- attributes.fail_if_major_perf_caveat = false;
- attributes.lose_context_when_out_of_memory = true;
-
-#if BUILDFLAG(IS_ANDROID)
- if (renderer_settings.color_space == gfx::ColorSpace::CreateSRGB()) {
- attributes.color_space = gpu::COLOR_SPACE_SRGB;
- } else if (renderer_settings.color_space ==
- gfx::ColorSpace::CreateDisplayP3D65()) {
- attributes.color_space = gpu::COLOR_SPACE_DISPLAY_P3;
- } else {
- // The browser only sends the above two color spaces.
- NOTREACHED();
- }
-
- if (!requires_alpha_channel && PreferRGB565ResourcesForDisplay()) {
- // See compositor_impl_android.cc for more information about this.
- // It is inside GetCompositorContextAttributes().
- attributes.alpha_size = 0;
- attributes.red_size = 5;
- attributes.green_size = 6;
- attributes.blue_size = 5;
- }
-
- attributes.enable_swap_timestamps_if_supported = true;
-#endif // BUILDFLAG(IS_ANDROID)
-
- return attributes;
-}
-
-void UmaRecordContextLost(ContextLostReason reason) {
- UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.DisplayCompositor", reason);
-}
-
-gpu::SharedMemoryLimits SharedMemoryLimitsForRendererSettings(
- const RendererSettings& renderer_settings) {
-#if BUILDFLAG(IS_ANDROID)
- return gpu::SharedMemoryLimits::ForDisplayCompositor(
- renderer_settings.initial_screen_size);
-#else
- return gpu::SharedMemoryLimits::ForDisplayCompositor();
-#endif
-}
-
-} // namespace
-
-VizProcessContextProvider::VizProcessContextProvider(
- gpu::CommandBufferTaskExecutor* task_executor,
- gpu::SurfaceHandle surface_handle,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
- gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- DisplayCompositorMemoryAndTaskController* display_controller,
- const RendererSettings& renderer_settings)
- : attributes_(CreateAttributes(renderer_settings.requires_alpha_channel,
- renderer_settings)) {
- InitializeContext(std::move(task_executor), surface_handle,
- gpu_memory_buffer_manager, image_factory,
- gpu_channel_manager_delegate, display_controller,
- SharedMemoryLimitsForRendererSettings(renderer_settings));
-
- if (context_result_ == gpu::ContextResult::kSuccess) {
- // |gles2_implementation_| is owned here so bind an unretained pointer or
- // there will be a circular reference preventing destruction.
- gles2_implementation_->SetLostContextCallback(base::BindOnce(
- &VizProcessContextProvider::OnContextLost, base::Unretained(this)));
-
- base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, "VizProcessContextProvider", base::ThreadTaskRunnerHandle::Get());
- } else {
- UmaRecordContextLost(CONTEXT_INIT_FAILED);
- }
-}
-
-VizProcessContextProvider::VizProcessContextProvider() = default;
-
-VizProcessContextProvider::~VizProcessContextProvider() {
- if (context_result_ == gpu::ContextResult::kSuccess) {
- base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
- this);
- }
-
- // cache_controller_ might ne nullptr if we failed to initialize
- if (cache_controller_)
- cache_controller_->SetGrContext(nullptr);
-}
-
-void VizProcessContextProvider::AddRef() const {
- base::RefCountedThreadSafe<VizProcessContextProvider>::AddRef();
-}
-
-void VizProcessContextProvider::Release() const {
- base::RefCountedThreadSafe<VizProcessContextProvider>::Release();
-}
-
-gpu::ContextResult VizProcessContextProvider::BindToCurrentThread() {
- return context_result_;
-}
-
-gpu::gles2::GLES2Interface* VizProcessContextProvider::ContextGL() {
- return gles2_implementation_.get();
-}
-
-gpu::ContextSupport* VizProcessContextProvider::ContextSupport() {
- return gles2_implementation_.get();
-}
-
-class GrDirectContext* VizProcessContextProvider::GrContext() {
- if (gr_context_)
- return gr_context_->get();
-
- size_t max_resource_cache_bytes;
- size_t max_glyph_cache_texture_bytes;
- gpu::DetermineGrCacheLimitsFromAvailableMemory(
- &max_resource_cache_bytes, &max_glyph_cache_texture_bytes);
-
- gr_context_ = std::make_unique<skia_bindings::GrContextForGLES2Interface>(
- ContextGL(), ContextSupport(), ContextCapabilities(),
- max_resource_cache_bytes, max_glyph_cache_texture_bytes);
- cache_controller_->SetGrContext(gr_context_->get());
- return gr_context_->get();
-}
-
-gpu::SharedImageInterface* VizProcessContextProvider::SharedImageInterface() {
- return command_buffer_->GetSharedImageInterface();
-}
-
-ContextCacheController* VizProcessContextProvider::CacheController() {
- return cache_controller_.get();
-}
-
-base::Lock* VizProcessContextProvider::GetLock() {
- // Locking isn't supported on display compositor contexts.
- return nullptr;
-}
-
-const gpu::Capabilities& VizProcessContextProvider::ContextCapabilities()
- const {
- return command_buffer_->GetCapabilities();
-}
-
-const gpu::GpuFeatureInfo& VizProcessContextProvider::GetGpuFeatureInfo()
- const {
- return command_buffer_->GetGpuFeatureInfo();
-}
-
-void VizProcessContextProvider::AddObserver(ContextLostObserver* obs) {
- observers_.AddObserver(obs);
-}
-
-void VizProcessContextProvider::RemoveObserver(ContextLostObserver* obs) {
- observers_.RemoveObserver(obs);
-}
-
-void VizProcessContextProvider::SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback) {
- command_buffer_->SetUpdateVSyncParametersCallback(std::move(callback));
-}
-
-void VizProcessContextProvider::SetGpuVSyncCallback(GpuVSyncCallback callback) {
- command_buffer_->SetGpuVSyncCallback(std::move(callback));
-}
-
-void VizProcessContextProvider::SetGpuVSyncEnabled(bool enabled) {
- command_buffer_->SetGpuVSyncEnabled(enabled);
-}
-
-bool VizProcessContextProvider::UseRGB565PixelFormat() const {
- return attributes_.alpha_size == 0 && attributes_.red_size == 5 &&
- attributes_.green_size == 6 && attributes_.blue_size == 5;
-}
-
-uint32_t VizProcessContextProvider::GetCopyTextureInternalFormat() {
- return attributes_.alpha_size > 0 ? GL_RGBA : GL_RGB;
-}
-
-void VizProcessContextProvider::InitializeContext(
- gpu::CommandBufferTaskExecutor* task_executor,
- gpu::SurfaceHandle surface_handle,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
- gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- DisplayCompositorMemoryAndTaskController* display_controller,
- const gpu::SharedMemoryLimits& mem_limits) {
- const bool is_offscreen = surface_handle == gpu::kNullSurfaceHandle;
- DCHECK(display_controller);
- gpu_task_scheduler_helper_ = display_controller->gpu_task_scheduler();
-
- command_buffer_ = std::make_unique<gpu::InProcessCommandBuffer>(
- task_executor,
- GURL("chrome://gpu/VizProcessContextProvider::InitializeContext"));
- context_result_ = command_buffer_->Initialize(
- /*surface=*/nullptr, is_offscreen, surface_handle, attributes_,
- gpu_memory_buffer_manager, image_factory, gpu_channel_manager_delegate,
- base::ThreadTaskRunnerHandle::Get(),
- gpu_task_scheduler_helper_->GetTaskSequence(),
- display_controller->controller_on_gpu(), nullptr, nullptr);
- if (context_result_ != gpu::ContextResult::kSuccess) {
- DLOG(ERROR) << "Failed to initialize InProcessCommmandBuffer";
- return;
- }
-
- // Create the GLES2 helper, which writes the command buffer protocol.
- gles2_helper_ =
- std::make_unique<gpu::gles2::GLES2CmdHelper>(command_buffer_.get());
- context_result_ = gles2_helper_->Initialize(mem_limits.command_buffer_size);
- if (context_result_ != gpu::ContextResult::kSuccess) {
- DLOG(ERROR) << "Failed to initialize GLES2CmdHelper";
- return;
- }
-
- if (gpu_task_scheduler_helper_)
- gpu_task_scheduler_helper_->Initialize(gles2_helper_.get());
-
- transfer_buffer_ = std::make_unique<gpu::TransferBuffer>(gles2_helper_.get());
-
- // Create the object exposing the OpenGL API.
- gles2_implementation_ =
- std::make_unique<skia_bindings::GLES2ImplementationWithGrContextSupport>(
- gles2_helper_.get(), /*share_group=*/nullptr, transfer_buffer_.get(),
- attributes_.bind_generates_resource,
- attributes_.lose_context_when_out_of_memory,
- /*support_client_side_arrays=*/false, command_buffer_.get());
-
- context_result_ = gles2_implementation_->Initialize(mem_limits);
- if (context_result_ != gpu::ContextResult::kSuccess) {
- DLOG(ERROR) << "Failed to initialize GLES2Implementation";
- return;
- }
-
- cache_controller_ = std::make_unique<ContextCacheController>(
- gles2_implementation_.get(), base::ThreadTaskRunnerHandle::Get());
-
- // TraceEndCHROMIUM is implicit when the context is destroyed
- gles2_implementation_->TraceBeginCHROMIUM("VizCompositor",
- "DisplayCompositor");
-}
-
-void VizProcessContextProvider::OnContextLost() {
- for (auto& observer : observers_)
- observer.OnContextLost();
- if (gr_context_)
- gr_context_->OnLostContext();
-
- gpu::CommandBuffer::State state = command_buffer_->GetLastState();
- UmaRecordContextLost(
- GetContextLostReason(state.error, state.context_lost_reason));
-}
-
-bool VizProcessContextProvider::OnMemoryDump(
- const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) {
- DCHECK_EQ(context_result_, gpu::ContextResult::kSuccess);
- if (args.level_of_detail ==
- base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
- if (gr_context_)
- gpu::raster::DumpBackgroundGrMemoryStatistics(gr_context_->get(), pmd);
-
- // Early out, no need for more detail in a BACKGROUND dump.
- return true;
- }
-
- gles2_implementation_->OnMemoryDump(args, pmd);
- gles2_helper_->OnMemoryDump(args, pmd);
-
- if (gr_context_) {
- gpu::raster::DumpGrMemoryStatistics(
- gr_context_->get(), pmd,
- gles2_implementation_->ShareGroupTracingGUID());
- }
- return true;
-}
-
-base::ScopedClosureRunner VizProcessContextProvider::GetCacheBackBufferCb() {
- return command_buffer_->GetCacheBackBufferCb();
-}
-
-void VizProcessContextProvider::SetNeedsMeasureNextDrawLatency() {
- return command_buffer_->SetNeedsMeasureNextDrawLatency();
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/viz_process_context_provider.h b/chromium/components/viz/service/display_embedder/viz_process_context_provider.h
deleted file mode 100644
index 8ff0ccce732..00000000000
--- a/chromium/components/viz/service/display_embedder/viz_process_context_provider.h
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/callback_helpers.h"
-#include "base/memory/raw_ptr.h"
-#include "base/observer_list.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "components/viz/common/display/update_vsync_parameters_callback.h"
-#include "components/viz/common/gpu/context_cache_controller.h"
-#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/gpu/gpu_vsync_callback.h"
-#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/common/context_creation_attribs.h"
-#include "gpu/ipc/common/surface_handle.h"
-#include "gpu/ipc/gpu_task_scheduler_helper.h"
-#include "ui/gfx/native_widget_types.h"
-
-class GrDirectContext;
-
-namespace gpu {
-namespace gles2 {
-class GLES2CmdHelper;
-class GLES2Implementation;
-} // namespace gles2
-class CommandBufferTaskExecutor;
-class GpuChannelManagerDelegate;
-class GpuMemoryBufferManager;
-class ImageFactory;
-class InProcessCommandBuffer;
-class TransferBuffer;
-struct SharedMemoryLimits;
-} // namespace gpu
-
-namespace skia_bindings {
-class GrContextForGLES2Interface;
-}
-
-namespace viz {
-class ContextLostObserver;
-class DisplayCompositorMemoryAndTaskController;
-class GpuTaskSchedulerHelper;
-class RendererSettings;
-
-// A ContextProvider used in the viz process to setup an InProcessCommandBuffer
-// for the display compositor.
-class VIZ_SERVICE_EXPORT VizProcessContextProvider
- : public base::RefCountedThreadSafe<VizProcessContextProvider>,
- public ContextProvider,
- public base::trace_event::MemoryDumpProvider {
- public:
- VizProcessContextProvider(
- gpu::CommandBufferTaskExecutor* task_executor,
- gpu::SurfaceHandle surface_handle,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
- gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- DisplayCompositorMemoryAndTaskController* display_controller,
- const RendererSettings& renderer_settings);
-
- // ContextProvider implementation.
- void AddRef() const override;
- void Release() const override;
- gpu::ContextResult BindToCurrentThread() override;
- gpu::gles2::GLES2Interface* ContextGL() override;
- gpu::ContextSupport* ContextSupport() override;
- class GrDirectContext* GrContext() override;
- gpu::SharedImageInterface* SharedImageInterface() override;
- ContextCacheController* CacheController() override;
- base::Lock* GetLock() override;
- const gpu::Capabilities& ContextCapabilities() const override;
- const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override;
- void AddObserver(ContextLostObserver* obs) override;
- void RemoveObserver(ContextLostObserver* obs) override;
-
- virtual void SetUpdateVSyncParametersCallback(
- UpdateVSyncParametersCallback callback);
- virtual void SetGpuVSyncCallback(GpuVSyncCallback callback);
- virtual void SetGpuVSyncEnabled(bool enabled);
- virtual bool UseRGB565PixelFormat() const;
-
- // Provides the GL internal format that should be used when calling
- // glCopyTexImage2D() on the default framebuffer.
- virtual uint32_t GetCopyTextureInternalFormat();
-
- virtual base::ScopedClosureRunner GetCacheBackBufferCb();
-
- void SetNeedsMeasureNextDrawLatency();
-
- protected:
- friend class base::RefCountedThreadSafe<VizProcessContextProvider>;
- VizProcessContextProvider(); // For testing only.
- ~VizProcessContextProvider() override;
-
- private:
- void InitializeContext(
- gpu::CommandBufferTaskExecutor* task_executor,
- gpu::SurfaceHandle surface_handle,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
- gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- DisplayCompositorMemoryAndTaskController* display_controller,
- const gpu::SharedMemoryLimits& mem_limits);
- void OnContextLost();
-
- // base::trace_event::MemoryDumpProvider implementation.
- bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) override;
-
- const gpu::ContextCreationAttribs attributes_;
-
- // The |gpu_task_scheduler_helper_| has 1:1 relationship with the Display
- // compositor.
- raw_ptr<gpu::GpuTaskSchedulerHelper> gpu_task_scheduler_helper_;
- std::unique_ptr<gpu::InProcessCommandBuffer> command_buffer_;
- std::unique_ptr<gpu::gles2::GLES2CmdHelper> gles2_helper_;
- std::unique_ptr<gpu::TransferBuffer> transfer_buffer_;
- std::unique_ptr<gpu::gles2::GLES2Implementation> gles2_implementation_;
- std::unique_ptr<ContextCacheController> cache_controller_;
- gpu::ContextResult context_result_ = gpu::ContextResult::kSuccess;
-
- std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_;
-
- base::ObserverList<ContextLostObserver>::Unchecked observers_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 51c829c9e0b..4828b3ed23f 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -192,6 +192,14 @@ void CompositorFrameSinkSupport::ThrottleBeginFrame(base::TimeDelta interval) {
begin_frame_interval_ = interval;
}
+void CompositorFrameSinkSupport::OnSurfaceCommitted(Surface* surface) {
+ if (surface->HasPendingFrame()) {
+ // Make sure we periodically check if the frame should activate.
+ pending_surfaces_.insert(surface);
+ UpdateNeedsBeginFramesInternal();
+ }
+}
+
void CompositorFrameSinkSupport::OnSurfaceActivated(Surface* surface) {
DCHECK(surface);
DCHECK(surface->HasActiveFrame());
@@ -281,7 +289,7 @@ void CompositorFrameSinkSupport::OnFrameTokenChanged(uint32_t frame_token) {
frame_sink_manager_->OnFrameTokenChanged(frame_sink_id_, frame_token);
}
-void CompositorFrameSinkSupport::OnSurfaceProcessed(Surface* surface) {
+void CompositorFrameSinkSupport::SendCompositorFrameAck() {
DidReceiveCompositorFrameAck();
}
@@ -676,9 +684,7 @@ SubmitResult CompositorFrameSinkSupport::MaybeSubmitCompositorFrame(
TRACE_EVENT_SCOPE_THREAD);
return SubmitResult::SIZE_MISMATCH;
case Surface::QueueFrameResult::ACCEPTED_PENDING:
- // Make sure we periodically check if the frame should activate.
- pending_surfaces_.insert(current_surface);
- UpdateNeedsBeginFramesInternal();
+ // Pending frames are processed in OnSurfaceCommitted.
break;
case Surface::QueueFrameResult::ACCEPTED_ACTIVE:
// Nothing to do here.
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index f3a5548db7a..704adeffbc4 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -141,6 +141,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
void ThrottleBeginFrame(base::TimeDelta interval);
// SurfaceClient implementation.
+ void OnSurfaceCommitted(Surface* surface) override;
void OnSurfaceActivated(Surface* surface) override;
void OnSurfaceDestroyed(Surface* surface) override;
void OnSurfaceWillDraw(Surface* surface) override;
@@ -155,7 +156,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
std::vector<PendingCopyOutputRequest> TakeCopyOutputRequests(
const LocalSurfaceId& local_surface_id) override;
void OnFrameTokenChanged(uint32_t frame_token) override;
- void OnSurfaceProcessed(Surface* surface) override;
+ void SendCompositorFrameAck() override;
void OnSurfaceAggregatedDamage(
Surface* surface,
const LocalSurfaceId& local_surface_id,
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 0a4a21b7915..083f26653b7 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -70,7 +70,9 @@ FrameSinkManagerImpl::FrameSinkManagerImpl(const InitParams& params)
: shared_bitmap_manager_(params.shared_bitmap_manager),
output_surface_provider_(params.output_surface_provider),
gmb_context_provider_(params.gmb_context_provider),
- surface_manager_(this, params.activation_deadline_in_frames),
+ surface_manager_(this,
+ params.activation_deadline_in_frames,
+ params.max_uncommitted_frames),
hit_test_manager_(surface_manager()),
restart_id_(params.restart_id),
run_all_compositor_stages_before_draw_(
@@ -414,6 +416,11 @@ void FrameSinkManagerImpl::RegisterCompositorFrameSinkSupport(
for (auto& observer : observer_list_)
observer.OnCreatedCompositorFrameSink(frame_sink_id, support->is_root());
+
+ if (global_throttle_interval_) {
+ UpdateThrottlingRecursively(frame_sink_id,
+ global_throttle_interval_.value());
+ }
}
void FrameSinkManagerImpl::UnregisterCompositorFrameSinkSupport(
@@ -733,16 +740,41 @@ void FrameSinkManagerImpl::Throttle(const std::vector<FrameSinkId>& ids,
UpdateThrottling();
}
+void FrameSinkManagerImpl::StartThrottlingAllFrameSinks(
+ base::TimeDelta interval) {
+ global_throttle_interval_ = interval;
+ UpdateThrottling();
+}
+
+void FrameSinkManagerImpl::StopThrottlingAllFrameSinks() {
+ global_throttle_interval_ = absl::nullopt;
+ UpdateThrottling();
+}
+
void FrameSinkManagerImpl::UpdateThrottling() {
// Clear previous throttling effect on all frame sinks.
for (auto& support_map_item : support_map_) {
support_map_item.second->ThrottleBeginFrame(base::TimeDelta());
}
- if (throttle_interval_.is_zero())
+ if (throttle_interval_.is_zero() &&
+ (!global_throttle_interval_ ||
+ global_throttle_interval_.value().is_zero()))
return;
- for (const auto& id : frame_sink_ids_to_throttle_) {
- UpdateThrottlingRecursively(id, throttle_interval_);
+ if (global_throttle_interval_) {
+ for (const auto& support : support_map_) {
+ support.second->ThrottleBeginFrame(global_throttle_interval_.value());
+ }
+ }
+
+ // If the per-frame sink throttle interval is more aggressive than the global
+ // throttling interval, apply it to those frame sinks effectively always
+ // throttling a frame sink as much as possible.
+ if (!global_throttle_interval_ ||
+ throttle_interval_ > global_throttle_interval_) {
+ for (const auto& id : frame_sink_ids_to_throttle_) {
+ UpdateThrottlingRecursively(id, throttle_interval_);
+ }
}
// Clear throttling on frame sinks currently being captured.
for (const auto& id : captured_frame_sink_ids_) {
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index 833d23c839e..7c7c2791d4a 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -87,6 +87,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
DebugRendererSettings debug_renderer_settings;
base::ProcessId host_process_id = base::kNullProcessId;
raw_ptr<HintSessionFactory> hint_session_factory = nullptr;
+ size_t max_uncommitted_frames = 0;
};
explicit FrameSinkManagerImpl(const InitParams& params);
@@ -152,6 +153,8 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
const DebugRendererSettings& debug_settings) override;
void Throttle(const std::vector<FrameSinkId>& ids,
base::TimeDelta interval) override;
+ void StartThrottlingAllFrameSinks(base::TimeDelta interval) override;
+ void StopThrottlingAllFrameSinks() override;
void DestroyFrameSinkBundle(const FrameSinkBundleId& id);
@@ -394,9 +397,16 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// Ids of the frame sinks that have been requested to throttle.
std::vector<FrameSinkId> frame_sink_ids_to_throttle_;
- // The throttling interval which defines how often BeginFrames are sent.
+ // The throttling interval which defines how often BeginFrames are sent for
+ // frame sinks in `frame_sink_ids_to_throttle_`, if
+ // `global_throttle_interval_` is unset or if this interval is longer than
+ // `global_throttle_interval_`.
base::TimeDelta throttle_interval_ = BeginFrameArgs::DefaultInterval();
+ // If present, the throttling interval which defines the upper bound of how
+ // often BeginFrames are sent for all current and future frame sinks.
+ absl::optional<base::TimeDelta> global_throttle_interval_ = absl::nullopt;
+
base::flat_map<uint32_t, base::ScopedClosureRunner> cached_back_buffers_;
THREAD_CHECKER(thread_checker_);
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
index c49494e98fb..8f8ba7ef6c9 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_unittest.cc
@@ -33,6 +33,8 @@ constexpr FrameSinkId kFrameSinkIdA(2, 1);
constexpr FrameSinkId kFrameSinkIdB(3, 1);
constexpr FrameSinkId kFrameSinkIdC(4, 1);
constexpr FrameSinkId kFrameSinkIdD(5, 1);
+constexpr FrameSinkId kFrameSinkIdE(6, 1);
+constexpr FrameSinkId kFrameSinkIdF(7, 1);
// Holds the four interface objects needed to create a RootCompositorFrameSink.
struct RootCompositorFrameSinkData {
@@ -472,6 +474,86 @@ TEST_F(FrameSinkManagerTest, Throttle) {
client_d->frame_sink_id());
}
+TEST_F(FrameSinkManagerTest, GlobalThrottle) {
+ // root -> A -> B
+ // -> C -> D
+ auto root = CreateCompositorFrameSinkSupport(kFrameSinkIdRoot);
+ auto client_a = CreateCompositorFrameSinkSupport(kFrameSinkIdA);
+ auto client_b = CreateCompositorFrameSinkSupport(kFrameSinkIdB);
+ auto client_c = CreateCompositorFrameSinkSupport(kFrameSinkIdC);
+ auto client_d = CreateCompositorFrameSinkSupport(kFrameSinkIdD);
+
+ // Set up the hierarchy.
+ manager_.RegisterFrameSinkHierarchy(root->frame_sink_id(),
+ client_a->frame_sink_id());
+ manager_.RegisterFrameSinkHierarchy(client_a->frame_sink_id(),
+ client_b->frame_sink_id());
+ manager_.RegisterFrameSinkHierarchy(root->frame_sink_id(),
+ client_c->frame_sink_id());
+ manager_.RegisterFrameSinkHierarchy(client_c->frame_sink_id(),
+ client_d->frame_sink_id());
+
+ constexpr base::TimeDelta global_interval = base::Hertz(30);
+ constexpr base::TimeDelta interval = base::Hertz(20);
+
+ std::vector<FrameSinkId> ids{kFrameSinkIdRoot, kFrameSinkIdA, kFrameSinkIdB,
+ kFrameSinkIdC, kFrameSinkIdD};
+
+ // By default, a CompositorFrameSinkSupport shouldn't have its
+ // |begin_frame_interval| set.
+ VerifyThrottling(base::TimeDelta(), ids);
+
+ // Starting global throttling should throttle the entire hierarchy.
+ manager_.StartThrottlingAllFrameSinks(global_interval);
+ VerifyThrottling(global_interval, ids);
+
+ // Throttling more aggressively on top of global throttling should further
+ // throttle the specified frame sink hierarchy, but preserve global throttling
+ // on the unaffected framesinks.
+ manager_.Throttle({kFrameSinkIdC}, interval);
+ VerifyThrottling(global_interval,
+ {kFrameSinkIdRoot, kFrameSinkIdA, kFrameSinkIdB});
+ VerifyThrottling(interval, {kFrameSinkIdC, kFrameSinkIdD});
+
+ // Attempting to per-sink throttle to an interval shorter than the global
+ // throttling should still throttle all frame sinks to the global interval.
+ manager_.Throttle({kFrameSinkIdA}, base::Hertz(40));
+ VerifyThrottling(global_interval, ids);
+
+ // Add a new branch to the hierarchy. These new frame sinks should be globally
+ // throttled immediately. root -> A -> B
+ // -> C -> D
+ // -> E -> F
+ auto client_e = CreateCompositorFrameSinkSupport(kFrameSinkIdE);
+ auto client_f = CreateCompositorFrameSinkSupport(kFrameSinkIdF);
+ manager_.RegisterFrameSinkHierarchy(root->frame_sink_id(),
+ client_e->frame_sink_id());
+ manager_.RegisterFrameSinkHierarchy(client_e->frame_sink_id(),
+ client_f->frame_sink_id());
+ VerifyThrottling(
+ global_interval,
+ {kFrameSinkIdRoot, kFrameSinkIdA, kFrameSinkIdB, kFrameSinkIdC,
+ kFrameSinkIdD, kFrameSinkIdE, kFrameSinkIdF});
+
+ // Disabling global throttling should revert back to only the up-to-date
+ // per-frame sink throttling.
+ manager_.StopThrottlingAllFrameSinks();
+ VerifyThrottling(base::Hertz(40), {kFrameSinkIdA, kFrameSinkIdB});
+
+ manager_.UnregisterFrameSinkHierarchy(root->frame_sink_id(),
+ client_a->frame_sink_id());
+ manager_.UnregisterFrameSinkHierarchy(client_a->frame_sink_id(),
+ client_b->frame_sink_id());
+ manager_.UnregisterFrameSinkHierarchy(root->frame_sink_id(),
+ client_c->frame_sink_id());
+ manager_.UnregisterFrameSinkHierarchy(client_c->frame_sink_id(),
+ client_d->frame_sink_id());
+ manager_.UnregisterFrameSinkHierarchy(root->frame_sink_id(),
+ client_e->frame_sink_id());
+ manager_.UnregisterFrameSinkHierarchy(client_e->frame_sink_id(),
+ client_f->frame_sink_id());
+}
+
// Verifies if a frame sink is being captured, it should not be throttled.
TEST_F(FrameSinkManagerTest, NoThrottleOnFrameSinksBeingCaptured) {
// root -> A -> B -> C
diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index 4e38e0f4905..8eeb87e2322 100644
--- a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -81,7 +81,7 @@ RootCompositorFrameSinkImpl::Create(
mojo::Remote<mojom::DisplayClient> display_client(
std::move(params->display_client));
auto display_controller = output_surface_provider->CreateGpuDependency(
- params->gpu_compositing, params->widget, params->renderer_settings);
+ params->gpu_compositing, params->widget);
auto output_surface = output_surface_provider->CreateOutputSurface(
params->widget, params->gpu_compositing, display_client.get(),
display_controller.get(), params->renderer_settings, debug_settings);
@@ -175,9 +175,7 @@ RootCompositorFrameSinkImpl::Create(
auto* output_surface_ptr = output_surface.get();
#endif
gpu::SharedImageInterface* sii = nullptr;
- if (output_surface->context_provider())
- sii = output_surface->context_provider()->SharedImageInterface();
- else if (display_controller)
+ if (display_controller)
sii = display_controller->shared_image_interface();
auto overlay_processor = OverlayProcessorInterface::CreateOverlayProcessor(
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 87a00f3433e..d4924b12e0e 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -37,6 +37,8 @@
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/color_space.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
using media::VideoCaptureOracle;
@@ -111,6 +113,46 @@ CopyOutputRequest::ResultFormat VideoPixelFormatToCopyOutputRequestFormat(
}
}
+bool IsCompatibleWithFormat(const gfx::Rect& rect,
+ media::VideoPixelFormat format) {
+ DCHECK(format == media::PIXEL_FORMAT_I420 ||
+ format == media::PIXEL_FORMAT_NV12 ||
+ format == media::PIXEL_FORMAT_ARGB);
+ if (format == media::PIXEL_FORMAT_ARGB) {
+ // No special requirements:
+ return true;
+ }
+
+ return rect.origin().x() % 2 == 0 && rect.origin().y() % 2 == 0 &&
+ rect.width() % 2 == 0 && rect.height() % 2 == 0;
+}
+
+// Given a |visible_rect| representing visible rectangle of some video frame,
+// calculates a centered rectangle that fits entirely within |visible_rect| and
+// has the same aspect ratio as |source_size|, taking into account
+// |pixel_format|.
+gfx::Rect GetContentRectangle(const gfx::Rect& visible_rect,
+ const gfx::Size& source_size,
+ media::VideoPixelFormat pixel_format) {
+ DCHECK(pixel_format == media::PIXEL_FORMAT_I420 ||
+ pixel_format == media::PIXEL_FORMAT_NV12 ||
+ pixel_format == media::PIXEL_FORMAT_ARGB);
+
+ if (pixel_format == media::PIXEL_FORMAT_I420 ||
+ pixel_format == media::PIXEL_FORMAT_NV12) {
+ return media::ComputeLetterboxRegionForI420(visible_rect, source_size);
+ } else {
+ DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format);
+ const gfx::Rect content_rect =
+ media::ComputeLetterboxRegion(visible_rect, source_size);
+
+ // The media letterboxing computation explicitly allows for off-by-one
+ // errors due to computation, so we address those here.
+ return content_rect.ApproximatelyEqual(visible_rect, 1) ? visible_rect
+ : content_rect;
+ }
+}
+
} // namespace
// static
@@ -208,6 +250,7 @@ void FrameSinkVideoCapturerImpl::SetResolvedTarget(
resolved_target_->AttachCaptureClient(this);
RefreshEntireSourceNow();
} else {
+ MaybeInformConsumerOfEmptyRegion();
// The capturer will remain idle until either: 1) the requested target is
// re-resolved by the |frame_sink_manager_|, or 2) a new target is set via a
// call to ChangeTarget().
@@ -308,6 +351,10 @@ void FrameSinkVideoCapturerImpl::SetResolutionConstraints(
bool use_fixed_aspect_ratio) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DVLOG(2) << __func__ << ": min_size=" << min_size.ToString()
+ << ", max_size=" << max_size.ToString()
+ << ", use_fixed_aspect_ratio=" << use_fixed_aspect_ratio;
+
TRACE_EVENT_INSTANT2("gpu.capture", "SetResolutionConstraints",
TRACE_EVENT_SCOPE_THREAD, "min_size.width",
min_size.width(), "min_size.height", min_size.height());
@@ -534,7 +581,7 @@ void FrameSinkVideoCapturerImpl::RefreshInternal(
// If the capture region is empty, it means one of two things: the first
// frame has not been composited yet or the current region selected for
// capture has a current size of zero. We schedule a frame refresh here,
- // although its not useful in all circumstances.
+ // although it's not useful in all circumstances.
MaybeScheduleRefreshFrame();
return;
}
@@ -695,6 +742,7 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
// TODO(https://crbug.com/1300943): we should likely just get the frame
// region from the last aggregated surface.
if (!compositor_frame_region.Contains(capture_region)) {
+ DVLOG(3) << __func__ << ": skipping capture!";
MaybeScheduleRefreshFrame();
return;
}
@@ -707,9 +755,24 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
// Reserve a buffer from the pool for the next frame.
const OracleFrameNumber oracle_frame_number = oracle_->next_frame_number();
+
+ // Size of the video frames that we are supposed to produce. Depends on the
+ // pixel format and the capture size as determined by the oracle (which in
+ // turn depends on the capture constraints).
const gfx::Size capture_size =
AdjustSizeForPixelFormat(oracle_->capture_size());
+ // Size of the source that we are capturing:
+ const gfx::Size source_size = oracle_->source_size();
+ DCHECK_EQ(capture_region.size(), source_size);
+ DCHECK(!source_size.IsEmpty());
+
+ DVLOG(3) << __func__
+ << ": compositor_frame_region=" << compositor_frame_region.ToString()
+ << ", capture_region=" << capture_region.ToString()
+ << ", capture_size=" << capture_size.ToString()
+ << ", event=" << event;
+
const bool can_resurrect_content = CanResurrectFrame(capture_size);
scoped_refptr<VideoFrame> frame;
if (can_resurrect_content) {
@@ -757,6 +820,13 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
return;
}
+ // If frame was resurrected / allocated from the pool, its visible rectangle
+ // should match what we requested:
+ DCHECK_EQ(frame->visible_rect().size(), capture_size);
+ // The pool should return a frame with visible rectangle that is compatible
+ // with the capture format.
+ DCHECK(IsCompatibleWithFormat(frame->visible_rect(), pixel_format_));
+
// Record a trace event if the capture pipeline is redlining, but capture will
// still proceed.
if (utilization >= 1.0) {
@@ -791,28 +861,33 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
metadata.top_controls_visible_height = last_top_controls_visible_height_;
oracle_->RecordCapture(utilization);
- TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("gpu.capture", "Capture",
- oracle_frame_number, "frame_number",
- capture_frame_number, "trigger",
- VideoCaptureOracle::EventAsString(event));
-
- const gfx::Size& source_size = oracle_->source_size();
- DCHECK(!source_size.IsEmpty());
- gfx::Rect content_rect;
- if (pixel_format_ == media::PIXEL_FORMAT_I420 ||
- pixel_format_ == media::PIXEL_FORMAT_NV12) {
- content_rect = media::ComputeLetterboxRegionForI420(frame->visible_rect(),
- source_size);
- } else {
- DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format_);
- content_rect =
- media::ComputeLetterboxRegion(frame->visible_rect(), source_size);
- // The media letterboxing computation explicitly allows for off-by-one
- // errors due to computation, so we address those here.
- if (content_rect.ApproximatelyEqual(frame->visible_rect(), 1)) {
- content_rect = frame->visible_rect();
- }
- }
+ // Note: The following is used by
+ // chrome/browser/media/cast_mirroring_performance_browsertest.cc, in
+ // addition to the usual runtime tracing
+ // TODO(https://crbug.com/1322573): change to _NESTABLE_ variant of the macro
+ // once the bug is fixed.
+ TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", oracle_frame_number,
+ "frame_number", capture_frame_number, "trigger",
+ VideoCaptureOracle::EventAsString(event));
+
+ // `content_rect` is the region of the `frame` that we would like to populate.
+ // We know our source is of size `source_size`, and we have
+ // `frame->visible_rect()` to fill out - find the largest centered rectangle
+ // that will fit within the frame and maintains the aspect ratio of the
+ // source.
+ // TODO(https://crbug.com/1323342): currently, both the frame's visible
+ // rectangle and source size are controlled by oracle
+ // (`frame->visible_rect().size() == `capture_size`). Oracle also knows if we
+ // need to maintain fixed aspect ratio, so it should compute both the
+ // `capture_size` and `content_rect` for us, thus ensuring that letterboxing
+ // happens only when it needs to (i.e. when we allocate a frame and know that
+ // aspect ratio does not have to be maintained, we should use a size that we
+ // know would not require letterboxing).
+ const gfx::Rect content_rect =
+ GetContentRectangle(frame->visible_rect(), source_size, pixel_format_);
+ DVLOG(3) << __func__ << ": content_rect=" << content_rect.ToString()
+ << ", source_size=" << source_size.ToString()
+ << ", frame=" << frame->AsHumanReadableString();
// Determine what rectangular region has changed since the last captured
// frame.
@@ -896,8 +971,17 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
return;
}
- DCHECK(capture_region.size() == source_size);
- if (absl::holds_alternative<RegionCaptureCropId>(target_->sub_target)) {
+ // If the target is in a different renderer than the root renderer (indicated
+ // by having a different frame sink ID), we currently cannot provide
+ // reasonable metadata about the region capture rect. For more context, see
+ // https://crbug.com/1327560.
+ //
+ // TODO(https://crbug.com/1335175): Provide accurate bounds for elements
+ // embedded in different renderers.
+ const bool is_same_frame_sink_as_requested =
+ resolved_target_->GetFrameSinkId() == target_->frame_sink_id;
+ if (absl::holds_alternative<RegionCaptureCropId>(target_->sub_target) &&
+ is_same_frame_sink_as_requested) {
const float scale_factor = frame_metadata.device_scale_factor;
metadata.region_capture_rect =
scale_factor ? ScaleToEnclosingRect(capture_region, 1.0f / scale_factor)
@@ -923,7 +1007,12 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
std::array<gpu::MailboxHolder, 3> mailbox_holders = {
request_properties.frame->mailbox_holder(0),
request_properties.frame->mailbox_holder(1), gpu::MailboxHolder{}};
- blit_request = BlitRequest(content_rect.origin(), mailbox_holders);
+
+ // TODO(https://crbug.com/775740): change the capturer to only request the
+ // parts of the frame that have changed whenever possible.
+ blit_request =
+ BlitRequest(content_rect.origin(), LetterboxingBehavior::kLetterbox,
+ mailbox_holders, true);
// We haven't captured the frame yet, but let's pretend that we did for the
// sake of blend information computation. We will be asking for an entire
@@ -1017,6 +1106,7 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
scoped_refptr<media::VideoFrame>& frame = properties.frame;
const gfx::Rect& content_rect = properties.content_rect;
+
if (log_to_webrtc_ && consumer_) {
std::string format = "";
std::string strides = "";
@@ -1106,8 +1196,6 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
} else {
frame = nullptr;
}
-
- UMA_HISTOGRAM_CAPTURE_SUCCEEDED("RGBA", success);
} else {
DCHECK_EQ(pixel_format_, media::PIXEL_FORMAT_NV12);
// NV12 is only supported for GMBs for now, in which case there is nothing
@@ -1127,6 +1215,13 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
}
if (frame) {
+ // The result may be smaller than what was requested, if unforeseen
+ // clamping to the source boundaries occurred by the executor of the
+ // CopyOutputRequest. However, the result should never contain more than
+ // what was requested.
+ DCHECK_LE(result->size().width(), content_rect.width());
+ DCHECK_LE(result->size().height(), content_rect.height());
+
if (!frame->HasGpuMemoryBuffer()) {
// For GMB-backed video frames, overlays were already applied by
// CopyOutputRequest API. For in-memory frames, apply overlays here:
@@ -1141,15 +1236,21 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
}
}
- // The result may be smaller than what was requested, if unforeseen
- // clamping to the source boundaries occurred by the executor of the
- // CopyOutputRequest. However, the result should never contain more than
- // what was requested.
- DCHECK_LE(result->size().width(), content_rect.width());
- DCHECK_LE(result->size().height(), content_rect.height());
- media::LetterboxVideoFrame(
- frame.get(), gfx::Rect(content_rect.origin(),
- AdjustSizeForPixelFormat(result->size())));
+ const gfx::Rect result_rect =
+ gfx::Rect(content_rect.origin(), result->size());
+ DCHECK(IsCompatibleWithFormat(result_rect, pixel_format_));
+
+ DVLOG(3) << __func__ << ": result->size()=" << result->size().ToString()
+ << ", content_rect=" << content_rect.ToString()
+ << ", result_rect=" << result_rect.ToString()
+ << ", frame=" << frame->AsHumanReadableString();
+
+ if (frame->visible_rect() != result_rect && !frame->HasGpuMemoryBuffer()) {
+ // If there are parts of the frame that are visible but we have not wrote
+ // into them, letterbox them. This is not needed for GMB-backed frames as
+ // the letterboxing happens on GPU.
+ media::LetterboxVideoFrame(frame.get(), result_rect);
+ }
if (ShouldMark(*frame, properties.content_version)) {
MarkFrame(frame, properties.content_version);
@@ -1220,11 +1321,13 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
// original source content.
base::TimeTicks media_ticks;
if (!oracle_->CompleteCapture(oracle_frame_number, !!frame, &media_ticks)) {
- // The following is used by
+ // Note: The following is used by
// chrome/browser/media/cast_mirroring_performance_browsertest.cc, in
- // addition to the usual runtime tracing.
- TRACE_EVENT_NESTABLE_ASYNC_END1("gpu.capture", "Capture",
- oracle_frame_number, "success", false);
+ // addition to the usual runtime tracing
+ // TODO(https://crbug.com/1322573): change to _NESTABLE_ variant of the
+ // macro once the bug is fixed.
+ TRACE_EVENT_ASYNC_END1("gpu.capture", "Capture", oracle_frame_number,
+ "success", false);
MaybeScheduleRefreshFrame();
return;
@@ -1236,12 +1339,14 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
}
frame->set_timestamp(media_ticks - *first_frame_media_ticks_);
- // The following is used by
+ // Note: The following is used by
// chrome/browser/media/cast_mirroring_performance_browsertest.cc, in
- // addition to the usual runtime tracing.
- TRACE_EVENT_NESTABLE_ASYNC_END2("gpu.capture", "Capture", oracle_frame_number,
- "success", true, "time_delta",
- frame->timestamp().InMicroseconds());
+ // addition to the usual runtime tracing
+ // TODO(https://crbug.com/1322573): change to _NESTABLE_ variant of the macro
+ // once the bug is fixed.
+ TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", oracle_frame_number,
+ "success", true, "time_delta",
+ frame->timestamp().InMicroseconds());
// Clone a handle to the shared memory backing the populated video frame, to
// send to the consumer.
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
index 3e4f833cfdd..20565f12fb2 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -442,8 +442,9 @@ MATCHER_P2(IsLetterboxedFrame, color, content_rect, "") {
const VideoFrame& frame = *arg;
const gfx::Rect kContentRect = content_rect;
- const auto IsLetterboxedPlane = [&frame, kContentRect](int plane,
- uint8_t component) {
+
+ const auto IsLetterboxedPlane = [&frame, kContentRect, result_listener](
+ int plane, uint8_t component) {
gfx::Rect content_rect_copy = kContentRect;
if (plane != VideoFrame::kYPlane) {
content_rect_copy = gfx::Rect(
@@ -455,10 +456,19 @@ MATCHER_P2(IsLetterboxedFrame, color, content_rect, "") {
for (int col = 0; col < frame.row_bytes(plane); ++col) {
if (content_rect_copy.Contains(gfx::Point(col, row))) {
if (p[col] != component) {
+ *result_listener << " where pixel at (" << col << ", " << row
+ << ") should be inside content rectangle and the "
+ "component should match 0x"
+ << std::hex << component << " but is 0x"
+ << std::hex << static_cast<unsigned int>(p[col]);
return false;
}
} else { // Letterbox border around content.
if (plane == VideoFrame::kYPlane && p[col] != 0x00) {
+ *result_listener << " where pixel at (" << col << ", " << row
+ << ") should be outside content rectangle and the "
+ "component should match 0x00 but is 0x"
+ << std::hex << static_cast<unsigned int>(p[col]);
return false;
}
}
@@ -1138,6 +1148,45 @@ TEST_F(FrameSinkVideoCapturerTest, RefreshDemandsAreProperlyHandled) {
StopCapture();
}
+// Tests that the capturer honors requested refresh frames (see
+// crbug.com/1320798)
+TEST_F(FrameSinkVideoCapturerTest, HonorsRequestRefreshFrame) {
+ frame_sink_.SetCopyOutputColor(YUVColor{0x80, 0x80, 0x80});
+ ON_CALL(frame_sink_manager_, FindCapturableFrameSink(kVideoCaptureTarget))
+ .WillByDefault(Return(&frame_sink_));
+
+ capturer_->ChangeTarget(kVideoCaptureTarget, /*crop_version=*/0);
+
+ // Start off and consume the immediate refresh and copy result.
+ MockConsumer consumer;
+ StartCapture(&consumer);
+ frame_sink_.SendCopyOutputResult(0);
+ ASSERT_EQ(1, consumer.num_frames_received());
+ consumer.SendDoneNotification(0);
+
+ // Advance time to avoid being frame rate limited by the oracle.
+ // Demand a refresh frame. We should be past the minimum time to add one, so
+ // it should be done immediately.
+ AdvanceClockToNextVsync();
+ capturer_->RefreshNow();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(2, consumer.num_frames_received());
+
+ // Advance time to avoid being frame rate limited by the oracle.
+ // Request a refresh frame. The request should be serviced immediately.
+ AdvanceClockToNextVsync();
+ capturer_->RequestRefreshFrame();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(3, consumer.num_frames_received());
+
+ // Advance time to avoid being frame rate limited by the oracle.
+ // Request again and expect service.
+ AdvanceClockToNextVsync();
+ capturer_->RequestRefreshFrame();
+ base::RunLoop().RunUntilIdle();
+ ASSERT_EQ(4, consumer.num_frames_received());
+}
+
// Tests that full capture happens on capture resolution change due to oracle,
// but only once and resurrected frames are used after that.
TEST_F(FrameSinkVideoCapturerTest,
diff --git a/chromium/components/viz/service/gl/DEPS b/chromium/components/viz/service/gl/DEPS
index 1510a5d8abd..f5fbbbfbc39 100644
--- a/chromium/components/viz/service/gl/DEPS
+++ b/chromium/components/viz/service/gl/DEPS
@@ -15,6 +15,7 @@ include_rules = [
"+ipc",
"+media/base/android/media_codec_util.h",
"+media/base/media_log.h",
+ "+media/base/win/mf_feature_checks.h",
"+media/gpu",
"+media/mojo",
"+mojo/public/cpp",
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.cc b/chromium/components/viz/service/gl/gpu_service_impl.cc
index a965233a61b..0f9b617fd03 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl.cc
@@ -38,7 +38,6 @@
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "gpu/ipc/common/gpu_peak_memory.h"
#include "gpu/ipc/common/memory_stats.h"
-#include "gpu/ipc/in_process_command_buffer.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
@@ -99,6 +98,8 @@
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
#if BUILDFLAG(IS_WIN)
+#include "components/viz/common/overlay_state/win/overlay_state_service.h"
+#include "media/base/win/mf_feature_checks.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "ui/gl/dcomp_surface_registry.h"
#include "ui/gl/direct_composition_surface_win.h"
@@ -297,10 +298,8 @@ void GetVideoCapabilities(const gpu::GpuPreferences& gpu_preferences,
}
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
- if (media::MediaCodecUtil::IsH264EncoderAvailable(/*use_codec_list*/ false)) {
- vea_profile.profile = gpu::H264PROFILE_BASELINE;
- encoding_profiles.push_back(vea_profile);
- }
+ vea_profile.profile = gpu::H264PROFILE_BASELINE;
+ encoding_profiles.push_back(vea_profile);
#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
// Note: Since Android doesn't have to support PPAPI/Flash, we have not
@@ -431,10 +430,18 @@ GpuServiceImpl::GpuServiceImpl(
#endif
#if BUILDFLAG(IS_WIN)
- auto info_callback = base::BindRepeating(
- &GpuServiceImpl::UpdateOverlayAndHDRInfo, weak_ptr_factory_.GetWeakPtr());
+ auto info_callback =
+ base::BindRepeating(&GpuServiceImpl::UpdateOverlayAndDXGIInfo,
+ weak_ptr_factory_.GetWeakPtr());
gl::DirectCompositionSurfaceWin::SetOverlayHDRGpuInfoUpdateCallback(
info_callback);
+
+ if (media::SupportMediaFoundationClearPlayback()) {
+ // Initialize the OverlayStateService using the GPUServiceImpl task
+ // sequence.
+ auto* overlay_state_service = OverlayStateService::GetInstance();
+ overlay_state_service->Initialize(base::SequencedTaskRunnerHandle::Get());
+ }
#endif
gpu_memory_buffer_factory_ =
@@ -806,7 +813,7 @@ void GpuServiceImpl::CreateJpegEncodeAccelerator(
void GpuServiceImpl::RegisterDCOMPSurfaceHandle(
mojo::PlatformHandle surface_handle,
RegisterDCOMPSurfaceHandleCallback callback) {
- auto token =
+ base::UnguessableToken token =
gl::DCOMPSurfaceRegistry::GetInstance()->RegisterDCOMPSurfaceHandle(
surface_handle.TakeHandle());
std::move(callback).Run(token);
@@ -894,23 +901,22 @@ void GpuServiceImpl::GetPeakMemoryUsage(uint32_t sequence_num,
weak_ptr_, sequence_num, std::move(callback)));
}
-void GpuServiceImpl::RequestHDRStatus(RequestHDRStatusCallback callback) {
+#if BUILDFLAG(IS_WIN)
+void GpuServiceImpl::RequestDXGIInfo(RequestDXGIInfoCallback callback) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
- FROM_HERE, base::BindOnce(&GpuServiceImpl::RequestHDRStatusOnMainThread,
+ FROM_HERE, base::BindOnce(&GpuServiceImpl::RequestDXGIInfoOnMainThread,
weak_ptr_, std::move(callback)));
}
-void GpuServiceImpl::RequestHDRStatusOnMainThread(
- RequestHDRStatusCallback callback) {
+void GpuServiceImpl::RequestDXGIInfoOnMainThread(
+ RequestDXGIInfoCallback callback) {
DCHECK(main_runner_->BelongsToCurrentThread());
-
-#if BUILDFLAG(IS_WIN)
- hdr_enabled_ = gl::DirectCompositionSurfaceWin::IsHDRSupported();
-#endif
+ dxgi_info_ = gl::DirectCompositionSurfaceWin::GetDXGIInfo();
io_runner_->PostTask(FROM_HERE,
- base::BindOnce(std::move(callback), hdr_enabled_));
+ base::BindOnce(std::move(callback), dxgi_info_.Clone()));
}
+#endif
void GpuServiceImpl::RegisterDisplayContext(
gpu::DisplayContext* display_context) {
@@ -960,17 +966,6 @@ void GpuServiceImpl::DidLoseContext(bool offscreen,
gpu_host_->DidLoseContext(offscreen, reason, active_url);
}
-#if BUILDFLAG(IS_WIN)
-void GpuServiceImpl::DidUpdateOverlayInfo(
- const gpu::OverlayInfo& overlay_info) {
- gpu_host_->DidUpdateOverlayInfo(gpu_info_.overlay_info);
-}
-
-void GpuServiceImpl::DidUpdateHDRStatus(bool hdr_enabled) {
- gpu_host_->DidUpdateHDRStatus(hdr_enabled);
-}
-#endif
-
void GpuServiceImpl::StoreShaderToDisk(int client_id,
const std::string& key,
const std::string& shader) {
@@ -1260,7 +1255,7 @@ void GpuServiceImpl::OnForegroundedOnMainThread() {
#if !BUILDFLAG(IS_ANDROID)
void GpuServiceImpl::OnMemoryPressure(
- ::base::MemoryPressureListener::MemoryPressureLevel level) {
+ base::MemoryPressureListener::MemoryPressureLevel level) {
// Forward the notification to the registry of MemoryPressureListeners.
base::MemoryPressureListener::NotifyMemoryPressure(level);
}
@@ -1327,20 +1322,20 @@ gpu::Scheduler* GpuServiceImpl::GetGpuScheduler() {
}
#if BUILDFLAG(IS_WIN)
-void GpuServiceImpl::UpdateOverlayAndHDRInfo() {
+void GpuServiceImpl::UpdateOverlayAndDXGIInfo() {
gpu::OverlayInfo old_overlay_info = gpu_info_.overlay_info;
gpu::CollectHardwareOverlayInfo(&gpu_info_.overlay_info);
// Update overlay info in the GPU process and send the updated data back to
// the GPU host in the Browser process through mojom if the info has changed.
if (old_overlay_info != gpu_info_.overlay_info)
- DidUpdateOverlayInfo(gpu_info_.overlay_info);
+ gpu_host_->DidUpdateOverlayInfo(gpu_info_.overlay_info);
- // Update HDR status in the GPU process through the GPU host mojom.
- bool old_hdr_enabled_status = hdr_enabled_;
- hdr_enabled_ = gl::DirectCompositionSurfaceWin::IsHDRSupported();
- if (old_hdr_enabled_status != hdr_enabled_)
- DidUpdateHDRStatus(hdr_enabled_);
+ // Update DXGI adapter info in the GPU process through the GPU host mojom.
+ auto old_dxgi_info = std::move(dxgi_info_);
+ dxgi_info_ = gl::DirectCompositionSurfaceWin::GetDXGIInfo();
+ if (!mojo::Equals(dxgi_info_, old_dxgi_info))
+ gpu_host_->DidUpdateDXGIInfo(dxgi_info_.Clone());
}
#endif
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.h b/chromium/components/viz/service/gl/gpu_service_impl.h
index 450ebc7730b..194edf37ff7 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.h
+++ b/chromium/components/viz/service/gl/gpu_service_impl.h
@@ -59,18 +59,15 @@ class GpuMemoryBufferFactory;
class GpuWatchdogThread;
class ImageDecodeAcceleratorWorker;
class Scheduler;
-class SyncPointManager;
+class SharedContextState;
class SharedImageManager;
+class SyncPointManager;
class VulkanImplementation;
} // namespace gpu
namespace media {
class MediaGpuChannelManager;
-}
-
-namespace gpu {
-class SharedContextState;
-} // namespace gpu
+} // namespace media
namespace viz {
@@ -194,8 +191,9 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void StartPeakMemoryMonitor(uint32_t sequence_num) override;
void GetPeakMemoryUsage(uint32_t sequence_num,
GetPeakMemoryUsageCallback callback) override;
-
- void RequestHDRStatus(RequestHDRStatusCallback callback) override;
+#if BUILDFLAG(IS_WIN)
+ void RequestDXGIInfo(RequestDXGIInfoCallback callback) override;
+#endif
void LoadedShader(int32_t client_id,
const std::string& key,
const std::string& data) override;
@@ -236,10 +234,6 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void DidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason,
const GURL& active_url) override;
-#if BUILDFLAG(IS_WIN)
- void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
- void DidUpdateHDRStatus(bool hdr_enabled) override;
-#endif
void GetDawnInfo(GetDawnInfoCallback callback) override;
void StoreShaderToDisk(int client_id,
@@ -386,7 +380,9 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
#endif // BUILDFLAG(IS_CHROMEOS_ASH) &&
// BUILDFLAG(USE_CHROMEOS_MEDIA_ACCELERATION)
- void RequestHDRStatusOnMainThread(RequestHDRStatusCallback callback);
+#if BUILDFLAG(IS_WIN)
+ void RequestDXGIInfoOnMainThread(RequestDXGIInfoCallback callback);
+#endif
void OnBackgroundedOnMainThread();
void OnForegroundedOnMainThread();
@@ -403,7 +399,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
// Update overlay info and HDR status on the GPU process and send the updated
// info back to the browser process if there is a change.
#if BUILDFLAG(IS_WIN)
- void UpdateOverlayAndHDRInfo();
+ void UpdateOverlayAndDXGIInfo();
#endif
void GetDawnInfoOnMain(GetDawnInfoCallback callback);
@@ -425,7 +421,9 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
const gpu::GpuDriverBugWorkarounds gpu_driver_bug_workarounds_;
- bool hdr_enabled_ = false;
+#if BUILDFLAG(IS_WIN)
+ gfx::mojom::DXGIInfoPtr dxgi_info_;
+#endif
// What we would have gotten if we haven't fallen back to SwiftShader or
// pure software (in the viz case).
diff --git a/chromium/components/viz/service/main/viz_compositor_thread_runner.h b/chromium/components/viz/service/main/viz_compositor_thread_runner.h
index 4d69c164c50..69798c9c4ff 100644
--- a/chromium/components/viz/service/main/viz_compositor_thread_runner.h
+++ b/chromium/components/viz/service/main/viz_compositor_thread_runner.h
@@ -14,10 +14,6 @@ namespace base {
class SingleThreadTaskRunner;
}
-namespace gpu {
-class CommandBufferTaskExecutor;
-} // namespace gpu
-
namespace viz {
class GpuServiceImpl;
@@ -36,16 +32,12 @@ class VizCompositorThreadRunner {
base::flat_set<base::PlatformThreadId> thread_ids,
base::RepeatingClosure* wake_up_closure) = 0;
- // Creates FrameSinkManager from |params|. The version with |gpu_service| and
- // |task_executor| supports both GPU and software compositing, while the
- // version without supports only software compositing. Should be called from
- // the thread that owns |this| to initialize state on VizCompositorThread.
- virtual void CreateFrameSinkManager(
- mojom::FrameSinkManagerParamsPtr params) = 0;
- virtual void CreateFrameSinkManager(
- mojom::FrameSinkManagerParamsPtr params,
- gpu::CommandBufferTaskExecutor* task_executor,
- GpuServiceImpl* gpu_service) = 0;
+ // Creates FrameSinkManager from |params|. If |gpu_service| is null the
+ // display compositor will only support software compositing. Should be called
+ // from the thread that owns |this| to initialize state on
+ // VizCompositorThread.
+ virtual void CreateFrameSinkManager(mojom::FrameSinkManagerParamsPtr params,
+ GpuServiceImpl* gpu_service) = 0;
};
} // namespace viz
diff --git a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc
index 798434cf6df..6b7d8fcc565 100644
--- a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc
+++ b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.cc
@@ -28,7 +28,6 @@
#include "components/viz/service/performance_hint/hint_session.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_switches.h"
-#include "gpu/ipc/command_buffer_task_executor.h"
#include "gpu/ipc/scheduler_sequence.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "services/tracing/public/cpp/stack_sampling/tracing_sampler_profiler.h"
@@ -151,17 +150,7 @@ base::SingleThreadTaskRunner* VizCompositorThreadRunnerImpl::task_runner() {
}
void VizCompositorThreadRunnerImpl::CreateFrameSinkManager(
- mojom::FrameSinkManagerParamsPtr params) {
- task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&VizCompositorThreadRunnerImpl::
- CreateFrameSinkManagerOnCompositorThread,
- base::Unretained(this), std::move(params),
- nullptr, nullptr));
-}
-
-void VizCompositorThreadRunnerImpl::CreateFrameSinkManager(
mojom::FrameSinkManagerParamsPtr params,
- gpu::CommandBufferTaskExecutor* task_executor,
GpuServiceImpl* gpu_service) {
// All of the unretained objects are owned on the GPU thread and destroyed
// after VizCompositorThread has been shutdown.
@@ -169,18 +158,15 @@ void VizCompositorThreadRunnerImpl::CreateFrameSinkManager(
FROM_HERE, base::BindOnce(&VizCompositorThreadRunnerImpl::
CreateFrameSinkManagerOnCompositorThread,
base::Unretained(this), std::move(params),
- base::Unretained(task_executor),
base::Unretained(gpu_service)));
}
void VizCompositorThreadRunnerImpl::CreateFrameSinkManagerOnCompositorThread(
mojom::FrameSinkManagerParamsPtr params,
- gpu::CommandBufferTaskExecutor* task_executor,
GpuServiceImpl* gpu_service) {
DCHECK(task_runner_->BelongsToCurrentThread());
DCHECK(!frame_sink_manager_);
- if (features::IsUsingSkiaRenderer())
- gpu::SchedulerSequence::DefaultDisallowScheduleTaskOnCurrentThread();
+ gpu::SchedulerSequence::DefaultDisallowScheduleTaskOnCurrentThread();
server_shared_bitmap_manager_ = std::make_unique<ServerSharedBitmapManager>();
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
@@ -192,17 +178,14 @@ void VizCompositorThreadRunnerImpl::CreateFrameSinkManagerOnCompositorThread(
const bool run_all_compositor_stages_before_draw =
command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw);
- if (task_executor) {
- DCHECK(gpu_service);
+ if (gpu_service) {
// Create OutputSurfaceProvider usable for GPU + software compositing.
gpu_memory_buffer_manager_ =
std::make_unique<InProcessGpuMemoryBufferManager>(
gpu_service->gpu_memory_buffer_factory(),
gpu_service->sync_point_manager());
- auto* image_factory = gpu_service->gpu_image_factory();
- output_surface_provider_ = std::make_unique<OutputSurfaceProviderImpl>(
- gpu_service, task_executor, gpu_service,
- gpu_memory_buffer_manager_.get(), image_factory, headless);
+ output_surface_provider_ =
+ std::make_unique<OutputSurfaceProviderImpl>(gpu_service, headless);
// Create video frame pool context provider that will enable the frame sink
// manager to create GMB-backed video frames.
diff --git a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h
index d0ea9a64371..c03ed0ef016 100644
--- a/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h
+++ b/chromium/components/viz/service/main/viz_compositor_thread_runner_impl.h
@@ -52,9 +52,7 @@ class VizCompositorThreadRunnerImpl : public VizCompositorThreadRunner {
bool CreateHintSessionFactory(
base::flat_set<base::PlatformThreadId> thread_ids,
base::RepeatingClosure* wake_up_closure) override;
- void CreateFrameSinkManager(mojom::FrameSinkManagerParamsPtr params) override;
void CreateFrameSinkManager(mojom::FrameSinkManagerParamsPtr params,
- gpu::CommandBufferTaskExecutor* task_executor,
GpuServiceImpl* gpu_service) override;
private:
@@ -65,7 +63,6 @@ class VizCompositorThreadRunnerImpl : public VizCompositorThreadRunner {
void WakeUpOnCompositorThread();
void CreateFrameSinkManagerOnCompositorThread(
mojom::FrameSinkManagerParamsPtr params,
- gpu::CommandBufferTaskExecutor* task_executor,
GpuServiceImpl* gpu_service);
void TearDownOnCompositorThread();
diff --git a/chromium/components/viz/service/main/viz_main_impl.cc b/chromium/components/viz/service/main/viz_main_impl.cc
index f682cf1fced..8275099bb63 100644
--- a/chromium/components/viz/service/main/viz_main_impl.cc
+++ b/chromium/components/viz/service/main/viz_main_impl.cc
@@ -172,7 +172,7 @@ void VizMainImpl::CreateGpuService(
mojo::PendingRemote<
discardable_memory::mojom::DiscardableSharedMemoryManager>
discardable_memory_manager,
- mojo::ScopedSharedBufferHandle activity_flags,
+ base::UnsafeSharedMemoryRegion activity_flags_region,
gfx::FontRenderParams::SubpixelRendering subpixel_rendering) {
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
@@ -208,7 +208,7 @@ void VizMainImpl::CreateGpuService(
gpu_service_->InitializeWithHost(
gpu_host.Unbind(),
- gpu::GpuProcessActivityFlags(std::move(activity_flags)),
+ gpu::GpuProcessActivityFlags(std::move(activity_flags_region)),
gpu_init_->TakeDefaultOffscreenSurface(),
dependencies_.sync_point_manager, dependencies_.shared_image_manager,
dependencies_.shutdown_event);
@@ -261,16 +261,6 @@ void VizMainImpl::CreateFrameSinkManagerInternal(
DCHECK(gpu_service_);
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
- gl::GLSurfaceFormat format;
- // If we are running a SW Viz process, we may not have a default offscreen
- // surface.
- if (auto* offscreen_surface =
- gpu_service_->gpu_channel_manager()->default_offscreen_surface()) {
- format = offscreen_surface->GetFormat();
- } else {
- DCHECK_EQ(gl::GetGLImplementation(), gl::kGLImplementationDisabled);
- }
-
// When the host loses its connection to the viz process, it assumes the
// process has crashed and tries to reinitialize it. However, it is possible
// to have lost the connection for other reasons (e.g. deserialization
@@ -278,18 +268,11 @@ void VizMainImpl::CreateFrameSinkManagerInternal(
// FrameSinkManagerImpl, so just do a hard CHECK rather than crashing down the
// road so that all crash reports caused by this issue look the same and have
// the same signature. https://crbug.com/928845
- CHECK(!task_executor_);
-
- task_executor_ = std::make_unique<gpu::GpuInProcessThreadService>(
- this, gpu_thread_task_runner_, gpu_service_->GetGpuScheduler(),
- gpu_service_->sync_point_manager(), gpu_service_->mailbox_manager(),
- format, gpu_service_->gpu_feature_info(),
- gpu_service_->gpu_channel_manager()->gpu_preferences(),
- gpu_service_->shared_image_manager(),
- gpu_service_->gpu_channel_manager()->program_cache());
-
- viz_compositor_thread_runner_->CreateFrameSinkManager(
- std::move(params), task_executor_.get(), gpu_service_.get());
+ CHECK(!has_created_frame_sink_manager_);
+ has_created_frame_sink_manager_ = true;
+
+ viz_compositor_thread_runner_->CreateFrameSinkManager(std::move(params),
+ gpu_service_.get());
}
#if BUILDFLAG(USE_VIZ_DEBUGGER)
@@ -307,20 +290,6 @@ void VizMainImpl::StopDebugStream() {
}
#endif
-scoped_refptr<gpu::SharedContextState> VizMainImpl::GetSharedContextState() {
- // This method should be only called for GLRenderer and not for SkiaRenderer.
- // Hence adding DCHECK since DrDc only works with SkiaRenderer.
- DCHECK(!features::IsDrDcEnabled());
- return gpu_service_->GetContextState();
-}
-
-scoped_refptr<gl::GLShareGroup> VizMainImpl::GetShareGroup() {
- // This method should be only called for GLRenderer and not for SkiaRenderer.
- // Hence adding DCHECK since DrDc only works with SkiaRenderer.
- DCHECK(!features::IsDrDcEnabled());
- return gpu_service_->share_group();
-}
-
void VizMainImpl::ExitProcess(ExitCode immediate_exit_code) {
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
diff --git a/chromium/components/viz/service/main/viz_main_impl.h b/chromium/components/viz/service/main/viz_main_impl.h
index b2965ba9abf..74024c98bef 100644
--- a/chromium/components/viz/service/main/viz_main_impl.h
+++ b/chromium/components/viz/service/main/viz_main_impl.h
@@ -8,6 +8,7 @@
#include <memory>
#include "base/memory/raw_ptr.h"
+#include "base/memory/unsafe_shared_memory_region.h"
#include "base/process/process_handle.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread.h"
@@ -16,8 +17,6 @@
#include "components/viz/common/buildflags.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "components/viz/service/main/viz_compositor_thread_runner_impl.h"
-#include "gpu/ipc/gpu_in_process_thread_service.h"
-#include "gpu/ipc/in_process_command_buffer.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
@@ -50,8 +49,7 @@ namespace viz {
class InfoCollectionGpuServiceImpl;
#endif
-class VizMainImpl : public mojom::VizMain,
- public gpu::GpuInProcessThreadServiceDelegate {
+class VizMainImpl : public mojom::VizMain {
public:
class Delegate {
public:
@@ -120,7 +118,7 @@ class VizMainImpl : public mojom::VizMain,
mojo::PendingRemote<
discardable_memory::mojom::DiscardableSharedMemoryManager>
discardable_memory_manager,
- mojo::ScopedSharedBufferHandle activity_flags,
+ base::UnsafeSharedMemoryRegion activity_flags_region,
gfx::FontRenderParams::SubpixelRendering subpixel_rendering) override;
#if BUILDFLAG(IS_WIN)
void CreateInfoCollectionGpuService(
@@ -138,10 +136,6 @@ class VizMainImpl : public mojom::VizMain,
void StopDebugStream() override;
#endif
- // gpu::GpuInProcessThreadServiceDelegate implementation:
- scoped_refptr<gpu::SharedContextState> GetSharedContextState() override;
- scoped_refptr<gl::GLShareGroup> GetShareGroup() override;
-
GpuServiceImpl* gpu_service() { return gpu_service_.get(); }
const GpuServiceImpl* gpu_service() const { return gpu_service_.get(); }
@@ -179,22 +173,19 @@ class VizMainImpl : public mojom::VizMain,
std::unique_ptr<InfoCollectionGpuServiceImpl> info_collection_gpu_service_;
#endif
- // Allows the display compositor to use InProcessCommandBuffer to send GPU
- // commands to the GPU thread from the compositor thread. This must outlive
- // |viz_compositor_thread_runner_|.
- std::unique_ptr<gpu::CommandBufferTaskExecutor> task_executor_;
-
// If the gpu service is not yet ready then we stash pending
// FrameSinkManagerParams.
mojom::FrameSinkManagerParamsPtr pending_frame_sink_manager_params_;
+ bool has_created_frame_sink_manager_ = false;
+
// Runs the VizCompositorThread for the display compositor.
std::unique_ptr<VizCompositorThreadRunnerImpl>
viz_compositor_thread_runner_impl_;
// Note under Android WebView where VizCompositorThreadRunner is not created
// and owned by this, Viz does not interact with other objects in this class,
- // such as GpuServiceImpl or CommandBufferTaskExecutor. Code should take care
- // to avoid introducing such assumptions.
+ // such as GpuServiceImpl. Code should take care to avoid introducing such
+ // assumptions.
raw_ptr<VizCompositorThreadRunner> viz_compositor_thread_runner_ = nullptr;
const scoped_refptr<base::SingleThreadTaskRunner> gpu_thread_task_runner_;
diff --git a/chromium/components/viz/service/main/viz_main_impl_unittest.cc b/chromium/components/viz/service/main/viz_main_impl_unittest.cc
index abc59d12216..f5c74005135 100644
--- a/chromium/components/viz/service/main/viz_main_impl_unittest.cc
+++ b/chromium/components/viz/service/main/viz_main_impl_unittest.cc
@@ -57,11 +57,8 @@ class MockVizCompositorThreadRunner : public VizCompositorThreadRunner {
base::RepeatingClosure* wake_up_closure) override {
return false;
}
- MOCK_METHOD1(CreateFrameSinkManager, void(mojom::FrameSinkManagerParamsPtr));
- MOCK_METHOD3(CreateFrameSinkManager,
- void(mojom::FrameSinkManagerParamsPtr,
- gpu::CommandBufferTaskExecutor*,
- GpuServiceImpl*));
+ MOCK_METHOD2(CreateFrameSinkManager,
+ void(mojom::FrameSinkManagerParamsPtr, GpuServiceImpl*));
private:
const raw_ptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/chromium/components/viz/service/performance_hint/hint_session.cc b/chromium/components/viz/service/performance_hint/hint_session.cc
index ecb5a5f2281..1731aef08dc 100644
--- a/chromium/components/viz/service/performance_hint/hint_session.cc
+++ b/chromium/components/viz/service/performance_hint/hint_session.cc
@@ -35,6 +35,8 @@ using pAPerformanceHint_createSession =
const int32_t* threadIds,
size_t size,
int64_t initialTargetWorkDurationNanos);
+using pAPerformanceHint_updateTargetWorkDuration =
+ int (*)(APerformanceHintSession* session, int64_t targetDurationNanos);
using pAPerformanceHint_reportActualWorkDuration =
int (*)(APerformanceHintSession* session, int64_t actualDurationNanos);
using pAPerformanceHint_closeSession =
@@ -74,6 +76,7 @@ struct AdpfMethods {
LOAD_FUNCTION(main_dl_handle, APerformanceHint_getManager);
LOAD_FUNCTION(main_dl_handle, APerformanceHint_createSession);
+ LOAD_FUNCTION(main_dl_handle, APerformanceHint_updateTargetWorkDuration);
LOAD_FUNCTION(main_dl_handle, APerformanceHint_reportActualWorkDuration);
LOAD_FUNCTION(main_dl_handle, APerformanceHint_closeSession);
}
@@ -83,6 +86,8 @@ struct AdpfMethods {
bool supported = true;
pAPerformanceHint_getManager APerformanceHint_getManagerFn;
pAPerformanceHint_createSession APerformanceHint_createSessionFn;
+ pAPerformanceHint_updateTargetWorkDuration
+ APerformanceHint_updateTargetWorkDurationFn;
pAPerformanceHint_reportActualWorkDuration
APerformanceHint_reportActualWorkDurationFn;
pAPerformanceHint_closeSession APerformanceHint_closeSessionFn;
@@ -95,6 +100,7 @@ class AdpfHintSession : public HintSession {
base::TimeDelta target_duration);
~AdpfHintSession() override;
+ void UpdateTargetDuration(base::TimeDelta target_duration) override;
void ReportCpuCompletionTime(base::TimeDelta actual_duration) override;
void WakeUp();
@@ -102,7 +108,7 @@ class AdpfHintSession : public HintSession {
private:
APerformanceHintSession* const hint_session_;
HintSessionFactoryImpl* const factory_;
- const base::TimeDelta target_duration_;
+ base::TimeDelta target_duration_;
};
class HintSessionFactoryImpl : public HintSessionFactory {
@@ -143,6 +149,15 @@ AdpfHintSession::~AdpfHintSession() {
AdpfMethods::Get().APerformanceHint_closeSessionFn(hint_session_);
}
+void AdpfHintSession::UpdateTargetDuration(base::TimeDelta target_duration) {
+ DCHECK_CALLED_ON_VALID_THREAD(factory_->thread_checker_);
+ if (target_duration_ == target_duration)
+ return;
+ target_duration_ = target_duration;
+ AdpfMethods::Get().APerformanceHint_updateTargetWorkDurationFn(
+ hint_session_, target_duration.InNanoseconds());
+}
+
void AdpfHintSession::ReportCpuCompletionTime(base::TimeDelta actual_duration) {
DCHECK_CALLED_ON_VALID_THREAD(factory_->thread_checker_);
AdpfMethods::Get().APerformanceHint_reportActualWorkDurationFn(
diff --git a/chromium/components/viz/service/performance_hint/hint_session.h b/chromium/components/viz/service/performance_hint/hint_session.h
index a961ea93522..91b601465ff 100644
--- a/chromium/components/viz/service/performance_hint/hint_session.h
+++ b/chromium/components/viz/service/performance_hint/hint_session.h
@@ -22,6 +22,8 @@ class VIZ_SERVICE_EXPORT HintSession {
public:
virtual ~HintSession() = default;
+ virtual void UpdateTargetDuration(base::TimeDelta target_duration) = 0;
+
// `actual_duration` is compared to `target_duration` in `CreateSession` to
// determine the performance of a frame.
virtual void ReportCpuCompletionTime(base::TimeDelta actual_duration) = 0;
diff --git a/chromium/components/viz/service/surfaces/surface.cc b/chromium/components/viz/service/surfaces/surface.cc
index 900270f8b6d..9a68ef9a234 100644
--- a/chromium/components/viz/service/surfaces/surface.cc
+++ b/chromium/components/viz/service/surfaces/surface.cc
@@ -80,11 +80,13 @@ void Surface::PresentationHelper::DidPresent(
Surface::Surface(const SurfaceInfo& surface_info,
SurfaceManager* surface_manager,
SurfaceAllocationGroup* allocation_group,
- base::WeakPtr<SurfaceClient> surface_client)
+ base::WeakPtr<SurfaceClient> surface_client,
+ size_t max_uncommitted_frames)
: surface_info_(surface_info),
surface_manager_(surface_manager),
surface_client_(std::move(surface_client)),
- allocation_group_(allocation_group) {
+ allocation_group_(allocation_group),
+ max_uncommitted_frames_(max_uncommitted_frames) {
TRACE_EVENT_ASYNC_BEGIN1(TRACE_DISABLED_BY_DEFAULT("viz.surface_lifetime"),
"Surface", this, "surface_info",
surface_info.ToString());
@@ -189,30 +191,70 @@ Surface::QueueFrameResult Surface::QueueFrame(
return QueueFrameResult::REJECTED;
}
- QueueFrameResult result = QueueFrameResult::ACCEPTED_ACTIVE;
+ // Receive and track the resources referenced from the CompositorFrame
+ // regardless of whether it's pending or active.
+ surface_client_->ReceiveFromChild(frame.resource_list);
+
+ QueueFrameResult result = QueueFrameResult::ACCEPTED_PENDING;
+
+ if (!max_uncommitted_frames_) {
+ result = CommitFrame(FrameData(std::move(frame), frame_index));
+ } else {
+ // Return oldest frame if uncommitted queue is full.
+ DCHECK_LE(uncommitted_frames_.size(), max_uncommitted_frames_);
+ if (uncommitted_frames_.size() == max_uncommitted_frames_) {
+ TRACE_EVENT_INSTANT1("viz", "DropUncommitedFrame",
+ TRACE_EVENT_SCOPE_THREAD, "queue_length",
+ uncommitted_frames_.size());
+
+ UnrefFrameResourcesAndRunCallbacks(
+ std::move(uncommitted_frames_.front()));
+ uncommitted_frames_.pop_front();
+ }
+
+ uncommitted_frames_.push_back(FrameData(std::move(frame), frame_index));
+
+ // If we still have space in queue we should send ack the client because we
+ // can receive another frame without dropping it.
+ if (uncommitted_frames_.size() < max_uncommitted_frames_) {
+ TRACE_EVENT_INSTANT1("viz", "AckingUncommitedFrame",
+ TRACE_EVENT_SCOPE_THREAD, "queue_length",
+ uncommitted_frames_.size());
+ uncommitted_frames_.back().SendAckIfNeeded(surface_client_.get());
+ }
+
+ surface_manager_->OnSurfaceHasNewUncommittedFrame(this);
+ }
+ // The frame should not fail to display beyond this point. Release the
+ // callback so it is not called.
+ std::ignore = frame_rejected_callback.Release();
+
+ return result;
+}
+
+Surface::QueueFrameResult Surface::CommitFrame(FrameData frame) {
+ TRACE_EVENT1("viz", "Surface::CommitFrame", "SurfaceId",
+ surface_id().ToString());
is_latency_info_taken_ = false;
if (active_frame_data_ || pending_frame_data_)
previous_frame_surface_id_ = surface_id();
- TakePendingLatencyInfo(&frame.metadata.latency_info);
+ TakePendingLatencyInfo(&frame.frame.metadata.latency_info);
absl::optional<FrameData> previous_pending_frame_data =
std::move(pending_frame_data_);
pending_frame_data_.reset();
- UpdateActivationDependencies(frame);
-
- // Receive and track the resources referenced from the CompositorFrame
- // regardless of whether it's pending or active.
- surface_client_->ReceiveFromChild(frame.resource_list);
+ UpdateActivationDependencies(frame.frame);
+ QueueFrameResult result = QueueFrameResult::ACCEPTED_ACTIVE;
if (activation_dependencies_.empty()) {
// If there are no blockers, then immediately activate the frame.
- ActivateFrame(FrameData(std::move(frame), frame_index));
+ ActivateFrame(std::move(frame));
} else {
- pending_frame_data_ = FrameData(std::move(frame), frame_index);
+ pending_frame_data_ = std::move(frame);
auto traced_value = std::make_unique<base::trace_event::TracedValue>();
traced_value->BeginArray("Pending");
@@ -240,9 +282,8 @@ Surface::QueueFrameResult Surface::QueueFrame(
// Returns resources for the previous pending frame.
UnrefFrameResourcesAndRunCallbacks(std::move(previous_pending_frame_data));
- // The frame should not fail to display beyond this point. Release the
- // callback so it is not called.
- std::ignore = frame_rejected_callback.Release();
+ if (surface_client_)
+ surface_client_->OnSurfaceCommitted(this);
return result;
}
@@ -340,6 +381,14 @@ Surface::FrameData& Surface::FrameData::operator=(FrameData&& other) = default;
Surface::FrameData::~FrameData() = default;
+void Surface::FrameData::SendAckIfNeeded(SurfaceClient* client) {
+ if (!frame_acked) {
+ frame_acked = true;
+ if (client)
+ client->SendCompositorFrameAck();
+ }
+}
+
void Surface::ActivatePendingFrame() {
DCHECK(pending_frame_data_);
FrameData frame_data = std::move(*pending_frame_data_);
@@ -356,6 +405,67 @@ void Surface::ActivatePendingFrame() {
ActivateFrame(std::move(frame_data));
}
+void Surface::CommitFramesRecursively(const CommitPredicate& predicate) {
+ TRACE_EVENT1("viz", "Surface::CommitFramesRecursively", "SurfaceId",
+ surface_id().ToString());
+
+ // This should only be called if we use uncommitted frames queue.
+ DCHECK_GT(max_uncommitted_frames_, 0u);
+
+ while (!uncommitted_frames_.empty()) {
+ const auto& ack =
+ uncommitted_frames_.front().frame.metadata.begin_frame_ack;
+
+ if (!predicate.Run(surface_id(), ack.frame_id))
+ break;
+
+ CommitFrame(std::move(uncommitted_frames_.front()));
+ uncommitted_frames_.pop_front();
+ }
+
+ if (HasPendingFrame()) {
+ for (auto& range : pending_frame_data_->frame.metadata.referenced_surfaces)
+ surface_manager_->CommitFramesInRangeRecursively(range, predicate);
+ }
+
+ if (HasActiveFrame()) {
+ for (auto& range : active_frame_data_->frame.metadata.referenced_surfaces)
+ surface_manager_->CommitFramesInRangeRecursively(range, predicate);
+ }
+
+ // If we freed up some space in queue send ack for the last frame if it's
+ // still unacked, so client can continue producing frames.
+ if (uncommitted_frames_.size() < max_uncommitted_frames_) {
+ if (!uncommitted_frames_.empty())
+ uncommitted_frames_.back().SendAckIfNeeded(surface_client_.get());
+
+ // Only last frame can be unacked because we ack frames as we put them in
+ // queue if queue isn't full. If we acked frame above, now verify that
+ // they all are acked, to ensure we ack frame in order.
+#if DCHECK_IS_ON()
+ for (auto& frames : uncommitted_frames_) {
+ DCHECK(frames.frame_acked);
+ }
+#endif
+ }
+}
+
+absl::optional<BeginFrameId> Surface::GetFirstUncommitedFrameId() {
+ if (uncommitted_frames_.empty())
+ return absl::nullopt;
+ return uncommitted_frames_.front().frame.metadata.begin_frame_ack.frame_id;
+}
+
+absl::optional<BeginFrameId> Surface::GetUncommitedFrameIdNewerThan(
+ const BeginFrameId& frame_id) {
+ for (auto& frame : uncommitted_frames_) {
+ if (frame.frame.metadata.begin_frame_ack.frame_id.IsNextInSequenceTo(
+ frame_id))
+ return frame.frame.metadata.begin_frame_ack.frame_id;
+ }
+ return absl::nullopt;
+}
+
void Surface::UpdateReferencedAllocationGroups(
std::vector<SurfaceAllocationGroup*> new_referenced_allocation_groups) {
base::flat_set<SurfaceAllocationGroup*> new_set(
@@ -668,11 +778,8 @@ Surface::TakePresentationHelperForPresentNotification() {
}
void Surface::SendAckToClient() {
- if (!active_frame_data_ || active_frame_data_->frame_acked)
- return;
- active_frame_data_->frame_acked = true;
- if (surface_client_)
- surface_client_->OnSurfaceProcessed(this);
+ if (active_frame_data_)
+ active_frame_data_->SendAckIfNeeded(surface_client_.get());
}
void Surface::MarkAsDrawn() {
@@ -718,8 +825,7 @@ void Surface::UnrefFrameResourcesAndRunCallbacks(
resource.sync_token.Clear();
surface_client_->UnrefResources(std::move(resources));
- if (!frame_data->frame_acked)
- surface_client_->OnSurfaceProcessed(this);
+ frame_data->SendAckIfNeeded(surface_client_.get());
// If we won't be getting a presented notification, we'll notify the client
// when the frame is unref'd.
@@ -790,7 +896,6 @@ void Surface::OnWillBeDrawn() {
}
void Surface::ActivatePendingFrameForInheritedDeadline() {
- DCHECK(HasPendingFrame());
// Deadline inheritance implies that this surface was blocking the embedder,
// so there shouldn't be an active frame.
DCHECK(!HasActiveFrame());
diff --git a/chromium/components/viz/service/surfaces/surface.h b/chromium/components/viz/service/surfaces/surface.h
index 30c4619c576..565c043f33e 100644
--- a/chromium/components/viz/service/surfaces/surface.h
+++ b/chromium/components/viz/service/surfaces/surface.h
@@ -17,6 +17,7 @@
#include "base/callback.h"
#include "base/callback_helpers.h"
+#include "base/containers/circular_deque.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/platform_thread.h"
@@ -53,24 +54,32 @@ class SurfaceManager;
// A Surface is a representation of a sequence of CompositorFrames with a
// common set of properties uniquely identified by a SurfaceId. In particular,
// all CompositorFrames submitted to a single Surface share properties described
-// in SurfaceInfo: device scale factor and size. A Surface can hold up to two
+// in SurfaceInfo: device scale factor and size. A Surface can hold up few
// CompositorFrames at a given time:
//
-// Active frame: An active frame is a candidate for display. A
-// CompositorFrame is active if it has been explicitly marked
-// as active after a deadline has passed or all its
-// dependencies are active.
+// Uncommitted frames: It's frame that has been received, but hasn't been
+// processed yet. There can be up to
+// `max_uncommitted_frames_` in this state. If
+// `max_uncommitted_frames_` is zero all frames are
+// committed as soon as they are received.
//
-// Pending frame: A pending CompositorFrame cannot be displayed on screen. A
-// CompositorFrame is pending if it has unresolved
-// dependencies: surface Ids to which there are no active
-// CompositorFrames.
+// Pending frame: A pending CompositorFrame cannot be displayed on
+// screen. A CompositorFrame is pending when it has been
+// committed but has unresolved dependencies: surface Ids
+// to which there are no active CompositorFrames. There
+// can be only one pending frame.
//
-// This two stage mechanism for managing CompositorFrames from a client exists
-// to enable best-effort synchronization across clients. A surface subtree will
-// remain pending until all dependencies are resolved: all clients have
-// submitted CompositorFrames corresponding to a new property of the subtree
-// (e.g. a new size).
+// Active frame: An active frame is a candidate for display. A
+// CompositorFrame is active if it has been explicitly
+// marked as active after a deadline has passed or all
+// its dependencies are active. There can be only one
+// active frame.
+//
+// This pending+active frame mechanism for managing CompositorFrames from a
+// client exists to enable best-effort synchronization across clients. A surface
+// subtree will remain pending until all dependencies are resolved: all clients
+// have submitted CompositorFrames corresponding to a new property of the
+// subtree (e.g. a new size).
//
// Clients are assumed to be untrusted and so a client may not submit a
// CompositorFrame to satisfy the dependency of the parent. Thus, by default, a
@@ -78,6 +87,13 @@ class SurfaceManager;
// deadline passes, then the CompositorFrame will activate despite missing
// dependencies. The activated CompositorFrame can specify fallback behavior in
// the event of missing dependencies at display time.
+//
+// On WebView display compositor runs asynchronously in regards of BeginFrames
+// and CompositorFrame submissions, to avoid frame drops due to racyness
+// uncommitted queue mechanism is used. When clients submits frame it goes to
+// the queue and when the display compositor draws frames are committed from
+// the queue to the pending or active frame.
+
class VIZ_SERVICE_EXPORT Surface final {
public:
class PresentationHelper {
@@ -103,10 +119,14 @@ class VIZ_SERVICE_EXPORT Surface final {
base::OnceCallback<void(const gfx::PresentationFeedback&)>;
enum QueueFrameResult { REJECTED, ACCEPTED_ACTIVE, ACCEPTED_PENDING };
+ using CommitPredicate =
+ base::RepeatingCallback<bool(const SurfaceId&, const BeginFrameId&)>;
+
Surface(const SurfaceInfo& surface_info,
SurfaceManager* surface_manager,
SurfaceAllocationGroup* allocation_group,
- base::WeakPtr<SurfaceClient> surface_client);
+ base::WeakPtr<SurfaceClient> surface_client,
+ size_t max_uncommitted_frames);
Surface(const Surface&) = delete;
Surface& operator=(const Surface&) = delete;
@@ -137,14 +157,19 @@ class VIZ_SERVICE_EXPORT Surface final {
void SetPreviousFrameSurface(Surface* surface);
- // Returns false if |frame| is invalid.
- // |frame_rejected_callback| will be called once if the frame will not be
- // displayed.
+ // Returns false if |frame| is invalid. |frame_rejected_callback| will be
+ // called once if the frame will not be displayed.
QueueFrameResult QueueFrame(
CompositorFrame frame,
uint64_t frame_index,
base::ScopedClosureRunner frame_rejected_callback);
+ // Commits frame(s) in this Surface and its dependencies. For each affected
+ // surface, the predicate will be called for each uncommitted frame in each
+ // surface from the oldest to the newest and will abort at first case of
+ // returning false.
+ void CommitFramesRecursively(const CommitPredicate& predicate);
+
// Notifies the Surface that a blocking SurfaceId now has an active
// frame.
void NotifySurfaceIdAvailable(const SurfaceId& surface_id);
@@ -286,6 +311,14 @@ class VIZ_SERVICE_EXPORT Surface final {
void DidAggregate();
+ // Returns frame id of the oldest uncommitted frame if any,
+ absl::optional<BeginFrameId> GetFirstUncommitedFrameId();
+
+ // Returns frame id of the oldest uncommitted frame that is newer than
+ // provided `frame_id`.
+ absl::optional<BeginFrameId> GetUncommitedFrameIdNewerThan(
+ const BeginFrameId& frame_id);
+
private:
struct FrameData {
FrameData(CompositorFrame&& frame, uint64_t frame_index);
@@ -299,6 +332,8 @@ class VIZ_SERVICE_EXPORT Surface final {
return std::move(frame.metadata.delegated_ink_metadata);
}
+ void SendAckIfNeeded(SurfaceClient* client);
+
CompositorFrame frame;
uint64_t frame_index;
// Whether the frame has been displayed or not.
@@ -337,6 +372,10 @@ class VIZ_SERVICE_EXPORT Surface final {
// Called when all of the surface's dependencies have been resolved.
void ActivateFrame(FrameData frame_data);
+ // Called when display compositor is ready for this frame to be processed and
+ // it can become pending or active.
+ QueueFrameResult CommitFrame(FrameData frame);
+
// Resolve the activation deadline specified by |current_frame| into a wall
// time to be used by SurfaceDependencyDeadline.
FrameDeadline ResolveFrameDeadline(const CompositorFrame& current_frame);
@@ -362,6 +401,10 @@ class VIZ_SERVICE_EXPORT Surface final {
absl::optional<FrameData> pending_frame_data_;
absl::optional<FrameData> active_frame_data_;
+
+ // Queue of uncommitted frames, oldest first.
+ base::circular_deque<FrameData> uncommitted_frames_;
+
absl::optional<CompositorFrame> interpolated_frame_;
bool seen_first_frame_activation_ = false;
bool seen_first_surface_embedding_ = false;
@@ -397,6 +440,8 @@ class VIZ_SERVICE_EXPORT Surface final {
bool has_damage_from_interpolated_frame_ = false;
+ const size_t max_uncommitted_frames_;
+
base::WeakPtrFactory<Surface> weak_factory_{this};
};
diff --git a/chromium/components/viz/service/surfaces/surface_allocation_group.h b/chromium/components/viz/service/surfaces/surface_allocation_group.h
index 29cc1418134..8a89cccff64 100644
--- a/chromium/components/viz/service/surfaces/surface_allocation_group.h
+++ b/chromium/components/viz/service/surfaces/surface_allocation_group.h
@@ -127,6 +127,8 @@ class VIZ_SERVICE_EXPORT SurfaceAllocationGroup {
return surfaces_.empty() ? nullptr : surfaces_.back();
}
+ const std::vector<Surface*>& surfaces() const { return surfaces_; }
+
private:
// Returns an iterator to the latest surface in |surfaces_| whose SurfaceId is
// older than or equal to |surface_id|. The returned surface may not be active
diff --git a/chromium/components/viz/service/surfaces/surface_client.h b/chromium/components/viz/service/surfaces/surface_client.h
index 19e303ca26f..37482e1a41d 100644
--- a/chromium/components/viz/service/surfaces/surface_client.h
+++ b/chromium/components/viz/service/surfaces/surface_client.h
@@ -40,6 +40,10 @@ class VIZ_SERVICE_EXPORT SurfaceClient {
virtual ~SurfaceClient() = default;
+ // Called when |surface| has committed a new CompositorFrame that become
+ // pending or active.
+ virtual void OnSurfaceCommitted(Surface* surface) = 0;
+
// Called when |surface| has a new CompositorFrame available for display.
virtual void OnSurfaceActivated(Surface* surface) = 0;
@@ -73,9 +77,9 @@ class VIZ_SERVICE_EXPORT SurfaceClient {
// Notifies the client that a frame with |token| has been activated.
virtual void OnFrameTokenChanged(uint32_t frame_token) = 0;
- // Notifies the client that the submitted CompositorFrame has been processed
- // (where processed may mean the frame has been displayed, or discarded).
- virtual void OnSurfaceProcessed(Surface* surface) = 0;
+ // Sends a compositor frame ack to the client. Usually happens when viz is
+ // ready to receive another frame without dropping previous one.
+ virtual void SendCompositorFrameAck() = 0;
// Notifies the client that a frame with |token| has been presented.
virtual void OnSurfacePresented(
diff --git a/chromium/components/viz/service/surfaces/surface_manager.cc b/chromium/components/viz/service/surfaces/surface_manager.cc
index 43a0037f5de..924fe2d7b13 100644
--- a/chromium/components/viz/service/surfaces/surface_manager.cc
+++ b/chromium/components/viz/service/surfaces/surface_manager.cc
@@ -38,12 +38,14 @@ constexpr base::TimeDelta kExpireInterval = base::Seconds(10);
SurfaceManager::SurfaceManager(
SurfaceManagerDelegate* delegate,
- absl::optional<uint32_t> activation_deadline_in_frames)
+ absl::optional<uint32_t> activation_deadline_in_frames,
+ size_t max_uncommitted_frames)
: delegate_(delegate),
activation_deadline_in_frames_(activation_deadline_in_frames),
root_surface_id_(FrameSinkId(0u, 0u),
LocalSurfaceId(1u, base::UnguessableToken::Create())),
- tick_clock_(base::DefaultTickClock::GetInstance()) {
+ tick_clock_(base::DefaultTickClock::GetInstance()),
+ max_uncommitted_frames_(max_uncommitted_frames) {
thread_checker_.DetachFromThread();
// Android WebView doesn't have a task runner and doesn't need the timer.
@@ -113,8 +115,9 @@ Surface* SurfaceManager::CreateSurface(
if (!allocation_group)
return nullptr;
- std::unique_ptr<Surface> surface = std::make_unique<Surface>(
- surface_info, this, allocation_group, surface_client);
+ std::unique_ptr<Surface> surface =
+ std::make_unique<Surface>(surface_info, this, allocation_group,
+ surface_client, max_uncommitted_frames_);
surface->SetDependencyDeadline(
std::make_unique<SurfaceDependencyDeadline>(tick_clock_));
surface_map_[surface_info.id()] = std::move(surface);
@@ -450,6 +453,11 @@ void SurfaceManager::FirstSurfaceActivation(const SurfaceInfo& surface_info) {
observer.OnFirstSurfaceActivation(surface_info);
}
+void SurfaceManager::OnSurfaceHasNewUncommittedFrame(Surface* surface) {
+ for (auto& observer : observer_list_)
+ observer.OnSurfaceHasNewUncommittedFrame(surface->surface_id());
+}
+
void SurfaceManager::SurfaceActivated(Surface* surface) {
// Trigger a display frame if necessary.
const CompositorFrameMetadata& metadata = surface->GetActiveFrameMetadata();
@@ -629,4 +637,33 @@ void SurfaceManager::AggregatedFrameSinksChanged() {
delegate_->AggregatedFrameSinksChanged();
}
+void SurfaceManager::CommitFramesInRangeRecursively(
+ const SurfaceRange& range,
+ const CommitPredicate& predicate) {
+ // Technically we need only latest active surface, but because activation will
+ // happen during commit, it's impossible to predict which one will be active,
+ // so we're committing all surfaces in range.
+
+ // If start of the range is in a different allocation group, process it first
+ // to keep activation in order.
+ if (range.start() && range.start()->local_surface_id().embed_token() !=
+ range.end().local_surface_id().embed_token()) {
+ if (auto* allocation_group =
+ GetAllocationGroupForSurfaceId(*range.start())) {
+ for (auto* surface : allocation_group->surfaces()) {
+ if (range.IsInRangeInclusive(surface->surface_id()))
+ surface->CommitFramesRecursively(predicate);
+ }
+ }
+ }
+
+ // Process the allocation group of the end of the range.
+ if (auto* allocation_group = GetAllocationGroupForSurfaceId(range.end())) {
+ for (auto* surface : allocation_group->surfaces()) {
+ if (range.IsInRangeInclusive(surface->surface_id()))
+ surface->CommitFramesRecursively(predicate);
+ }
+ }
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/surfaces/surface_manager.h b/chromium/components/viz/service/surfaces/surface_manager.h
index b20b20bb0a1..36ca45d07e9 100644
--- a/chromium/components/viz/service/surfaces/surface_manager.h
+++ b/chromium/components/viz/service/surfaces/surface_manager.h
@@ -44,11 +44,13 @@ class SurfaceManagerDelegate;
class SurfaceRange;
struct BeginFrameAck;
struct BeginFrameArgs;
+struct BeginFrameId;
class VIZ_SERVICE_EXPORT SurfaceManager {
public:
SurfaceManager(SurfaceManagerDelegate* delegate,
- absl::optional<uint32_t> activation_deadline_in_frames);
+ absl::optional<uint32_t> activation_deadline_in_frames,
+ size_t max_uncommitted_frames);
SurfaceManager(const SurfaceManager&) = delete;
SurfaceManager& operator=(const SurfaceManager&) = delete;
@@ -108,6 +110,9 @@ class VIZ_SERVICE_EXPORT SurfaceManager {
// Called when a surface has an active frame for the first time.
void FirstSurfaceActivation(const SurfaceInfo& surface_info);
+ // Called when there is new frame in uncommitted queue of the surface.
+ void OnSurfaceHasNewUncommittedFrame(Surface* surface);
+
// Called when a CompositorFrame within |surface| has activated.
void SurfaceActivated(Surface* surface);
@@ -200,6 +205,15 @@ class VIZ_SERVICE_EXPORT SurfaceManager {
// changed since the previous aggregation.
void AggregatedFrameSinksChanged();
+ using CommitPredicate =
+ base::RepeatingCallback<bool(const SurfaceId&, const BeginFrameId&)>;
+ // Commits all surfaces in range and their referenced surfaces. For each
+ // surface processed calls `predicate` for each uncommitted frame from oldest
+ // to newest. If predicate returns true, surface is committed. If not the
+ // surface processing stops and we go to the next surface.
+ void CommitFramesInRangeRecursively(const SurfaceRange& range,
+ const CommitPredicate& predicate);
+
private:
friend class CompositorFrameSinkSupportTest;
friend class FrameSinkManagerTest;
@@ -326,6 +340,10 @@ class VIZ_SERVICE_EXPORT SurfaceManager {
bool allocation_groups_need_garbage_collection_ = false;
+ // Maximum length of uncommitted queue, zero means all frames are committed
+ // automatically.
+ const size_t max_uncommitted_frames_;
+
base::WeakPtrFactory<SurfaceManager> weak_factory_{this};
};
diff --git a/chromium/components/viz/service/surfaces/surface_observer.h b/chromium/components/viz/service/surfaces/surface_observer.h
index 7bbb7b9c499..6bb23de3ad0 100644
--- a/chromium/components/viz/service/surfaces/surface_observer.h
+++ b/chromium/components/viz/service/surfaces/surface_observer.h
@@ -23,6 +23,9 @@ class VIZ_SERVICE_EXPORT SurfaceObserver {
// time.
virtual void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) {}
+ // Called when there is new frame in uncommitted queue of the surface.
+ virtual void OnSurfaceHasNewUncommittedFrame(const SurfaceId& surface_id) {}
+
// Called when a CompositorFrame within a surface corresponding to
// |surface_id| activates.
virtual void OnSurfaceActivated(const SurfaceId& surface_id) {}
diff --git a/chromium/components/viz/service/transitions/surface_animation_manager.cc b/chromium/components/viz/service/transitions/surface_animation_manager.cc
index 6877eacd5e4..53696dc22a2 100644
--- a/chromium/components/viz/service/transitions/surface_animation_manager.cc
+++ b/chromium/components/viz/service/transitions/surface_animation_manager.cc
@@ -182,8 +182,9 @@ void ReplaceSharedElementWithRenderPass(
auto* render_pass_quad =
target_render_pass
->CreateAndAppendDrawQuad<CompositorRenderPassDrawQuad>();
- gfx::RectF tex_coord_rect(
- gfx::SizeF(shared_element_content_pass->output_rect.size()));
+ gfx::RectF tex_coord_rect(gfx::SizeF(shared_element_quad.rect.size()));
+ tex_coord_rect.Offset(-shared_pass_output_rect.x(),
+ -shared_pass_output_rect.y());
render_pass_quad->SetNew(
/*shared_quad_state=*/copied_quad_state,
/*rect=*/shared_element_quad.rect,
@@ -322,9 +323,7 @@ class SurfaceAnimationManager::StorageWithSurface {
SurfaceAnimationManager::SurfaceAnimationManager(
SharedBitmapManager* shared_bitmap_manager)
- : animation_slowdown_factor_(
- switches::GetDocumentTransitionSlowDownFactor()),
- transferable_resource_tracker_(shared_bitmap_manager) {}
+ : transferable_resource_tracker_(shared_bitmap_manager) {}
SurfaceAnimationManager::~SurfaceAnimationManager() = default;
@@ -1069,10 +1068,8 @@ void SurfaceAnimationManager::CreateRootAnimationCurves(
: gfx::CubicBezierTimingFunction::EaseType::EASE_OUT);
// Create the transform curve.
- base::TimeDelta total_duration =
- ApplySlowdownFactor(save_directive_->root_config().duration);
- base::TimeDelta total_delay =
- ApplySlowdownFactor(save_directive_->root_config().delay);
+ base::TimeDelta total_duration = save_directive_->root_config().duration;
+ base::TimeDelta total_delay = save_directive_->root_config().delay;
// The transform animation runs for the entire duration of the root
// transition.
@@ -1131,14 +1128,14 @@ void SurfaceAnimationManager::CreateSharedElementCurves() {
const bool has_src_element = shared.has_value();
const auto& config = save_directive_->shared_elements()[i].config;
- const auto total_duration = ApplySlowdownFactor(config.duration);
- const auto total_delay = ApplySlowdownFactor(config.delay);
+ const auto total_duration = config.duration;
+ const auto total_delay = config.delay;
- const auto opacity_duration = ApplySlowdownFactor(
- total_duration * kSharedOpacityTransitionDurationScaleFactor);
- const auto opacity_delay = ApplySlowdownFactor(
+ const auto opacity_duration =
+ total_duration * kSharedOpacityTransitionDurationScaleFactor;
+ const auto opacity_delay =
total_delay +
- (total_duration * kSharedOpacityTransitionDelayScaleFactor));
+ (total_duration * kSharedOpacityTransitionDelayScaleFactor);
// The kSrcOpacity curve animates the screen space opacity applied to the
// blended content from src and dest elements. The value goes from the
@@ -1320,11 +1317,6 @@ SurfaceAnimationManager::GetSurfaceSavedFrameStorageForTesting() {
return &surface_saved_frame_storage_;
}
-base::TimeDelta SurfaceAnimationManager::ApplySlowdownFactor(
- base::TimeDelta original) const {
- return original * animation_slowdown_factor_;
-}
-
// RootAnimationState
SurfaceAnimationManager::RootAnimationState::RootAnimationState() = default;
SurfaceAnimationManager::RootAnimationState::RootAnimationState(
diff --git a/chromium/components/viz/service/transitions/surface_animation_manager.h b/chromium/components/viz/service/transitions/surface_animation_manager.h
index 03efd964403..03a96239c3c 100644
--- a/chromium/components/viz/service/transitions/surface_animation_manager.h
+++ b/chromium/components/viz/service/transitions/surface_animation_manager.h
@@ -159,8 +159,6 @@ class VIZ_SERVICE_EXPORT SurfaceAnimationManager {
// Returns true if we have a running animation for root or shared elements.
bool HasRunningAnimations() const;
- base::TimeDelta ApplySlowdownFactor(base::TimeDelta original) const;
-
// The state machine can take the following paths :
// 1) Viz driven animation : kIdle -> kAnimating -> kLastFrame -> kIdle
// 2) Renderer driven animation : kIdle -> kAnimatingRenderer -> kIdle
@@ -170,7 +168,6 @@ class VIZ_SERVICE_EXPORT SurfaceAnimationManager {
uint32_t last_processed_sequence_id_ = 0;
- const int animation_slowdown_factor_ = 1;
TransferableResourceTracker transferable_resource_tracker_;
absl::optional<TransferableResourceTracker::ResourceFrame> saved_textures_;
diff --git a/chromium/components/viz/test/BUILD.gn b/chromium/components/viz/test/BUILD.gn
index 147c6dfd364..ba5d6888d89 100644
--- a/chromium/components/viz/test/BUILD.gn
+++ b/chromium/components/viz/test/BUILD.gn
@@ -11,7 +11,6 @@ buildflag_header("buildflags") {
header = "buildflags.h"
flags = [
- "ENABLE_GL_RENDERER_TESTS=$enable_gl_renderer_tests",
"ENABLE_GL_BACKEND_TESTS=$enable_gl_backend_tests",
"ENABLE_VULKAN_BACKEND_TESTS=$enable_vulkan_backend_tests",
"ENABLE_DAWN_BACKEND_TESTS=$enable_dawn_backend_tests",
diff --git a/chromium/components/viz/viz.gni b/chromium/components/viz/viz.gni
index 8cf273608e3..2a5d9d72722 100644
--- a/chromium/components/viz/viz.gni
+++ b/chromium/components/viz/viz.gni
@@ -10,10 +10,6 @@ import("//testing/test.gni")
# that code path.
enable_gl_backend_tests = !is_fuchsia
-# Controls if GLRenderer related tests should be built and run.
-# TODO(crbug.com/1247756): Delete this flag along with GLRenderer.
-enable_gl_renderer_tests = false
-
# TODO(samans): Support more configurations.
# CFI issue: https://crbug.com/967819
# Fuchsia ARM64 https://crbug.com/1058247
@@ -72,8 +68,5 @@ template("viz_test") {
}
configs -= viz_remove_configs
configs += viz_add_configs
-
- # TODO(crbug.com/1292951): Remove this line.
- configs -= [ "//build/config/compiler:prevent_unsafe_narrowing" ]
}
}