summaryrefslogtreecommitdiff
path: root/chromium/components/viz
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-12 14:27:29 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-13 09:35:20 +0000
commitc30a6232df03e1efbd9f3b226777b07e087a1122 (patch)
treee992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/viz
parent7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff)
downloadqtwebengine-chromium-85-based.tar.gz
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/viz')
-rw-r--r--chromium/components/viz/client/client_resource_provider.cc4
-rw-r--r--chromium/components/viz/client/frame_eviction_manager.cc1
-rw-r--r--chromium/components/viz/common/BUILD.gn2
-rw-r--r--chromium/components/viz/common/DEPS4
-rw-r--r--chromium/components/viz/common/delegated_ink_metadata.h62
-rw-r--r--chromium/components/viz/common/features.cc12
-rw-r--r--chromium/components/viz/common/features.h3
-rw-r--r--chromium/components/viz/common/frame_sinks/begin_frame_source.h2
-rw-r--r--chromium/components/viz/common/frame_sinks/copy_output_request.cc28
-rw-r--r--chromium/components/viz/common/gl_scaler_test_util.cc1
-rw-r--r--chromium/components/viz/common/gpu/context_cache_controller_unittest.cc2
-rw-r--r--chromium/components/viz/common/gpu/context_lost_reason.h10
-rw-r--r--chromium/components/viz/common/gpu/metal_api_proxy.h3
-rw-r--r--chromium/components/viz/common/gpu/metal_context_provider.mm1
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc36
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h3
-rw-r--r--chromium/components/viz/common/quads/compositor_frame_metadata.cc28
-rw-r--r--chromium/components/viz/common/quads/compositor_frame_metadata.h14
-rw-r--r--chromium/components/viz/common/quads/draw_quad.cc4
-rw-r--r--chromium/components/viz/common/quads/draw_quad_unittest.cc1
-rw-r--r--chromium/components/viz/common/quads/render_pass.cc8
-rw-r--r--chromium/components/viz/common/resources/platform_color.h2
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.cc7
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.h5
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils_mac.mm40
-rw-r--r--chromium/components/viz/common/resources/resource_sizes.h2
-rw-r--r--chromium/components/viz/common/yuv_readback_unittest.cc15
-rw-r--r--chromium/components/viz/demo/demo_main.cc22
-rw-r--r--chromium/components/viz/host/BUILD.gn4
-rw-r--r--chromium/components/viz/host/gpu_host_impl.cc12
-rw-r--r--chromium/components/viz/host/gpu_host_impl.h2
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.cc6
-rw-r--r--chromium/components/viz/host/host_gpu_memory_buffer_manager.cc20
-rw-r--r--chromium/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc15
-rw-r--r--chromium/components/viz/host/renderer_settings_creation.cc23
-rw-r--r--chromium/components/viz/service/BUILD.gn29
-rw-r--r--chromium/components/viz/service/display/DEPS1
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.h7
-rw-r--r--chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc3
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.cc1
-rw-r--r--chromium/components/viz/service/display/direct_renderer.cc106
-rw-r--r--chromium/components/viz/service/display/direct_renderer.h5
-rw-r--r--chromium/components/viz/service/display/display.cc108
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.cc87
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.h21
-rw-r--r--chromium/components/viz/service/display/display_unittest.cc28
-rw-r--r--chromium/components/viz/service/display/gl_renderer.cc32
-rw-r--r--chromium/components/viz/service/display/gl_renderer.h5
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.cc26
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier_unittest.cc12
-rw-r--r--chromium/components/viz/service/display/gl_renderer_unittest.cc6
-rw-r--r--chromium/components/viz/service/display/output_surface.h12
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.cc6
-rw-r--r--chromium/components/viz/service/display/overlay_processor_interface.h4
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.cc6
-rw-r--r--chromium/components/viz/service/display/overlay_processor_mac.h1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_ozone.cc1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.cc4
-rw-r--r--chromium/components/viz/service/display/overlay_processor_stub.h1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.cc7
-rw-r--r--chromium/components/viz/service/display/overlay_processor_using_strategy.h1
-rw-r--r--chromium/components/viz/service/display/overlay_processor_win.cc6
-rw-r--r--chromium/components/viz/service/display/overlay_processor_win.h1
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc1
-rw-r--r--chromium/components/viz/service/display/program_binding.cc1
-rw-r--r--chromium/components/viz/service/display/program_binding.h2
-rw-r--r--chromium/components/viz/service/display/renderer_perftest.cc3
-rw-r--r--chromium/components/viz/service/display/shader.h1
-rw-r--r--chromium/components/viz/service/display/skia_readback_pixeltest.cc3
-rw-r--r--chromium/components/viz/service/display/skia_renderer.cc76
-rw-r--r--chromium/components/viz/service/display/software_renderer.cc5
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.cc494
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.h107
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_unittest.cc796
-rw-r--r--chromium/components/viz/service/display_embedder/buffer_queue.cc15
-rw-r--r--chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc5
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc10
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter.cc115
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter.h117
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc490
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h115
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_gl.cc408
-rw-r--r--chromium/components/viz/service/display_embedder/output_presenter_gl.h78
-rw-r--r--chromium/components/viz/service/display_embedder/output_surface_provider_impl.cc46
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device.cc80
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device.h31
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc519
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h73
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc22
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc28
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_dawn.h12
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_gl.cc33
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_gl.h9
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc77
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h12
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_webview.cc5
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_device_x11.cc29
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h4
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc108
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.h3
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc364
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h31
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_unittest.cc1
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc17
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc37
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h2
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc2
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc43
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc137
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc1
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.cc39
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.h9
-rw-r--r--chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc46
-rw-r--r--chromium/components/viz/service/gl/info_collection_gpu_service_impl.h19
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.cc3
-rw-r--r--chromium/components/viz/service/surfaces/surface_manager.h2
-rw-r--r--chromium/components/viz/service/surfaces/surface_unittest.cc10
-rw-r--r--chromium/components/viz/viz.gni2
119 files changed, 4094 insertions, 1537 deletions
diff --git a/chromium/components/viz/client/client_resource_provider.cc b/chromium/components/viz/client/client_resource_provider.cc
index 68fa8738572..ee2871b3f49 100644
--- a/chromium/components/viz/client/client_resource_provider.cc
+++ b/chromium/components/viz/client/client_resource_provider.cc
@@ -375,7 +375,7 @@ ClientResourceProvider::ScopedSkSurface::ScopedSkSurface(
SkSurfaceProps surface_props = ComputeSurfaceProps(can_use_lcd_text);
// This type is used only for gpu raster, which implies gpu compositing.
bool gpu_compositing = true;
- surface_ = SkSurface::MakeFromBackendTextureAsRenderTarget(
+ surface_ = SkSurface::MakeFromBackendTexture(
gr_context, backend_texture, kTopLeft_GrSurfaceOrigin, msaa_sample_count,
ResourceFormatToClosestSkColorType(gpu_compositing, format), color_space,
&surface_props);
@@ -383,7 +383,7 @@ ClientResourceProvider::ScopedSkSurface::ScopedSkSurface(
ClientResourceProvider::ScopedSkSurface::~ScopedSkSurface() {
if (surface_)
- surface_->flush();
+ surface_->flushAndSubmit();
}
SkSurfaceProps ClientResourceProvider::ScopedSkSurface::ComputeSurfaceProps(
diff --git a/chromium/components/viz/client/frame_eviction_manager.cc b/chromium/components/viz/client/frame_eviction_manager.cc
index 3a5c8cb684d..48056fdc038 100644
--- a/chromium/components/viz/client/frame_eviction_manager.cc
+++ b/chromium/components/viz/client/frame_eviction_manager.cc
@@ -103,6 +103,7 @@ size_t FrameEvictionManager::GetMaxNumberOfSavedFrames() const {
FrameEvictionManager::FrameEvictionManager()
: memory_pressure_listener_(new base::MemoryPressureListener(
+ FROM_HERE,
base::BindRepeating(&FrameEvictionManager::OnMemoryPressure,
base::Unretained(this)))) {
max_number_of_saved_frames_ =
diff --git a/chromium/components/viz/common/BUILD.gn b/chromium/components/viz/common/BUILD.gn
index e98ecb33505..926d753ad76 100644
--- a/chromium/components/viz/common/BUILD.gn
+++ b/chromium/components/viz/common/BUILD.gn
@@ -19,6 +19,7 @@ viz_component("resource_format_utils") {
sources = [
"resources/resource_format_utils.cc",
"resources/resource_format_utils.h",
+ "resources/resource_format_utils_mac.mm",
"resources/resource_sizes.h",
"viz_resource_format_export.h",
]
@@ -141,6 +142,7 @@ viz_component("common") {
sources = [
"constants.cc",
"constants.h",
+ "delegated_ink_metadata.h",
"display/de_jelly.cc",
"display/de_jelly.h",
"display/overlay_strategy.cc",
diff --git a/chromium/components/viz/common/DEPS b/chromium/components/viz/common/DEPS
index 71bb14cbcb1..f40bbfd2a81 100644
--- a/chromium/components/viz/common/DEPS
+++ b/chromium/components/viz/common/DEPS
@@ -7,12 +7,12 @@ include_rules = [
# Exception is struct_traits.h which is used for defining friends only.
"+mojo/public/cpp/bindings/struct_traits.h",
"+third_party/perfetto/protos/perfetto/trace/track_event",
+ "+third_party/skia",
]
specific_include_rules = {
"skia_helper.(cc|h)": [
"+cc/base",
- "+third_party/skia",
],
# DEPS for GLHelper and friends which are in the root common/ directory.
"(yuv_readback|gl_helper|gl_scaler).*\.(cc|h)": [
@@ -21,7 +21,6 @@ specific_include_rules = {
"+gpu/command_buffer/common",
"+gpu/command_buffer/service",
"+gpu/ipc/common",
- "+third_party/skia",
],
".*(_unittest|_pixeltest|test_util)\.cc": [
"+cc/test",
@@ -29,7 +28,6 @@ specific_include_rules = {
"+gpu/ipc/gl_in_process_context.h",
"+gpu/ipc/test_gpu_thread_holder.h",
"+media/base",
- "+third_party/skia/include/core",
"+ui/gl",
],
".*_benchmark\.cc": [
diff --git a/chromium/components/viz/common/delegated_ink_metadata.h b/chromium/components/viz/common/delegated_ink_metadata.h
new file mode 100644
index 00000000000..3f0584444f0
--- /dev/null
+++ b/chromium/components/viz/common/delegated_ink_metadata.h
@@ -0,0 +1,62 @@
+// Copyright 2020 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_DELEGATED_INK_METADATA_H_
+#define COMPONENTS_VIZ_COMMON_DELEGATED_INK_METADATA_H_
+
+#include "base/time/time.h"
+#include "components/viz/common/viz_common_export.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace viz {
+
+// This class stores all the metadata that is gathered when the WebAPI
+// updateInkTrailStartPoint is called. This metadata flows from blink,
+// through cc, and into viz in order to produce a delegated ink trail on the
+// end of what was already rendered.
+//
+// Explainer for the feature:
+// https://github.com/WICG/ink-enhancement/blob/master/README.md
+class VIZ_COMMON_EXPORT DelegatedInkMetadata {
+ public:
+ DelegatedInkMetadata() = default;
+ DelegatedInkMetadata(const gfx::PointF& pt,
+ double diameter,
+ SkColor color,
+ base::TimeTicks timestamp,
+ const gfx::RectF& area)
+ : point_(pt),
+ diameter_(diameter),
+ color_(color),
+ timestamp_(timestamp),
+ presentation_area_(area) {}
+ DelegatedInkMetadata(const DelegatedInkMetadata& other) = default;
+
+ const gfx::PointF& point() const { return point_; }
+ double diameter() const { return diameter_; }
+ SkColor color() const { return color_; }
+ base::TimeTicks timestamp() const { return timestamp_; }
+ const gfx::RectF& presentation_area() const { return presentation_area_; }
+
+ private:
+ // Location of the pointerevent relative to the root frame.
+ gfx::PointF point_;
+
+ // Width of the trail, in physical pixels.
+ double diameter_ = 0;
+
+ // Color to draw the ink trail.
+ SkColor color_ = 0;
+
+ // Timestamp from the pointerevent for the ink point.
+ base::TimeTicks timestamp_;
+
+ // The rect to clip the ink trail to, defaults to the containing viewport.
+ gfx::RectF presentation_area_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_DELEGATED_INK_METADATA_H_
diff --git a/chromium/components/viz/common/features.cc b/chromium/components/viz/common/features.cc
index 23722815a87..ba807b6597c 100644
--- a/chromium/components/viz/common/features.cc
+++ b/chromium/components/viz/common/features.cc
@@ -53,18 +53,24 @@ const base::Feature kVizForWebView{"VizForWebView",
const base::Feature kVizFrameSubmissionForWebView{
"VizFrameSubmissionForWebView", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kUsePreferredIntervalForVideo{
+ "UsePreferredIntervalForVideo", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Whether we should use the real buffers corresponding to overlay candidates in
// order to do a pageflip test rather than allocating test buffers.
const base::Feature kUseRealBuffersForPageFlipTest{
"UseRealBuffersForPageFlipTest", base::FEATURE_DISABLED_BY_DEFAULT};
+#if defined(OS_FUCHSIA)
+// Enables SkiaOutputDeviceBufferQueue instead of Vulkan swapchain on Fuchsia.
+const base::Feature kUseSkiaOutputDeviceBufferQueue{
+ "UseSkiaOutputDeviceBufferQueue", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
// Whether we should split partially occluded quads to reduce overdraw.
const base::Feature kSplitPartiallyOccludedQuads{
"SplitPartiallyOccludedQuads", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kUsePreferredIntervalForVideo{
- "UsePreferredIntervalForVideo", base::FEATURE_DISABLED_BY_DEFAULT};
-
// Whether we should log extra debug information to webrtc native log.
const base::Feature kWebRtcLogCapturePipeline{
"WebRtcLogCapturePipeline", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/viz/common/features.h b/chromium/components/viz/common/features.h
index 2a42f537bfd..1b077aa7ab7 100644
--- a/chromium/components/viz/common/features.h
+++ b/chromium/components/viz/common/features.h
@@ -24,6 +24,9 @@ VIZ_COMMON_EXPORT extern const base::Feature kVizForWebView;
VIZ_COMMON_EXPORT extern const base::Feature kVizFrameSubmissionForWebView;
VIZ_COMMON_EXPORT extern const base::Feature kUsePreferredIntervalForVideo;
VIZ_COMMON_EXPORT extern const base::Feature kUseRealBuffersForPageFlipTest;
+#if defined(OS_FUCHSIA)
+VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaOutputDeviceBufferQueue;
+#endif
VIZ_COMMON_EXPORT extern const base::Feature kSplitPartiallyOccludedQuads;
VIZ_COMMON_EXPORT extern const base::Feature kWebRtcLogCapturePipeline;
diff --git a/chromium/components/viz/common/frame_sinks/begin_frame_source.h b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
index 8be3ad72924..2ca5c252021 100644
--- a/chromium/components/viz/common/frame_sinks/begin_frame_source.h
+++ b/chromium/components/viz/common/frame_sinks/begin_frame_source.h
@@ -10,8 +10,8 @@
#include <string>
+#include "base/check.h"
#include "base/containers/flat_set.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
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 1a10284b8af..ef836fb3a44 100644
--- a/chromium/components/viz/common/frame_sinks/copy_output_request.cc
+++ b/chromium/components/viz/common/frame_sinks/copy_output_request.cc
@@ -6,6 +6,8 @@
#include "base/bind.h"
#include "base/check_op.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -53,20 +55,24 @@ void CopyOutputRequest::SetUniformScaleRatio(int scale_from, int scale_to) {
}
void CopyOutputRequest::SendResult(std::unique_ptr<CopyOutputResult> result) {
- TRACE_EVENT_NESTABLE_ASYNC_END1("viz", "CopyOutputRequest", this, "success",
- !result->IsEmpty());
- if (result_task_runner_) {
- result_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(result_callback_), std::move(result)));
- result_task_runner_ = nullptr;
- } else {
- std::move(result_callback_).Run(std::move(result));
- }
+ TRACE_EVENT_NESTABLE_ASYNC_END2(
+ "viz", "CopyOutputRequest", this, "success", !result->IsEmpty(),
+ "has_provided_task_runner", !!result_task_runner_);
+ // Serializing the result requires an expensive copy, so to not block the
+ // any important thread we PostTask onto the threadpool by default, but if the
+ // user has provided a task runner use that instead.
+ auto runner =
+ result_task_runner_
+ ? result_task_runner_
+ : base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()});
+ runner->PostTask(FROM_HERE, base::BindOnce(std::move(result_callback_),
+ std::move(result)));
+ // Remove the reference to the task runner (no-op if we didn't have one).
+ result_task_runner_ = nullptr;
}
bool CopyOutputRequest::SendsResultsInCurrentSequence() const {
- return !result_task_runner_ ||
+ return result_task_runner_ &&
result_task_runner_->RunsTasksInCurrentSequence();
}
diff --git a/chromium/components/viz/common/gl_scaler_test_util.cc b/chromium/components/viz/common/gl_scaler_test_util.cc
index 62560e8755a..9a1754e7492 100644
--- a/chromium/components/viz/common/gl_scaler_test_util.cc
+++ b/chromium/components/viz/common/gl_scaler_test_util.cc
@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/notreached.h"
#include "base/path_service.h"
#include "cc/test/pixel_test_utils.h"
#include "components/viz/test/paths.h"
diff --git a/chromium/components/viz/common/gpu/context_cache_controller_unittest.cc b/chromium/components/viz/common/gpu/context_cache_controller_unittest.cc
index c380ea621e7..03696829f15 100644
--- a/chromium/components/viz/common/gpu/context_cache_controller_unittest.cc
+++ b/chromium/components/viz/common/gpu/context_cache_controller_unittest.cc
@@ -177,7 +177,7 @@ TEST(ContextCacheControllerTest, CheckSkiaResourcePurgeAPI) {
SkPixmap pixmap(image_info, image_data.data(), image_info.minRowBytes());
auto image = SkImage::MakeRasterCopy(pixmap);
auto image_gpu = image->makeTextureImage(gr_context);
- gr_context->flush();
+ gr_context->flushAndSubmit();
}
// Ensure we see size taken up for the image (now released, but cached for
diff --git a/chromium/components/viz/common/gpu/context_lost_reason.h b/chromium/components/viz/common/gpu/context_lost_reason.h
index 823b5c5b822..9a4ea393e59 100644
--- a/chromium/components/viz/common/gpu/context_lost_reason.h
+++ b/chromium/components/viz/common/gpu/context_lost_reason.h
@@ -26,12 +26,14 @@ enum ContextLostReason {
CONTEXT_LOST_OUT_OF_MEMORY = 10,
CONTEXT_LOST_MAKECURRENT_FAILED = 11,
CONTEXT_LOST_INVALID_GPU_MESSAGE = 12,
-
// SkiaRenderer marked context as lost because of failed Reshape call
CONTEXT_LOST_RESHAPE_FAILED = 13,
- // Update kMaxValue and //tools/metrics/histograms/histograms.xml when adding
- // new values.
- kMaxValue = CONTEXT_LOST_RESHAPE_FAILED
+ CONTEXT_LOST_SET_DRAW_RECTANGLE_FAILED = 14,
+ CONTEXT_LOST_DIRECT_COMPOSITION_OVERLAY_FAILED = 15,
+ CONTEXT_LOST_SWAP_FAILED = 16,
+ // Update kMaxValue here and <enum name="ContextLostReason"> in
+ // tools/metrics/histograms/enum.xml when adding new values.
+ kMaxValue = CONTEXT_LOST_SWAP_FAILED
};
VIZ_COMMON_EXPORT ContextLostReason
diff --git a/chromium/components/viz/common/gpu/metal_api_proxy.h b/chromium/components/viz/common/gpu/metal_api_proxy.h
index 39c1a1a2a03..c32a55c3ea1 100644
--- a/chromium/components/viz/common/gpu/metal_api_proxy.h
+++ b/chromium/components/viz/common/gpu/metal_api_proxy.h
@@ -5,6 +5,9 @@
#ifndef COMPONENTS_VIZ_COMMON_GPU_METAL_API_PROXY_H_
#define COMPONENTS_VIZ_COMMON_GPU_METAL_API_PROXY_H_
+#include <memory>
+#include <string>
+
#import <Metal/Metal.h>
#include <os/availability.h>
diff --git a/chromium/components/viz/common/gpu/metal_context_provider.mm b/chromium/components/viz/common/gpu/metal_context_provider.mm
index f3d7e1d49f9..40e0c5c2390 100644
--- a/chromium/components/viz/common/gpu/metal_context_provider.mm
+++ b/chromium/components/viz/common/gpu/metal_context_provider.mm
@@ -7,6 +7,7 @@
#import <Metal/Metal.h>
#include "base/bind.h"
+#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_macros.h"
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
index 204fea1b374..4d098c579d1 100644
--- a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -4,6 +4,8 @@
#include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
#include "gpu/vulkan/buildflags.h"
#include "gpu/vulkan/init/gr_vk_memory_allocator_impl.h"
#include "gpu/vulkan/vulkan_device_queue.h"
@@ -12,9 +14,30 @@
#include "gpu/vulkan/vulkan_implementation.h"
#include "gpu/vulkan/vulkan_instance.h"
#include "gpu/vulkan/vulkan_util.h"
+#include "third_party/skia/include/core/SkExecutor.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/vk/GrVkExtensions.h"
+namespace {
+
+class VizExecutor : public SkExecutor {
+ public:
+ VizExecutor() = default;
+ ~VizExecutor() override = default;
+ VizExecutor(const VizExecutor&) = delete;
+ VizExecutor& operator=(const VizExecutor&) = delete;
+
+ // std::function is used by SkExecutor in //third_party/skia. nocheck
+ using Fn = std::function<void(void)>; // nocheck
+ // SkExecutor:
+ void add(Fn task) override {
+ base::ThreadPool::PostTask(
+ FROM_HERE, base::BindOnce([](Fn task) { task(); }, std::move(task)));
+ }
+};
+
+} // namespace
+
namespace viz {
// static
@@ -102,7 +125,16 @@ bool VulkanInProcessContextProvider::Initialize(
vulkan_implementation_->enforce_protected_memory() ? GrProtected::kYes
: GrProtected::kNo;
- gr_context_ = GrContext::MakeVulkan(backend_context, context_options);
+ GrContextOptions options;
+ if (base::ThreadPoolInstance::Get()) {
+ // For some tests, ThreadPoolInstance is not initialized. VizExecutor will
+ // not be used for this case.
+ // TODO(penghuang): Make sure ThreadPoolInstance is initialized for related
+ // tests.
+ executor_ = std::make_unique<VizExecutor>();
+ options.fExecutor = executor_.get();
+ }
+ gr_context_ = GrContext::MakeVulkan(backend_context, options);
return gr_context_ != nullptr;
}
@@ -122,6 +154,8 @@ void VulkanInProcessContextProvider::Destroy() {
gr_context_.reset();
}
+ executor_.reset();
+
if (device_queue_) {
device_queue_->Destroy();
device_queue_.reset();
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
index 1215dff230d..05ea0a5c815 100644
--- a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
@@ -16,6 +16,8 @@
#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
#endif
+class SkExecutor;
+
namespace gpu {
class VulkanImplementation;
class VulkanDeviceQueue;
@@ -53,6 +55,7 @@ class VIZ_VULKAN_CONTEXT_PROVIDER_EXPORT VulkanInProcessContextProvider
#if BUILDFLAG(ENABLE_VULKAN)
sk_sp<GrContext> gr_context_;
+ std::unique_ptr<SkExecutor> executor_;
gpu::VulkanImplementation* vulkan_implementation_;
std::unique_ptr<gpu::VulkanDeviceQueue> device_queue_;
#endif
diff --git a/chromium/components/viz/common/quads/compositor_frame_metadata.cc b/chromium/components/viz/common/quads/compositor_frame_metadata.cc
index 96c246eeb84..c9709eae9de 100644
--- a/chromium/components/viz/common/quads/compositor_frame_metadata.cc
+++ b/chromium/components/viz/common/quads/compositor_frame_metadata.cc
@@ -22,6 +22,32 @@ CompositorFrameMetadata CompositorFrameMetadata::Clone() const {
}
CompositorFrameMetadata::CompositorFrameMetadata(
- const CompositorFrameMetadata& other) = default;
+ const CompositorFrameMetadata& other)
+ : device_scale_factor(other.device_scale_factor),
+ root_scroll_offset(other.root_scroll_offset),
+ page_scale_factor(other.page_scale_factor),
+ scrollable_viewport_size(other.scrollable_viewport_size),
+ content_color_usage(other.content_color_usage),
+ may_contain_video(other.may_contain_video),
+ is_resourceless_software_draw_with_scroll_or_animation(
+ other.is_resourceless_software_draw_with_scroll_or_animation),
+ root_background_color(other.root_background_color),
+ latency_info(other.latency_info),
+ referenced_surfaces(other.referenced_surfaces),
+ activation_dependencies(other.activation_dependencies),
+ deadline(other.deadline),
+ begin_frame_ack(other.begin_frame_ack),
+ frame_token(other.frame_token),
+ send_frame_token_to_embedder(other.send_frame_token_to_embedder),
+ min_page_scale_factor(other.min_page_scale_factor),
+ top_controls_visible_height(other.top_controls_visible_height),
+ local_surface_id_allocation_time(other.local_surface_id_allocation_time),
+ preferred_frame_interval(other.preferred_frame_interval),
+ display_transform_hint(other.display_transform_hint) {
+ if (other.delegated_ink_metadata) {
+ delegated_ink_metadata = std::make_unique<DelegatedInkMetadata>(
+ *other.delegated_ink_metadata.get());
+ }
+}
} // namespace viz
diff --git a/chromium/components/viz/common/quads/compositor_frame_metadata.h b/chromium/components/viz/common/quads/compositor_frame_metadata.h
index de4513fe572..06b680d5de5 100644
--- a/chromium/components/viz/common/quads/compositor_frame_metadata.h
+++ b/chromium/components/viz/common/quads/compositor_frame_metadata.h
@@ -11,6 +11,7 @@
#include "base/optional.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "components/viz/common/delegated_ink_metadata.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/quads/frame_deadline.h"
#include "components/viz/common/surfaces/surface_id.h"
@@ -152,6 +153,19 @@ class VIZ_COMMON_EXPORT CompositorFrameMetadata {
// applicable to frames of the root surface.
gfx::OverlayTransform display_transform_hint = gfx::OVERLAY_TRANSFORM_NONE;
+ // Contains the metadata required for drawing a delegated ink trail onto the
+ // end of a rendered ink stroke. This should only be present when two
+ // conditions are met:
+ // 1. The JS API |updateInkTrailStartPoint| is used - This gathers the
+ // metadata and puts it onto a compositor frame to be sent to viz.
+ // 2. This frame will not be submitted to the root surface - The browser UI
+ // does not use this, and the frame must be contained within a
+ // SurfaceDrawQuad.
+ // The ink trail created with this metadata will only last for a single frame
+ // before it disappears, regardless of whether or not the next frame contains
+ // delegated ink metadata.
+ std::unique_ptr<DelegatedInkMetadata> delegated_ink_metadata;
+
private:
CompositorFrameMetadata(const CompositorFrameMetadata& other);
CompositorFrameMetadata operator=(const CompositorFrameMetadata&) = delete;
diff --git a/chromium/components/viz/common/quads/draw_quad.cc b/chromium/components/viz/common/quads/draw_quad.cc
index a0b0255820d..7de9198ef27 100644
--- a/chromium/components/viz/common/quads/draw_quad.cc
+++ b/chromium/components/viz/common/quads/draw_quad.cc
@@ -27,7 +27,9 @@ void DrawQuad::SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
bool needs_blending) {
- DCHECK(rect.Contains(visible_rect))
+ // TODO(boliu): Temporarily making this a release check to catch
+ // crbug.com/1072407.
+ CHECK(rect.Contains(visible_rect))
<< "rect: " << rect.ToString()
<< " visible_rect: " << visible_rect.ToString();
diff --git a/chromium/components/viz/common/quads/draw_quad_unittest.cc b/chromium/components/viz/common/quads/draw_quad_unittest.cc
index 32e4828180d..4ddc34dde7d 100644
--- a/chromium/components/viz/common/quads/draw_quad_unittest.cc
+++ b/chromium/components/viz/common/quads/draw_quad_unittest.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/logging.h"
#include "base/unguessable_token.h"
#include "cc/base/math_util.h"
#include "cc/paint/filter_operations.h"
diff --git a/chromium/components/viz/common/quads/render_pass.cc b/chromium/components/viz/common/quads/render_pass.cc
index 2e08e454b64..9ff21584a2f 100644
--- a/chromium/components/viz/common/quads/render_pass.cc
+++ b/chromium/components/viz/common/quads/render_pass.cc
@@ -229,7 +229,9 @@ void RenderPass::SetNew(uint64_t id,
const gfx::Rect& output_rect,
const gfx::Rect& damage_rect,
const gfx::Transform& transform_to_root_target) {
- DCHECK(id);
+ // TODO(boliu): Temporarily making this a release check to catch
+ // crbug.com/1072407.
+ CHECK(id);
DCHECK(damage_rect.IsEmpty() || output_rect.Contains(damage_rect))
<< "damage_rect: " << damage_rect.ToString()
<< " output_rect: " << output_rect.ToString();
@@ -256,7 +258,9 @@ void RenderPass::SetAll(
bool cache_render_pass,
bool has_damage_from_contributing_content,
bool generate_mipmap) {
- DCHECK(id);
+ // TODO(boliu): Temporarily making this a release check to catch
+ // crbug.com/1072407.
+ CHECK(id);
this->id = id;
this->output_rect = output_rect;
diff --git a/chromium/components/viz/common/resources/platform_color.h b/chromium/components/viz/common/resources/platform_color.h
index 6e8790d0a06..3d573570d8c 100644
--- a/chromium/components/viz/common/resources/platform_color.h
+++ b/chromium/components/viz/common/resources/platform_color.h
@@ -5,8 +5,8 @@
#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_PLATFORM_COLOR_H_
#define COMPONENTS_VIZ_COMMON_RESOURCES_PLATFORM_COLOR_H_
-#include "base/logging.h"
#include "base/macros.h"
+#include "base/notreached.h"
#include "components/viz/common/resources/resource_format.h"
#include "gpu/command_buffer/common/capabilities.h"
#include "third_party/skia/include/core/SkTypes.h"
diff --git a/chromium/components/viz/common/resources/resource_format_utils.cc b/chromium/components/viz/common/resources/resource_format_utils.cc
index ea1ae8de815..2bfdfd5d2e4 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.cc
+++ b/chromium/components/viz/common/resources/resource_format_utils.cc
@@ -4,6 +4,8 @@
#include "components/viz/common/resources/resource_format_utils.h"
+#include <ostream>
+
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/stl_util.h"
@@ -324,10 +326,11 @@ unsigned int TextureStorageFormat(ResourceFormat format) {
case RGBA_1010102:
case BGRA_1010102:
return GL_RGB10_A2_EXT;
- case BGR_565:
- case BGRX_8888:
case YVU_420:
case YUV_420_BIPLANAR:
+ return GL_RGB8_OES;
+ case BGR_565:
+ case BGRX_8888:
case P010:
break;
}
diff --git a/chromium/components/viz/common/resources/resource_format_utils.h b/chromium/components/viz/common/resources/resource_format_utils.h
index ca10863b695..ce691952e0a 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.h
+++ b/chromium/components/viz/common/resources/resource_format_utils.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
+#include "build/build_config.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/viz_resource_format_export.h"
#include "gpu/vulkan/buildflags.h"
@@ -73,6 +74,10 @@ VIZ_RESOURCE_FORMAT_EXPORT wgpu::TextureFormat ToDawnFormat(
VIZ_RESOURCE_FORMAT_EXPORT WGPUTextureFormat
ToWGPUFormat(ResourceFormat format);
+#if defined(OS_MACOSX)
+VIZ_RESOURCE_FORMAT_EXPORT unsigned int ToMTLPixelFormat(ResourceFormat format);
+#endif
+
} // namespace viz
#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_FORMAT_UTILS_H_
diff --git a/chromium/components/viz/common/resources/resource_format_utils_mac.mm b/chromium/components/viz/common/resources/resource_format_utils_mac.mm
new file mode 100644
index 00000000000..5a095e7f30d
--- /dev/null
+++ b/chromium/components/viz/common/resources/resource_format_utils_mac.mm
@@ -0,0 +1,40 @@
+// Copyright 2020 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/resources/resource_format_utils.h"
+
+#include <Metal/MTLPixelFormat.h>
+
+#include "base/logging.h"
+
+namespace viz {
+
+unsigned int ToMTLPixelFormat(ResourceFormat format) {
+ if (@available(macOS 10.11, *)) {
+ MTLPixelFormat mtl_pixel_format = MTLPixelFormatInvalid;
+ switch (format) {
+ case RED_8:
+ case ALPHA_8:
+ case LUMINANCE_8:
+ mtl_pixel_format = MTLPixelFormatR8Unorm;
+ break;
+ case RG_88:
+ mtl_pixel_format = MTLPixelFormatRG8Unorm;
+ break;
+ case RGBA_8888:
+ mtl_pixel_format = MTLPixelFormatRGBA8Unorm;
+ break;
+ case BGRA_8888:
+ mtl_pixel_format = MTLPixelFormatBGRA8Unorm;
+ break;
+ default:
+ DLOG(ERROR) << "Invalid Metal pixel format.";
+ break;
+ }
+ return static_cast<unsigned int>(mtl_pixel_format);
+ }
+ return 0;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/resources/resource_sizes.h b/chromium/components/viz/common/resources/resource_sizes.h
index 9c4d9eee7b7..f2745793207 100644
--- a/chromium/components/viz/common/resources/resource_sizes.h
+++ b/chromium/components/viz/common/resources/resource_sizes.h
@@ -9,7 +9,7 @@
#include <limits>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/macros.h"
#include "base/numerics/safe_math.h"
#include "cc/base/math_util.h"
diff --git a/chromium/components/viz/common/yuv_readback_unittest.cc b/chromium/components/viz/common/yuv_readback_unittest.cc
index ab37ff6fd71..c1d7f1be9eb 100644
--- a/chromium/components/viz/common/yuv_readback_unittest.cc
+++ b/chromium/components/viz/common/yuv_readback_unittest.cc
@@ -102,16 +102,15 @@ class YUVReadbackTest : public testing::Test {
run_loop.Run();
json_data.append("]");
- std::string error_msg;
- std::unique_ptr<base::Value> trace_data =
- base::JSONReader::ReadAndReturnErrorDeprecated(json_data, 0, nullptr,
- &error_msg);
- CHECK(trace_data) << "JSON parsing failed (" << error_msg
- << ") JSON data:" << std::endl
- << json_data;
+ base::JSONReader::ValueWithError parsed_json =
+ base::JSONReader::ReadAndReturnValueWithError(json_data);
+ CHECK(parsed_json.value)
+ << "JSON parsing failed (" << parsed_json.error_message
+ << ") JSON data:" << std::endl
+ << json_data;
base::ListValue* list;
- CHECK(trace_data->GetAsList(&list));
+ CHECK(parsed_json.value->GetAsList(&list));
for (size_t i = 0; i < list->GetSize(); i++) {
base::Value* item = nullptr;
if (list->Get(i, &item)) {
diff --git a/chromium/components/viz/demo/demo_main.cc b/chromium/components/viz/demo/demo_main.cc
index f470f6c7d47..6de8e394c3d 100644
--- a/chromium/components/viz/demo/demo_main.cc
+++ b/chromium/components/viz/demo/demo_main.cc
@@ -20,6 +20,7 @@
#include "mojo/core/embedder/scoped_ipc_support.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "ui/base/ui_base_features.h"
#include "ui/events/platform/platform_event_source.h"
#include "ui/platform_window/platform_window.h"
#include "ui/platform_window/platform_window_delegate.h"
@@ -30,7 +31,6 @@
#endif
#if defined(OS_WIN)
-#include "ui/base/cursor/cursor_loader_win.h"
#include "ui/platform_window/win/win_window.h"
#endif
@@ -85,7 +85,8 @@ class InitUI {
public:
InitUI() {
#if defined(USE_X11)
- XInitThreads();
+ if (!features::IsUsingOzonePlatform())
+ XInitThreads();
#endif
event_source_ = ui::PlatformEventSource::CreateDefault();
}
@@ -117,15 +118,22 @@ class DemoWindow : public ui::PlatformWindowDelegate {
std::unique_ptr<ui::PlatformWindow> CreatePlatformWindow(
const gfx::Rect& bounds) {
ui::PlatformWindowInitProperties props(bounds);
+#if defined(USE_X11) || defined(USE_OZONE)
#if defined(USE_OZONE)
- return ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
- this, std::move(props));
-#elif defined(OS_WIN)
- return std::make_unique<ui::WinWindow>(this, props.bounds);
-#elif defined(USE_X11)
+ if (features::IsUsingOzonePlatform()) {
+ return ui::OzonePlatform::GetInstance()->CreatePlatformWindow(
+ this, std::move(props));
+ }
+#endif
+#if defined(USE_X11)
auto x11_window = std::make_unique<ui::X11Window>(this);
x11_window->Initialize(std::move(props));
return x11_window;
+#endif
+ NOTREACHED();
+ return nullptr;
+#elif defined(OS_WIN)
+ return std::make_unique<ui::WinWindow>(this, props.bounds);
#else
NOTIMPLEMENTED();
return nullptr;
diff --git a/chromium/components/viz/host/BUILD.gn b/chromium/components/viz/host/BUILD.gn
index 8bf87caba72..09fff133014 100644
--- a/chromium/components/viz/host/BUILD.gn
+++ b/chromium/components/viz/host/BUILD.gn
@@ -95,6 +95,10 @@ viz_source_set("unit_tests") {
if (use_ozone) {
deps += [ "//ui/ozone" ]
}
+
+ if (use_x11 || use_ozone) {
+ deps += [ "//ui/base:features" ]
+ }
}
fuzzer_test("hit_test_query_fuzzer") {
diff --git a/chromium/components/viz/host/gpu_host_impl.cc b/chromium/components/viz/host/gpu_host_impl.cc
index 414ba48b659..c3d6c9a3fd0 100644
--- a/chromium/components/viz/host/gpu_host_impl.cc
+++ b/chromium/components/viz/host/gpu_host_impl.cc
@@ -36,6 +36,10 @@
#include "ui/gfx/win/rendering_window_manager.h"
#endif
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"
+#endif
+
namespace viz {
namespace {
@@ -125,7 +129,8 @@ GpuHostImpl::GpuHostImpl(Delegate* delegate,
GetFontRenderParams().Get()->subpixel_rendering);
#if defined(USE_OZONE)
- InitOzone();
+ if (features::IsUsingOzonePlatform())
+ InitOzone();
#endif // defined(USE_OZONE)
}
@@ -294,6 +299,7 @@ mojom::InfoCollectionGpuService* GpuHostImpl::info_collection_gpu_service() {
#if defined(USE_OZONE)
void GpuHostImpl::InitOzone() {
+ DCHECK(features::IsUsingOzonePlatform());
// Ozone needs to send the primary DRM device to GPU service as early as
// possible to ensure the latter always has a valid device.
// https://crbug.com/608839
@@ -512,6 +518,10 @@ void GpuHostImpl::DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) {
delegate_->DidUpdateOverlayInfo(overlay_info);
}
+void GpuHostImpl::DidUpdateHDRStatus(bool hdr_enabled) {
+ delegate_->DidUpdateHDRStatus(hdr_enabled);
+}
+
void GpuHostImpl::SetChildSurface(gpu::SurfaceHandle parent,
gpu::SurfaceHandle child) {
if (pid_ != base::kNullProcessId) {
diff --git a/chromium/components/viz/host/gpu_host_impl.h b/chromium/components/viz/host/gpu_host_impl.h
index 6481e8f0ed5..640814e68d0 100644
--- a/chromium/components/viz/host/gpu_host_impl.h
+++ b/chromium/components/viz/host/gpu_host_impl.h
@@ -73,6 +73,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
virtual void MaybeShutdownGpuProcess() = 0;
#if defined(OS_WIN)
virtual void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) = 0;
+ virtual void DidUpdateHDRStatus(bool hdr_enabled) = 0;
#endif
virtual void BlockDomainFrom3DAPIs(const GURL& url,
gpu::DomainGuilt guilt) = 0;
@@ -231,6 +232,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
void DisableGpuCompositing() override;
#if defined(OS_WIN)
void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
+ void DidUpdateHDRStatus(bool hdr_enabled) 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 54cd565e50a..9ca5eba8860 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query.cc
+++ b/chromium/components/viz/host/hit_test/hit_test_query.cc
@@ -4,6 +4,8 @@
#include "components/viz/host/hit_test/hit_test_query.h"
+#include <sstream>
+
#include "base/containers/stack.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
@@ -224,8 +226,8 @@ bool HitTestQuery::FindTargetInRegionForLocation(
// hit test data, e.g. overlapped by ShelfApp on ChromeOS.
// The kHitTestAsk flag should be ignored in such a case because there is no
// need to do async hit testing on the root merely because it was overlapped.
- // TODO(yigu): Do not set the kHitTestAsk and kOverlappedRegion flags for
- // root when building hit test data.
+ // TODO(crbug.com/1001238): Do not set the kHitTestAsk and kOverlappedRegion
+ // flags for root when building hit test data.
bool root_view_overlapped =
hit_test_data_[region_index].frame_sink_id == root_view_frame_sink_id &&
hit_test_data_[region_index].async_hit_test_reasons ==
diff --git a/chromium/components/viz/host/host_gpu_memory_buffer_manager.cc b/chromium/components/viz/host/host_gpu_memory_buffer_manager.cc
index 913efda7a10..34af06414c2 100644
--- a/chromium/components/viz/host/host_gpu_memory_buffer_manager.cc
+++ b/chromium/components/viz/host/host_gpu_memory_buffer_manager.cc
@@ -15,6 +15,7 @@
#include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "services/viz/privileged/mojom/gl/gpu_service.mojom.h"
+#include "ui/base/ui_base_features.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/buffer_usage_util.h"
@@ -46,11 +47,15 @@ HostGpuMemoryBufferManager::HostGpuMemoryBufferManager(
client_id_(client_id),
gpu_memory_buffer_support_(std::move(gpu_memory_buffer_support)),
task_runner_(std::move(task_runner)) {
-#if !defined(USE_X11)
- native_configurations_ = gpu::GetNativeGpuMemoryBufferConfigurations(
- gpu_memory_buffer_support_.get());
- native_configurations_initialized_.Signal();
+ bool should_get_native_configs = true;
+#if defined(USE_X11)
+ should_get_native_configs = features::IsUsingOzonePlatform();
#endif
+ if (should_get_native_configs) {
+ native_configurations_ = gpu::GetNativeGpuMemoryBufferConfigurations(
+ gpu_memory_buffer_support_.get());
+ native_configurations_initialized_.Signal();
+ }
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
this, "HostGpuMemoryBufferManager", task_runner_);
}
@@ -283,7 +288,12 @@ void HostGpuMemoryBufferManager::OnConnectionError() {
<< ", size = " << buffer.size.ToString()
<< ", format = " << gfx::BufferFormatToString(buffer.format)
<< ", usage = " << gfx::BufferUsageToString(buffer.usage)
- << ", surface_handle = " << buffer.surface_handle
+ << ", surface_handle = "
+#if defined(USE_X11)
+ << static_cast<uint32_t>(buffer.surface_handle)
+#else
+ << buffer.surface_handle
+#endif
<< " due to connection error";
AllocateGpuMemoryBuffer(
buffer_pair.first, client_pair.first, buffer.size, buffer.format,
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 6620f76f584..6a62df062f5 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
@@ -19,6 +19,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/client_native_pixmap_factory.h"
+#if defined(USE_OZONE) || defined(USE_X11)
+#include "ui/base/ui_base_features.h" // nogncheck
+#endif
+
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif
@@ -229,7 +233,8 @@ class HostGpuMemoryBufferManagerTest : public ::testing::Test {
base::ThreadTaskRunnerHandle::Get());
#if defined(USE_X11)
// X11 requires GPU process initialization to determine GMB support.
- gpu_memory_buffer_manager_->native_configurations_initialized_.Signal();
+ if (!features::IsUsingOzonePlatform())
+ gpu_memory_buffer_manager_->native_configurations_initialized_.Signal();
#endif
}
@@ -238,9 +243,11 @@ class HostGpuMemoryBufferManagerTest : public ::testing::Test {
bool IsNativePixmapConfigSupported() {
bool native_pixmap_supported = false;
#if defined(USE_OZONE)
- native_pixmap_supported =
- ui::OzonePlatform::GetInstance()->IsNativePixmapConfigSupported(
- gfx::BufferFormat::RGBA_8888, gfx::BufferUsage::GPU_READ);
+ if (features::IsUsingOzonePlatform()) {
+ native_pixmap_supported =
+ ui::OzonePlatform::GetInstance()->IsNativePixmapConfigSupported(
+ gfx::BufferFormat::RGBA_8888, gfx::BufferUsage::GPU_READ);
+ }
#elif defined(OS_ANDROID)
native_pixmap_supported =
base::AndroidHardwareBufferCompat::IsSupportAvailable();
diff --git a/chromium/components/viz/host/renderer_settings_creation.cc b/chromium/components/viz/host/renderer_settings_creation.cc
index 0fc4813b2f7..f28c3218baa 100644
--- a/chromium/components/viz/host/renderer_settings_creation.cc
+++ b/chromium/components/viz/host/renderer_settings_creation.cc
@@ -20,6 +20,7 @@
#endif
#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"
#include "ui/ozone/public/ozone_platform.h"
#endif
@@ -86,16 +87,18 @@ RendererSettings CreateRendererSettings() {
}
#if defined(USE_OZONE)
- if (command_line->HasSwitch(switches::kEnableHardwareOverlays)) {
- renderer_settings.overlay_strategies = ParseOverlayStrategies(
- command_line->GetSwitchValueASCII(switches::kEnableHardwareOverlays));
- } else {
- auto& host_properties =
- ui::OzonePlatform::GetInstance()->GetInitializedHostProperties();
- if (host_properties.supports_overlays) {
- renderer_settings.overlay_strategies = {OverlayStrategy::kFullscreen,
- OverlayStrategy::kSingleOnTop,
- OverlayStrategy::kUnderlay};
+ if (features::IsUsingOzonePlatform()) {
+ if (command_line->HasSwitch(switches::kEnableHardwareOverlays)) {
+ renderer_settings.overlay_strategies = ParseOverlayStrategies(
+ command_line->GetSwitchValueASCII(switches::kEnableHardwareOverlays));
+ } else {
+ auto& host_properties =
+ ui::OzonePlatform::GetInstance()->GetInitializedHostProperties();
+ if (host_properties.supports_overlays) {
+ renderer_settings.overlay_strategies = {OverlayStrategy::kFullscreen,
+ OverlayStrategy::kSingleOnTop,
+ OverlayStrategy::kUnderlay};
+ }
}
}
#endif
diff --git a/chromium/components/viz/service/BUILD.gn b/chromium/components/viz/service/BUILD.gn
index b2ba22d8da6..09797704091 100644
--- a/chromium/components/viz/service/BUILD.gn
+++ b/chromium/components/viz/service/BUILD.gn
@@ -330,6 +330,10 @@ viz_source_set("gpu_service_dependencies") {
sources = [
"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",
@@ -365,7 +369,10 @@ viz_source_set("gpu_service_dependencies") {
defines = [ "VIZ_SERVICE_IMPLEMENTATION" ]
- deps = [ "//gpu/config" ]
+ deps = [
+ "//base",
+ "//gpu/config",
+ ]
if (is_win) {
sources += [
@@ -409,7 +416,7 @@ viz_source_set("gpu_service_dependencies") {
deps += [ "//ui/gfx/x" ]
}
- if (skia_use_dawn) {
+ if (skia_use_dawn && is_win) {
sources += [
"display_embedder/skia_output_device_dawn.cc",
"display_embedder/skia_output_device_dawn.h",
@@ -423,6 +430,19 @@ 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",
+ ]
+
+ deps += [
+ "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.images",
+ "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.sysmem",
+ "//third_party/fuchsia-sdk/sdk/pkg/sys_inspect_cpp",
+ ]
+ }
}
viz_source_set("unit_tests") {
@@ -491,6 +511,7 @@ viz_source_set("unit_tests") {
"//components/viz/common",
"//components/viz/host",
"//components/viz/service/main:main",
+ "//components/viz/test:test_suite",
"//components/viz/test:test_support",
"//gpu/command_buffer/client",
"//gpu/command_buffer/client:gles2_implementation",
@@ -554,7 +575,9 @@ viz_source_set("unit_tests") {
# TODO(samans): Support more configurations.
# CFI issue: https://crbug.com/967819
# LSAN issue: https://crbug.com/971357
- if (use_x11 && !is_cfi && !is_lsan) {
+ # Fuchsia ARM64 https://crbug.com/1058247
+ if ((use_x11 && !is_cfi && !is_lsan) ||
+ (is_fuchsia && target_cpu == "x64")) {
defines += [ "ENABLE_VIZ_VULKAN_TESTS" ]
}
}
diff --git a/chromium/components/viz/service/display/DEPS b/chromium/components/viz/service/display/DEPS
index e21abf9abcb..39b3ff37c99 100644
--- a/chromium/components/viz/service/display/DEPS
+++ b/chromium/components/viz/service/display/DEPS
@@ -62,5 +62,6 @@ specific_include_rules = {
"+gpu/GLES2",
"+media",
"+third_party/libyuv",
+ "+ui/gl/gl_implementation.h",
],
}
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.h b/chromium/components/viz/service/display/ca_layer_overlay.h
index 2594167459e..5e9c2f27322 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.h
+++ b/chromium/components/viz/service/display/ca_layer_overlay.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "components/viz/common/quads/render_pass.h"
#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/SkMatrix44.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -23,7 +24,7 @@ class RenderPassDrawQuad;
// Holds information that is frequently shared between consecutive
// CALayerOverlays.
class VIZ_SERVICE_EXPORT CALayerOverlaySharedState
- : public base::RefCounted<CALayerOverlaySharedState> {
+ : public base::RefCountedThreadSafe<CALayerOverlaySharedState> {
public:
CALayerOverlaySharedState() {}
// Layers in a non-zero sorting context exist in the same 3D space and should
@@ -40,7 +41,7 @@ class VIZ_SERVICE_EXPORT CALayerOverlaySharedState
SkMatrix44 transform = SkMatrix44(SkMatrix44::kIdentity_Constructor);
private:
- friend class base::RefCounted<CALayerOverlaySharedState>;
+ friend class base::RefCountedThreadSafe<CALayerOverlaySharedState>;
~CALayerOverlaySharedState() {}
};
@@ -57,6 +58,8 @@ class VIZ_SERVICE_EXPORT CALayerOverlay {
// Texture that corresponds to an IOSurface to set as the content of the
// CALayer. If this is 0 then the CALayer is a solid color.
unsigned contents_resource_id = 0;
+ // Mailbox from contents_resource_id. It is used by SkiaRenderer.
+ gpu::Mailbox mailbox;
// The contents rect property for the CALayer.
gfx::RectF contents_rect;
// The bounds for the CALayer in pixels.
diff --git a/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc b/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
index dad254b2c68..c684f2d5498 100644
--- a/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
+++ b/chromium/components/viz/service/display/copy_output_scaling_pixeltest.cc
@@ -169,6 +169,9 @@ class CopyOutputScalingPixelTest
renderer()->DecideRenderPassAllocationsForFrame(list);
renderer()->DrawFrame(&list, 1.0f, viewport_size,
gfx::DisplayColorSpaces());
+ // Call SwapBuffersSkipped(), so the renderer can release related
+ // resources.
+ renderer()->SwapBuffersSkipped();
loop.Run();
}
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.cc b/chromium/components/viz/service/display/dc_layer_overlay.cc
index 647d33f7a2a..089e265f0f5 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.cc
+++ b/chromium/components/viz/service/display/dc_layer_overlay.cc
@@ -17,7 +17,6 @@
#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/overlay_processor_interface.h"
#include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/config/gpu_finch_features.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
diff --git a/chromium/components/viz/service/display/direct_renderer.cc b/chromium/components/viz/service/display/direct_renderer.cc
index 15ac491792a..9691ccf8bed 100644
--- a/chromium/components/viz/service/display/direct_renderer.cc
+++ b/chromium/components/viz/service/display/direct_renderer.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/display/direct_renderer.h"
+#include <limits.h>
#include <stddef.h>
#include <utility>
@@ -11,6 +12,7 @@
#include "base/auto_reset.h"
#include "base/containers/circular_deque.h"
+#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/stl_util.h"
@@ -465,6 +467,15 @@ void DirectRenderer::DrawFrame(
current_frame_valid_ = false;
}
+gfx::Rect DirectRenderer::GetTargetDamageBoundingRect() const {
+ gfx::Rect bounding_rect = output_surface_->GetCurrentFramebufferDamage();
+ if (overlay_processor_) {
+ bounding_rect.Union(
+ overlay_processor_->GetPreviousFrameOverlaysBoundingRect());
+ }
+ return bounding_rect;
+}
+
gfx::Rect DirectRenderer::DeviceViewportRectInDrawSpace() const {
gfx::Rect device_viewport_rect(current_frame()->device_viewport_size);
device_viewport_rect -= current_viewport_rect_.OffsetFromOrigin();
@@ -808,48 +819,67 @@ gfx::Rect DirectRenderer::ComputeScissorRectForRenderPass(
gfx::Rect root_damage_rect = current_frame()->root_damage_rect;
if (render_pass == root_render_pass) {
- auto display_area = current_frame()->device_viewport_size.GetArea();
- DCHECK(display_area);
-
- auto frame_buffer_damage = output_surface_->GetCurrentFramebufferDamage();
- auto root_damage_area = root_damage_rect.size().GetArea();
-
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.FrameBufferDamage",
- 100ull * frame_buffer_damage.size().GetArea() / display_area);
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.RootDamage",
- 100ull * root_damage_area / display_area);
-
- root_damage_rect.Union(frame_buffer_damage);
-
- // If the root damage rect intersects any child render pass that has a
- // pixel-moving backdrop-filter, expand the damage to include the entire
- // child pass. See crbug.com/986206 for context.
- if (!backdrop_filter_output_rects_.empty() && !root_damage_rect.IsEmpty()) {
- for (auto* quad : render_pass->quad_list) {
- if (quad->material == DrawQuad::Material::kRenderPass) {
- auto iter = backdrop_filter_output_rects_.find(
- RenderPassDrawQuad::MaterialCast(quad)->render_pass_id);
- if (iter != backdrop_filter_output_rects_.end()) {
- auto this_output_rect = iter->second;
- if (root_damage_rect.Intersects(this_output_rect))
- root_damage_rect.Union(this_output_rect);
+ base::CheckedNumeric<int> display_area =
+ current_frame()->device_viewport_size.GetCheckedArea();
+ gfx::Rect frame_buffer_damage =
+ output_surface_->GetCurrentFramebufferDamage();
+ base::CheckedNumeric<int> root_damage_area =
+ root_damage_rect.size().GetCheckedArea();
+ if (display_area.IsValid() && root_damage_area.IsValid()) {
+ DCHECK_GT(static_cast<int>(display_area.ValueOrDie()), 0);
+ {
+ base::CheckedNumeric<int> frame_buffer_damage_area =
+ frame_buffer_damage.size().GetCheckedArea();
+ int ratio =
+ (frame_buffer_damage_area / display_area).ValueOrDefault(INT_MAX);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.FrameBufferDamage",
+ 100ull * ratio);
+ }
+ {
+ int ratio = (root_damage_area / display_area).ValueOrDie();
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.RootDamage",
+ 100ull * ratio);
+ }
+
+ root_damage_rect.Union(frame_buffer_damage);
+
+ // If the root damage rect intersects any child render pass that has a
+ // pixel-moving backdrop-filter, expand the damage to include the entire
+ // child pass. See crbug.com/986206 for context.
+ if (!backdrop_filter_output_rects_.empty() &&
+ !root_damage_rect.IsEmpty()) {
+ for (auto* quad : render_pass->quad_list) {
+ if (quad->material == DrawQuad::Material::kRenderPass) {
+ auto iter = backdrop_filter_output_rects_.find(
+ RenderPassDrawQuad::MaterialCast(quad)->render_pass_id);
+ if (iter != backdrop_filter_output_rects_.end()) {
+ gfx::Rect this_output_rect = iter->second;
+ if (root_damage_rect.Intersects(this_output_rect))
+ root_damage_rect.Union(this_output_rect);
+ }
}
}
}
- }
-
- // Total damage after all adjustments.
- auto total_damage_area = root_damage_rect.size().GetArea();
-
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.TotalDamage",
- 100ull * total_damage_area / display_area);
- UMA_HISTOGRAM_PERCENTAGE(
- "Compositing.DirectRenderer.PartialSwap.ExtraDamage",
- 100ull * (total_damage_area - root_damage_area) / display_area);
+ // Total damage after all adjustments.
+ base::CheckedNumeric<int> total_damage_area =
+ root_damage_rect.size().GetCheckedArea();
+ {
+ int ratio = (total_damage_area / display_area).ValueOrDefault(INT_MAX);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.TotalDamage",
+ 100ull * ratio);
+ }
+ {
+ int ratio = ((total_damage_area - root_damage_area) / display_area)
+ .ValueOrDefault(INT_MAX);
+ UMA_HISTOGRAM_PERCENTAGE(
+ "Compositing.DirectRenderer.PartialSwap.ExtraDamage",
+ 100ull * ratio);
+ }
+ }
return root_damage_rect;
}
diff --git a/chromium/components/viz/service/display/direct_renderer.h b/chromium/components/viz/service/display/direct_renderer.h
index 259ec01ce1c..ef57383011a 100644
--- a/chromium/components/viz/service/display/direct_renderer.h
+++ b/chromium/components/viz/service/display/direct_renderer.h
@@ -69,6 +69,11 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
const gfx::Size& device_viewport_size,
const gfx::DisplayColorSpaces& display_color_spaces);
+ // The renderer might expand the damage (e.g: HW overlays were used,
+ // invalidation rects on previous buffers). This function returns a
+ // bounding rect of the area that might need to be recomposited.
+ gfx::Rect GetTargetDamageBoundingRect() const;
+
// Public interface implemented by subclasses.
struct SwapFrameData {
SwapFrameData();
diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc
index 80382efd040..fd92ca7cfee 100644
--- a/chromium/components/viz/service/display/display.cc
+++ b/chromium/components/viz/service/display/display.cc
@@ -5,7 +5,9 @@
#include "components/viz/service/display/display.h"
#include <stddef.h>
+#include <algorithm>
#include <limits>
+#include <utility>
#include "base/debug/dump_without_crashing.h"
#include "base/metrics/histogram_macros.h"
@@ -55,6 +57,14 @@ namespace viz {
namespace {
+enum class TypeOfVideoInFrame {
+ kNoVideo = 0,
+ kVideo = 1,
+
+ // This should be the last entry/largest value above.
+ kMaxValue = kVideo,
+};
+
const DrawQuad::Material kNonSplittableMaterials[] = {
// Exclude debug quads from quad splitting
DrawQuad::Material::kDebugBorder,
@@ -97,8 +107,11 @@ gfx::PresentationFeedback SanitizePresentationFeedback(
// therefore the timestamp can be slightly in the future in comparison with
// base::TimeTicks::Now(). Such presentation feedbacks should not be rejected.
// See https://crbug.com/1040178
+ // Sometimes we snap the feedback's time stamp to the nearest vsync, and that
+ // can be offset by one vsync-internal. These feedback has kVSync set.
const auto allowed_delta_from_future =
- ((feedback.flags & gfx::PresentationFeedback::kHWClock) != 0)
+ ((feedback.flags & (gfx::PresentationFeedback::kHWClock |
+ gfx::PresentationFeedback::kVSync)) != 0)
? kAllowedDeltaFromFuture
: base::TimeDelta();
if (feedback.timestamp > now + allowed_delta_from_future) {
@@ -165,25 +178,41 @@ gfx::Rect SafeConvertRectForRegion(const gfx::Rect& r) {
return safe_rect;
}
-// Computes the accumulated area of all the rectangles in the list of |rects|.
-int ComputeArea(const std::vector<gfx::Rect>& rects) {
- int area = 0;
- for (const auto& r : rects)
- area += r.size().GetArea();
- return area;
-}
-
// Decides whether or not a DrawQuad should be split into a more complex visible
// region in order to avoid overdraw.
bool CanSplitQuad(const DrawQuad::Material m,
- const int visible_region_area,
- const int visible_region_bounding_area,
- const int minimum_fragments_reduced,
+ const std::vector<gfx::Rect>& visible_region_rects,
+ const gfx::Size& visible_region_bounding_size,
+ int minimum_fragments_reduced,
const float device_scale_factor) {
- return !base::Contains(kNonSplittableMaterials, m) &&
- (visible_region_bounding_area - visible_region_area) *
- device_scale_factor * device_scale_factor >
- minimum_fragments_reduced;
+ if (base::Contains(kNonSplittableMaterials, m))
+ return false;
+
+ base::CheckedNumeric<int> area = 0;
+ for (const auto& r : visible_region_rects) {
+ area += r.size().GetCheckedArea();
+ // In calculations below, assume false if this addition overflows.
+ if (!area.IsValid()) {
+ return false;
+ }
+ }
+
+ base::CheckedNumeric<int> visible_region_bounding_area =
+ visible_region_bounding_size.GetCheckedArea();
+ if (!visible_region_bounding_area.IsValid()) {
+ // In calculations below, assume true if this overflows.
+ return true;
+ }
+
+ area = visible_region_bounding_area - area;
+ if (!area.IsValid()) {
+ // In calculations below, assume false if this subtraction underflows.
+ return false;
+ }
+
+ int int_area = area.ValueOrDie();
+ return int_area * device_scale_factor * device_scale_factor >
+ minimum_fragments_reduced;
}
// Attempts to consolidate rectangles that were only split because of the
@@ -521,10 +550,13 @@ void Display::InitializeRenderer(bool enable_shared_images) {
// Outputting a partial list of quads might not work in cases where contents
// outside the damage rect might be needed by the renderer.
+ bool might_invalidate_outside_damage =
+ !output_surface_->capabilities().only_invalidates_damage_rect ||
+ overlay_processor_->IsOverlaySupported();
bool output_partial_list =
- output_surface_->capabilities().only_invalidates_damage_rect &&
renderer_->use_partial_swap() &&
- !overlay_processor_->IsOverlaySupported();
+ (!might_invalidate_outside_damage ||
+ output_surface_->capabilities().supports_target_damage);
aggregator_ = std::make_unique<SurfaceAggregator>(
surface_manager_, resource_provider_.get(), output_partial_list,
@@ -611,9 +643,32 @@ bool Display::DrawAndSwap(base::TimeTicks expected_display_time) {
{
FrameRateDecider::ScopedAggregate scoped_aggregate(
frame_rate_decider_.get());
- frame =
- aggregator_->Aggregate(current_surface_id_, expected_display_time,
- current_display_transform, ++swapped_trace_id_);
+ gfx::Rect target_damage_bounding_rect;
+ if (output_surface_->capabilities().supports_target_damage)
+ target_damage_bounding_rect = renderer_->GetTargetDamageBoundingRect();
+
+ frame = aggregator_->Aggregate(
+ current_surface_id_, expected_display_time, current_display_transform,
+ target_damage_bounding_rect, ++swapped_trace_id_);
+ }
+
+ // Records whether the aggregated frame contains video or not.
+ // TODO(vikassoni) : Extend this capability to record whether a video frame is
+ // inline or fullscreen.
+ UMA_HISTOGRAM_ENUMERATION("Compositing.SurfaceAggregator.FrameContainsVideo",
+ frame.metadata.may_contain_video
+ ? TypeOfVideoInFrame::kVideo
+ : TypeOfVideoInFrame::kNoVideo);
+
+ if (frame.metadata.delegated_ink_metadata) {
+ TRACE_EVENT_INSTANT2(
+ "viz", "Delegated Ink Metadata was aggregated for DrawAndSwap.",
+ TRACE_EVENT_SCOPE_THREAD, "point",
+ frame.metadata.delegated_ink_metadata->point().ToString(), "area",
+ frame.metadata.delegated_ink_metadata->presentation_area().ToString());
+ // TODO(1052145): This metadata will be stored here and used to determine
+ // which points should be drawn onto the back buffer (via Skia or OS APIs)
+ // before being swapped onto the screen.
}
#if defined(OS_ANDROID)
@@ -1039,9 +1094,12 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
settings_.kMaximumOccluderComplexity) {
gfx::Rect smallest_rect = *occlusion_in_target_space.begin();
for (const auto& occluding_rect : occlusion_in_target_space) {
- if (occluding_rect.size().GetArea() <
- smallest_rect.size().GetArea())
+ if (occluding_rect.size().GetCheckedArea().ValueOrDefault(
+ INT_MAX) <
+ smallest_rect.size().GetCheckedArea().ValueOrDefault(
+ INT_MAX)) {
smallest_rect = occluding_rect;
+ }
}
occlusion_in_target_space.Subtract(smallest_rect);
}
@@ -1130,8 +1188,8 @@ void Display::RemoveOverdrawQuads(CompositorFrame* frame) {
!visible_region.Intersects(render_pass_quads_in_content_space) &&
ReduceComplexity(visible_region, settings_.quad_split_limit,
&cached_visible_region_) &&
- CanSplitQuad(quad->material, ComputeArea(cached_visible_region_),
- visible_region.bounds().size().GetArea(),
+ CanSplitQuad(quad->material, cached_visible_region_,
+ visible_region.bounds().size(),
settings_.minimum_fragments_reduced,
device_scale_factor_);
if (should_split_quads) {
diff --git a/chromium/components/viz/service/display/display_resource_provider.cc b/chromium/components/viz/service/display/display_resource_provider.cc
index bcf21f8135b..faa7a2179be 100644
--- a/chromium/components/viz/service/display/display_resource_provider.cc
+++ b/chromium/components/viz/service/display/display_resource_provider.cc
@@ -198,7 +198,7 @@ void DisplayResourceProvider::SendPromotionHints(
if (it->second.marked_for_deletion)
continue;
- const ChildResource* resource = LockForRead(id);
+ const ChildResource* resource = LockForRead(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
@@ -218,7 +218,7 @@ void DisplayResourceProvider::SendPromotionHints(
promotable ? iter->second.width() : 0,
promotable ? iter->second.height() : 0);
}
- UnlockForRead(id);
+ UnlockForRead(id, false /* overlay_only */);
}
#endif
}
@@ -493,7 +493,7 @@ GLES2Interface* DisplayResourceProvider::ContextGL() const {
}
const DisplayResourceProvider::ChildResource*
-DisplayResourceProvider::LockForRead(ResourceId id) {
+DisplayResourceProvider::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
@@ -519,10 +519,27 @@ DisplayResourceProvider::LockForRead(ResourceId id) {
}
resource->SetLocallyUsed();
}
- if (mailbox.IsSharedImage() && enable_shared_images_ &&
- resource->lock_for_read_count == 0) {
- gl->BeginSharedImageAccessDirectCHROMIUM(
- resource->gl_id, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
+ 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);
+ }
+ }
}
}
@@ -540,7 +557,10 @@ DisplayResourceProvider::LockForRead(ResourceId id) {
}
}
- resource->lock_for_read_count++;
+ 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();
@@ -550,7 +570,7 @@ DisplayResourceProvider::LockForRead(ResourceId id) {
return resource;
}
-void DisplayResourceProvider::UnlockForRead(ResourceId id) {
+void DisplayResourceProvider::UnlockForRead(ResourceId id, bool overlay_only) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto it = resources_.find(id);
// TODO(ericrk): We should never fail to find id, but we appear to be
@@ -560,16 +580,23 @@ void DisplayResourceProvider::UnlockForRead(ResourceId id) {
return;
ChildResource* resource = &it->second;
- DCHECK_GT(resource->lock_for_read_count, 0);
if (resource->transferable.mailbox_holder.mailbox.IsSharedImage() &&
- resource->is_gpu_resource_type() && enable_shared_images_ &&
- resource->lock_for_read_count == 1) {
- DCHECK(resource->gl_id);
- GLES2Interface* gl = ContextGL();
- DCHECK(gl);
- gl->EndSharedImageAccessDirectCHROMIUM(resource->gl_id);
+ resource->is_gpu_resource_type() && 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);
+ 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--;
}
- resource->lock_for_read_count--;
TryReleaseResource(id, resource);
}
@@ -851,7 +878,8 @@ DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
DisplayResourceProvider* resource_provider,
ResourceId resource_id)
: resource_provider_(resource_provider), resource_id_(resource_id) {
- const ChildResource* resource = resource_provider->LockForRead(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
@@ -865,7 +893,23 @@ DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
}
DisplayResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
- resource_provider_->UnlockForRead(resource_id_);
+ resource_provider_->UnlockForRead(resource_id_, false /* overlay_only */);
+}
+
+DisplayResourceProvider::ScopedOverlayLockGL::ScopedOverlayLockGL(
+ DisplayResourceProvider* 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;
+}
+
+DisplayResourceProvider::ScopedOverlayLockGL::~ScopedOverlayLockGL() {
+ resource_provider_->UnlockForRead(resource_id_, true /* overlay_only */);
}
DisplayResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
@@ -893,7 +937,8 @@ DisplayResourceProvider::ScopedReadLockSkImage::ScopedReadLockSkImage(
SkAlphaType alpha_type,
GrSurfaceOrigin origin)
: resource_provider_(resource_provider), resource_id_(resource_id) {
- const ChildResource* resource = resource_provider->LockForRead(resource_id);
+ const ChildResource* resource =
+ resource_provider->LockForRead(resource_id, false /* overlay_only */);
DCHECK(resource);
// Use cached SkImage if possible.
@@ -942,7 +987,7 @@ DisplayResourceProvider::ScopedReadLockSkImage::ScopedReadLockSkImage(
}
DisplayResourceProvider::ScopedReadLockSkImage::~ScopedReadLockSkImage() {
- resource_provider_->UnlockForRead(resource_id_);
+ resource_provider_->UnlockForRead(resource_id_, false /* overlay_only */);
}
DisplayResourceProvider::ScopedReadLockSharedImage::ScopedReadLockSharedImage(
diff --git a/chromium/components/viz/service/display/display_resource_provider.h b/chromium/components/viz/service/display/display_resource_provider.h
index 71abecc9fd6..2b5c0a95167 100644
--- a/chromium/components/viz/service/display/display_resource_provider.h
+++ b/chromium/components/viz/service/display/display_resource_provider.h
@@ -158,6 +158,23 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
gfx::ColorSpace color_space_;
};
+ class VIZ_SERVICE_EXPORT ScopedOverlayLockGL {
+ public:
+ ScopedOverlayLockGL(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id);
+ ~ScopedOverlayLockGL();
+
+ ScopedOverlayLockGL(const ScopedOverlayLockGL&) = delete;
+ ScopedOverlayLockGL& operator=(const ScopedOverlayLockGL&) = delete;
+
+ GLuint texture_id() const { return texture_id_; }
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+ const ResourceId resource_id_;
+ GLuint texture_id_ = 0;
+ };
+
class VIZ_SERVICE_EXPORT ScopedSamplerGL {
public:
ScopedSamplerGL(DisplayResourceProvider* resource_provider,
@@ -521,8 +538,8 @@ class VIZ_SERVICE_EXPORT DisplayResourceProvider
// Returns null if we do not have a ContextProvider.
gpu::gles2::GLES2Interface* ContextGL() const;
- const ChildResource* LockForRead(ResourceId id);
- void UnlockForRead(ResourceId id);
+ const ChildResource* LockForRead(ResourceId id, bool overlay_only);
+ void UnlockForRead(ResourceId id, bool overlay_only);
void TryReleaseResource(ResourceId id, ChildResource* resource);
// Binds the given GL resource to a texture target for sampling using the
diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc
index 94f6984ba7f..58082642162 100644
--- a/chromium/components/viz/service/display/display_unittest.cc
+++ b/chromium/components/viz/service/display/display_unittest.cc
@@ -36,6 +36,7 @@
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
#include "components/viz/test/test_gles2_interface.h"
+#include "components/viz/test/viz_test_suite.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -102,8 +103,11 @@ class StubDisplayClient : public DisplayClient {
}
};
-void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
+void CopyCallback(bool* called,
+ base::OnceClosure finished,
+ std::unique_ptr<CopyOutputResult> result) {
*called = true;
+ std::move(finished).Run();
}
gfx::SwapTimings GetTestSwapTimings() {
@@ -214,10 +218,7 @@ class DisplayTest : public testing::Test {
void ResetDamageForTest() { scheduler_->ResetDamageForTest(); }
- void RunAllPendingInMessageLoop() {
- base::RunLoop run_loop;
- run_loop.RunUntilIdle();
- }
+ void RunUntilIdle() { VizTestSuite::RunUntilIdle(); }
void LatencyInfoCapTest(bool over_capacity);
@@ -424,10 +425,12 @@ TEST_F(DisplayTest, DisplayDamaged) {
pass = RenderPass::Create();
pass->output_rect = gfx::Rect(0, 0, 100, 100);
pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ base::RunLoop copy_run_loop;
bool copy_called = false;
pass->copy_requests.push_back(std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&CopyCallback, &copy_called)));
+ base::BindOnce(&CopyCallback, &copy_called,
+ copy_run_loop.QuitClosure())));
pass->id = 1u;
pass_list.push_back(std::move(pass));
@@ -441,6 +444,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
display_->DrawAndSwap(base::TimeTicks::Now());
EXPECT_TRUE(scheduler_->swapped());
EXPECT_EQ(5u, output_surface_->num_sent_frames());
+ copy_run_loop.Run();
EXPECT_TRUE(copy_called);
}
@@ -3543,7 +3547,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
pass_list.push_back(std::move(pass));
SubmitCompositorFrame(&pass_list, local_surface_id);
display_->DrawAndSwap(base::TimeTicks::Now());
- RunAllPendingInMessageLoop();
+ RunUntilIdle();
}
{
@@ -3557,7 +3561,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
sub_support->SubmitCompositorFrame(sub_local_surface_id, std::move(frame));
display_->DrawAndSwap(base::TimeTicks::Now());
- RunAllPendingInMessageLoop();
+ RunUntilIdle();
// Both frames with frame-tokens 1 and 2 requested presentation-feedback.
ASSERT_EQ(2u, sub_support->timing_details().size());
@@ -3575,7 +3579,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
sub_support->SubmitCompositorFrame(sub_local_surface_id, std::move(frame));
display_->DrawAndSwap(base::TimeTicks::Now());
- RunAllPendingInMessageLoop();
+ RunUntilIdle();
}
}
@@ -4500,10 +4504,12 @@ TEST_F(DisplayTest, DisplaySizeMismatch) {
std::unique_ptr<RenderPass> pass = RenderPass::Create();
pass->output_rect = gfx::Rect(0, 0, 99, 99);
pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ base::RunLoop copy_run_loop;
bool copy_called = false;
pass->copy_requests.push_back(std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&CopyCallback, &copy_called)));
+ base::BindOnce(&CopyCallback, &copy_called,
+ copy_run_loop.QuitClosure())));
pass->id = 1u;
RenderPassList pass_list;
@@ -4516,6 +4522,8 @@ TEST_F(DisplayTest, DisplaySizeMismatch) {
display_->DrawAndSwap(base::TimeTicks::Now());
+ copy_run_loop.Run();
+
// Expect no swap happen
EXPECT_EQ(0u, output_surface_->num_sent_frames());
diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc
index 1efef996517..591e5c4e6f7 100644
--- a/chromium/components/viz/service/display/gl_renderer.cc
+++ b/chromium/components/viz/service/display/gl_renderer.cc
@@ -83,6 +83,10 @@
#include "ui/gfx/rrect_f.h"
#include "ui/gfx/skia_util.h"
+#if defined(USE_X11)
+#include "ui/base/ui_base_features.h"
+#endif
+
using gpu::gles2::GLES2Interface;
namespace viz {
@@ -2826,7 +2830,12 @@ void GLRenderer::FinishDrawingFrame() {
ScheduleOutputSurfaceAsOverlay();
#if defined(OS_ANDROID) || defined(USE_OZONE)
- ScheduleOverlays();
+ bool schedule_overlays = true;
+#if defined(USE_X11)
+ schedule_overlays = features::IsUsingOzonePlatform();
+#endif
+ if (schedule_overlays)
+ ScheduleOverlays();
#elif defined(OS_MACOSX)
ScheduleCALayers();
#elif defined(OS_WIN)
@@ -2855,8 +2864,9 @@ void GLRenderer::FinishDrawingQuadList() {
// 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.
- const int surface_area = current_surface_size_.GetArea();
- DCHECK_GT(surface_area, 0);
+ 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(
@@ -3528,7 +3538,7 @@ void GLRenderer::ScheduleCALayers() {
unsigned texture_id = 0;
if (contents_resource_id) {
pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedOverlayLockGL>(
resource_provider_, contents_resource_id));
texture_id = pending_overlay_resources_.back()->texture_id();
}
@@ -3585,7 +3595,7 @@ void GLRenderer::ScheduleDCLayers() {
if (resource_id == kInvalidResourceId)
break;
pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedOverlayLockGL>(
resource_provider_, resource_id));
texture_ids[i] = pending_overlay_resources_.back()->texture_id();
}
@@ -3624,7 +3634,7 @@ void GLRenderer::ScheduleOverlays() {
OverlayCandidateList& overlays = current_frame()->overlay_list;
for (const auto& overlay_candidate : overlays) {
pending_overlay_resources_.push_back(
- std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedOverlayLockGL>(
resource_provider_, overlay_candidate.resource_id));
unsigned texture_id = pending_overlay_resources_.back()->texture_id();
@@ -3981,7 +3991,7 @@ void GLRenderer::FlushOverdrawFeedback(const gfx::Rect& output_rect) {
}
}
-void GLRenderer::ProcessOverdrawFeedback(int surface_area,
+void GLRenderer::ProcessOverdrawFeedback(base::CheckedNumeric<int> surface_area,
unsigned occlusion_query) {
unsigned result = 0;
DCHECK(occlusion_query);
@@ -3990,7 +4000,8 @@ void GLRenderer::ProcessOverdrawFeedback(int surface_area,
// Report GPU overdraw as a percentage of |surface_area|.
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("viz.overdraw"), "GPU Overdraw",
- (result * 100.0 / surface_area));
+ (result * 100.0 /
+ static_cast<int>(surface_area.ValueOrDefault(INT_MAX))));
}
void GLRenderer::UpdateRenderPassTextures(
@@ -4041,8 +4052,11 @@ void GLRenderer::AllocateRenderPassResourceIfNeeded(
const RenderPassId& 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())
+ 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,
diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h
index f4943ca0721..94e7a088b39 100644
--- a/chromium/components/viz/service/display/gl_renderer.h
+++ b/chromium/components/viz/service/display/gl_renderer.h
@@ -155,7 +155,7 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
friend class GLRendererTest;
using OverlayResourceLock =
- std::unique_ptr<DisplayResourceProvider::ScopedReadLockGL>;
+ std::unique_ptr<DisplayResourceProvider::ScopedOverlayLockGL>;
using OverlayResourceLockList = std::vector<OverlayResourceLock>;
// If a RenderPass is used as an overlay, we render the RenderPass with any
@@ -351,7 +351,8 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
void SetupOverdrawFeedback();
// Process overdraw feedback from query.
- void ProcessOverdrawFeedback(int surface_area, unsigned query);
+ void ProcessOverdrawFeedback(base::CheckedNumeric<int> surface_area,
+ unsigned query);
bool OverdrawTracingEnabled();
ResourceFormat CurrentRenderPassResourceFormat() const;
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.cc b/chromium/components/viz/service/display/gl_renderer_copier.cc
index cd54ec7f65b..eca6218676e 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/process/memory.h"
#include "base/stl_util.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"
@@ -215,7 +216,9 @@ void GLRendererCopier::CopyFromTextureOrFramebuffer(
// 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.
- DCHECK(request->SendsResultsInCurrentSequence() || async_gl_task_runner_);
+ if (!request->SendsResultsInCurrentSequence() && !async_gl_task_runner_) {
+ request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
+ }
const gfx::Rect aligned_rect = RenderI420Textures(
*request, flipped_source, color_space, source_texture,
@@ -508,9 +511,10 @@ class ReadPixelsWorkflow {
// 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,
- kRGBABytesPerPixel * result_rect.size().GetArea(), nullptr,
- GL_STREAM_READ);
+ 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.
@@ -749,13 +753,15 @@ class ReadI420PlanesWorkflow
auto* const gl = context_provider_->ContextGL();
gl->GenBuffers(1, &transfer_buffer_);
gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- const int y_plane_bytes = kRGBABytesPerPixel * y_texture_size().GetArea();
- const int chroma_plane_bytes =
- kRGBABytesPerPixel * chroma_texture_size().GetArea();
+ 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 + 2 * chroma_plane_bytes, nullptr,
- GL_STREAM_READ);
- data_offsets_ = {0, y_plane_bytes, y_plane_bytes + chroma_plane_bytes};
+ (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
diff --git a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc b/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
index aebb5ed5d56..fb3452b9e0f 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier_unittest.cc
@@ -113,7 +113,7 @@ TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
const base::UnguessableToken no_source;
EXPECT_EQ(0u, GetCopierCacheSize());
auto things = TakeReusableThingsOrCreate(no_source);
- EXPECT_TRUE(!!things);
+ EXPECT_TRUE(things);
StashReusableThingsOrDelete(no_source, std::move(things));
EXPECT_EQ(nullptr, PeekReusableThings(no_source));
EXPECT_EQ(0u, GetCopierCacheSize());
@@ -122,7 +122,7 @@ TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
const auto source = base::UnguessableToken::Create();
things = TakeReusableThingsOrCreate(source);
ReusableThings* things_raw_ptr = things.get();
- EXPECT_TRUE(!!things_raw_ptr);
+ EXPECT_TRUE(things_raw_ptr);
StashReusableThingsOrDelete(source, std::move(things));
EXPECT_EQ(things_raw_ptr, PeekReusableThings(source));
EXPECT_EQ(1u, GetCopierCacheSize());
@@ -131,7 +131,7 @@ TEST_F(GLRendererCopierTest, ReusesThingsFromSameSource) {
const auto source2 = base::UnguessableToken::Create();
things = TakeReusableThingsOrCreate(source2);
things_raw_ptr = things.get();
- EXPECT_TRUE(!!things_raw_ptr);
+ EXPECT_TRUE(things_raw_ptr);
EXPECT_EQ(1u, GetCopierCacheSize());
StashReusableThingsOrDelete(source2, std::move(things));
EXPECT_EQ(things_raw_ptr, PeekReusableThings(source2));
@@ -144,14 +144,14 @@ TEST_F(GLRendererCopierTest, FreesUnusedResources) {
const base::UnguessableToken source = base::UnguessableToken::Create();
EXPECT_EQ(0u, GetCopierCacheSize());
StashReusableThingsOrDelete(source, TakeReusableThingsOrCreate(source));
- EXPECT_TRUE(!!PeekReusableThings(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_TRUE(PeekReusableThings(source));
EXPECT_EQ(1u, GetCopierCacheSize());
if (HasFailure())
break;
@@ -160,7 +160,7 @@ TEST_F(GLRendererCopierTest, FreesUnusedResources) {
// Calling FreeUnusedCachedResources() just one more time should cause the
// cache entry to be freed.
FreeUnusedCachedResources();
- EXPECT_FALSE(!!PeekReusableThings(source));
+ EXPECT_FALSE(PeekReusableThings(source));
EXPECT_EQ(0u, GetCopierCacheSize());
}
diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc
index a698822e170..6e7ecb769eb 100644
--- a/chromium/components/viz/service/display/gl_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_unittest.cc
@@ -37,6 +37,7 @@
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/test_gles2_interface.h"
#include "components/viz/test/test_shared_bitmap_manager.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"
@@ -85,6 +86,11 @@ MATCHER_P(MatchesSyncToken, 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();
+ }
RenderPass* root_render_pass() {
return render_passes_in_draw_order_.back().get();
}
diff --git a/chromium/components/viz/service/display/output_surface.h b/chromium/components/viz/service/display/output_surface.h
index 6476ec148f2..b58adf77f08 100644
--- a/chromium/components/viz/service/display/output_surface.h
+++ b/chromium/components/viz/service/display/output_surface.h
@@ -9,7 +9,6 @@
#include <vector>
#include "base/callback_helpers.h"
-#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
@@ -57,6 +56,10 @@ class VIZ_SERVICE_EXPORT OutputSurface {
Capabilities(const Capabilities& capabilities);
int max_frames_pending = 1;
+ // The number of buffers for the SkiaOutputDevice. If the
+ // |supports_post_sub_buffer| true, SkiaOutputSurfaceImpl will track target
+ // damaged area based on this number.
+ int number_of_buffers = 2;
// Whether this output surface renders to the default OpenGL zero
// framebuffer or to an offscreen framebuffer.
bool uses_default_gl_framebuffer = true;
@@ -88,6 +91,9 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// When this is false contents outside the damaged area might need to be
// recomposited to the surface.
bool only_invalidates_damage_rect = true;
+ // Whether OutputSurface::GetTargetDamageBoundingRect is implemented and
+ // will return a bounding rectangle of the target buffer invalidated area.
+ bool supports_target_damage = false;
// Whether the gpu supports surfaceless surface (equivalent of using buffer
// queue).
bool supports_surfaceless = false;
@@ -96,6 +102,10 @@ class VIZ_SERVICE_EXPORT OutputSurface {
bool android_surface_control_feature_enabled = false;
// True if the buffer content will be preserved after presenting.
bool preserve_buffer_content = false;
+ // True if the SkiaOutputDevice will set
+ // SwapBuffersCompleteParams::frame_buffer_damage_area for every
+ // SwapBuffers complete callback.
+ bool damage_area_from_skia_output_device = false;
// The SkColorType and GrBackendFormat for non-HDR and HDR.
// TODO(penghuang): remove SkColorType and GrBackendFormat when
// OutputSurface uses the |format| passed to Reshape().
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.cc b/chromium/components/viz/service/display/overlay_processor_interface.cc
index 5f9990fbd50..f09e8ac00fb 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.cc
+++ b/chromium/components/viz/service/display/overlay_processor_interface.cc
@@ -8,6 +8,7 @@
#include "base/metrics/histogram_macros.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/features.h"
+#include "components/viz/service/display/overlay_processor_stub.h"
#if defined(OS_MACOSX)
#include "components/viz/service/display/overlay_processor_mac.h"
@@ -18,10 +19,9 @@
#include "components/viz/service/display/overlay_processor_surface_control.h"
#elif defined(USE_OZONE)
#include "components/viz/service/display/overlay_processor_ozone.h"
+#include "ui/base/ui_base_features.h"
#include "ui/ozone/public/overlay_manager_ozone.h"
#include "ui/ozone/public/ozone_platform.h"
-#else
-#include "components/viz/service/display/overlay_processor_stub.h"
#endif
namespace viz {
@@ -98,6 +98,8 @@ OverlayProcessorInterface::CreateOverlayProcessor(
enable_dc_overlay,
std::make_unique<DCLayerOverlayProcessor>(renderer_settings)));
#elif defined(USE_OZONE)
+ if (!features::IsUsingOzonePlatform())
+ return std::make_unique<OverlayProcessorStub>();
bool overlay_enabled = surface_handle != gpu::kNullSurfaceHandle;
overlay_enabled &= !renderer_settings.overlay_strategies.empty();
std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates;
diff --git a/chromium/components/viz/service/display/overlay_processor_interface.h b/chromium/components/viz/service/display/overlay_processor_interface.h
index c5db304223f..e1779e03646 100644
--- a/chromium/components/viz/service/display/overlay_processor_interface.h
+++ b/chromium/components/viz/service/display/overlay_processor_interface.h
@@ -107,6 +107,10 @@ class VIZ_SERVICE_EXPORT OverlayProcessorInterface {
virtual ~OverlayProcessorInterface() {}
virtual bool IsOverlaySupported() const = 0;
+ // Returns a bounding rectangle of the last set of overlay planes scheduled.
+ // It's expected to be called after ProcessForOverlays at frame N-1 has been
+ // called and before GetAndResetOverlayDamage at frame N.
+ virtual gfx::Rect GetPreviousFrameOverlaysBoundingRect() const = 0;
virtual gfx::Rect GetAndResetOverlayDamage() = 0;
// Returns true if the platform supports hw overlays and surface occluding
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.cc b/chromium/components/viz/service/display/overlay_processor_mac.cc
index d972c9873dd..2a3b10b4336 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.cc
+++ b/chromium/components/viz/service/display/overlay_processor_mac.cc
@@ -37,6 +37,12 @@ bool OverlayProcessorMac::IsOverlaySupported() const {
return could_overlay_;
}
+gfx::Rect OverlayProcessorMac::GetPreviousFrameOverlaysBoundingRect() const {
+ // TODO(dcastagna): Implement me.
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
gfx::Rect OverlayProcessorMac::GetAndResetOverlayDamage() {
gfx::Rect result = ca_overlay_damage_rect_;
ca_overlay_damage_rect_ = gfx::Rect();
diff --git a/chromium/components/viz/service/display/overlay_processor_mac.h b/chromium/components/viz/service/display/overlay_processor_mac.h
index 03a8112ad4f..26e583a2b6b 100644
--- a/chromium/components/viz/service/display/overlay_processor_mac.h
+++ b/chromium/components/viz/service/display/overlay_processor_mac.h
@@ -35,6 +35,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorMac
bool DisableSplittingQuads() const override;
bool IsOverlaySupported() const override;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const override;
gfx::Rect GetAndResetOverlayDamage() override;
// Returns true if the platform supports hw overlays and surface occluding
diff --git a/chromium/components/viz/service/display/overlay_processor_ozone.cc b/chromium/components/viz/service/display/overlay_processor_ozone.cc
index 9dc16e17d09..9f3e7ef0679 100644
--- a/chromium/components/viz/service/display/overlay_processor_ozone.cc
+++ b/chromium/components/viz/service/display/overlay_processor_ozone.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/display/overlay_processor_ozone.h"
+#include "base/logging.h"
#include "components/viz/common/features.h"
#include "components/viz/service/display/overlay_strategy_fullscreen.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.cc b/chromium/components/viz/service/display/overlay_processor_stub.cc
index 799083887a6..0be55eec1c4 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.cc
+++ b/chromium/components/viz/service/display/overlay_processor_stub.cc
@@ -11,6 +11,10 @@ bool OverlayProcessorStub::IsOverlaySupported() const {
gfx::Rect OverlayProcessorStub::GetAndResetOverlayDamage() {
return gfx::Rect();
}
+gfx::Rect OverlayProcessorStub::GetPreviousFrameOverlaysBoundingRect() const {
+ return gfx::Rect();
+}
+
bool OverlayProcessorStub::NeedsSurfaceOccludingDamageRect() const {
return false;
}
diff --git a/chromium/components/viz/service/display/overlay_processor_stub.h b/chromium/components/viz/service/display/overlay_processor_stub.h
index 92069a7e077..1dee0517889 100644
--- a/chromium/components/viz/service/display/overlay_processor_stub.h
+++ b/chromium/components/viz/service/display/overlay_processor_stub.h
@@ -18,6 +18,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorStub
// Overrides OverlayProcessorInterface's pure virtual functions.
bool IsOverlaySupported() const final;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const final;
gfx::Rect GetAndResetOverlayDamage() final;
bool NeedsSurfaceOccludingDamageRect() const final;
void ProcessForOverlays(
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 a218f08c331..86b00f87f22 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.cc
@@ -35,6 +35,13 @@ OverlayProcessorUsingStrategy::OverlayProcessorUsingStrategy()
OverlayProcessorUsingStrategy::~OverlayProcessorUsingStrategy() = default;
+gfx::Rect OverlayProcessorUsingStrategy::GetPreviousFrameOverlaysBoundingRect()
+ const {
+ gfx::Rect result = overlay_damage_rect_;
+ result.Union(previous_frame_underlay_rect_);
+ return result;
+}
+
gfx::Rect OverlayProcessorUsingStrategy::GetAndResetOverlayDamage() {
gfx::Rect result = overlay_damage_rect_;
overlay_damage_rect_ = gfx::Rect();
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 f946919c378..faa34d1b99b 100644
--- a/chromium/components/viz/service/display/overlay_processor_using_strategy.h
+++ b/chromium/components/viz/service/display/overlay_processor_using_strategy.h
@@ -66,6 +66,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorUsingStrategy
~OverlayProcessorUsingStrategy() override;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const final;
gfx::Rect GetAndResetOverlayDamage() final;
// Override OverlayProcessor.
diff --git a/chromium/components/viz/service/display/overlay_processor_win.cc b/chromium/components/viz/service/display/overlay_processor_win.cc
index ffa85923c69..9c5b852fb69 100644
--- a/chromium/components/viz/service/display/overlay_processor_win.cc
+++ b/chromium/components/viz/service/display/overlay_processor_win.cc
@@ -27,6 +27,12 @@ bool OverlayProcessorWin::IsOverlaySupported() const {
return enable_dc_overlay_;
}
+gfx::Rect OverlayProcessorWin::GetPreviousFrameOverlaysBoundingRect() const {
+ // TODO(dcastagna): Implement me.
+ NOTIMPLEMENTED();
+ return gfx::Rect();
+}
+
gfx::Rect OverlayProcessorWin::GetAndResetOverlayDamage() {
return gfx::Rect();
}
diff --git a/chromium/components/viz/service/display/overlay_processor_win.h b/chromium/components/viz/service/display/overlay_processor_win.h
index f7863ad20da..95147c7dfc3 100644
--- a/chromium/components/viz/service/display/overlay_processor_win.h
+++ b/chromium/components/viz/service/display/overlay_processor_win.h
@@ -34,6 +34,7 @@ class VIZ_SERVICE_EXPORT OverlayProcessorWin
~OverlayProcessorWin() override;
bool IsOverlaySupported() const override;
+ gfx::Rect GetPreviousFrameOverlaysBoundingRect() const override;
gfx::Rect GetAndResetOverlayDamage() override;
// Returns true if the platform supports hw overlays and surface occluding
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 4d1fda11a4b..5436d5dea3c 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -6,6 +6,7 @@
#include "base/containers/adapters.h"
#include "base/lazy_instance.h"
+#include "base/logging.h"
#include "base/unguessable_token.h"
#include "build/chromecast_buildflags.h"
#include "components/viz/common/quads/draw_quad.h"
diff --git a/chromium/components/viz/service/display/program_binding.cc b/chromium/components/viz/service/display/program_binding.cc
index 0c246b056d8..975d1d01845 100644
--- a/chromium/components/viz/service/display/program_binding.cc
+++ b/chromium/components/viz/service/display/program_binding.cc
@@ -4,6 +4,7 @@
#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"
diff --git a/chromium/components/viz/service/display/program_binding.h b/chromium/components/viz/service/display/program_binding.h
index 19bf651da6a..bba6169e8ab 100644
--- a/chromium/components/viz/service/display/program_binding.h
+++ b/chromium/components/viz/service/display/program_binding.h
@@ -7,7 +7,7 @@
#include <string>
-#include "base/logging.h"
+#include "base/check_op.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "components/viz/common/gpu/context_provider.h"
diff --git a/chromium/components/viz/service/display/renderer_perftest.cc b/chromium/components/viz/service/display/renderer_perftest.cc
index 27ac29e25c9..19a0a751da4 100644
--- a/chromium/components/viz/service/display/renderer_perftest.cc
+++ b/chromium/components/viz/service/display/renderer_perftest.cc
@@ -58,6 +58,7 @@
#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gl/gl_implementation.h"
namespace viz {
@@ -296,6 +297,7 @@ class RendererPerfTest : public testing::Test {
GpuServiceImpl* gpu_service);
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)
@@ -685,6 +687,7 @@ class RendererPerfTest : public testing::Test {
std::unique_ptr<ClientResourceProvider> child_resource_provider_;
std::vector<TransferableResource> resource_list_;
base::LapTimer timer_;
+ std::unique_ptr<gl::DisableNullDrawGLBindings> enable_pixel_output_;
DISALLOW_COPY_AND_ASSIGN(RendererPerfTest);
};
diff --git a/chromium/components/viz/service/display/shader.h b/chromium/components/viz/service/display/shader.h
index 6d154b623cb..f64ae804946 100644
--- a/chromium/components/viz/service/display/shader.h
+++ b/chromium/components/viz/service/display/shader.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/logging.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "components/viz/service/viz_service_export.h"
diff --git a/chromium/components/viz/service/display/skia_readback_pixeltest.cc b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
index 93264575e8c..d2f1b7cc176 100644
--- a/chromium/components/viz/service/display/skia_readback_pixeltest.cc
+++ b/chromium/components/viz/service/display/skia_readback_pixeltest.cc
@@ -199,6 +199,9 @@ TEST_P(SkiaReadbackPixelTest, ExecutesCopyRequest) {
renderer_->DecideRenderPassAllocationsForFrame(pass_list);
renderer_->DrawFrame(&pass_list, 1.0f, kSourceSize,
gfx::DisplayColorSpaces());
+ // Call SwapBuffersSkipped(), so the renderer can have a chance to release
+ // resources.
+ renderer_->SwapBuffersSkipped();
loop.Run();
diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc
index 4a56dcc9a10..cff81b3c901 100644
--- a/chromium/components/viz/service/display/skia_renderer.cc
+++ b/chromium/components/viz/service/display/skia_renderer.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "base/bits.h"
#include "base/command_line.h"
+#include "base/logging.h"
#include "base/optional.h"
#include "base/synchronization/waitable_event.h"
#include "base/trace_event/trace_event.h"
@@ -63,6 +64,10 @@
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"
+#endif
+
namespace viz {
namespace {
@@ -836,8 +841,6 @@ void SkiaRenderer::BindFramebufferToOutputSurface() {
switch (draw_mode_) {
case DrawMode::DDL: {
root_canvas_ = skia_output_surface_->BeginPaintCurrentFrame();
- // TODO(https://crbug.com/1038107): Handle BeginPaintCurrentFrame() fail.
- CHECK(root_canvas_);
break;
}
case DrawMode::SKPRECORD: {
@@ -1119,12 +1122,25 @@ void SkiaRenderer::PrepareCanvasForRPDQ(const DrawRPDQParams& rpdq_params,
}
}
+ if (rpdq_params.mask_image.get()) {
+ // The old behavior (in skia) was to filter the clipmask based on the
+ // setting in the layer's paint. Now we can set that to whatever we want
+ // when we make the clip-shader. For now, I will replicate the old (impl)
+ // logic.
+ SkFilterQuality filtering =
+ layer_paint.getFilterQuality() == kNone_SkFilterQuality
+ ? kNone_SkFilterQuality
+ : kLow_SkFilterQuality;
+ current_canvas_->save();
+ current_canvas_->clipShader(rpdq_params.mask_image->makeShader(
+ SkTileMode::kClamp, SkTileMode::kClamp,
+ &rpdq_params.mask_to_quad_matrix, filtering));
+ }
SkRect bounds = gfx::RectFToSkRect(rpdq_params.bypass_clip.has_value()
? *rpdq_params.bypass_clip
: params->visible_rect);
- current_canvas_->saveLayer(SkCanvas::SaveLayerRec(
- &bounds, &layer_paint, backdrop_filter.get(),
- rpdq_params.mask_image.get(), &rpdq_params.mask_to_quad_matrix, 0));
+ current_canvas_->saveLayer(
+ SkCanvas::SaveLayerRec(&bounds, &layer_paint, backdrop_filter.get(), 0));
// If we have backdrop filtered content (and not transparent black like with
// regular render passes), we have to clear out the parts of the layer that
@@ -2167,11 +2183,47 @@ void SkiaRenderer::ScheduleOverlays() {
}
skia_output_surface_->ScheduleOverlays(
std::move(current_frame()->overlay_list), std::move(sync_tokens));
-#elif defined(OS_MACOSX) || defined(USE_OZONE)
+#elif defined(OS_MACOSX)
+ DCHECK(output_surface_->capabilities().supports_surfaceless);
+ auto& locks = pending_overlay_locks_.back();
+ std::vector<gpu::SyncToken> sync_tokens;
+ for (CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) {
+ // Some overlays are for solid-color layers.
+ if (!ca_layer_overlay.contents_resource_id)
+ continue;
+
+ // TODO(https://crbug.com/894929): Track IOSurface in-use instead of just
+ // unlocking after the next SwapBuffers is completed.
+ locks.emplace_back(resource_provider_,
+ ca_layer_overlay.contents_resource_id);
+ auto& lock = locks.back();
+
+ // Sync tokens ensure the texture to be overlaid is available before
+ // scheduling it for display.
+ if (lock.sync_token().HasData())
+ sync_tokens.push_back(lock.sync_token());
+
+ // Populate the |mailbox| of the CALayerOverlay which will be used to look
+ // up the corresponding GLImageIOSurface when building the CALayer tree.
+ ca_layer_overlay.mailbox = lock.mailbox();
+ DCHECK(!ca_layer_overlay.mailbox.IsZero());
+ }
+ skia_output_surface_->ScheduleOverlays(
+ std::move(current_frame()->overlay_list), std::move(sync_tokens));
+#elif defined(USE_OZONE)
+ // For platforms that don't support overlays, the
+ // current_frame()->overlay_list should be empty, and this code should not be
+ // reached.
+ if (!features::IsUsingOzonePlatform()) {
+ NOTREACHED();
+ return;
+ }
+
NOTIMPLEMENTED_LOG_ONCE();
#else
- // For platforms doesn't support overlays, the current_frame()->overlay_list
- // should be empty, and here should not be reached.
+ // For platforms that don't support overlays, the
+ // current_frame()->overlay_list should be empty, and this code should not be
+ // reached.
NOTREACHED();
#endif
}
@@ -2411,6 +2463,10 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad,
}
}
+ if (!content_image) {
+ return;
+ }
+
// If the RP generated mipmaps when it was created, set quality to medium,
// which turns on mipmap filtering in Skia.
if (backing.generate_mipmap)
@@ -2562,8 +2618,10 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
const RenderPassId& render_pass_id,
const RenderPassRequirements& requirements) {
auto it = render_pass_backings_.find(render_pass_id);
- if (it != render_pass_backings_.end())
+ if (it != render_pass_backings_.end()) {
+ DCHECK(gfx::Rect(it->second.size).Contains(gfx::Rect(requirements.size)));
return;
+ }
// TODO(penghuang): check supported format correctly.
gpu::Capabilities caps;
diff --git a/chromium/components/viz/service/display/software_renderer.cc b/chromium/components/viz/service/display/software_renderer.cc
index ebbaa150688..3321bf0001a 100644
--- a/chromium/components/viz/service/display/software_renderer.cc
+++ b/chromium/components/viz/service/display/software_renderer.cc
@@ -925,8 +925,11 @@ void SoftwareRenderer::AllocateRenderPassResourceIfNeeded(
const RenderPassId& render_pass_id,
const RenderPassRequirements& requirements) {
auto it = render_pass_bitmaps_.find(render_pass_id);
- if (it != render_pass_bitmaps_.end())
+ if (it != render_pass_bitmaps_.end()) {
+ DCHECK(it->second.width() >= requirements.size.width() &&
+ it->second.height() >= requirements.size.height());
return;
+ }
// The |requirements.mipmap| is only used for gpu-based rendering, so not used
// here.
diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc
index ea0032fe854..a94b9c8f540 100644
--- a/chromium/components/viz/service/display/surface_aggregator.cc
+++ b/chromium/components/viz/service/display/surface_aggregator.cc
@@ -118,39 +118,9 @@ struct SurfaceAggregator::RoundedCornerInfo {
bool is_fast_rounded_corner;
};
-struct SurfaceAggregator::ChildSurfaceInfo {
- struct QuadStateInfo {
- gfx::Transform transform_to_root_target;
- gfx::Transform quad_to_target_transform;
- gfx::Rect clip_rect;
- bool is_clipped;
- };
-
- ChildSurfaceInfo(RenderPassId parent_pass_id,
- const gfx::Rect& quad_rect,
- bool stretch_content_to_fill_bounds)
- : parent_pass_id(parent_pass_id),
- quad_rect(quad_rect),
- stretch_content_to_fill_bounds(stretch_content_to_fill_bounds) {
- // In most cases there would be one or two different embeddings of a
- // surface in the render pass tree. Reserve two elements to avoid
- // unnecessary copies.
- quad_state_infos.reserve(2);
- }
-
- RenderPassId parent_pass_id;
- gfx::Rect quad_rect;
- bool stretch_content_to_fill_bounds;
- bool has_moved_pixels = false;
- std::vector<QuadStateInfo> quad_state_infos;
-};
-
struct SurfaceAggregator::RenderPassMapEntry {
- RenderPassMapEntry(RenderPass* render_pass,
- bool has_pixel_moving_backdrop_filter)
- : render_pass(render_pass),
- damage_rect(render_pass->output_rect),
- has_pixel_moving_backdrop_filter(has_pixel_moving_backdrop_filter) {}
+ explicit RenderPassMapEntry(RenderPass* render_pass)
+ : render_pass(render_pass) {}
// Make this move-only.
RenderPassMapEntry(RenderPassMapEntry&&) = default;
@@ -161,12 +131,8 @@ struct SurfaceAggregator::RenderPassMapEntry {
RenderPass* render_pass;
// Damage rect of the render pass in its own content space.
gfx::Rect damage_rect;
- bool has_pixel_moving_backdrop_filter;
bool is_visited = false;
- // If the render pass contains any surfaces in its quad list, either from
- // SurfaceDrawQuads or from render passes referenced by RPDQs.
- bool contains_surfaces = false;
};
SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
@@ -198,18 +164,16 @@ SurfaceAggregator::GenerateRenderPassMap(const RenderPassList& render_pass_list,
// This data is created once and typically small or empty. Collect all items
// and pass to a flat_map to sort once.
std::vector<std::pair<RenderPassId, RenderPassMapEntry>> render_pass_data;
+ render_pass_data.reserve(render_pass_list.size());
for (const auto& render_pass : render_pass_list) {
- bool has_pixel_moving_backdrop_filter =
- render_pass->backdrop_filters.HasFilterThatMovesPixels();
- if (has_pixel_moving_backdrop_filter) {
+ if (render_pass->backdrop_filters.HasFilterThatMovesPixels()) {
DCHECK_NE(render_pass.get(), root_pass_in_root_surface)
<< "The root render pass on the root surface can not have backdrop "
"affecting filters";
}
- render_pass_data.emplace_back(
- std::piecewise_construct, std::forward_as_tuple(render_pass->id),
- std::forward_as_tuple(render_pass.get(),
- has_pixel_moving_backdrop_filter));
+ render_pass_data.emplace_back(std::piecewise_construct,
+ std::forward_as_tuple(render_pass->id),
+ std::forward_as_tuple(render_pass.get()));
}
return base::flat_map<RenderPassId, RenderPassMapEntry>(
std::move(render_pass_data));
@@ -308,15 +272,25 @@ gfx::Rect SurfaceAggregator::CalculateOccludingSurfaceDamageRect(
// Transform the quad to the parent root target space
// Note: this quad is on the child root render pass.
- gfx::Transform transform(parent_quad_to_root_target_transform,
- quad->shared_quad_state->quad_to_target_transform);
- gfx::Rect surface_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(transform, quad->visible_rect);
+ gfx::Rect quad_in_root_target_space;
+ if (quad->shared_quad_state->is_clipped) {
+ gfx::Rect quad_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad->visible_rect);
+ quad_in_target_space.Intersect(quad->shared_quad_state->clip_rect);
+ quad_in_root_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ parent_quad_to_root_target_transform, quad_in_target_space);
+
+ } else {
+ gfx::Transform transform(parent_quad_to_root_target_transform,
+ quad->shared_quad_state->quad_to_target_transform);
+ quad_in_root_target_space =
+ cc::MathUtil::MapEnclosingClippedRect(transform, quad->visible_rect);
+ }
// damage_rects_union_of_surfaces_on_top_ is already in the parent root target
// space.
gfx::Rect occluding_damage_rect = damage_rects_union_of_surfaces_on_top_;
- occluding_damage_rect.Intersect(surface_in_root_target_space);
+ occluding_damage_rect.Intersect(quad_in_root_target_space);
return occluding_damage_rect;
}
@@ -560,6 +534,12 @@ void SurfaceAggregator::EmitSurfaceContent(
CanMergeRoundedCorner(rounded_corner_info, *render_pass_list.back()) &&
source_sqs->de_jelly_delta_y == 0;
+ if (frame.metadata.delegated_ink_metadata) {
+ TransformAndStoreDelegatedInkMetadata(
+ gfx::Transform(dest_pass->transform_to_root_target, combined_transform),
+ frame.metadata.delegated_ink_metadata.get());
+ }
+
gfx::Rect occluding_damage_rect;
bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage(
surface, render_pass_list, combined_transform, dest_pass,
@@ -702,14 +682,23 @@ void SurfaceAggregator::EmitSurfaceContent(
// We can't produce content outside of |quad_rect|, so clip the visible
// rect if necessary.
quad_visible_rect.Intersect(quad_rect);
-
- auto* quad = dest_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
RenderPassId remapped_pass_id = RemapPassId(last_pass.id, surface_id);
- quad->SetNew(shared_quad_state, quad_rect, quad_visible_rect,
- remapped_pass_id, 0, gfx::RectF(), gfx::Size(),
- gfx::Vector2dF(), gfx::PointF(), tex_coord_rect,
- /*force_anti_aliasing_off=*/false,
- /* backdrop_filter_quality*/ 1.0f);
+ if (quad_visible_rect.IsEmpty()) {
+ dest_pass_list_->erase(
+ std::remove_if(
+ dest_pass_list_->begin(), dest_pass_list_->end(),
+ [&remapped_pass_id](const std::unique_ptr<RenderPass>& pass) {
+ return pass->id == remapped_pass_id;
+ }),
+ dest_pass_list_->end());
+ } else {
+ auto* quad = dest_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
+ quad->SetNew(shared_quad_state, quad_rect, quad_visible_rect,
+ remapped_pass_id, 0, gfx::RectF(), gfx::Size(),
+ gfx::Vector2dF(), gfx::PointF(), tex_coord_rect,
+ /*force_anti_aliasing_off=*/false,
+ /* backdrop_filter_quality*/ 1.0f);
+ }
}
referenced_surfaces_.erase(surface_id);
@@ -1144,6 +1133,13 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame,
const gfx::Transform surface_transform =
IsRootSurface(surface) ? root_surface_transform_ : gfx::Transform();
+ if (frame.metadata.delegated_ink_metadata) {
+ TransformAndStoreDelegatedInkMetadata(
+ gfx::Transform(source_pass_list.back()->transform_to_root_target,
+ surface_transform),
+ frame.metadata.delegated_ink_metadata.get());
+ }
+
gfx::Rect occluding_damage_rect;
bool occluding_damage_rect_valid = ProcessSurfaceOccludingDamage(
surface, source_pass_list, surface_transform,
@@ -1235,125 +1231,52 @@ void SurfaceAggregator::ProcessAddedAndRemovedSurfaces() {
}
}
-void SurfaceAggregator::FindChildSurfaces(
- SurfaceId surface_id,
+gfx::Rect SurfaceAggregator::PrewalkRenderPass(
+ RenderPassId render_pass_id,
+ const Surface* surface,
base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
- RenderPassMapEntry* current_pass_entry,
+ bool will_draw,
const gfx::Transform& transform_to_root_target,
- base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
std::vector<gfx::Rect>* pixel_moving_backdrop_filters_rects,
- bool* has_backdrop_cache_flags_to_update) {
- if (current_pass_entry->is_visited) {
- // This means that this render pass is an ancestor of itself. This is not
- // supported. Stop processing the render pass again.
- return;
+ PrewalkResult* result) {
+ auto it = render_pass_map->find(render_pass_id);
+ DCHECK(it != render_pass_map->end());
+ RenderPassMapEntry& render_pass_entry = it->second;
+ if (render_pass_entry.is_visited) {
+ // This render pass is an ancestor of itself (not supported) or has been
+ // processed.
+ return render_pass_entry.damage_rect;
}
- base::AutoReset<bool> reset_is_visited(&current_pass_entry->is_visited, true);
- RenderPass* render_pass = current_pass_entry->render_pass;
- if (current_pass_entry->has_pixel_moving_backdrop_filter) {
+ render_pass_entry.is_visited = true;
+ const RenderPass& render_pass = *render_pass_entry.render_pass;
+
+ if (render_pass.backdrop_filters.HasFilterThatMovesPixels()) {
has_pixel_moving_backdrop_filter_ = true;
// If the render pass has a backdrop filter that moves pixels, its entire
// bounds, with proper transform applied, may be added to the damage
// rect if it intersects.
pixel_moving_backdrop_filters_rects->push_back(
cc::MathUtil::MapEnclosingClippedRect(transform_to_root_target,
- render_pass->output_rect));
+ render_pass.output_rect));
}
- RenderPassId remapped_pass_id = RemapPassId(render_pass->id, surface_id);
- bool has_pixel_moving_filter =
- render_pass->filters.HasFilterThatMovesPixels();
+
+ RenderPassId remapped_pass_id =
+ RemapPassId(render_pass.id, surface->surface_id());
+ // |moved_pixel_passes_| stores all the render passes affected by filters
+ // that move pixels, so |has_pixel_moving_filter| should be set to true either
+ // if the current render pass has pixel_moving_filter(s) or if it is inside an
+ // ancestor render pass that has pixel_moving_filter(s).
+ bool has_pixel_moving_filter = render_pass.filters.HasFilterThatMovesPixels();
if (has_pixel_moving_filter)
moved_pixel_passes_.insert(remapped_pass_id);
bool in_moved_pixel_pass =
has_pixel_moving_filter ||
base::Contains(moved_pixel_passes_, remapped_pass_id);
- for (auto* quad : render_pass->quad_list) {
- if (quad->material == DrawQuad::Material::kSurfaceContent) {
- // A child surface has been found. Add necessary info from this surface to
- // the set of child surfaces that can be used to update damage rect for
- // the parent surface. If this child surface has been visited previously,
- // we only need to update |has_moved_pixels| and add the transform
- // corresponding to this visit; rest of the info would remain the same.
- const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
- auto it = child_surfaces->find(surface_quad->surface_range);
- if (it == child_surfaces->end()) {
- auto insert_pair = child_surfaces->emplace(
- std::piecewise_construct,
- std::forward_as_tuple(surface_quad->surface_range),
- std::forward_as_tuple(
- remapped_pass_id, surface_quad->rect,
- surface_quad->stretch_content_to_fill_bounds));
- DCHECK(insert_pair.second);
- it = insert_pair.first;
- }
- auto& child_surface_info = it->second;
- if (in_moved_pixel_pass)
- child_surface_info.has_moved_pixels = true;
- child_surface_info.quad_state_infos.push_back(
- {transform_to_root_target,
- surface_quad->shared_quad_state->quad_to_target_transform,
- surface_quad->shared_quad_state->clip_rect,
- surface_quad->shared_quad_state->is_clipped});
- current_pass_entry->contains_surfaces = true;
- } else if (quad->material == DrawQuad::Material::kRenderPass) {
- // A child render pass has been found. Find its child surfaces
- // recursively.
- const auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
- *has_backdrop_cache_flags_to_update |=
- render_pass_quad->can_use_backdrop_filter_cache;
- RenderPassId child_pass_id = render_pass_quad->render_pass_id;
- RenderPassId remapped_child_pass_id =
- RemapPassId(child_pass_id, surface_id);
- if (in_moved_pixel_pass)
- moved_pixel_passes_.insert(remapped_child_pass_id);
- auto child_pass_it = render_pass_map->find(child_pass_id);
- DCHECK(child_pass_it != render_pass_map->end());
- RenderPassMapEntry& child_pass_entry = child_pass_it->second;
- // TODO(crbug/1011042): Here, we used to set |in_moved_pixel_pass| to true
- // if the child render pass has a pixel-moving backdrop filter. This
- // behavior was added in r687426 to fix another problem, but caused a huge
- // performance issue in some cases that enabled background blur, by
- // expanding the damage rect unnecessarily to the entire screen
- // (crbug/1008740). This is removed now, but a proper fix for the
- // pixel-moving backdrop filter should be implemented.
- render_pass_dependencies_[remapped_pass_id].insert(
- remapped_child_pass_id);
- FindChildSurfaces(
- surface_id, render_pass_map, &child_pass_entry,
- gfx::Transform(
- transform_to_root_target,
- render_pass_quad->shared_quad_state->quad_to_target_transform),
- child_surfaces, pixel_moving_backdrop_filters_rects,
- has_backdrop_cache_flags_to_update);
- current_pass_entry->contains_surfaces |=
- child_pass_entry.contains_surfaces;
- }
- }
-}
-gfx::Rect
-SurfaceAggregator::UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- RenderPassId id,
- PrewalkResult* result,
- base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map) {
- auto render_pass_it = render_pass_map->find(id);
- DCHECK(render_pass_it != render_pass_map->end());
- RenderPassMapEntry& render_pass_entry = render_pass_it->second;
-
- // If there's no surface embedded in the render pass, return an empty rect.
- if (!render_pass_entry.contains_surfaces)
- return gfx::Rect();
-
- if (render_pass_entry.is_visited) {
- // This render pass is an ancestor of itself (not supported) or has been
- // processed.
- return render_pass_entry.damage_rect;
- }
- render_pass_entry.is_visited = true;
+ const CompositorFrame& frame = surface->GetActiveFrame();
+ gfx::Rect full_damage = frame.render_pass_list.back()->output_rect;
- const RenderPass& render_pass = *render_pass_entry.render_pass;
gfx::Rect damage_rect;
-
// Iterate through the quad list back-to-front and accumulate damage from
// all quads (only SurfaceDrawQuads and RenderPassDrawQuads can have damage
// at this point). |damage_rect| has damage from all quads below the current
@@ -1362,36 +1285,50 @@ SurfaceAggregator::UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
for (QuadList::ConstReverseIterator it = render_pass.quad_list.rbegin();
it != render_pass.quad_list.rend(); ++it) {
const DrawQuad* quad = *it;
+ gfx::Rect quad_damage_rect;
if (quad->material == DrawQuad::Material::kSurfaceContent) {
const auto* surface_quad = SurfaceDrawQuad::MaterialCast(quad);
- Surface* surface =
+ Surface* child_surface =
manager_->GetLatestInFlightSurface(surface_quad->surface_range);
- auto it = result->damage_on_surfaces.end();
- if (surface)
- it = result->damage_on_surfaces.find(surface->surface_id());
- if (it != result->damage_on_surfaces.end()) {
- gfx::Rect surface_damage_rect = it->second;
+ // If the primary surface is not available then we assume the damage is
+ // the full size of the SurfaceDrawQuad because we might need to introduce
+ // gutter.
+ if (!child_surface ||
+ child_surface->surface_id() != surface_quad->surface_range.end()) {
+ quad_damage_rect = quad->rect;
+ }
+
+ if (child_surface) {
+ gfx::Rect child_rect;
+ auto it = result->damage_on_surfaces.find(child_surface->surface_id());
+ if (it != result->damage_on_surfaces.end()) {
+ // the surface damage has been accummulated previously
+ child_rect = it->second;
+ } else {
+ // first encounter of the surface
+ child_rect = PrewalkSurface(child_surface, in_moved_pixel_pass,
+ remapped_pass_id, will_draw, result);
+ }
+
if (surface_quad->stretch_content_to_fill_bounds) {
- if (surface->size_in_pixels().GetCheckedArea().ValueOrDefault(0) >
- 0) {
+ if (!child_surface->size_in_pixels().IsEmpty()) {
float y_scale = static_cast<float>(surface_quad->rect.height()) /
- surface->size_in_pixels().height();
+ child_surface->size_in_pixels().height();
float x_scale = static_cast<float>(surface_quad->rect.width()) /
- surface->size_in_pixels().width();
- surface_damage_rect = gfx::ScaleToEnclosingRect(surface_damage_rect,
- x_scale, y_scale);
+ child_surface->size_in_pixels().width();
+ child_rect =
+ gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale);
}
}
- gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
- quad->shared_quad_state->quad_to_target_transform,
- surface_damage_rect);
- damage_rect.Union(rect_in_target_space);
- } else {
- // The damage info was not found for the (probably invalid) surface,
- // take the whole quad rect as damaged.
- gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
- quad->shared_quad_state->quad_to_target_transform, quad->rect);
- damage_rect.Union(rect_in_target_space);
+ quad_damage_rect.Union(child_rect);
+ }
+
+ if (quad_damage_rect.IsEmpty())
+ continue;
+
+ if (in_moved_pixel_pass) {
+ damage_rect = full_damage;
+ continue;
}
} else if (quad->material == DrawQuad::Material::kRenderPass) {
auto* render_pass_quad = RenderPassDrawQuad::MaterialCast(quad);
@@ -1406,28 +1343,42 @@ SurfaceAggregator::UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
render_pass_quad->can_use_backdrop_filter_cache = false;
}
- gfx::Rect render_pass_damage_rect =
- UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- render_pass_quad->render_pass_id, result, render_pass_map);
+ RenderPassId child_pass_id = render_pass_quad->render_pass_id;
+ RenderPassId remapped_child_pass_id =
+ RemapPassId(child_pass_id, surface->surface_id());
+ if (in_moved_pixel_pass)
+ moved_pixel_passes_.insert(remapped_child_pass_id);
- gfx::Rect rect = cc::MathUtil::MapEnclosingClippedRect(
- render_pass_quad->shared_quad_state->quad_to_target_transform,
- render_pass_damage_rect);
- damage_rect.Union(rect);
+ render_pass_dependencies_[remapped_pass_id].insert(
+ remapped_child_pass_id);
+ quad_damage_rect = PrewalkRenderPass(
+ child_pass_id, surface, render_pass_map, will_draw,
+ gfx::Transform(
+ transform_to_root_target,
+ render_pass_quad->shared_quad_state->quad_to_target_transform),
+ pixel_moving_backdrop_filters_rects, result);
+
+ } else {
+ continue;
}
+ // Convert the quad damage rect into its target space and clip it
+ // if needed.
+ gfx::Rect rect_in_target_space = cc::MathUtil::MapEnclosingClippedRect(
+ quad->shared_quad_state->quad_to_target_transform, quad_damage_rect);
+ if (quad->shared_quad_state->is_clipped) {
+ rect_in_target_space.Intersect(quad->shared_quad_state->clip_rect);
+ }
+ damage_rect.Union(rect_in_target_space);
}
render_pass_entry.damage_rect = damage_rect;
return damage_rect;
}
-// Walk the Surface tree from surface_id. Validate the resources of the current
-// surface and its descendants, check if there are any copy requests, and
-// return the combined damage rect.
-gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
- bool in_moved_pixel_surface,
- int parent_pass_id,
- bool will_draw,
- PrewalkResult* result) {
+gfx::Rect SurfaceAggregator::PrewalkSurface(Surface* surface,
+ bool in_moved_pixel_surface,
+ int parent_pass_id,
+ bool will_draw,
+ PrewalkResult* result) {
if (referenced_surfaces_.count(surface->surface_id()))
return gfx::Rect();
@@ -1470,17 +1421,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
base::flat_map<RenderPassId, RenderPassMapEntry> render_pass_map =
GenerateRenderPassMap(frame.render_pass_list, IsRootSurface(surface));
- auto root_pass_it = render_pass_map.find(frame.render_pass_list.back()->id);
- DCHECK(root_pass_it != render_pass_map.end());
- RenderPassMapEntry& root_pass_entry = root_pass_it->second;
- base::flat_map<SurfaceRange, ChildSurfaceInfo> child_surfaces;
- std::vector<gfx::Rect> pixel_moving_backdrop_filters_rects;
- bool has_backdrop_cache_flags_to_update = false;
- FindChildSurfaces(surface->surface_id(), &render_pass_map, &root_pass_entry,
- root_pass_transform, &child_surfaces,
- &pixel_moving_backdrop_filters_rects,
- &has_backdrop_cache_flags_to_update);
-
std::vector<ResourceId> referenced_resources;
referenced_resources.reserve(frame.resource_list.size());
@@ -1518,82 +1458,12 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
// Avoid infinite recursion by adding current surface to
// |referenced_surfaces_|.
referenced_surfaces_.insert(surface->surface_id());
- for (const auto& child_surface_info_pair : child_surfaces) {
- auto& child_surface_range = child_surface_info_pair.first;
- auto& child_surface_info = child_surface_info_pair.second;
- // TODO(fsamuel): Consider caching this value somewhere so that
- // HandleSurfaceQuad doesn't need to call it again.
- Surface* child_surface =
- manager_->GetLatestInFlightSurface(child_surface_range);
-
- // If the primary surface is not available then we assume the damage is
- // the full size of the SurfaceDrawQuad because we might need to introduce
- // gutter.
- gfx::Rect child_surface_damage;
- if (!child_surface ||
- child_surface->surface_id() != child_surface_range.end()) {
- child_surface_damage = child_surface_info.quad_rect;
- }
-
- if (child_surface) {
- if (child_surface_info.stretch_content_to_fill_bounds) {
- // Scale up the damage_quad generated by the child_surface to fit
- // the containing quad_rect.
- gfx::Rect child_rect =
- PrewalkTree(child_surface, child_surface_info.has_moved_pixels,
- child_surface_info.parent_pass_id, will_draw, result);
- if (child_surface->size_in_pixels().GetCheckedArea().ValueOrDefault(0) >
- 0) {
- float y_scale =
- static_cast<float>(child_surface_info.quad_rect.height()) /
- child_surface->size_in_pixels().height();
- float x_scale =
- static_cast<float>(child_surface_info.quad_rect.width()) /
- child_surface->size_in_pixels().width();
- child_surface_damage.Union(
- gfx::ScaleToEnclosingRect(child_rect, x_scale, y_scale));
- }
- } else {
- child_surface_damage.Union(
- PrewalkTree(child_surface, child_surface_info.has_moved_pixels,
- child_surface_info.parent_pass_id, will_draw, result));
- }
- }
-
- if (child_surface_damage.IsEmpty())
- continue;
-
- if (child_surface_info.has_moved_pixels) {
- // Areas outside the rect hit by target_to_surface_transform may be
- // modified if there is a filter that moves pixels.
- damage_rect = full_damage;
- continue;
- }
-
- // Add the child surface damage rect to the parent surface damage rect. The
- // child surface damage rect is first transformed to the parent surface
- // coordinate space. There would be multiple transforms for a child surface
- // if it is embedded multiple times which means its damage rect should be
- // added multiple times.
- for (const auto& quad_state_info : child_surface_info.quad_state_infos) {
- gfx::Transform target_to_surface_transform(
- quad_state_info.transform_to_root_target,
- quad_state_info.quad_to_target_transform);
-
- gfx::Rect child_surface_damage_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(target_to_surface_transform,
- child_surface_damage);
- if (quad_state_info.is_clipped) {
- gfx::Rect clip_rect_in_root_target_space =
- cc::MathUtil::MapEnclosingClippedRect(
- quad_state_info.transform_to_root_target,
- quad_state_info.clip_rect);
- child_surface_damage_in_root_target_space.Intersect(
- clip_rect_in_root_target_space);
- }
- damage_rect.Union(child_surface_damage_in_root_target_space);
- }
- }
+ std::vector<gfx::Rect> pixel_moving_backdrop_filters_rects;
+ const gfx::Rect surface_root_damage = PrewalkRenderPass(
+ frame.render_pass_list.back()->id, surface, &render_pass_map, will_draw,
+ root_pass_transform, &pixel_moving_backdrop_filters_rects, result);
+ damage_rect.Union(cc::MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(
+ root_pass_transform, surface_root_damage));
if (!damage_rect.IsEmpty()) {
// The following call can cause one or more copy requests to be added to the
@@ -1635,7 +1505,7 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
result->undrawn_surfaces.insert(surface_id);
Surface* undrawn_surface = manager_->GetSurfaceForId(surface_id);
if (undrawn_surface)
- PrewalkTree(undrawn_surface, false, 0, false /* will_draw */, result);
+ PrewalkSurface(undrawn_surface, false, 0, /*will_draw=*/false, result);
}
}
@@ -1673,11 +1543,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
std::forward_as_tuple(damage_rect));
DCHECK(emplace_result.second);
- if (has_backdrop_cache_flags_to_update) {
- UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- frame.render_pass_list.back()->id, result, &render_pass_map);
- }
-
return damage_rect;
}
@@ -1763,6 +1628,7 @@ CompositorFrame SurfaceAggregator::Aggregate(
const SurfaceId& surface_id,
base::TimeTicks expected_display_time,
gfx::OverlayTransform display_transform,
+ const gfx::Rect& target_damage,
int64_t display_trace_id) {
DCHECK(!expected_display_time.is_null());
@@ -1810,8 +1676,14 @@ CompositorFrame SurfaceAggregator::Aggregate(
new_surfaces_.clear();
DCHECK(referenced_surfaces_.empty());
PrewalkResult prewalk_result;
- root_damage_rect_ =
- PrewalkTree(surface, false, 0, true /* will_draw */, &prewalk_result);
+ gfx::Rect surfaces_damage_rect =
+ PrewalkSurface(surface, false, 0, /*will_draw=*/true, &prewalk_result);
+
+ root_damage_rect_ = surfaces_damage_rect;
+ // |root_damage_rect_| is used to restrict aggregating quads only if they
+ // intersect this area.
+ root_damage_rect_.Union(target_damage);
+
root_content_color_usage_ = prewalk_result.content_color_usage;
if (prewalk_result.frame_sinks_changed)
@@ -1827,6 +1699,15 @@ CompositorFrame SurfaceAggregator::Aggregate(
CopyPasses(root_surface_frame, surface);
referenced_surfaces_.erase(surface_id);
+ // The root render pass damage might have been expanded by target_damage (the
+ // area that might need to be recomposited on the target surface). We restrict
+ // the damage_rect of the root render pass to the one caused by the source
+ // surfaces.
+ // The damage on the root render pass should not include the expanded area
+ // since Renderer and OverlayProcessor expect the non expanded damage.
+ if (!RenderPassNeedsFullDamage(dest_pass_list_->back().get()))
+ dest_pass_list_->back()->damage_rect.Intersect(surfaces_damage_rect);
+
// Now that we've handled our main surface aggregation, apply de-jelly effect
// if enabled.
if (de_jelly_enabled_)
@@ -1875,6 +1756,8 @@ CompositorFrame SurfaceAggregator::Aggregate(
}
}
+ frame.metadata.delegated_ink_metadata = std::move(delegated_ink_metadata_);
+
if (frame_annotator_)
frame_annotator_->AnnotateAggregatedFrame(&frame);
@@ -1941,6 +1824,43 @@ bool SurfaceAggregator::IsRootSurface(const Surface* surface) const {
return surface->surface_id() == root_surface_id_;
}
+// Transform the point and presentation area of the metadata to be in the root
+// target space. They need to be in the root target space because they will
+// eventually be drawn directly onto the buffer just before being swapped onto
+// the screen, so root target space is required so that they are positioned
+// correctly. After transforming, they are stored in the
+// |delegated_ink_metadata_| member in order to be placed on the final
+// aggregated frame, after which the member is then cleared.
+void SurfaceAggregator::TransformAndStoreDelegatedInkMetadata(
+ const gfx::Transform& parent_quad_to_root_target_transform,
+ DelegatedInkMetadata* metadata) {
+ if (delegated_ink_metadata_) {
+ // This member could already be populated in two scenarios:
+ // 1. The delegated ink metadata was committed to a frame's metadata that
+ // wasn't ultimately used to produce a frame, but is now being used.
+ // 2. There are two or more ink strokes requesting a delegated ink trail
+ // simultaneously.
+ // In both cases, we want to default to using a "last write wins" strategy
+ // to determine the metadata to put on the final aggregated frame. This
+ // avoids potential issues of using stale ink metadata in the first scenario
+ // by always using the newest one. For the second scenario, it would be a
+ // very niche use case to have more than one at a time, so the explainer
+ // specifies using last write wins to decide.
+ base::TimeTicks stored_time = delegated_ink_metadata_->timestamp();
+ base::TimeTicks new_time = metadata->timestamp();
+ if (new_time < stored_time)
+ return;
+ }
+
+ gfx::PointF point(metadata->point());
+ gfx::RectF area(metadata->presentation_area());
+ parent_quad_to_root_target_transform.TransformPoint(&point);
+ parent_quad_to_root_target_transform.TransformRect(&area);
+ delegated_ink_metadata_ = std::make_unique<DelegatedInkMetadata>(
+ point, metadata->diameter(), metadata->color(), metadata->timestamp(),
+ area);
+}
+
void SurfaceAggregator::HandleDeJelly(Surface* surface) {
TRACE_EVENT0("viz", "SurfaceAggregator::HandleDeJelly");
diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h
index 6da752f8739..9f3c9a41a79 100644
--- a/chromium/components/viz/service/display/surface_aggregator.h
+++ b/chromium/components/viz/service/display/surface_aggregator.h
@@ -8,11 +8,14 @@
#include <memory>
#include <string>
#include <unordered_map>
+#include <utility>
+#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "components/viz/common/delegated_ink_metadata.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/common/resources/transferable_resource.h"
@@ -50,9 +53,14 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
bool needs_surface_occluding_damage_rect);
~SurfaceAggregator();
+ // |target_damage| represents an area on the output surface that might have
+ // been invalidated. It can be used in cases where we still want to support
+ // partial damage but the target surface might need contents outside the
+ // damage rect of the root surface.
CompositorFrame Aggregate(const SurfaceId& surface_id,
base::TimeTicks expected_display_time,
gfx::OverlayTransform display_transform,
+ const gfx::Rect& target_damage = gfx::Rect(),
int64_t display_trace_id = -1);
void ReleaseResources(const SurfaceId& surface_id);
const SurfaceIndexMap& previous_contained_surfaces() const {
@@ -181,61 +189,42 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const gfx::Rect& occluding_damage_rect,
bool occluding_damage_rect_valid);
- // Helper function that uses backtracking on the render pass tree of a surface
- // to find all surfaces embedded in it. If a surface is embedded multiple
- // times (due to use of a MirrorLayer), it will be reachable via multiple
- // paths from the root render pass. For each such a path the appropriate
- // transform is calculated.
- // - |surface_id| specifies the surface to find all child surfaces of.
- // - |render_pass_map| is a pre-computed map from render pass id to some info
- // about the render pass, including the render pass itself and whether it
- // has pixel moving backdrop filter.
- // - |current_pass_entry| is the info about the current render pass to
- // process.
+ // Recursively walks through the render pass and updates the
+ // |can_use_backdrop_filter_cache| flag on all RenderPassDrawQuads(RPDQ).
+ // The function returns the damage rect of the render pass in its own content
+ // space.
+ // - |render_pass_id| specifies the id of the render pass.
+ // - |surface| is the surface containing the render pass.
+ // - |render_pass_map| is a map that contains all render passes and their
+ // entry data.
+ // - |will_draw| indicates that the surface can be aggregated into the final
+ // frame and might be drawn (based on damage/occlusion/etc.) if it is set
+ // to true. Or the surface isn't in the aggregated frame and is only
+ // needed for CopyOutputRequests if set to false.
// - |transform_to_root_target| is the accumulated transform of all render
- // passes along the way to the current render pass.
- // - |child_surfaces| is the main output of the function containing all child
- // surfaces found in the process.
- // - |pixel_moving_backdrop_filters_rect| is another output that is union of
- // bounds of render passes that have a pixel moving backdrop filter.
- // - |has_backdrop_cache_flags_to_update| indicates if any
- // RenderPassDrawQuad(s) contained in the surface have
- // |can_use_backdrop_filter_cache| flag set to true and having to be
- // updated. This is used to avoid iterating through all the render passes
- // in the surface frame when not needed (i.e. no flag needs to be
- // updated).
- // TODO(mohsen): Consider refactoring this backtracking algorithm into a
- // self-contained class.
- void FindChildSurfaces(
- SurfaceId surface_id,
+ // passes in the containing surface along the way to the current render
+ // pass.
+ // - |pixel_moving_backdrop_filters_rects| is a vector of bounds of render
+ // passes that have a pixel moving backdrop filter.
+ // - |result| is the result of a prewalk of the surface that contains the
+ // render pass.
+ gfx::Rect PrewalkRenderPass(
+ RenderPassId render_pass_id,
+ const Surface* surface,
base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map,
- RenderPassMapEntry* current_pass_entry,
+ bool will_draw,
const gfx::Transform& transform_to_root_target,
- base::flat_map<SurfaceRange, ChildSurfaceInfo>* child_surfaces,
std::vector<gfx::Rect>* pixel_moving_backdrop_filters_rects,
- bool* has_backdrop_cache_flags_to_update);
-
- // Recursively updates the |can_use_backdrop_filter_cache| flag on all
- // RenderPassDrawQuads(RPDQ) in the specified render pass. The function
- // recursively traverses any render pass referenced by a RPDQ but doesn't
- // traverse any render passes in the frame of any embedded surfaces. The
- // function returns the damage rect of the render pass in its own content
- // space.
- // - |id| specifies the render pass whose quads are to be updated
- // - |result| is the result of a prewalk of a root surface that contains the
- // render pass
- // - |render_pass_map| is a map that contains all render passes and their
- // entry data
- gfx::Rect UpdateRPDQCanUseBackdropFilterCacheWithSurfaceDamage(
- RenderPassId id,
- PrewalkResult* result,
- base::flat_map<RenderPassId, RenderPassMapEntry>* render_pass_map);
-
- gfx::Rect PrewalkTree(Surface* surface,
- bool in_moved_pixel_surface,
- int parent_pass,
- bool will_draw,
- PrewalkResult* result);
+ PrewalkResult* result);
+
+ // Walk the Surface tree from |surface|. Validate the resources of the
+ // current surface and its descendants, check if there are any copy requests,
+ // and return the combined damage rect.
+ gfx::Rect PrewalkSurface(Surface* surface,
+ bool in_moved_pixel_surface,
+ int parent_pass,
+ bool will_draw,
+ PrewalkResult* result);
void CopyUndrawnSurfaces(PrewalkResult* prewalk);
void CopyPasses(const CompositorFrame& frame, Surface* surface);
void AddColorConversionPass();
@@ -276,6 +265,15 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
static void UnrefResources(base::WeakPtr<SurfaceClient> surface_client,
const std::vector<ReturnedResource>& resources);
+ // This method transforms the delegated ink metadata to be in the root target
+ // space, so that it can eventually be drawn onto the back buffer in the
+ // correct position. It should only ever be called when a frame contains
+ // delegated ink metadata, in which case this function will transform it and
+ // then store it in the |delegated_ink_metadata_| member.
+ void TransformAndStoreDelegatedInkMetadata(
+ const gfx::Transform& parent_quad_to_root_target_transform,
+ DelegatedInkMetadata* metadata);
+
// De-Jelly Effect:
// HandleDeJelly applies a de-jelly transform to quads in the root render
// pass.
@@ -436,6 +434,13 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
// production on Windows only (does not interact with jelly).
bool last_frame_had_color_conversion_pass_ = false;
+ // The metadata used for drawing a delegated ink trail on the end of a normal
+ // ink stroke. It needs to be transformed to root coordinates and then put on
+ // the final aggregated frame. This is only populated during aggregation when
+ // a surface contains delegated ink metadata on its frame, and it is cleared
+ // after it is placed on the final aggregated frame during aggregation.
+ std::unique_ptr<DelegatedInkMetadata> delegated_ink_metadata_;
+
base::WeakPtrFactory<SurfaceAggregator> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SurfaceAggregator);
diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
index 0a3f1ae681d..085c6cd27cb 100644
--- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
@@ -7,6 +7,8 @@
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
+#include <map>
#include <set>
#include <utility>
#include <vector>
@@ -132,10 +134,11 @@ class SurfaceAggregatorTest : public testing::Test, public DisplayTimeSource {
testing::Test::TearDown();
}
- CompositorFrame AggregateFrame(const SurfaceId& surface_id) {
+ CompositorFrame AggregateFrame(const SurfaceId& surface_id,
+ gfx::Rect target_damage = gfx::Rect()) {
return aggregator_.Aggregate(
surface_id, GetNextDisplayTimeAndIncrement(),
- gfx::OVERLAY_TRANSFORM_NONE /* display_transform */);
+ /*display_transform=*/gfx::OVERLAY_TRANSFORM_NONE, target_damage);
}
struct Quad {
@@ -4399,6 +4402,133 @@ TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
}
}
+TEST_F(SurfaceAggregatorPartialSwapTest, ExpandByTargetDamage) {
+ ParentLocalSurfaceIdAllocator allocator;
+ allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ constexpr float device_scale_factor = 1.0f;
+
+ // The child surface has one quad.
+ {
+ int child_pass_id = 1;
+ std::vector<Quad> child_quads1 = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_passes = {
+ Pass(child_quads1, child_pass_id, gfx::Rect(5, 5))};
+
+ RenderPassList child_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&child_pass_list, child_passes, &referenced_surfaces);
+
+ SubmitPassListAsFrame(child_sink_.get(), child_local_surface_id,
+ &child_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ {
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(SurfaceSize()), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ RenderPassList root_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&root_pass_list, root_passes, &referenced_surfaces);
+ // No damage, this is the first frame submitted, so all quads should be
+ // produced.
+ SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
+ &root_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
+
+ ASSERT_EQ(1u, aggregated_pass_list.size());
+
+ // Damage rect for first aggregation should contain entire root surface.
+ EXPECT_EQ(gfx::Rect(SurfaceSize()), aggregated_pass_list.back()->damage_rect);
+ EXPECT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
+
+ // Create a root surface with a smaller damage rect.
+ // This time the damage should be smaller.
+ {
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(SurfaceSize()), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ RenderPassList root_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&root_pass_list, root_passes, &referenced_surfaces);
+
+ auto* root_pass = root_pass_list[0].get();
+ root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
+ SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
+ &root_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ {
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
+
+ ASSERT_EQ(1u, aggregated_pass_list.size());
+
+ // No quads inside the damage
+ EXPECT_EQ(gfx::Rect(10, 10, 2, 2),
+ aggregated_pass_list.back()->damage_rect);
+ EXPECT_EQ(0u, aggregated_pass_list.back()->quad_list.size());
+ }
+
+ // This pass has damage that does not intersect the quad in the child
+ // surface.
+ {
+ std::vector<Quad> root_quads = {
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_surface_id),
+ SK_ColorWHITE, gfx::Rect(SurfaceSize()), false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ RenderPassList root_pass_list;
+ std::vector<SurfaceRange> referenced_surfaces;
+ AddPasses(&root_pass_list, root_passes, &referenced_surfaces);
+
+ auto* root_pass = root_pass_list[0].get();
+ root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
+ SubmitPassListAsFrame(root_sink_.get(), root_local_surface_id_,
+ &root_pass_list, std::move(referenced_surfaces),
+ device_scale_factor);
+ }
+
+ // The target surface invalidates one pixel in the top left, the quad in the
+ // child surface should be added even if it's not causing damage nor in the
+ // root render pass damage.
+ {
+ gfx::Rect target_damage(0, 0, 1, 1);
+ CompositorFrame aggregated_frame =
+ AggregateFrame(root_surface_id, target_damage);
+
+ const auto& aggregated_pass_list = aggregated_frame.render_pass_list;
+ ASSERT_EQ(1u, aggregated_pass_list.size());
+
+ // The damage rect of the root render pass should not be changed.
+ EXPECT_EQ(gfx::Rect(10, 10, 2, 2),
+ aggregated_pass_list.back()->damage_rect);
+ // We expect one quad
+ ASSERT_EQ(1u, aggregated_pass_list[0]->quad_list.size());
+ }
+}
+
class SurfaceAggregatorWithResourcesTest : public testing::Test,
public DisplayTimeSource {
public:
@@ -5667,6 +5797,41 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OverlayOccludingDamageRect) {
EXPECT_EQ(gfx::Rect(60, 0, 30, 40),
video_sqs->occluding_damage_rect.value());
}
+ // Frame #4 - Has occluding damage and clipping of the video quad is on
+ {
+ CompositorFrame child_surface_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_surface_frame.render_pass_list, child_surface_passes,
+ &child_surface_frame.metadata.referenced_surfaces);
+
+ auto* render_pass = child_surface_frame.render_pass_list[0].get();
+ auto* surface_quad_sqs = render_pass->shared_quad_state_list.front();
+ surface_quad_sqs->is_clipped = true;
+ surface_quad_sqs->clip_rect = gfx::Rect(20, 0, 60, 80);
+
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_surface_frame));
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ auto* output_root_pass = aggregated_frame.render_pass_list.back().get();
+ // The video quad (10, 0, 80, 80) unions the solid quad on top (60, 0, 40,
+ // 40)
+ EXPECT_EQ(gfx::Rect(10, 0, 90, 80), output_root_pass->damage_rect);
+
+ const SharedQuadState* video_sqs =
+ output_root_pass->quad_list.back()->shared_quad_state;
+ // The solid quad on top (60, 0, 40, 40) intersects the clipped video quad
+ // (26, 0, 48, 64)
+ EXPECT_EQ(gfx::Rect(60, 0, 14, 40),
+ video_sqs->occluding_damage_rect.value());
+ }
}
// Tests that quads outside the damage rect are not ignored for cached render
@@ -5833,7 +5998,9 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DisplayTransformDamageCallback) {
std::vector<Quad> root_quads = {Quad::SurfaceQuad(
SurfaceRange(primary_child_surface_id), SK_ColorWHITE, surface_quad_rect,
/*stretch_content_to_fill_bounds=*/true)};
- std::vector<Pass> root_passes = {Pass(root_quads, SurfaceSize())};
+
+ constexpr gfx::Size surface_size(60, 100);
+ std::vector<Pass> root_passes = {Pass(root_quads, surface_size)};
MockAggregatedDamageCallback aggregated_damage_callback;
root_sink_->SetAggregatedDamageCallbackForTesting(
@@ -5844,15 +6011,14 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, DisplayTransformDamageCallback) {
SubmitCompositorFrame(root_sink_.get(), root_passes, root_local_surface_id_,
0.5f);
- EXPECT_CALL(
- aggregated_damage_callback,
- OnAggregatedDamage(root_local_surface_id_, SurfaceSize(),
- gfx::Rect(SurfaceSize()), next_display_time()));
+ EXPECT_CALL(aggregated_damage_callback,
+ OnAggregatedDamage(root_local_surface_id_, surface_size,
+ gfx::Rect(surface_size), next_display_time()));
- gfx::Rect transformed_rect(SurfaceSize().height(), SurfaceSize().width());
CompositorFrame frame =
aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement(),
gfx::OVERLAY_TRANSFORM_ROTATE_90);
+ gfx::Rect transformed_rect(surface_size.height(), surface_size.width());
EXPECT_EQ(frame.render_pass_list.back()->output_rect, transformed_rect);
EXPECT_EQ(frame.render_pass_list.back()->damage_rect, transformed_rect);
}
@@ -6434,6 +6600,63 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, AllowMerge) {
}
}
+// Check that if a non-merged surface is invisible, its entire render pass is
+// skipped.
+TEST_F(SurfaceAggregatorValidSurfaceTest, SkipInvisibleSurface) {
+ // Child surface.
+ gfx::Rect child_rect(5, 5);
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ {
+ std::vector<Quad> child_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, child_rect)};
+ // Offset child output rect so it's outside the root visible rect.
+ gfx::Rect output_rect(SurfaceSize());
+ output_rect.Offset(output_rect.width(), output_rect.height());
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, output_rect)};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+ }
+
+ gfx::Rect root_rect(SurfaceSize());
+
+ auto pass = RenderPass::Create();
+ pass->SetNew(1, root_rect, root_rect, gfx::Transform());
+ auto* sqs = pass->CreateAndAppendSharedQuadState();
+ sqs->opacity = 1.f;
+
+ // Disallow merge.
+ auto* surface_quad = pass->CreateAndAppendDrawQuad<SurfaceDrawQuad>();
+ surface_quad->SetAll(sqs, child_rect, child_rect,
+ /*needs_blending=*/false,
+ SurfaceRange(base::nullopt, child_surface_id),
+ SK_ColorWHITE,
+ /*stretch_content_to_fill_bounds=*/false,
+ /*is_reflection=*/false,
+ /*allow_merge=*/false);
+
+ CompositorFrame frame =
+ CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+ // Merging not allowed, but child rect should be dropped.
+ EXPECT_EQ(1u, aggregated_frame.render_pass_list.size());
+}
+
// Verify that a SurfaceDrawQuad's root RenderPass has correct texture
// parameters if being drawn via RPDQ.
TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassDoesNotFillSurface) {
@@ -6691,5 +6914,562 @@ TEST_F(SurfaceAggregatorValidSurfaceTest,
hit_test_region_index);
}
+void ExpectDelegatedInkMetadataIsEqual(const DelegatedInkMetadata& lhs,
+ const DelegatedInkMetadata& rhs) {
+ EXPECT_FLOAT_EQ(lhs.point().y(), rhs.point().y());
+ EXPECT_FLOAT_EQ(lhs.point().x(), rhs.point().x());
+ EXPECT_EQ(lhs.diameter(), rhs.diameter());
+ EXPECT_EQ(lhs.color(), rhs.color());
+ EXPECT_EQ(lhs.timestamp(), rhs.timestamp());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().y(), rhs.presentation_area().y());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().x(), rhs.presentation_area().x());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().width(),
+ rhs.presentation_area().width());
+ EXPECT_FLOAT_EQ(lhs.presentation_area().height(),
+ rhs.presentation_area().height());
+}
+
+// Basic test to confirm that ink metadata on a child surface will be
+// transformed by the parent.
+TEST_F(SurfaceAggregatorValidSurfaceTest, DelegatedInkMetadataTest) {
+ std::vector<Quad> child_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ DelegatedInkMetadata metadata(gfx::PointF(100, 100), 1.5, SK_ColorRED,
+ base::TimeTicks::Now(),
+ gfx::RectF(10, 10, 200, 200));
+ child_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(1.5, 1.5);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(70, 240);
+
+ // Update the expected metadata to reflect the transforms to point and area
+ // that are expected to occur.
+ gfx::PointF pt = metadata.point();
+ gfx::RectF area = metadata.presentation_area();
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+ metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
+// Confirm that transforms are aggregated as the tree is walked and correctly
+// applied to the ink metadata.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ TransformDelegatedInkMetadataTallTree) {
+ auto greatgrand_child_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot);
+ std::vector<Quad> greatgrandchild_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> greatgrandchild_passes = {
+ Pass(greatgrandchild_quads, 1, gfx::Size(100, 100))};
+
+ DelegatedInkMetadata metadata(gfx::PointF(100, 100), 1.5, SK_ColorRED,
+ base::TimeTicks::Now(),
+ gfx::RectF(10, 10, 200, 200));
+ CompositorFrame greatgrandchild_frame = MakeEmptyCompositorFrame();
+ greatgrandchild_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&greatgrandchild_frame.render_pass_list, greatgrandchild_passes,
+ &greatgrandchild_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator greatgrandchild_allocator;
+ greatgrandchild_allocator.GenerateId();
+ LocalSurfaceId greatgrandchild_local_surface_id =
+ greatgrandchild_allocator.GetCurrentLocalSurfaceIdAllocation()
+ .local_surface_id();
+ SurfaceId great_grandchild_surface_id(
+ greatgrand_child_support->frame_sink_id(),
+ greatgrandchild_local_surface_id);
+ greatgrand_child_support->SubmitCompositorFrame(
+ greatgrandchild_local_surface_id, std::move(greatgrandchild_frame));
+
+ auto grand_child_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot);
+ std::vector<Quad> grandchild_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, great_grandchild_surface_id), SK_ColorWHITE,
+ gfx::Rect(7, 7), /*stretch_content_to_fill_bounds=*/false)};
+ std::vector<Pass> grandchild_passes = {
+ Pass(grandchild_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame grandchild_frame = MakeEmptyCompositorFrame();
+
+ AddPasses(&grandchild_frame.render_pass_list, grandchild_passes,
+ &grandchild_frame.metadata.referenced_surfaces);
+
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(1.5, 1.5);
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(37, 82);
+
+ // Update the expected metadata to reflect the transforms to point and area
+ // that are expected to occur.
+ gfx::PointF pt = metadata.point();
+ gfx::RectF area = metadata.presentation_area();
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ grandchild_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ ParentLocalSurfaceIdAllocator grandchild_allocator;
+ grandchild_allocator.GenerateId();
+ LocalSurfaceId grandchild_local_surface_id =
+ grandchild_allocator.GetCurrentLocalSurfaceIdAllocation()
+ .local_surface_id();
+ SurfaceId grandchild_surface_id(grand_child_support->frame_sink_id(),
+ grandchild_local_surface_id);
+ grand_child_support->SubmitCompositorFrame(grandchild_local_surface_id,
+ std::move(grandchild_frame));
+
+ std::vector<Quad> child_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, grandchild_surface_id), SK_ColorWHITE,
+ gfx::Rect(7, 7), /*stretch_content_to_fill_bounds=*/false)};
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ child_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(36, 15);
+
+ child_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ child_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ std::vector<Quad> root_quads = {Quad::SurfaceQuad(
+ SurfaceRange(base::nullopt, child_surface_id), SK_ColorWHITE,
+ gfx::Rect(5, 5), /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(0.7, 0.7);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(70, 240);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
+// Confirm the metadata is transformed correctly and makes it to the aggregated
+// frame when there are multiple children.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ DelegatedInkMetadataMultipleChildren) {
+ auto child_2_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot);
+ auto child_3_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot);
+
+ std::vector<Quad> child_1_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_1_passes = {
+ Pass(child_1_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_1_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_1_frame.render_pass_list, child_1_passes,
+ &child_1_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_1_allocator;
+ child_1_allocator.GenerateId();
+ LocalSurfaceId child_1_local_surface_id =
+ child_1_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_1_surface_id(child_sink_->frame_sink_id(),
+ child_1_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_1_local_surface_id,
+ std::move(child_1_frame));
+
+ std::vector<Quad> child_2_quads = {
+ Quad::SolidColorQuad(SK_ColorMAGENTA, gfx::Rect(5, 5))};
+ std::vector<Pass> child_2_passes = {
+ Pass(child_2_quads, 1, gfx::Size(100, 100))};
+
+ DelegatedInkMetadata metadata = DelegatedInkMetadata(
+ gfx::PointF(88, 34), 1.8, SK_ColorBLACK, base::TimeTicks::Now(),
+ gfx::RectF(50, 50, 300, 300));
+ CompositorFrame child_2_frame = MakeEmptyCompositorFrame();
+ child_2_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&child_2_frame.render_pass_list, child_2_passes,
+ &child_2_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_2_allocator;
+ child_2_allocator.GenerateId();
+ LocalSurfaceId child_2_local_surface_id =
+ child_2_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_2_surface_id(child_2_support->frame_sink_id(),
+ child_2_local_surface_id);
+ child_2_support->SubmitCompositorFrame(child_2_local_surface_id,
+ std::move(child_2_frame));
+
+ std::vector<Quad> child_3_quads = {
+ Quad::SolidColorQuad(SK_ColorCYAN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_3_passes = {
+ Pass(child_3_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_3_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_3_frame.render_pass_list, child_3_passes,
+ &child_3_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_3_allocator;
+ child_3_allocator.GenerateId();
+ LocalSurfaceId child_3_local_surface_id =
+ child_3_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_3_surface_id(child_3_support->frame_sink_id(),
+ child_3_local_surface_id);
+ child_3_support->SubmitCompositorFrame(child_3_local_surface_id,
+ std::move(child_3_frame));
+
+ std::vector<Quad> root_quads = {
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_1_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_2_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_3_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(9, 87);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Scale(0.7, 0.7);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Translate(70, 240);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(2)
+ ->quad_to_target_transform.Scale(2.7, 0.2);
+
+ // Update the expected metadata to reflect the transforms to point and area
+ // that are expected to occur.
+ gfx::PointF pt = metadata.point();
+ gfx::RectF area = metadata.presentation_area();
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ metadata = DelegatedInkMetadata(pt, metadata.diameter(), metadata.color(),
+ metadata.timestamp(), area);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
+// Confirm the the metadata with the most recent timestamp is used when
+// multiple children have delegated ink metadata.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ MultipleChildrenHaveDelegatedInkMetadata) {
+ auto child_2_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot);
+ auto child_3_support = std::make_unique<CompositorFrameSinkSupport>(
+ nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot);
+
+ std::vector<Quad> child_1_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_1_passes = {
+ Pass(child_1_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_1_frame = MakeEmptyCompositorFrame();
+ AddPasses(&child_1_frame.render_pass_list, child_1_passes,
+ &child_1_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_1_allocator;
+ child_1_allocator.GenerateId();
+ LocalSurfaceId child_1_local_surface_id =
+ child_1_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_1_surface_id(child_sink_->frame_sink_id(),
+ child_1_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_1_local_surface_id,
+ std::move(child_1_frame));
+
+ std::vector<Quad> child_2_quads = {
+ Quad::SolidColorQuad(SK_ColorMAGENTA, gfx::Rect(5, 5))};
+ std::vector<Pass> child_2_passes = {
+ Pass(child_2_quads, 1, gfx::Size(100, 100))};
+
+ // Making both metadatas here so that the one with a later timestamp can be
+ // on child 2. This will cause the test to fail if we don't default to using
+ // the metadata with the later timestamp. Specifically setting the
+ // later_metadata timestamp to be 50 microseconds later than Now() to avoid
+ // issues with both metadatas sometimes having the same time in Release.
+ DelegatedInkMetadata early_metadata = DelegatedInkMetadata(
+ gfx::PointF(88, 34), 1.8, SK_ColorBLACK, base::TimeTicks::Now(),
+ gfx::RectF(50, 50, 300, 300));
+ DelegatedInkMetadata later_metadata = DelegatedInkMetadata(
+ gfx::PointF(92, 35), 0.08, SK_ColorYELLOW,
+ base::TimeTicks::Now() + base::TimeDelta::FromMicroseconds(50),
+ gfx::RectF(35, 55, 128, 256));
+
+ CompositorFrame child_2_frame = MakeEmptyCompositorFrame();
+ child_2_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(later_metadata);
+ AddPasses(&child_2_frame.render_pass_list, child_2_passes,
+ &child_2_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_2_allocator;
+ child_2_allocator.GenerateId();
+ LocalSurfaceId child_2_local_surface_id =
+ child_2_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_2_surface_id(child_2_support->frame_sink_id(),
+ child_2_local_surface_id);
+ child_2_support->SubmitCompositorFrame(child_2_local_surface_id,
+ std::move(child_2_frame));
+
+ std::vector<Quad> child_3_quads = {
+ Quad::SolidColorQuad(SK_ColorCYAN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_3_passes = {
+ Pass(child_3_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_3_frame = MakeEmptyCompositorFrame();
+ child_3_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(early_metadata);
+ AddPasses(&child_3_frame.render_pass_list, child_3_passes,
+ &child_3_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_3_allocator;
+ child_3_allocator.GenerateId();
+ LocalSurfaceId child_3_local_surface_id =
+ child_3_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_3_surface_id(child_3_support->frame_sink_id(),
+ child_3_local_surface_id);
+ child_3_support->SubmitCompositorFrame(child_3_local_surface_id,
+ std::move(child_3_frame));
+
+ std::vector<Quad> root_quads = {
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_1_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_2_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false),
+ Quad::SurfaceQuad(SurfaceRange(base::nullopt, child_3_surface_id),
+ SK_ColorWHITE, gfx::Rect(5, 5),
+ /*stretch_content_to_fill_bounds=*/false)};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(9, 87);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Scale(1.4, 1.7);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.Translate(214, 144);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(2)
+ ->quad_to_target_transform.Scale(2.7, 0.2);
+
+ // Two surfaces have delegated ink metadata on them, and when this happens
+ // on the metadata with the most recent timestamp should be used. Take this
+ // metadata and transform it to what should be expected.
+ gfx::PointF pt = later_metadata.point();
+ gfx::RectF area = later_metadata.presentation_area();
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformPoint(&pt);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(1)
+ ->quad_to_target_transform.TransformRect(&area);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ DelegatedInkMetadata expected_metadata = DelegatedInkMetadata(
+ pt, later_metadata.diameter(), later_metadata.color(),
+ later_metadata.timestamp(), area);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), expected_metadata);
+}
+
+// Confirm that delegated ink metadata on an undrawn surface is not on the
+// aggregated surface unless the undrawn surface contains a CopyOutputRequest.
+TEST_F(SurfaceAggregatorValidSurfaceTest,
+ DelegatedInkMetadataOnUndrawnSurface) {
+ std::vector<Quad> child_quads = {
+ Quad::SolidColorQuad(SK_ColorGREEN, gfx::Rect(5, 5))};
+ std::vector<Pass> child_passes = {Pass(child_quads, 1, gfx::Size(100, 100))};
+
+ CompositorFrame child_frame = MakeEmptyCompositorFrame();
+ DelegatedInkMetadata metadata(gfx::PointF(34, 89), 1.597, SK_ColorBLUE,
+ base::TimeTicks::Now(),
+ gfx::RectF(2.3, 3.2, 177, 212));
+ child_frame.metadata.delegated_ink_metadata =
+ std::make_unique<DelegatedInkMetadata>(metadata);
+ AddPasses(&child_frame.render_pass_list, child_passes,
+ &child_frame.metadata.referenced_surfaces);
+
+ ParentLocalSurfaceIdAllocator child_allocator;
+ child_allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceIdAllocation().local_surface_id();
+ SurfaceId child_surface_id(child_sink_->frame_sink_id(),
+ child_local_surface_id);
+ child_sink_->SubmitCompositorFrame(child_local_surface_id,
+ std::move(child_frame));
+
+ // Do not put the child surface in a SurfaceDrawQuad so that it remains
+ // undrawn.
+ std::vector<Quad> root_quads = {
+ Quad::SolidColorQuad(SK_ColorMAGENTA, gfx::Rect(5, 5))};
+
+ std::vector<Pass> root_passes = {Pass(root_quads, 1, gfx::Size(30, 30))};
+
+ CompositorFrame root_frame = MakeEmptyCompositorFrame();
+ root_frame.metadata.referenced_surfaces.emplace_back(
+ SurfaceRange(base::nullopt, child_surface_id));
+ AddPasses(&root_frame.render_pass_list, root_passes,
+ &root_frame.metadata.referenced_surfaces);
+
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Scale(1.5, 1.5);
+ root_frame.render_pass_list[0]
+ ->shared_quad_state_list.ElementAt(0)
+ ->quad_to_target_transform.Translate(70, 240);
+
+ root_sink_->SubmitCompositorFrame(root_local_surface_id_,
+ std::move(root_frame));
+
+ SurfaceId root_surface_id(root_sink_->frame_sink_id(),
+ root_local_surface_id_);
+ CompositorFrame aggregated_frame = AggregateFrame(root_surface_id);
+
+ EXPECT_FALSE(aggregated_frame.metadata.delegated_ink_metadata);
+
+ // Now add a CopyOutputRequest on the child surface, so that the delegated
+ // ink metadata does get populated on the aggregated frame.
+ auto copy_request = CopyOutputRequest::CreateStubForTesting();
+ child_sink_->RequestCopyOfOutput(child_local_surface_id,
+ std::move(copy_request));
+
+ aggregated_frame = AggregateFrame(root_surface_id);
+
+ std::unique_ptr<DelegatedInkMetadata> actual_metadata =
+ std::move(aggregated_frame.metadata.delegated_ink_metadata);
+ EXPECT_TRUE(actual_metadata);
+ ExpectDelegatedInkMetadataIsEqual(*actual_metadata.get(), metadata);
+}
+
} // namespace
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/buffer_queue.cc b/chromium/components/viz/service/display_embedder/buffer_queue.cc
index 85241086b23..ddec6ab1dae 100644
--- a/chromium/components/viz/service/display_embedder/buffer_queue.cc
+++ b/chromium/components/viz/service/display_embedder/buffer_queue.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/containers/adapters.h"
+#include "base/logging.h"
#include "build/build_config.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
@@ -52,8 +53,18 @@ void BufferQueue::UpdateBufferDamage(const gfx::Rect& damage) {
}
gfx::Rect BufferQueue::CurrentBufferDamage() const {
- DCHECK(current_surface_);
- return current_surface_->damage;
+ if (current_surface_)
+ return current_surface_->damage;
+
+ // In case there is no current_surface_, we get the damage from the surface
+ // that will be set as current_surface_ by the next call to GetNextSurface.
+ if (!available_surfaces_.empty()) {
+ return available_surfaces_.back()->damage;
+ }
+
+ // If we can't determine which surface will be the next current_surface_, we
+ // conservatively invalidate the whole buffer.
+ return gfx::Rect(size_);
}
void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
diff --git a/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc b/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
index 9c921dab300..4cb71e78984 100644
--- a/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/buffer_queue_unittest.cc
@@ -92,7 +92,7 @@ class StubGpuMemoryBufferManager : public TestGpuMemoryBufferManager {
gfx::BufferFormat format,
gfx::BufferUsage usage,
gpu::SurfaceHandle surface_handle) override {
- if (!surface_handle) {
+ if (surface_handle == gpu::kNullSurfaceHandle) {
return TestGpuMemoryBufferManager::CreateGpuMemoryBuffer(
size, format, usage, surface_handle);
}
@@ -110,6 +110,9 @@ class StubGpuMemoryBufferManager : public TestGpuMemoryBufferManager {
#if defined(OS_WIN)
const gpu::SurfaceHandle kFakeSurfaceHandle =
reinterpret_cast<gpu::SurfaceHandle>(1);
+#elif defined(USE_X11)
+const gpu::SurfaceHandle kFakeSurfaceHandle =
+ static_cast<gpu::SurfaceHandle>(1);
#else
const gpu::SurfaceHandle kFakeSurfaceHandle = 1;
#endif
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
index cde84eac27f..dfbcf050e87 100644
--- 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
@@ -8,6 +8,8 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/logging.h"
+#include "build/build_config.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"
@@ -40,7 +42,13 @@ GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue(
// shifts the start of the new frame forward relative to the old
// implementation.
capabilities_.max_frames_pending = 2;
-
+ // GetCurrentFramebufferDamage will return an upper bound of the part of the
+ // buffer that needs to be recomposited.
+#if defined(OS_MACOSX)
+ 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_|
diff --git a/chromium/components/viz/service/display_embedder/output_presenter.cc b/chromium/components/viz/service/display_embedder/output_presenter.cc
new file mode 100644
index 00000000000..240c7d442a8
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_presenter.cc
@@ -0,0 +1,115 @@
+// Copyright 2020 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/output_presenter.h"
+
+#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+
+namespace viz {
+
+OutputPresenter::Image::Image() = default;
+
+OutputPresenter::Image::~Image() {
+ // TODO(vasilyt): As we are going to delete image anyway we should be able
+ // to abort write to avoid unnecessary flush to submit semaphores.
+ if (scoped_skia_write_access_) {
+ EndWriteSkia();
+ }
+ DCHECK(!scoped_skia_write_access_);
+}
+
+bool OutputPresenter::Image::Initialize(
+ gpu::SharedImageFactory* factory,
+ gpu::SharedImageRepresentationFactory* representation_factory,
+ const gpu::Mailbox& mailbox,
+ SkiaOutputSurfaceDependency* deps) {
+ skia_representation_ = representation_factory->ProduceSkia(
+ mailbox, deps->GetSharedContextState());
+ if (!skia_representation_) {
+ DLOG(ERROR) << "ProduceSkia() failed.";
+ return false;
+ }
+
+ // Initialize |shared_image_deleter_| to make sure the shared image backing
+ // will be released with the Image.
+ shared_image_deleter_.ReplaceClosure(base::BindOnce(
+ base::IgnoreResult(&gpu::SharedImageFactory::DestroySharedImage),
+ base::Unretained(factory), mailbox));
+
+ return true;
+}
+
+void OutputPresenter::Image::BeginWriteSkia() {
+ DCHECK(!scoped_skia_write_access_);
+ DCHECK(!present_count());
+ DCHECK(end_semaphores_.empty());
+
+ std::vector<GrBackendSemaphore> begin_semaphores;
+ // LegacyFontHost will get LCD text and skia figures out what type to use.
+ SkSurfaceProps surface_props(0 /* flags */,
+ SkSurfaceProps::kLegacyFontHost_InitType);
+
+ // Buffer queue is internal to GPU proc and handles texture initialization,
+ // so allow uncleared access.
+ // TODO(vasilyt): Props and MSAA
+ scoped_skia_write_access_ = skia_representation_->BeginScopedWriteAccess(
+ 0 /* final_msaa_count */, surface_props, &begin_semaphores,
+ &end_semaphores_,
+ gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
+ DCHECK(scoped_skia_write_access_);
+ if (!begin_semaphores.empty()) {
+ scoped_skia_write_access_->surface()->wait(begin_semaphores.size(),
+ begin_semaphores.data());
+ }
+}
+
+SkSurface* OutputPresenter::Image::sk_surface() {
+ return scoped_skia_write_access_ ? scoped_skia_write_access_->surface()
+ : nullptr;
+}
+
+std::vector<GrBackendSemaphore>
+OutputPresenter::Image::TakeEndWriteSkiaSemaphores() {
+ std::vector<GrBackendSemaphore> result;
+ result.swap(end_semaphores_);
+ return result;
+}
+
+void OutputPresenter::Image::EndWriteSkia() {
+ // The Flush now takes place in finishPaintCurrentBuffer on the CPU side.
+ // check if end_semaphores is not empty then flash here
+ DCHECK(scoped_skia_write_access_);
+ if (!end_semaphores_.empty()) {
+ GrFlushInfo flush_info = {
+ .fFlags = kNone_GrFlushFlags,
+ .fNumSemaphores = end_semaphores_.size(),
+ .fSignalSemaphores = end_semaphores_.data(),
+ };
+ scoped_skia_write_access_->surface()->flush(
+ SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
+ DCHECK(scoped_skia_write_access_->surface()->getContext());
+ scoped_skia_write_access_->surface()->getContext()->submit();
+ }
+ scoped_skia_write_access_.reset();
+ end_semaphores_.clear();
+
+ // SkiaRenderer always draws the full frame.
+ skia_representation_->SetCleared();
+}
+
+OutputPresenter::OverlayData::OverlayData(
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay> representation,
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
+ scoped_read_access)
+ : representation_(std::move(representation)),
+ scoped_read_access_(std::move(scoped_read_access)) {}
+OutputPresenter::OverlayData::OverlayData(OverlayData&&) = default;
+OutputPresenter::OverlayData::~OverlayData() = default;
+OutputPresenter::OverlayData& OutputPresenter::OverlayData::operator=(
+ OverlayData&&) = default;
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter.h b/chromium/components/viz/service/display_embedder/output_presenter.h
new file mode 100644
index 00000000000..70a30fb3fbe
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_presenter.h
@@ -0,0 +1,117 @@
+// Copyright 2020 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_OUTPUT_PRESENTER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_PRESENTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "components/viz/service/display/output_surface.h"
+#include "components/viz/service/display/overlay_processor_interface.h"
+#include "components/viz/service/display/skia_output_surface.h"
+#include "components/viz/service/viz_service_export.h"
+#include "gpu/command_buffer/service/shared_image_factory.h"
+#include "ui/gfx/presentation_feedback.h"
+#include "ui/gfx/swap_result.h"
+
+namespace viz {
+
+class SkiaOutputSurfaceDependency;
+
+class VIZ_SERVICE_EXPORT OutputPresenter {
+ public:
+ class Image {
+ public:
+ Image();
+ virtual ~Image();
+
+ Image(const Image&) = delete;
+ Image& operator=(const Image&) = delete;
+
+ bool Initialize(
+ gpu::SharedImageFactory* factory,
+ gpu::SharedImageRepresentationFactory* representation_factory,
+ const gpu::Mailbox& mailbox,
+ SkiaOutputSurfaceDependency* deps);
+
+ gpu::SharedImageRepresentationSkia* skia_representation() {
+ return skia_representation_.get();
+ }
+
+ void BeginWriteSkia();
+ SkSurface* sk_surface();
+ std::vector<GrBackendSemaphore> TakeEndWriteSkiaSemaphores();
+ void EndWriteSkia();
+
+ virtual void BeginPresent() = 0;
+ virtual void EndPresent() = 0;
+ virtual int present_count() const = 0;
+
+ base::WeakPtr<Image> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
+
+ private:
+ base::ScopedClosureRunner shared_image_deleter_;
+ std::unique_ptr<gpu::SharedImageRepresentationSkia> skia_representation_;
+ std::unique_ptr<gpu::SharedImageRepresentationSkia::ScopedWriteAccess>
+ scoped_skia_write_access_;
+
+ std::vector<GrBackendSemaphore> end_semaphores_;
+ base::WeakPtrFactory<Image> weak_ptr_factory_{this};
+ };
+
+ class OverlayData {
+ public:
+ OverlayData(
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay> representation,
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
+ scoped_read_access);
+ OverlayData(OverlayData&&);
+ ~OverlayData();
+ OverlayData& operator=(OverlayData&&);
+
+ private:
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay> representation_;
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
+ scoped_read_access_;
+ };
+
+ OutputPresenter() = default;
+ virtual ~OutputPresenter() = default;
+
+ using BufferPresentedCallback =
+ base::OnceCallback<void(const gfx::PresentationFeedback& feedback)>;
+ using SwapCompletionCallback =
+ base::OnceCallback<void(gfx::SwapCompletionResult)>;
+
+ virtual void InitializeCapabilities(
+ OutputSurface::Capabilities* capabilities) = 0;
+ virtual bool Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ gfx::BufferFormat format,
+ gfx::OverlayTransform transform) = 0;
+ virtual std::vector<std::unique_ptr<Image>> AllocateImages(
+ gfx::ColorSpace color_space,
+ gfx::Size image_size,
+ size_t num_images) = 0;
+ virtual void SwapBuffers(SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) = 0;
+ virtual void PostSubBuffer(const gfx::Rect& rect,
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) = 0;
+ virtual void CommitOverlayPlanes(
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) = 0;
+ virtual void SchedulePrimaryPlane(
+ const OverlayProcessorInterface::OutputSurfaceOverlayPlane& plane,
+ Image* image,
+ bool is_submitted) = 0;
+ virtual std::vector<OverlayData> ScheduleOverlays(
+ SkiaOutputSurface::OverlayList overlays) = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_PRESENTER_H_
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
new file mode 100644
index 00000000000..50a65e98c66
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.cc
@@ -0,0 +1,490 @@
+// Copyright 2020 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/output_presenter_fuchsia.h"
+
+#include <fuchsia/sysmem/cpp/fidl.h>
+#include <lib/sys/cpp/component_context.h>
+#include <lib/sys/inspect/cpp/component.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/feature_list.h"
+#include "base/fuchsia/fuchsia_logging.h"
+#include "base/fuchsia/process_context.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/features.h"
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/ipc/common/gpu_client_ids.h"
+#include "gpu/vulkan/vulkan_device_queue.h"
+#include "gpu/vulkan/vulkan_function_pointers.h"
+#include "gpu/vulkan/vulkan_implementation.h"
+#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
+#include "ui/ozone/public/platform_window_surface.h"
+
+namespace viz {
+
+namespace {
+
+void GrSemaphoresToZxEvents(gpu::VulkanImplementation* vulkan_implementation,
+ VkDevice vk_device,
+ const std::vector<GrBackendSemaphore>& semaphores,
+ std::vector<zx::event>* events) {
+ for (auto& semaphore : semaphores) {
+ gpu::SemaphoreHandle handle = vulkan_implementation->GetSemaphoreHandle(
+ vk_device, semaphore.vkSemaphore());
+ DCHECK(handle.is_valid());
+ events->push_back(handle.TakeHandle());
+ }
+}
+
+class PresenterImageFuchsia : public OutputPresenter::Image {
+ public:
+ explicit PresenterImageFuchsia(uint32_t image_id);
+ ~PresenterImageFuchsia() override;
+
+ void BeginPresent() final;
+ void EndPresent() final;
+ int present_count() const final;
+
+ uint32_t image_id() const { return image_id_; }
+
+ void TakeSemaphores(std::vector<GrBackendSemaphore>* read_begin_semaphores,
+ std::vector<GrBackendSemaphore>* read_end_semaphores);
+
+ private:
+ const uint32_t image_id_;
+
+ int present_count_ = 0;
+
+ std::unique_ptr<gpu::SharedImageRepresentationSkia::ScopedReadAccess>
+ read_access_;
+
+ std::vector<GrBackendSemaphore> read_begin_semaphores_;
+ std::vector<GrBackendSemaphore> read_end_semaphores_;
+};
+
+PresenterImageFuchsia::PresenterImageFuchsia(uint32_t image_id)
+ : image_id_(image_id) {}
+
+PresenterImageFuchsia::~PresenterImageFuchsia() {
+ DCHECK(read_begin_semaphores_.empty());
+ DCHECK(read_end_semaphores_.empty());
+}
+
+void PresenterImageFuchsia::BeginPresent() {
+ ++present_count_;
+
+ if (present_count_ == 1) {
+ DCHECK(!read_access_);
+ DCHECK(read_begin_semaphores_.empty());
+ DCHECK(read_end_semaphores_.empty());
+ read_access_ = skia_representation()->BeginScopedReadAccess(
+ &read_begin_semaphores_, &read_end_semaphores_);
+ }
+}
+
+void PresenterImageFuchsia::EndPresent() {
+ DCHECK(present_count_);
+ --present_count_;
+ if (!present_count_)
+ read_access_.reset();
+}
+
+int PresenterImageFuchsia::present_count() const {
+ return present_count_;
+}
+
+void PresenterImageFuchsia::TakeSemaphores(
+ std::vector<GrBackendSemaphore>* read_begin_semaphores,
+ std::vector<GrBackendSemaphore>* read_end_semaphores) {
+ DCHECK(read_begin_semaphores->empty());
+ std::swap(*read_begin_semaphores, read_begin_semaphores_);
+
+ DCHECK(read_end_semaphores->empty());
+ std::swap(*read_end_semaphores, read_end_semaphores_);
+}
+
+} // namespace
+
+OutputPresenterFuchsia::PendingFrame::PendingFrame() = default;
+OutputPresenterFuchsia::PendingFrame::~PendingFrame() = default;
+
+OutputPresenterFuchsia::PendingFrame::PendingFrame(PendingFrame&&) = default;
+OutputPresenterFuchsia::PendingFrame&
+OutputPresenterFuchsia::PendingFrame::operator=(PendingFrame&&) = default;
+
+// static
+std::unique_ptr<OutputPresenterFuchsia> OutputPresenterFuchsia::Create(
+ ui::PlatformWindowSurface* window_surface,
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker) {
+ auto* inspector = base::ComponentInspectorForProcess();
+
+ if (!base::FeatureList::IsEnabled(
+ features::kUseSkiaOutputDeviceBufferQueue)) {
+ inspector->root().CreateString("output_presenter", "swapchain", inspector);
+ return {};
+ }
+
+ inspector->root().CreateString("output_presenter",
+ "SkiaOutputDeviceBufferQueue", inspector);
+
+ // SetTextureToNewImagePipe() will call ScenicSession::Present() to send
+ // CreateImagePipe2Cmd creation command, but it will be processed only after
+ // vsync, which will delay buffer allocation of buffers in AllocateImages(),
+ // but that shouldn't cause any issues.
+ fuchsia::images::ImagePipe2Ptr image_pipe;
+ if (!window_surface->SetTextureToNewImagePipe(image_pipe.NewRequest()))
+ return {};
+
+ return std::make_unique<OutputPresenterFuchsia>(std::move(image_pipe), deps,
+ memory_tracker);
+}
+
+OutputPresenterFuchsia::OutputPresenterFuchsia(
+ fuchsia::images::ImagePipe2Ptr image_pipe,
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker)
+ : image_pipe_(std::move(image_pipe)),
+ dependency_(deps),
+ shared_image_factory_(deps->GetGpuPreferences(),
+ deps->GetGpuDriverBugWorkarounds(),
+ deps->GetGpuFeatureInfo(),
+ deps->GetSharedContextState().get(),
+ deps->GetMailboxManager(),
+ deps->GetSharedImageManager(),
+ deps->GetGpuImageFactory(),
+ memory_tracker,
+ true),
+ shared_image_representation_factory_(deps->GetSharedImageManager(),
+ memory_tracker) {
+ sysmem_allocator_ = base::ComponentContextForProcess()
+ ->svc()
+ ->Connect<fuchsia::sysmem::Allocator>();
+
+ image_pipe_.set_error_handler([this](zx_status_t status) {
+ ZX_LOG(ERROR, status) << "ImagePipe disconnected";
+
+ for (auto& frame : pending_frames_) {
+ std::move(frame.completion_callback)
+ .Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_FAILED));
+ }
+ pending_frames_.clear();
+ });
+}
+
+OutputPresenterFuchsia::~OutputPresenterFuchsia() {}
+
+void OutputPresenterFuchsia::InitializeCapabilities(
+ OutputSurface::Capabilities* capabilities) {
+ // We expect origin of buffers is at top left.
+ capabilities->output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
+ capabilities->supports_post_sub_buffer = false;
+ capabilities->supports_commit_overlay_planes = false;
+
+ capabilities->sk_color_type = kRGBA_8888_SkColorType;
+ capabilities->gr_backend_format =
+ dependency_->GetSharedContextState()->gr_context()->defaultBackendFormat(
+ capabilities->sk_color_type, GrRenderable::kYes);
+}
+
+bool OutputPresenterFuchsia::Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ gfx::BufferFormat format,
+ gfx::OverlayTransform transform) {
+ if (!image_pipe_)
+ return false;
+
+ frame_size_ = size;
+
+ return true;
+}
+
+std::vector<std::unique_ptr<OutputPresenter::Image>>
+OutputPresenterFuchsia::AllocateImages(gfx::ColorSpace color_space,
+ gfx::Size image_size,
+ size_t num_images) {
+ if (!image_pipe_)
+ return {};
+
+ // If we already allocated buffer collection then it needs to be released.
+ if (last_buffer_collection_id_) {
+ // If there are pending frames for the old buffer collection then remove the
+ // collection only after that frame is presented. Otherwise remove it now.
+ if (!pending_frames_.empty() &&
+ pending_frames_.back().buffer_collection_id ==
+ last_buffer_collection_id_) {
+ DCHECK(!pending_frames_.back().remove_buffer_collection);
+ pending_frames_.back().remove_buffer_collection = true;
+ } else {
+ image_pipe_->RemoveBufferCollection(last_buffer_collection_id_);
+ }
+ }
+
+ buffer_collection_.reset();
+
+ // Create buffer collection with 2 extra tokens: one for Vulkan and one for
+ // the ImagePipe.
+ fuchsia::sysmem::BufferCollectionTokenPtr collection_token;
+ sysmem_allocator_->AllocateSharedCollection(collection_token.NewRequest());
+
+ fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
+ token_for_scenic;
+ collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
+ token_for_scenic.NewRequest());
+
+ fidl::InterfaceHandle<fuchsia::sysmem::BufferCollectionToken>
+ token_for_vulkan;
+ collection_token->Duplicate(ZX_RIGHT_SAME_RIGHTS,
+ token_for_vulkan.NewRequest());
+
+ fuchsia::sysmem::BufferCollectionSyncPtr collection;
+ sysmem_allocator_->BindSharedCollection(std::move(collection_token),
+ collection.NewRequest());
+
+ zx_status_t status = collection->Sync();
+ if (status != ZX_OK) {
+ ZX_DLOG(ERROR, status) << "fuchsia.sysmem.BufferCollection.Sync()";
+ return {};
+ }
+
+ auto* vulkan =
+ dependency_->GetVulkanContextProvider()->GetVulkanImplementation();
+
+ // Set constraints for the new collection.
+ fuchsia::sysmem::BufferCollectionConstraints constraints;
+ constraints.min_buffer_count = num_images;
+ constraints.usage.none = fuchsia::sysmem::noneUsage;
+ constraints.image_format_constraints_count = 1;
+ constraints.image_format_constraints[0].pixel_format.type =
+ fuchsia::sysmem::PixelFormatType::R8G8B8A8;
+ constraints.image_format_constraints[0].min_coded_width = frame_size_.width();
+ constraints.image_format_constraints[0].min_coded_height =
+ frame_size_.height();
+ constraints.image_format_constraints[0].color_spaces_count = 1;
+ constraints.image_format_constraints[0].color_space[0].type =
+ fuchsia::sysmem::ColorSpaceType::SRGB;
+ collection->SetConstraints(true, constraints);
+
+ // Register the new buffer collection with the ImagePipe.
+ last_buffer_collection_id_++;
+ image_pipe_->AddBufferCollection(last_buffer_collection_id_,
+ std::move(token_for_scenic));
+
+ // Register the new buffer collection with Vulkan.
+ gfx::SysmemBufferCollectionId buffer_collection_id =
+ gfx::SysmemBufferCollectionId::Create();
+
+ VkDevice vk_device = dependency_->GetVulkanContextProvider()
+ ->GetDeviceQueue()
+ ->GetVulkanDevice();
+ buffer_collection_ = vulkan->RegisterSysmemBufferCollection(
+ vk_device, buffer_collection_id, token_for_vulkan.TakeChannel(),
+ buffer_format_, gfx::BufferUsage::SCANOUT);
+
+ // Wait for the images to be allocated.
+ zx_status_t wait_status;
+ fuchsia::sysmem::BufferCollectionInfo_2 buffers_info;
+ status = collection->WaitForBuffersAllocated(&wait_status, &buffers_info);
+ if (status != ZX_OK) {
+ ZX_DLOG(ERROR, status) << "fuchsia.sysmem.BufferCollection failed";
+ return {};
+ }
+
+ if (wait_status != ZX_OK) {
+ ZX_DLOG(ERROR, wait_status)
+ << "Sysmem buffer collection allocation failed.";
+ return {};
+ }
+
+ DCHECK_GE(buffers_info.buffer_count, num_images);
+
+ // We no longer need the BufferCollection connection. Close it to ensure
+ // ImagePipe can still use the collection after BufferCollection connection
+ // is dropped below.
+ collection->Close();
+
+ // Create PresenterImageFuchsia for each buffer in the collection.
+ uint32_t image_usage = gpu::SHARED_IMAGE_USAGE_RASTER;
+ if (vulkan->enforce_protected_memory())
+ image_usage |= gpu::SHARED_IMAGE_USAGE_PROTECTED;
+
+ std::vector<std::unique_ptr<OutputPresenter::Image>> images;
+ images.reserve(num_images);
+
+ fuchsia::sysmem::ImageFormat_2 image_format;
+ image_format.coded_width = frame_size_.width();
+ image_format.coded_height = frame_size_.height();
+
+ // Create an image for each buffer in the collection.
+ for (size_t i = 0; i < num_images; ++i) {
+ last_image_id_++;
+ image_pipe_->AddImage(last_image_id_, last_buffer_collection_id_, i,
+ image_format);
+
+ gfx::GpuMemoryBufferHandle gmb_handle;
+ gmb_handle.type = gfx::GpuMemoryBufferType::NATIVE_PIXMAP;
+ gmb_handle.native_pixmap_handle.buffer_collection_id = buffer_collection_id;
+ gmb_handle.native_pixmap_handle.buffer_index = i;
+
+ auto mailbox = gpu::Mailbox::GenerateForSharedImage();
+ if (!shared_image_factory_.CreateSharedImage(
+ mailbox, gpu::kInProcessCommandBufferClientId,
+ std::move(gmb_handle), buffer_format_, gpu::kNullSurfaceHandle,
+ frame_size_, color_space, image_usage)) {
+ return {};
+ }
+
+ auto image = std::make_unique<PresenterImageFuchsia>(last_image_id_);
+ if (!image->Initialize(&shared_image_factory_,
+ &shared_image_representation_factory_, mailbox,
+ dependency_)) {
+ return {};
+ }
+ images.push_back(std::move(image));
+ }
+
+ return images;
+}
+
+void OutputPresenterFuchsia::SwapBuffers(
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) {
+ if (!image_pipe_) {
+ std::move(completion_callback)
+ .Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_FAILED));
+ return;
+ }
+
+ // SwapBuffer() should be called only after SchedulePrimaryPlane().
+ DCHECK(next_frame_);
+
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
+ "viz", "OutputPresenterFuchsia::PresentQueue", TRACE_ID_LOCAL(this),
+ "image_id", next_frame_->image_id);
+
+ next_frame_->completion_callback = std::move(completion_callback);
+ next_frame_->presentation_callback = std::move(presentation_callback);
+
+ pending_frames_.push_back(std::move(next_frame_.value()));
+ next_frame_.reset();
+
+ if (!present_is_pending_)
+ PresentNextFrame();
+}
+
+void OutputPresenterFuchsia::PostSubBuffer(
+ const gfx::Rect& rect,
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) {
+ // Sub buffer presentation is not supported.
+ NOTREACHED();
+}
+
+void OutputPresenterFuchsia::CommitOverlayPlanes(
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) {
+ // Overlays are not supported yet.
+ NOTREACHED();
+}
+
+void OutputPresenterFuchsia::SchedulePrimaryPlane(
+ const OverlayProcessorInterface::OutputSurfaceOverlayPlane& plane,
+ Image* image,
+ bool is_submitted) {
+ auto* image_fuchsia = static_cast<PresenterImageFuchsia*>(image);
+
+ DCHECK(!next_frame_);
+ next_frame_ = PendingFrame();
+ next_frame_->image_id = image_fuchsia->image_id();
+ next_frame_->buffer_collection_id = last_buffer_collection_id_;
+
+ // Take semaphores for the image and covert them to zx::events that are later
+ // passed to ImagePipe::PresentImage().
+ std::vector<GrBackendSemaphore> read_begin_semaphores;
+ std::vector<GrBackendSemaphore> read_end_semaphores;
+ image_fuchsia->TakeSemaphores(&read_begin_semaphores, &read_end_semaphores);
+
+ auto* vulkan_context_provider = dependency_->GetVulkanContextProvider();
+ auto* vulkan_implementation =
+ vulkan_context_provider->GetVulkanImplementation();
+ VkDevice vk_device =
+ vulkan_context_provider->GetDeviceQueue()->GetVulkanDevice();
+
+ GrSemaphoresToZxEvents(vulkan_implementation, vk_device,
+ read_begin_semaphores, &(next_frame_->acquire_fences));
+ GrSemaphoresToZxEvents(vulkan_implementation, vk_device, read_end_semaphores,
+ &(next_frame_->release_fences));
+
+ // Destroy |read_begin_semaphores|, but not |read_end_semaphores|, since
+ // SharedImageRepresentationSkia::BeginScopedReadAccess() keeps ownership of
+ // the end_semaphores.
+ for (auto& semaphore : read_begin_semaphores) {
+ vkDestroySemaphore(vk_device, semaphore.vkSemaphore(), nullptr);
+ }
+}
+
+std::vector<OutputPresenter::OverlayData>
+OutputPresenterFuchsia::ScheduleOverlays(
+ SkiaOutputSurface::OverlayList overlays) {
+ // Overlays are not supported yet.
+ NOTREACHED();
+ return {};
+}
+
+void OutputPresenterFuchsia::PresentNextFrame() {
+ DCHECK(!present_is_pending_);
+ DCHECK(!pending_frames_.empty());
+
+ TRACE_EVENT_NESTABLE_ASYNC_END1("viz", "OutputPresenterFuchsia::PresentQueue",
+ TRACE_ID_LOCAL(this), "image_id",
+ pending_frames_.front().image_id);
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
+ "viz", "OutputPresenterFuchsia::PresentFrame", TRACE_ID_LOCAL(this),
+ "image_id", pending_frames_.front().image_id);
+
+ present_is_pending_ = true;
+ uint64_t target_presentation_time = zx_clock_get_monotonic();
+ image_pipe_->PresentImage(
+ pending_frames_.front().image_id, target_presentation_time,
+ std::move(pending_frames_.front().acquire_fences),
+ std::move(pending_frames_.front().release_fences),
+ fit::bind_member(this, &OutputPresenterFuchsia::OnPresentComplete));
+}
+
+void OutputPresenterFuchsia::OnPresentComplete(
+ fuchsia::images::PresentationInfo presentation_info) {
+ DCHECK(present_is_pending_);
+ present_is_pending_ = false;
+
+ TRACE_EVENT_NESTABLE_ASYNC_END1("viz", "OutputPresenterFuchsia::PresentFrame",
+ TRACE_ID_LOCAL(this), "image_id",
+ pending_frames_.front().image_id);
+
+ std::move(pending_frames_.front().completion_callback)
+ .Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK));
+ std::move(pending_frames_.front().presentation_callback)
+ .Run(gfx::PresentationFeedback(
+ base::TimeTicks::FromZxTime(presentation_info.presentation_time),
+ base::TimeDelta::FromZxDuration(
+ presentation_info.presentation_interval),
+ gfx::PresentationFeedback::kVSync));
+
+ if (pending_frames_.front().remove_buffer_collection) {
+ image_pipe_->RemoveBufferCollection(
+ pending_frames_.front().buffer_collection_id);
+ }
+
+ pending_frames_.pop_front();
+ if (!pending_frames_.empty())
+ PresentNextFrame();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h
new file mode 100644
index 00000000000..bfee93dae49
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_presenter_fuchsia.h
@@ -0,0 +1,115 @@
+// Copyright 2020 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_OUTPUT_PRESENTER_FUCHSIA_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_PRESENTER_FUCHSIA_H_
+
+#include <fuchsia/images/cpp/fidl.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/containers/circular_deque.h"
+#include "components/viz/service/display_embedder/output_presenter.h"
+#include "components/viz/service/viz_service_export.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/command_buffer/service/shared_image_factory.h"
+
+namespace ui {
+class PlatformWindowSurface;
+} // namespace ui
+
+namespace viz {
+
+class VIZ_SERVICE_EXPORT OutputPresenterFuchsia : public OutputPresenter {
+ public:
+ static std::unique_ptr<OutputPresenterFuchsia> Create(
+ ui::PlatformWindowSurface* window_surface,
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker);
+
+ OutputPresenterFuchsia(fuchsia::images::ImagePipe2Ptr image_pipe,
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker);
+ ~OutputPresenterFuchsia() override;
+
+ // OutputPresenter implementation:
+ void InitializeCapabilities(OutputSurface::Capabilities* capabilities) final;
+ bool Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ gfx::BufferFormat format,
+ gfx::OverlayTransform transform) final;
+ std::vector<std::unique_ptr<Image>> AllocateImages(
+ gfx::ColorSpace color_space,
+ gfx::Size image_size,
+ size_t num_images) final;
+ void SwapBuffers(SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) final;
+ void PostSubBuffer(const gfx::Rect& rect,
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) final;
+ void CommitOverlayPlanes(SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) final;
+ void SchedulePrimaryPlane(
+ const OverlayProcessorInterface::OutputSurfaceOverlayPlane& plane,
+ Image* image,
+ bool is_submitted) final;
+ std::vector<OverlayData> ScheduleOverlays(
+ SkiaOutputSurface::OverlayList overlays) final;
+
+ private:
+ struct PendingFrame {
+ PendingFrame();
+ ~PendingFrame();
+
+ PendingFrame(PendingFrame&&);
+ PendingFrame& operator=(PendingFrame&&);
+
+ uint32_t buffer_collection_id;
+ uint32_t image_id;
+
+ std::vector<zx::event> acquire_fences;
+ std::vector<zx::event> release_fences;
+
+ SwapCompletionCallback completion_callback;
+ BufferPresentedCallback presentation_callback;
+
+ // Indicates that this is the last frame for this buffer collection and that
+ // the collection can be removed after the frame is presented.
+ bool remove_buffer_collection = false;
+ };
+
+ void PresentNextFrame();
+ void OnPresentComplete(fuchsia::images::PresentationInfo presentation_info);
+
+ fuchsia::sysmem::AllocatorPtr sysmem_allocator_;
+ fuchsia::images::ImagePipe2Ptr image_pipe_;
+ SkiaOutputSurfaceDependency* const dependency_;
+ gpu::SharedImageFactory shared_image_factory_;
+ gpu::SharedImageRepresentationFactory shared_image_representation_factory_;
+
+ gfx::Size frame_size_;
+ gfx::BufferFormat buffer_format_ = gfx::BufferFormat::RGBA_8888;
+
+ // Last buffer collection ID for the ImagePipe. Incremented every time buffers
+ // are reallocated.
+ uint32_t last_buffer_collection_id_ = 0;
+
+ // Counter to generate image IDs for the ImagePipe.
+ uint32_t last_image_id_ = 0;
+
+ std::unique_ptr<gpu::SysmemBufferCollection> buffer_collection_;
+
+ // The next frame to be submitted by SwapBuffers().
+ base::Optional<PendingFrame> next_frame_;
+
+ base::circular_deque<PendingFrame> pending_frames_;
+
+ bool present_is_pending_ = false;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_PRESENTER_FUCHSIA_H_
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_gl.cc b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
new file mode 100644
index 00000000000..289ab589939
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_presenter_gl.cc
@@ -0,0 +1,408 @@
+// Copyright 2020 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/output_presenter_gl.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/ipc/common/gpu_surface_lookup.h"
+#include "ui/display/types/display_snapshot.h"
+#include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gl/gl_fence.h"
+#include "ui/gl/gl_surface.h"
+
+#if defined(OS_ANDROID)
+#include "ui/gl/gl_surface_egl_surface_control.h"
+#endif
+
+#if defined(USE_OZONE)
+#include "ui/base/ui_base_features.h"
+#endif
+
+namespace viz {
+
+namespace {
+
+class PresenterImageGL : public OutputPresenter::Image {
+ public:
+ PresenterImageGL() = default;
+ ~PresenterImageGL() override = default;
+
+ bool Initialize(gpu::SharedImageFactory* factory,
+ gpu::SharedImageRepresentationFactory* representation_factory,
+ const gfx::Size& size,
+ const gfx::ColorSpace& color_space,
+ ResourceFormat format,
+ SkiaOutputSurfaceDependency* deps,
+ uint32_t shared_image_usage);
+
+ void BeginPresent() final;
+ void EndPresent() final;
+ int present_count() const final;
+
+ gl::GLImage* GetGLImage(std::unique_ptr<gfx::GpuFence>* fence);
+
+ private:
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay>
+ overlay_representation_;
+ std::unique_ptr<gpu::SharedImageRepresentationGLTexture> gl_representation_;
+ std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
+ scoped_overlay_read_access_;
+ std::unique_ptr<gpu::SharedImageRepresentationGLTexture::ScopedAccess>
+ scoped_gl_read_access_;
+
+ int present_count_ = 0;
+};
+
+bool PresenterImageGL::Initialize(
+ gpu::SharedImageFactory* factory,
+ gpu::SharedImageRepresentationFactory* representation_factory,
+ const gfx::Size& size,
+ const gfx::ColorSpace& color_space,
+ ResourceFormat format,
+ SkiaOutputSurfaceDependency* deps,
+ uint32_t shared_image_usage) {
+ auto mailbox = gpu::Mailbox::GenerateForSharedImage();
+
+ if (!factory->CreateSharedImage(mailbox, format, size, color_space,
+ deps->GetSurfaceHandle(),
+ shared_image_usage)) {
+ DLOG(ERROR) << "CreateSharedImage failed.";
+ return false;
+ }
+
+ if (!Image::Initialize(factory, representation_factory, mailbox, deps))
+ return false;
+
+ overlay_representation_ = representation_factory->ProduceOverlay(mailbox);
+
+ // If the backing doesn't support overlay, then fallback to GL.
+ if (!overlay_representation_)
+ gl_representation_ = representation_factory->ProduceGLTexture(mailbox);
+
+ if (!overlay_representation_ && !gl_representation_) {
+ DLOG(ERROR) << "ProduceOverlay() and ProduceGLTexture() failed.";
+ return false;
+ }
+
+ return true;
+}
+
+void PresenterImageGL::BeginPresent() {
+ if (++present_count_ != 1) {
+ DCHECK(scoped_overlay_read_access_ || scoped_gl_read_access_);
+ return;
+ }
+
+ DCHECK(!sk_surface());
+ DCHECK(!scoped_overlay_read_access_);
+
+ if (overlay_representation_) {
+ scoped_overlay_read_access_ =
+ overlay_representation_->BeginScopedReadAccess(
+ true /* need_gl_image */);
+ DCHECK(scoped_overlay_read_access_);
+ return;
+ }
+
+ scoped_gl_read_access_ = gl_representation_->BeginScopedAccess(
+ GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM,
+ gpu::SharedImageRepresentation::AllowUnclearedAccess::kNo);
+ DCHECK(scoped_gl_read_access_);
+}
+
+void PresenterImageGL::EndPresent() {
+ DCHECK(present_count_);
+ if (--present_count_)
+ return;
+ scoped_overlay_read_access_.reset();
+ scoped_gl_read_access_.reset();
+}
+
+int PresenterImageGL::present_count() const {
+ return present_count_;
+}
+
+gl::GLImage* PresenterImageGL::GetGLImage(
+ std::unique_ptr<gfx::GpuFence>* fence) {
+ if (scoped_overlay_read_access_)
+ return scoped_overlay_read_access_->gl_image();
+
+ DCHECK(scoped_gl_read_access_);
+
+ if (gl::GLFence::IsGpuFenceSupported() && fence) {
+ if (auto gl_fence = gl::GLFence::CreateForGpuFence())
+ *fence = gl_fence->GetGpuFence();
+ }
+ auto* texture = gl_representation_->GetTexture();
+ return texture->GetLevelImage(texture->target(), 0);
+}
+
+} // namespace
+
+// static
+const uint32_t OutputPresenterGL::kDefaultSharedImageUsage =
+ gpu::SHARED_IMAGE_USAGE_SCANOUT | gpu::SHARED_IMAGE_USAGE_DISPLAY |
+ gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
+
+// static
+std::unique_ptr<OutputPresenterGL> OutputPresenterGL::Create(
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker) {
+#if defined(OS_ANDROID)
+ if (deps->GetGpuFeatureInfo()
+ .status_values[gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] !=
+ gpu::kGpuFeatureStatusEnabled) {
+ return nullptr;
+ }
+
+ bool can_be_used_with_surface_control = false;
+ ANativeWindow* window =
+ gpu::GpuSurfaceLookup::GetInstance()->AcquireNativeWidget(
+ deps->GetSurfaceHandle(), &can_be_used_with_surface_control);
+ if (!window || !can_be_used_with_surface_control)
+ return nullptr;
+ // TODO(https://crbug.com/1012401): don't depend on GL.
+ auto gl_surface = base::MakeRefCounted<gl::GLSurfaceEGLSurfaceControl>(
+ window, base::ThreadTaskRunnerHandle::Get());
+ if (!gl_surface->Initialize(gl::GLSurfaceFormat())) {
+ LOG(ERROR) << "Failed to initialize GLSurfaceEGLSurfaceControl.";
+ return nullptr;
+ }
+
+ if (!deps->GetSharedContextState()->MakeCurrent(gl_surface.get(),
+ true /* needs_gl*/)) {
+ LOG(ERROR) << "MakeCurrent failed.";
+ return nullptr;
+ }
+
+ return std::make_unique<OutputPresenterGL>(
+ std::move(gl_surface), deps, memory_tracker, kDefaultSharedImageUsage);
+#else
+ return nullptr;
+#endif
+}
+
+OutputPresenterGL::OutputPresenterGL(scoped_refptr<gl::GLSurface> gl_surface,
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker,
+ uint32_t shared_image_usage)
+ : gl_surface_(gl_surface),
+ dependency_(deps),
+ supports_async_swap_(gl_surface_->SupportsAsyncSwap()),
+ shared_image_factory_(deps->GetGpuPreferences(),
+ deps->GetGpuDriverBugWorkarounds(),
+ deps->GetGpuFeatureInfo(),
+ deps->GetSharedContextState().get(),
+ deps->GetMailboxManager(),
+ deps->GetSharedImageManager(),
+ deps->GetGpuImageFactory(),
+ memory_tracker,
+ true),
+ shared_image_representation_factory_(deps->GetSharedImageManager(),
+ memory_tracker),
+ shared_image_usage_(shared_image_usage) {
+ // GL is origin is at bottom left normally, all Surfaceless implementations
+ // are flipped.
+ DCHECK_EQ(gl_surface_->GetOrigin(), gfx::SurfaceOrigin::kTopLeft);
+
+ // TODO(https://crbug.com/958166): The initial |image_format_| should not be
+ // used, and the gfx::BufferFormat specified in Reshape should be used
+ // instead, because it may be updated to reflect changes in the content being
+ // displayed (e.g, HDR content appearing on-screen).
+#if defined(OS_MACOSX)
+ image_format_ = BGRA_8888;
+#else
+#if defined(USE_OZONE)
+ if (features::IsUsingOzonePlatform()) {
+ image_format_ =
+ GetResourceFormat(display::DisplaySnapshot::PrimaryFormat());
+ return;
+ }
+#endif
+ image_format_ = RGBA_8888;
+#endif
+}
+
+OutputPresenterGL::~OutputPresenterGL() = default;
+
+void OutputPresenterGL::InitializeCapabilities(
+ OutputSurface::Capabilities* capabilities) {
+ capabilities->android_surface_control_feature_enabled = true;
+ capabilities->supports_post_sub_buffer = gl_surface_->SupportsPostSubBuffer();
+ capabilities->supports_commit_overlay_planes =
+ gl_surface_->SupportsCommitOverlayPlanes();
+
+ // Set supports_surfaceless to enable overlays.
+ capabilities->supports_surfaceless = true;
+ // We expect origin of buffers is at top left.
+ capabilities->output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
+
+ // TODO(penghuang): Use defaultBackendFormat() in shared image implementation
+ // to make sure backend format is consistent.
+ capabilities->sk_color_type = ResourceFormatToClosestSkColorType(
+ true /* gpu_compositing */, image_format_);
+ capabilities->gr_backend_format =
+ dependency_->GetSharedContextState()->gr_context()->defaultBackendFormat(
+ capabilities->sk_color_type, GrRenderable::kYes);
+}
+
+bool OutputPresenterGL::Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ gfx::BufferFormat format,
+ gfx::OverlayTransform transform) {
+ return gl_surface_->Resize(size, device_scale_factor, color_space,
+ gfx::AlphaBitsForBufferFormat(format));
+}
+
+std::vector<std::unique_ptr<OutputPresenter::Image>>
+OutputPresenterGL::AllocateImages(gfx::ColorSpace color_space,
+ gfx::Size image_size,
+ size_t num_images) {
+ std::vector<std::unique_ptr<Image>> images;
+ for (size_t i = 0; i < num_images; ++i) {
+ auto image = std::make_unique<PresenterImageGL>();
+ if (!image->Initialize(&shared_image_factory_,
+ &shared_image_representation_factory_, image_size,
+ color_space, image_format_, dependency_,
+ shared_image_usage_)) {
+ DLOG(ERROR) << "Failed to initialize image.";
+ return {};
+ }
+ images.push_back(std::move(image));
+ }
+
+ return images;
+}
+
+void OutputPresenterGL::SwapBuffers(
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) {
+ if (supports_async_swap_) {
+ gl_surface_->SwapBuffersAsync(std::move(completion_callback),
+ std::move(presentation_callback));
+ } else {
+ auto result = gl_surface_->SwapBuffers(std::move(presentation_callback));
+ std::move(completion_callback).Run(gfx::SwapCompletionResult(result));
+ }
+}
+
+void OutputPresenterGL::PostSubBuffer(
+ const gfx::Rect& rect,
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) {
+ if (supports_async_swap_) {
+ gl_surface_->PostSubBufferAsync(
+ rect.x(), rect.y(), rect.width(), rect.height(),
+ std::move(completion_callback), std::move(presentation_callback));
+ } else {
+ auto result = gl_surface_->PostSubBuffer(rect.x(), rect.y(), rect.width(),
+ rect.height(),
+ std::move(presentation_callback));
+ std::move(completion_callback).Run(gfx::SwapCompletionResult(result));
+ }
+}
+
+void OutputPresenterGL::SchedulePrimaryPlane(
+ const OverlayProcessorInterface::OutputSurfaceOverlayPlane& plane,
+ Image* image,
+ bool is_submitted) {
+ std::unique_ptr<gfx::GpuFence> fence;
+ // If the submitted_image() is being scheduled, we don't new a new fence.
+ auto* gl_image = reinterpret_cast<PresenterImageGL*>(image)->GetGLImage(
+ is_submitted ? nullptr : &fence);
+
+ // Output surface is also z-order 0.
+ constexpr int kPlaneZOrder = 0;
+ // Output surface always uses the full texture.
+ constexpr gfx::RectF kUVRect(0.f, 0.f, 1.0f, 1.0f);
+ gl_surface_->ScheduleOverlayPlane(kPlaneZOrder, plane.transform, gl_image,
+ ToNearestRect(plane.display_rect), kUVRect,
+ plane.enable_blending, std::move(fence));
+}
+
+void OutputPresenterGL::CommitOverlayPlanes(
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) {
+ if (supports_async_swap_) {
+ gl_surface_->CommitOverlayPlanesAsync(std::move(completion_callback),
+ std::move(presentation_callback));
+ } else {
+ auto result =
+ gl_surface_->CommitOverlayPlanes(std::move(presentation_callback));
+ std::move(completion_callback).Run(gfx::SwapCompletionResult(result));
+ }
+}
+
+std::vector<OutputPresenter::OverlayData> OutputPresenterGL::ScheduleOverlays(
+ SkiaOutputSurface::OverlayList overlays) {
+ std::vector<OverlayData> pending_overlays;
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
+ // Note while reading through this for-loop that |overlay| has different
+ // types on different platforms. On Android and Ozone it is an
+ // OverlayCandidate, on Windows it is a DCLayerOverlay, and on macOS it is
+ // a CALayerOverlay.
+ for (auto& overlay : overlays) {
+ // Extract the shared image and GLImage for the overlay. Note that for
+ // solid color overlays, this will remain nullptr.
+ gl::GLImage* gl_image = nullptr;
+ if (overlay.mailbox.IsSharedImage()) {
+ auto shared_image =
+ shared_image_representation_factory_.ProduceOverlay(overlay.mailbox);
+ // When display is re-opened, the first few frames might not have video
+ // resource ready. Possible investigation crbug.com/1023971.
+ if (!shared_image) {
+ LOG(ERROR) << "Invalid mailbox.";
+ continue;
+ }
+
+ auto shared_image_access =
+ shared_image->BeginScopedReadAccess(true /* needs_gl_image */);
+ if (!shared_image_access) {
+ LOG(ERROR) << "Could not access SharedImage for read.";
+ continue;
+ }
+
+ gl_image = shared_image_access->gl_image();
+ DLOG_IF(ERROR, !gl_image) << "Cannot get GLImage.";
+
+ pending_overlays.emplace_back(std::move(shared_image),
+ std::move(shared_image_access));
+ }
+
+#if defined(OS_ANDROID)
+ if (gl_image) {
+ DCHECK(!overlay.gpu_fence_id);
+ gl_surface_->ScheduleOverlayPlane(
+ overlay.plane_z_order, overlay.transform, gl_image,
+ ToNearestRect(overlay.display_rect), overlay.uv_rect,
+ !overlay.is_opaque, nullptr /* gpu_fence */);
+ }
+#elif defined(OS_MACOSX)
+ gl_surface_->ScheduleCALayer(ui::CARendererLayerParams(
+ overlay.shared_state->is_clipped,
+ gfx::ToEnclosingRect(overlay.shared_state->clip_rect),
+ overlay.shared_state->rounded_corner_bounds,
+ 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,
+ overlay.shared_state->opacity, overlay.filter));
+#endif
+ }
+#endif // defined(OS_ANDROID) || defined(OS_MACOSX)
+
+ return pending_overlays;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_presenter_gl.h b/chromium/components/viz/service/display_embedder/output_presenter_gl.h
new file mode 100644
index 00000000000..bfbf51996d1
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_presenter_gl.h
@@ -0,0 +1,78 @@
+// Copyright 2020 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_OUTPUT_PRESENTER_GL_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_PRESENTER_GL_H_
+
+#include <memory>
+#include <vector>
+
+#include "components/viz/service/display_embedder/output_presenter.h"
+#include "components/viz/service/viz_service_export.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/command_buffer/service/shared_image_factory.h"
+
+namespace gl {
+class GLSurface;
+} // namespace gl
+
+namespace viz {
+
+class VIZ_SERVICE_EXPORT OutputPresenterGL : public OutputPresenter {
+ public:
+ static const uint32_t kDefaultSharedImageUsage;
+
+ static std::unique_ptr<OutputPresenterGL> Create(
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker);
+
+ OutputPresenterGL(scoped_refptr<gl::GLSurface> gl_surface,
+ SkiaOutputSurfaceDependency* deps,
+ gpu::MemoryTracker* memory_tracker,
+ uint32_t shared_image_usage = kDefaultSharedImageUsage);
+ ~OutputPresenterGL() override;
+
+ gl::GLSurface* gl_surface() { return gl_surface_.get(); }
+
+ // OutputPresenter implementation:
+ void InitializeCapabilities(OutputSurface::Capabilities* capabilities) final;
+ bool Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ gfx::BufferFormat format,
+ gfx::OverlayTransform transform) final;
+ std::vector<std::unique_ptr<Image>> AllocateImages(
+ gfx::ColorSpace color_space,
+ gfx::Size image_size,
+ size_t num_images) final;
+ void SwapBuffers(SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) final;
+ void PostSubBuffer(const gfx::Rect& rect,
+ SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) final;
+ void CommitOverlayPlanes(SwapCompletionCallback completion_callback,
+ BufferPresentedCallback presentation_callback) final;
+ void SchedulePrimaryPlane(
+ const OverlayProcessorInterface::OutputSurfaceOverlayPlane& plane,
+ Image* image,
+ bool is_submitted) final;
+ std::vector<OverlayData> ScheduleOverlays(
+ SkiaOutputSurface::OverlayList overlays) final;
+
+ private:
+ scoped_refptr<gl::GLSurface> gl_surface_;
+ SkiaOutputSurfaceDependency* dependency_;
+ const bool supports_async_swap_;
+
+ ResourceFormat image_format_;
+
+ // Shared Image factories
+ gpu::SharedImageFactory shared_image_factory_;
+ gpu::SharedImageRepresentationFactory shared_image_representation_factory_;
+ uint32_t shared_image_usage_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_PRESENTER_GL_H_
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 b4d4b1c1c59..da8936a87cf 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
@@ -57,6 +57,7 @@
#if defined(USE_OZONE)
#include "components/viz/service/display_embedder/software_output_device_ozone.h"
+#include "ui/base/ui_base_features.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/platform_window_surface.h"
@@ -115,11 +116,6 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
output_surface = std::make_unique<SoftwareOutputSurface>(
CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client));
} else if (renderer_settings.use_skia_renderer) {
-#if defined(OS_MACOSX)
- // TODO(penghuang): Support SkiaRenderer for all platforms.
- NOTIMPLEMENTED();
- return nullptr;
-#else
{
gpu::ScopedAllowScheduleGpuTask allow_schedule_gpu_task;
output_surface = SkiaOutputSurfaceImpl::Create(
@@ -138,7 +134,6 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
#endif
return nullptr;
}
-#endif
} else {
DCHECK(task_executor_);
@@ -183,6 +178,10 @@ std::unique_ptr<OutputSurface> OutputSurfaceProviderImpl::CreateOutputSurface(
std::move(context_provider));
} else if (context_provider->ContextCapabilities().surfaceless) {
#if defined(USE_OZONE) || defined(OS_MACOSX) || defined(OS_ANDROID)
+#if defined(USE_OZONE)
+ if (!features::IsUsingOzonePlatform())
+ NOTREACHED();
+#endif
output_surface = std::make_unique<GLOutputSurfaceBufferQueue>(
std::move(context_provider), surface_handle,
std::make_unique<BufferQueue>(
@@ -234,24 +233,31 @@ OutputSurfaceProviderImpl::CreateSoftwareOutputDeviceForPlatform(
NOTREACHED();
return nullptr;
#elif defined(USE_OZONE)
- ui::SurfaceFactoryOzone* factory =
- ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
- std::unique_ptr<ui::PlatformWindowSurface> platform_window_surface =
- factory->CreatePlatformWindowSurface(surface_handle);
- bool in_host_process =
- !gpu_service_impl_ || gpu_service_impl_->in_host_process();
- std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
- factory->CreateCanvasForWidget(
- surface_handle,
- in_host_process ? nullptr : gpu_service_impl_->main_runner());
- CHECK(surface_ozone);
- return std::make_unique<SoftwareOutputDeviceOzone>(
- std::move(platform_window_surface), std::move(surface_ozone));
-#elif defined(USE_X11)
+ if (features::IsUsingOzonePlatform()) {
+ ui::SurfaceFactoryOzone* factory =
+ ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
+ std::unique_ptr<ui::PlatformWindowSurface> platform_window_surface =
+ factory->CreatePlatformWindowSurface(surface_handle);
+ bool in_host_process =
+ !gpu_service_impl_ || gpu_service_impl_->in_host_process();
+ std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
+ factory->CreateCanvasForWidget(
+ surface_handle,
+ in_host_process ? nullptr : gpu_service_impl_->main_runner());
+ CHECK(surface_ozone);
+ return std::make_unique<SoftwareOutputDeviceOzone>(
+ std::move(platform_window_surface), std::move(surface_ozone));
+ }
+#endif
+
+#if defined(USE_X11)
return std::make_unique<SoftwareOutputDeviceX11>(
surface_handle, gpu_service_impl_->in_host_process()
? nullptr
: gpu_service_impl_->main_runner());
+#else
+ NOTREACHED();
+ return nullptr;
#endif
}
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 3bec0806cec..d767dd45e7a 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device.cc
@@ -6,15 +6,43 @@
#include <utility>
+#include "base/bind.h"
#include "base/check_op.h"
#include "base/notreached.h"
+#include "base/task/task_traits.h"
+#include "base/task/thread_pool.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
#include "components/viz/service/display/dc_layer_overlay.h"
#include "gpu/command_buffer/service/memory_tracking.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/gpu_fence.h"
#include "ui/gfx/presentation_feedback.h"
+#include "ui/latency/latency_tracker.h"
namespace viz {
+namespace {
+
+scoped_refptr<base::SequencedTaskRunner> CreateLatencyTracerRunner() {
+ if (!base::ThreadPoolInstance::Get())
+ return nullptr;
+ return base::ThreadPool::CreateSequencedTaskRunner(
+ {base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+}
+
+void ReportLatency(const gfx::SwapTimings& timings,
+ ui::LatencyTracker* tracker,
+ std::vector<ui::LatencyInfo> latency_info) {
+ for (auto& latency : latency_info) {
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, timings.swap_start);
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT, timings.swap_end);
+ }
+ tracker->OnGpuSwapBuffersCompleted(std::move(latency_info));
+}
+
+} // namespace
SkiaOutputDevice::ScopedPaint::ScopedPaint(SkiaOutputDevice* device)
: device_(device), sk_surface_(device->BeginPaint(&end_semaphores_)) {
@@ -31,9 +59,14 @@ SkiaOutputDevice::SkiaOutputDevice(
: did_swap_buffer_complete_callback_(
std::move(did_swap_buffer_complete_callback)),
memory_type_tracker_(
- std::make_unique<gpu::MemoryTypeTracker>(memory_tracker)) {}
+ std::make_unique<gpu::MemoryTypeTracker>(memory_tracker)),
+ latency_tracker_(std::make_unique<ui::LatencyTracker>()),
+ latency_tracker_runner_(CreateLatencyTracerRunner()) {}
-SkiaOutputDevice::~SkiaOutputDevice() = default;
+SkiaOutputDevice::~SkiaOutputDevice() {
+ if (latency_tracker_runner_)
+ latency_tracker_runner_->DeleteSoon(FROM_HERE, std::move(latency_tracker_));
+}
void SkiaOutputDevice::CommitOverlayPlanes(
BufferPresentedCallback feedback,
@@ -48,7 +81,9 @@ void SkiaOutputDevice::PostSubBuffer(
NOTREACHED();
}
-void SkiaOutputDevice::SetDrawRectangle(const gfx::Rect& draw_rectangle) {}
+bool SkiaOutputDevice::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
+ return false;
+}
void SkiaOutputDevice::SetGpuVSyncEnabled(bool enabled) {
NOTIMPLEMENTED();
@@ -74,6 +109,9 @@ void SkiaOutputDevice::SetEnableDCLayers(bool enable) {
}
#endif
+void SkiaOutputDevice::EnsureBackbuffer() {}
+void SkiaOutputDevice::DiscardBackbuffer() {}
+
void SkiaOutputDevice::StartSwapBuffers(BufferPresentedCallback feedback) {
DCHECK_LT(static_cast<int>(pending_swaps_.size()),
capabilities_.max_frames_pending);
@@ -82,34 +120,33 @@ void SkiaOutputDevice::StartSwapBuffers(BufferPresentedCallback feedback) {
}
void SkiaOutputDevice::FinishSwapBuffers(
- gfx::SwapResult result,
+ gfx::SwapCompletionResult result,
const gfx::Size& size,
- std::vector<ui::LatencyInfo> latency_info) {
+ std::vector<ui::LatencyInfo> latency_info,
+ const base::Optional<gfx::Rect>& damage_area) {
DCHECK(!pending_swaps_.empty());
const gpu::SwapBuffersCompleteParams& params =
- pending_swaps_.front().Complete(result);
+ pending_swaps_.front().Complete(std::move(result), damage_area);
did_swap_buffer_complete_callback_.Run(params, size);
pending_swaps_.front().CallFeedback();
- for (auto& latency : latency_info) {
- latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT,
- params.swap_response.timings.swap_start);
- latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_FRAME_SWAP_COMPONENT,
- params.swap_response.timings.swap_end);
+ if (latency_tracker_runner_) {
+ // Report latency off GPU main thread.
+ latency_tracker_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ReportLatency, params.swap_response.timings,
+ latency_tracker_.get(), std::move(latency_info)));
+ } else {
+ ReportLatency(params.swap_response.timings, latency_tracker_.get(),
+ std::move(latency_info));
}
- latency_tracker_.OnGpuSwapBuffersCompleted(latency_info);
pending_swaps_.pop();
}
-void SkiaOutputDevice::EnsureBackbuffer() {}
-void SkiaOutputDevice::DiscardBackbuffer() {}
-
SkiaOutputDevice::SwapInfo::SwapInfo(
uint64_t swap_id,
SkiaOutputDevice::BufferPresentedCallback feedback)
@@ -123,10 +160,13 @@ SkiaOutputDevice::SwapInfo::SwapInfo(SwapInfo&& other) = default;
SkiaOutputDevice::SwapInfo::~SwapInfo() = default;
const gpu::SwapBuffersCompleteParams& SkiaOutputDevice::SwapInfo::Complete(
- gfx::SwapResult result) {
- params_.swap_response.result = result;
+ gfx::SwapCompletionResult result,
+ const base::Optional<gfx::Rect>& damage_rect) {
+ params_.swap_response.result = result.swap_result;
params_.swap_response.timings.swap_end = base::TimeTicks::Now();
-
+ params_.frame_buffer_damage_area = damage_rect;
+ if (result.ca_layer_params)
+ params_.ca_layer_params = *result.ca_layer_params;
return params_;
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device.h b/chromium/components/viz/service/display_embedder/skia_output_device.h
index 80dab35e5c3..0aa9857cd2c 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/containers/queue.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "build/build_config.h"
#include "components/viz/service/display/output_surface.h"
@@ -20,10 +21,13 @@
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/src/gpu/GrSemaphore.h"
#include "ui/gfx/swap_result.h"
-#include "ui/latency/latency_tracker.h"
class SkSurface;
+namespace base {
+class SequencedTaskRunner;
+}
+
namespace gfx {
class ColorSpace;
class Rect;
@@ -36,6 +40,10 @@ class MemoryTracker;
class MemoryTypeTracker;
} // namespace gpu
+namespace ui {
+class LatencyTracker;
+}
+
namespace viz {
class SkiaOutputDevice {
@@ -89,7 +97,7 @@ class SkiaOutputDevice {
std::vector<ui::LatencyInfo> latency_info);
// Set the rectangle that will be drawn into on the surface.
- virtual void SetDrawRectangle(const gfx::Rect& draw_rectangle);
+ virtual bool SetDrawRectangle(const gfx::Rect& draw_rectangle);
virtual void SetGpuVSyncEnabled(bool enabled);
@@ -129,7 +137,9 @@ class SkiaOutputDevice {
SwapInfo(uint64_t swap_id, BufferPresentedCallback feedback);
SwapInfo(SwapInfo&& other);
~SwapInfo();
- const gpu::SwapBuffersCompleteParams& Complete(gfx::SwapResult result);
+ const gpu::SwapBuffersCompleteParams& Complete(
+ gfx::SwapCompletionResult result,
+ const base::Optional<gfx::Rect>& damage_area);
void CallFeedback();
private:
@@ -150,9 +160,11 @@ class SkiaOutputDevice {
// Helper method for SwapBuffers() and PostSubBuffer(). It should be called
// at the end of SwapBuffers() and PostSubBuffer() implementations
- void FinishSwapBuffers(gfx::SwapResult result,
- const gfx::Size& size,
- std::vector<ui::LatencyInfo> latency_info);
+ void FinishSwapBuffers(
+ gfx::SwapCompletionResult result,
+ const gfx::Size& size,
+ std::vector<ui::LatencyInfo> latency_info,
+ const base::Optional<gfx::Rect>& damage_area = base::nullopt);
OutputSurface::Capabilities capabilities_;
@@ -161,13 +173,16 @@ class SkiaOutputDevice {
base::queue<SwapInfo> pending_swaps_;
- ui::LatencyTracker latency_tracker_;
-
// RGBX format is emulated with RGBA.
bool is_emulated_rgbx_ = false;
std::unique_ptr<gpu::MemoryTypeTracker> memory_type_tracker_;
+ private:
+ std::unique_ptr<ui::LatencyTracker> latency_tracker_;
+ // task runner for latency tracker.
+ scoped_refptr<base::SequencedTaskRunner> latency_tracker_runner_;
+
DISALLOW_COPY_AND_ASSIGN(SkiaOutputDevice);
};
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 1ba33bf3fe3..1969bdfedcc 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
@@ -4,284 +4,36 @@
#include "components/viz/service/display_embedder/skia_output_device_buffer_queue.h"
+#include <memory>
+#include <utility>
+#include <vector>
+
#include "base/command_line.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
-#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/switches.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
#include "gpu/command_buffer/common/capabilities.h"
-#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/config/gpu_finch_features.h"
-#include "gpu/ipc/common/gpu_surface_lookup.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceProps.h"
-#include "ui/display/types/display_snapshot.h"
-#include "ui/gfx/buffer_format_util.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_surface.h"
-#if defined(OS_ANDROID)
-#include "ui/gl/gl_surface_egl_surface_control.h"
-#endif
-
namespace viz {
-namespace {
-
-constexpr uint32_t kSharedImageUsage =
- gpu::SHARED_IMAGE_USAGE_SCANOUT | gpu::SHARED_IMAGE_USAGE_DISPLAY |
- gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
-
-} // namespace
-
-class SkiaOutputDeviceBufferQueue::Image {
- public:
- Image(gpu::SharedImageFactory* factory,
- gpu::SharedImageRepresentationFactory* representation_factory)
- : factory_(factory), representation_factory_(representation_factory) {}
- ~Image() {
- // TODO(vasilyt): As we are going to delete image anyway we should be able
- // to abort write to avoid unnecessary flush to submit semaphores.
- if (scoped_skia_write_access_) {
- EndWriteSkia();
- }
- DCHECK(!scoped_skia_write_access_);
- }
-
- bool Initialize(const gfx::Size& size,
- const gfx::ColorSpace& color_space,
- ResourceFormat format,
- SkiaOutputSurfaceDependency* deps,
- uint32_t shared_image_usage) {
- auto mailbox = gpu::Mailbox::GenerateForSharedImage();
- // TODO(penghuang): This should pass the surface handle for ChromeOS
- if (!factory_->CreateSharedImage(mailbox, format, size, color_space,
- gpu::kNullSurfaceHandle,
- shared_image_usage)) {
- DLOG(ERROR) << "CreateSharedImage failed.";
- return false;
- }
-
- // Initialize |shared_image_deletor_| to make sure the shared image backing
- // will be released with the Image.
- shared_image_deletor_.ReplaceClosure(base::BindOnce(
- base::IgnoreResult(&gpu::SharedImageFactory::DestroySharedImage),
- base::Unretained(factory_), mailbox));
-
- skia_representation_ = representation_factory_->ProduceSkia(
- mailbox, deps->GetSharedContextState());
- if (!skia_representation_) {
- DLOG(ERROR) << "ProduceSkia() failed.";
- return false;
- }
-
- overlay_representation_ = representation_factory_->ProduceOverlay(mailbox);
-
- // If the backing doesn't support overlay, then fallback to GL.
- if (!overlay_representation_)
- gl_representation_ = representation_factory_->ProduceGLTexture(mailbox);
-
- if (!overlay_representation_ && !gl_representation_) {
- DLOG(ERROR) << "ProduceOverlay() and ProduceGLTexture() failed.";
- return false;
- }
-
- return true;
- }
-
- void BeginWriteSkia() {
- DCHECK(!scoped_skia_write_access_);
- DCHECK(!scoped_overlay_read_access_);
- DCHECK(end_semaphores_.empty());
-
- std::vector<GrBackendSemaphore> begin_semaphores;
- // LegacyFontHost will get LCD text and skia figures out what type to use.
- SkSurfaceProps surface_props(0 /* flags */,
- SkSurfaceProps::kLegacyFontHost_InitType);
-
- // Buffer queue is internal to GPU proc and handles texture initialization,
- // so allow uncleared access.
- // TODO(vasilyt): Props and MSAA
- scoped_skia_write_access_ = skia_representation_->BeginScopedWriteAccess(
- 0 /* final_msaa_count */, surface_props, &begin_semaphores,
- &end_semaphores_,
- gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
- DCHECK(scoped_skia_write_access_);
- if (!begin_semaphores.empty()) {
- scoped_skia_write_access_->surface()->wait(begin_semaphores.size(),
- begin_semaphores.data());
- }
- }
-
- SkSurface* sk_surface() {
- return scoped_skia_write_access_ ? scoped_skia_write_access_->surface()
- : nullptr;
- }
-
- std::vector<GrBackendSemaphore> TakeEndWriteSkiaSemaphores() {
- std::vector<GrBackendSemaphore> temp_vector;
- temp_vector.swap(end_semaphores_);
- return temp_vector;
- }
-
- void EndWriteSkia() {
- // The Flush now takes place in finishPaintCurrentBuffer on the CPU side.
- // check if end_semaphores is not empty then flash here
- DCHECK(scoped_skia_write_access_);
- if (!end_semaphores_.empty()) {
- GrFlushInfo flush_info = {
- .fFlags = kNone_GrFlushFlags,
- .fNumSemaphores = end_semaphores_.size(),
- .fSignalSemaphores = end_semaphores_.data(),
- };
- scoped_skia_write_access_->surface()->flush(
- SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
- }
- scoped_skia_write_access_.reset();
- end_semaphores_.clear();
-
- // SkiaRenderer always draws the full frame.
- skia_representation_->SetCleared();
- }
-
- void BeginPresent() {
- if (++present_count_ != 1) {
- DCHECK(scoped_overlay_read_access_ || scoped_gl_read_access_);
- return;
- }
-
- DCHECK(!scoped_skia_write_access_);
- DCHECK(!scoped_overlay_read_access_);
-
- if (overlay_representation_) {
- scoped_overlay_read_access_ =
- overlay_representation_->BeginScopedReadAccess(
- true /* need_gl_image */);
- DCHECK(scoped_overlay_read_access_);
- return;
- }
-
- scoped_gl_read_access_ = gl_representation_->BeginScopedAccess(
- GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM,
- gpu::SharedImageRepresentation::AllowUnclearedAccess::kNo);
- DCHECK(scoped_gl_read_access_);
- }
-
- void EndPresent() {
- DCHECK(present_count_);
- if (--present_count_)
- return;
- scoped_overlay_read_access_.reset();
- scoped_gl_read_access_.reset();
- }
-
- gl::GLImage* GetGLImage(std::unique_ptr<gfx::GpuFence>* fence) {
- if (scoped_overlay_read_access_)
- return scoped_overlay_read_access_->gl_image();
-
- DCHECK(scoped_gl_read_access_);
-
- if (gl::GLFence::IsGpuFenceSupported() && fence) {
- if (auto gl_fence = gl::GLFence::CreateForGpuFence())
- *fence = gl_fence->GetGpuFence();
- }
- auto* texture = gl_representation_->GetTexture();
- return texture->GetLevelImage(texture->target(), 0);
- }
-
- base::WeakPtr<Image> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); }
-
- int present_count() const { return present_count_; }
- gpu::SharedImageRepresentationSkia* skia_representation() {
- return skia_representation_.get();
- }
- const gfx::Size& size() const { return skia_representation_->size(); }
-
- private:
- gpu::SharedImageFactory* const factory_;
- gpu::SharedImageRepresentationFactory* const representation_factory_;
-
- base::ScopedClosureRunner shared_image_deletor_;
- std::unique_ptr<gpu::SharedImageRepresentationSkia> skia_representation_;
- std::unique_ptr<gpu::SharedImageRepresentationOverlay>
- overlay_representation_;
- std::unique_ptr<gpu::SharedImageRepresentationGLTexture> gl_representation_;
- std::unique_ptr<gpu::SharedImageRepresentationSkia::ScopedWriteAccess>
- scoped_skia_write_access_;
- std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
- scoped_overlay_read_access_;
- std::unique_ptr<gpu::SharedImageRepresentationGLTexture::ScopedAccess>
- scoped_gl_read_access_;
- std::vector<GrBackendSemaphore> end_semaphores_;
- int present_count_ = 0;
- base::WeakPtrFactory<Image> weak_ptr_factory_{this};
-
- DISALLOW_COPY_AND_ASSIGN(Image);
-};
-
-class SkiaOutputDeviceBufferQueue::OverlayData {
- public:
- OverlayData(
- std::unique_ptr<gpu::SharedImageRepresentationOverlay> representation,
- std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
- scoped_read_access)
- : representation_(std::move(representation)),
- scoped_read_access_(std::move(scoped_read_access)) {}
- OverlayData(OverlayData&&) = default;
- ~OverlayData() = default;
- OverlayData& operator=(OverlayData&&) = default;
-
- gl::GLImage* gl_image() { return scoped_read_access_->gl_image(); }
-
- private:
- std::unique_ptr<gpu::SharedImageRepresentationOverlay> representation_;
- std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
- scoped_read_access_;
-};
SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue(
- scoped_refptr<gl::GLSurface> gl_surface,
+ std::unique_ptr<OutputPresenter> presenter,
SkiaOutputSurfaceDependency* deps,
gpu::MemoryTracker* memory_tracker,
- const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
- uint32_t shared_image_usage)
+ const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback)
: SkiaOutputDevice(memory_tracker, did_swap_buffer_complete_callback),
- dependency_(deps),
- gl_surface_(std::move(gl_surface)),
- supports_async_swap_(gl_surface_->SupportsAsyncSwap()),
- shared_image_factory_(deps->GetGpuPreferences(),
- deps->GetGpuDriverBugWorkarounds(),
- deps->GetGpuFeatureInfo(),
- deps->GetSharedContextState().get(),
- deps->GetMailboxManager(),
- deps->GetSharedImageManager(),
- deps->GetGpuImageFactory(),
- memory_tracker,
- true),
- shared_image_usage_(shared_image_usage) {
- shared_image_representation_factory_ =
- std::make_unique<gpu::SharedImageRepresentationFactory>(
- dependency_->GetSharedImageManager(), memory_tracker);
-
-#if defined(USE_OZONE)
- image_format_ = GetResourceFormat(display::DisplaySnapshot::PrimaryFormat());
-#else
- image_format_ = RGBA_8888;
-#endif
- // GL is origin is at bottom left normally, all Surfaceless implementations
- // are flipped.
- DCHECK_EQ(gl_surface_->GetOrigin(), gfx::SurfaceOrigin::kTopLeft);
-
+ presenter_(std::move(presenter)),
+ dependency_(deps) {
capabilities_.uses_default_gl_framebuffer = false;
- capabilities_.android_surface_control_feature_enabled = true;
- capabilities_.supports_post_sub_buffer = gl_surface_->SupportsPostSubBuffer();
- capabilities_.supports_commit_overlay_planes =
- gl_surface_->SupportsCommitOverlayPlanes();
- capabilities_.max_frames_pending = 2;
+ capabilities_.preserve_buffer_content = true;
+ capabilities_.only_invalidates_damage_rect = false;
+ capabilities_.number_of_buffers = 3;
// Force the number of max pending frames to one when the switch
// "double-buffer-compositing" is passed.
@@ -289,35 +41,12 @@ SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue(
// allocates at most one additional buffer.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kDoubleBufferCompositing))
- capabilities_.max_frames_pending = 1;
+ capabilities_.number_of_buffers = 2;
+ capabilities_.max_frames_pending = capabilities_.number_of_buffers - 1;
- capabilities_.only_invalidates_damage_rect = false;
- // Set supports_surfaceless to enable overlays.
- capabilities_.supports_surfaceless = true;
- capabilities_.preserve_buffer_content = true;
- // We expect origin of buffers is at top left.
- capabilities_.output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
-
- // TODO(penghuang): Use defaultBackendFormat() in shared image implementation
- // to make sure backend formant is consistent.
- capabilities_.sk_color_type = ResourceFormatToClosestSkColorType(
- true /* gpu_compositing */, image_format_);
- capabilities_.gr_backend_format =
- dependency_->GetSharedContextState()->gr_context()->defaultBackendFormat(
- capabilities_.sk_color_type, GrRenderable::kYes);
+ presenter_->InitializeCapabilities(&capabilities_);
}
-SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue(
- scoped_refptr<gl::GLSurface> gl_surface,
- SkiaOutputSurfaceDependency* deps,
- gpu::MemoryTracker* memory_tracker,
- const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback)
- : SkiaOutputDeviceBufferQueue(std::move(gl_surface),
- deps,
- memory_tracker,
- did_swap_buffer_complete_callback,
- kSharedImageUsage) {}
-
SkiaOutputDeviceBufferQueue::~SkiaOutputDeviceBufferQueue() {
FreeAllSurfaces();
// Clear and cancel swap_completion_callbacks_ to free all resource bind to
@@ -325,58 +54,17 @@ SkiaOutputDeviceBufferQueue::~SkiaOutputDeviceBufferQueue() {
swap_completion_callbacks_.clear();
}
-// static
-std::unique_ptr<SkiaOutputDeviceBufferQueue>
-SkiaOutputDeviceBufferQueue::Create(
- SkiaOutputSurfaceDependency* deps,
- gpu::MemoryTracker* memory_tracker,
- const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback) {
-#if defined(OS_ANDROID)
- if (deps->GetGpuFeatureInfo()
- .status_values[gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] !=
- gpu::kGpuFeatureStatusEnabled) {
- return nullptr;
- }
-
- bool can_be_used_with_surface_control = false;
- ANativeWindow* window =
- gpu::GpuSurfaceLookup::GetInstance()->AcquireNativeWidget(
- deps->GetSurfaceHandle(), &can_be_used_with_surface_control);
- if (!window || !can_be_used_with_surface_control)
- return nullptr;
- // TODO(https://crbug.com/1012401): don't depend on GL.
- auto gl_surface = base::MakeRefCounted<gl::GLSurfaceEGLSurfaceControl>(
- window, base::ThreadTaskRunnerHandle::Get());
- if (!gl_surface->Initialize(gl::GLSurfaceFormat())) {
- LOG(ERROR) << "Failed to initialize GLSurfaceEGLSurfaceControl.";
- return nullptr;
- }
-
- if (!deps->GetSharedContextState()->MakeCurrent(gl_surface.get(),
- true /* needs_gl*/)) {
- LOG(ERROR) << "MakeCurrent failed.";
- return nullptr;
- }
-
- return std::make_unique<SkiaOutputDeviceBufferQueue>(
- std::move(gl_surface), deps, memory_tracker,
- did_swap_buffer_complete_callback);
-#else
- return nullptr;
-#endif
-}
-
-SkiaOutputDeviceBufferQueue::Image*
-SkiaOutputDeviceBufferQueue::GetNextImage() {
+OutputPresenter::Image* SkiaOutputDeviceBufferQueue::GetNextImage() {
DCHECK(!available_images_.empty());
auto* image = available_images_.front();
available_images_.pop_front();
return image;
}
-void SkiaOutputDeviceBufferQueue::PageFlipComplete(Image* image) {
+void SkiaOutputDeviceBufferQueue::PageFlipComplete(
+ OutputPresenter::Image* image) {
if (displayed_image_) {
- DCHECK_EQ(displayed_image_->size(), image_size_);
+ DCHECK_EQ(displayed_image_->skia_representation()->size(), image_size_);
DCHECK_EQ(displayed_image_->present_count() > 1, displayed_image_ == image);
displayed_image_->EndPresent();
if (!displayed_image_->present_count()) {
@@ -417,57 +105,13 @@ void SkiaOutputDeviceBufferQueue::SchedulePrimaryPlane(
DCHECK(image);
image->BeginPresent();
-
- std::unique_ptr<gfx::GpuFence> fence;
- // If the submitted_image_ is being scheduled, we don't new a new fence.
- auto* gl_image =
- image->GetGLImage(image == submitted_image_ ? nullptr : &fence);
-
- // Output surface is also z-order 0.
- constexpr int kPlaneZOrder = 0;
- // Output surface always uses the full texture.
- constexpr gfx::RectF kUVRect(0.f, 0.f, 1.0f, 1.0f);
- gl_surface_->ScheduleOverlayPlane(kPlaneZOrder, plane.transform, gl_image,
- ToNearestRect(plane.display_rect), kUVRect,
- plane.enable_blending, std::move(fence));
+ presenter_->SchedulePrimaryPlane(plane, image, image == submitted_image_);
}
void SkiaOutputDeviceBufferQueue::ScheduleOverlays(
SkiaOutputSurface::OverlayList overlays) {
-#if defined(OS_ANDROID)
DCHECK(pending_overlays_.empty());
- for (auto& overlay : overlays) {
- auto shared_image =
- shared_image_representation_factory_->ProduceOverlay(overlay.mailbox);
- // When display is re-opened, the first few frames might not have video
- // resource ready. Possible investigation crbug.com/1023971.
- if (!shared_image) {
- LOG(ERROR) << "Invalid mailbox.";
- continue;
- }
-
- std::unique_ptr<gpu::SharedImageRepresentationOverlay::ScopedReadAccess>
- shared_image_access =
- shared_image->BeginScopedReadAccess(true /* needs_gl_image */);
- if (!shared_image_access) {
- LOG(ERROR) << "Could not access SharedImage for read.";
- continue;
- }
-
- pending_overlays_.emplace_back(std::move(shared_image),
- std::move(shared_image_access));
- auto* gl_image = pending_overlays_.back().gl_image();
- DLOG_IF(ERROR, !gl_image) << "Cannot get GLImage.";
-
- if (gl_image) {
- DCHECK(!overlay.gpu_fence_id);
- gl_surface_->ScheduleOverlayPlane(
- overlay.plane_z_order, overlay.transform, gl_image,
- ToNearestRect(overlay.display_rect), overlay.uv_rect,
- !overlay.is_opaque, nullptr /* gpu_fence */);
- }
- }
-#endif // defined(OS_ANDROID)
+ pending_overlays_ = presenter_->ScheduleOverlays(std::move(overlays));
}
void SkiaOutputDeviceBufferQueue::SwapBuffers(
@@ -479,24 +123,17 @@ void SkiaOutputDeviceBufferQueue::SwapBuffers(
submitted_image_ = current_image_;
current_image_ = nullptr;
- if (supports_async_swap_) {
- // Cancelable callback uses weak ptr to drop this task upon destruction.
- // Thus it is safe to use |base::Unretained(this)|.
- // Bind submitted_image_->GetWeakPtr(), since the |submitted_image_| could
- // be released due to reshape() or destruction.
- swap_completion_callbacks_.emplace_back(
- std::make_unique<CancelableSwapCompletionCallback>(base::BindOnce(
- &SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers,
- base::Unretained(this), image_size_, std::move(latency_info),
- submitted_image_->GetWeakPtr(), std::move(committed_overlays_))));
- gl_surface_->SwapBuffersAsync(swap_completion_callbacks_.back()->callback(),
- std::move(feedback));
- } else {
- DoFinishSwapBuffers(image_size_, std::move(latency_info),
- submitted_image_->GetWeakPtr(),
- std::move(committed_overlays_),
- gl_surface_->SwapBuffers(std::move(feedback)), nullptr);
- }
+ // Cancelable callback uses weak ptr to drop this task upon destruction.
+ // Thus it is safe to use |base::Unretained(this)|.
+ // Bind submitted_image_->GetWeakPtr(), since the |submitted_image_| could
+ // be released due to reshape() or destruction.
+ swap_completion_callbacks_.emplace_back(
+ std::make_unique<CancelableSwapCompletionCallback>(base::BindOnce(
+ &SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers,
+ base::Unretained(this), image_size_, std::move(latency_info),
+ submitted_image_->GetWeakPtr(), std::move(committed_overlays_))));
+ presenter_->SwapBuffers(swap_completion_callbacks_.back()->callback(),
+ std::move(feedback));
committed_overlays_.clear();
std::swap(committed_overlays_, pending_overlays_);
}
@@ -513,27 +150,18 @@ void SkiaOutputDeviceBufferQueue::PostSubBuffer(
}
DCHECK(submitted_image_);
- if (supports_async_swap_) {
- // Cancelable callback uses weak ptr to drop this task upon destruction.
- // Thus it is safe to use |base::Unretained(this)|.
- // Bind submitted_image_->GetWeakPtr(), since the |submitted_image_| could
- // be released due to reshape() or destruction.
- swap_completion_callbacks_.emplace_back(
- std::make_unique<CancelableSwapCompletionCallback>(base::BindOnce(
- &SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers,
- base::Unretained(this), image_size_, std::move(latency_info),
- submitted_image_->GetWeakPtr(), std::move(committed_overlays_))));
- gl_surface_->PostSubBufferAsync(
- rect.x(), rect.y(), rect.width(), rect.height(),
- swap_completion_callbacks_.back()->callback(), std::move(feedback));
- } else {
- DoFinishSwapBuffers(
- image_size_, std::move(latency_info), submitted_image_->GetWeakPtr(),
- std::move(committed_overlays_),
- gl_surface_->PostSubBuffer(rect.x(), rect.y(), rect.width(),
- rect.height(), std::move(feedback)),
- nullptr);
- }
+ // Cancelable callback uses weak ptr to drop this task upon destruction.
+ // Thus it is safe to use |base::Unretained(this)|.
+ // Bind submitted_image_->GetWeakPtr(), since the |submitted_image_| could
+ // be released due to reshape() or destruction.
+ swap_completion_callbacks_.emplace_back(
+ std::make_unique<CancelableSwapCompletionCallback>(base::BindOnce(
+ &SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers,
+ base::Unretained(this), image_size_, std::move(latency_info),
+ submitted_image_->GetWeakPtr(), std::move(committed_overlays_))));
+ presenter_->PostSubBuffer(rect, swap_completion_callbacks_.back()->callback(),
+ std::move(feedback));
+
committed_overlays_.clear();
std::swap(committed_overlays_, pending_overlays_);
}
@@ -548,24 +176,18 @@ void SkiaOutputDeviceBufferQueue::CommitOverlayPlanes(
// A main buffer has to be submitted for previous frames.
DCHECK(submitted_image_);
- if (supports_async_swap_) {
- // Cancelable callback uses weak ptr to drop this task upon destruction.
- // Thus it is safe to use |base::Unretained(this)|.
- // Bind submitted_image_->GetWeakPtr(), since the |submitted_image_| could
- // be released due to reshape() or destruction.
- swap_completion_callbacks_.emplace_back(
- std::make_unique<CancelableSwapCompletionCallback>(base::BindOnce(
- &SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers,
- base::Unretained(this), image_size_, std::move(latency_info),
- submitted_image_->GetWeakPtr(), std::move(committed_overlays_))));
- gl_surface_->CommitOverlayPlanesAsync(
- swap_completion_callbacks_.back()->callback(), std::move(feedback));
- } else {
- DoFinishSwapBuffers(
- image_size_, std::move(latency_info), submitted_image_->GetWeakPtr(),
- std::move(committed_overlays_),
- gl_surface_->CommitOverlayPlanes(std::move(feedback)), nullptr);
- }
+ // Cancelable callback uses weak ptr to drop this task upon destruction.
+ // Thus it is safe to use |base::Unretained(this)|.
+ // Bind submitted_image_->GetWeakPtr(), since the |submitted_image_| could
+ // be released due to reshape() or destruction.
+ swap_completion_callbacks_.emplace_back(
+ std::make_unique<CancelableSwapCompletionCallback>(base::BindOnce(
+ &SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers,
+ base::Unretained(this), image_size_, std::move(latency_info),
+ submitted_image_->GetWeakPtr(), std::move(committed_overlays_))));
+ presenter_->CommitOverlayPlanes(swap_completion_callbacks_.back()->callback(),
+ std::move(feedback));
+
committed_overlays_.clear();
std::swap(committed_overlays_, pending_overlays_);
}
@@ -573,13 +195,11 @@ void SkiaOutputDeviceBufferQueue::CommitOverlayPlanes(
void SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers(
const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info,
- const base::WeakPtr<Image>& image,
- std::vector<OverlayData> overlays,
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence) {
- DCHECK(!gpu_fence);
-
- FinishSwapBuffers(result, size, latency_info);
+ const base::WeakPtr<OutputPresenter::Image>& image,
+ std::vector<OutputPresenter::OverlayData> overlays,
+ gfx::SwapCompletionResult result) {
+ DCHECK(!result.gpu_fence);
+ FinishSwapBuffers(std::move(result), size, latency_info);
PageFlipComplete(image.get());
}
@@ -588,8 +208,8 @@ bool SkiaOutputDeviceBufferQueue::Reshape(const gfx::Size& size,
const gfx::ColorSpace& color_space,
gfx::BufferFormat format,
gfx::OverlayTransform transform) {
- if (!gl_surface_->Resize(size, device_scale_factor, color_space,
- gfx::AlphaBitsForBufferFormat(format))) {
+ if (!presenter_->Reshape(size, device_scale_factor, color_space, format,
+ transform)) {
DLOG(ERROR) << "Failed to resize.";
return false;
}
@@ -598,16 +218,13 @@ bool SkiaOutputDeviceBufferQueue::Reshape(const gfx::Size& size,
image_size_ = size;
FreeAllSurfaces();
- for (int i = 0; i < capabilities_.max_frames_pending + 1; ++i) {
- auto image = std::make_unique<Image>(
- &shared_image_factory_, shared_image_representation_factory_.get());
- if (!image->Initialize(image_size_, color_space_, image_format_,
- dependency_, shared_image_usage_)) {
- DLOG(ERROR) << "Failed to initialize image.";
- return false;
- }
+ images_ = presenter_->AllocateImages(color_space_, image_size_,
+ capabilities_.number_of_buffers);
+ if (images_.empty())
+ return false;
+
+ for (auto& image : images_) {
available_images_.push_back(image.get());
- images_.push_back(std::move(image));
}
return true;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
index 77ad81308cf..efb7d9c629a 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue.h
@@ -7,39 +7,29 @@
#include "base/cancelable_callback.h"
#include "base/macros.h"
+#include "components/viz/service/display_embedder/output_presenter.h"
#include "components/viz/service/display_embedder/skia_output_device.h"
#include "components/viz/service/viz_service_export.h"
-#include "gpu/command_buffer/service/shared_image_factory.h"
-
-namespace gl {
-class GLSurface;
-} // namespace gl
namespace viz {
class SkiaOutputSurfaceDependency;
-class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue final
- : public SkiaOutputDevice {
+class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice {
public:
SkiaOutputDeviceBufferQueue(
- scoped_refptr<gl::GLSurface> gl_surface,
+ std::unique_ptr<OutputPresenter> presenter,
SkiaOutputSurfaceDependency* deps,
gpu::MemoryTracker* memory_tracker,
const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback);
- SkiaOutputDeviceBufferQueue(
- scoped_refptr<gl::GLSurface> gl_surface,
- SkiaOutputSurfaceDependency* deps,
- gpu::MemoryTracker* memory_tracker,
- const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
- uint32_t shared_image_usage);
+
~SkiaOutputDeviceBufferQueue() override;
- static std::unique_ptr<SkiaOutputDeviceBufferQueue> Create(
- SkiaOutputSurfaceDependency* deps,
- gpu::MemoryTracker* memory_tracker,
- const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback);
+ SkiaOutputDeviceBufferQueue(const SkiaOutputDeviceBufferQueue&) = delete;
+ SkiaOutputDeviceBufferQueue& operator=(const SkiaOutputDeviceBufferQueue&) =
+ delete;
+ // SkiaOutputDevice overrides.
void SwapBuffers(BufferPresentedCallback feedback,
std::vector<ui::LatencyInfo> latency_info) override;
void PostSubBuffer(const gfx::Rect& rect,
@@ -63,48 +53,41 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue final
override;
void ScheduleOverlays(SkiaOutputSurface::OverlayList overlays) override;
- gl::GLSurface* gl_surface() { return gl_surface_.get(); }
-
private:
friend class SkiaOutputDeviceBufferQueueTest;
- class Image;
- class OverlayData;
using CancelableSwapCompletionCallback =
- base::CancelableOnceCallback<void(gfx::SwapResult,
- std::unique_ptr<gfx::GpuFence>)>;
+ base::CancelableOnceCallback<void(gfx::SwapCompletionResult)>;
- Image* GetNextImage();
- void PageFlipComplete(Image* image);
+ OutputPresenter::Image* GetNextImage();
+ void PageFlipComplete(OutputPresenter::Image* image);
void FreeAllSurfaces();
- // Used as callback for SwapBuff ersAsync and PostSubBufferAsync to finish
+ // Used as callback for SwapBuffersAsync and PostSubBufferAsync to finish
// operation
void DoFinishSwapBuffers(const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info,
- const base::WeakPtr<Image>& image,
- std::vector<OverlayData> overlays,
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence);
+ const base::WeakPtr<OutputPresenter::Image>& image,
+ std::vector<OutputPresenter::OverlayData> overlays,
+ gfx::SwapCompletionResult result);
+
+ std::unique_ptr<OutputPresenter> presenter_;
SkiaOutputSurfaceDependency* const dependency_;
- scoped_refptr<gl::GLSurface> gl_surface_;
- const bool supports_async_swap_;
// Format of images
gfx::ColorSpace color_space_;
gfx::Size image_size_;
- ResourceFormat image_format_;
// All allocated images.
- std::vector<std::unique_ptr<Image>> images_;
+ std::vector<std::unique_ptr<OutputPresenter::Image>> images_;
// This image is currently used by Skia as RenderTarget. This may be nullptr
// if there is no drawing for the current frame or if allocation failed.
- Image* current_image_ = nullptr;
+ OutputPresenter::Image* current_image_ = nullptr;
// The last image submitted for presenting.
- Image* submitted_image_ = nullptr;
+ OutputPresenter::Image* submitted_image_ = nullptr;
// The image currently on the screen, if any.
- Image* displayed_image_ = nullptr;
+ OutputPresenter::Image* displayed_image_ = nullptr;
// These are free for use, and are not nullptr.
- base::circular_deque<Image*> available_images_;
+ base::circular_deque<OutputPresenter::Image*> available_images_;
// These cancelable callbacks bind images that have been scheduled to display
// but are not displayed yet. This deque will be cleared when represented
// frames are destroyed. Use CancelableOnceCallback to prevent resources
@@ -112,17 +95,9 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue final
base::circular_deque<std::unique_ptr<CancelableSwapCompletionCallback>>
swap_completion_callbacks_;
// Scheduled overlays for the next SwapBuffers call.
- std::vector<OverlayData> pending_overlays_;
+ std::vector<OutputPresenter::OverlayData> pending_overlays_;
// Committed overlays for the last SwapBuffers call.
- std::vector<OverlayData> committed_overlays_;
-
- // Shared Image factories
- gpu::SharedImageFactory shared_image_factory_;
- std::unique_ptr<gpu::SharedImageRepresentationFactory>
- shared_image_representation_factory_;
- uint32_t shared_image_usage_;
-
- DISALLOW_COPY_AND_ASSIGN(SkiaOutputDeviceBufferQueue);
+ std::vector<OutputPresenter::OverlayData> committed_overlays_;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
index 8cc92113d1d..92a51592bf6 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_buffer_queue_unittest.cc
@@ -16,6 +16,7 @@
#include "build/build_config.h"
#include "gpu/command_buffer/service/scheduler.h"
+#include "components/viz/service/display_embedder/output_presenter_gl.h"
#include "components/viz/service/display_embedder/skia_output_surface_dependency_impl.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "components/viz/test/test_gpu_service_holder.h"
@@ -157,7 +158,8 @@ class MockGLSurfaceAsync : public gl::GLSurfaceStub {
void SwapComplete() {
DCHECK(!callbacks_.empty());
- std::move(callbacks_.front()).Run(gfx::SwapResult::SWAP_ACK, nullptr);
+ std::move(callbacks_.front())
+ .Run(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK));
callbacks_.pop_front();
}
@@ -222,15 +224,17 @@ class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {
std::unique_ptr<SkiaOutputDeviceBufferQueue> onscreen_device =
std::make_unique<SkiaOutputDeviceBufferQueue>(
- gl_surface_, dependency_.get(), memory_tracker_.get(),
- present_callback, shared_image_usage);
+ std::make_unique<OutputPresenterGL>(gl_surface_, dependency_.get(),
+ memory_tracker_.get(),
+ shared_image_usage),
+ dependency_.get(), memory_tracker_.get(), present_callback);
output_device_ = std::move(onscreen_device);
}
void TearDownOnGpu() override { output_device_.reset(); }
- using Image = SkiaOutputDeviceBufferQueue::Image;
+ using Image = OutputPresenter::Image;
const std::vector<std::unique_ptr<Image>>& images() {
return output_device_->images_;
@@ -279,11 +283,15 @@ class SkiaOutputDeviceBufferQueueTest : public TestOnGpu {
(size_t)CountBuffers());
}
- Image* PaintAndSchedulePrimaryPlane() {
- // Call Begin/EndPaint to ensusre the image is initialized before use.
+ Image* PaintPrimaryPlane() {
std::vector<GrBackendSemaphore> end_semaphores;
output_device_->BeginPaint(&end_semaphores);
output_device_->EndPaint();
+ return current_image();
+ }
+
+ Image* PaintAndSchedulePrimaryPlane() {
+ PaintPrimaryPlane();
SchedulePrimaryPlane();
return current_image();
}
@@ -330,7 +338,7 @@ TEST_F_GPU(SkiaOutputDeviceBufferQueueTest, MultipleGetCurrentBufferCalls) {
output_device_->Reshape(screen_size, 1.0f, gfx::ColorSpace(), kDefaultFormat,
gfx::OVERLAY_TRANSFORM_NONE);
EXPECT_NE(0U, memory_tracker().GetSize());
- EXPECT_NE(PaintAndSchedulePrimaryPlane(), nullptr);
+ EXPECT_NE(PaintPrimaryPlane(), nullptr);
EXPECT_NE(0U, memory_tracker().GetSize());
EXPECT_EQ(3, CountBuffers());
auto* fb = current_image();
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
index a2bb693c020..9790a1b1a03 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.cc
@@ -6,17 +6,11 @@
#include "base/check_op.h"
#include "base/notreached.h"
-#include "build/build_config.h"
#include "components/viz/common/gpu/dawn_context_provider.h"
+#include "third_party/dawn/src/include/dawn_native/D3D12Backend.h"
#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/vsync_provider.h"
-
-#if defined(OS_WIN)
-#include "third_party/dawn/src/include/dawn_native/D3D12Backend.h"
#include "ui/gl/vsync_provider_win.h"
-#elif defined(OS_LINUX)
-#include "third_party/dawn/src/include/dawn_native/VulkanBackend.h"
-#endif
namespace viz {
@@ -41,7 +35,7 @@ SkiaOutputDeviceDawn::SkiaOutputDeviceDawn(
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
: SkiaOutputDevice(memory_tracker, did_swap_buffer_complete_callback),
context_provider_(context_provider),
- widget_(widget) {
+ child_window_(widget) {
capabilities_.output_surface_origin = origin;
capabilities_.uses_default_gl_framebuffer = false;
capabilities_.supports_post_sub_buffer = false;
@@ -51,13 +45,16 @@ SkiaOutputDeviceDawn::SkiaOutputDeviceDawn(
context_provider_->GetGrContext()->defaultBackendFormat(
kSurfaceColorType, GrRenderable::kYes);
-#if defined(OS_WIN)
- vsync_provider_ = std::make_unique<gl::VSyncProviderWin>(widget_);
-#endif
+ vsync_provider_ = std::make_unique<gl::VSyncProviderWin>(widget);
+ child_window_.Initialize();
}
SkiaOutputDeviceDawn::~SkiaOutputDeviceDawn() = default;
+gpu::SurfaceHandle SkiaOutputDeviceDawn::GetChildSurfaceHandle() const {
+ return child_window_.window();
+}
+
bool SkiaOutputDeviceDawn::Reshape(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
@@ -86,7 +83,7 @@ void SkiaOutputDeviceDawn::SwapBuffers(
std::vector<ui::LatencyInfo> latency_info) {
StartSwapBuffers({});
swap_chain_.Present();
- FinishSwapBuffers(gfx::SwapResult::SWAP_ACK,
+ FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK),
gfx::Size(size_.width(), size_.height()),
std::move(latency_info));
@@ -136,13 +133,8 @@ void SkiaOutputDeviceDawn::EndPaint() {
}
void SkiaOutputDeviceDawn::CreateSwapChainImplementation() {
-#if defined(OS_WIN)
swap_chain_implementation_ = dawn_native::d3d12::CreateNativeSwapChainImpl(
- context_provider_->GetDevice().Get(), widget_);
-#else
- NOTREACHED();
- ALLOW_UNUSED_LOCAL(widget_);
-#endif
+ context_provider_->GetDevice().Get(), child_window_.window());
}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h
index 56ef86fe380..3d6bcf821f0 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_dawn.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_DAWN_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_DEVICE_DAWN_H_
+#include "build/build_config.h"
#include "components/viz/service/display_embedder/skia_output_device.h"
#include "third_party/dawn/src/include/dawn/dawn_wsi.h"
#include "third_party/dawn/src/include/dawn/webgpu.h"
@@ -13,6 +14,7 @@
#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/child_window_win.h"
namespace viz {
@@ -28,6 +30,8 @@ class SkiaOutputDeviceDawn : public SkiaOutputDevice {
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback);
~SkiaOutputDeviceDawn() override;
+ gpu::SurfaceHandle GetChildSurfaceHandle() const;
+
// SkiaOutputDevice implementation:
bool Reshape(const gfx::Size& size,
float device_scale_factor,
@@ -45,7 +49,6 @@ class SkiaOutputDeviceDawn : public SkiaOutputDevice {
void CreateSwapChainImplementation();
DawnContextProvider* const context_provider_;
- gfx::AcceleratedWidget widget_;
DawnSwapChainImplementation swap_chain_implementation_;
wgpu::SwapChain swap_chain_;
wgpu::Texture texture_;
@@ -56,6 +59,13 @@ class SkiaOutputDeviceDawn : public SkiaOutputDevice {
sk_sp<SkColorSpace> sk_color_space_;
GrBackendTexture backend_texture_;
+ // D3D12 requires that we use flip model swap chains. Flip swap chains
+ // require that the swap chain be connected with DWM. DWM requires that
+ // the rendering windows are owned by the process that's currently doing
+ // the rendering. gl::ChildWindowWin creates and owns a window which is
+ // reparented by the browser to be a child of its window.
+ gl::ChildWindowWin child_window_;
+
DISALLOW_COPY_AND_ASSIGN(SkiaOutputDeviceDawn);
};
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 44ce3b99f68..2f80461da3b 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
@@ -7,6 +7,7 @@
#include <utility>
#include "base/bind_helpers.h"
+#include "components/viz/common/gpu/context_lost_reason.h"
#include "components/viz/service/display/dc_layer_overlay.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "gpu/command_buffer/service/feature_info.h"
@@ -25,6 +26,7 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_utils.h"
#include "ui/gl/gl_version_info.h"
namespace viz {
@@ -192,8 +194,9 @@ void SkiaOutputDeviceGL::SwapBuffers(
std::move(latency_info));
gl_surface_->SwapBuffersAsync(std::move(callback), std::move(feedback));
} else {
- FinishSwapBuffers(gl_surface_->SwapBuffers(std::move(feedback)),
- surface_size, std::move(latency_info));
+ gfx::SwapResult result = gl_surface_->SwapBuffers(std::move(feedback));
+ FinishSwapBuffers(gfx::SwapCompletionResult(result), surface_size,
+ std::move(latency_info));
}
}
@@ -213,12 +216,11 @@ void SkiaOutputDeviceGL::PostSubBuffer(
gl_surface_->PostSubBufferAsync(rect.x(), rect.y(), rect.width(),
rect.height(), std::move(callback),
std::move(feedback));
-
} else {
- FinishSwapBuffers(
- gl_surface_->PostSubBuffer(rect.x(), rect.y(), rect.width(),
- rect.height(), std::move(feedback)),
- surface_size, std::move(latency_info));
+ gfx::SwapResult result = gl_surface_->PostSubBuffer(
+ rect.x(), rect.y(), rect.width(), rect.height(), std::move(feedback));
+ FinishSwapBuffers(gfx::SwapCompletionResult(result), surface_size,
+ std::move(latency_info));
}
}
@@ -237,22 +239,23 @@ void SkiaOutputDeviceGL::CommitOverlayPlanes(
gl_surface_->CommitOverlayPlanesAsync(std::move(callback),
std::move(feedback));
} else {
- FinishSwapBuffers(gl_surface_->CommitOverlayPlanes(std::move(feedback)),
- surface_size, std::move(latency_info));
+ FinishSwapBuffers(
+ gfx::SwapCompletionResult(
+ gl_surface_->CommitOverlayPlanes(std::move(feedback))),
+ surface_size, std::move(latency_info));
}
}
void SkiaOutputDeviceGL::DoFinishSwapBuffers(
const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info,
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence> gpu_fence) {
- DCHECK(!gpu_fence);
- FinishSwapBuffers(result, size, latency_info);
+ gfx::SwapCompletionResult result) {
+ DCHECK(!result.gpu_fence);
+ FinishSwapBuffers(std::move(result), size, latency_info);
}
-void SkiaOutputDeviceGL::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
- gl_surface_->SetDrawRectangle(draw_rectangle);
+bool SkiaOutputDeviceGL::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
+ return gl_surface_->SetDrawRectangle(draw_rectangle);
}
void SkiaOutputDeviceGL::SetGpuVSyncEnabled(bool enabled) {
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_gl.h b/chromium/components/viz/service/display_embedder/skia_output_device_gl.h
index d8491578a4b..a1318dbbaec 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_gl.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_gl.h
@@ -20,10 +20,6 @@ class GLImage;
class GLSurface;
} // namespace gl
-namespace gfx {
-class GpuFence;
-} // namespace gfx
-
namespace gpu {
class MailboxManager;
class SharedContextState;
@@ -63,7 +59,7 @@ class SkiaOutputDeviceGL final : public SkiaOutputDevice {
std::vector<ui::LatencyInfo> latency_info) override;
void CommitOverlayPlanes(BufferPresentedCallback feedback,
std::vector<ui::LatencyInfo> latency_info) override;
- void SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
+ bool SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
void SetGpuVSyncEnabled(bool enabled) override;
#if defined(OS_WIN)
void SetEnableDCLayers(bool enable) override;
@@ -80,8 +76,7 @@ class SkiaOutputDeviceGL final : public SkiaOutputDevice {
// operation
void DoFinishSwapBuffers(const gfx::Size& size,
std::vector<ui::LatencyInfo> latency_info,
- gfx::SwapResult result,
- std::unique_ptr<gfx::GpuFence>);
+ gfx::SwapCompletionResult result);
scoped_refptr<gl::GLImage> GetGLImageForMailbox(const gpu::Mailbox& mailbox);
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc b/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc
index 7b4708d94c9..b846ee6db2a 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_offscreen.cc
@@ -63,7 +63,7 @@ void SkiaOutputDeviceOffscreen::SwapBuffers(
DCHECK(backend_texture_.isValid());
StartSwapBuffers(std::move(feedback));
- FinishSwapBuffers(gfx::SwapResult::SWAP_ACK,
+ FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK),
gfx::Size(size_.width(), size_.height()),
std::move(latency_info));
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
index 930ec126a14..6b89f737bdc 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/logging.h"
#include "build/build_config.h"
#include "components/viz/common/gpu/vulkan_context_provider.h"
#include "gpu/command_buffer/service/memory_tracking.h"
@@ -101,22 +102,37 @@ void SkiaOutputDeviceVulkan::PostSubBuffer(
#endif
StartSwapBuffers(std::move(feedback));
- auto image_size = vulkan_surface_->image_size();
- gfx::SwapResult result = gfx::SwapResult::SWAP_ACK;
- // If the swapchain is new created, but rect doesn't cover the whole buffer,
- // we will still present it even it causes a artifact in this frame and
- // recovered when the next frame is presented. We do that because the old
- // swapchain's present thread is blocked on waiting a reply from xserver, and
- // presenting a new image with the new create swapchain will somehow makes
- // xserver send a reply to us, and then unblock the old swapchain's present
- // thread. So the old swapchain can be destroyed properly.
- if (!rect.IsEmpty())
- result = vulkan_surface_->PostSubBuffer(rect);
- if (is_new_swapchain_) {
- is_new_swapchain_ = false;
- result = gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS;
+
+ if (is_new_swap_chain_ && rect == gfx::Rect(vulkan_surface_->image_size())) {
+ is_new_swap_chain_ = false;
+ }
+
+ if (!is_new_swap_chain_) {
+ auto image_index = vulkan_surface_->swap_chain()->current_image_index();
+ for (size_t i = 0; i < damage_of_images_.size(); ++i) {
+ if (i == image_index) {
+ damage_of_images_[i] = gfx::Rect();
+ } else {
+ damage_of_images_[i].Union(rect);
+ }
+ }
+ }
+
+ if (!rect.IsEmpty()) {
+ // If the swapchain is new created, but rect doesn't cover the whole buffer,
+ // we will still present it even it causes a artifact in this frame and
+ // recovered when the next frame is presented. We do that because the old
+ // swapchain's present thread is blocked on waiting a reply from xserver,
+ // and presenting a new image with the new create swapchain will somehow
+ // makes xserver send a reply to us, and then unblock the old swapchain's
+ // present thread. So the old swapchain can be destroyed properly.
+ vulkan_surface_->PostSubBufferAsync(
+ rect, base::BindOnce(&SkiaOutputDeviceVulkan::OnPostSubBufferFinished,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(latency_info)));
+ } else {
+ OnPostSubBufferFinished(std::move(latency_info), gfx::SwapResult::SWAP_ACK);
}
- FinishSwapBuffers(result, image_size, std::move(latency_info));
}
SkSurface* SkiaOutputDeviceVulkan::BeginPaint(
@@ -241,7 +257,7 @@ bool SkiaOutputDeviceVulkan::Initialize() {
vulkan_surface_ = std::move(vulkan_surface);
capabilities_.uses_default_gl_framebuffer = false;
- capabilities_.max_frames_pending = vulkan_surface_->image_count() - 1;
+ capabilities_.max_frames_pending = 1;
// Vulkan FIFO swap chain should return vk images in presenting order, so set
// preserve_buffer_content & supports_post_sub_buffer to true to let
// SkiaOutputBufferImpl to manager damages.
@@ -249,6 +265,12 @@ bool SkiaOutputDeviceVulkan::Initialize() {
capabilities_.output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
capabilities_.supports_post_sub_buffer = true;
capabilities_.supports_pre_transform = true;
+ // We don't know the number of buffers until the VulkanSwapChain is
+ // initialized, so set it to 0. Since |damage_area_from_skia_output_device| is
+ // assigned to true, so |number_of_buffers| will not be used for tracking
+ // framebuffer damages.
+ capabilities_.number_of_buffers = 0;
+ capabilities_.damage_area_from_skia_output_device = true;
const auto surface_format = vulkan_surface_->surface_format().format;
DCHECK(surface_format == VK_FORMAT_B8G8R8A8_UNORM ||
@@ -277,15 +299,34 @@ bool SkiaOutputDeviceVulkan::RecreateSwapChain(
for (const auto& sk_surface_size_pair : sk_surface_size_pairs_) {
memory_type_tracker_->TrackMemFree(sk_surface_size_pair.bytes_allocated);
}
+ auto num_images = vulkan_surface_->swap_chain()->num_images();
sk_surface_size_pairs_.clear();
- sk_surface_size_pairs_.resize(vulkan_surface_->swap_chain()->num_images());
+ sk_surface_size_pairs_.resize(num_images);
color_space_ = std::move(color_space);
- is_new_swapchain_ = true;
+ damage_of_images_.resize(num_images);
+ for (auto& damage : damage_of_images_)
+ damage = gfx::Rect(vulkan_surface_->image_size());
+ is_new_swap_chain_ = true;
}
return true;
}
+void SkiaOutputDeviceVulkan::OnPostSubBufferFinished(
+ std::vector<ui::LatencyInfo> latency_info,
+ gfx::SwapResult result) {
+ if (result == gfx::SwapResult::SWAP_ACK) {
+ auto image_index = vulkan_surface_->swap_chain()->current_image_index();
+ FinishSwapBuffers(gfx::SwapCompletionResult(result),
+ vulkan_surface_->image_size(), std::move(latency_info),
+ damage_of_images_[image_index]);
+ } else {
+ FinishSwapBuffers(gfx::SwapCompletionResult(result),
+ vulkan_surface_->image_size(), std::move(latency_info),
+ gfx::Rect(vulkan_surface_->image_size()));
+ }
+}
+
SkiaOutputDeviceVulkan::SkSurfaceSizePair::SkSurfaceSizePair() = default;
SkiaOutputDeviceVulkan::SkSurfaceSizePair::SkSurfaceSizePair(
const SkSurfaceSizePair& other) = default;
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
index af859a52785..4ae2ad690d4 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_vulkan.h
@@ -9,6 +9,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/util/type_safety/pass_key.h"
#include "build/build_config.h"
@@ -72,6 +73,8 @@ class SkiaOutputDeviceVulkan final : public SkiaOutputDevice {
bool RecreateSwapChain(const gfx::Size& size,
sk_sp<SkColorSpace> color_space,
gfx::OverlayTransform transform);
+ void OnPostSubBufferFinished(std::vector<ui::LatencyInfo> latency_info,
+ gfx::SwapResult result);
VulkanContextProvider* const context_provider_;
@@ -88,7 +91,14 @@ class SkiaOutputDeviceVulkan final : public SkiaOutputDevice {
std::vector<SkSurfaceSizePair> sk_surface_size_pairs_;
sk_sp<SkColorSpace> color_space_;
- bool is_new_swapchain_ = true;
+
+ // The swapchain is new created without a frame which convers the whole area
+ // of it.
+ bool is_new_swap_chain_ = true;
+
+ std::vector<gfx::Rect> damage_of_images_;
+
+ base::WeakPtrFactory<SkiaOutputDeviceVulkan> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(SkiaOutputDeviceVulkan);
};
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 a0526224e33..e8aa380c9f9 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
@@ -80,8 +80,9 @@ void SkiaOutputDeviceWebView::SwapBuffers(
gfx::Size surface_size =
gfx::Size(sk_surface_->width(), sk_surface_->height());
- FinishSwapBuffers(gl_surface_->SwapBuffers(std::move(feedback)), surface_size,
- std::move(latency_info));
+ FinishSwapBuffers(
+ gfx::SwapCompletionResult(gl_surface_->SwapBuffers(std::move(feedback))),
+ surface_size, std::move(latency_info));
}
SkSurface* SkiaOutputDeviceWebView::BeginPaint(
diff --git a/chromium/components/viz/service/display_embedder/skia_output_device_x11.cc b/chromium/components/viz/service/display_embedder/skia_output_device_x11.cc
index 2fc506b3fff..c30693c52c4 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_device_x11.cc
+++ b/chromium/components/viz/service/display_embedder/skia_output_device_x11.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/logging.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
@@ -27,10 +28,11 @@ SkiaOutputDeviceX11::SkiaOutputDeviceX11(
did_swap_buffer_complete_callback),
display_(gfx::GetXDisplay()),
widget_(widget),
- gc_(XCreateGC(display_, widget_, 0, nullptr)) {
- int result = XGetWindowAttributes(display_, widget_, &attributes_);
+ gc_(XCreateGC(display_, static_cast<uint32_t>(widget_), 0, nullptr)) {
+ int result = XGetWindowAttributes(display_, static_cast<uint32_t>(widget_),
+ &attributes_);
LOG_IF(FATAL, !result) << "XGetWindowAttributes failed for window "
- << widget_;
+ << static_cast<uint32_t>(widget_);
bpp_ = gfx::BitsPerPixelForPixmapDepth(display_, attributes_.depth);
support_rendr_ = ui::QueryRenderSupport(display_);
@@ -82,14 +84,15 @@ void SkiaOutputDeviceX11::PostSubBuffer(
if (bpp_ == 32 || bpp_ == 16) {
// gfx::PutARGBImage() only supports 16 and 32 bpp.
// TODO(penghuang): Switch to XShmPutImage.
- gfx::PutARGBImage(display_, attributes_.visual, attributes_.depth, widget_,
- gc_, static_cast<const uint8_t*>(sk_pixmap.addr()),
+ gfx::PutARGBImage(display_, attributes_.visual, attributes_.depth,
+ static_cast<uint32_t>(widget_), gc_,
+ static_cast<const uint8_t*>(sk_pixmap.addr()),
rect.width(), rect.height(), 0 /* src_x */, 0 /* src_y */,
rect.x() /* dst_x */, rect.y() /* dst_y */, rect.width(),
rect.height());
} else if (support_rendr_) {
- Pixmap pixmap =
- XCreatePixmap(display_, widget_, rect.width(), rect.height(), 32);
+ Pixmap pixmap = XCreatePixmap(display_, static_cast<uint32_t>(widget_),
+ rect.width(), rect.height(), 32);
GC gc = XCreateGC(display_, pixmap, 0, nullptr);
XImage image = {};
@@ -97,10 +100,10 @@ void SkiaOutputDeviceX11::PostSubBuffer(
image.height = rect.height();
image.depth = 32;
image.bits_per_pixel = 32;
- image.format = ZPixmap;
- image.byte_order = LSBFirst;
+ image.format = static_cast<int>(x11::ImageFormat::ZPixmap);
+ image.byte_order = static_cast<int>(x11::ImageOrder::LSBFirst);
image.bitmap_unit = 8;
- image.bitmap_bit_order = LSBFirst;
+ image.bitmap_bit_order = static_cast<int>(x11::ImageOrder::LSBFirst);
image.bytes_per_line = sk_pixmap.rowBytes();
image.red_mask = 0xff << SK_R32_SHIFT;
@@ -115,8 +118,8 @@ void SkiaOutputDeviceX11::PostSubBuffer(
display_, pixmap, ui::GetRenderARGB32Format(display_), 0, nullptr);
XRenderPictFormat* pictformat =
XRenderFindVisualFormat(display_, attributes_.visual);
- Picture dest_picture =
- XRenderCreatePicture(display_, widget_, pictformat, 0, nullptr);
+ Picture dest_picture = XRenderCreatePicture(
+ display_, static_cast<uint32_t>(widget_), pictformat, 0, nullptr);
XRenderComposite(display_,
PictOpSrc, // op
picture, // src
@@ -137,7 +140,7 @@ void SkiaOutputDeviceX11::PostSubBuffer(
NOTIMPLEMENTED();
}
XFlush(display_);
- FinishSwapBuffers(gfx::SwapResult::SWAP_ACK,
+ FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK),
gfx::Size(sk_surface_->width(), sk_surface_->height()),
std::move(latency_info));
}
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
index d3d814edf9b..a85a0cf5c1c 100644
--- a/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_dependency.h
@@ -120,6 +120,10 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceDependency {
bool IsUsingDawn() const {
return gr_context_type() == gpu::GrContextType::kDawn;
}
+
+ bool IsUsingMetal() const {
+ return gr_context_type() == gpu::GrContextType::kMetal;
+ }
};
} // namespace viz
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 36404ea695d..f453eae9c38 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
@@ -204,10 +204,14 @@ void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
// SetDrawRectangle() will need to be called at the new size.
has_set_draw_rectangle_for_frame_ = false;
- // Reshape will damage all buffers.
- current_buffer_ = 0u;
- for (auto& damage : damage_of_buffers_)
- damage = gfx::Rect(size);
+ if (use_damage_area_from_skia_output_device_) {
+ damage_of_current_buffer_ = gfx::Rect(size);
+ } else {
+ // Reshape will damage all buffers.
+ current_buffer_ = 0u;
+ for (auto& damage : damage_of_buffers_)
+ damage = gfx::Rect(size);
+ }
// impl_on_gpu_ is released on the GPU thread by a posted task from
// SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
@@ -429,21 +433,15 @@ void SkiaOutputSurfaceImpl::SwapBuffers(OutputSurfaceFrame frame) {
}
void SkiaOutputSurfaceImpl::SwapBuffersSkipped() {
- if (deferred_framebuffer_draw_closure_) {
- // Run the task to draw the root RenderPass on the GPU thread. If we aren't
- // going to swap buffers and there are no CopyOutputRequests on the root
- // RenderPass we don't strictly need to draw. However, we still need to
- // PostTask to the GPU thread to deal with freeing resources and running
- // callbacks. This is infrequent and all the work is already done in
- // FinishPaintCurrentFrame() so use the same path.
- auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped,
- base::Unretained(impl_on_gpu_.get()),
- std::move(deferred_framebuffer_draw_closure_));
- ScheduleGpuTask(std::move(task), std::move(resource_sync_tokens_));
-
- // TODO(vasilyt): reuse root recorder
- RecreateRootRecorder();
- }
+ // PostTask to the GPU thread to deal with freeing resources and running
+ // callbacks.
+ auto task = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped,
+ base::Unretained(impl_on_gpu_.get()),
+ std::move(deferred_framebuffer_draw_closure_));
+ ScheduleGpuTask(std::move(task), std::move(resource_sync_tokens_));
+
+ // TODO(vasilyt): reuse root recorder
+ RecreateRootRecorder();
}
void SkiaOutputSurfaceImpl::ScheduleOutputSurfaceAsOverlay(
@@ -491,7 +489,6 @@ gpu::SyncToken SkiaOutputSurfaceImpl::SubmitPaint(
sync_token.SetVerifyFlush();
auto ddl = current_paint_->recorder()->detach();
- DCHECK(ddl);
// impl_on_gpu_ is released on the GPU thread by a posted task from
// SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
@@ -562,7 +559,9 @@ sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromRenderPass(
image_context->color_space(), Fulfill, DoNothing, DoNothing,
image_context.get()),
backend_format);
- DCHECK(image_context->has_image());
+ if (!image_context->has_image()) {
+ return nullptr;
+ }
}
images_in_current_paint_.push_back(image_context.get());
return image_context->image();
@@ -601,14 +600,22 @@ void SkiaOutputSurfaceImpl::CopyOutput(
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!request->has_result_task_runner())
- request->set_result_task_runner(base::ThreadTaskRunnerHandle::Get());
- auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::CopyOutput,
- base::Unretained(impl_on_gpu_.get()), id,
- geometry, color_space, std::move(request),
- std::move(deferred_framebuffer_draw_closure_));
- ScheduleGpuTask(std::move(callback), std::move(resource_sync_tokens_));
+ // Defer CopyOutput for root render pass with draw framebuffer to
+ // SwapBuffers() or SwapBuffersSkipped().
+ if (!id) {
+ deferred_framebuffer_draw_closure_ = base::BindOnce(
+ &SkiaOutputSurfaceImplOnGpu::CopyOutput,
+ base::Unretained(impl_on_gpu_.get()), id, geometry, color_space,
+ std::move(request), std::move(deferred_framebuffer_draw_closure_));
+ } else {
+ DCHECK(!deferred_framebuffer_draw_closure_);
+ auto callback = base::BindOnce(
+ base::IgnoreResult(&SkiaOutputSurfaceImplOnGpu::CopyOutput),
+ base::Unretained(impl_on_gpu_.get()), id, geometry, color_space,
+ std::move(request), base::OnceCallback<bool()>());
+ ScheduleGpuTask(std::move(callback), std::move(resource_sync_tokens_));
+ }
}
void SkiaOutputSurfaceImpl::ScheduleOverlays(
@@ -692,7 +699,17 @@ bool SkiaOutputSurfaceImpl::Initialize() {
if (capabilities_.preserve_buffer_content &&
capabilities_.supports_post_sub_buffer) {
capabilities_.only_invalidates_damage_rect = false;
- damage_of_buffers_.resize(capabilities_.max_frames_pending + 1);
+ capabilities_.supports_target_damage = true;
+ // If there is only one pending frame, then we can use damage area hint from
+ // SkiaOutputDevice, otherwise we have to track damage area in
+ // SkiaOutputSurfaceImpl.
+ if (capabilities_.max_frames_pending == 1 &&
+ capabilities_.damage_area_from_skia_output_device) {
+ use_damage_area_from_skia_output_device_ = true;
+ damage_of_current_buffer_ = gfx::Rect();
+ } else {
+ damage_of_buffers_.resize(capabilities_.number_of_buffers);
+ }
}
return result;
@@ -769,7 +786,24 @@ SkiaOutputSurfaceImpl::CreateSkSurfaceCharacterization(
impl_on_gpu_->GetGpuPreferences().enforce_vulkan_protected_memory
? GrProtected::kYes
: GrProtected::kNo);
- DCHECK(characterization.isValid());
+ VkFormat vk_format = VK_FORMAT_UNDEFINED;
+ LOG_IF(DFATAL, !characterization.isValid())
+ << "\n surface_size=" << surface_size.ToString()
+ << "\n format=" << static_cast<int>(format)
+ << "\n color_type=" << static_cast<int>(color_type)
+ << "\n backend_format.isValid()=" << backend_format.isValid()
+ << "\n backend_format.backend()="
+ << static_cast<int>(backend_format.backend())
+ << "\n backend_format.asGLFormat()="
+ << static_cast<int>(backend_format.asGLFormat())
+ << "\n backend_format.asVkFormat()="
+ << static_cast<int>(backend_format.asVkFormat(&vk_format))
+ << "\n backend_format.asVkFormat() vk_format="
+ << static_cast<int>(vk_format)
+ << "\n surface_origin=" << static_cast<int>(surface_origin)
+ << "\n willGlFBO0=" << capabilities_.uses_default_gl_framebuffer
+ << "\n isProtected="
+ << impl_on_gpu_->GetGpuPreferences().enforce_vulkan_protected_memory;
return characterization;
}
@@ -806,6 +840,11 @@ void SkiaOutputSurfaceImpl::DidSwapBuffersComplete(
damage = gfx::Rect(size_);
}
+ if (use_damage_area_from_skia_output_device_) {
+ damage_of_current_buffer_ = params.frame_buffer_damage_area;
+ DCHECK(damage_of_current_buffer_);
+ }
+
if (!params.texture_in_use_responses.empty())
client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses);
if (!params.ca_layer_params.is_empty)
@@ -881,6 +920,10 @@ GrBackendFormat SkiaOutputSurfaceImpl::GetGrBackendFormatForTexture(
wgpu::TextureFormat format = ToDawnFormat(resource_format);
return GrBackendFormat::MakeDawn(format);
#endif
+ } else if (dependency_->IsUsingMetal()) {
+#if defined(OS_MACOSX)
+ return GrBackendFormat::MakeMtl(ToMTLPixelFormat(resource_format));
+#endif
} else {
DCHECK(!ycbcr_info);
// Convert internal format from GLES2 to platform GL.
@@ -988,6 +1031,11 @@ SkiaOutputSurfaceImpl::GetGpuTaskSchedulerHelper() {
}
gfx::Rect SkiaOutputSurfaceImpl::GetCurrentFramebufferDamage() const {
+ if (use_damage_area_from_skia_output_device_) {
+ DCHECK(damage_of_current_buffer_);
+ return *damage_of_current_buffer_;
+ }
+
if (damage_of_buffers_.empty())
return gfx::Rect();
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 e7738f180a5..d3369b11a64 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
@@ -269,6 +269,9 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
// to avoid the expense of posting a task and calling MakeCurrent.
base::OnceCallback<bool()> deferred_framebuffer_draw_closure_;
+ bool use_damage_area_from_skia_output_device_ = false;
+ // Damage area of the current buffer. Differ to the last submit buffer.
+ base::Optional<gfx::Rect> damage_of_current_buffer_;
// Current buffer index.
size_t current_buffer_ = 0;
// Damage area of the buffer. Differ to the last submit buffer.
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 1c27142a2d1..7d6ebac68f7 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
@@ -26,6 +26,7 @@
#include "components/viz/service/display/texture_deleter.h"
#include "components/viz/service/display_embedder/direct_context_provider.h"
#include "components/viz/service/display_embedder/image_context_impl.h"
+#include "components/viz/service/display_embedder/output_presenter_gl.h"
#include "components/viz/service/display_embedder/skia_output_device.h"
#include "components/viz/service/display_embedder/skia_output_device_buffer_queue.h"
#include "components/viz/service/display_embedder/skia_output_device_gl.h"
@@ -83,8 +84,18 @@
#if BUILDFLAG(SKIA_USE_DAWN)
#include "components/viz/common/gpu/dawn_context_provider.h"
+#if defined(OS_WIN)
#include "components/viz/service/display_embedder/skia_output_device_dawn.h"
#endif
+#endif
+
+#if defined(USE_OZONE) || defined(USE_X11)
+#include "ui/base/ui_base_features.h"
+#endif
+
+#if defined(OS_FUCHSIA)
+#include "components/viz/service/display_embedder/output_presenter_fuchsia.h"
+#endif
namespace viz {
@@ -278,36 +289,34 @@ void OnRGBAReadbackDone(
} // namespace
-class SkiaOutputSurfaceImplOnGpu::ScopedPromiseImageAccess {
- public:
- ScopedPromiseImageAccess(SkiaOutputSurfaceImplOnGpu* impl_on_gpu,
- std::vector<ImageContextImpl*> image_contexts)
- : impl_on_gpu_(impl_on_gpu), image_contexts_(std::move(image_contexts)) {
- begin_semaphores_.reserve(image_contexts_.size());
- // We may need one more space for the swap buffer semaphore.
- end_semaphores_.reserve(image_contexts_.size() + 1);
- impl_on_gpu_->BeginAccessImages(image_contexts_, &begin_semaphores_,
- &end_semaphores_);
- }
-
- ~ScopedPromiseImageAccess() {
- impl_on_gpu_->EndAccessImages(image_contexts_);
- }
-
- std::vector<GrBackendSemaphore>& begin_semaphores() {
- return begin_semaphores_;
- }
+SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::PromiseImageAccessHelper(
+ SkiaOutputSurfaceImplOnGpu* impl_on_gpu)
+ : impl_on_gpu_(impl_on_gpu) {}
- std::vector<GrBackendSemaphore>& end_semaphores() { return end_semaphores_; }
+SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::
+ ~PromiseImageAccessHelper() {
+ CHECK(image_contexts_.empty());
+}
- private:
- SkiaOutputSurfaceImplOnGpu* const impl_on_gpu_;
- std::vector<ImageContextImpl*> image_contexts_;
- std::vector<GrBackendSemaphore> begin_semaphores_;
- std::vector<GrBackendSemaphore> end_semaphores_;
+void SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::BeginAccess(
+ std::vector<ImageContextImpl*> image_contexts,
+ std::vector<GrBackendSemaphore>* begin_semaphores,
+ std::vector<GrBackendSemaphore>* end_semaphores) {
+ DCHECK(begin_semaphores);
+ DCHECK(end_semaphores);
+ begin_semaphores->reserve(image_contexts.size());
+ // We may need one more space for the swap buffer semaphore.
+ end_semaphores->reserve(image_contexts.size() + 1);
+ image_contexts_.reserve(image_contexts.size() + image_contexts_.size());
+ image_contexts_.insert(image_contexts.begin(), image_contexts.end());
+ impl_on_gpu_->BeginAccessImages(std::move(image_contexts), begin_semaphores,
+ end_semaphores);
+}
- DISALLOW_COPY_AND_ASSIGN(ScopedPromiseImageAccess);
-};
+void SkiaOutputSurfaceImplOnGpu::PromiseImageAccessHelper::EndAccess() {
+ impl_on_gpu_->EndAccessImages(image_contexts_);
+ image_contexts_.clear();
+}
// Skia gr_context() and |context_provider_| share an underlying GLContext.
// Each of them caches some GL state. Interleaving usage could make cached
@@ -599,7 +608,9 @@ class DirectContextProviderDelegateImpl : public DirectContextProviderDelegate,
#if defined(OS_FUCHSIA)
void RegisterSysmemBufferCollection(gfx::SysmemBufferCollectionId id,
- zx::channel token) override {
+ zx::channel token,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage) override {
NOTREACHED();
}
@@ -621,6 +632,10 @@ class DirectContextProviderDelegateImpl : public DirectContextProviderDelegate,
return sync_token;
}
+ void WaitSyncToken(const gpu::SyncToken& sync_token) override {
+ NOTREACHED();
+ }
+
void Flush() override {
// No need to flush in this implementation.
}
@@ -810,6 +825,8 @@ SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu(
dawn_context_provider_(dependency_->GetDawnContextProvider()),
renderer_settings_(renderer_settings),
sequence_id_(sequence_id),
+ did_swap_buffer_complete_callback_(
+ std::move(did_swap_buffer_complete_callback)),
context_lost_callback_(std::move(context_lost_callback)),
gpu_vsync_callback_(std::move(gpu_vsync_callback)),
gpu_preferences_(dependency_->GetGpuPreferences()),
@@ -818,8 +835,6 @@ SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu(
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
- did_swap_buffer_complete_callback_ = CreateSafeRepeatingCallback(
- weak_ptr_, std::move(did_swap_buffer_complete_callback));
buffer_presented_callback_ = CreateSafeRepeatingCallback(
weak_ptr_, std::move(buffer_presented_callback));
}
@@ -833,7 +848,7 @@ SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() {
gl::ScopedProgressReporter scoped_progress_reporter(
context_state_->progress_reporter());
// This ensures any outstanding callbacks for promise images are performed.
- gr_context()->flush();
+ gr_context()->flushAndSubmit();
release_current_last_.emplace(gl_surface_, context_state_);
}
@@ -884,14 +899,23 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
base::Optional<gfx::Rect> draw_rectangle) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(ddl);
DCHECK(!scoped_output_device_paint_);
- if (!MakeCurrent(true /* need_fbo0 */))
+ bool need_fbo0 = gl_surface_ && !gl_surface_->IsSurfaceless();
+ if (!MakeCurrent(need_fbo0))
+ return false;
+
+ if (!ddl) {
+ MarkContextLost(CONTEXT_LOST_UNKNOWN);
return false;
+ }
- if (draw_rectangle)
- output_device_->SetDrawRectangle(*draw_rectangle);
+ if (draw_rectangle) {
+ if (!output_device_->SetDrawRectangle(*draw_rectangle)) {
+ MarkContextLost(
+ ContextLostReason::CONTEXT_LOST_SET_DRAW_RECTANGLE_FAILED);
+ }
+ }
// We do not reset scoped_output_device_paint_ after drawing the ddl until
// SwapBuffers() is called, because we may need access to output_sk_surface()
@@ -910,12 +934,13 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
gpu::kInProcessCommandBufferClientId);
}
- ScopedPromiseImageAccess scoped_promise_image_access(
- this, std::move(image_contexts));
- if (!scoped_promise_image_access.begin_semaphores().empty()) {
- auto result = output_sk_surface()->wait(
- scoped_promise_image_access.begin_semaphores().size(),
- scoped_promise_image_access.begin_semaphores().data());
+ std::vector<GrBackendSemaphore> begin_semaphores;
+ std::vector<GrBackendSemaphore> end_semaphores;
+ promise_image_access_helper_.BeginAccess(
+ std::move(image_contexts), &begin_semaphores, &end_semaphores);
+ if (!begin_semaphores.empty()) {
+ auto result = output_sk_surface()->wait(begin_semaphores.size(),
+ begin_semaphores.data());
DCHECK(result);
}
@@ -941,22 +966,16 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
&paint);
}
- GrFlushInfo flush_info;
- flush_info.fFlags = kNone_GrFlushFlags;
-
auto end_paint_semaphores =
scoped_output_device_paint_->TakeEndPaintSemaphores();
+ end_semaphores.insert(end_semaphores.end(), end_paint_semaphores.begin(),
+ end_paint_semaphores.end());
- end_paint_semaphores.insert(
- end_paint_semaphores.end(),
- std::make_move_iterator(
- scoped_promise_image_access.end_semaphores().begin()),
- std::make_move_iterator(
- scoped_promise_image_access.end_semaphores().end()));
-
- // update the size and data pointer
- flush_info.fNumSemaphores = end_paint_semaphores.size();
- flush_info.fSignalSemaphores = end_paint_semaphores.data();
+ GrFlushInfo flush_info = {
+ .fFlags = kNone_GrFlushFlags,
+ .fNumSemaphores = end_semaphores.size(),
+ .fSignalSemaphores = end_semaphores.data(),
+ };
gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_,
&flush_info);
@@ -972,8 +991,7 @@ bool SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
}
if (result != GrSemaphoresSubmitted::kYes &&
- !(scoped_promise_image_access.begin_semaphores().empty() &&
- end_paint_semaphores.empty())) {
+ !(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
DLOG(ERROR) << "output_sk_surface()->flush() failed.";
return false;
@@ -1007,6 +1025,8 @@ void SkiaOutputSurfaceImplOnGpu::SwapBuffers(
}
DCHECK(output_device_);
+ gr_context()->submit();
+ promise_image_access_helper_.EndAccess();
scoped_output_device_paint_.reset();
if (output_surface_plane_) {
@@ -1049,12 +1069,15 @@ void SkiaOutputSurfaceImplOnGpu::SwapBuffers(
void SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped(
base::OnceCallback<bool()> deferred_framebuffer_draw_closure) {
- std::move(deferred_framebuffer_draw_closure).Run();
-
+ if (deferred_framebuffer_draw_closure)
+ std::move(deferred_framebuffer_draw_closure).Run();
+ gr_context()->submit();
+ promise_image_access_helper_.EndAccess();
// Perform cleanup that would have otherwise happened in SwapBuffers().
scoped_output_device_paint_.reset();
context_state_->UpdateSkiaOwnedMemorySize();
destroy_after_swap_.clear();
+
#if BUILDFLAG(ENABLE_VULKAN)
if (is_using_vulkan())
gpu::ReportQueueSubmitPerSwapBuffers();
@@ -1071,8 +1094,13 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(ddl);
- if (!MakeCurrent(true /* need_fbo0 */))
+ if (!MakeCurrent(false /* need_fbo0 */))
+ return;
+
+ if (!ddl) {
+ MarkContextLost(CONTEXT_LOST_UNKNOWN);
return;
+ }
PullTextureUpdates(std::move(sync_tokens));
@@ -1089,31 +1117,29 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
cache_use.emplace(dependency_->GetGrShaderCache(),
gpu::kInProcessCommandBufferClientId);
}
- ScopedPromiseImageAccess scoped_promise_image_access(
- this, std::move(image_contexts));
- if (!scoped_promise_image_access.begin_semaphores().empty()) {
- auto result = offscreen.surface()->wait(
- scoped_promise_image_access.begin_semaphores().size(),
- scoped_promise_image_access.begin_semaphores().data());
+ std::vector<GrBackendSemaphore> begin_semaphores;
+ std::vector<GrBackendSemaphore> end_semaphores;
+ promise_image_access_helper_.BeginAccess(
+ std::move(image_contexts), &begin_semaphores, &end_semaphores);
+ if (!begin_semaphores.empty()) {
+ auto result = offscreen.surface()->wait(begin_semaphores.size(),
+ begin_semaphores.data());
DCHECK(result);
}
offscreen.surface()->draw(ddl.get());
destroy_after_swap_.emplace_back(std::move(ddl));
- GrFlushInfo flush_info;
- flush_info.fFlags = kNone_GrFlushFlags;
- flush_info.fNumSemaphores =
- scoped_promise_image_access.end_semaphores().size();
- flush_info.fSignalSemaphores =
- scoped_promise_image_access.end_semaphores().data();
-
+ GrFlushInfo flush_info = {
+ .fFlags = kNone_GrFlushFlags,
+ .fNumSemaphores = end_semaphores.size(),
+ .fSignalSemaphores = end_semaphores.data(),
+ };
gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_,
&flush_info);
auto result = offscreen.surface()->flush(
SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
if (result != GrSemaphoresSubmitted::kYes &&
- !(scoped_promise_image_access.begin_semaphores().empty() &&
- scoped_promise_image_access.end_semaphores().empty())) {
+ !(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
DLOG(ERROR) << "offscreen.surface()->flush() failed.";
return;
@@ -1142,7 +1168,7 @@ void SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource(
// |image_contexts| will go out of scope and be destroyed now.
}
-void SkiaOutputSurfaceImplOnGpu::CopyOutput(
+bool SkiaOutputSurfaceImplOnGpu::CopyOutput(
RenderPassId id,
copy_output::RenderPassGeometry geometry,
const gfx::ColorSpace& color_space,
@@ -1152,10 +1178,15 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
// TODO(crbug.com/898595): Do this on the GPU instead of CPU with Vulkan.
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // Clear |destroy_after_swap_| if we CopyOutput without SwapBuffers.
- base::ScopedClosureRunner cleanup(
- base::BindOnce([](std::vector<std::unique_ptr<SkDeferredDisplayList>>) {},
- std::move(destroy_after_swap_)));
+ if (deferred_framebuffer_draw_closure) {
+ // returns false if context not set to current, i.e lost
+ if (!std::move(deferred_framebuffer_draw_closure).Run())
+ return false;
+ DCHECK(context_state_->IsCurrent(nullptr /* surface */));
+ } else {
+ if (!MakeCurrent(true /* need_fbo0 */))
+ return false;
+ }
if (use_gl_renderer_copier_)
gpu::ContextUrl::SetActiveUrl(copier_active_url_);
@@ -1163,8 +1194,6 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
// Lazy initialize GLRendererCopier before draw because
// DirectContextProvider ctor the backbuffer.
if (use_gl_renderer_copier_ && !copier_) {
- if (!MakeCurrent(true /* need_fbo0 */))
- return;
auto client = std::make_unique<DirectContextProviderDelegateImpl>(
gpu_preferences_, dependency_->GetGpuDriverBugWorkarounds(),
dependency_->GetGpuFeatureInfo(), context_state_.get(),
@@ -1178,7 +1207,7 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
if (result != gpu::ContextResult::kSuccess) {
DLOG(ERROR) << "Couldn't initialize GLRendererCopier";
context_provider_ = nullptr;
- return;
+ return false;
}
context_current_task_runner_ =
base::MakeRefCounted<ContextCurrentTaskRunner>(weak_ptr_);
@@ -1193,15 +1222,6 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
gr_context()->resetContext();
}
- if (deferred_framebuffer_draw_closure) {
- // returns false if context not set to current, i.e lost
- if (!std::move(deferred_framebuffer_draw_closure).Run())
- return;
- DCHECK(context_state_->IsCurrent(nullptr /* surface */));
- } else {
- if (!MakeCurrent(true /* need_fbo0 */))
- return;
- }
bool from_fbo0 = !id;
DCHECK(scoped_output_device_paint_ || !from_fbo0);
@@ -1227,11 +1247,11 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
surface->getCanvas()->drawPaint(paint);
gl::ScopedProgressReporter scoped_progress_reporter(
context_state_->progress_reporter());
- surface->flush();
+ surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, {});
}
if (use_gl_renderer_copier_) {
- surface->flush();
+ surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, {});
GLuint gl_id = 0;
GLenum internal_format = supports_alpha_ ? GL_RGBA : GL_RGB;
@@ -1262,7 +1282,7 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
if (decoder()->HasMoreIdleWork() || decoder()->HasPendingQueries())
ScheduleDelayedWork();
- return;
+ return true;
}
base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
@@ -1307,7 +1327,6 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
SkIRect src_rect =
SkIRect::MakeXYWH(source_selection.x(), source_selection.y(),
source_selection.width(), source_selection.height());
-
if (request->result_format() ==
CopyOutputRequest::ResultFormat::I420_PLANES) {
std::unique_ptr<ReadPixelsContext> context =
@@ -1338,6 +1357,7 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
NOTIMPLEMENTED(); // ResultFormat::RGBA_TEXTURE
}
ScheduleCheckReadbackCompletion();
+ return true;
}
gpu::DecoderContext* SkiaOutputSurfaceImplOnGpu::decoder() {
@@ -1399,7 +1419,7 @@ void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
}
void SkiaOutputSurfaceImplOnGpu::EndAccessImages(
- const std::vector<ImageContextImpl*>& image_contexts) {
+ const base::flat_set<ImageContextImpl*>& image_contexts) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::EndAccessImages");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
for (auto* context : image_contexts)
@@ -1457,7 +1477,7 @@ void SkiaOutputSurfaceImplOnGpu::SetCapabilitiesForTesting(
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, capabilities.output_surface_origin,
renderer_settings_.requires_alpha_channel, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ GetDidSwapBuffersCompleteCallback());
}
bool SkiaOutputSurfaceImplOnGpu::Initialize() {
@@ -1465,11 +1485,13 @@ bool SkiaOutputSurfaceImplOnGpu::Initialize() {
"is_using_vulkan", is_using_vulkan());
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
#if defined(USE_OZONE)
- gpu::SurfaceHandle surface_handle = dependency_->GetSurfaceHandle();
- if (surface_handle != gpu::kNullSurfaceHandle) {
- window_surface_ = ui::OzonePlatform::GetInstance()
- ->GetSurfaceFactoryOzone()
- ->CreatePlatformWindowSurface(surface_handle);
+ if (features::IsUsingOzonePlatform()) {
+ gpu::SurfaceHandle surface_handle = dependency_->GetSurfaceHandle();
+ if (surface_handle != gpu::kNullSurfaceHandle) {
+ window_surface_ = ui::OzonePlatform::GetInstance()
+ ->GetSurfaceFactoryOzone()
+ ->CreatePlatformWindowSurface(surface_handle);
+ }
}
#endif
@@ -1516,7 +1538,7 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, gfx::SurfaceOrigin::kTopLeft,
renderer_settings_.requires_alpha_channel, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ GetDidSwapBuffersCompleteCallback());
supports_alpha_ = renderer_settings_.requires_alpha_channel;
} else {
gl_surface_ =
@@ -1529,8 +1551,10 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
if (gl_surface_->IsSurfaceless()) {
std::unique_ptr<SkiaOutputDeviceBufferQueue> onscreen_device =
std::make_unique<SkiaOutputDeviceBufferQueue>(
- gl_surface_, dependency_, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ std::make_unique<OutputPresenterGL>(gl_surface_, dependency_,
+ memory_tracker_.get()),
+ dependency_, memory_tracker_.get(),
+ GetDidSwapBuffersCompleteCallback());
supports_alpha_ = onscreen_device->supports_alpha();
output_device_ = std::move(onscreen_device);
@@ -1539,7 +1563,7 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
std::unique_ptr<SkiaOutputDeviceWebView> onscreen_device =
std::make_unique<SkiaOutputDeviceWebView>(
context_state_.get(), gl_surface_, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ GetDidSwapBuffersCompleteCallback());
supports_alpha_ = onscreen_device->supports_alpha();
output_device_ = std::move(onscreen_device);
} else {
@@ -1547,7 +1571,7 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForGL() {
std::make_unique<SkiaOutputDeviceGL>(
dependency_->GetMailboxManager(), context_state_.get(),
gl_surface_, feature_info_, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ GetDidSwapBuffersCompleteCallback());
supports_alpha_ = onscreen_device->supports_alpha();
output_device_ = std::move(onscreen_device);
}
@@ -1571,44 +1595,56 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, gfx::SurfaceOrigin::kBottomLeft,
renderer_settings_.requires_alpha_channel, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ GetDidSwapBuffersCompleteCallback());
supports_alpha_ = renderer_settings_.requires_alpha_channel;
} else {
#if defined(USE_X11)
- supports_alpha_ = true;
- if (!gpu_preferences_.disable_vulkan_surface) {
- output_device_ = SkiaOutputDeviceVulkan::Create(
- vulkan_context_provider_, dependency_->GetSurfaceHandle(),
- memory_tracker_.get(), did_swap_buffer_complete_callback_);
+ if (!features::IsUsingOzonePlatform()) {
+ supports_alpha_ = true;
+ if (!gpu_preferences_.disable_vulkan_surface) {
+ output_device_ = SkiaOutputDeviceVulkan::Create(
+ vulkan_context_provider_, dependency_->GetSurfaceHandle(),
+ memory_tracker_.get(), GetDidSwapBuffersCompleteCallback());
+ }
+ if (!output_device_) {
+ output_device_ = std::make_unique<SkiaOutputDeviceX11>(
+ context_state_, dependency_->GetSurfaceHandle(),
+ memory_tracker_.get(), GetDidSwapBuffersCompleteCallback());
+ }
}
+#endif
if (!output_device_) {
- output_device_ = std::make_unique<SkiaOutputDeviceX11>(
- context_state_, dependency_->GetSurfaceHandle(),
- memory_tracker_.get(), did_swap_buffer_complete_callback_);
- }
+#if defined(OS_FUCHSIA)
+ auto output_presenter = OutputPresenterFuchsia::Create(
+ window_surface_.get(), dependency_, memory_tracker_.get());
#else
- auto output_device = SkiaOutputDeviceBufferQueue::Create(
- dependency_, memory_tracker_.get(), did_swap_buffer_complete_callback_);
- if (output_device) {
- // TODO(https://crbug.com/1012401): don't depend on GL.
- gl_surface_ = output_device->gl_surface();
- output_device_ = std::move(output_device);
- } else {
- auto output_device = SkiaOutputDeviceVulkan::Create(
- vulkan_context_provider_, dependency_->GetSurfaceHandle(),
- memory_tracker_.get(), did_swap_buffer_complete_callback_);
-#if defined(OS_WIN)
- gpu::SurfaceHandle child_surface =
- output_device ? output_device->GetChildSurfaceHandle()
- : gpu::kNullSurfaceHandle;
- if (child_surface != gpu::kNullSurfaceHandle) {
- DidCreateAcceleratedSurfaceChildWindow(dependency_->GetSurfaceHandle(),
- child_surface);
+ auto output_presenter =
+ OutputPresenterGL::Create(dependency_, memory_tracker_.get());
+ if (output_presenter) {
+ // TODO(https://crbug.com/1012401): don't depend on GL.
+ gl_surface_ = output_presenter->gl_surface();
}
#endif
- output_device_ = std::move(output_device);
- }
+ if (output_presenter) {
+ output_device_ = std::make_unique<SkiaOutputDeviceBufferQueue>(
+ std::move(output_presenter), dependency_, memory_tracker_.get(),
+ GetDidSwapBuffersCompleteCallback());
+ } else {
+ auto output_device = SkiaOutputDeviceVulkan::Create(
+ vulkan_context_provider_, dependency_->GetSurfaceHandle(),
+ memory_tracker_.get(), GetDidSwapBuffersCompleteCallback());
+#if defined(OS_WIN)
+ gpu::SurfaceHandle child_surface =
+ output_device ? output_device->GetChildSurfaceHandle()
+ : gpu::kNullSurfaceHandle;
+ if (child_surface != gpu::kNullSurfaceHandle) {
+ DidCreateAcceleratedSurfaceChildWindow(
+ dependency_->GetSurfaceHandle(), child_surface);
+ }
#endif
+ output_device_ = std::move(output_device);
+ }
+ }
}
#endif
return !!output_device_;
@@ -1622,20 +1658,33 @@ bool SkiaOutputSurfaceImplOnGpu::InitializeForDawn() {
output_device_ = std::make_unique<SkiaOutputDeviceOffscreen>(
context_state_, gfx::SurfaceOrigin::kBottomLeft,
renderer_settings_.requires_alpha_channel, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ GetDidSwapBuffersCompleteCallback());
supports_alpha_ = renderer_settings_.requires_alpha_channel;
} else {
#if defined(USE_X11)
// TODO(sgilhuly): Set up a Vulkan swapchain so that Linux can also use
// SkiaOutputDeviceDawn.
- output_device_ = std::make_unique<SkiaOutputDeviceX11>(
- context_state_, dependency_->GetSurfaceHandle(), memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ if (!features::IsUsingOzonePlatform()) {
+ output_device_ = std::make_unique<SkiaOutputDeviceX11>(
+ context_state_, dependency_->GetSurfaceHandle(),
+ memory_tracker_.get(), GetDidSwapBuffersCompleteCallback());
+ } else {
+ return false;
+ }
+#elif defined(OS_WIN)
+ std::unique_ptr<SkiaOutputDeviceDawn> output_device =
+ std::make_unique<SkiaOutputDeviceDawn>(
+ dawn_context_provider_, dependency_->GetSurfaceHandle(),
+ gfx::SurfaceOrigin::kTopLeft, memory_tracker_.get(),
+ GetDidSwapBuffersCompleteCallback());
+ const gpu::SurfaceHandle child_surface_handle =
+ output_device->GetChildSurfaceHandle();
+ DidCreateAcceleratedSurfaceChildWindow(dependency_->GetSurfaceHandle(),
+ child_surface_handle);
+ output_device_ = std::move(output_device);
#else
- output_device_ = std::make_unique<SkiaOutputDeviceDawn>(
- dawn_context_provider_, dependency_->GetSurfaceHandle(),
- gfx::SurfaceOrigin::kTopLeft, memory_tracker_.get(),
- did_swap_buffer_complete_callback_);
+ NOTREACHED();
+ return false;
#endif
}
#endif
@@ -1651,9 +1700,10 @@ bool SkiaOutputSurfaceImplOnGpu::MakeCurrent(bool need_fbo0) {
if (!context_state_->MakeCurrent(gl_surface, need_gl)) {
LOG(ERROR) << "Failed to make current.";
dependency_->DidLoseContext(
- gpu::error::kMakeCurrentFailed,
+ *context_state_->context_lost_reason(),
GURL("chrome://gpu/SkiaOutputSurfaceImplOnGpu::MakeCurrent"));
- MarkContextLost(CONTEXT_LOST_MAKECURRENT_FAILED);
+ MarkContextLost(GetContextLostReason(
+ gpu::error::kLostContext, *context_state_->context_lost_reason()));
return false;
}
context_state_->set_need_context_state_reset(true);
@@ -1734,6 +1784,28 @@ void SkiaOutputSurfaceImplOnGpu::BufferPresented(
// Handled by SkiaOutputDevice already.
}
+void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal(
+ gpu::SwapBuffersCompleteParams params,
+ const gfx::Size& pixel_size) {
+ if (params.swap_response.result == gfx::SwapResult::SWAP_FAILED) {
+ DLOG(ERROR) << "Context lost on SWAP_FAILED";
+ if (!context_state_->IsCurrent(nullptr) ||
+ !context_state_->CheckResetStatus(false)) {
+ // Mark the context lost if not already lost.
+ MarkContextLost(ContextLostReason::CONTEXT_LOST_SWAP_FAILED);
+ }
+ }
+
+ PostTaskToClientThread(
+ base::BindOnce(did_swap_buffer_complete_callback_, params, pixel_size));
+}
+
+SkiaOutputSurfaceImplOnGpu::DidSwapBufferCompleteCallback
+SkiaOutputSurfaceImplOnGpu::GetDidSwapBuffersCompleteCallback() {
+ return base::BindRepeating(
+ &SkiaOutputSurfaceImplOnGpu::DidSwapBuffersCompleteInternal, weak_ptr_);
+}
+
void SkiaOutputSurfaceImplOnGpu::MarkContextLost(ContextLostReason reason) {
// This function potentially can be re-entered during from
// SharedContextState::MarkContextLost(). This guards against it.
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 b9ab673914a..c6919214b9c 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
@@ -9,7 +9,6 @@
#include <utility>
#include <vector>
-#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/threading/thread_checker.h"
@@ -153,7 +152,7 @@ class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
void RemoveRenderPassResource(
std::vector<RenderPassId> ids,
std::vector<std::unique_ptr<ImageContextImpl>> image_contexts);
- void CopyOutput(RenderPassId id,
+ bool CopyOutput(RenderPassId id,
copy_output::RenderPassGeometry geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request,
@@ -162,7 +161,7 @@ class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
void BeginAccessImages(const std::vector<ImageContextImpl*>& image_contexts,
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores);
- void EndAccessImages(const std::vector<ImageContextImpl*>& image_contexts);
+ void EndAccessImages(const base::flat_set<ImageContextImpl*>& image_contexts);
sk_sp<GrContextThreadSafeProxy> GetGrContextThreadSafeProxy();
const gl::GLVersionInfo* gl_version_info() const { return gl_version_info_; }
@@ -211,7 +210,6 @@ class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
gpu::MemoryTracker* GetMemoryTracker() { return memory_tracker_.get(); }
private:
- class ScopedPromiseImageAccess;
class OffscreenSurface;
class DisplayContext;
@@ -220,6 +218,12 @@ class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
bool InitializeForVulkan();
bool InitializeForDawn();
+ // Provided as a callback to |device_|.
+ void DidSwapBuffersCompleteInternal(gpu::SwapBuffersCompleteParams params,
+ const gfx::Size& pixel_size);
+
+ DidSwapBufferCompleteCallback GetDidSwapBuffersCompleteCallback();
+
// Make context current for GL, and return false if the context is lost.
// It will do nothing when Vulkan is used.
bool MakeCurrent(bool need_fbo0);
@@ -286,6 +290,7 @@ class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
// readback using GLRendererCopier.
// TODO(samans): Remove |sequence_id| once readback always uses Skia.
const gpu::SequenceId sequence_id_;
+ // Should only be run on the client thread with PostTaskToClientThread().
DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_;
BufferPresentedCallback buffer_presented_callback_;
ContextLostCallback context_lost_callback_;
@@ -308,6 +313,24 @@ class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
std::unique_ptr<DisplayContext> display_context_;
bool context_is_lost_ = false;
+ class PromiseImageAccessHelper {
+ public:
+ explicit PromiseImageAccessHelper(SkiaOutputSurfaceImplOnGpu* impl_on_gpu);
+ ~PromiseImageAccessHelper();
+
+ void BeginAccess(std::vector<ImageContextImpl*> image_contexts,
+ std::vector<GrBackendSemaphore>* begin_semaphores,
+ std::vector<GrBackendSemaphore>* end_semaphores);
+ void EndAccess();
+
+ private:
+ SkiaOutputSurfaceImplOnGpu* const impl_on_gpu_;
+ base::flat_set<ImageContextImpl*> image_contexts_;
+
+ DISALLOW_COPY_AND_ASSIGN(PromiseImageAccessHelper);
+ };
+ PromiseImageAccessHelper promise_image_access_helper_{this};
+
std::unique_ptr<SkiaOutputDevice> output_device_;
base::Optional<SkiaOutputDevice::ScopedPaint> scoped_output_device_paint_;
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 67800b78170..8f5b7e6e077 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
@@ -156,6 +156,7 @@ TEST_F(SkiaOutputSurfaceImplTest, SubmitPaint) {
geometry.readback_offset = gfx::Vector2d(0, 0);
output_surface_->CopyOutput(0, geometry, color_space, std::move(request));
+ output_surface_->SwapBuffersSkipped();
BlockMainThread();
// SubmitPaint draw is deferred until CopyOutput.
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 dc602776aad..bb23f23c193 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
@@ -11,6 +11,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/resources/bitmap_allocation.h"
@@ -46,6 +47,20 @@ void RecordShouldSendBeginFrame(SendBeginFrameResult result) {
"Compositing.CompositorFrameSinkSupport.ShouldSendBeginFrame", result);
}
+void AdjustPresentationFeedback(gfx::PresentationFeedback* feedback,
+ base::TimeTicks swap_start) {
+ // Swap start to end breakdown is always reported if ready timestamp is
+ // available. The other timestamps are adjusted to assume 0 delay in those
+ // stages if the breakdown is not available.
+ if (feedback->ready_timestamp.is_null())
+ return;
+
+ feedback->available_timestamp =
+ std::max(feedback->available_timestamp, swap_start);
+ feedback->latch_timestamp =
+ std::max(feedback->latch_timestamp, feedback->ready_timestamp);
+}
+
} // namespace
CompositorFrameSinkSupport::CompositorFrameSinkSupport(
@@ -623,6 +638,8 @@ void CompositorFrameSinkSupport::DidPresentCompositorFrame(
details.draw_start_timestamp = draw_start_timestamp;
details.swap_timings = swap_timings;
details.presentation_feedback = feedback;
+ AdjustPresentationFeedback(&details.presentation_feedback,
+ swap_timings.swap_start);
pending_received_frame_times_.erase(received_frame_timestamp);
// We should only ever get one PresentationFeedback per frame_token.
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index 04968717787..dacc55a238f 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/test/simple_test_tick_clock.h"
+#include "build/build_config.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/compositor_frame.h"
@@ -22,18 +23,19 @@
#include "components/viz/test/fake_external_begin_frame_source.h"
#include "components/viz/test/fake_surface_observer.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
+#include "components/viz/test/viz_test_suite.h"
#include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
#include "services/viz/public/mojom/compositing/compositor_frame_sink.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/khronos/GLES2/gl2.h"
-using testing::UnorderedElementsAre;
-using testing::IsEmpty;
-using testing::SizeIs;
-using testing::Invoke;
using testing::_;
using testing::Eq;
+using testing::Invoke;
+using testing::IsEmpty;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
namespace viz {
namespace {
@@ -645,13 +647,17 @@ TEST_F(CompositorFrameSinkSupportTest, ProhibitsUnprivilegedCopyRequests) {
false /* not root frame sink */);
bool did_receive_aborted_copy_result = false;
+ base::RunLoop aborted_copy_run_loop;
auto request = std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
base::BindOnce(
- [](bool* got_nothing, std::unique_ptr<CopyOutputResult> result) {
+ [](bool* got_nothing, base::OnceClosure finished,
+ std::unique_ptr<CopyOutputResult> result) {
*got_nothing = result->IsEmpty();
+ std::move(finished).Run();
},
- &did_receive_aborted_copy_result));
+ &did_receive_aborted_copy_result,
+ aborted_copy_run_loop.QuitClosure()));
auto frame = MakeDefaultCompositorFrame();
ResourceId frame_resource_ids[] = {1, 2, 3};
@@ -660,6 +666,7 @@ TEST_F(CompositorFrameSinkSupportTest, ProhibitsUnprivilegedCopyRequests) {
EXPECT_FALSE(SubmitCompositorFrameWithCopyRequest(std::move(frame),
std::move(request)));
+ aborted_copy_run_loop.Run();
EXPECT_TRUE(did_receive_aborted_copy_result);
// All the resources in the rejected frame should have been returned.
@@ -778,8 +785,10 @@ TEST_F(CompositorFrameSinkSupportTest, EvictOlderSurfaces) {
}
void CopyRequestTestCallback(bool* called,
+ base::OnceClosure finished,
std::unique_ptr<CopyOutputResult> result) {
*called = true;
+ std::move(finished).Run();
}
TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
@@ -796,9 +805,11 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
}
bool called1 = false;
+ base::RunLoop called1_run_loop;
auto request = std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&CopyRequestTestCallback, &called1));
+ base::BindOnce(&CopyRequestTestCallback, &called1,
+ called1_run_loop.QuitClosure()));
request->set_source(kArbitrarySourceId1);
support_->RequestCopyOfOutput(local_surface_id_, std::move(request));
@@ -806,9 +817,11 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
EXPECT_FALSE(called1);
bool called2 = false;
+ base::RunLoop called2_run_loop;
request = std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&CopyRequestTestCallback, &called2));
+ base::BindOnce(&CopyRequestTestCallback, &called2,
+ called2_run_loop.QuitClosure()));
request->set_source(kArbitrarySourceId2);
support_->RequestCopyOfOutput(local_surface_id_, std::move(request));
@@ -818,14 +831,17 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
EXPECT_FALSE(called2);
bool called3 = false;
+ base::RunLoop called3_run_loop;
request = std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&CopyRequestTestCallback, &called3));
+ base::BindOnce(&CopyRequestTestCallback, &called3,
+ called3_run_loop.QuitClosure()));
request->set_source(kArbitrarySourceId1);
support_->RequestCopyOfOutput(local_surface_id_, std::move(request));
GetSurfaceForId(surface_id)->TakeCopyOutputRequestsFromClient();
// Two callbacks are from source1, so the first should be called.
+ called1_run_loop.Run();
EXPECT_TRUE(called1);
EXPECT_FALSE(called2);
EXPECT_FALSE(called3);
@@ -834,6 +850,8 @@ TEST_F(CompositorFrameSinkSupportTest, DuplicateCopyRequest) {
ExpireAllTemporaryReferences();
local_surface_id_ = LocalSurfaceId();
manager_.surface_manager()->GarbageCollectSurfaces();
+ called2_run_loop.Run();
+ called3_run_loop.Run();
EXPECT_TRUE(called1);
EXPECT_TRUE(called2);
EXPECT_TRUE(called3);
@@ -1437,5 +1455,4 @@ TEST_F(CompositorFrameSinkSupportTest, ThrottleUnresponsiveClient) {
support->SetNeedsBeginFrame(false);
}
-
} // namespace viz
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 f7623ec4869..80767529f3c 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
@@ -12,10 +12,10 @@
#include <vector>
#include "base/callback_helpers.h"
+#include "base/check.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h"
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 c2b189e0e66..675e05a76a7 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
@@ -64,7 +64,7 @@ RootCompositorFrameSinkImpl::Create(
bool hw_support_for_multiple_refresh_rates = false;
bool wants_vsync_updates = false;
- if (params->external_begin_frame_controller.is_pending()) {
+ if (params->external_begin_frame_controller) {
auto owned_external_begin_frame_source_mojo =
std::make_unique<ExternalBeginFrameSourceMojo>(
frame_sink_manager,
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 08338b4153b..037d3cbea16 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
@@ -15,6 +15,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -521,29 +522,20 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
// metadata, and notify the oracle.
const int64_t capture_frame_number = next_capture_frame_number_++;
VideoFrameMetadata* const metadata = frame->metadata();
- metadata->SetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME,
- clock_->NowTicks());
- metadata->SetInteger(VideoFrameMetadata::CAPTURE_COUNTER,
- capture_frame_number);
- metadata->SetTimeDelta(VideoFrameMetadata::FRAME_DURATION,
- oracle_->estimated_frame_duration());
- metadata->SetDouble(VideoFrameMetadata::FRAME_RATE,
- 1.0 / oracle_->min_capture_period().InSecondsF());
- metadata->SetTimeTicks(VideoFrameMetadata::REFERENCE_TIME, event_time);
- metadata->SetDouble(VideoFrameMetadata::DEVICE_SCALE_FACTOR,
- frame_metadata.device_scale_factor);
- metadata->SetDouble(VideoFrameMetadata::PAGE_SCALE_FACTOR,
- frame_metadata.page_scale_factor);
- metadata->SetDouble(VideoFrameMetadata::ROOT_SCROLL_OFFSET_X,
- frame_metadata.root_scroll_offset.x());
- metadata->SetDouble(VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y,
- frame_metadata.root_scroll_offset.y());
+ metadata->capture_begin_time = clock_->NowTicks();
+ metadata->capture_counter = capture_frame_number;
+ metadata->frame_duration = oracle_->estimated_frame_duration();
+ metadata->frame_rate = 1.0 / oracle_->min_capture_period().InSecondsF();
+ metadata->reference_time = event_time;
+ metadata->device_scale_factor = frame_metadata.device_scale_factor;
+ metadata->page_scale_factor = frame_metadata.page_scale_factor;
+ metadata->root_scroll_offset_x = frame_metadata.root_scroll_offset.x();
+ metadata->root_scroll_offset_y = frame_metadata.root_scroll_offset.y();
if (frame_metadata.top_controls_visible_height.has_value()) {
last_top_controls_visible_height_ =
*frame_metadata.top_controls_visible_height;
}
- metadata->SetDouble(VideoFrameMetadata::TOP_CONTROLS_VISIBLE_HEIGHT,
- last_top_controls_visible_height_);
+ metadata->top_controls_visible_height = last_top_controls_visible_height_;
oracle_->RecordCapture(utilization);
TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", oracle_frame_number,
@@ -578,8 +570,8 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
if (pixel_format_ == media::PIXEL_FORMAT_I420)
update_rect = ExpandRectToI420SubsampleBoundaries(update_rect);
}
- metadata->SetRect(media::VideoFrameMetadata::CAPTURE_UPDATE_RECT,
- update_rect);
+ metadata->capture_update_rect = update_rect;
+
// Extreme edge-case: If somehow the source size is so tiny that the content
// region becomes empty, just deliver a frame filled with black.
if (content_rect.IsEmpty()) {
@@ -639,6 +631,7 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
VideoCaptureOverlay::MakeCombinedRenderer(
GetOverlaysInOrder(), content_rect, frame->format()),
std::move(frame), base::TimeTicks::Now())));
+ request->set_result_task_runner(base::SequencedTaskRunnerHandle::Get());
request->set_source(copy_request_source_);
request->set_area(gfx::Rect(source_size));
request->SetScaleRatio(
@@ -803,10 +796,8 @@ void FrameSinkVideoCapturerImpl::OnFrameReadyForDelivery(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_GE(capture_frame_number, next_delivery_frame_number_);
- if (frame) {
- frame->metadata()->SetTimeTicks(VideoFrameMetadata::CAPTURE_END_TIME,
- clock_->NowTicks());
- }
+ if (frame)
+ frame->metadata()->capture_end_time = clock_->NowTicks();
// Ensure frames are delivered in-order by using a min-heap, and only
// deliver the next frame(s) in-sequence when they are found at the top.
@@ -871,7 +862,7 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
// the consumer.
media::mojom::VideoFrameInfoPtr info = media::mojom::VideoFrameInfo::New();
info->timestamp = frame->timestamp();
- info->metadata = frame->metadata()->GetInternalValues().Clone();
+ info->metadata = *(frame->metadata());
info->pixel_format = frame->format();
info->coded_size = frame->coded_size();
info->visible_rect = frame->visible_rect();
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 11b9327289f..21ef53a9b01 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
@@ -58,20 +58,16 @@ bool CompareVarsInCompositorFrameMetadata(
float device_scale_factor,
float page_scale_factor,
const gfx::Vector2dF& root_scroll_offset) {
- double dsf, psf, rso_x, rso_y;
- bool valid = true;
-
- valid &= frame.metadata()->GetDouble(
- media::VideoFrameMetadata::DEVICE_SCALE_FACTOR, &dsf);
- valid &= frame.metadata()->GetDouble(
- media::VideoFrameMetadata::PAGE_SCALE_FACTOR, &psf);
- valid &= frame.metadata()->GetDouble(
- media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_X, &rso_x);
- valid &= frame.metadata()->GetDouble(
- media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y, &rso_y);
-
- return valid && dsf == device_scale_factor && psf == page_scale_factor &&
- gfx::Vector2dF(rso_x, rso_y) == root_scroll_offset;
+ auto dsf = frame.metadata()->device_scale_factor;
+ auto psf = frame.metadata()->page_scale_factor;
+ auto rso_x = frame.metadata()->root_scroll_offset_x;
+ auto rso_y = frame.metadata()->root_scroll_offset_y;
+
+ bool valid = dsf.has_value() && psf.has_value() && rso_x.has_value() &&
+ rso_y.has_value();
+
+ return valid && *dsf == device_scale_factor && *psf == page_scale_factor &&
+ gfx::Vector2dF(*rso_x, *rso_y) == root_scroll_offset;
}
// Dummy frame sink ID.
@@ -107,7 +103,11 @@ struct YUVColor {
// Forces any pending Mojo method calls between the capturer and consumer to be
// made.
-void PropagateMojoTasks() {
+void PropagateMojoTasks(
+ scoped_refptr<base::TestMockTimeTaskRunner> runner = nullptr) {
+ if (runner) {
+ runner->RunUntilIdle();
+ }
base::RunLoop().RunUntilIdle();
}
@@ -171,7 +171,7 @@ class MockConsumer : public mojom::FrameSinkVideoConsumer {
const_cast<uint8_t*>(static_cast<const uint8_t*>(mapping.memory())),
mapping.size(), info->timestamp);
ASSERT_TRUE(frame);
- frame->metadata()->MergeInternalValuesFrom(info->metadata);
+ frame->set_metadata(info->metadata);
if (info->color_space.has_value())
frame->set_color_space(info->color_space.value());
@@ -288,7 +288,11 @@ class FakeCapturableFrameSink : public CapturableFrameSink {
void SendCopyOutputResult(int offset) {
auto it = results_.begin() + offset;
std::move(*it).Run();
- PropagateMojoTasks();
+ PropagateMojoTasks(task_runner_);
+ }
+
+ void set_task_runner(scoped_refptr<base::TestMockTimeTaskRunner> runner) {
+ task_runner_ = std::move(runner);
}
private:
@@ -296,6 +300,7 @@ class FakeCapturableFrameSink : public CapturableFrameSink {
YUVColor color_ = {0xde, 0xad, 0xbf};
SizeSet size_set_;
CompositorFrameMetadata metadata_;
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
std::vector<base::OnceClosure> results_;
};
@@ -393,6 +398,10 @@ class FrameSinkVideoCapturerTest : public testing::Test {
start_time_ = task_runner_->NowTicks();
capturer_->clock_ = task_runner_->GetMockTickClock();
+ // Ensure any posted tasks for CopyOutputResults will be handled when
+ // PropagateMojoTasks() is called
+ frame_sink_.set_task_runner(task_runner_);
+
// Replace the retry timer with one that uses this test's fake clock and
// task runner.
capturer_->refresh_frame_retry_timer_.emplace(
@@ -642,26 +651,15 @@ TEST_F(FrameSinkVideoCapturerTest, CapturesCompositedFrames) {
EXPECT_LT(last_timestamp, frame->timestamp());
last_timestamp = frame->timestamp();
const VideoFrameMetadata* metadata = frame->metadata();
- base::TimeTicks capture_begin_time;
- EXPECT_TRUE(metadata->GetTimeTicks(VideoFrameMetadata::CAPTURE_BEGIN_TIME,
- &capture_begin_time));
- EXPECT_EQ(expected_capture_begin_time, capture_begin_time);
- base::TimeTicks capture_end_time;
- EXPECT_TRUE(metadata->GetTimeTicks(VideoFrameMetadata::CAPTURE_END_TIME,
- &capture_end_time));
- EXPECT_EQ(expected_capture_end_time, capture_end_time);
+ EXPECT_EQ(expected_capture_begin_time, *metadata->capture_begin_time);
+ EXPECT_EQ(expected_capture_end_time, *metadata->capture_end_time);
EXPECT_EQ(gfx::ColorSpace::CreateREC709(), frame->ColorSpace());
- EXPECT_TRUE(metadata->HasKey(VideoFrameMetadata::FRAME_DURATION));
- // FRAME_DURATION is an estimate computed by the VideoCaptureOracle, so it
+ // frame_duration is an estimate computed by the VideoCaptureOracle, so it
// its exact value is not being checked here.
- double frame_rate = 0.0;
- EXPECT_TRUE(
- metadata->GetDouble(VideoFrameMetadata::FRAME_RATE, &frame_rate));
- EXPECT_NEAR(media::limits::kMaxFramesPerSecond, frame_rate, 0.001);
- base::TimeTicks reference_time;
- EXPECT_TRUE(metadata->GetTimeTicks(VideoFrameMetadata::REFERENCE_TIME,
- &reference_time));
- EXPECT_EQ(expected_reference_time, reference_time);
+ EXPECT_TRUE(metadata->frame_duration.has_value());
+ EXPECT_NEAR(media::limits::kMaxFramesPerSecond, *metadata->frame_rate,
+ 0.001);
+ EXPECT_EQ(expected_reference_time, *metadata->reference_time);
// Notify the capturer that the consumer is done with the frame.
consumer.SendDoneNotification(i);
@@ -1150,14 +1148,10 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {
EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
{
auto received_frame = consumer.TakeFrame(cur_frame_index);
- gfx::Rect received_update_rect;
- int received_capture_counter = 0;
- ASSERT_TRUE(received_frame->metadata()->GetInteger(
- media::VideoFrameMetadata::CAPTURE_COUNTER, &received_capture_counter));
- ASSERT_TRUE(received_frame->metadata()->GetRect(
- media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, &received_update_rect));
- EXPECT_EQ(gfx::Rect(size_set().capture_size), received_update_rect);
- previous_capture_counter_received = received_capture_counter;
+ EXPECT_EQ(gfx::Rect(size_set().capture_size),
+ received_frame->metadata()->capture_update_rect);
+ previous_capture_counter_received =
+ *received_frame->metadata()->capture_counter;
}
consumer.SendDoneNotification(cur_frame_index);
@@ -1184,13 +1178,9 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {
EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
{
auto received_frame = consumer.TakeFrame(++cur_frame_index);
- int received_capture_counter = 0;
- gfx::Rect received_update_rect;
- ASSERT_TRUE(received_frame->metadata()->GetInteger(
- media::VideoFrameMetadata::CAPTURE_COUNTER, &received_capture_counter));
- ASSERT_TRUE(received_frame->metadata()->GetRect(
- media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, &received_update_rect));
- EXPECT_EQ(expected_frame_update_rect, received_update_rect);
+ int received_capture_counter = *received_frame->metadata()->capture_counter;
+ EXPECT_EQ(expected_frame_update_rect,
+ *received_frame->metadata()->capture_update_rect);
EXPECT_EQ(previous_capture_counter_received + 1, received_capture_counter);
previous_capture_counter_received = received_capture_counter;
}
@@ -1206,13 +1196,8 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {
EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
{
auto received_frame = consumer.TakeFrame(++cur_frame_index);
- int received_capture_counter = 0;
- gfx::Rect received_update_rect;
- ASSERT_TRUE(received_frame->metadata()->GetInteger(
- media::VideoFrameMetadata::CAPTURE_COUNTER, &received_capture_counter));
- ASSERT_TRUE(received_frame->metadata()->GetRect(
- media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, &received_update_rect));
- EXPECT_TRUE(received_update_rect.IsEmpty());
+ int received_capture_counter = *received_frame->metadata()->capture_counter;
+ EXPECT_TRUE(received_frame->metadata()->capture_update_rect->IsEmpty());
EXPECT_EQ(previous_capture_counter_received + 1, received_capture_counter);
previous_capture_counter_received = received_capture_counter;
}
@@ -1229,13 +1214,9 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {
EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
{
auto received_frame = consumer.TakeFrame(++cur_frame_index);
- int received_capture_counter = 0;
- gfx::Rect received_update_rect;
- ASSERT_TRUE(received_frame->metadata()->GetInteger(
- media::VideoFrameMetadata::CAPTURE_COUNTER, &received_capture_counter));
- ASSERT_TRUE(received_frame->metadata()->GetRect(
- media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, &received_update_rect));
- EXPECT_EQ(gfx::Rect(size_set().capture_size), received_update_rect);
+ int received_capture_counter = *received_frame->metadata()->capture_counter;
+ EXPECT_EQ(gfx::Rect(size_set().capture_size),
+ *received_frame->metadata()->capture_update_rect);
EXPECT_EQ(previous_capture_counter_received + 1, received_capture_counter);
previous_capture_counter_received = received_capture_counter;
}
@@ -1252,13 +1233,9 @@ TEST_F(FrameSinkVideoCapturerTest, DeliversUpdateRectAndCaptureCounter) {
EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
{
auto received_frame = consumer.TakeFrame(++cur_frame_index);
- int received_capture_counter = 0;
- gfx::Rect received_update_rect;
- ASSERT_TRUE(received_frame->metadata()->GetInteger(
- media::VideoFrameMetadata::CAPTURE_COUNTER, &received_capture_counter));
- ASSERT_TRUE(received_frame->metadata()->GetRect(
- media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, &received_update_rect));
- EXPECT_EQ(gfx::Rect(size_set().capture_size), received_update_rect);
+ int received_capture_counter = *received_frame->metadata()->capture_counter;
+ EXPECT_EQ(gfx::Rect(size_set().capture_size),
+ *received_frame->metadata()->capture_update_rect);
EXPECT_EQ(previous_capture_counter_received + 1, received_capture_counter);
previous_capture_counter_received = received_capture_counter;
}
@@ -1286,14 +1263,10 @@ TEST_F(FrameSinkVideoCapturerTest, CaptureCounterSkipsWhenFramesAreDropped) {
EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
{
auto received_frame = consumer.TakeFrame(cur_receive_frame_index);
- int received_capture_counter = 0;
- gfx::Rect received_update_rect;
- ASSERT_TRUE(received_frame->metadata()->GetInteger(
- media::VideoFrameMetadata::CAPTURE_COUNTER, &received_capture_counter));
- ASSERT_TRUE(received_frame->metadata()->GetRect(
- media::VideoFrameMetadata::CAPTURE_UPDATE_RECT, &received_update_rect));
- EXPECT_EQ(gfx::Rect(size_set().capture_size), received_update_rect);
- previous_capture_counter_received = received_capture_counter;
+ EXPECT_EQ(gfx::Rect(size_set().capture_size),
+ *received_frame->metadata()->capture_update_rect);
+ previous_capture_counter_received =
+ *received_frame->metadata()->capture_counter;
}
consumer.SendDoneNotification(cur_receive_frame_index);
@@ -1318,10 +1291,8 @@ TEST_F(FrameSinkVideoCapturerTest, CaptureCounterSkipsWhenFramesAreDropped) {
EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
{
auto received_frame = consumer.TakeFrame(++cur_receive_frame_index);
- int received_capture_counter = 0;
- ASSERT_TRUE(received_frame->metadata()->GetInteger(
- media::VideoFrameMetadata::CAPTURE_COUNTER, &received_capture_counter));
- EXPECT_NE(previous_capture_counter_received + 1, received_capture_counter);
+ EXPECT_NE(previous_capture_counter_received + 1,
+ *received_frame->metadata()->capture_counter);
}
StopCapture();
}
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
index 04d16521310..419d97d9f39 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/logging.h"
using media::VideoFrame;
using media::VideoPixelFormat;
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.cc b/chromium/components/viz/service/gl/gpu_service_impl.cc
index df961f12be1..98cdbff9bf0 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl.cc
@@ -405,6 +405,13 @@ GpuServiceImpl::GpuServiceImpl(
}
#endif
+#if defined(OS_WIN)
+ auto info_callback = base::BindRepeating(
+ &GpuServiceImpl::UpdateOverlayAndHDRInfo, weak_ptr_factory_.GetWeakPtr());
+ gl::DirectCompositionSurfaceWin::SetOverlayHDRGpuInfoUpdateCallback(
+ info_callback);
+#endif
+
gpu_memory_buffer_factory_ =
gpu::GpuMemoryBufferFactory::CreateNativeType(vulkan_context_provider());
@@ -768,12 +775,12 @@ void GpuServiceImpl::RequestHDRStatus(RequestHDRStatusCallback callback) {
void GpuServiceImpl::RequestHDRStatusOnMainThread(
RequestHDRStatusCallback callback) {
DCHECK(main_runner_->BelongsToCurrentThread());
- bool hdr_enabled = false;
+
#if defined(OS_WIN)
- hdr_enabled = gl::DirectCompositionSurfaceWin::IsHDRSupported();
+ hdr_enabled_ = gl::DirectCompositionSurfaceWin::IsHDRSupported();
#endif
io_runner_->PostTask(FROM_HERE,
- base::BindOnce(std::move(callback), hdr_enabled));
+ base::BindOnce(std::move(callback), hdr_enabled_));
}
void GpuServiceImpl::RegisterDisplayContext(
@@ -837,6 +844,10 @@ 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,
@@ -968,12 +979,6 @@ void GpuServiceImpl::DisplayAdded() {
if (!in_host_process())
ui::GpuSwitchingManager::GetInstance()->NotifyDisplayAdded();
-
-#if defined(OS_WIN)
- // 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.
- UpdateOverlayInfo();
-#endif
}
void GpuServiceImpl::DisplayRemoved() {
@@ -986,12 +991,6 @@ void GpuServiceImpl::DisplayRemoved() {
if (!in_host_process())
ui::GpuSwitchingManager::GetInstance()->NotifyDisplayRemoved();
-
-#if defined(OS_WIN)
- // 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.
- UpdateOverlayInfo();
-#endif
}
void GpuServiceImpl::DestroyAllChannels() {
@@ -1141,12 +1140,20 @@ gpu::Scheduler* GpuServiceImpl::GetGpuScheduler() {
}
#if defined(OS_WIN)
-void GpuServiceImpl::UpdateOverlayInfo() {
+void GpuServiceImpl::UpdateOverlayAndHDRInfo() {
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);
+
+ // 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_);
}
#endif
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.h b/chromium/components/viz/service/gl/gpu_service_impl.h
index 018be6ac2cb..90d68b30ce3 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.h
+++ b/chromium/components/viz/service/gl/gpu_service_impl.h
@@ -210,6 +210,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
const GURL& active_url) override;
#if defined(OS_WIN)
void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
+ void DidUpdateHDRStatus(bool hdr_enabled) override;
#endif
void StoreShaderToDisk(int client_id,
const std::string& key,
@@ -342,10 +343,10 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
// process. If |for_context_loss| is true an error message will be logged.
void MaybeExit(bool for_context_loss);
- // Update overlay info on the GPU process and send the updated info back
- // to the browser process if there is a change.
+ // 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 defined(OS_WIN)
- void UpdateOverlayInfo();
+ void UpdateOverlayAndHDRInfo();
#endif
scoped_refptr<base::SingleThreadTaskRunner> main_runner_;
@@ -363,6 +364,8 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
// Information about general chrome feature support for the GPU.
gpu::GpuFeatureInfo gpu_feature_info_;
+ bool hdr_enabled_ = false;
+
// What we would have gotten if we haven't fallen back to SwiftShader or
// pure software (in the viz case).
base::Optional<gpu::GPUInfo> gpu_info_for_hardware_gpu_;
diff --git a/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc b/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc
index ef5bf16f6bd..f72d981d39c 100644
--- a/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc
+++ b/chromium/components/viz/service/gl/info_collection_gpu_service_impl.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/gl/info_collection_gpu_service_impl.h"
+#include <utility>
#include "base/task/post_task.h"
#include "base/task_runner_util.h"
#include "gpu/config/dx_diag_node.h"
@@ -15,10 +16,12 @@ InfoCollectionGpuServiceImpl::InfoCollectionGpuServiceImpl(
scoped_refptr<base::SingleThreadTaskRunner> main_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
const gpu::DevicePerfInfo& device_perf_info,
+ const gpu::GPUInfo::GPUDevice& gpu_device,
mojo::PendingReceiver<mojom::InfoCollectionGpuService> pending_receiver)
: main_runner_(std::move(main_runner)),
io_runner_(std::move(io_runner)),
- device_perf_info_(device_perf_info) {
+ device_perf_info_(device_perf_info),
+ gpu_device_(gpu_device) {
DCHECK(!io_runner_->BelongsToCurrentThread());
DCHECK(main_runner_->BelongsToCurrentThread());
@@ -41,29 +44,48 @@ void InfoCollectionGpuServiceImpl::BindOnIO(
receiver_.Bind(std::move(pending_receiver));
}
-void InfoCollectionGpuServiceImpl::
- GetGpuSupportedRuntimeVersionAndDevicePerfInfo(
- GetGpuSupportedRuntimeVersionAndDevicePerfInfoCallback callback) {
+void InfoCollectionGpuServiceImpl::GetGpuSupportedDx12VersionAndDevicePerfInfo(
+ GetGpuSupportedDx12VersionAndDevicePerfInfoCallback callback) {
DCHECK(io_runner_->BelongsToCurrentThread());
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&InfoCollectionGpuServiceImpl::
- GetGpuSupportedRuntimeVersionAndDevicePerfInfoOnMain,
+ GetGpuSupportedDx12VersionAndDevicePerfInfoOnMain,
base::Unretained(this), std::move(callback)));
}
void InfoCollectionGpuServiceImpl::
- GetGpuSupportedRuntimeVersionAndDevicePerfInfoOnMain(
- GetGpuSupportedRuntimeVersionAndDevicePerfInfoCallback callback) {
+ GetGpuSupportedDx12VersionAndDevicePerfInfoOnMain(
+ GetGpuSupportedDx12VersionAndDevicePerfInfoCallback callback) {
DCHECK(main_runner_->BelongsToCurrentThread());
- gpu::Dx12VulkanVersionInfo dx12_vulkan_version_info;
- gpu::RecordGpuSupportedRuntimeVersionHistograms(&dx12_vulkan_version_info);
+ uint32_t d3d12_feature_level = gpu::GetGpuSupportedD3D12Version();
+ gpu::RecordGpuSupportedDx12VersionHistograms(d3d12_feature_level);
- io_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), dx12_vulkan_version_info,
- device_perf_info_));
+ io_runner_->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), d3d12_feature_level,
+ device_perf_info_));
+}
+
+void InfoCollectionGpuServiceImpl::GetGpuSupportedVulkanVersionInfo(
+ GetGpuSupportedVulkanVersionInfoCallback callback) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+
+ main_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &InfoCollectionGpuServiceImpl::GetGpuSupportedVulkanVersionInfoOnMain,
+ base::Unretained(this), std::move(callback)));
+}
+
+void InfoCollectionGpuServiceImpl::GetGpuSupportedVulkanVersionInfoOnMain(
+ GetGpuSupportedVulkanVersionInfoCallback callback) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+
+ uint32_t vulkan_version = gpu::GetGpuSupportedVulkanVersion(gpu_device_);
+ io_runner_->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), vulkan_version));
}
void InfoCollectionGpuServiceImpl::RequestDxDiagNodeInfo(
diff --git a/chromium/components/viz/service/gl/info_collection_gpu_service_impl.h b/chromium/components/viz/service/gl/info_collection_gpu_service_impl.h
index 82fbd8a190c..52800cabd5a 100644
--- a/chromium/components/viz/service/gl/info_collection_gpu_service_impl.h
+++ b/chromium/components/viz/service/gl/info_collection_gpu_service_impl.h
@@ -28,14 +28,18 @@ class VIZ_SERVICE_EXPORT InfoCollectionGpuServiceImpl
scoped_refptr<base::SingleThreadTaskRunner> main_runner,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
const gpu::DevicePerfInfo& device_perf_info,
+ const gpu::GPUInfo::GPUDevice& gpu_device,
mojo::PendingReceiver<mojom::InfoCollectionGpuService> pending_receiver);
~InfoCollectionGpuServiceImpl() override;
void RequestDxDiagNodeInfo(RequestDxDiagNodeInfoCallback callback) override;
- void GetGpuSupportedRuntimeVersionAndDevicePerfInfo(
- GetGpuSupportedRuntimeVersionAndDevicePerfInfoCallback callback) override;
+ void GetGpuSupportedDx12VersionAndDevicePerfInfo(
+ GetGpuSupportedDx12VersionAndDevicePerfInfoCallback callback) override;
+
+ void GetGpuSupportedVulkanVersionInfo(
+ GetGpuSupportedVulkanVersionInfoCallback callback) override;
private:
void BindOnIO(
@@ -43,8 +47,11 @@ class VIZ_SERVICE_EXPORT InfoCollectionGpuServiceImpl
void RequestDxDiagNodeInfoOnMain(RequestDxDiagNodeInfoCallback callback);
- void GetGpuSupportedRuntimeVersionAndDevicePerfInfoOnMain(
- GetGpuSupportedRuntimeVersionAndDevicePerfInfoCallback callback);
+ void GetGpuSupportedDx12VersionAndDevicePerfInfoOnMain(
+ GetGpuSupportedDx12VersionAndDevicePerfInfoCallback callback);
+
+ void GetGpuSupportedVulkanVersionInfoOnMain(
+ GetGpuSupportedVulkanVersionInfoCallback callback);
scoped_refptr<base::SingleThreadTaskRunner> main_runner_;
scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
@@ -53,6 +60,10 @@ class VIZ_SERVICE_EXPORT InfoCollectionGpuServiceImpl
// unsandboxed GPU process.
const gpu::DevicePerfInfo device_perf_info_;
+ // The GPU ids and the driver version that was passed down from the browser
+ // process
+ const gpu::GPUInfo::GPUDevice gpu_device_;
+
// Should only be accessed on the IO thread after creation.
mojo::Receiver<mojom::InfoCollectionGpuService> receiver_{this};
diff --git a/chromium/components/viz/service/main/viz_main_impl.cc b/chromium/components/viz/service/main/viz_main_impl.cc
index 13c8e2a1482..f74b6cd4ea8 100644
--- a/chromium/components/viz/service/main/viz_main_impl.cc
+++ b/chromium/components/viz/service/main/viz_main_impl.cc
@@ -199,7 +199,8 @@ void VizMainImpl::CreateInfoCollectionGpuService(
info_collection_gpu_service_ = std::make_unique<InfoCollectionGpuServiceImpl>(
gpu_thread_task_runner_, io_task_runner(),
- gpu_init_->device_perf_info().value(), std::move(pending_receiver));
+ gpu_init_->device_perf_info().value(), gpu_init_->gpu_info().active_gpu(),
+ std::move(pending_receiver));
}
#endif
diff --git a/chromium/components/viz/service/surfaces/surface_manager.h b/chromium/components/viz/service/surfaces/surface_manager.h
index 75a7c60158c..a2a774769f7 100644
--- a/chromium/components/viz/service/surfaces/surface_manager.h
+++ b/chromium/components/viz/service/surfaces/surface_manager.h
@@ -12,9 +12,9 @@
#include <unordered_set>
#include <vector>
+#include "base/check_op.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
diff --git a/chromium/components/viz/service/surfaces/surface_unittest.cc b/chromium/components/viz/service/surfaces/surface_unittest.cc
index 1054b5fa130..0ccffb3ffac 100644
--- a/chromium/components/viz/service/surfaces/surface_unittest.cc
+++ b/chromium/components/viz/service/surfaces/surface_unittest.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/surfaces/surface.h"
#include "base/bind.h"
+#include "base/run_loop.h"
#include "cc/test/scheduler_test_common.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
@@ -76,8 +77,10 @@ TEST(SurfaceTest, SurfaceIds) {
}
void TestCopyResultCallback(bool* called,
+ base::OnceClosure finished,
std::unique_ptr<CopyOutputResult> result) {
*called = true;
+ std::move(finished).Run();
}
// Test that CopyOutputRequests can outlive the current frame and be
@@ -94,14 +97,16 @@ TEST(SurfaceTest, CopyRequestLifetime) {
CompositorFrame frame = MakeDefaultCompositorFrame();
support->SubmitCompositorFrame(local_surface_id, std::move(frame));
Surface* surface = surface_manager->GetSurfaceForId(surface_id);
- ASSERT_TRUE(!!surface);
+ ASSERT_TRUE(surface);
bool copy_called = false;
+ base::RunLoop copy_runloop;
support->RequestCopyOfOutput(
local_surface_id,
std::make_unique<CopyOutputRequest>(
CopyOutputRequest::ResultFormat::RGBA_BITMAP,
- base::BindOnce(&TestCopyResultCallback, &copy_called)));
+ base::BindOnce(&TestCopyResultCallback, &copy_called,
+ copy_runloop.QuitClosure())));
surface->TakeCopyOutputRequestsFromClient();
EXPECT_TRUE(surface_manager->GetSurfaceForId(surface_id));
EXPECT_FALSE(copy_called);
@@ -135,6 +140,7 @@ TEST(SurfaceTest, CopyRequestLifetime) {
ASSERT_EQ(1u, copy_requests.count(last_pass_id));
EXPECT_FALSE(copy_called);
copy_requests.clear(); // Deleted requests will auto-send an empty result.
+ copy_runloop.Run();
EXPECT_TRUE(copy_called);
}
diff --git a/chromium/components/viz/viz.gni b/chromium/components/viz/viz.gni
index 89ee3c3f1f8..5f9f5501430 100644
--- a/chromium/components/viz/viz.gni
+++ b/chromium/components/viz/viz.gni
@@ -8,7 +8,7 @@ import("//testing/test.gni")
viz_remove_configs = []
viz_add_configs = [ "//build/config:precompiled_headers" ]
-if (!is_debug && (is_win || is_android)) {
+if (!is_debug) {
viz_remove_configs += [ "//build/config/compiler:default_optimization" ]
viz_add_configs += [ "//build/config/compiler:optimize_max" ]
}