diff options
Diffstat (limited to 'chromium/components/viz/service')
144 files changed, 9087 insertions, 3158 deletions
diff --git a/chromium/components/viz/service/BUILD.gn b/chromium/components/viz/service/BUILD.gn index 154fb88b827..cfec9fbec12 100644 --- a/chromium/components/viz/service/BUILD.gn +++ b/chromium/components/viz/service/BUILD.gn @@ -27,6 +27,8 @@ viz_component("service") { "display/display.cc", "display/display.h", "display/display_client.h", + "display/display_resource_provider.cc", + "display/display_resource_provider.h", "display/display_scheduler.cc", "display/display_scheduler.h", "display/draw_polygon.cc", @@ -48,6 +50,8 @@ viz_component("service") { "display/output_surface_client.h", "display/output_surface_frame.cc", "display/output_surface_frame.h", + "display/overlay_candidate.cc", + "display/overlay_candidate.h", "display/overlay_candidate_validator.h", "display/overlay_processor.cc", "display/overlay_processor.h", @@ -69,6 +73,8 @@ viz_component("service") { "display/scoped_render_pass_texture.h", "display/shader.cc", "display/shader.h", + "display/skia_output_surface.cc", + "display/skia_output_surface.h", "display/skia_renderer.cc", "display/skia_renderer.h", "display/software_output_device.cc", @@ -101,10 +107,14 @@ viz_component("service") { "display_embedder/in_process_gpu_memory_buffer_manager.h", "display_embedder/server_shared_bitmap_manager.cc", "display_embedder/server_shared_bitmap_manager.h", - "display_embedder/shared_bitmap_allocation_notifier_impl.cc", - "display_embedder/shared_bitmap_allocation_notifier_impl.h", + "display_embedder/skia_output_surface_impl.cc", + "display_embedder/skia_output_surface_impl.h", + "display_embedder/skia_output_surface_impl_on_gpu.cc", + "display_embedder/skia_output_surface_impl_on_gpu.h", "display_embedder/software_output_surface.cc", "display_embedder/software_output_surface.h", + "display_embedder/viz_process_context_provider.cc", + "display_embedder/viz_process_context_provider.h", "frame_sinks/compositor_frame_sink_impl.cc", "frame_sinks/compositor_frame_sink_impl.h", "frame_sinks/compositor_frame_sink_support.cc", @@ -168,12 +178,16 @@ viz_component("service") { "//cc/paint", "//components/crash/core/common:crash_key", "//components/viz/common", + "//gpu/command_buffer/client:gles2_implementation", + "//gpu/command_buffer/client:raster", + "//gpu/command_buffer/service:gles2", "//gpu/ipc:gl_in_process_context", # Note that dependency on //gpu/ipc/client is for GpuMemoryBufferImpl. This # dependency should not be in public_deps. "//gpu/ipc/client", "//gpu/ipc/service", + "//gpu/skia_bindings:skia_bindings", "//gpu/vulkan:buildflags", "//media", "//media/capture:capture_lib", @@ -249,6 +263,8 @@ viz_component("service") { "display_embedder/compositor_overlay_candidate_validator_win.h", "display_embedder/gl_output_surface_win.cc", "display_embedder/gl_output_surface_win.h", + "display_embedder/output_device_backing.cc", + "display_embedder/output_device_backing.h", "display_embedder/software_output_device_win.cc", "display_embedder/software_output_device_win.h", ] @@ -264,6 +280,7 @@ viz_source_set("unit_tests") { sources = [ "display/bsp_tree_unittest.cc", "display/copy_output_scaling_pixeltest.cc", + "display/display_resource_provider_unittest.cc", "display/display_scheduler_unittest.cc", "display/display_unittest.cc", "display/draw_polygon_unittest.cc", @@ -343,6 +360,10 @@ viz_source_set("unit_tests") { sources += [ "display_embedder/software_output_device_mac_unittest.mm" ] libs = [ "IOSurface.framework" ] } + + if (is_win) { + sources += [ "display_embedder/output_device_backing_unittest.cc" ] + } } viz_source_set("perf_tests") { diff --git a/chromium/components/viz/service/display/DEPS b/chromium/components/viz/service/display/DEPS index 314ebb3a28c..3560a35a10b 100644 --- a/chromium/components/viz/service/display/DEPS +++ b/chromium/components/viz/service/display/DEPS @@ -19,6 +19,7 @@ include_rules = [ "+ui/latency", "+ui/gl/ca_renderer_layer_params.h", "+ui/gl/dc_renderer_layer_params.h", + "+ui/gl/trace_util.h", ] specific_include_rules = { diff --git a/chromium/components/viz/service/display/bsp_tree_perftest.cc b/chromium/components/viz/service/display/bsp_tree_perftest.cc index 76ea2e10eff..93df78fa388 100644 --- a/chromium/components/viz/service/display/bsp_tree_perftest.cc +++ b/chromium/components/viz/service/display/bsp_tree_perftest.cc @@ -59,7 +59,7 @@ class BspTreePerfTest : public cc::LayerTreeTest { void ReadTestFile(const std::string& name) { base::FilePath test_data_dir; - ASSERT_TRUE(PathService::Get(Paths::DIR_TEST_DATA, &test_data_dir)); + ASSERT_TRUE(base::PathService::Get(Paths::DIR_TEST_DATA, &test_data_dir)); base::FilePath json_file = test_data_dir.AppendASCII(name + ".json"); ASSERT_TRUE(base::ReadFileToString(json_file, &json_)); } diff --git a/chromium/components/viz/service/display/ca_layer_overlay.cc b/chromium/components/viz/service/display/ca_layer_overlay.cc index eb6c8aa9982..284ccf3a565 100644 --- a/chromium/components/viz/service/display/ca_layer_overlay.cc +++ b/chromium/components/viz/service/display/ca_layer_overlay.cc @@ -7,12 +7,12 @@ #include <algorithm> #include "base/metrics/histogram_macros.h" -#include "cc/resources/display_resource_provider.h" #include "components/viz/common/quads/render_pass_draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/stream_video_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/quads/tile_draw_quad.h" +#include "components/viz/service/display/display_resource_provider.h" #include "gpu/GLES2/gl2extchromium.h" namespace viz { @@ -75,7 +75,7 @@ bool FilterOperationSupported(const cc::FilterOperation& operation) { } CALayerResult FromRenderPassQuad( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const RenderPassDrawQuad* quad, const base::flat_map<RenderPassId, cc::FilterOperations*>& render_pass_filters, @@ -104,10 +104,9 @@ CALayerResult FromRenderPassQuad( return CA_LAYER_SUCCESS; } -CALayerResult FromStreamVideoQuad( - cc::DisplayResourceProvider* resource_provider, - const StreamVideoDrawQuad* quad, - CALayerOverlay* ca_layer_overlay) { +CALayerResult FromStreamVideoQuad(DisplayResourceProvider* resource_provider, + const StreamVideoDrawQuad* quad, + CALayerOverlay* ca_layer_overlay) { unsigned resource_id = quad->resource_id(); if (!resource_provider->IsOverlayCandidate(resource_id)) return CA_LAYER_FAILED_STREAM_VIDEO_NOT_CANDIDATE; @@ -132,7 +131,7 @@ CALayerResult FromSolidColorDrawQuad(const SolidColorDrawQuad* quad, return CA_LAYER_SUCCESS; } -CALayerResult FromTextureQuad(cc::DisplayResourceProvider* resource_provider, +CALayerResult FromTextureQuad(DisplayResourceProvider* resource_provider, const TextureDrawQuad* quad, CALayerOverlay* ca_layer_overlay) { unsigned resource_id = quad->resource_id(); @@ -160,7 +159,7 @@ CALayerResult FromTextureQuad(cc::DisplayResourceProvider* resource_provider, return CA_LAYER_SUCCESS; } -CALayerResult FromTileQuad(cc::DisplayResourceProvider* resource_provider, +CALayerResult FromTileQuad(DisplayResourceProvider* resource_provider, const TileDrawQuad* quad, CALayerOverlay* ca_layer_overlay) { unsigned resource_id = quad->resource_id(); @@ -177,7 +176,7 @@ CALayerResult FromTileQuad(cc::DisplayResourceProvider* resource_provider, class CALayerOverlayProcessor { public: CALayerResult FromDrawQuad( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, const DrawQuad* quad, const base::flat_map<RenderPassId, cc::FilterOperations*>& @@ -277,7 +276,7 @@ CALayerOverlay::CALayerOverlay(const CALayerOverlay& other) = default; CALayerOverlay::~CALayerOverlay() {} bool ProcessForCALayerOverlays( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, const QuadList& quad_list, const base::flat_map<RenderPassId, cc::FilterOperations*>& diff --git a/chromium/components/viz/service/display/ca_layer_overlay.h b/chromium/components/viz/service/display/ca_layer_overlay.h index 248fbeeebd3..ac52d0eb783 100644 --- a/chromium/components/viz/service/display/ca_layer_overlay.h +++ b/chromium/components/viz/service/display/ca_layer_overlay.h @@ -14,11 +14,8 @@ #include "ui/gfx/geometry/rect_f.h" #include "ui/gl/ca_renderer_layer_params.h" -namespace cc { -class DisplayResourceProvider; -} - namespace viz { +class DisplayResourceProvider; class DrawQuad; class RenderPassDrawQuad; @@ -77,7 +74,7 @@ typedef std::vector<CALayerOverlay> CALayerOverlayList; // Returns true if all quads in the root render pass have been replaced by // CALayerOverlays. bool ProcessForCALayerOverlays( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, const QuadList& quad_list, const base::flat_map<RenderPassId, cc::FilterOperations*>& diff --git a/chromium/components/viz/service/display/dc_layer_overlay.cc b/chromium/components/viz/service/display/dc_layer_overlay.cc index 592eb099581..288b1703c71 100644 --- a/chromium/components/viz/service/display/dc_layer_overlay.cc +++ b/chromium/components/viz/service/display/dc_layer_overlay.cc @@ -6,10 +6,10 @@ #include "base/metrics/histogram_macros.h" #include "cc/base/math_util.h" -#include "cc/resources/display_resource_provider.h" #include "components/viz/common/quads/render_pass_draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/yuv_video_draw_quad.h" +#include "components/viz/service/display/display_resource_provider.h" #include "gpu/GLES2/gl2extchromium.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gl/gl_switches.h" @@ -19,18 +19,19 @@ namespace viz { namespace { DCLayerOverlayProcessor::DCLayerResult FromYUVQuad( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const YUVVideoDrawQuad* quad, - DCLayerOverlay* ca_layer_overlay) { + DCLayerOverlay* dc_layer_overlay) { for (const auto& resource : quad->resources) { if (!resource_provider->IsOverlayCandidate(resource)) return DCLayerOverlayProcessor::DC_LAYER_FAILED_TEXTURE_NOT_CANDIDATE; } - ca_layer_overlay->resources = quad->resources; - ca_layer_overlay->contents_rect = quad->ya_tex_coord_rect; - ca_layer_overlay->filter = GL_LINEAR; - ca_layer_overlay->color_space = quad->video_color_space; - ca_layer_overlay->require_overlay = quad->require_overlay; + dc_layer_overlay->resources = quad->resources; + dc_layer_overlay->contents_rect = quad->ya_tex_coord_rect; + dc_layer_overlay->filter = GL_LINEAR; + dc_layer_overlay->color_space = quad->video_color_space; + dc_layer_overlay->require_overlay = quad->require_overlay; + dc_layer_overlay->is_protected_video = quad->is_protected_video; return DCLayerOverlayProcessor::DC_LAYER_SUCCESS; } @@ -90,11 +91,11 @@ DCLayerOverlayProcessor::DCLayerOverlayProcessor() = default; DCLayerOverlayProcessor::~DCLayerOverlayProcessor() = default; DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, QuadList::ConstIterator quad_list_begin, QuadList::ConstIterator quad, - DCLayerOverlay* ca_layer_overlay) { + DCLayerOverlay* dc_layer_overlay) { if (quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver) return DC_LAYER_FAILED_QUAD_BLEND_MODE; @@ -103,7 +104,7 @@ DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad( case DrawQuad::YUV_VIDEO_CONTENT: result = FromYUVQuad(resource_provider, YUVVideoDrawQuad::MaterialCast(*quad), - ca_layer_overlay); + dc_layer_overlay); break; default: return DC_LAYER_FAILED_UNSUPPORTED_QUAD; @@ -123,19 +124,19 @@ DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad( overlay_shared_state->transform = quad->shared_quad_state->quad_to_target_transform.matrix(); - ca_layer_overlay->shared_state = overlay_shared_state; - ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect); + dc_layer_overlay->shared_state = overlay_shared_state; + dc_layer_overlay->bounds_rect = gfx::RectF(quad->rect); return result; } void DCLayerOverlayProcessor::Process( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, RenderPassList* render_passes, gfx::Rect* overlay_damage_rect, gfx::Rect* damage_rect, - DCLayerOverlayList* ca_layer_overlays) { + DCLayerOverlayList* dc_layer_overlays) { DCHECK(pass_info_.empty()); processed_overlay_in_frame_ = false; if (base::FeatureList::IsEnabled( @@ -145,12 +146,12 @@ void DCLayerOverlayProcessor::Process( ProcessRenderPass(resource_provider, display_rect, pass.get(), is_root, overlay_damage_rect, is_root ? damage_rect : &pass->damage_rect, - ca_layer_overlays); + dc_layer_overlays); } } else { ProcessRenderPass(resource_provider, display_rect, render_passes->back().get(), true, overlay_damage_rect, - damage_rect, ca_layer_overlays); + damage_rect, dc_layer_overlays); } pass_info_.clear(); } @@ -218,13 +219,13 @@ QuadList::Iterator DCLayerOverlayProcessor::ProcessRenderPassDrawQuad( } void DCLayerOverlayProcessor::ProcessRenderPass( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, RenderPass* render_pass, bool is_root, gfx::Rect* overlay_damage_rect, gfx::Rect* damage_rect, - DCLayerOverlayList* ca_layer_overlays) { + DCLayerOverlayList* dc_layer_overlays) { gfx::Rect this_frame_underlay_rect; QuadList* quad_list = &render_pass->quad_list; @@ -286,7 +287,7 @@ void DCLayerOverlayProcessor::ProcessRenderPass( overlay_damage_rect->Union(rect_in_root); RecordDCLayerResult(DC_LAYER_SUCCESS); - ca_layer_overlays->push_back(dc_layer); + dc_layer_overlays->push_back(dc_layer); if (!base::FeatureList::IsEnabled( features::kDirectCompositionNonrootOverlays)) { // Only allow one overlay for now. diff --git a/chromium/components/viz/service/display/dc_layer_overlay.h b/chromium/components/viz/service/display/dc_layer_overlay.h index 280b8dfe2ff..34d118dccd0 100644 --- a/chromium/components/viz/service/display/dc_layer_overlay.h +++ b/chromium/components/viz/service/display/dc_layer_overlay.h @@ -14,11 +14,8 @@ #include "ui/gfx/geometry/rect_f.h" #include "ui/gl/dc_renderer_layer_params.h" -namespace cc { -class DisplayResourceProvider; -} - namespace viz { +class DisplayResourceProvider; class VIZ_SERVICE_EXPORT DCLayerOverlaySharedState : public base::RefCounted<DCLayerOverlaySharedState> { @@ -71,6 +68,7 @@ class VIZ_SERVICE_EXPORT DCLayerOverlay { gfx::ColorSpace color_space; bool require_overlay = false; + bool is_protected_video = false; }; typedef std::vector<DCLayerOverlay> DCLayerOverlayList; @@ -96,7 +94,7 @@ class DCLayerOverlayProcessor { DCLayerOverlayProcessor(); ~DCLayerOverlayProcessor(); - void Process(cc::DisplayResourceProvider* resource_provider, + void Process(DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, RenderPassList* render_passes, gfx::Rect* overlay_damage_rect, @@ -108,7 +106,7 @@ class DCLayerOverlayProcessor { } private: - DCLayerResult FromDrawQuad(cc::DisplayResourceProvider* resource_provider, + DCLayerResult FromDrawQuad(DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, QuadList::ConstIterator quad_list_begin, QuadList::ConstIterator quad, @@ -117,7 +115,7 @@ class DCLayerOverlayProcessor { QuadList::Iterator ProcessRenderPassDrawQuad(RenderPass* render_pass, gfx::Rect* damage_rect, QuadList::Iterator it); - void ProcessRenderPass(cc::DisplayResourceProvider* resource_provider, + void ProcessRenderPass(DisplayResourceProvider* resource_provider, const gfx::RectF& display_rect, RenderPass* render_pass, bool is_root, diff --git a/chromium/components/viz/service/display/direct_renderer.cc b/chromium/components/viz/service/display/direct_renderer.cc index 4e6823d2780..2e79ba0f068 100644 --- a/chromium/components/viz/service/display/direct_renderer.cc +++ b/chromium/components/viz/service/display/direct_renderer.cc @@ -80,7 +80,7 @@ DirectRenderer::DrawingFrame::~DrawingFrame() = default; DirectRenderer::DirectRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider) + DisplayResourceProvider* resource_provider) : settings_(settings), output_surface_(output_surface), resource_provider_(resource_provider), @@ -273,7 +273,7 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, // Create the overlay candidate for the output surface, and mark it as // always handled. if (output_surface_->IsDisplayedAsOverlayPlane()) { - cc::OverlayCandidate output_surface_plane; + OverlayCandidate output_surface_plane; output_surface_plane.display_rect = gfx::RectF(device_viewport_size.width(), device_viewport_size.height()); output_surface_plane.resource_size_in_pixels = device_viewport_size; @@ -328,8 +328,23 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order, if (!skip_drawing_root_render_pass && !use_partial_swap_) current_frame()->root_damage_rect = gfx::Rect(device_viewport_size); - if (!skip_drawing_root_render_pass) + if (!skip_drawing_root_render_pass) { DrawRenderPassAndExecuteCopyRequests(root_render_pass); + // Use a fence to synchronize display of the surface overlay. Note that + // gpu_fence_id may have the special value 0 ("no fence") if fences are not + // supported. In that case synchronization will happen through other means + // on the service side. + // TODO(crbug.com/840805): We currently only use fences for root render + // passes but we may also need to use fences for non-root passes in some + // cases (e.g. WebGL canvas). + auto gpu_fence_id = output_surface_->UpdateGpuFence(); + for (auto& overlay : current_frame()->overlay_list) { + if (overlay.use_output_surface_for_resource) { + overlay.gpu_fence_id = gpu_fence_id; + break; + } + } + } FinishDrawingFrame(); render_passes_in_draw_order->clear(); diff --git a/chromium/components/viz/service/display/direct_renderer.h b/chromium/components/viz/service/display/direct_renderer.h index 63be93b71c4..5cf6c6840aa 100644 --- a/chromium/components/viz/service/display/direct_renderer.h +++ b/chromium/components/viz/service/display/direct_renderer.h @@ -12,10 +12,10 @@ #include "base/containers/circular_deque.h" #include "base/containers/flat_map.h" #include "base/macros.h" -#include "cc/resources/display_resource_provider.h" #include "components/viz/common/quads/tile_draw_quad.h" #include "components/viz/service/display/ca_layer_overlay.h" #include "components/viz/service/display/dc_layer_overlay.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/overlay_processor.h" #include "components/viz/service/viz_service_export.h" #include "gpu/command_buffer/common/texture_in_use_response.h" @@ -25,7 +25,6 @@ namespace cc { class FilterOperations; -class OutputSurface; } // namespace cc namespace gfx { @@ -35,6 +34,7 @@ class ColorSpace; namespace viz { class BspWalkActionDrawPolygon; class DrawPolygon; +class OutputSurface; class RendererSettings; class RenderPass; @@ -46,7 +46,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer { public: DirectRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider); + DisplayResourceProvider* resource_provider); virtual ~DirectRenderer(); void Initialize(); @@ -61,7 +61,8 @@ class VIZ_SERVICE_EXPORT DirectRenderer { const gfx::Size& device_viewport_size); // Public interface implemented by subclasses. - virtual void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) = 0; + virtual void SwapBuffers(std::vector<ui::LatencyInfo> latency_info, + bool need_presentation_feedback) = 0; virtual void SwapBuffersComplete() {} virtual void DidReceiveTextureInUseResponses( const gpu::TextureInUseResponses& responses) {} @@ -82,7 +83,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer { gfx::Transform projection_matrix; gfx::Transform window_matrix; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; CALayerOverlayList ca_layer_overlay_list; DCLayerOverlayList dc_layer_overlay_list; }; @@ -201,7 +202,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer { const RendererSettings* const settings_; OutputSurface* const output_surface_; - cc::DisplayResourceProvider* const resource_provider_; + DisplayResourceProvider* const resource_provider_; // This can be replaced by test implementations. std::unique_ptr<OverlayProcessor> overlay_processor_; diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc index ef3b32de61b..178708effd2 100644 --- a/chromium/components/viz/service/display/display.cc +++ b/chromium/components/viz/service/display/display.cc @@ -24,6 +24,7 @@ #include "components/viz/service/display/display_scheduler.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/service/display/output_surface.h" +#include "components/viz/service/display/skia_output_surface.h" #include "components/viz/service/display/skia_renderer.h" #include "components/viz/service/display/software_renderer.h" #include "components/viz/service/display/surface_aggregator.h" @@ -44,10 +45,12 @@ Display::Display( const FrameSinkId& frame_sink_id, std::unique_ptr<OutputSurface> output_surface, std::unique_ptr<DisplayScheduler> scheduler, - scoped_refptr<base::SingleThreadTaskRunner> current_task_runner) + scoped_refptr<base::SingleThreadTaskRunner> current_task_runner, + SkiaOutputSurface* skia_output_surface) : bitmap_manager_(bitmap_manager), settings_(settings), frame_sink_id_(frame_sink_id), + skia_output_surface_(skia_output_surface), output_surface_(std::move(output_surface)), scheduler_(std::move(scheduler)), current_task_runner_(std::move(current_task_runner)) { @@ -58,17 +61,11 @@ Display::Display( } Display::~Display() { - for (auto& callbacks : previous_presented_callbacks_) { - for (auto& callback : callbacks) + for (auto& callback_list : pending_presented_callbacks_) { + for (auto& callback : callback_list) std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0); } - for (auto& callback : active_presented_callbacks_) - std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0); - - for (auto& callback : presented_callbacks_) - std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0); - // Only do this if Initialize() happened. if (client_) { if (auto* context = output_surface_->context_provider()) @@ -95,6 +92,9 @@ void Display::Initialize(DisplayClient* client, surface_manager_->AddObserver(scheduler_.get()); output_surface_->BindToClient(this); + if (output_surface_->software_device()) + output_surface_->software_device()->BindToClient(this); + InitializeRenderer(); // This depends on assumptions that Display::Initialize will happen on the @@ -205,7 +205,7 @@ void Display::SetOutputIsSecure(bool secure) { } void Display::InitializeRenderer() { - resource_provider_ = std::make_unique<cc::DisplayResourceProvider>( + resource_provider_ = std::make_unique<DisplayResourceProvider>( output_surface_->context_provider(), bitmap_manager_); if (output_surface_->context_provider()) { @@ -214,15 +214,15 @@ void Display::InitializeRenderer() { &settings_, output_surface_.get(), resource_provider_.get(), current_task_runner_); } else { + DCHECK(output_surface_); renderer_ = std::make_unique<SkiaRenderer>( - &settings_, output_surface_.get(), resource_provider_.get()); + &settings_, output_surface_.get(), resource_provider_.get(), + skia_output_surface_); } - } else if (output_surface_->vulkan_context_provider()) { #if BUILDFLAG(ENABLE_VULKAN) + } else if (output_surface_->vulkan_context_provider()) { renderer_ = std::make_unique<SkiaRenderer>( &settings_, output_surface_.get(), resource_provider_.get()); -#else - NOTREACHED(); #endif } else { auto renderer = std::make_unique<SoftwareRenderer>( @@ -307,7 +307,8 @@ bool Display::DrawAndSwap() { gfx::Size surface_size; bool have_damage = false; auto& last_render_pass = *frame.render_pass_list.back(); - if (last_render_pass.output_rect.size() != current_surface_size_ && + if (settings_.auto_resize_output_surface && + last_render_pass.output_rect.size() != current_surface_size_ && last_render_pass.damage_rect == last_render_pass.output_rect && !current_surface_size_.IsEmpty()) { // Resize the output rect to the current surface size so that we won't @@ -323,15 +324,6 @@ bool Display::DrawAndSwap() { TRACE_EVENT_INSTANT0("viz", "Size mismatch.", TRACE_EVENT_SCOPE_THREAD); bool should_draw = have_copy_requests || (have_damage && size_matches); - - // If the surface is suspended then the resources to be used by the draw are - // likely destroyed. - if (output_surface_->SurfaceIsSuspendForRecycle()) { - TRACE_EVENT_INSTANT0("viz", "Surface is suspended for recycle.", - TRACE_EVENT_SCOPE_THREAD); - should_draw = false; - } - client_->DisplayWillDrawAndSwap(should_draw, frame.render_pass_list); if (should_draw) { @@ -375,24 +367,28 @@ bool Display::DrawAndSwap() { if (scheduler_) { frame.metadata.latency_info.emplace_back(ui::SourceEventType::FRAME); frame.metadata.latency_info.back().AddLatencyNumberWithTimestamp( - ui::LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT, 0, 0, + ui::LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT, 0, scheduler_->current_frame_time(), 1); } - DLOG_IF(WARNING, !presented_callbacks_.empty()) - << "DidReceiveSwapBuffersAck() is not called for the last SwapBuffers!"; + std::vector<Surface::PresentedCallback> callbacks; for (const auto& id_entry : aggregator_->previous_contained_surfaces()) { Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first); Surface::PresentedCallback callback; - if (surface && surface->TakePresentedCallback(&callback)) - presented_callbacks_.push_back(std::move(callback)); + if (surface && surface->TakePresentedCallback(&callback)) { + callbacks.emplace_back(std::move(callback)); + } } + bool need_presentation_feedback = !callbacks.empty(); + if (need_presentation_feedback) + pending_presented_callbacks_.emplace_back(std::move(callbacks)); ui::LatencyInfo::TraceIntermediateFlowEvents(frame.metadata.latency_info, "Display::DrawAndSwap"); cc::benchmark_instrumentation::IssueDisplayRenderingStatsEvent(); - renderer_->SwapBuffers(std::move(frame.metadata.latency_info)); + renderer_->SwapBuffers(std::move(frame.metadata.latency_info), + need_presentation_feedback); if (scheduler_) scheduler_->DidSwapBuffers(); } else { @@ -413,13 +409,11 @@ bool Display::DrawAndSwap() { base::TimeTicks now = base::TimeTicks::Now(); while (!frame.metadata.latency_info.empty()) { auto& latency = frame.metadata.latency_info.back(); - if (latency.FindLatency(ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT, - nullptr)) { + if (latency.Snapshots().size()) { stored_latency_info_.push_back(std::move(latency)); } else { latency.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_LATENCY_TERMINATED_NO_SWAP_COMPONENT, 0, 0, now, - 1); + ui::INPUT_EVENT_LATENCY_TERMINATED_NO_SWAP_COMPONENT, 0, now, 1); } frame.metadata.latency_info.pop_back(); } @@ -441,17 +435,7 @@ bool Display::DrawAndSwap() { return true; } -void Display::DidReceiveSwapBuffersAck(uint64_t swap_id) { - // TODO(penghuang): Remove it when we can get accurate presentation time from - // GPU for every SwapBuffers. https://crbug.com/776877 - if (!active_presented_callbacks_.empty() || - !previous_presented_callbacks_.empty()) { - DLOG(WARNING) << "VSync for last SwapBuffers is not received!"; - previous_presented_callbacks_.push_back( - std::move(active_presented_callbacks_)); - } - active_presented_callbacks_ = std::move(presented_callbacks_); - +void Display::DidReceiveSwapBuffersAck() { if (scheduler_) scheduler_->DidReceiveSwapBuffersAck(); if (renderer_) @@ -471,25 +455,28 @@ void Display::DidReceiveCALayerParams( } void Display::DidReceivePresentationFeedback( - uint64_t swap_id, const gfx::PresentationFeedback& feedback) { - // TODO(penghuang): Remove it when we can get accurate presentation time from - // GPU for every SwapBuffers. https://crbug.com/776877 - base::TimeTicks previous_timebase = - feedback.timestamp - - feedback.interval * previous_presented_callbacks_.size(); - for (auto& callbacks : previous_presented_callbacks_) { - for (auto& callback : callbacks) - std::move(callback).Run(previous_timebase, feedback.interval, 0); - previous_timebase += feedback.interval; - } - previous_presented_callbacks_.clear(); - - for (auto& callback : active_presented_callbacks_) { + DCHECK(!pending_presented_callbacks_.empty()); + auto& callbacks = pending_presented_callbacks_.front(); + for (auto& callback : callbacks) { std::move(callback).Run(feedback.timestamp, feedback.interval, feedback.flags); } - active_presented_callbacks_.clear(); + pending_presented_callbacks_.pop_front(); +} + +void Display::DidFinishLatencyInfo( + const std::vector<ui::LatencyInfo>& latency_info) { + std::vector<ui::LatencyInfo> latency_info_with_snapshot_component; + for (const auto& latency : latency_info) { + if (latency.Snapshots().size()) + latency_info_with_snapshot_component.push_back(latency); + } + + if (!latency_info_with_snapshot_component.empty()) { + client_->DidSwapAfterSnapshotRequestReceived( + latency_info_with_snapshot_component); + } } void Display::SetNeedsRedrawRect(const gfx::Rect& damage_rect) { @@ -561,6 +548,12 @@ LocalSurfaceId Display::GetSurfaceAtAggregation( return it->second; } +void Display::SoftwareDeviceUpdatedCALayerParams( + const gfx::CALayerParams& ca_layer_params) { + if (client_) + client_->DisplayDidReceiveCALayerParams(ca_layer_params); +} + void Display::ForceImmediateDrawAndSwapIfPossible() { if (scheduler_) scheduler_->ForceImmediateSwapIfPossible(); diff --git a/chromium/components/viz/service/display/display.h b/chromium/components/viz/service/display/display.h index 7759c67aa47..51312be163e 100644 --- a/chromium/components/viz/service/display/display.h +++ b/chromium/components/viz/service/display/display.h @@ -8,16 +8,19 @@ #include <memory> #include <vector> +#include "base/containers/circular_deque.h" #include "base/macros.h" #include "base/observer_list.h" -#include "cc/resources/display_resource_provider.h" +#include "base/single_thread_task_runner.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/gpu/context_lost_observer.h" #include "components/viz/common/resources/returned_resource.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/surface_id.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/display_scheduler.h" #include "components/viz/service/display/output_surface_client.h" +#include "components/viz/service/display/software_output_device_client.h" #include "components/viz/service/display/surface_aggregator.h" #include "components/viz/service/surfaces/latest_local_surface_id_lookup_delegate.h" #include "components/viz/service/surfaces/surface_manager.h" @@ -26,11 +29,6 @@ #include "ui/gfx/color_space.h" #include "ui/latency/latency_info.h" -namespace cc { -class DisplayResourceProvider; -class RendererSettings; -} // namespace cc - namespace gfx { class Size; } @@ -38,8 +36,11 @@ class Size; namespace viz { class DirectRenderer; class DisplayClient; +class DisplayResourceProvider; class OutputSurface; +class RendererSettings; class SharedBitmapManager; +class SkiaOutputSurface; class SoftwareRenderer; class VIZ_SERVICE_EXPORT DisplayObserver { @@ -55,18 +56,22 @@ class VIZ_SERVICE_EXPORT DisplayObserver { class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient, public OutputSurfaceClient, public ContextLostObserver, - public LatestLocalSurfaceIdLookupDelegate { + public LatestLocalSurfaceIdLookupDelegate, + public SoftwareOutputDeviceClient { public: // The |begin_frame_source| and |scheduler| may be null (together). In that // case, DrawAndSwap must be called externally when needed. // The |current_task_runner| may be null if the Display is on a thread without // a MessageLoop. + // TODO(penghuang): Remove skia_output_surface when all DirectRenderer + // subclasses are replaced by SkiaRenderer. Display(SharedBitmapManager* bitmap_manager, const RendererSettings& settings, const FrameSinkId& frame_sink_id, std::unique_ptr<OutputSurface> output_surface, std::unique_ptr<DisplayScheduler> scheduler, - scoped_refptr<base::SingleThreadTaskRunner> current_task_runner); + scoped_refptr<base::SingleThreadTaskRunner> current_task_runner, + SkiaOutputSurface* skia_output_surface = nullptr); ~Display() override; @@ -101,19 +106,24 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient, // OutputSurfaceClient implementation. void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override; - void DidReceiveSwapBuffersAck(uint64_t swap_id) override; + void DidReceiveSwapBuffersAck() override; void DidReceiveTextureInUseResponses( const gpu::TextureInUseResponses& responses) override; void DidReceiveCALayerParams( const gfx::CALayerParams& ca_layer_params) override; void DidReceivePresentationFeedback( - uint64_t swap_id, const gfx::PresentationFeedback& feedback) override; + void DidFinishLatencyInfo( + const std::vector<ui::LatencyInfo>& latency_info) override; // LatestLocalSurfaceIdLookupDelegate implementation. LocalSurfaceId GetSurfaceAtAggregation( const FrameSinkId& frame_sink_id) const override; + // SoftwareOutputDeviceClient implementation + void SoftwareDeviceUpdatedCALayerParams( + const gfx::CALayerParams& ca_layer_params) override; + bool has_scheduler() const { return !!scheduler_; } DirectRenderer* renderer_for_testing() const { return renderer_.get(); } @@ -144,9 +154,10 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient, bool swapped_since_resize_ = false; bool output_is_secure_ = false; + SkiaOutputSurface* skia_output_surface_; std::unique_ptr<OutputSurface> output_surface_; std::unique_ptr<DisplayScheduler> scheduler_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<SurfaceAggregator> aggregator_; // This may be null if the Display is on a thread without a MessageLoop. scoped_refptr<base::SingleThreadTaskRunner> current_task_runner_; @@ -154,12 +165,8 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient, SoftwareRenderer* software_renderer_ = nullptr; std::vector<ui::LatencyInfo> stored_latency_info_; - using PresentedCallbacks = std::vector<Surface::PresentedCallback>; - PresentedCallbacks presented_callbacks_; - PresentedCallbacks active_presented_callbacks_; - // TODO(penghuang): Remove it when we can get accurate presentation time from - // GPU for every SwapBuffers. https://crbug.com/776877 - std::vector<PresentedCallbacks> previous_presented_callbacks_; + base::circular_deque<std::vector<Surface::PresentedCallback>> + pending_presented_callbacks_; private: DISALLOW_COPY_AND_ASSIGN(Display); diff --git a/chromium/components/viz/service/display/display_client.h b/chromium/components/viz/service/display/display_client.h index 286aa158ff3..9734040a581 100644 --- a/chromium/components/viz/service/display/display_client.h +++ b/chromium/components/viz/service/display/display_client.h @@ -11,6 +11,10 @@ namespace gfx { struct CALayerParams; } // namespace gfx +namespace ui { +class LatencyInfo; +} // namespace ui + namespace viz { class DisplayClient { @@ -22,6 +26,11 @@ class DisplayClient { virtual void DisplayDidDrawAndSwap() = 0; virtual void DisplayDidReceiveCALayerParams( const gfx::CALayerParams& ca_layer_params) = 0; + + // Notifies that a swap has occured after some latency info with snapshot + // component reached the display. + virtual void DidSwapAfterSnapshotRequestReceived( + const std::vector<ui::LatencyInfo>& latency_info) = 0; }; } // namespace viz diff --git a/chromium/components/viz/service/display/display_resource_provider.cc b/chromium/components/viz/service/display/display_resource_provider.cc new file mode 100644 index 00000000000..2b78a9662b5 --- /dev/null +++ b/chromium/components/viz/service/display/display_resource_provider.cc @@ -0,0 +1,972 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display/display_resource_provider.h" + +#include "base/atomic_sequence_num.h" +#include "base/numerics/safe_math.h" +#include "base/strings/stringprintf.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/trace_event/memory_dump_manager.h" +#include "base/trace_event/trace_event.h" +#include "components/viz/common/gpu/context_provider.h" +#include "components/viz/common/resources/resource_format_utils.h" +#include "components/viz/common/resources/resource_sizes.h" +#include "components/viz/common/resources/shared_bitmap_manager.h" +#include "gpu/command_buffer/client/context_support.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "third_party/skia/include/gpu/GrBackendSurface.h" +#include "ui/gl/trace_util.h" + +using gpu::gles2::GLES2Interface; + +namespace viz { + +namespace { + +// Generates process-unique IDs to use for tracing resources. +base::AtomicSequenceNumber g_next_display_resource_provider_tracing_id; + +} // namespace + +static GLint GetActiveTextureUnit(GLES2Interface* gl) { + GLint active_unit = 0; + gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); + return active_unit; +} + +class ScopedSetActiveTexture { + public: + ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit) + : gl_(gl), unit_(unit) { + DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); + + if (unit_ != GL_TEXTURE0) + gl_->ActiveTexture(unit_); + } + + ~ScopedSetActiveTexture() { + // Active unit being GL_TEXTURE0 is effectively the ground state. + if (unit_ != GL_TEXTURE0) + gl_->ActiveTexture(GL_TEXTURE0); + } + + private: + GLES2Interface* gl_; + GLenum unit_; +}; + +DisplayResourceProvider::DisplayResourceProvider( + ContextProvider* compositor_context_provider, + SharedBitmapManager* shared_bitmap_manager) + : compositor_context_provider_(compositor_context_provider), + shared_bitmap_manager_(shared_bitmap_manager), + tracing_id_(g_next_display_resource_provider_tracing_id.GetNext()) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview). + // Don't register a dump provider in these cases. + // TODO(crbug.com/517156): Get this working in Android Webview. + if (base::ThreadTaskRunnerHandle::IsSet()) { + base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( + this, "cc::ResourceProvider", base::ThreadTaskRunnerHandle::Get()); + } +} + +DisplayResourceProvider::~DisplayResourceProvider() { + while (!children_.empty()) + DestroyChildInternal(children_.begin(), FOR_SHUTDOWN); + + GLES2Interface* gl = ContextGL(); + if (gl) + gl->Finish(); + + while (!resources_.empty()) + DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN); + + if (compositor_context_provider_) { + // Check that all GL resources has been deleted. + for (const auto& pair : resources_) + DCHECK(!pair.second.is_gpu_resource_type()); + } + + base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( + this); +} + +bool DisplayResourceProvider::OnMemoryDump( + const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + for (const auto& resource_entry : resources_) { + const auto& resource = resource_entry.second; + + bool backing_memory_allocated = false; + switch (resource.type) { + case ResourceType::kTexture: + backing_memory_allocated = !!resource.gl_id; + break; + case ResourceType::kBitmap: + backing_memory_allocated = !!resource.shared_bitmap; + break; + } + + if (!backing_memory_allocated) { + // Don't log unallocated resources - they have no backing memory. + continue; + } + + // ResourceIds are not process-unique, so log with the ResourceProvider's + // unique id. + std::string dump_name = + base::StringPrintf("cc/resource_memory/provider_%d/resource_%d", + tracing_id_, resource_entry.first); + base::trace_event::MemoryAllocatorDump* dump = + pmd->CreateAllocatorDump(dump_name); + + // Texture resources may not come with a size, in which case don't report + // one. + if (!resource.size.IsEmpty()) { + uint64_t total_bytes = ResourceSizes::UncheckedSizeInBytesAligned<size_t>( + resource.size, resource.format); + dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, + base::trace_event::MemoryAllocatorDump::kUnitsBytes, + static_cast<uint64_t>(total_bytes)); + } + + // Resources may be shared across processes and require a shared GUID to + // prevent double counting the memory. + base::trace_event::MemoryAllocatorDumpGuid guid; + base::UnguessableToken shared_memory_guid; + switch (resource.type) { + case ResourceType::kTexture: + DCHECK(resource.gl_id); + guid = gl::GetGLTextureClientGUIDForTracing( + compositor_context_provider_->ContextSupport() + ->ShareGroupTracingGUID(), + resource.gl_id); + break; + case ResourceType::kBitmap: + // If the resource comes from out of process, it will have this id, + // which we prefer. Otherwise, we fall back to the SharedBitmapGUID + // which can be generated for in-process bitmaps. + shared_memory_guid = resource.shared_bitmap->GetCrossProcessGUID(); + if (shared_memory_guid.is_empty()) + guid = GetSharedBitmapGUIDForTracing(resource.shared_bitmap_id); + break; + } + + DCHECK(!shared_memory_guid.is_empty() || !guid.empty()); + + // The client that owns the resource will use a higher importance (2), and + // the GPU service will use a lower one (0). + const int importance = 1; + if (!shared_memory_guid.is_empty()) { + pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_memory_guid, + importance); + } else { + pmd->CreateSharedGlobalAllocatorDump(guid); + pmd->AddOwnershipEdge(dump->guid(), guid, importance); + } + } + + return true; +} + +#if defined(OS_ANDROID) +void DisplayResourceProvider::SendPromotionHints( + const OverlayCandidateList::PromotionHintInfoMap& promotion_hints) { + GLES2Interface* gl = ContextGL(); + if (!gl) + return; + + for (const auto& id : wants_promotion_hints_set_) { + auto it = resources_.find(id); + if (it == resources_.end()) + continue; + + if (it->second.marked_for_deletion) + continue; + + const internal::Resource* resource = LockForRead(id); + // TODO(ericrk): We should never fail LockForRead, but we appear to be + // doing so on Android in rare cases. Handle this gracefully until a better + // solution can be found. https://crbug.com/811858 + if (!resource) + return; + + DCHECK(resource->wants_promotion_hint); + + // Insist that this is backed by a GPU texture. + if (resource->is_gpu_resource_type()) { + DCHECK(resource->gl_id); + auto iter = promotion_hints.find(id); + bool promotable = iter != promotion_hints.end(); + gl->OverlayPromotionHintCHROMIUM(resource->gl_id, promotable, + promotable ? iter->second.x() : 0, + promotable ? iter->second.y() : 0, + promotable ? iter->second.width() : 0, + promotable ? iter->second.height() : 0); + } + UnlockForRead(id); + } +} + +bool DisplayResourceProvider::IsBackedBySurfaceTexture(ResourceId id) { + internal::Resource* resource = GetResource(id); + return resource->is_backed_by_surface_texture; +} + +bool DisplayResourceProvider::WantsPromotionHintForTesting(ResourceId id) { + return wants_promotion_hints_set_.count(id) > 0; +} + +size_t DisplayResourceProvider::CountPromotionHintRequestsForTesting() { + return wants_promotion_hints_set_.size(); +} +#endif + +bool DisplayResourceProvider::IsOverlayCandidate(ResourceId id) { + internal::Resource* resource = TryGetResource(id); + // TODO(ericrk): We should never fail TryGetResource, but we appear to + // be doing so on Android in rare cases. Handle this gracefully until a + // better solution can be found. https://crbug.com/811858 + return resource && resource->is_overlay_candidate; +} + +ResourceType DisplayResourceProvider::GetResourceType(ResourceId id) { + return GetResource(id)->type; +} + +GLenum DisplayResourceProvider::GetResourceTextureTarget(ResourceId id) { + return GetResource(id)->target; +} + +gfx::BufferFormat DisplayResourceProvider::GetBufferFormat(ResourceId id) { + internal::Resource* resource = GetResource(id); + return resource->buffer_format; +} + +void DisplayResourceProvider::WaitSyncToken(ResourceId id) { + internal::Resource* resource = TryGetResource(id); + // TODO(ericrk): We should never fail TryGetResource, but we appear to + // be doing so on Android in rare cases. Handle this gracefully until a + // better solution can be found. https://crbug.com/811858 + if (!resource) + return; + WaitSyncTokenInternal(resource); +#if defined(OS_ANDROID) + // Now that the resource is synced, we may send it a promotion hint. We could + // sync all |wants_promotion_hint| resources elsewhere, and send 'no' to all + // resources that weren't used. However, there's no real advantage. + if (resource->wants_promotion_hint) + wants_promotion_hints_set_.insert(id); +#endif // OS_ANDROID +} + +int DisplayResourceProvider::CreateChild( + const ReturnCallback& return_callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + Child child_info; + child_info.return_callback = return_callback; + + int child = next_child_++; + children_[child] = child_info; + return child; +} + +void DisplayResourceProvider::SetChildNeedsSyncTokens(int child_id, + bool needs) { + auto it = children_.find(child_id); + DCHECK(it != children_.end()); + it->second.needs_sync_tokens = needs; +} + +void DisplayResourceProvider::DestroyChild(int child_id) { + auto it = children_.find(child_id); + DCHECK(it != children_.end()); + DestroyChildInternal(it, NORMAL); +} + +void DisplayResourceProvider::ReceiveFromChild( + int child, + const std::vector<TransferableResource>& resources) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + GLES2Interface* gl = ContextGL(); + Child& child_info = children_.find(child)->second; + DCHECK(!child_info.marked_for_deletion); + for (std::vector<TransferableResource>::const_iterator it = resources.begin(); + it != resources.end(); ++it) { + auto resource_in_map_it = child_info.child_to_parent_map.find(it->id); + if (resource_in_map_it != child_info.child_to_parent_map.end()) { + internal::Resource* resource = GetResource(resource_in_map_it->second); + resource->marked_for_deletion = false; + resource->imported_count++; + continue; + } + + if ((!it->is_software && !gl) || + (it->is_software && !shared_bitmap_manager_)) { + TRACE_EVENT0( + "cc", "DisplayResourceProvider::ReceiveFromChild dropping invalid"); + std::vector<ReturnedResource> to_return; + to_return.push_back(it->ToReturnedResource()); + child_info.return_callback.Run(to_return); + continue; + } + + ResourceId local_id = next_id_++; + internal::Resource* resource = nullptr; + if (it->is_software) { + DCHECK(IsBitmapFormatSupported(it->format)); + resource = InsertResource( + local_id, internal::Resource(it->size, ResourceType::kBitmap, + it->format, it->color_space)); + resource->has_shared_bitmap_id = true; + resource->shared_bitmap_id = it->mailbox_holder.mailbox; + } else { + resource = InsertResource( + local_id, internal::Resource(it->size, ResourceType::kTexture, + it->format, it->color_space)); + resource->target = it->mailbox_holder.texture_target; + resource->filter = it->filter; + resource->original_filter = it->filter; + resource->min_filter = it->filter; + resource->buffer_format = it->buffer_format; + resource->mailbox = it->mailbox_holder.mailbox; + resource->UpdateSyncToken(it->mailbox_holder.sync_token); + resource->read_lock_fences_enabled = it->read_lock_fences_enabled; + resource->is_overlay_candidate = it->is_overlay_candidate; +#if defined(OS_ANDROID) + resource->is_backed_by_surface_texture = it->is_backed_by_surface_texture; + resource->wants_promotion_hint = it->wants_promotion_hint; +#endif + } + resource->child_id = child; + resource->imported_count = 1; + resource->id_in_child = it->id; + child_info.child_to_parent_map[it->id] = local_id; + } +} + +void DisplayResourceProvider::DeclareUsedResourcesFromChild( + int child, + const ResourceIdSet& resources_from_child) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + auto child_it = children_.find(child); + DCHECK(child_it != children_.end()); + Child& child_info = child_it->second; + DCHECK(!child_info.marked_for_deletion); + + std::vector<ResourceId> unused; + for (auto it = child_info.child_to_parent_map.begin(); + it != child_info.child_to_parent_map.end(); ++it) { + ResourceId local_id = it->second; + bool resource_is_in_use = resources_from_child.count(it->first) > 0; + if (!resource_is_in_use) + unused.push_back(local_id); + } + DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused); +} + +const std::unordered_map<ResourceId, ResourceId>& +DisplayResourceProvider::GetChildToParentMap(int child) const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + ChildMap::const_iterator it = children_.find(child); + DCHECK(it != children_.end()); + DCHECK(!it->second.marked_for_deletion); + return it->second.child_to_parent_map; +} + +bool DisplayResourceProvider::InUse(ResourceId id) { + internal::Resource* resource = GetResource(id); + return resource->lock_for_read_count > 0 || resource->locked_for_external_use; +} + +internal::Resource* DisplayResourceProvider::InsertResource( + ResourceId id, + internal::Resource resource) { + auto result = + resources_.insert(ResourceMap::value_type(id, std::move(resource))); + DCHECK(result.second); + return &result.first->second; +} + +internal::Resource* DisplayResourceProvider::GetResource(ResourceId id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(id); + auto it = resources_.find(id); + DCHECK(it != resources_.end()); + return &it->second; +} + +internal::Resource* DisplayResourceProvider::TryGetResource(ResourceId id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (!id) + return nullptr; + auto it = resources_.find(id); + if (it == resources_.end()) + return nullptr; + return &it->second; +} + +void DisplayResourceProvider::PopulateSkBitmapWithResource( + SkBitmap* sk_bitmap, + const internal::Resource* resource) { + DCHECK(IsBitmapFormatSupported(resource->format)); + SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(), + resource->size.height()); + bool pixels_installed = + sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes()); + DCHECK(pixels_installed); +} + +void DisplayResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, + DeleteStyle style) { + TRACE_EVENT0("cc", "DosplayResourceProvider::DeleteResourceInternal"); + internal::Resource* resource = &it->second; + + if (resource->gl_id) { + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + gl->DeleteTextures(1, &resource->gl_id); + resource->gl_id = 0; + } + + if (resource->owned_shared_bitmap) { + DCHECK_EQ(ResourceType::kBitmap, resource->type); + resource->shared_bitmap = nullptr; + resource->pixels = nullptr; + resource->owned_shared_bitmap = nullptr; + } + + resources_.erase(it); +} + +void DisplayResourceProvider::WaitSyncTokenInternal( + internal::Resource* resource) { + DCHECK(resource); + if (!resource->ShouldWaitSyncToken()) + return; + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + // In the case of context lost, this sync token may be empty (see comment in + // the UpdateSyncToken() function). The WaitSyncTokenCHROMIUM() function + // handles empty sync tokens properly so just wait anyways and update the + // state the synchronized. + gl->WaitSyncTokenCHROMIUM(resource->sync_token().GetConstData()); + resource->SetSynchronized(); +} + +GLES2Interface* DisplayResourceProvider::ContextGL() const { + ContextProvider* context_provider = compositor_context_provider_; + return context_provider ? context_provider->ContextGL() : nullptr; +} + +const internal::Resource* DisplayResourceProvider::LockForRead(ResourceId id) { + // TODO(ericrk): We should never fail TryGetResource, but we appear to be + // doing so on Android in rare cases. Handle this gracefully until a better + // solution can be found. https://crbug.com/811858 + internal::Resource* resource = TryGetResource(id); + if (!resource) + return nullptr; + + // Mailbox sync_tokens must be processed by a call to WaitSyncToken() prior to + // calling LockForRead(). + DCHECK_NE(internal::Resource::NEEDS_WAIT, resource->synchronization_state()); + + if (resource->is_gpu_resource_type() && !resource->gl_id) { + DCHECK(!resource->mailbox.IsZero()); + + GLES2Interface* gl = ContextGL(); + DCHECK(gl); + resource->gl_id = + gl->CreateAndConsumeTextureCHROMIUM(resource->mailbox.name); + resource->SetLocallyUsed(); + } + + if (!resource->pixels && resource->has_shared_bitmap_id && + shared_bitmap_manager_) { + std::unique_ptr<SharedBitmap> bitmap = + shared_bitmap_manager_->GetSharedBitmapFromId( + resource->size, resource->format, resource->shared_bitmap_id); + if (bitmap) { + resource->SetSharedBitmap(bitmap.get()); + resource->owned_shared_bitmap = std::move(bitmap); + } + } + + resource->lock_for_read_count++; + if (resource->read_lock_fences_enabled) { + if (current_read_lock_fence_.get()) + current_read_lock_fence_->Set(); + resource->read_lock_fence = current_read_lock_fence_; + } + + return resource; +} + +void DisplayResourceProvider::UnlockForRead(ResourceId id) { + 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 + // doing so on Android in rare cases. Handle this gracefully until a better + // solution can be found. https://crbug.com/811858 + if (it == resources_.end()) + return; + + internal::Resource* resource = &it->second; + DCHECK_GT(resource->lock_for_read_count, 0); + resource->lock_for_read_count--; + TryReleaseResource(it); +} + +ResourceMetadata DisplayResourceProvider::LockForExternalUse(ResourceId id) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + auto it = resources_.find(id); + DCHECK(it != resources_.end()); + + internal::Resource* resource = &it->second; + ResourceMetadata metadata; + // Make sure there is no outstanding LockForExternalUse without calling + // UnlockForExternalUse. + DCHECK(!resource->locked_for_external_use); + // TODO(penghuang): support software resource. + DCHECK(resource->is_gpu_resource_type()); + + metadata.mailbox = resource->mailbox; + metadata.backend_format = GrBackendFormat::MakeGL( + TextureStorageFormat(resource->format), resource->target); + metadata.size = resource->size; + metadata.mip_mapped = GrMipMapped::kNo; + metadata.origin = kTopLeft_GrSurfaceOrigin; + metadata.color_type = + ResourceFormatToClosestSkColorType(!IsSoftware(), resource->format); + metadata.alpha_type = kPremul_SkAlphaType; + metadata.color_space = nullptr; + metadata.sync_token = resource->sync_token(); + + resource->locked_for_external_use = true; + return metadata; +} + +void DisplayResourceProvider::UnlockForExternalUse( + ResourceId id, + const gpu::SyncToken& sync_token) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + auto it = resources_.find(id); + DCHECK(it != resources_.end()); + DCHECK(sync_token.verified_flush()); + + internal::Resource* resource = &it->second; + DCHECK(resource->locked_for_external_use); + // TODO(penghuang): support software resource. + DCHECK(resource->is_gpu_resource_type()); + + // Update the resource sync token to |sync_token|. When the next frame is + // being composited, the DeclareUsedResourcesFromChild() will be called with + // resources belong to every child for the next frame. If the resource is not + // used by the next frame, the resource will be returned to a child which + // owns it with the |sync_token|. The child is responsible for issuing a + // WaitSyncToken GL command with the |sync_token| before reusing it. + resource->UpdateSyncToken(sync_token); + resource->locked_for_external_use = false; + + TryReleaseResource(it); +} + +void DisplayResourceProvider::TryReleaseResource(ResourceMap::iterator it) { + ResourceId id = it->first; + internal::Resource* resource = &it->second; + if (resource->marked_for_deletion && !resource->lock_for_read_count && + !resource->locked_for_external_use) { + if (!resource->child_id) { +// The resource belongs to this instance, so it can be destroyed. +// TODO(danakj): Is this dead code? +#if defined(OS_ANDROID) + DeletePromotionHint(it, NORMAL); +#endif + DeleteResourceInternal(it, NORMAL); + } else { + if (batch_return_resources_) { + batched_returning_resources_[resource->child_id].push_back(id); + } else { + auto child_it = children_.find(resource->child_id); + std::vector<ResourceId> unused; + unused.push_back(id); + DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused); + } + } + } +} + +GLenum DisplayResourceProvider::BindForSampling(ResourceId resource_id, + GLenum unit, + GLenum filter) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + GLES2Interface* gl = ContextGL(); + auto it = resources_.find(resource_id); + // TODO(ericrk): We should never fail to find resource_id, but we appear to + // be doing so on Android in rare cases. Handle this gracefully until a + // better solution can be found. https://crbug.com/811858 + if (it == resources_.end()) + return GL_TEXTURE_2D; + + internal::Resource* resource = &it->second; + DCHECK(resource->lock_for_read_count); + + ScopedSetActiveTexture scoped_active_tex(gl, unit); + GLenum target = resource->target; + gl->BindTexture(target, resource->gl_id); + GLenum min_filter = filter; + if (min_filter != resource->min_filter) { + gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter); + resource->min_filter = min_filter; + } + if (filter != resource->filter) { + gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); + resource->filter = filter; + } + + return target; +} + +bool DisplayResourceProvider::ReadLockFenceHasPassed( + const internal::Resource* resource) { + return !resource->read_lock_fence || resource->read_lock_fence->HasPassed(); +} + +#if defined(OS_ANDROID) +void DisplayResourceProvider::DeletePromotionHint(ResourceMap::iterator it, + DeleteStyle style) { + internal::Resource* resource = &it->second; + // If this resource was interested in promotion hints, then remove it from + // the set of resources that we'll notify. + if (resource->wants_promotion_hint) + wants_promotion_hints_set_.erase(it->first); +} +#endif + +void DisplayResourceProvider::DeleteAndReturnUnusedResourcesToChild( + ChildMap::iterator child_it, + DeleteStyle style, + const std::vector<ResourceId>& unused) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(child_it != children_.end()); + Child* child_info = &child_it->second; + + if (unused.empty() && !child_info->marked_for_deletion) + return; + + std::vector<ReturnedResource> to_return; + to_return.reserve(unused.size()); + std::vector<ReturnedResource*> need_synchronization_resources; + std::vector<GLbyte*> unverified_sync_tokens; + std::vector<size_t> to_return_indices_unverified; + + GLES2Interface* gl = ContextGL(); + + for (ResourceId local_id : unused) { + auto it = resources_.find(local_id); + CHECK(it != resources_.end()); + internal::Resource& resource = it->second; + + ResourceId child_id = resource.id_in_child; + DCHECK(child_info->child_to_parent_map.count(child_id)); + + bool is_lost = (resource.is_gpu_resource_type() && lost_context_provider_); + if (resource.lock_for_read_count > 0 || resource.locked_for_external_use) { + if (style != FOR_SHUTDOWN) { + // Defer this resource deletion. + resource.marked_for_deletion = true; + continue; + } + // We can't postpone the deletion, so we'll have to lose it. + is_lost = true; + } else if (!ReadLockFenceHasPassed(&resource)) { + // TODO(dcastagna): see if it's possible to use this logic for + // the branch above too, where the resource is locked or still exported. + if (style != FOR_SHUTDOWN && !child_info->marked_for_deletion) { + // Defer this resource deletion. + resource.marked_for_deletion = true; + continue; + } + // We can't postpone the deletion, so we'll have to lose it. + is_lost = true; + } + + if (resource.is_gpu_resource_type() && + resource.filter != resource.original_filter) { + DCHECK(resource.target); + DCHECK(resource.gl_id); + DCHECK(gl); + gl->BindTexture(resource.target, resource.gl_id); + gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER, + resource.original_filter); + gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER, + resource.original_filter); + resource.SetLocallyUsed(); + } + + ReturnedResource returned; + returned.id = child_id; + returned.sync_token = resource.sync_token(); + returned.count = resource.imported_count; + returned.lost = is_lost; + to_return.push_back(returned); + + if (resource.is_gpu_resource_type() && child_info->needs_sync_tokens) { + if (resource.needs_sync_token()) { + need_synchronization_resources.push_back(&to_return.back()); + } else if (returned.sync_token.HasData() && + !returned.sync_token.verified_flush()) { + // Before returning any sync tokens, they must be verified. Store an + // index into |to_return| instead of a pointer as vectors may realloc + // and move their data. + to_return_indices_unverified.push_back(to_return.size() - 1); + } + } + + child_info->child_to_parent_map.erase(child_id); + resource.imported_count = 0; +#if defined(OS_ANDROID) + DeletePromotionHint(it, style); +#endif + DeleteResourceInternal(it, style); + } + + for (size_t i : to_return_indices_unverified) + unverified_sync_tokens.push_back(to_return[i].sync_token.GetData()); + + gpu::SyncToken new_sync_token; + if (!need_synchronization_resources.empty()) { + DCHECK(child_info->needs_sync_tokens); + DCHECK(gl); + gl->GenUnverifiedSyncTokenCHROMIUM(new_sync_token.GetData()); + unverified_sync_tokens.push_back(new_sync_token.GetData()); + } + + if (!unverified_sync_tokens.empty()) { + DCHECK(child_info->needs_sync_tokens); + DCHECK(gl); + gl->VerifySyncTokensCHROMIUM(unverified_sync_tokens.data(), + unverified_sync_tokens.size()); + } + + // Set sync token after verification. + for (ReturnedResource* returned : need_synchronization_resources) + returned->sync_token = new_sync_token; + + if (!to_return.empty()) + child_info->return_callback.Run(to_return); + + if (child_info->marked_for_deletion && + child_info->child_to_parent_map.empty()) { + children_.erase(child_it); + } +} + +void DisplayResourceProvider::DestroyChildInternal(ChildMap::iterator it, + DeleteStyle style) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + Child& child = it->second; + DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion); + + std::vector<ResourceId> resources_for_child; + + for (auto child_it = child.child_to_parent_map.begin(); + child_it != child.child_to_parent_map.end(); ++child_it) { + ResourceId id = child_it->second; + resources_for_child.push_back(id); + } + + child.marked_for_deletion = true; + + DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child); +} + +void DisplayResourceProvider::SetBatchReturnResources(bool batch) { + DCHECK_NE(batch_return_resources_, batch); + batch_return_resources_ = batch; + if (!batch) { + for (const auto& resources : batched_returning_resources_) { + auto child_it = children_.find(resources.first); + DCHECK(child_it != children_.end()); + DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, resources.second); + } + batched_returning_resources_.clear(); + } +} + +DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL( + DisplayResourceProvider* resource_provider, + ResourceId resource_id) + : resource_provider_(resource_provider), resource_id_(resource_id) { + const internal::Resource* resource = + resource_provider->LockForRead(resource_id); + // TODO(ericrk): We should never fail LockForRead, but we appear to be + // doing so on Android in rare cases. Handle this gracefully until a better + // solution can be found. https://crbug.com/811858 + if (!resource) + return; + + texture_id_ = resource->gl_id; + target_ = resource->target; + size_ = resource->size; + color_space_ = resource->color_space; +} + +DisplayResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() { + resource_provider_->UnlockForRead(resource_id_); +} + +DisplayResourceProvider::ScopedSamplerGL::ScopedSamplerGL( + DisplayResourceProvider* resource_provider, + ResourceId resource_id, + GLenum filter) + : resource_lock_(resource_provider, resource_id), + unit_(GL_TEXTURE0), + target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {} + +DisplayResourceProvider::ScopedSamplerGL::ScopedSamplerGL( + DisplayResourceProvider* resource_provider, + ResourceId resource_id, + GLenum unit, + GLenum filter) + : resource_lock_(resource_provider, resource_id), + unit_(unit), + target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {} + +DisplayResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() = default; + +DisplayResourceProvider::ScopedReadLockSkImage::ScopedReadLockSkImage( + DisplayResourceProvider* resource_provider, + ResourceId resource_id) + : resource_provider_(resource_provider), resource_id_(resource_id) { + const internal::Resource* resource = + resource_provider->LockForRead(resource_id); + DCHECK(resource); + if (resource_provider_->resource_sk_image_.find(resource_id) != + resource_provider_->resource_sk_image_.end()) { + // Use cached sk_image. + sk_image_ = + resource_provider_->resource_sk_image_.find(resource_id)->second; + } else if (resource->gl_id) { + GrGLTextureInfo texture_info; + texture_info.fID = resource->gl_id; + texture_info.fTarget = resource->target; + texture_info.fFormat = TextureStorageFormat(resource->format); + GrBackendTexture backend_texture(resource->size.width(), + resource->size.height(), GrMipMapped::kNo, + texture_info); + sk_image_ = SkImage::MakeFromTexture( + resource_provider->compositor_context_provider_->GrContext(), + backend_texture, kTopLeft_GrSurfaceOrigin, + ResourceFormatToClosestSkColorType(!resource_provider->IsSoftware(), + resource->format), + kPremul_SkAlphaType, nullptr); + } else if (resource->pixels) { + SkBitmap sk_bitmap; + resource_provider->PopulateSkBitmapWithResource(&sk_bitmap, resource); + sk_bitmap.setImmutable(); + sk_image_ = SkImage::MakeFromBitmap(sk_bitmap); + } else { + // During render process shutdown, ~RenderMessageFilter which calls + // ~HostSharedBitmapClient (which deletes shared bitmaps from child) + // can race with OnBeginFrameDeadline which draws a frame. + // In these cases, shared bitmaps (and this read lock) won't be valid. + // Renderers need to silently handle locks failing until this race + // is fixed. DCHECK that this is the only case where there are no pixels. + DCHECK(!resource->shared_bitmap_id.IsZero()); + } +} + +DisplayResourceProvider::ScopedReadLockSkImage::~ScopedReadLockSkImage() { + resource_provider_->UnlockForRead(resource_id_); +} + +DisplayResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware( + DisplayResourceProvider* resource_provider, + ResourceId resource_id) + : resource_provider_(resource_provider), resource_id_(resource_id) { + const internal::Resource* resource = + resource_provider->LockForRead(resource_id); + DCHECK(resource); + resource_provider->PopulateSkBitmapWithResource(&sk_bitmap_, resource); +} + +DisplayResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() { + resource_provider_->UnlockForRead(resource_id_); +} + +DisplayResourceProvider::LockSetForExternalUse::LockSetForExternalUse( + DisplayResourceProvider* resource_provider) + : resource_provider_(resource_provider) {} + +DisplayResourceProvider::LockSetForExternalUse::~LockSetForExternalUse() { + DCHECK(resources_.empty()); +} + +ResourceMetadata DisplayResourceProvider::LockSetForExternalUse::LockResource( + ResourceId id) { + DCHECK(std::find(resources_.begin(), resources_.end(), id) == + resources_.end()); + resources_.push_back(id); + return resource_provider_->LockForExternalUse(id); +} + +void DisplayResourceProvider::LockSetForExternalUse::UnlockResources( + const gpu::SyncToken& sync_token) { + for (const auto& id : resources_) + resource_provider_->UnlockForExternalUse(id, sync_token); + resources_.clear(); +} + +DisplayResourceProvider::SynchronousFence::SynchronousFence( + gpu::gles2::GLES2Interface* gl) + : gl_(gl), has_synchronized_(true) {} + +DisplayResourceProvider::SynchronousFence::~SynchronousFence() = default; + +void DisplayResourceProvider::SynchronousFence::Set() { + has_synchronized_ = false; +} + +bool DisplayResourceProvider::SynchronousFence::HasPassed() { + if (!has_synchronized_) { + has_synchronized_ = true; + Synchronize(); + } + return true; +} + +void DisplayResourceProvider::SynchronousFence::Wait() { + HasPassed(); +} + +void DisplayResourceProvider::SynchronousFence::Synchronize() { + TRACE_EVENT0("cc", "DisplayResourceProvider::SynchronousFence::Synchronize"); + gl_->Finish(); +} + +DisplayResourceProvider::ScopedBatchReturnResources::ScopedBatchReturnResources( + DisplayResourceProvider* resource_provider) + : resource_provider_(resource_provider) { + resource_provider_->SetBatchReturnResources(true); +} + +DisplayResourceProvider::ScopedBatchReturnResources:: + ~ScopedBatchReturnResources() { + resource_provider_->SetBatchReturnResources(false); +} + +DisplayResourceProvider::Child::Child() = default; +DisplayResourceProvider::Child::Child(const Child& other) = default; +DisplayResourceProvider::Child::~Child() = default; + +} // namespace viz diff --git a/chromium/components/viz/service/display/display_resource_provider.h b/chromium/components/viz/service/display/display_resource_provider.h new file mode 100644 index 00000000000..d81e561bee8 --- /dev/null +++ b/chromium/components/viz/service/display/display_resource_provider.h @@ -0,0 +1,397 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_ + +#include <stddef.h> +#include <map> +#include <unordered_map> +#include <vector> + +#include "base/containers/flat_map.h" +#include "base/containers/small_map.h" +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "base/trace_event/memory_dump_provider.h" +#include "build/build_config.h" +#include "components/viz/common/resources/resource.h" +#include "components/viz/common/resources/resource_fence.h" +#include "components/viz/common/resources/resource_id.h" +#include "components/viz/common/resources/resource_metadata.h" +#include "components/viz/common/resources/return_callback.h" +#include "components/viz/common/resources/transferable_resource.h" +#include "components/viz/service/display/overlay_candidate.h" +#include "components/viz/service/viz_service_export.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "third_party/skia/include/core/SkBitmap.h" + +namespace gfx { +class ColorSpace; +class Size; +} // namespace gfx + +namespace gpu { +namespace gles2 { +class GLES2Interface; +} +} // namespace gpu + +namespace viz { +class ContextProvider; +class SharedBitmapManager; + +// This class provides abstractions for receiving and using resources from other +// modules/threads/processes. It abstracts away GL textures vs GpuMemoryBuffers +// vs software bitmaps behind a single ResourceId so that code in common can +// hold onto ResourceIds, as long as the code using them knows the correct type. +// It accepts as input TransferableResources which it holds internally, tracks +// state on, and exposes as a ResourceId. +// +// The resource's underlying type is accessed through locks that help to +// scope and safeguard correct usage with DCHECKs. +// +// This class is not thread-safe and can only be called from the thread it was +// created on. +class VIZ_SERVICE_EXPORT DisplayResourceProvider + : public base::trace_event::MemoryDumpProvider { + public: + DisplayResourceProvider(ContextProvider* compositor_context_provider, + SharedBitmapManager* shared_bitmap_manager); + ~DisplayResourceProvider() override; + + bool IsSoftware() const { return !compositor_context_provider_; } + void DidLoseContextProvider() { lost_context_provider_ = true; } + size_t num_resources() const { return resources_.size(); } + + // base::trace_event::MemoryDumpProvider implementation. + bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, + base::trace_event::ProcessMemoryDump* pmd) override; + +#if defined(OS_ANDROID) + // Send an overlay promotion hint to all resources that requested it via + // |wants_promotion_hints_set_|. |promotable_hints| contains all the + // resources that should be told that they're promotable. Others will be told + // that they're not promotable right now. + void SendPromotionHints( + const OverlayCandidateList::PromotionHintInfoMap& promotion_hints); + + // Indicates if this resource is backed by an Android SurfaceTexture, and thus + // can't really be promoted to an overlay. + bool IsBackedBySurfaceTexture(ResourceId id); + + // Indicates if this resource wants to receive promotion hints. + bool WantsPromotionHintForTesting(ResourceId id); + + // Return the number of resources that request promotion hints. + size_t CountPromotionHintRequestsForTesting(); +#endif + + ResourceType GetResourceType(ResourceId id); + GLenum GetResourceTextureTarget(ResourceId id); + // Return the format of the underlying buffer that can be used for scanout. + gfx::BufferFormat GetBufferFormat(ResourceId id); + // Indicates if this resource may be used for a hardware overlay plane. + bool IsOverlayCandidate(ResourceId id); + + void WaitSyncToken(ResourceId id); + + // Checks whether a resource is in use. + bool InUse(ResourceId id); + + // The following lock classes are part of the DisplayResourceProvider API and + // are needed to read the resource contents. The user must ensure that they + // only use GL locks on GL resources, etc, and this is enforced by assertions. + class VIZ_SERVICE_EXPORT ScopedReadLockGL { + public: + ScopedReadLockGL(DisplayResourceProvider* resource_provider, + ResourceId resource_id); + ~ScopedReadLockGL(); + + GLuint texture_id() const { return texture_id_; } + GLenum target() const { return target_; } + const gfx::Size& size() const { return size_; } + const gfx::ColorSpace& color_space() const { return color_space_; } + + private: + DisplayResourceProvider* const resource_provider_; + const ResourceId resource_id_; + + GLuint texture_id_ = 0; + GLenum target_ = GL_TEXTURE_2D; + gfx::Size size_; + gfx::ColorSpace color_space_; + + DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL); + }; + + class VIZ_SERVICE_EXPORT ScopedSamplerGL { + public: + ScopedSamplerGL(DisplayResourceProvider* resource_provider, + ResourceId resource_id, + GLenum filter); + ScopedSamplerGL(DisplayResourceProvider* resource_provider, + ResourceId resource_id, + GLenum unit, + GLenum filter); + ~ScopedSamplerGL(); + + GLuint texture_id() const { return resource_lock_.texture_id(); } + GLenum target() const { return target_; } + const gfx::ColorSpace& color_space() const { + return resource_lock_.color_space(); + } + + private: + const ScopedReadLockGL resource_lock_; + const GLenum unit_; + const GLenum target_; + + DISALLOW_COPY_AND_ASSIGN(ScopedSamplerGL); + }; + + class VIZ_SERVICE_EXPORT ScopedReadLockSkImage { + public: + ScopedReadLockSkImage(DisplayResourceProvider* resource_provider, + ResourceId resource_id); + ~ScopedReadLockSkImage(); + + const SkImage* sk_image() const { return sk_image_.get(); } + + bool valid() const { return !!sk_image_; } + + private: + DisplayResourceProvider* const resource_provider_; + const ResourceId resource_id_; + sk_sp<SkImage> sk_image_; + + DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSkImage); + }; + + class VIZ_SERVICE_EXPORT ScopedReadLockSoftware { + public: + ScopedReadLockSoftware(DisplayResourceProvider* resource_provider, + ResourceId resource_id); + ~ScopedReadLockSoftware(); + + const SkBitmap* sk_bitmap() const { + DCHECK(valid()); + return &sk_bitmap_; + } + + bool valid() const { return !!sk_bitmap_.getPixels(); } + + private: + DisplayResourceProvider* const resource_provider_; + const ResourceId resource_id_; + SkBitmap sk_bitmap_; + + DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware); + }; + + // Maintains set of lock for external use. + class VIZ_SERVICE_EXPORT LockSetForExternalUse { + public: + explicit LockSetForExternalUse(DisplayResourceProvider* resource_provider); + ~LockSetForExternalUse(); + + // Lock a resource for external use. + ResourceMetadata LockResource(ResourceId resource_id); + + // Unlock all locked resources with a |sync_token|. + // See UnlockForExternalUse for the detail. All resources must be unlocked + // before destroying this class. + void UnlockResources(const gpu::SyncToken& sync_token); + + private: + DisplayResourceProvider* const resource_provider_; + std::vector<ResourceId> resources_; + + DISALLOW_COPY_AND_ASSIGN(LockSetForExternalUse); + }; + + // All resources that are returned to children while an instance of this + // class exists will be stored and returned when the instance is destroyed. + class VIZ_SERVICE_EXPORT ScopedBatchReturnResources { + public: + explicit ScopedBatchReturnResources( + DisplayResourceProvider* resource_provider); + ~ScopedBatchReturnResources(); + + private: + DisplayResourceProvider* const resource_provider_; + + DISALLOW_COPY_AND_ASSIGN(ScopedBatchReturnResources); + }; + + class VIZ_SERVICE_EXPORT SynchronousFence : public ResourceFence { + public: + explicit SynchronousFence(gpu::gles2::GLES2Interface* gl); + + // ResourceFence implementation. + void Set() override; + bool HasPassed() override; + void Wait() override; + + // Returns true if fence has been set but not yet synchornized. + bool has_synchronized() const { return has_synchronized_; } + + private: + ~SynchronousFence() override; + + void Synchronize(); + + gpu::gles2::GLES2Interface* gl_; + bool has_synchronized_; + + DISALLOW_COPY_AND_ASSIGN(SynchronousFence); + }; + + // Sets the current read fence. If a resource is locked for read + // and has read fences enabled, the resource will not allow writes + // until this fence has passed. + void SetReadLockFence(ResourceFence* fence) { + current_read_lock_fence_ = fence; + } + + // Creates accounting for a child. Returns a child ID. + int CreateChild(const ReturnCallback& return_callback); + + // Destroys accounting for the child, deleting all accounted resources. + void DestroyChild(int child); + + // Sets whether resources need sync points set on them when returned to this + // child. Defaults to true. + void SetChildNeedsSyncTokens(int child, bool needs_sync_tokens); + + // Gets the child->parent resource ID map. + const std::unordered_map<ResourceId, ResourceId>& GetChildToParentMap( + int child) const; + + // Receives resources from a child, moving them from mailboxes. ResourceIds + // passed are in the child namespace, and will be translated to the parent + // namespace, added to the child->parent map. + // This adds the resources to the working set in the ResourceProvider without + // declaring which resources are in use. Use DeclareUsedResourcesFromChild + // after calling this method to do that. All calls to ReceiveFromChild should + // be followed by a DeclareUsedResourcesFromChild. + // NOTE: if the sync_token is set on any TransferableResource, this will + // wait on it. + void ReceiveFromChild( + int child, + const std::vector<TransferableResource>& transferable_resources); + + // Once a set of resources have been received, they may or may not be used. + // This declares what set of resources are currently in use from the child, + // releasing any other resources back to the child. + void DeclareUsedResourcesFromChild(int child, + const ResourceIdSet& resources_from_child); + + private: + struct Child { + Child(); + Child(const Child& other); + ~Child(); + + std::unordered_map<ResourceId, ResourceId> child_to_parent_map; + ReturnCallback return_callback; + bool marked_for_deletion = false; + bool needs_sync_tokens = true; + }; + + enum DeleteStyle { + NORMAL, + FOR_SHUTDOWN, + }; + + using ChildMap = std::unordered_map<int, Child>; + using ResourceMap = std::unordered_map<ResourceId, internal::Resource>; + + internal::Resource* InsertResource(ResourceId id, + internal::Resource resource); + internal::Resource* GetResource(ResourceId id); + + // TODO(ericrk): TryGetResource is part of a temporary workaround for cases + // where resources which should be available are missing. This version may + // return nullptr if a resource is not found. https://crbug.com/811858 + internal::Resource* TryGetResource(ResourceId id); + + void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap, + const internal::Resource* resource); + + void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style); + + void WaitSyncTokenInternal(internal::Resource* resource); + + // Returns null if we do not have a ContextProvider. + gpu::gles2::GLES2Interface* ContextGL() const; + + const internal::Resource* LockForRead(ResourceId id); + void UnlockForRead(ResourceId id); + + // Lock a resource for external use. + ResourceMetadata LockForExternalUse(ResourceId id); + + // Unlock a resource which locked by LockForExternalUse. + // The |sync_token| should be waited on before reusing the resouce's backing + // to ensure that any external use of it is completed. This |sync_token| + // should have been verified. + void UnlockForExternalUse(ResourceId id, const gpu::SyncToken& sync_token); + + void TryReleaseResource(ResourceMap::iterator it); + // Binds the given GL resource to a texture target for sampling using the + // specified filter for both minification and magnification. Returns the + // texture target used. The resource must be locked for reading. + GLenum BindForSampling(ResourceId resource_id, GLenum unit, GLenum filter); + bool ReadLockFenceHasPassed(const internal::Resource* resource); +#if defined(OS_ANDROID) + void DeletePromotionHint(ResourceMap::iterator it, DeleteStyle style); +#endif + + void DeleteAndReturnUnusedResourcesToChild( + ChildMap::iterator child_it, + DeleteStyle style, + const std::vector<ResourceId>& unused); + void DestroyChildInternal(ChildMap::iterator it, DeleteStyle style); + + void SetBatchReturnResources(bool aggregate); + + THREAD_CHECKER(thread_checker_); + ContextProvider* const compositor_context_provider_; + SharedBitmapManager* const shared_bitmap_manager_; + + ResourceMap resources_; + ChildMap children_; + base::flat_map<ResourceId, sk_sp<SkImage>> resource_sk_image_; + // Maps from a child id to the set of resources to be returned to it. + base::small_map<std::map<int, std::vector<ResourceId>>> + batched_returning_resources_; + scoped_refptr<ResourceFence> current_read_lock_fence_; + // Keep track of whether deleted resources should be batched up or returned + // immediately. + bool batch_return_resources_ = false; + // Set to true when the ContextProvider becomes lost, to inform that resources + // modified by this class are now in an indeterminate state. + bool lost_context_provider_ = false; + // The ResourceIds in DisplayResourceProvider start from 2 to avoid + // conflicts with id from LayerTreeResourceProvider. + ResourceId next_id_ = 2; + // Used as child id when creating a child. + int next_child_ = 1; + // A process-unique ID used for disambiguating memory dumps from different + // resource providers. + int tracing_id_; + +#if defined(OS_ANDROID) + // Set of ResourceIds that would like to be notified about promotion hints. + ResourceIdSet wants_promotion_hints_set_; +#endif + + DISALLOW_COPY_AND_ASSIGN(DisplayResourceProvider); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_ diff --git a/chromium/components/viz/service/display/display_resource_provider_unittest.cc b/chromium/components/viz/service/display/display_resource_provider_unittest.cc new file mode 100644 index 00000000000..af4d091a81a --- /dev/null +++ b/chromium/components/viz/service/display/display_resource_provider_unittest.cc @@ -0,0 +1,1389 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display/display_resource_provider.h" +#include "cc/resources/layer_tree_resource_provider.h" + +#include <stddef.h> +#include <stdint.h> + +#include <algorithm> +#include <map> +#include <memory> +#include <set> +#include <unordered_map> +#include <vector> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/memory/ref_counted.h" +#include "base/memory/shared_memory.h" +#include "build/build_config.h" +#include "cc/test/render_pass_test_utils.h" +#include "cc/test/resource_provider_test_utils.h" +#include "components/viz/common/quads/shared_bitmap.h" +#include "components/viz/common/resources/bitmap_allocation.h" +#include "components/viz/common/resources/resource_format_utils.h" +#include "components/viz/common/resources/returned_resource.h" +#include "components/viz/common/resources/shared_bitmap_manager.h" +#include "components/viz/common/resources/single_release_callback.h" +#include "components/viz/test/test_context_provider.h" +#include "components/viz/test/test_gpu_memory_buffer_manager.h" +#include "components/viz/test/test_shared_bitmap_manager.h" +#include "components/viz/test/test_texture.h" +#include "components/viz/test/test_web_graphics_context_3d.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/gpu_memory_buffer.h" + +using testing::_; +using testing::Return; +using testing::SaveArg; + +namespace viz { +namespace { + +class MockReleaseCallback { + public: + MOCK_METHOD2(Released, void(const gpu::SyncToken& token, bool lost)); +}; + +MATCHER_P(MatchesSyncToken, sync_token, "") { + gpu::SyncToken other; + memcpy(&other, arg, sizeof(other)); + return other == sync_token; +} + +static void CollectResources(std::vector<ReturnedResource>* array, + const std::vector<ReturnedResource>& returned) { + array->insert(array->end(), returned.begin(), returned.end()); +} + +static SharedBitmapId CreateAndFillSharedBitmap(SharedBitmapManager* manager, + const gfx::Size& size, + ResourceFormat format, + uint32_t value) { + SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); + + std::unique_ptr<base::SharedMemory> shm = + bitmap_allocation::AllocateMappedBitmap(size, RGBA_8888); + manager->ChildAllocatedSharedBitmap( + bitmap_allocation::DuplicateAndCloseMappedBitmap(shm.get(), size, + RGBA_8888), + shared_bitmap_id); + + std::fill_n(static_cast<uint32_t*>(shm->memory()), size.GetArea(), value); + return shared_bitmap_id; +} + +// Shared data between multiple ResourceProviderContext. This contains mailbox +// contents as well as information about sync points. +class ContextSharedData { + public: + static std::unique_ptr<ContextSharedData> Create() { + return base::WrapUnique(new ContextSharedData()); + } + + uint32_t InsertFenceSync() { return next_fence_sync_++; } + + void GenMailbox(GLbyte* mailbox) { + memset(mailbox, 0, GL_MAILBOX_SIZE_CHROMIUM); + memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_)); + ++next_mailbox_; + } + + void ProduceTexture(const GLbyte* mailbox_name, + const gpu::SyncToken& sync_token, + scoped_refptr<TestTexture> texture) { + uint32_t sync_point = static_cast<uint32_t>(sync_token.release_count()); + + unsigned mailbox = 0; + memcpy(&mailbox, mailbox_name, sizeof(mailbox)); + ASSERT_TRUE(mailbox && mailbox < next_mailbox_); + textures_[mailbox] = texture; + ASSERT_LT(sync_point_for_mailbox_[mailbox], sync_point); + sync_point_for_mailbox_[mailbox] = sync_point; + } + + scoped_refptr<TestTexture> ConsumeTexture(const GLbyte* mailbox_name, + const gpu::SyncToken& sync_token) { + unsigned mailbox = 0; + memcpy(&mailbox, mailbox_name, sizeof(mailbox)); + DCHECK(mailbox && mailbox < next_mailbox_); + + // If the latest sync point the context has waited on is before the sync + // point for when the mailbox was set, pretend we never saw that + // ProduceTexture. + if (sync_point_for_mailbox_[mailbox] > sync_token.release_count()) { + NOTREACHED(); + return scoped_refptr<TestTexture>(); + } + return textures_[mailbox]; + } + + private: + ContextSharedData() : next_fence_sync_(1), next_mailbox_(1) {} + + uint64_t next_fence_sync_; + unsigned next_mailbox_; + using TextureMap = std::unordered_map<unsigned, scoped_refptr<TestTexture>>; + TextureMap textures_; + std::unordered_map<unsigned, uint32_t> sync_point_for_mailbox_; +}; + +class ResourceProviderContext : public TestWebGraphicsContext3D { + public: + static std::unique_ptr<ResourceProviderContext> Create( + ContextSharedData* shared_data) { + return base::WrapUnique(new ResourceProviderContext(shared_data)); + } + + void genSyncToken(GLbyte* sync_token) override { + uint64_t fence_sync = shared_data_->InsertFenceSync(); + gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x123), + fence_sync); + sync_token_data.SetVerifyFlush(); + // Commit the ProduceTextureDirectCHROMIUM calls at this point, so that + // they're associated with the sync point. + for (const std::unique_ptr<PendingProduceTexture>& pending_texture : + pending_produce_textures_) { + shared_data_->ProduceTexture(pending_texture->mailbox, sync_token_data, + pending_texture->texture); + } + pending_produce_textures_.clear(); + memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)); + } + + void waitSyncToken(const GLbyte* sync_token) override { + gpu::SyncToken sync_token_data; + if (sync_token) + memcpy(&sync_token_data, sync_token, sizeof(sync_token_data)); + + if (sync_token_data.release_count() > + last_waited_sync_token_.release_count()) { + last_waited_sync_token_ = sync_token_data; + } + } + + const gpu::SyncToken& last_waited_sync_token() const { + return last_waited_sync_token_; + } + + void texStorage2DEXT(GLenum target, + GLint levels, + GLuint internalformat, + GLint width, + GLint height) override { + CheckTextureIsBound(target); + ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); + ASSERT_EQ(1, levels); + GLenum format = GL_RGBA; + switch (internalformat) { + case GL_RGBA8_OES: + break; + case GL_BGRA8_EXT: + format = GL_BGRA_EXT; + break; + default: + NOTREACHED(); + } + AllocateTexture(gfx::Size(width, height), format); + } + + void texImage2D(GLenum target, + GLint level, + GLenum internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const void* pixels) override { + CheckTextureIsBound(target); + ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); + ASSERT_FALSE(level); + ASSERT_EQ(internalformat, format); + ASSERT_FALSE(border); + ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); + AllocateTexture(gfx::Size(width, height), format); + if (pixels) + SetPixels(0, 0, width, height, pixels); + } + + void texSubImage2D(GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const void* pixels) override { + CheckTextureIsBound(target); + ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); + ASSERT_FALSE(level); + ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); + { + base::AutoLock lock_for_texture_access(namespace_->lock); + ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format); + } + ASSERT_TRUE(pixels); + SetPixels(xoffset, yoffset, width, height, pixels); + } + + void genMailboxCHROMIUM(GLbyte* mailbox) override { + return shared_data_->GenMailbox(mailbox); + } + + void produceTextureDirectCHROMIUM(GLuint texture, + const GLbyte* mailbox) override { + // Delay moving the texture into the mailbox until the next + // sync token, so that it is not visible to other contexts that + // haven't waited on that sync point. + std::unique_ptr<PendingProduceTexture> pending(new PendingProduceTexture); + memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox)); + base::AutoLock lock_for_texture_access(namespace_->lock); + pending->texture = UnboundTexture(texture); + pending_produce_textures_.push_back(std::move(pending)); + } + + GLuint createAndConsumeTextureCHROMIUM(const GLbyte* mailbox) override { + GLuint texture_id = createTexture(); + base::AutoLock lock_for_texture_access(namespace_->lock); + scoped_refptr<TestTexture> texture = + shared_data_->ConsumeTexture(mailbox, last_waited_sync_token_); + namespace_->textures.Replace(texture_id, texture); + return texture_id; + } + + void GetPixels(const gfx::Size& size, + ResourceFormat format, + uint8_t* pixels) { + CheckTextureIsBound(GL_TEXTURE_2D); + base::AutoLock lock_for_texture_access(namespace_->lock); + scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D); + ASSERT_EQ(texture->size, size); + ASSERT_EQ(texture->format, format); + memcpy(pixels, texture->data.get(), TextureSizeBytes(size, format)); + } + + protected: + explicit ResourceProviderContext(ContextSharedData* shared_data) + : shared_data_(shared_data) {} + + private: + void AllocateTexture(const gfx::Size& size, GLenum format) { + CheckTextureIsBound(GL_TEXTURE_2D); + ResourceFormat texture_format = RGBA_8888; + switch (format) { + case GL_RGBA: + texture_format = RGBA_8888; + break; + case GL_BGRA_EXT: + texture_format = BGRA_8888; + break; + } + base::AutoLock lock_for_texture_access(namespace_->lock); + BoundTexture(GL_TEXTURE_2D)->Reallocate(size, texture_format); + } + + void SetPixels(int xoffset, + int yoffset, + int width, + int height, + const void* pixels) { + CheckTextureIsBound(GL_TEXTURE_2D); + base::AutoLock lock_for_texture_access(namespace_->lock); + scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D); + ASSERT_TRUE(texture->data.get()); + ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width()); + ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height()); + ASSERT_TRUE(pixels); + size_t in_pitch = TextureSizeBytes(gfx::Size(width, 1), texture->format); + size_t out_pitch = + TextureSizeBytes(gfx::Size(texture->size.width(), 1), texture->format); + uint8_t* dest = texture->data.get() + yoffset * out_pitch + + TextureSizeBytes(gfx::Size(xoffset, 1), texture->format); + const uint8_t* src = static_cast<const uint8_t*>(pixels); + for (int i = 0; i < height; ++i) { + memcpy(dest, src, in_pitch); + dest += out_pitch; + src += in_pitch; + } + } + + struct PendingProduceTexture { + GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM]; + scoped_refptr<TestTexture> texture; + }; + ContextSharedData* shared_data_; + gpu::SyncToken last_waited_sync_token_; + std::vector<std::unique_ptr<PendingProduceTexture>> pending_produce_textures_; +}; + +class DisplayResourceProviderTest : public testing::TestWithParam<bool> { + public: + explicit DisplayResourceProviderTest(bool child_needs_sync_token) + : use_gpu_(GetParam()), + child_needs_sync_token_(child_needs_sync_token), + shared_data_(ContextSharedData::Create()) { + if (use_gpu_) { + auto context3d(ResourceProviderContext::Create(shared_data_.get())); + context3d_ = context3d.get(); + context_provider_ = TestContextProvider::Create(std::move(context3d)); + context_provider_->UnboundTestContext3d() + ->set_support_texture_format_bgra8888(true); + context_provider_->BindToCurrentThread(); + + auto child_context_owned = + ResourceProviderContext::Create(shared_data_.get()); + child_context_ = child_context_owned.get(); + child_context_provider_ = + TestContextProvider::Create(std::move(child_context_owned)); + child_context_provider_->UnboundTestContext3d() + ->set_support_texture_format_bgra8888(true); + child_context_provider_->BindToCurrentThread(); + gpu_memory_buffer_manager_ = + std::make_unique<TestGpuMemoryBufferManager>(); + } else { + shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>(); + } + + resource_provider_ = std::make_unique<DisplayResourceProvider>( + context_provider_.get(), shared_bitmap_manager_.get()); + + MakeChildResourceProvider(); + } + + DisplayResourceProviderTest() : DisplayResourceProviderTest(true) {} + + bool use_gpu() const { return use_gpu_; } + + void MakeChildResourceProvider() { + child_resource_provider_ = std::make_unique<cc::LayerTreeResourceProvider>( + child_context_provider_.get(), child_needs_sync_token_); + } + + static ReturnCallback GetReturnCallback( + std::vector<ReturnedResource>* array) { + return base::BindRepeating(&CollectResources, array); + } + + static void SetResourceFilter(DisplayResourceProvider* resource_provider, + ResourceId id, + GLenum filter) { + DisplayResourceProvider::ScopedSamplerGL sampler(resource_provider, id, + GL_TEXTURE_2D, filter); + } + + ResourceProviderContext* context() { return context3d_; } + + TransferableResource CreateResource(ResourceFormat format) { + if (use_gpu()) { + unsigned texture = child_context_->createTexture(); + gpu::Mailbox gpu_mailbox; + child_context_->genMailboxCHROMIUM(gpu_mailbox.name); + child_context_->produceTextureDirectCHROMIUM(texture, gpu_mailbox.name); + gpu::SyncToken sync_token; + child_context_->genSyncToken(sync_token.GetData()); + EXPECT_TRUE(sync_token.HasData()); + + TransferableResource gl_resource = TransferableResource::MakeGL( + gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token); + gl_resource.format = format; + return gl_resource; + } else { + gfx::Size size(64, 64); + SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap( + shared_bitmap_manager_.get(), size, format, 0); + + return TransferableResource::MakeSoftware(shared_bitmap_id, size, format); + } + } + + ResourceId MakeGpuResourceAndSendToDisplay( + char c, + GLuint filter, + GLuint target, + const gpu::SyncToken& sync_token, + DisplayResourceProvider* resource_provider) { + ReturnCallback return_callback = base::DoNothing(); + + int child = resource_provider->CreateChild(return_callback); + + gpu::Mailbox gpu_mailbox; + gpu_mailbox.name[0] = c; + gpu_mailbox.name[1] = 0; + auto resource = TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR, target, + sync_token); + resource.id = 11; + resource_provider->ReceiveFromChild(child, {resource}); + auto& map = resource_provider->GetChildToParentMap(child); + return map.find(resource.id)->second; + } + + protected: + const bool use_gpu_; + const bool child_needs_sync_token_; + const std::unique_ptr<ContextSharedData> shared_data_; + ResourceProviderContext* context3d_ = nullptr; + ResourceProviderContext* child_context_ = nullptr; + scoped_refptr<TestContextProvider> context_provider_; + scoped_refptr<TestContextProvider> child_context_provider_; + std::unique_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; + std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_; + std::unique_ptr<TestSharedBitmapManager> shared_bitmap_manager_; +}; + +INSTANTIATE_TEST_CASE_P(DisplayResourceProviderTests, + DisplayResourceProviderTest, + ::testing::Values(false, true)); + +TEST_P(DisplayResourceProviderTest, LockForExternalUse) { + // TODO(penghuang): consider supporting SW mode. + if (!use_gpu()) + return; + + gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x123), + 0x42); + auto mailbox = gpu::Mailbox::Generate(); + TransferableResource gl_resource = TransferableResource::MakeGL( + mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token1); + ResourceId id1 = child_resource_provider_->ImportResource( + gl_resource, SingleReleaseCallback::Create(base::DoNothing())); + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent({id1}, &list, + child_context_provider_.get()); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + unsigned parent_id = resource_map[list.front().id]; + + DisplayResourceProvider::LockSetForExternalUse lock_set( + resource_provider_.get()); + + ResourceMetadata metadata = lock_set.LockResource(parent_id); + ASSERT_EQ(metadata.mailbox, mailbox); + ASSERT_TRUE(metadata.sync_token.HasData()); + + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + // The resource should not be returned due to the external use lock. + EXPECT_EQ(0u, returned_to_child.size()); + + gpu::SyncToken sync_token2(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x234), + 0x456); + sync_token2.SetVerifyFlush(); + lock_set.UnlockResources(sync_token2); + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + // The resource should be returned after the lock is released. + EXPECT_EQ(1u, returned_to_child.size()); + EXPECT_EQ(sync_token2, returned_to_child[0].sync_token); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + child_resource_provider_->RemoveImportedResource(id1); +} + +TEST_P(DisplayResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) { + if (!use_gpu()) + return; + + MockReleaseCallback release; + TransferableResource tran = CreateResource(RGBA_8888); + ResourceId id1 = child_resource_provider_->ImportResource( + tran, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + { + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent( + {id1}, &list, child_context_provider_.get()); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceId mapped_resource_id = resource_map[list[0].id]; + resource_provider_->WaitSyncToken(mapped_resource_id); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), + mapped_resource_id); + + resource_provider_->DeclareUsedResourcesFromChild(child_id, + ResourceIdSet()); + EXPECT_EQ(0u, returned_to_child.size()); + } + + EXPECT_EQ(1u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + + // No need to wait for the sync token here -- it will be returned to the + // client on delete. + { + EXPECT_CALL(release, Released(_, _)); + child_resource_provider_->RemoveImportedResource(id1); + } + + resource_provider_->DestroyChild(child_id); +} + +class TestFence : public ResourceFence { + public: + TestFence() = default; + + // ResourceFence implementation. + void Set() override {} + bool HasPassed() override { return passed; } + void Wait() override {} + + bool passed = false; + + private: + ~TestFence() override = default; +}; + +TEST_P(DisplayResourceProviderTest, ReadLockFenceStopsReturnToChildOrDelete) { + if (!use_gpu()) + return; + + MockReleaseCallback release; + TransferableResource tran1 = CreateResource(RGBA_8888); + tran1.read_lock_fences_enabled = true; + ResourceId id1 = child_resource_provider_->ImportResource( + tran1, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent({id1}, &list, + child_context_provider_.get()); + ASSERT_EQ(1u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(list[0].read_lock_fences_enabled); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + scoped_refptr<TestFence> fence(new TestFence); + resource_provider_->SetReadLockFence(fence.get()); + { + unsigned parent_id = resource_map[list.front().id]; + resource_provider_->WaitSyncToken(parent_id); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), + parent_id); + } + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(0u, returned_to_child.size()); + + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(0u, returned_to_child.size()); + fence->passed = true; + + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(1u, returned_to_child.size()); + + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + EXPECT_CALL(release, Released(_, _)); + child_resource_provider_->RemoveImportedResource(id1); +} + +TEST_P(DisplayResourceProviderTest, ReadLockFenceDestroyChild) { + if (!use_gpu()) + return; + + MockReleaseCallback release; + + TransferableResource tran1 = CreateResource(RGBA_8888); + tran1.read_lock_fences_enabled = true; + ResourceId id1 = child_resource_provider_->ImportResource( + tran1, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + + TransferableResource tran2 = CreateResource(RGBA_8888); + tran2.read_lock_fences_enabled = false; + ResourceId id2 = child_resource_provider_->ImportResource( + tran2, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent({id1, id2}, &list, + child_context_provider_.get()); + ASSERT_EQ(2u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + scoped_refptr<TestFence> fence(new TestFence); + resource_provider_->SetReadLockFence(fence.get()); + { + for (size_t i = 0; i < list.size(); i++) { + unsigned parent_id = resource_map[list[i].id]; + resource_provider_->WaitSyncToken(parent_id); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), + parent_id); + } + } + EXPECT_EQ(0u, returned_to_child.size()); + + EXPECT_EQ(2u, resource_provider_->num_resources()); + + resource_provider_->DestroyChild(child_id); + + EXPECT_EQ(0u, resource_provider_->num_resources()); + EXPECT_EQ(2u, returned_to_child.size()); + + // id1 should be lost and id2 should not. + EXPECT_EQ(returned_to_child[0].lost, returned_to_child[0].id == id1); + EXPECT_EQ(returned_to_child[1].lost, returned_to_child[1].id == id1); + + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + EXPECT_CALL(release, Released(_, _)).Times(2); + child_resource_provider_->RemoveImportedResource(id1); + child_resource_provider_->RemoveImportedResource(id2); +} + +TEST_P(DisplayResourceProviderTest, ReadLockFenceContextLost) { + if (!use_gpu()) + return; + + TransferableResource tran1 = CreateResource(RGBA_8888); + tran1.read_lock_fences_enabled = true; + ResourceId id1 = child_resource_provider_->ImportResource( + tran1, SingleReleaseCallback::Create(base::DoNothing())); + + TransferableResource tran2 = CreateResource(RGBA_8888); + tran2.read_lock_fences_enabled = false; + ResourceId id2 = child_resource_provider_->ImportResource( + tran2, SingleReleaseCallback::Create(base::DoNothing())); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent({id1, id2}, &list, + child_context_provider_.get()); + ASSERT_EQ(2u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1)); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2)); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + scoped_refptr<TestFence> fence(new TestFence); + resource_provider_->SetReadLockFence(fence.get()); + { + for (size_t i = 0; i < list.size(); i++) { + unsigned parent_id = resource_map[list[i].id]; + resource_provider_->WaitSyncToken(parent_id); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), + parent_id); + } + } + EXPECT_EQ(0u, returned_to_child.size()); + + EXPECT_EQ(2u, resource_provider_->num_resources()); + resource_provider_->DidLoseContextProvider(); + resource_provider_ = nullptr; + + EXPECT_EQ(2u, returned_to_child.size()); + + EXPECT_TRUE(returned_to_child[0].lost); + EXPECT_TRUE(returned_to_child[1].lost); +} + +TEST_P(DisplayResourceProviderTest, ReturnResourcesWithoutSyncToken) { + if (!use_gpu()) + return; + + bool need_sync_tokens = false; + auto no_token_resource_provider = + std::make_unique<cc::LayerTreeResourceProvider>( + child_context_provider_.get(), need_sync_tokens); + + GLuint external_texture_id = child_context_->createExternalTexture(); + + // A sync point is specified directly and should be used. + gpu::Mailbox external_mailbox; + child_context_->genMailboxCHROMIUM(external_mailbox.name); + child_context_->produceTextureDirectCHROMIUM(external_texture_id, + external_mailbox.name); + gpu::SyncToken external_sync_token; + child_context_->genSyncToken(external_sync_token.GetData()); + EXPECT_TRUE(external_sync_token.HasData()); + ResourceId id = no_token_resource_provider->ImportResource( + TransferableResource::MakeGL(external_mailbox, GL_LINEAR, + GL_TEXTURE_EXTERNAL_OES, + external_sync_token), + SingleReleaseCallback::Create(base::DoNothing())); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + resource_provider_->SetChildNeedsSyncTokens(child_id, false); + { + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + no_token_resource_provider->PrepareSendToParent( + {id}, &list, child_context_provider_.get()); + ASSERT_EQ(1u, list.size()); + // A given sync point should be passed through. + EXPECT_EQ(external_sync_token, list[0].mailbox_holder.sync_token); + resource_provider_->ReceiveFromChild(child_id, list); + + ResourceIdSet resource_ids_to_receive; + resource_ids_to_receive.insert(id); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_receive); + } + + { + EXPECT_EQ(0u, returned_to_child.size()); + + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + ResourceIdSet no_resources; + resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources); + + ASSERT_EQ(1u, returned_to_child.size()); + std::map<ResourceId, gpu::SyncToken> returned_sync_tokens; + for (const auto& returned : returned_to_child) + returned_sync_tokens[returned.id] = returned.sync_token; + + // Original sync point given should be returned. + ASSERT_TRUE(returned_sync_tokens.find(id) != returned_sync_tokens.end()); + EXPECT_EQ(external_sync_token, returned_sync_tokens[id]); + EXPECT_FALSE(returned_to_child[0].lost); + no_token_resource_provider->ReceiveReturnsFromParent(returned_to_child); + returned_to_child.clear(); + } + + resource_provider_->DestroyChild(child_id); +} + +// Test that ScopedBatchReturnResources batching works. +TEST_P(DisplayResourceProviderTest, ScopedBatchReturnResourcesPreventsReturn) { + if (!use_gpu()) + return; + + MockReleaseCallback release; + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<ResourceId> resource_ids_to_transfer; + ResourceId ids[2]; + for (size_t i = 0; i < base::size(ids); i++) { + TransferableResource tran = CreateResource(RGBA_8888); + ids[i] = child_resource_provider_->ImportResource( + tran, SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + resource_ids_to_transfer.push_back(ids[i]); + } + + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list, + child_context_provider_.get()); + ASSERT_EQ(2u, list.size()); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(ids[0])); + EXPECT_TRUE(child_resource_provider_->InUseByConsumer(ids[1])); + + resource_provider_->ReceiveFromChild(child_id, list); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + + std::vector<std::unique_ptr<DisplayResourceProvider::ScopedReadLockGL>> + read_locks; + for (auto& resource_id : list) { + unsigned int mapped_resource_id = resource_map[resource_id.id]; + resource_provider_->WaitSyncToken(mapped_resource_id); + read_locks.push_back( + std::make_unique<DisplayResourceProvider::ScopedReadLockGL>( + resource_provider_.get(), mapped_resource_id)); + } + + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + std::unique_ptr<DisplayResourceProvider::ScopedBatchReturnResources> + returner = + std::make_unique<DisplayResourceProvider::ScopedBatchReturnResources>( + resource_provider_.get()); + EXPECT_EQ(0u, returned_to_child.size()); + + read_locks.clear(); + EXPECT_EQ(0u, returned_to_child.size()); + + returner.reset(); + EXPECT_EQ(2u, returned_to_child.size()); + // All resources in a batch should share a sync token. + EXPECT_EQ(returned_to_child[0].sync_token, returned_to_child[1].sync_token); + + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + EXPECT_CALL(release, Released(_, _)).Times(2); + child_resource_provider_->RemoveImportedResource(ids[0]); + child_resource_provider_->RemoveImportedResource(ids[1]); +} + +TEST_P(DisplayResourceProviderTest, LostMailboxInParent) { + gpu::Mailbox gpu_mailbox; + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34); + auto tran = TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR, + GL_TEXTURE_2D, sync_token); + tran.id = 11; + + std::vector<ReturnedResource> returned_to_child; + int child_id = resource_provider_->CreateChild( + base::BindRepeating(&CollectResources, &returned_to_child)); + + // Receive a resource then lose the gpu context. + resource_provider_->ReceiveFromChild(child_id, {tran}); + resource_provider_->DidLoseContextProvider(); + + // Transfer resources back from the parent to the child. + resource_provider_->DeclareUsedResourcesFromChild(child_id, {}); + ASSERT_EQ(1u, returned_to_child.size()); + + // Losing an output surface only loses hardware resources. + EXPECT_EQ(returned_to_child[0].lost, use_gpu()); +} + +TEST_P(DisplayResourceProviderTest, ReadSoftwareResources) { + if (use_gpu()) + return; + + gfx::Size size(64, 64); + ResourceFormat format = RGBA_8888; + const uint32_t kBadBeef = 0xbadbeef; + SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap( + shared_bitmap_manager_.get(), size, format, kBadBeef); + + auto resource = + TransferableResource::MakeSoftware(shared_bitmap_id, size, format); + + MockReleaseCallback release; + ResourceId resource_id = child_resource_provider_->ImportResource( + resource, + SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + EXPECT_NE(0u, resource_id); + + // Transfer resources to the parent. + std::vector<TransferableResource> send_to_parent; + std::vector<ReturnedResource> returned_to_child; + int child_id = resource_provider_->CreateChild( + base::BindRepeating(&CollectResources, &returned_to_child)); + child_resource_provider_->PrepareSendToParent({resource_id}, &send_to_parent, + child_context_provider_.get()); + resource_provider_->ReceiveFromChild(child_id, send_to_parent); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceId mapped_resource_id = resource_map[resource_id]; + + { + DisplayResourceProvider::ScopedReadLockSoftware lock( + resource_provider_.get(), mapped_resource_id); + const SkBitmap* sk_bitmap = lock.sk_bitmap(); + EXPECT_EQ(sk_bitmap->width(), size.width()); + EXPECT_EQ(sk_bitmap->height(), size.height()); + EXPECT_EQ(*sk_bitmap->getAddr32(16, 16), kBadBeef); + } + + EXPECT_EQ(0u, returned_to_child.size()); + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(1u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + + EXPECT_CALL(release, Released(_, false)); + child_resource_provider_->RemoveImportedResource(resource_id); +} + +class TextureStateTrackingContext : public TestWebGraphicsContext3D { + public: + MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture)); + MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param)); + MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token)); + MOCK_METHOD2(produceTextureDirectCHROMIUM, + void(GLuint texture, const GLbyte* mailbox)); + MOCK_METHOD1(createAndConsumeTextureCHROMIUM, + unsigned(const GLbyte* mailbox)); + + // Force all textures to be consecutive numbers starting at "1", + // so we easily can test for them. + GLuint NextTextureId() override { + base::AutoLock lock(namespace_->lock); + return namespace_->next_texture_id++; + } + + void RetireTextureId(GLuint) override {} + + void genSyncToken(GLbyte* sync_token) override { + gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x123), + next_fence_sync_++); + sync_token_data.SetVerifyFlush(); + memcpy(sync_token, &sync_token_data, sizeof(sync_token_data)); + } + + GLuint64 GetNextFenceSync() const { return next_fence_sync_; } + + GLuint64 next_fence_sync_ = 1; +}; + +class ResourceProviderTestImportedResourceGLFilters { + public: + static void RunTest(TestSharedBitmapManager* shared_bitmap_manager, + bool mailbox_nearest_neighbor, + GLenum sampler_filter) { + auto context_owned(std::make_unique<TextureStateTrackingContext>()); + TextureStateTrackingContext* context = context_owned.get(); + auto context_provider = + TestContextProvider::Create(std::move(context_owned)); + context_provider->BindToCurrentThread(); + + auto resource_provider = std::make_unique<DisplayResourceProvider>( + context_provider.get(), shared_bitmap_manager); + + auto child_context_owned = std::make_unique<TextureStateTrackingContext>(); + TextureStateTrackingContext* child_context = child_context_owned.get(); + auto child_context_provider = + TestContextProvider::Create(std::move(child_context_owned)); + child_context_provider->BindToCurrentThread(); + + auto child_resource_provider = + std::make_unique<cc::LayerTreeResourceProvider>( + child_context_provider.get(), + /*delegated_sync_points_required=*/true); + + unsigned texture_id = 1; + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x12), + 0x34); + const GLuint64 current_fence_sync = child_context->GetNextFenceSync(); + + EXPECT_CALL(*child_context, bindTexture(_, _)).Times(0); + EXPECT_CALL(*child_context, waitSyncToken(_)).Times(0); + EXPECT_CALL(*child_context, produceTextureDirectCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*child_context, createAndConsumeTextureCHROMIUM(_)).Times(0); + + gpu::Mailbox gpu_mailbox; + memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); + GLuint filter = mailbox_nearest_neighbor ? GL_NEAREST : GL_LINEAR; + auto resource = TransferableResource::MakeGL(gpu_mailbox, filter, + GL_TEXTURE_2D, sync_token); + + MockReleaseCallback release; + ResourceId resource_id = child_resource_provider->ImportResource( + resource, + SingleReleaseCallback::Create(base::BindOnce( + &MockReleaseCallback::Released, base::Unretained(&release)))); + EXPECT_NE(0u, resource_id); + EXPECT_EQ(current_fence_sync, child_context->GetNextFenceSync()); + + testing::Mock::VerifyAndClearExpectations(child_context); + + // Transfer resources to the parent. + std::vector<TransferableResource> send_to_parent; + std::vector<ReturnedResource> returned_to_child; + int child_id = resource_provider->CreateChild( + base::BindRepeating(&CollectResources, &returned_to_child)); + child_resource_provider->PrepareSendToParent({resource_id}, &send_to_parent, + child_context_provider.get()); + resource_provider->ReceiveFromChild(child_id, send_to_parent); + + // In DisplayResourceProvider's namespace, use the mapped resource id. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider->GetChildToParentMap(child_id); + ResourceId mapped_resource_id = resource_map[resource_id]; + { + // The verified flush flag will be set by + // cc::LayerTreeResourceProvider::PrepareSendToParent. Before checking if + // the gpu::SyncToken matches, set this flag first. + sync_token.SetVerifyFlush(); + + // Mailbox sync point WaitSyncToken before using the texture. + EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))); + resource_provider->WaitSyncToken(mapped_resource_id); + testing::Mock::VerifyAndClearExpectations(context); + + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_)) + .WillOnce(Return(texture_id)); + EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); + + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0); + + // The sampler will reset these if |mailbox_nearest_neighbor| does not + // match |sampler_filter|. + if (mailbox_nearest_neighbor != (sampler_filter == GL_NEAREST)) { + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + sampler_filter)); + EXPECT_CALL(*context, + texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + sampler_filter)); + } + + DisplayResourceProvider::ScopedSamplerGL lock( + resource_provider.get(), mapped_resource_id, sampler_filter); + testing::Mock::VerifyAndClearExpectations(context); + EXPECT_EQ(current_fence_sync, context->GetNextFenceSync()); + + // When done with it, a sync point should be inserted, but no produce is + // necessary. + EXPECT_CALL(*child_context, bindTexture(_, _)).Times(0); + EXPECT_CALL(*child_context, produceTextureDirectCHROMIUM(_, _)).Times(0); + + EXPECT_CALL(*child_context, waitSyncToken(_)).Times(0); + EXPECT_CALL(*child_context, createAndConsumeTextureCHROMIUM(_)).Times(0); + } + + EXPECT_EQ(0u, returned_to_child.size()); + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + resource_provider->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(1u, returned_to_child.size()); + child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + + gpu::SyncToken released_sync_token; + { + EXPECT_CALL(release, Released(_, false)) + .WillOnce(SaveArg<0>(&released_sync_token)); + child_resource_provider->RemoveImportedResource(resource_id); + } + EXPECT_TRUE(released_sync_token.HasData()); + } +}; + +TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_LinearToLinear) { + // Mailboxing is only supported for GL textures. + if (!use_gpu()) + return; + + ResourceProviderTestImportedResourceGLFilters::RunTest( + shared_bitmap_manager_.get(), false, GL_LINEAR); +} + +TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_NearestToNearest) { + // Mailboxing is only supported for GL textures. + if (!use_gpu()) + return; + + ResourceProviderTestImportedResourceGLFilters::RunTest( + shared_bitmap_manager_.get(), true, GL_NEAREST); +} + +TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_NearestToLinear) { + // Mailboxing is only supported for GL textures. + if (!use_gpu()) + return; + + ResourceProviderTestImportedResourceGLFilters::RunTest( + shared_bitmap_manager_.get(), true, GL_LINEAR); +} + +TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_LinearToNearest) { + // Mailboxing is only supported for GL textures. + if (!use_gpu()) + return; + + ResourceProviderTestImportedResourceGLFilters::RunTest( + shared_bitmap_manager_.get(), false, GL_NEAREST); +} + +TEST_P(DisplayResourceProviderTest, ReceiveGLTextureExternalOES) { + // Mailboxing is only supported for GL textures. + if (!use_gpu()) + return; + + auto context_owned(std::make_unique<TextureStateTrackingContext>()); + TextureStateTrackingContext* context = context_owned.get(); + auto context_provider = TestContextProvider::Create(std::move(context_owned)); + context_provider->BindToCurrentThread(); + + auto resource_provider = std::make_unique<DisplayResourceProvider>( + context_provider.get(), shared_bitmap_manager_.get()); + + auto child_context_owned = std::make_unique<TextureStateTrackingContext>(); + TextureStateTrackingContext* child_context = child_context_owned.get(); + auto child_context_provider = + TestContextProvider::Create(std::move(child_context_owned)); + child_context_provider->BindToCurrentThread(); + + auto child_resource_provider = + std::make_unique<cc::LayerTreeResourceProvider>( + child_context_provider.get(), + /*delegated_sync_points_required=*/true); + + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34); + const GLuint64 current_fence_sync = child_context->GetNextFenceSync(); + + EXPECT_CALL(*child_context, bindTexture(_, _)).Times(0); + EXPECT_CALL(*child_context, waitSyncToken(_)).Times(0); + EXPECT_CALL(*child_context, produceTextureDirectCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*child_context, createAndConsumeTextureCHROMIUM(_)).Times(0); + + gpu::Mailbox gpu_mailbox; + memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); + std::unique_ptr<SingleReleaseCallback> callback = + SingleReleaseCallback::Create(base::DoNothing()); + + auto resource = TransferableResource::MakeGL( + gpu_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, sync_token); + + ResourceId resource_id = + child_resource_provider->ImportResource(resource, std::move(callback)); + EXPECT_NE(0u, resource_id); + EXPECT_EQ(current_fence_sync, child_context->GetNextFenceSync()); + + testing::Mock::VerifyAndClearExpectations(child_context); + + // Transfer resources to the parent. + std::vector<TransferableResource> send_to_parent; + std::vector<ReturnedResource> returned_to_child; + int child_id = resource_provider->CreateChild( + base::BindRepeating(&CollectResources, &returned_to_child)); + child_resource_provider->PrepareSendToParent({resource_id}, &send_to_parent, + child_context_provider_.get()); + resource_provider->ReceiveFromChild(child_id, send_to_parent); + + // Before create DrawQuad in DisplayResourceProvider's namespace, get the + // mapped resource id first. + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider->GetChildToParentMap(child_id); + ResourceId mapped_resource_id = resource_map[resource_id]; + { + // The verified flush flag will be set by + // cc::LayerTreeResourceProvider::PrepareSendToParent. Before checking if + // the gpu::SyncToken matches, set this flag first. + sync_token.SetVerifyFlush(); + + // Mailbox sync point WaitSyncToken before using the texture. + EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))); + resource_provider->WaitSyncToken(mapped_resource_id); + testing::Mock::VerifyAndClearExpectations(context); + + unsigned texture_id = 1; + + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_)) + .WillOnce(Return(texture_id)); + + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0); + + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider.get(), + mapped_resource_id); + testing::Mock::VerifyAndClearExpectations(context); + + // When done with it, a sync point should be inserted, but no produce is + // necessary. + EXPECT_CALL(*context, bindTexture(_, _)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0); + + EXPECT_CALL(*context, waitSyncToken(_)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_)).Times(0); + testing::Mock::VerifyAndClearExpectations(context); + } + EXPECT_EQ(0u, returned_to_child.size()); + // Transfer resources back from the parent to the child. Set no resources as + // being in use. + resource_provider->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(1u, returned_to_child.size()); + child_resource_provider->ReceiveReturnsFromParent(returned_to_child); + + child_resource_provider->RemoveImportedResource(resource_id); +} + +TEST_P(DisplayResourceProviderTest, WaitSyncTokenIfNeeded) { + // Mailboxing is only supported for GL textures. + if (!use_gpu()) + return; + + auto context_owned = std::make_unique<TextureStateTrackingContext>(); + TextureStateTrackingContext* context = context_owned.get(); + auto context_provider = TestContextProvider::Create(std::move(context_owned)); + context_provider->BindToCurrentThread(); + + auto resource_provider = std::make_unique<DisplayResourceProvider>( + context_provider.get(), shared_bitmap_manager_.get()); + + const GLuint64 current_fence_sync = context->GetNextFenceSync(); + + EXPECT_CALL(*context, bindTexture(_, _)).Times(0); + EXPECT_CALL(*context, waitSyncToken(_)).Times(0); + EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0); + EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_)).Times(0); + + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, + gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34); + ResourceId id_with_sync = MakeGpuResourceAndSendToDisplay( + 'a', GL_LINEAR, GL_TEXTURE_2D, sync_token, resource_provider.get()); + ResourceId id_without_sync = MakeGpuResourceAndSendToDisplay( + 'a', GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(), resource_provider.get()); + + EXPECT_EQ(current_fence_sync, context->GetNextFenceSync()); + + // First call to WaitSyncToken should call WaitSyncToken, but only if a + // SyncToken was present. + { + EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))).Times(1); + resource_provider->WaitSyncToken(id_with_sync); + EXPECT_CALL(*context, waitSyncToken(_)).Times(0); + resource_provider->WaitSyncToken(id_without_sync); + } + + { + // Subsequent calls to WaitSyncToken shouldn't call WaitSyncToken. + EXPECT_CALL(*context, waitSyncToken(_)).Times(0); + resource_provider->WaitSyncToken(id_with_sync); + resource_provider->WaitSyncToken(id_without_sync); + } +} + +#if defined(OS_ANDROID) +TEST_P(DisplayResourceProviderTest, OverlayPromotionHint) { + if (!use_gpu()) + return; + + GLuint external_texture_id = child_context_->createExternalTexture(); + + gpu::Mailbox external_mailbox; + child_context_->genMailboxCHROMIUM(external_mailbox.name); + child_context_->produceTextureDirectCHROMIUM(external_texture_id, + external_mailbox.name); + gpu::SyncToken external_sync_token; + child_context_->genSyncToken(external_sync_token.GetData()); + EXPECT_TRUE(external_sync_token.HasData()); + + TransferableResource id1_transfer = TransferableResource::MakeGLOverlay( + external_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, external_sync_token, + gfx::Size(1, 1), true); + id1_transfer.wants_promotion_hint = true; + id1_transfer.is_backed_by_surface_texture = true; + ResourceId id1 = child_resource_provider_->ImportResource( + id1_transfer, SingleReleaseCallback::Create(base::DoNothing())); + + TransferableResource id2_transfer = TransferableResource::MakeGLOverlay( + external_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, external_sync_token, + gfx::Size(1, 1), true); + id2_transfer.wants_promotion_hint = false; + id2_transfer.is_backed_by_surface_texture = false; + ResourceId id2 = child_resource_provider_->ImportResource( + id2_transfer, SingleReleaseCallback::Create(base::DoNothing())); + + std::vector<ReturnedResource> returned_to_child; + int child_id = + resource_provider_->CreateChild(GetReturnCallback(&returned_to_child)); + + // Transfer some resources to the parent. + std::vector<TransferableResource> list; + child_resource_provider_->PrepareSendToParent({id1, id2}, &list, + child_context_provider_.get()); + ASSERT_EQ(2u, list.size()); + resource_provider_->ReceiveFromChild(child_id, list); + std::unordered_map<ResourceId, ResourceId> resource_map = + resource_provider_->GetChildToParentMap(child_id); + ResourceId mapped_id1 = resource_map[list[0].id]; + ResourceId mapped_id2 = resource_map[list[1].id]; + + // The promotion hints should not be recorded until after we wait. This is + // because we can't notify them until they're synchronized, and we choose to + // ignore unwaited resources rather than send them a "no" hint. If they end + // up in the request set before we wait, then the attempt to notify them wil; + // DCHECK when we try to lock them for reading in SendPromotionHints. + EXPECT_EQ(0u, resource_provider_->CountPromotionHintRequestsForTesting()); + { + resource_provider_->WaitSyncToken(mapped_id1); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), + mapped_id1); + } + EXPECT_EQ(1u, resource_provider_->CountPromotionHintRequestsForTesting()); + + EXPECT_EQ(list[0].mailbox_holder.sync_token, + context3d_->last_waited_sync_token()); + ResourceIdSet resource_ids_to_receive; + resource_ids_to_receive.insert(id1); + resource_ids_to_receive.insert(id2); + resource_provider_->DeclareUsedResourcesFromChild(child_id, + resource_ids_to_receive); + + EXPECT_EQ(2u, resource_provider_->num_resources()); + + EXPECT_NE(0u, mapped_id1); + EXPECT_NE(0u, mapped_id2); + + // Make sure that the request for a promotion hint was noticed. + EXPECT_TRUE(resource_provider_->IsOverlayCandidate(mapped_id1)); + EXPECT_TRUE(resource_provider_->IsBackedBySurfaceTexture(mapped_id1)); + EXPECT_TRUE(resource_provider_->WantsPromotionHintForTesting(mapped_id1)); + + EXPECT_TRUE(resource_provider_->IsOverlayCandidate(mapped_id2)); + EXPECT_FALSE(resource_provider_->IsBackedBySurfaceTexture(mapped_id2)); + EXPECT_FALSE(resource_provider_->WantsPromotionHintForTesting(mapped_id2)); + + // ResourceProvider maintains a set of promotion hint requests that should be + // cleared when resources are deleted. + resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet()); + EXPECT_EQ(2u, returned_to_child.size()); + child_resource_provider_->ReceiveReturnsFromParent(returned_to_child); + + EXPECT_EQ(0u, resource_provider_->CountPromotionHintRequestsForTesting()); + + resource_provider_->DestroyChild(child_id); +} +#endif + +} // namespace +} // namespace viz diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc index fa0e2f93a52..696bdb03231 100644 --- a/chromium/components/viz/service/display/display_unittest.cc +++ b/chromium/components/viz/service/display/display_unittest.cc @@ -30,8 +30,8 @@ #include "components/viz/test/compositor_frame_helpers.h" #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/test_shared_bitmap_manager.h" -#include "components/viz/test/test_web_graphics_context_3d.h" #include "gpu/GLES2/gl2extchromium.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -107,21 +107,40 @@ class DisplayTest : public testing::Test { ~DisplayTest() override {} - void SetUpDisplay(const RendererSettings& settings, - std::unique_ptr<TestWebGraphicsContext3D> context) { - begin_frame_source_.reset(new StubBeginFrameSource); + void SetUpSoftwareDisplay(const RendererSettings& settings) { + std::unique_ptr<FakeOutputSurface> output_surface; + auto device = std::make_unique<TestSoftwareOutputDevice>(); + software_output_device_ = device.get(); + output_surface = FakeOutputSurface::CreateSoftware(std::move(device)); + output_surface_ = output_surface.get(); + CreateDisplaySchedulerAndDisplay(settings, kArbitraryFrameSinkId, + std::move(output_surface)); + } + + void SetUpGpuDisplay(const RendererSettings& settings, + std::unique_ptr<TestGLES2Interface> context = nullptr) { std::unique_ptr<FakeOutputSurface> output_surface; + scoped_refptr<TestContextProvider> provider; if (context) { - auto provider = TestContextProvider::Create(std::move(context)); - provider->BindToCurrentThread(); - output_surface = FakeOutputSurface::Create3d(std::move(provider)); + provider = TestContextProvider::Create(std::move(context)); + } else { - auto device = std::make_unique<TestSoftwareOutputDevice>(); - software_output_device_ = device.get(); - output_surface = FakeOutputSurface::CreateSoftware(std::move(device)); + provider = TestContextProvider::Create(); } + provider->BindToCurrentThread(); + output_surface = FakeOutputSurface::Create3d(std::move(provider)); output_surface_ = output_surface.get(); + + CreateDisplaySchedulerAndDisplay(settings, kArbitraryFrameSinkId, + std::move(output_surface)); + } + + void CreateDisplaySchedulerAndDisplay( + const RendererSettings& settings, + const FrameSinkId& frame_sink_id, + std::unique_ptr<OutputSurface> output_surface) { + begin_frame_source_.reset(new StubBeginFrameSource); auto scheduler = std::make_unique<TestDisplayScheduler>( begin_frame_source_.get(), task_runner_.get()); scheduler_ = scheduler.get(); @@ -187,6 +206,8 @@ class StubDisplayClient : public DisplayClient { void DisplayDidDrawAndSwap() override {} void DisplayDidReceiveCALayerParams( const gfx::CALayerParams& ca_layer_params) override{}; + void DidSwapAfterSnapshotRequestReceived( + const std::vector<ui::LatencyInfo>& latency_info) override {} }; void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) { @@ -198,7 +219,7 @@ TEST_F(DisplayTest, DisplayDamaged) { RendererSettings settings; settings.partial_swap_enabled = true; settings.finish_rendering_on_resize = true; - SetUpDisplay(settings, nullptr); + SetUpSoftwareDisplay(settings); gfx::ColorSpace color_space_1 = gfx::ColorSpace::CreateXYZD50(); gfx::ColorSpace color_space_2 = gfx::ColorSpace::CreateSCRGBLinear(); @@ -462,7 +483,7 @@ TEST_F(DisplayTest, DisplayDamaged) { void DisplayTest::LatencyInfoCapTest(bool over_capacity) { RendererSettings settings; settings.finish_rendering_on_resize = true; - SetUpDisplay(settings, nullptr); + SetUpSoftwareDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -530,9 +551,9 @@ TEST_F(DisplayTest, OverLatencyInfoCap) { LatencyInfoCapTest(true); } -class MockedContext : public TestWebGraphicsContext3D { +class MockedGLES2Interface : public TestGLES2Interface { public: - MOCK_METHOD0(shallowFinishCHROMIUM, void()); + MOCK_METHOD0(ShallowFinishCHROMIUM, void()); }; TEST_F(DisplayTest, Finish) { @@ -543,11 +564,11 @@ TEST_F(DisplayTest, Finish) { settings.partial_swap_enabled = true; settings.finish_rendering_on_resize = true; - auto context = std::make_unique<MockedContext>(); - MockedContext* context_ptr = context.get(); - EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0); + auto gl = std::make_unique<MockedGLES2Interface>(); + MockedGLES2Interface* gl_ptr = gl.get(); + EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()).Times(0); - SetUpDisplay(settings, std::move(context)); + SetUpGpuDisplay(settings, std::move(gl)); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -570,19 +591,19 @@ TEST_F(DisplayTest, Finish) { display_->DrawAndSwap(); // First resize and draw shouldn't finish. - testing::Mock::VerifyAndClearExpectations(context_ptr); + testing::Mock::VerifyAndClearExpectations(gl_ptr); - EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()); + EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()); display_->Resize(gfx::Size(150, 150)); - testing::Mock::VerifyAndClearExpectations(context_ptr); + testing::Mock::VerifyAndClearExpectations(gl_ptr); // Another resize without a swap doesn't need to finish. - EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0); + EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()).Times(0); display_->SetLocalSurfaceId(local_surface_id2, 1.f); display_->Resize(gfx::Size(200, 200)); - testing::Mock::VerifyAndClearExpectations(context_ptr); + testing::Mock::VerifyAndClearExpectations(gl_ptr); - EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0); + EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()).Times(0); { RenderPassList pass_list; auto pass = RenderPass::Create(); @@ -596,11 +617,11 @@ TEST_F(DisplayTest, Finish) { display_->DrawAndSwap(); - testing::Mock::VerifyAndClearExpectations(context_ptr); + testing::Mock::VerifyAndClearExpectations(gl_ptr); - EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()); + EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()); display_->Resize(gfx::Size(250, 250)); - testing::Mock::VerifyAndClearExpectations(context_ptr); + testing::Mock::VerifyAndClearExpectations(gl_ptr); TearDownDisplay(); } @@ -617,7 +638,7 @@ class CountLossDisplayClient : public StubDisplayClient { }; TEST_F(DisplayTest, ContextLossInformsClient) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); CountLossDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -639,7 +660,7 @@ TEST_F(DisplayTest, CompositorFrameDamagesCorrectDisplay) { LocalSurfaceId local_surface_id(id_allocator_.GenerateId()); // Set up first display. - SetUpDisplay(settings, nullptr); + SetUpSoftwareDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); display_->SetLocalSurfaceId(local_surface_id, 1.f); @@ -690,7 +711,7 @@ TEST_F(DisplayTest, CompositorFrameDamagesCorrectDisplay) { // Check if draw occlusion does not remove any DrawQuads when no quad is being // covered completely. TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -911,7 +932,7 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) { TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1042,7 +1063,7 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) { // skip_rect size, such that DrawQuads that are smaller than the |skip_rect| // are drawn on the screen regardless is shown or not. TEST_F(DisplayTest, DrawOcclusionWithSkipRect) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1166,7 +1187,7 @@ TEST_F(DisplayTest, DrawOcclusionWithSkipRect) { // skip_rect size, such that DrawQuads that are smaller than the |skip_rect| // cannot occlude other quads behind it. TEST_F(DisplayTest, OcclusionIgnoringSkipRect) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1228,7 +1249,7 @@ TEST_F(DisplayTest, OcclusionIgnoringSkipRect) { TEST_F(DisplayTest, CompositorFrameWithTransformer) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1499,7 +1520,7 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) { // Check if draw occlusion works with transform at epsilon scale. TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1611,7 +1632,7 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) { // Check if draw occlusion works with transform at negative scale. TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1736,7 +1757,7 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) { TEST_F(DisplayTest, CompositorFrameWithRotation) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1865,7 +1886,7 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) { TEST_F(DisplayTest, CompositorFrameWithPerspective) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -1941,7 +1962,7 @@ TEST_F(DisplayTest, CompositorFrameWithPerspective) { TEST_F(DisplayTest, CompositorFrameWithOpacityChange) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2008,7 +2029,7 @@ TEST_F(DisplayTest, CompositorFrameWithOpacityChange) { TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2076,7 +2097,7 @@ TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) { TEST_F(DisplayTest, CompositorFrameZTranslate) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2131,7 +2152,7 @@ TEST_F(DisplayTest, CompositorFrameZTranslate) { TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2252,7 +2273,7 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) { TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2380,7 +2401,7 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) { TEST_F(DisplayTest, CompositorFrameWithMultipleRenderPass) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2454,7 +2475,7 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleRenderPass) { } TEST_F(DisplayTest, CompositorFrameWithCoveredRenderPass) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2524,7 +2545,7 @@ TEST_F(DisplayTest, CompositorFrameWithCoveredRenderPass) { TEST_F(DisplayTest, CompositorFrameWithClip) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2641,7 +2662,7 @@ TEST_F(DisplayTest, CompositorFrameWithClip) { TEST_F(DisplayTest, CompositorFrameWithCopyRequest) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2689,7 +2710,7 @@ TEST_F(DisplayTest, CompositorFrameWithCopyRequest) { TEST_F(DisplayTest, CompositorFrameWithRenderPass) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -2869,7 +2890,7 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) { TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -3046,7 +3067,7 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) { TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) { RendererSettings settings; settings.kMinimumDrawOcclusionSize.set_width(0); - SetUpDisplay(settings, TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -3149,7 +3170,7 @@ TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) { // Check if draw occlusion works with very large DrawQuad. crbug.com/824528. TEST_F(DisplayTest, DrawOcclusionWithLargeDrawQuad) { - SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create()); + SetUpGpuDisplay(RendererSettings()); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); @@ -3194,7 +3215,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) { const LocalSurfaceId local_surface_id(id_allocator_.GenerateId()); // Set up first display. - SetUpDisplay(settings, nullptr); + SetUpSoftwareDisplay(settings); StubDisplayClient client; display_->Initialize(&client, manager_.surface_manager()); display_->SetLocalSurfaceId(local_surface_id, 1.f); diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc index 0393c487f08..afda183f41e 100644 --- a/chromium/components/viz/service/display/gl_renderer.cc +++ b/chromium/components/viz/service/display/gl_renderer.cc @@ -58,7 +58,6 @@ #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/common/gpu_memory_allocation.h" #include "media/base/media_switches.h" -#include "skia/ext/texture_handle.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColorFilter.h" @@ -222,10 +221,8 @@ struct GLRenderer::DrawRenderPassDrawQuadParams { bool use_aa = false; - // Some filters affect pixels outside the original contents bounds. This - // requires translation of the source when texturing, as well as a change in - // the bounds of the destination. - gfx::Point src_offset; + // Some filters affect pixels outside the original contents bounds, in which + // case ApplyImageFilter will modify this rect. gfx::RectF dst_rect; // A Skia image that should be sampled from instead of the original @@ -233,25 +230,11 @@ struct GLRenderer::DrawRenderPassDrawQuadParams { sk_sp<SkImage> filter_image; // The original contents, bound for sampling. - std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> + std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL> bypass_quad_resource_lock; // A mask to be applied when drawing the RPDQ. - std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> - mask_resource_lock; - - // Original background texture. - uint32_t background_texture = 0; - - // Backdrop bounding box. - gfx::Rect background_rect; - - // Filtered background texture. - sk_sp<SkImage> background_image; - GLuint background_image_id = 0; - - // Whether the original background texture is needed for the mask. - bool mask_for_background = false; + std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL> mask_resource_lock; // Whether a color matrix needs to be applied by the shaders when drawing // the RPDQ. @@ -266,6 +249,17 @@ struct GLRenderer::DrawRenderPassDrawQuadParams { // The color space of the texture bound for sampling (from filter_image or // bypass_quad_resource_lock, depending on the path taken). gfx::ColorSpace contents_and_bypass_color_space; + + // Background filters block. + // Original background texture. + uint32_t background_texture = 0; + // Backdrop bounding box. + gfx::Rect background_rect; + // Filtered background texture. + sk_sp<SkImage> background_image; + GLuint background_image_id = 0; + // Whether the original background texture is needed for the mask. + bool mask_for_background = false; }; class GLRenderer::ScopedUseGrContext { @@ -307,7 +301,7 @@ class GLRenderer::ScopedUseGrContext { GLRenderer::GLRenderer( const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, scoped_refptr<base::SingleThreadTaskRunner> current_task_runner) : DirectRenderer(settings, output_surface, resource_provider), shared_geometry_quad_(QuadVertexRect()), @@ -452,8 +446,7 @@ void GLRenderer::BeginDrawingFrame() { read_lock_fence = sync_queries_.StartNewFrame(); } else { read_lock_fence = - base::MakeRefCounted<cc::DisplayResourceProvider::SynchronousFence>( - gl_); + base::MakeRefCounted<DisplayResourceProvider::SynchronousFence>(gl_); } resource_provider_->SetReadLockFence(read_lock_fence.get()); @@ -1028,6 +1021,21 @@ bool GLRenderer::InitializeRPDQParameters( return true; } +// Get a GL texture id from an SkImage. An optional origin pointer can be +// passed in which will be filled out with the origin for the texture +// backing the SkImage. +static GLuint GetGLTextureIDFromSkImage(const SkImage* image, + GrSurfaceOrigin* origin = nullptr) { + GrBackendTexture backend_texture = image->getBackendTexture(true, origin); + if (!backend_texture.isValid()) { + return 0; + } + GrGLTextureInfo info; + bool result = backend_texture.getGLTextureInfo(&info); + DCHECK(result); + return info.fID; +} + void GLRenderer::UpdateRPDQShadersForBlending( DrawRenderPassDrawQuadParams* params) { const RenderPassDrawQuad* quad = params->quad; @@ -1067,10 +1075,8 @@ void GLRenderer::UpdateRPDQShadersForBlending( params->background_rect, unclipped_rect); if (params->background_image) { params->background_image_id = - skia::GrBackendObjectToGrGLTextureInfo( - params->background_image->getTextureHandle(true)) - ->fID; - DCHECK(params->background_image_id); + GetGLTextureIDFromSkImage(params->background_image.get()); + DCHECK(params->background_image_id || IsContextLost()); } } } @@ -1169,7 +1175,7 @@ bool GLRenderer::UpdateRPDQWithSkiaFilters( src_image, src_rect, params->dst_rect, quad->filters_scale, std::move(filter), &offset, &subset, quad->filters_origin); } else { - cc::DisplayResourceProvider::ScopedReadLockGL + DisplayResourceProvider::ScopedReadLockGL prefilter_bypass_quad_texture_lock( resource_provider_, params->bypass_quad_texture.resource_id); params->contents_and_bypass_color_space = @@ -1189,8 +1195,7 @@ bool GLRenderer::UpdateRPDQWithSkiaFilters( params->dst_rect = gfx::RectF(src_rect.x() + offset.fX, src_rect.y() + offset.fY, subset.width(), subset.height()); - params->src_offset.SetPoint(subset.x(), subset.y()); - gfx::RectF tex_rect = gfx::RectF(gfx::PointF(params->src_offset), + gfx::RectF tex_rect = gfx::RectF(gfx::PointF(subset.x(), subset.y()), params->dst_rect.size()); params->tex_coord_rect = tex_rect; } @@ -1203,7 +1208,7 @@ void GLRenderer::UpdateRPDQTexturesForSampling( DrawRenderPassDrawQuadParams* params) { if (params->quad->mask_resource_id()) { params->mask_resource_lock.reset( - new cc::DisplayResourceProvider::ScopedSamplerGL( + new DisplayResourceProvider::ScopedSamplerGL( resource_provider_, params->quad->mask_resource_id(), GL_TEXTURE1, GL_LINEAR)); } @@ -1211,10 +1216,8 @@ void GLRenderer::UpdateRPDQTexturesForSampling( if (params->filter_image) { GrSurfaceOrigin origin; GLuint filter_image_id = - skia::GrBackendObjectToGrGLTextureInfo( - params->filter_image->getTextureHandle(true, &origin)) - ->fID; - DCHECK(filter_image_id); + GetGLTextureIDFromSkImage(params->filter_image.get(), &origin); + DCHECK(filter_image_id || IsContextLost()); DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_)); gl_->BindTexture(GL_TEXTURE_2D, filter_image_id); gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -1229,7 +1232,7 @@ void GLRenderer::UpdateRPDQTexturesForSampling( params->source_needs_flip = params->flip_texture; } else { params->bypass_quad_resource_lock = - std::make_unique<cc::DisplayResourceProvider::ScopedSamplerGL>( + std::make_unique<DisplayResourceProvider::ScopedSamplerGL>( resource_provider_, params->bypass_quad_texture.resource_id, GL_LINEAR); DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), @@ -1383,8 +1386,8 @@ void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) { gl_->Uniform4f(current_program_->backdrop_rect_location(), params->background_rect.x(), params->background_rect.y(), - params->background_rect.width(), - params->background_rect.height()); + 1.0f / params->background_rect.width(), + 1.0f / params->background_rect.height()); // Either |background_image_id| or |background_texture| will be the // |backdrop_location| in the shader. @@ -1862,7 +1865,7 @@ void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad, float edge[24]; SetupQuadForClippingAndAntialiasing(device_transform, quad, &aa_quad, clip_region, &local_quad, edge); - cc::DisplayResourceProvider::ScopedSamplerGL quad_resource_lock( + DisplayResourceProvider::ScopedSamplerGL quad_resource_lock( resource_provider_, resource_id, quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR); SamplerType sampler = @@ -1932,7 +1935,7 @@ void GLRenderer::DrawContentQuadNoAA(const ContentDrawQuadBase* quad, ? GL_LINEAR : GL_NEAREST; - cc::DisplayResourceProvider::ScopedSamplerGL quad_resource_lock( + DisplayResourceProvider::ScopedSamplerGL quad_resource_lock( resource_provider_, resource_id, filter); SamplerType sampler = SamplerTypeFromTextureTarget(quad_resource_lock.target()); @@ -2054,40 +2057,48 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad, ? UV_TEXTURE_MODE_UV : UV_TEXTURE_MODE_U_V; - // TODO(ccameron): There are currently three sources of the color space: the - // resource, quad->color_space, and quad->video_color_space. Remove two of - // them. - gfx::ColorSpace src_color_space = quad->video_color_space; - gfx::ColorSpace dst_color_space = - current_frame()->current_render_pass->color_space; - cc::DisplayResourceProvider::ScopedSamplerGL y_plane_lock( + DisplayResourceProvider::ScopedSamplerGL y_plane_lock( resource_provider_, quad->y_plane_resource_id(), GL_TEXTURE1, GL_LINEAR); - cc::DisplayResourceProvider::ScopedSamplerGL u_plane_lock( + DisplayResourceProvider::ScopedSamplerGL u_plane_lock( resource_provider_, quad->u_plane_resource_id(), GL_TEXTURE2, GL_LINEAR); DCHECK_EQ(y_plane_lock.target(), u_plane_lock.target()); DCHECK_EQ(y_plane_lock.color_space(), u_plane_lock.color_space()); - // TODO(jbauman): Use base::Optional when available. - std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> v_plane_lock; + // TODO(ccameron): There are currently three sources of the color space: the + // resource, quad->color_space, and quad->video_color_space. Remove two of + // them. + gfx::ColorSpace src_color_space = quad->video_color_space; // Invalid or unspecified color spaces should be treated as REC709. if (!src_color_space.IsValid()) src_color_space = gfx::ColorSpace::CreateREC709(); else DCHECK_EQ(src_color_space, y_plane_lock.color_space()); - // The source color space should never be RGB. DCHECK_NE(src_color_space, src_color_space.GetAsFullRangeRGB()); + gfx::ColorSpace dst_color_space = + current_frame()->current_render_pass->color_space; + // Force sRGB output on Windows for overlay candidate video quads to match + // DirectComposition behavior in case these switch between overlays and + // compositing. See https://crbug.com/811118 for details. + if (supports_dc_layers_ && + resource_provider_->IsOverlayCandidate(quad->y_plane_resource_id())) { + DCHECK(resource_provider_->IsOverlayCandidate(quad->u_plane_resource_id())); + dst_color_space = gfx::ColorSpace::CreateSRGB(); + } + + // TODO(jbauman): Use base::Optional when available. + std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL> v_plane_lock; if (uv_texture_mode == UV_TEXTURE_MODE_U_V) { - v_plane_lock.reset(new cc::DisplayResourceProvider::ScopedSamplerGL( + v_plane_lock.reset(new DisplayResourceProvider::ScopedSamplerGL( resource_provider_, quad->v_plane_resource_id(), GL_TEXTURE3, GL_LINEAR)); DCHECK_EQ(y_plane_lock.target(), v_plane_lock->target()); DCHECK_EQ(y_plane_lock.color_space(), v_plane_lock->color_space()); } - std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> a_plane_lock; + std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL> a_plane_lock; if (alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE) { - a_plane_lock.reset(new cc::DisplayResourceProvider::ScopedSamplerGL( + a_plane_lock.reset(new DisplayResourceProvider::ScopedSamplerGL( resource_provider_, quad->a_plane_resource_id(), GL_TEXTURE4, GL_LINEAR)); DCHECK_EQ(y_plane_lock.target(), a_plane_lock->target()); @@ -2210,8 +2221,8 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad, gl_, &highp_threshold_cache_, settings_->highp_threshold_min, quad->shared_quad_state->visible_quad_layer_rect.bottom_right()); - cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_, - quad->resource_id()); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_, + quad->resource_id()); SetUseProgram(ProgramKey::VideoStream(tex_coord_precision), lock.color_space(), @@ -2262,7 +2273,7 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) { SetBlendEnabled(draw_cache_.needs_blending); // Assume the current active textures is 0. - cc::DisplayResourceProvider::ScopedSamplerGL locked_quad( + DisplayResourceProvider::ScopedSamplerGL locked_quad( resource_provider_, draw_cache_.resource_id, draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR); @@ -2353,8 +2364,8 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad, gl_, &highp_threshold_cache_, settings_->highp_threshold_min, quad->shared_quad_state->visible_quad_layer_rect.bottom_right()); - cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_, - quad->resource_id()); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_, + quad->resource_id()); const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target()); bool need_tex_clamp_rect = !quad->resource_size_in_pixels().IsEmpty() && @@ -2659,7 +2670,8 @@ void GLRenderer::DrawQuadGeometryWithAA(const DrawQuad* quad, CenteredRect(tile_rect)); } -void GLRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) { +void GLRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info, + bool need_presentation_feedback) { DCHECK(visible_); TRACE_EVENT0("viz", "GLRenderer::SwapBuffers"); @@ -2670,6 +2682,7 @@ void GLRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) { OutputSurfaceFrame output_frame; output_frame.latency_info = std::move(latency_info); output_frame.size = surface_size; + output_frame.need_presentation_feedback = need_presentation_feedback; if (use_swap_with_bounds_) { output_frame.content_bounds = std::move(swap_content_bounds_); } else if (use_partial_swap_) { @@ -2752,7 +2765,7 @@ void GLRenderer::SwapBuffersComplete() { // that once a swap buffer has completed we can remove the oldest buffers // from the queue, but only once we've swapped another frame afterward. if (swapping_overlay_resources_.size() > 1) { - cc::DisplayResourceProvider::ScopedBatchReturnResources returner( + DisplayResourceProvider::ScopedBatchReturnResources returner( resource_provider_); swapping_overlay_resources_.pop_front(); } @@ -2770,7 +2783,7 @@ void GLRenderer::SwapBuffersComplete() { void GLRenderer::DidReceiveTextureInUseResponses( const gpu::TextureInUseResponses& responses) { DCHECK(settings_->release_overlay_resources_after_gpu_query); - cc::DisplayResourceProvider::ScopedBatchReturnResources returner( + DisplayResourceProvider::ScopedBatchReturnResources returner( resource_provider_); for (const gpu::TextureInUseResponse& response : responses) { if (response.in_use) @@ -3085,7 +3098,7 @@ void GLRenderer::ScheduleCALayers() { unsigned texture_id = 0; if (contents_resource_id) { pending_overlay_resources_.push_back( - std::make_unique<cc::DisplayResourceProvider::ScopedReadLockGL>( + std::make_unique<DisplayResourceProvider::ScopedReadLockGL>( resource_provider_, contents_resource_id)); texture_id = pending_overlay_resources_.back()->texture_id(); } @@ -3137,7 +3150,7 @@ void GLRenderer::ScheduleDCLayers() { for (const auto& contents_resource_id : dc_layer_overlay.resources) { if (contents_resource_id) { pending_overlay_resources_.push_back( - std::make_unique<cc::DisplayResourceProvider::ScopedReadLockGL>( + std::make_unique<DisplayResourceProvider::ScopedReadLockGL>( resource_provider_, contents_resource_id)); texture_ids[i] = pending_overlay_resources_.back()->texture_id(); ids_to_send = i + 1; @@ -3178,7 +3191,7 @@ void GLRenderer::ScheduleDCLayers() { gl_->ScheduleDCLayerCHROMIUM(ids_to_send, texture_ids, contents_rect, dc_layer_overlay.background_color, dc_layer_overlay.edge_aa_mask, bounds_rect, - filter); + filter, dc_layer_overlay.is_protected_video); } } @@ -3186,7 +3199,7 @@ void GLRenderer::ScheduleOverlays() { if (current_frame()->overlay_list.empty()) return; - cc::OverlayCandidateList& overlays = current_frame()->overlay_list; + OverlayCandidateList& overlays = current_frame()->overlay_list; for (const auto& overlay_candidate : overlays) { unsigned texture_id = 0; if (overlay_candidate.use_output_surface_for_resource) { @@ -3194,7 +3207,7 @@ void GLRenderer::ScheduleOverlays() { DCHECK(texture_id || IsContextLost()); } else { pending_overlay_resources_.push_back( - std::make_unique<cc::DisplayResourceProvider::ScopedReadLockGL>( + std::make_unique<DisplayResourceProvider::ScopedReadLockGL>( resource_provider_, overlay_candidate.resource_id)); texture_id = pending_overlay_resources_.back()->texture_id(); } @@ -3202,7 +3215,8 @@ void GLRenderer::ScheduleOverlays() { context_support_->ScheduleOverlayPlane( overlay_candidate.plane_z_order, overlay_candidate.transform, texture_id, ToNearestRect(overlay_candidate.display_rect), - overlay_candidate.uv_rect, !overlay_candidate.is_opaque); + overlay_candidate.uv_rect, !overlay_candidate.is_opaque, + overlay_candidate.gpu_fence_id); } } @@ -3614,8 +3628,7 @@ ResourceFormat GLRenderer::BackbufferFormat() const { DCHECK(caps.color_buffer_half_float_rgba); return RGBA_F16; } - return PlatformColor::BestSupportedTextureFormat( - caps.texture_format_bgra8888); + return PlatformColor::BestSupportedTextureFormat(caps); } void GLRenderer::AllocateRenderPassResourceIfNeeded( diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h index 180052af412..1cd981c9d71 100644 --- a/chromium/components/viz/service/display/gl_renderer.h +++ b/chromium/components/viz/service/display/gl_renderer.h @@ -33,12 +33,6 @@ namespace base { class SingleThreadTaskRunner; } -namespace cc { -class GLRendererShaderTest; -class OutputSurface; -class StreamVideoDrawQuad; -} // namespace cc - namespace gpu { namespace gles2 { class GLES2Interface; @@ -48,8 +42,11 @@ class GLES2Interface; namespace viz { class DynamicGeometryBinding; +class GLRendererShaderTest; +class OutputSurface; class ScopedRenderPassTexture; class StaticGeometryBinding; +class StreamVideoDrawQuad; class TextureDrawQuad; // Class that handles drawing of composited render layers using GL. @@ -59,13 +56,14 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer { GLRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, scoped_refptr<base::SingleThreadTaskRunner> current_task_runner); ~GLRenderer() override; bool use_swap_with_bounds() const { return use_swap_with_bounds_; } - void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override; + void SwapBuffers(std::vector<ui::LatencyInfo> latency_info, + bool need_presentation_feedback) override; void SwapBuffersComplete() override; void DidReceiveTextureInUseResponses( @@ -154,7 +152,7 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer { friend class GLRendererTest; using OverlayResourceLock = - std::unique_ptr<cc::DisplayResourceProvider::ScopedReadLockGL>; + std::unique_ptr<DisplayResourceProvider::ScopedReadLockGL>; using OverlayResourceLockList = std::vector<OverlayResourceLock>; // If a RenderPass is used as an overlay, we render the RenderPass with any diff --git a/chromium/components/viz/service/display/gl_renderer_copier.cc b/chromium/components/viz/service/display/gl_renderer_copier.cc index 478b2cb9950..f116895077d 100644 --- a/chromium/components/viz/service/display/gl_renderer_copier.cc +++ b/chromium/components/viz/service/display/gl_renderer_copier.cc @@ -215,10 +215,10 @@ GLuint GLRendererCopier::RenderResultTexture( // return it as the result texture. The request must not include scaling nor // a texture mailbox to use for delivering results. The texture format must // also be GL_RGBA, as described by CopyOutputResult::Format::RGBA_TEXTURE. - const int purpose = (!request.is_scaled() && flipped_source && - !request.has_mailbox() && internal_format == GL_RGBA) - ? CacheEntry::kResultTexture - : CacheEntry::kFramebufferCopyTexture; + const int purpose = + (!request.is_scaled() && flipped_source && internal_format == GL_RGBA) + ? CacheEntry::kResultTexture + : CacheEntry::kFramebufferCopyTexture; TakeCachedObjectsOrCreate(SourceOf(request), purpose, 1, &source_texture); gl->BindTexture(GL_TEXTURE_2D, source_texture); gl->CopyTexImage2D(GL_TEXTURE_2D, 0, internal_format, sampling_rect.x(), @@ -230,21 +230,9 @@ GLuint GLRendererCopier::RenderResultTexture( sampling_rect.set_origin(gfx::Point()); } - // Determine the result texture: If the copy request provided a valid one, use - // it instead of one owned by GLRendererCopier. GLuint result_texture = 0; - if (request.has_mailbox()) { - if (!request.mailbox().IsZero()) { - if (request.sync_token().HasData()) - gl->WaitSyncTokenCHROMIUM(request.sync_token().GetConstData()); - result_texture = - gl->CreateAndConsumeTextureCHROMIUM(request.mailbox().name); - } - } - if (result_texture == 0) { - TakeCachedObjectsOrCreate(SourceOf(request), CacheEntry::kResultTexture, 1, - &result_texture); - } + TakeCachedObjectsOrCreate(SourceOf(request), CacheEntry::kResultTexture, 1, + &result_texture); gl->BindTexture(GL_TEXTURE_2D, result_texture); gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, result_rect.width(), result_rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); @@ -266,11 +254,12 @@ GLuint GLRendererCopier::RenderResultTexture( CacheScalerOrDelete(SourceOf(request), std::move(scaler)); } else { DCHECK_SIZE_EQ(sampling_rect.size(), result_rect.size()); + const bool flip_output = !flipped_source; gl->CopySubTextureCHROMIUM( source_texture, 0 /* source_level */, GL_TEXTURE_2D, result_texture, 0 /* dest_level */, 0 /* xoffset */, 0 /* yoffset */, sampling_rect.x(), sampling_rect.y(), sampling_rect.width(), sampling_rect.height(), - !flipped_source, false, false); + flip_output, false, false); } // If |source_texture| was a copy, maybe cache it for future requests. @@ -305,6 +294,80 @@ void GLRendererCopier::StartReadbackFromTexture( namespace { +class GLPixelBufferRGBAResult : public CopyOutputResult { + public: + GLPixelBufferRGBAResult(const gfx::Rect& result_rect, + scoped_refptr<ContextProvider> context_provider, + GLuint transfer_buffer, + GLenum readback_format) + : CopyOutputResult(CopyOutputResult::Format::RGBA_BITMAP, result_rect), + context_provider_(std::move(context_provider)), + transfer_buffer_(transfer_buffer), + readback_format_(readback_format) {} + + ~GLPixelBufferRGBAResult() final { + if (transfer_buffer_) + context_provider_->ContextGL()->DeleteBuffers(1, &transfer_buffer_); + } + + bool ReadRGBAPlane(uint8_t* dest, int stride) const final { + // No need to read from GPU memory if a cached bitmap already exists. + if (rect().IsEmpty() || cached_bitmap()->readyToDraw()) + return CopyOutputResult::ReadRGBAPlane(dest, stride); + auto* const gl = context_provider_->ContextGL(); + gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_); + const uint8_t* pixels = static_cast<uint8_t*>(gl->MapBufferCHROMIUM( + GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); + if (pixels) { + const SkColorType src_format = (readback_format_ == GL_BGRA_EXT) + ? kBGRA_8888_SkColorType + : kRGBA_8888_SkColorType; + const int src_bytes_per_row = size().width() * kRGBABytesPerPixel; + const SkImageInfo src_row_image_info = + SkImageInfo::Make(size().width(), 1, src_format, kPremul_SkAlphaType); + const SkImageInfo dest_row_image_info = + SkImageInfo::MakeN32Premul(size().width(), 1); + + for (int y = 0; y < size().height(); ++y) { + const int flipped_y = (size().height() - y - 1); + const uint8_t* const src_row = pixels + flipped_y * src_bytes_per_row; + void* const dest_row = dest + y * stride; + SkPixmap src_pixmap(src_row_image_info, src_row, src_bytes_per_row); + SkPixmap dest_pixmap(dest_row_image_info, dest_row, stride); + src_pixmap.readPixels(dest_pixmap); + } + gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM); + } + gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0); + return !!pixels; + } + + const SkBitmap& AsSkBitmap() const final { + if (rect().IsEmpty()) + return *cached_bitmap(); // Return "null" bitmap for empty result. + + if (cached_bitmap()->readyToDraw()) + return *cached_bitmap(); + + SkBitmap result_bitmap; + result_bitmap.allocPixels( + SkImageInfo::MakeN32Premul(size().width(), size().height())); + ReadRGBAPlane(static_cast<uint8_t*>(result_bitmap.getPixels()), + result_bitmap.rowBytes()); + *cached_bitmap() = result_bitmap; + // Now that we have a cached bitmap, no need to read from GPU memory + // anymore. + context_provider_->ContextGL()->DeleteBuffers(1, &transfer_buffer_); + transfer_buffer_ = 0; + return *cached_bitmap(); + } + + private: + const scoped_refptr<ContextProvider> context_provider_; + mutable GLuint transfer_buffer_; + GLenum readback_format_; +}; + // Manages the execution of one asynchronous framebuffer readback and contains // all the relevant state needed to complete a copy request. The constructor // initiates the operation, and then at some later point either: 1) the Finish() @@ -357,7 +420,8 @@ class ReadPixelsWorkflow { ~ReadPixelsWorkflow() { auto* const gl = context_provider_->ContextGL(); gl->DeleteQueriesEXT(1, &query_); - gl->DeleteBuffers(1, &transfer_buffer_); + if (transfer_buffer_) + gl->DeleteBuffers(1, &transfer_buffer_); } GLuint query() const { return query_; } @@ -365,42 +429,15 @@ class ReadPixelsWorkflow { // Callback for the asynchronous glReadPixels(). The pixels are read from the // transfer buffer, and a CopyOutputResult is sent to the requestor. void Finish() { - auto* const gl = context_provider_->ContextGL(); - - gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_); - const uint8_t* pixels = static_cast<uint8_t*>(gl->MapBufferCHROMIUM( - GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY)); - if (!pixels) { - // CopyOutputRequest will auto-send an empty result when its destructor - // is run from ~ReadPixelsWorkflow(). - return; - } - - // Create the result bitmap, making sure to flip the image in the Y - // dimension. - // - // TODO(crbug/758057): Plumb-through color space into the output bitmap. - SkBitmap result_bitmap; - const int bytes_per_row = result_rect_.width() * kRGBABytesPerPixel; - result_bitmap.allocPixels( - SkImageInfo::Make(result_rect_.width(), result_rect_.height(), - (readback_format_ == GL_BGRA_EXT) - ? kBGRA_8888_SkColorType - : kRGBA_8888_SkColorType, - kPremul_SkAlphaType), - bytes_per_row); - for (int y = 0; y < result_rect_.height(); ++y) { - const int flipped_y = (result_rect_.height() - y - 1); - const uint8_t* const src_row = pixels + flipped_y * bytes_per_row; - void* const dest_row = result_bitmap.getAddr(0, y); - memcpy(dest_row, src_row, bytes_per_row); + auto result = std::make_unique<GLPixelBufferRGBAResult>( + result_rect_, context_provider_, transfer_buffer_, readback_format_); + transfer_buffer_ = 0; // Ownerhip was transferred to the result. + if (!copy_request_->SendsResultsInCurrentSequence()) { + // Force readback into a SkBitmap now, because after PostTask we don't + // have access to |context_provider_|. + result->AsSkBitmap(); } - gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM); - - copy_request_->SendResult(std::make_unique<CopyOutputSkBitmapResult>( - result_rect_, result_bitmap)); - - // |transfer_buffer_| and |query_| will be deleted soon by the destructor. + copy_request_->SendResult(std::move(result)); } private: @@ -444,34 +481,18 @@ void GLRendererCopier::SendTextureResult( // within its own GL context will be using the texture at a point in time // after the texture has been rendered (via GLRendererCopier's GL context). gpu::Mailbox mailbox; - if (request->has_mailbox()) { - mailbox = request->mailbox(); - } else { - gl->GenMailboxCHROMIUM(mailbox.name); - gl->ProduceTextureDirectCHROMIUM(result_texture, mailbox.name); - } + gl->GenMailboxCHROMIUM(mailbox.name); + gl->ProduceTextureDirectCHROMIUM(result_texture, mailbox.name); gpu::SyncToken sync_token; gl->GenSyncTokenCHROMIUM(sync_token.GetData()); - // Create a |release_callback| appropriate to the situation: If the - // |result_texture| was provided in the mailbox of the copy request, - // create a no-op release callback because the requestor owns the texture. - // Otherwise, create a callback that deletes what was created in this GL - // context. - std::unique_ptr<SingleReleaseCallback> release_callback; - if (request->has_mailbox()) { - gl->DeleteTextures(1, &result_texture); - // TODO(crbug/754872): This non-null release callback wart is going away - // soon, as copy requestors won't need pool/manage textures anymore. - release_callback = SingleReleaseCallback::Create(base::DoNothing()); - } else { - // Note: There's no need to try to pool/re-use the result texture from here, - // since only clients that are trying to re-invent video capture would see - // any significant performance benefit. Instead, such clients should use the - // video capture services provided by VIZ. - release_callback = - texture_deleter_->GetReleaseCallback(context_provider_, result_texture); - } + // Create a callback that deletes what was created in this GL context. + // Note: There's no need to try to pool/re-use the result texture from here, + // since only clients that are trying to re-invent video capture would see any + // significant performance benefit. Instead, such clients should use the video + // capture services provided by VIZ. + auto release_callback = + texture_deleter_->GetReleaseCallback(context_provider_, result_texture); request->SendResult(std::make_unique<CopyOutputTextureResult>( result_rect, mailbox, sync_token, color_space, @@ -825,9 +846,10 @@ GLRendererCopier::TakeCachedScalerOrCreate(const CopyOutputRequest& for_request, const GLHelper::ScalerQuality quality = is_downscale_in_both_dimensions ? GLHelper::SCALER_QUALITY_GOOD : GLHelper::SCALER_QUALITY_BEST; + const bool flip_output = !flipped_source; return helper_.CreateScaler(quality, for_request.scale_from(), - for_request.scale_to(), flipped_source, false, - false); + for_request.scale_to(), flipped_source, + flip_output, false); } void GLRendererCopier::CacheScalerOrDelete( diff --git a/chromium/components/viz/service/display/gl_renderer_copier.h b/chromium/components/viz/service/display/gl_renderer_copier.h index 7470b09cc91..5f60ffcddb1 100644 --- a/chromium/components/viz/service/display/gl_renderer_copier.h +++ b/chromium/components/viz/service/display/gl_renderer_copier.h @@ -183,6 +183,8 @@ class VIZ_SERVICE_EXPORT GLRendererCopier { const GLuint* names); // Returns a cached scaler for the given request, or creates one on-demand. + // The scaler can be configured for source textures that may or may not be + // Y-flipped, but its results will always be Y-flipped. std::unique_ptr<GLHelper::ScalerInterface> TakeCachedScalerOrCreate( const CopyOutputRequest& for_request, bool flipped_source); diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc index 241284a5ccc..1913ad59553 100644 --- a/chromium/components/viz/service/display/gl_renderer_unittest.cc +++ b/chromium/components/viz/service/display/gl_renderer_unittest.cc @@ -12,11 +12,12 @@ #include <vector> #include "base/location.h" +#include "base/single_thread_task_runner.h" #include "base/test/scoped_feature_list.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "cc/base/math_util.h" -#include "cc/resources/resource_provider.h" +#include "cc/resources/layer_tree_resource_provider.h" #include "cc/test/fake_impl_task_runner_provider.h" #include "cc/test/fake_layer_tree_host_impl.h" #include "cc/test/fake_output_surface_client.h" @@ -28,7 +29,9 @@ #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/frame_sinks/copy_output_result.h" #include "components/viz/common/quads/texture_draw_quad.h" +#include "components/viz/common/resources/platform_color.h" #include "components/viz/common/resources/transferable_resource.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/overlay_strategy_single_on_top.h" #include "components/viz/service/display/overlay_strategy_underlay.h" #include "components/viz/test/fake_output_surface.h" @@ -462,13 +465,13 @@ class FakeRendererGL : public GLRenderer { public: FakeRendererGL(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider) + DisplayResourceProvider* resource_provider) : GLRenderer(settings, output_surface, resource_provider, nullptr) {} FakeRendererGL( const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, scoped_refptr<base::SingleThreadTaskRunner> current_task_runner) : GLRenderer(settings, output_surface, @@ -504,13 +507,15 @@ class GLRendererWithDefaultHarnessTest : public GLRendererTest { renderer_->SetVisible(true); } - void SwapBuffers() { renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); } + void SwapBuffers() { + renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false); + } RendererSettings settings_; cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; }; @@ -538,7 +543,7 @@ class GLRendererShaderTest : public GLRendererTest { child_context_provider_->BindToCurrentThread(); child_resource_provider_ = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - child_context_provider_.get(), shared_bitmap_manager_.get()); + child_context_provider_.get()); } void TestRenderPassProgram(TexCoordPrecision precision, @@ -628,7 +633,7 @@ class GLRendererShaderTest : public GLRendererTest { cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; scoped_refptr<TestContextProvider> child_context_provider_; std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; @@ -651,38 +656,45 @@ TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) { EXPECT_TRUE(renderer_->stencil_enabled()); } -class ForbidSynchronousCallContext : public TestWebGraphicsContext3D { +class ForbidSynchronousCallGLES2Interface : public TestGLES2Interface { public: - ForbidSynchronousCallContext() {} + ForbidSynchronousCallGLES2Interface() = default; - void getAttachedShaders(GLuint program, + void GetAttachedShaders(GLuint program, GLsizei max_count, GLsizei* count, GLuint* shaders) override { ADD_FAILURE(); } - GLint getAttribLocation(GLuint program, const GLchar* name) override { + + GLint GetAttribLocation(GLuint program, const GLchar* name) override { ADD_FAILURE(); return 0; } - void getBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); } - void getBufferParameteriv(GLenum target, + + void GetBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); } + + void GetBufferParameteriv(GLenum target, GLenum pname, GLint* value) override { ADD_FAILURE(); } - GLenum getError() override { + + GLenum GetError() override { ADD_FAILURE(); return GL_NO_ERROR; } - void getFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); } - void getFramebufferAttachmentParameteriv(GLenum target, + + void GetFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); } + + void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* value) override { ADD_FAILURE(); } - void getIntegerv(GLenum pname, GLint* value) override { + + void GetIntegerv(GLenum pname, GLint* value) override { if (pname == GL_MAX_TEXTURE_SIZE) { // MAX_TEXTURE_SIZE is cached client side, so it's OK to query. *value = 1024; @@ -693,64 +705,66 @@ class ForbidSynchronousCallContext : public TestWebGraphicsContext3D { // We allow querying the shader compilation and program link status in debug // mode, but not release. - void getProgramiv(GLuint program, GLenum pname, GLint* value) override { -#ifndef NDEBUG - *value = 1; -#else + void GetProgramiv(GLuint program, GLenum pname, GLint* value) override { ADD_FAILURE(); -#endif } - void getShaderiv(GLuint shader, GLenum pname, GLint* value) override { -#ifndef NDEBUG - *value = 1; -#else + void GetShaderiv(GLuint shader, GLenum pname, GLint* value) override { ADD_FAILURE(); -#endif } - void getRenderbufferParameteriv(GLenum target, + void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* value) override { ADD_FAILURE(); } - void getShaderPrecisionFormat(GLenum shadertype, + void GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) override { ADD_FAILURE(); } - void getTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override { + + void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override { ADD_FAILURE(); } - void getTexParameteriv(GLenum target, GLenum pname, GLint* value) override { + + void GetTexParameteriv(GLenum target, GLenum pname, GLint* value) override { ADD_FAILURE(); } - void getUniformfv(GLuint program, GLint location, GLfloat* value) override { + + void GetUniformfv(GLuint program, GLint location, GLfloat* value) override { ADD_FAILURE(); } - void getUniformiv(GLuint program, GLint location, GLint* value) override { + + void GetUniformiv(GLuint program, GLint location, GLint* value) override { ADD_FAILURE(); } - GLint getUniformLocation(GLuint program, const GLchar* name) override { + + GLint GetUniformLocation(GLuint program, const GLchar* name) override { ADD_FAILURE(); return 0; } - void getVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override { + + void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override { ADD_FAILURE(); } - void getVertexAttribiv(GLuint index, GLenum pname, GLint* value) override { + + void GetVertexAttribiv(GLuint index, GLenum pname, GLint* value) override { ADD_FAILURE(); } - GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname) override { + + void GetVertexAttribPointerv(GLuint index, + GLenum pname, + void** pointer) override { ADD_FAILURE(); - return 0; } }; + TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) { - auto context = std::make_unique<ForbidSynchronousCallContext>(); - auto provider = TestContextProvider::Create(std::move(context)); + auto gl_owned = std::make_unique<ForbidSynchronousCallGLES2Interface>(); + auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); cc::FakeOutputSurfaceClient output_surface_client; @@ -760,7 +774,7 @@ TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -769,24 +783,26 @@ TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) { resource_provider.get()); } -class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D { +class LoseContextOnFirstGetGLES2Interface : public TestGLES2Interface { public: - LoseContextOnFirstGetContext() {} + LoseContextOnFirstGetGLES2Interface() {} - void getProgramiv(GLuint program, GLenum pname, GLint* value) override { - context_lost_ = true; + void GetProgramiv(GLuint program, GLenum pname, GLint* value) override { + LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, + GL_INNOCENT_CONTEXT_RESET_ARB); *value = 0; } - void getShaderiv(GLuint shader, GLenum pname, GLint* value) override { - context_lost_ = true; + void GetShaderiv(GLuint shader, GLenum pname, GLint* value) override { + LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, + GL_INNOCENT_CONTEXT_RESET_ARB); *value = 0; } }; TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) { - auto context = std::make_unique<LoseContextOnFirstGetContext>(); - auto provider = TestContextProvider::Create(std::move(context)); + auto gl_owned = std::make_unique<LoseContextOnFirstGetGLES2Interface>(); + auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); cc::FakeOutputSurfaceClient output_surface_client; @@ -796,7 +812,7 @@ TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -805,22 +821,24 @@ TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) { resource_provider.get()); } -class ClearCountingContext : public TestWebGraphicsContext3D { +class ClearCountingGLES2Interface : public TestGLES2Interface { public: - ClearCountingContext() { test_capabilities_.discard_framebuffer = true; } + ClearCountingGLES2Interface() = default; - MOCK_METHOD3(discardFramebufferEXT, + MOCK_METHOD3(DiscardFramebufferEXT, void(GLenum target, GLsizei numAttachments, const GLenum* attachments)); - MOCK_METHOD1(clear, void(GLbitfield mask)); + MOCK_METHOD1(Clear, void(GLbitfield mask)); }; TEST_F(GLRendererTest, OpaqueBackground) { - std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext); - ClearCountingContext* context = context_owned.get(); + auto gl_owned = std::make_unique<ClearCountingGLES2Interface>(); + gl_owned->set_have_discard_framebuffer(true); - auto provider = TestContextProvider::Create(std::move(context_owned)); + auto* gl = gl_owned.get(); + + auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); cc::FakeOutputSurfaceClient output_surface_client; @@ -830,7 +848,7 @@ TEST_F(GLRendererTest, OpaqueBackground) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -848,23 +866,24 @@ TEST_F(GLRendererTest, OpaqueBackground) { // On DEBUG builds, render passes with opaque background clear to blue to // easily see regions that were not drawn on the screen. - EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _)) + EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _)) .With(Args<2, 1>(ElementsAre(GL_COLOR_EXT))) .Times(1); #ifdef NDEBUG - EXPECT_CALL(*context, clear(_)).Times(0); + EXPECT_CALL(*gl, Clear(_)).Times(0); #else - EXPECT_CALL(*context, clear(_)).Times(1); + EXPECT_CALL(*gl, Clear(_)).Times(1); #endif DrawFrame(&renderer, viewport_size); - Mock::VerifyAndClearExpectations(context); + Mock::VerifyAndClearExpectations(gl); } TEST_F(GLRendererTest, TransparentBackground) { - std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext); - ClearCountingContext* context = context_owned.get(); + auto gl_owned = std::make_unique<ClearCountingGLES2Interface>(); + auto* gl = gl_owned.get(); + gl_owned->set_have_discard_framebuffer(true); - auto provider = TestContextProvider::Create(std::move(context_owned)); + auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); cc::FakeOutputSurfaceClient output_surface_client; @@ -874,7 +893,7 @@ TEST_F(GLRendererTest, TransparentBackground) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -890,18 +909,19 @@ TEST_F(GLRendererTest, TransparentBackground) { gfx::Transform(), cc::FilterOperations()); root_pass->has_transparent_background = true; - EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1); - EXPECT_CALL(*context, clear(_)).Times(1); + EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1); + EXPECT_CALL(*gl, Clear(_)).Times(1); DrawFrame(&renderer, viewport_size); - Mock::VerifyAndClearExpectations(context); + Mock::VerifyAndClearExpectations(gl); } TEST_F(GLRendererTest, OffscreenOutputSurface) { - std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext); - ClearCountingContext* context = context_owned.get(); + auto gl_owned = std::make_unique<ClearCountingGLES2Interface>(); + auto* gl = gl_owned.get(); + gl_owned->set_have_discard_framebuffer(true); - auto provider = TestContextProvider::Create(std::move(context_owned)); + auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); cc::FakeOutputSurfaceClient output_surface_client; @@ -911,7 +931,7 @@ TEST_F(GLRendererTest, OffscreenOutputSurface) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -925,26 +945,25 @@ TEST_F(GLRendererTest, OffscreenOutputSurface) { cc::AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size), gfx::Transform(), cc::FilterOperations()); - EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _)) + EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _)) .With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0))) .Times(1); - EXPECT_CALL(*context, clear(_)).Times(AnyNumber()); + EXPECT_CALL(*gl, Clear(_)).Times(AnyNumber()); DrawFrame(&renderer, viewport_size); - Mock::VerifyAndClearExpectations(context); + Mock::VerifyAndClearExpectations(gl); } -class TextureStateTrackingContext : public TestWebGraphicsContext3D { +class TextureStateTrackingGLES2Interface : public TestGLES2Interface { public: - TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) { - test_capabilities_.egl_image_external = true; - } + TextureStateTrackingGLES2Interface() : active_texture_(GL_INVALID_ENUM) {} - MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token)); - MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param)); - MOCK_METHOD4(drawElements, - void(GLenum mode, GLsizei count, GLenum type, GLintptr offset)); + MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token)); + MOCK_METHOD3(TexParameteri, void(GLenum target, GLenum pname, GLint param)); + MOCK_METHOD4( + DrawElements, + void(GLenum mode, GLsizei count, GLenum type, const void* indices)); - virtual void activeTexture(GLenum texture) { + void ActiveTexture(GLenum texture) override { EXPECT_NE(texture, active_texture_); active_texture_ = texture; } @@ -956,11 +975,11 @@ class TextureStateTrackingContext : public TestWebGraphicsContext3D { }; TEST_F(GLRendererTest, ActiveTextureState) { - std::unique_ptr<TextureStateTrackingContext> context_owned( - new TextureStateTrackingContext); - TextureStateTrackingContext* context = context_owned.get(); + auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>(); + gl_owned->set_have_extension_egl_image(true); + auto* gl = gl_owned.get(); - auto provider = TestContextProvider::Create(std::move(context_owned)); + auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); cc::FakeOutputSurfaceClient output_surface_client; @@ -970,7 +989,7 @@ TEST_F(GLRendererTest, ActiveTextureState) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -981,32 +1000,31 @@ TEST_F(GLRendererTest, ActiveTextureState) { renderer.SetVisible(true); // During initialization we are allowed to set any texture parameters. - EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber()); + EXPECT_CALL(*gl, TexParameteri(_, _, _)).Times(AnyNumber()); - std::unique_ptr<TextureStateTrackingContext> child_context_owned( - new TextureStateTrackingContext); + auto child_gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>(); auto child_context_provider = - TestContextProvider::Create(std::move(child_context_owned)); + TestContextProvider::Create(std::move(child_gl_owned)); child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - child_context_provider.get(), shared_bitmap_manager.get()); + child_context_provider.get()); RenderPass* root_pass = cc::AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(100, 100), gfx::Transform(), cc::FilterOperations()); gpu::SyncToken mailbox_sync_token; AddOneOfEveryQuadTypeInDisplayResourceProvider( - root_pass, resource_provider.get(), child_resource_provider.get(), 0, - &mailbox_sync_token); + root_pass, resource_provider.get(), child_resource_provider.get(), + child_context_provider.get(), 0, &mailbox_sync_token); EXPECT_EQ(12u, resource_provider->num_resources()); renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_); // Set up expected texture filter state transitions that match the quads // created in AppendOneOfEveryQuadType(). - Mock::VerifyAndClearExpectations(context); + Mock::VerifyAndClearExpectations(gl); { InSequence sequence; // The verified flush flag will be set by @@ -1018,43 +1036,45 @@ TEST_F(GLRendererTest, ActiveTextureState) { // (with mailbox), resource2, resource3, resource4, resource9, resource10, // resource11, resource12. resource8 has its own mailbox mailbox_sync_token. // The rest resources share a common default sync token. - EXPECT_CALL(*context, waitSyncToken(_)).Times(2); - EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(mailbox_sync_token))) + EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(2); + EXPECT_CALL(*gl, + WaitSyncTokenCHROMIUM(MatchesSyncToken(mailbox_sync_token))) .Times(1); - EXPECT_CALL(*context, waitSyncToken(_)).Times(7); + EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(7); // yuv_quad is drawn with the default linear filter. - EXPECT_CALL(*context, drawElements(_, _, _, _)); + EXPECT_CALL(*gl, DrawElements(_, _, _, _)); // tile_quad is drawn with GL_NEAREST because it is not transformed or // scaled. - EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - GL_NEAREST)); - EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - GL_NEAREST)); + EXPECT_CALL( + *gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + EXPECT_CALL( + *gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); // The remaining quads also use GL_LINEAR because nearest neighbor // filtering is currently only used with tile quads. - EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(8); + EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(8); } gfx::Size viewport_size(100, 100); DrawFrame(&renderer, viewport_size); - Mock::VerifyAndClearExpectations(context); + Mock::VerifyAndClearExpectations(gl); } -class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D { +class NoClearRootRenderPassMockGLES2Interface : public TestGLES2Interface { public: - MOCK_METHOD1(clear, void(GLbitfield mask)); - MOCK_METHOD4(drawElements, - void(GLenum mode, GLsizei count, GLenum type, GLintptr offset)); + MOCK_METHOD1(Clear, void(GLbitfield mask)); + MOCK_METHOD4( + DrawElements, + void(GLenum mode, GLsizei count, GLenum type, const void* indices)); }; TEST_F(GLRendererTest, ShouldClearRootRenderPass) { - std::unique_ptr<NoClearRootRenderPassMockContext> mock_context_owned( - new NoClearRootRenderPassMockContext); - NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get(); + auto mock_gl_owned = + std::make_unique<NoClearRootRenderPassMockGLES2Interface>(); + NoClearRootRenderPassMockGLES2Interface* mock_gl = mock_gl_owned.get(); - auto provider = TestContextProvider::Create(std::move(mock_context_owned)); + auto provider = TestContextProvider::Create(std::move(mock_gl_owned)); provider->BindToCurrentThread(); cc::FakeOutputSurfaceClient output_surface_client; @@ -1064,7 +1084,7 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -1099,17 +1119,15 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) { #endif // First render pass is not the root one, clearing should happen. - EXPECT_CALL(*mock_context, clear(clear_bits)).Times(AtLeast(1)); + EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(AtLeast(1)); Expectation first_render_pass = - EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1); + EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _)).Times(1); // The second render pass is the root one, clearing should be prevented. - EXPECT_CALL(*mock_context, clear(clear_bits)) - .Times(0) - .After(first_render_pass); + EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(0).After(first_render_pass); - EXPECT_CALL(*mock_context, drawElements(_, _, _, _)) + EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _)) .Times(AnyNumber()) .After(first_render_pass); @@ -1118,7 +1136,7 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) { // In multiple render passes all but the root pass should clear the // framebuffer. - Mock::VerifyAndClearExpectations(&mock_context); + Mock::VerifyAndClearExpectations(&mock_gl); } class ScissorTestOnClearCheckingGLES2Interface : public TestGLES2Interface { @@ -1154,7 +1172,7 @@ TEST_F(GLRendererTest, ScissorTestWhenClearing) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -1198,11 +1216,6 @@ class DiscardCheckingGLES2Interface : public TestGLES2Interface { public: DiscardCheckingGLES2Interface() = default; - void InitializeTestContext(TestWebGraphicsContext3D* context) override { - context->set_have_post_sub_buffer(true); - context->set_have_discard_framebuffer(true); - } - void DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum* attachments) override { @@ -1218,6 +1231,9 @@ class DiscardCheckingGLES2Interface : public TestGLES2Interface { TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { auto gl_owned = std::make_unique<DiscardCheckingGLES2Interface>(); + gl_owned->set_have_post_sub_buffer(true); + gl_owned->set_have_discard_framebuffer(true); + auto* gl = gl_owned.get(); auto provider = TestContextProvider::Create(std::move(gl_owned)); @@ -1229,7 +1245,7 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -1429,7 +1445,7 @@ TEST_F(GLRendererTest, NoResourceLeak) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -1457,10 +1473,6 @@ TEST_F(GLRendererTest, NoResourceLeak) { class DrawElementsGLES2Interface : public TestGLES2Interface { public: - void InitializeTestContext(TestWebGraphicsContext3D* context) override { - context->set_have_post_sub_buffer(true); - } - MOCK_METHOD4( DrawElements, void(GLenum mode, GLsizei count, GLenum type, const void* indices)); @@ -1470,6 +1482,7 @@ class GLRendererSkipTest : public GLRendererTest { protected: GLRendererSkipTest() { auto gl_owned = std::make_unique<StrictMock<DrawElementsGLES2Interface>>(); + gl_owned->set_have_post_sub_buffer(true); gl_ = gl_owned.get(); auto provider = TestContextProvider::Create(std::move(gl_owned)); @@ -1494,7 +1507,7 @@ class GLRendererSkipTest : public GLRendererTest { cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; }; @@ -1567,7 +1580,7 @@ TEST_F(GLRendererTest, DrawFramePreservesFramebuffer) { std::unique_ptr<SharedBitmapManager> shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), shared_bitmap_manager.get()); @@ -1611,15 +1624,16 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) { int root_pass_id = 1; RenderPass* root_pass; - ResourceId mask = child_resource_provider_->CreateGpuTextureResource( - gfx::Size(20, 12), ResourceTextureHint::kDefault, - child_resource_provider_->best_texture_format(), gfx::ColorSpace()); - child_resource_provider_->AllocateForTesting(mask); + auto transfer_resource = TransferableResource::MakeGL( + gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken()); + ResourceId mask = child_resource_provider_->ImportResource( + transfer_resource, SingleReleaseCallback::Create(base::DoNothing())); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({mask}, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), + child_context_provider_.get()); ResourceId mapped_mask = resource_map[mask]; SkScalar matrix[20]; @@ -1867,28 +1881,34 @@ TEST_F(GLRendererShaderTest, DrawSolidColorShader) { TestSolidColorProgramAA(); } -class OutputSurfaceMockContext : public TestWebGraphicsContext3D { +class OutputSurfaceMockGLES2Interface : public TestGLES2Interface { public: - OutputSurfaceMockContext() { test_capabilities_.post_sub_buffer = true; } + OutputSurfaceMockGLES2Interface() = default; // Specifically override methods even if they are unused (used in conjunction // with StrictMock). We need to make sure that GLRenderer does not issue // framebuffer-related GLuint calls directly. Instead these are supposed to go // through the OutputSurface abstraction. - MOCK_METHOD2(bindFramebuffer, void(GLenum target, GLuint framebuffer)); - MOCK_METHOD3(reshapeWithScaleFactor, - void(int width, int height, float scale_factor)); - MOCK_METHOD4(drawElements, - void(GLenum mode, GLsizei count, GLenum type, GLintptr offset)); + MOCK_METHOD2(BindFramebuffer, void(GLenum target, GLuint framebuffer)); + MOCK_METHOD5(ResizeCHROMIUM, + void(GLuint width, + GLuint height, + float device_scale, + GLenum color_space, + GLboolean has_alpha)); + MOCK_METHOD4( + DrawElements, + void(GLenum mode, GLsizei count, GLenum type, const void* indices)); }; class MockOutputSurface : public OutputSurface { public: explicit MockOutputSurface(scoped_refptr<ContextProvider> provider) : OutputSurface(std::move(provider)) {} - virtual ~MockOutputSurface() {} + ~MockOutputSurface() override {} void BindToClient(OutputSurfaceClient*) override {} + unsigned UpdateGpuFence() override { return 0; } MOCK_METHOD0(EnsureBackbuffer, void()); MOCK_METHOD0(DiscardBackbuffer, void()); @@ -1908,7 +1928,6 @@ class MockOutputSurface : public OutputSurface { MOCK_CONST_METHOD0(IsDisplayedAsOverlayPlane, bool()); MOCK_CONST_METHOD0(GetOverlayTextureId, unsigned()); MOCK_CONST_METHOD0(GetOverlayBufferFormat, gfx::BufferFormat()); - MOCK_CONST_METHOD0(SurfaceIsSuspendForRecycle, bool()); MOCK_CONST_METHOD0(HasExternalStencilTest, bool()); MOCK_METHOD0(ApplyExternalStencil, void()); }; @@ -1916,9 +1935,10 @@ class MockOutputSurface : public OutputSurface { class MockOutputSurfaceTest : public GLRendererTest { protected: void SetUp() override { - auto context = std::make_unique<StrictMock<OutputSurfaceMockContext>>(); - context_ = context.get(); - auto provider = TestContextProvider::Create(std::move(context)); + auto gl = std::make_unique<StrictMock<OutputSurfaceMockGLES2Interface>>(); + gl->set_have_post_sub_buffer(true); + gl_ = gl.get(); + auto provider = TestContextProvider::Create(std::move(gl)); provider->BindToCurrentThread(); output_surface_ = std::make_unique<StrictMock<MockOutputSurface>>(std::move(provider)); @@ -1941,7 +1961,9 @@ class MockOutputSurfaceTest : public GLRendererTest { Mock::VerifyAndClearExpectations(output_surface_.get()); } - void SwapBuffers() { renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); } + void SwapBuffers() { + renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false); + } void DrawFrame(float device_scale_factor, const gfx::Size& viewport_size, @@ -1961,7 +1983,7 @@ class MockOutputSurfaceTest : public GLRendererTest { EXPECT_CALL(*output_surface_, BindFramebuffer()).Times(1); - EXPECT_CALL(*context_, drawElements(_, _, _, _)).Times(1); + EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1); renderer_->DecideRenderPassAllocationsForFrame( render_passes_in_draw_order_); @@ -1971,10 +1993,10 @@ class MockOutputSurfaceTest : public GLRendererTest { RendererSettings settings_; cc::FakeOutputSurfaceClient output_surface_client_; - OutputSurfaceMockContext* context_ = nullptr; + OutputSurfaceMockGLES2Interface* gl_ = nullptr; std::unique_ptr<StrictMock<MockOutputSurface>> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<FakeRendererGL> renderer_; }; @@ -1999,9 +2021,9 @@ class TestOverlayProcessor : public OverlayProcessor { MOCK_METHOD5(Attempt, bool(const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidates, + OverlayCandidateList* candidates, std::vector<gfx::Rect>* content_bounds)); }; @@ -2019,7 +2041,7 @@ class TestOverlayProcessor : public OverlayProcessor { // to be traditionally composited. Candidates with |overlay_handled| set to // true must also have their |display_rect| converted to integer // coordinates if necessary. - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) {} + void CheckOverlaySupport(OverlayCandidateList* surfaces) override {} }; explicit TestOverlayProcessor(OutputSurface* surface) @@ -2056,7 +2078,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) { child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - child_context_provider.get(), shared_bitmap_manager.get()); + child_context_provider.get()); auto transfer_resource = TransferableResource::MakeGLOverlay( gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(), @@ -2071,14 +2093,15 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) { base::Bind(&CollectResources, &returned_to_child)); // Transfer resource to the parent. - cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer; + std::vector<ResourceId> resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource_id); std::vector<TransferableResource> list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list); + child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list, + child_context_provider.get()); parent_resource_provider->ReceiveFromChild(child_id, list); // In DisplayResourceProvider's namespace, use the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = parent_resource_provider->GetChildToParentMap(child_id); ResourceId parent_resource_id = resource_map[list[0].id]; @@ -2188,9 +2211,9 @@ class SingleOverlayOnTopProcessor : public OverlayProcessor { bool AllowCALayerOverlays() override { return false; } bool AllowDCLayerOverlays() override { return false; } - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override { + void CheckOverlaySupport(OverlayCandidateList* surfaces) override { ASSERT_EQ(1U, surfaces->size()); - cc::OverlayCandidate& candidate = surfaces->back(); + OverlayCandidate& candidate = surfaces->back(); candidate.overlay_handled = true; } }; @@ -2206,27 +2229,28 @@ class SingleOverlayOnTopProcessor : public OverlayProcessor { SingleOverlayValidator validator_; }; -class WaitSyncTokenCountingContext : public TestWebGraphicsContext3D { +class WaitSyncTokenCountingGLES2Interface : public TestGLES2Interface { public: - MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token)); + MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token)); }; class MockOverlayScheduler { public: - MOCK_METHOD5(Schedule, + MOCK_METHOD7(Schedule, void(int plane_z_order, gfx::OverlayTransform plane_transform, unsigned overlay_texture_id, const gfx::Rect& display_bounds, - const gfx::RectF& uv_rect)); + const gfx::RectF& uv_rect, + bool enable_blend, + unsigned gpu_fence_id)); }; TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) { - std::unique_ptr<WaitSyncTokenCountingContext> context_owned( - new WaitSyncTokenCountingContext); - WaitSyncTokenCountingContext* context = context_owned.get(); + auto gl_owned = std::make_unique<WaitSyncTokenCountingGLES2Interface>(); + WaitSyncTokenCountingGLES2Interface* gl = gl_owned.get(); - auto provider = TestContextProvider::Create(std::move(context_owned)); + auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); MockOverlayScheduler overlay_scheduler; @@ -2248,7 +2272,7 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) { child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - child_context_provider.get(), shared_bitmap_manager.get()); + child_context_provider.get()); gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, gpu::CommandBufferId::FromUnsafeValue(0x123), 29); @@ -2265,14 +2289,15 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) { base::Bind(&CollectResources, &returned_to_child)); // Transfer resource to the parent. - cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer; + std::vector<ResourceId> resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource_id); std::vector<TransferableResource> list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list); + child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list, + child_context_provider.get()); parent_resource_provider->ReceiveFromChild(child_id, list); // In DisplayResourceProvider's namespace, use the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = parent_resource_provider->GetChildToParentMap(child_id); ResourceId parent_resource_id = resource_map[list[0].id]; @@ -2321,12 +2346,13 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) { // Verify that overlay_quad actually gets turned into an overlay, and even // though it's not drawn, that its sync point is waited on. - EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))).Times(1); + EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(MatchesSyncToken(sync_token))) + .Times(1); EXPECT_CALL( overlay_scheduler, Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, gfx::Rect(viewport_size), - BoundingRect(uv_top_left, uv_bottom_right))) + BoundingRect(uv_top_left, uv_bottom_right), _, _)) .Times(1); DrawFrame(&renderer, viewport_size); @@ -2358,7 +2384,7 @@ TEST_F(GLRendererTest, OutputColorMatrixTest) { FakeOutputSurface::Create3d(std::move(provider))); cc::FakeOutputSurfaceClient output_surface_client; output_surface->BindToClient(&output_surface_client); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), nullptr); RendererSettings settings; @@ -2434,16 +2460,17 @@ class GenerateMipmapMockGLESInterface : public TestGLES2Interface { TEST_F(GLRendererTest, GenerateMipmap) { // Initialize the mock GL interface, the output surface and the renderer. auto gl_owned = std::make_unique<GenerateMipmapMockGLESInterface>(); + gl_owned->set_support_texture_npot(true); + auto* gl = gl_owned.get(); auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); - provider->TestContext3d()->set_support_texture_npot(true); std::unique_ptr<FakeOutputSurface> output_surface( FakeOutputSurface::Create3d(std::move(provider))); cc::FakeOutputSurfaceClient output_surface_client; output_surface->BindToClient(&output_surface_client); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), nullptr); RendererSettings settings; @@ -2480,28 +2507,21 @@ TEST_F(GLRendererTest, GenerateMipmap) { class PartialSwapMockGLES2Interface : public TestGLES2Interface { public: - explicit PartialSwapMockGLES2Interface(bool support_dc_layers) - : support_dc_layers_(support_dc_layers) {} - - void InitializeTestContext(TestWebGraphicsContext3D* context) override { - context->set_have_post_sub_buffer(true); - context->set_enable_dc_layers(support_dc_layers_); - } + PartialSwapMockGLES2Interface() = default; MOCK_METHOD1(Enable, void(GLenum cap)); MOCK_METHOD1(Disable, void(GLenum cap)); MOCK_METHOD4(Scissor, void(GLint x, GLint y, GLsizei width, GLsizei height)); MOCK_METHOD1(SetEnableDCLayersCHROMIUM, void(GLboolean enable)); - - private: - bool support_dc_layers_; }; class GLRendererPartialSwapTest : public GLRendererTest { protected: void RunTest(bool partial_swap, bool set_draw_rectangle) { - auto gl_owned = - std::make_unique<PartialSwapMockGLES2Interface>(set_draw_rectangle); + auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>(); + gl_owned->set_have_post_sub_buffer(true); + gl_owned->set_enable_dc_layers(set_draw_rectangle); + auto* gl = gl_owned.get(); auto provider = TestContextProvider::Create(std::move(gl_owned)); @@ -2512,7 +2532,7 @@ class GLRendererPartialSwapTest : public GLRendererTest { FakeOutputSurface::Create3d(std::move(provider))); output_surface->BindToClient(&output_surface_client); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), nullptr); @@ -2606,7 +2626,7 @@ class DCLayerValidator : public OverlayCandidateValidator { void GetStrategies(OverlayProcessor::StrategyList* strategies) override {} bool AllowCALayerOverlays() override { return false; } bool AllowDCLayerOverlays() override { return true; } - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {} + void CheckOverlaySupport(OverlayCandidateList* surfaces) override {} }; // Test that SetEnableDCLayersCHROMIUM is properly called when enabling @@ -2614,7 +2634,9 @@ class DCLayerValidator : public OverlayCandidateValidator { TEST_F(GLRendererTest, DCLayerOverlaySwitch) { base::test::ScopedFeatureList feature_list; feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays); - auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>(true); + auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>(); + gl_owned->set_have_post_sub_buffer(true); + gl_owned->set_enable_dc_layers(true); auto* gl = gl_owned.get(); auto provider = TestContextProvider::Create(std::move(gl_owned)); @@ -2633,7 +2655,7 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) { child_context_provider->BindToCurrentThread(); auto child_resource_provider = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - child_context_provider.get(), nullptr); + child_context_provider.get()); auto transfer_resource = TransferableResource::MakeGLOverlay( gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(), @@ -2648,13 +2670,14 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) { base::Bind(&CollectResources, &returned_to_child)); // Transfer resource to the parent. - cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer; + std::vector<ResourceId> resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource_id); std::vector<TransferableResource> list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list); + child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list, + child_context_provider.get()); parent_resource_provider->ReceiveFromChild(child_id, list); // In DisplayResourceProvider's namespace, use the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = parent_resource_provider->GetChildToParentMap(child_id); ResourceId parent_resource_id = resource_map[list[0].id]; @@ -2740,8 +2763,8 @@ class GLRendererWithMockContextTest : public ::testing::Test { void SetUp() override { auto context_support = std::make_unique<MockContextSupport>(); context_support_ptr_ = context_support.get(); - auto context_provider = TestContextProvider::Create( - TestWebGraphicsContext3D::Create(), std::move(context_support)); + auto context_provider = + TestContextProvider::Create(std::move(context_support)); ASSERT_EQ(context_provider->BindToCurrentThread(), gpu::ContextResult::kSuccess); output_surface_ = FakeOutputSurface::Create3d(std::move(context_provider)); @@ -2758,7 +2781,7 @@ class GLRendererWithMockContextTest : public ::testing::Test { cc::FakeOutputSurfaceClient output_surface_client_; MockContextSupport* context_support_ptr_; std::unique_ptr<OutputSurface> output_surface_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<GLRenderer> renderer_; }; @@ -2773,13 +2796,6 @@ TEST_F(GLRendererWithMockContextTest, Mock::VerifyAndClearExpectations(context_support_ptr_); } -class SwapWithBoundsMockGLES2Interface : public TestGLES2Interface { - public: - void InitializeTestContext(TestWebGraphicsContext3D* context) override { - context->set_have_swap_buffers_with_bounds(true); - } -}; - class ContentBoundsOverlayProcessor : public OverlayProcessor { public: class Strategy : public OverlayProcessor::Strategy { @@ -2789,9 +2805,9 @@ class ContentBoundsOverlayProcessor : public OverlayProcessor { ~Strategy() override = default; bool Attempt(const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidates, + OverlayCandidateList* candidates, std::vector<gfx::Rect>* content_bounds) override { content_bounds->insert(content_bounds->end(), content_bounds_.begin(), content_bounds_.end()); @@ -2820,7 +2836,8 @@ class ContentBoundsOverlayProcessor : public OverlayProcessor { class GLRendererSwapWithBoundsTest : public GLRendererTest { protected: void RunTest(const std::vector<gfx::Rect>& content_bounds) { - auto gl_owned = std::make_unique<SwapWithBoundsMockGLES2Interface>(); + auto gl_owned = std::make_unique<TestGLES2Interface>(); + gl_owned->set_have_swap_buffers_with_bounds(true); auto provider = TestContextProvider::Create(std::move(gl_owned)); provider->BindToCurrentThread(); @@ -2830,7 +2847,7 @@ class GLRendererSwapWithBoundsTest : public GLRendererTest { FakeOutputSurface::Create3d(std::move(provider))); output_surface->BindToClient(&output_surface_client); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), nullptr); @@ -2857,7 +2874,7 @@ class GLRendererSwapWithBoundsTest : public GLRendererTest { renderer.DecideRenderPassAllocationsForFrame( render_passes_in_draw_order_); DrawFrame(&renderer, viewport_size); - renderer.SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer.SwapBuffers(std::vector<ui::LatencyInfo>(), false); std::vector<gfx::Rect> expected_content_bounds; EXPECT_EQ(content_bounds, @@ -2883,7 +2900,7 @@ class CALayerValidator : public OverlayCandidateValidator { void GetStrategies(OverlayProcessor::StrategyList* strategies) override {} bool AllowCALayerOverlays() override { return true; } bool AllowDCLayerOverlays() override { return false; } - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {} + void CheckOverlaySupport(OverlayCandidateList* surfaces) override {} }; class MockCALayerGLES2Interface : public TestGLES2Interface { @@ -2903,16 +2920,6 @@ class MockCALayerGLES2Interface : public TestGLES2Interface { GLuint filter)); MOCK_METHOD2(ScheduleCALayerInUseQueryCHROMIUM, void(GLsizei count, const GLuint* textures)); - - void InitializeTestContext(TestWebGraphicsContext3D* context) override { - // Support image storage for GpuMemoryBuffers, needed for - // CALayers/IOSurfaces backed by textures. - context->set_support_texture_storage_image(true); - - // Allow the renderer to make an empty SwapBuffers - skipping even the - // root RenderPass. - context->set_have_commit_overlay_planes(true); - } }; class CALayerGLRendererTest : public GLRendererTest { @@ -2920,6 +2927,13 @@ class CALayerGLRendererTest : public GLRendererTest { void SetUp() override { // A mock GLES2Interface that can watch CALayer stuff happen. auto gles2_interface = std::make_unique<MockCALayerGLES2Interface>(); + // Support image storage for GpuMemoryBuffers, needed for + // CALayers/IOSurfaces backed by textures. + gles2_interface->set_support_texture_storage_image(true); + // Allow the renderer to make an empty SwapBuffers - skipping even the + // root RenderPass. + gles2_interface->set_have_commit_overlay_planes(true); + gl_ = gles2_interface.get(); auto provider = TestContextProvider::Create(std::move(gles2_interface)); @@ -2967,7 +2981,7 @@ class CALayerGLRendererTest : public GLRendererTest { MockCALayerGLES2Interface* gl_; CALayerValidator validator_; std::unique_ptr<FakeOutputSurface> output_surface_; - std::unique_ptr<cc::DisplayResourceProvider> display_resource_provider_; + std::unique_ptr<DisplayResourceProvider> display_resource_provider_; std::unique_ptr<RendererSettings> settings_; std::unique_ptr<FakeRendererGL> renderer_; }; @@ -3011,7 +3025,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysWithAllQuadsPromoted) { DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // The damage was eliminated when everything was promoted to CALayers. ASSERT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect); @@ -3049,7 +3063,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysWithAllQuadsPromoted) { DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); } TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) { @@ -3098,7 +3112,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) { } DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // ScheduleCALayerCHROMIUM happened and used a non-0 texture. EXPECT_NE(saved_texture_id, 0u); @@ -3151,7 +3165,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) { } DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // There are now 2 textures to check if they are free. EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _)); @@ -3201,7 +3215,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) { } DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); } TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) { @@ -3250,7 +3264,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) { } DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // ScheduleCALayerCHROMIUM happened and used a non-0 texture. EXPECT_NE(saved_texture_id, 0u); @@ -3301,7 +3315,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) { } DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // There are now 2 textures to check if they are free. EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _)); @@ -3349,7 +3363,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) { } DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); } TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseAfterNoSwapBuffers) { @@ -3435,7 +3449,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseAfterNoSwapBuffers) { Mock::VerifyAndClearExpectations(&gl()); // SwapBuffers() *does* happen this time. - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // There are 2 textures to check if they are free. EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _)); @@ -3480,7 +3494,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseAfterNoSwapBuffers) { } DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); } TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseManyIfReturnedSlowly) { @@ -3524,7 +3538,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseManyIfReturnedSlowly) { })); DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // ScheduleCALayerCHROMIUM happened and used a non-0 texture. EXPECT_NE(sent_texture_ids[i], 0u); @@ -3598,7 +3612,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseManyIfReturnedSlowly) { })); DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // All sent textures will be checked to verify if they are free yet. There's // also 1 outstanding texture to check for that wasn't returned yet from the @@ -3649,7 +3663,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysCachedTexturesAreFreed) { })); DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // ScheduleCALayerCHROMIUM happened and used a non-0 texture. EXPECT_NE(sent_texture_ids[i], 0u); @@ -3689,7 +3703,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysCachedTexturesAreFreed) { EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _)); DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); // There's just 1 outstanding RenderPass texture to query for. EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _)); @@ -3735,14 +3749,14 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysCachedTexturesAreFreed) { })); DrawFrame(&renderer(), viewport_size); Mock::VerifyAndClearExpectations(&gl()); - renderer().SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false); } class FramebufferWatchingGLRenderer : public FakeRendererGL { public: FramebufferWatchingGLRenderer(RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider) + DisplayResourceProvider* resource_provider) : FakeRendererGL(settings, output_surface, resource_provider) {} void BindFramebufferToOutputSurface() override { @@ -3780,7 +3794,7 @@ TEST_F(GLRendererTest, UndamagedRenderPassStillDrawnWhenNoPartialSwap) { auto output_surface = FakeOutputSurface::Create3d(std::move(provider)); output_surface->BindToClient(&output_surface_client); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( output_surface->context_provider(), nullptr); diff --git a/chromium/components/viz/service/display/output_surface.cc b/chromium/components/viz/service/display/output_surface.cc index 87cdf3118b7..f563afc1deb 100644 --- a/chromium/components/viz/service/display/output_surface.cc +++ b/chromium/components/viz/service/display/output_surface.cc @@ -16,6 +16,7 @@ #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" +#include "gpu/vulkan/buildflags.h" #include "ui/gfx/swap_result.h" namespace viz { @@ -31,72 +32,35 @@ OutputSurface::OutputSurface( DCHECK(software_device_); } +#if BUILDFLAG(ENABLE_VULKAN) OutputSurface::OutputSurface( scoped_refptr<VulkanContextProvider> vulkan_context_provider) : vulkan_context_provider_(std::move(vulkan_context_provider)) { DCHECK(vulkan_context_provider_); } +#endif OutputSurface::~OutputSurface() = default; -OutputSurface::LatencyInfoCache::SwapInfo::SwapInfo( - uint64_t id, - std::vector<ui::LatencyInfo> info) - : swap_id(id), latency_info(std::move(info)) {} - -OutputSurface::LatencyInfoCache::SwapInfo::SwapInfo(SwapInfo&& src) = default; - -OutputSurface::LatencyInfoCache::SwapInfo& -OutputSurface::LatencyInfoCache::SwapInfo::operator=(SwapInfo&& src) = default; - -OutputSurface::LatencyInfoCache::SwapInfo::~SwapInfo() = default; - -OutputSurface::LatencyInfoCache::LatencyInfoCache(Client* client) - : client_(client) { - DCHECK(client); -} - -OutputSurface::LatencyInfoCache::~LatencyInfoCache() = default; - -bool OutputSurface::LatencyInfoCache::WillSwap( - std::vector<ui::LatencyInfo> latency_info) { - bool snapshot_requested = false; - for (const auto& latency : latency_info) { - if (latency.FindLatency(ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT, - nullptr)) { - snapshot_requested = true; - break; - } - } - - // Don't grow unbounded in case of error. - while (swap_infos_.size() >= kCacheCountMax) { - client_->LatencyInfoCompleted(swap_infos_.front().latency_info); - swap_infos_.pop_front(); +void OutputSurface::UpdateLatencyInfoOnSwap( + const gfx::SwapResponse& response, + std::vector<ui::LatencyInfo>* latency_info) { + for (auto& latency : *latency_info) { + latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, response.swap_start, 1); + latency.AddLatencyNumberWithTimestamp( + ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, + response.swap_end, 1); } - swap_infos_.emplace_back(swap_id_++, std::move(latency_info)); - - return snapshot_requested; } -void OutputSurface::LatencyInfoCache::OnSwapBuffersCompleted( - const gfx::SwapResponse& response) { - auto it = std::find_if( - swap_infos_.begin(), swap_infos_.end(), - [&](const SwapInfo& si) { return si.swap_id == response.swap_id; }); - - if (it != swap_infos_.end()) { - for (auto& latency : it->latency_info) { - latency.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, response.swap_start, - 1); - latency.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, - response.swap_end, 1); - } - client_->LatencyInfoCompleted(it->latency_info); - swap_infos_.erase(it); +bool OutputSurface::LatencyInfoHasSnapshotRequest( + const std::vector<ui::LatencyInfo>& latency_info) { + for (const auto& latency : latency_info) { + if (latency.Snapshots().size()) + return true; } + return false; } } // namespace viz diff --git a/chromium/components/viz/service/display/output_surface.h b/chromium/components/viz/service/display/output_surface.h index 26d0e6394c2..9eaef93529a 100644 --- a/chromium/components/viz/service/display/output_surface.h +++ b/chromium/components/viz/service/display/output_surface.h @@ -12,17 +12,20 @@ #include "base/memory/ref_counted.h" #include "base/threading/thread_checker.h" #include "components/viz/common/gpu/context_provider.h" -#include "components/viz/common/gpu/vulkan_context_provider.h" #include "components/viz/common/resources/returned_resource.h" #include "components/viz/service/display/overlay_candidate_validator.h" #include "components/viz/service/display/software_output_device.h" #include "components/viz/service/viz_service_export.h" #include "gpu/command_buffer/common/texture_in_use_response.h" #include "gpu/vulkan/buildflags.h" -#include "gpu/vulkan/vulkan_surface.h" #include "ui/gfx/color_space.h" #include "ui/latency/latency_info.h" +#if BUILDFLAG(ENABLE_VULKAN) +#include "components/viz/common/gpu/vulkan_context_provider.h" +#include "gpu/vulkan/vulkan_surface.h" +#endif + namespace gfx { class ColorSpace; class Size; @@ -57,9 +60,11 @@ class VIZ_SERVICE_EXPORT OutputSurface { explicit OutputSurface(scoped_refptr<ContextProvider> context_provider); // Constructor for software compositing. explicit OutputSurface(std::unique_ptr<SoftwareOutputDevice> software_device); +#if BUILDFLAG(ENABLE_VULKAN) // Constructor for Vulkan-based compositing. explicit OutputSurface( scoped_refptr<VulkanContextProvider> vulkan_context_provider); +#endif virtual ~OutputSurface(); @@ -70,9 +75,11 @@ class VIZ_SERVICE_EXPORT OutputSurface { // In the event of a lost context, the entire output surface should be // recreated. ContextProvider* context_provider() const { return context_provider_.get(); } +#if BUILDFLAG(ENABLE_VULKAN) VulkanContextProvider* vulkan_context_provider() const { return vulkan_context_provider_.get(); } +#endif SoftwareOutputDevice* software_device() const { return software_device_.get(); } @@ -108,9 +115,6 @@ class VIZ_SERVICE_EXPORT OutputSurface { // Get the format for the main image's overlay. virtual gfx::BufferFormat GetOverlayBufferFormat() const = 0; - // If this returns true, then the surface will not attempt to draw. - virtual bool SurfaceIsSuspendForRecycle() const = 0; - virtual void Reshape(const gfx::Size& size, float device_scale_factor, const gfx::ColorSpace& color_space, @@ -134,54 +138,30 @@ class VIZ_SERVICE_EXPORT OutputSurface { virtual gpu::VulkanSurface* GetVulkanSurface() = 0; #endif - // A helper class for implementations of OutputSurface that want to cache - // LatencyInfos that can be updated when we get the corresponding - // gfx::SwapResponse. - class VIZ_SERVICE_EXPORT LatencyInfoCache { - public: - class Client { - public: - virtual ~Client() = default; - virtual void LatencyInfoCompleted( - const std::vector<ui::LatencyInfo>& latency_info) = 0; - }; - - explicit LatencyInfoCache(Client* client); - ~LatencyInfoCache(); - - // Returns true if there's a snapshot request. - bool WillSwap(std::vector<ui::LatencyInfo> latency_info); - void OnSwapBuffersCompleted(const gfx::SwapResponse& response); - - private: - struct SwapInfo { - SwapInfo(uint64_t id, std::vector<ui::LatencyInfo> info); - SwapInfo(SwapInfo&& src); - SwapInfo& operator=(SwapInfo&& src); - ~SwapInfo(); - uint64_t swap_id; - std::vector<ui::LatencyInfo> latency_info; - DISALLOW_COPY_AND_ASSIGN(SwapInfo); - }; - - Client* client_ = nullptr; - - // Incremented in sync with the ImageTransportSurface's swap_id_. - uint64_t swap_id_ = 0; - base::circular_deque<SwapInfo> swap_infos_; - - // We only expect a couple swap acks outstanding, but there are cases where - // we will get timestamps for swaps from several frames ago when using - // platform extensions like eglGetFrameTimestampsANDROID. - static constexpr size_t kCacheCountMax = 10; - - DISALLOW_COPY_AND_ASSIGN(LatencyInfoCache); - }; + // Updates the GpuFence associated with this surface. The id of a newly + // created GpuFence is returned, or if an error occurs, or fences are not + // supported, the special id of 0 (meaning "no fence") is returned. In all + // cases, any previously associated fence is destroyed. The returned fence id + // corresponds to the GL id used by the CHROMIUM_gpu_fence GL extension and + // can be passed directly to any related extension functions. + virtual unsigned UpdateGpuFence() = 0; + + // Returns true if any of the LatencyInfos provided contains a snapshot + // request. + static bool LatencyInfoHasSnapshotRequest( + const std::vector<ui::LatencyInfo>& latency_info); + + // Updates timing info on the provided LatencyInfo when swap completes. + static void UpdateLatencyInfoOnSwap( + const gfx::SwapResponse& response, + std::vector<ui::LatencyInfo>* latency_info); protected: struct OutputSurface::Capabilities capabilities_; scoped_refptr<ContextProvider> context_provider_; +#if BUILDFLAG(ENABLE_VULKAN) scoped_refptr<VulkanContextProvider> vulkan_context_provider_; +#endif std::unique_ptr<SoftwareOutputDevice> software_device_; private: diff --git a/chromium/components/viz/service/display/output_surface_client.h b/chromium/components/viz/service/display/output_surface_client.h index 58c086544c7..e802952c92d 100644 --- a/chromium/components/viz/service/display/output_surface_client.h +++ b/chromium/components/viz/service/display/output_surface_client.h @@ -13,6 +13,7 @@ #include "components/viz/service/viz_service_export.h" #include "gpu/command_buffer/common/texture_in_use_response.h" #include "ui/gfx/geometry/rect.h" +#include "ui/latency/latency_info.h" namespace gfx { struct CALayerParams; @@ -25,7 +26,7 @@ class VIZ_SERVICE_EXPORT OutputSurfaceClient { public: // A notification that the swap of the backbuffer to the hardware is complete // and is now visible to the user. - virtual void DidReceiveSwapBuffersAck(uint64_t swap_id) = 0; + virtual void DidReceiveSwapBuffersAck() = 0; // For surfaceless/ozone implementations to create damage for the next frame. virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0; @@ -38,12 +39,14 @@ class VIZ_SERVICE_EXPORT OutputSurfaceClient { virtual void DidReceiveCALayerParams( const gfx::CALayerParams& ca_layer_params) = 0; - // A notification that the presentation feedback for a CompositorFrame with - // given |swap_id|. See |gfx::PresentationFeedback| for detail. + // See |gfx::PresentationFeedback| for detail. virtual void DidReceivePresentationFeedback( - uint64_t swap_id, const gfx::PresentationFeedback& feedback) {} + // Call after a swap occurs with all LatencyInfo aggregated up to that point. + virtual void DidFinishLatencyInfo( + const std::vector<ui::LatencyInfo>& latency_info) = 0; + protected: virtual ~OutputSurfaceClient() {} }; diff --git a/chromium/components/viz/service/display/output_surface_frame.h b/chromium/components/viz/service/display/output_surface_frame.h index 6a09dfa06da..b3f20cedc66 100644 --- a/chromium/components/viz/service/display/output_surface_frame.h +++ b/chromium/components/viz/service/display/output_surface_frame.h @@ -34,6 +34,7 @@ class VIZ_SERVICE_EXPORT OutputSurfaceFrame { // Optional content area for SwapWithBounds. Rectangles may overlap. std::vector<gfx::Rect> content_bounds; std::vector<ui::LatencyInfo> latency_info; + bool need_presentation_feedback = false; private: DISALLOW_COPY_AND_ASSIGN(OutputSurfaceFrame); diff --git a/chromium/components/viz/service/display/overlay_candidate.cc b/chromium/components/viz/service/display/overlay_candidate.cc new file mode 100644 index 00000000000..2cac5568008 --- /dev/null +++ b/chromium/components/viz/service/display/overlay_candidate.cc @@ -0,0 +1,397 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display/overlay_candidate.h" + +#include <algorithm> +#include <limits> + +#include "base/logging.h" +#include "build/build_config.h" +#include "cc/base/math_util.h" +#include "components/viz/common/quads/solid_color_draw_quad.h" +#include "components/viz/common/quads/stream_video_draw_quad.h" +#include "components/viz/common/quads/texture_draw_quad.h" +#include "components/viz/common/quads/tile_draw_quad.h" +#include "components/viz/service/display/display_resource_provider.h" +#include "ui/gfx/geometry/rect_conversions.h" +#include "ui/gfx/geometry/vector3d_f.h" + +namespace viz { + +namespace { +// Tolerance for considering axis vector elements to be zero. +const SkMScalar kEpsilon = std::numeric_limits<float>::epsilon(); + +const gfx::BufferFormat kOverlayFormats[] = { + gfx::BufferFormat::RGBX_8888, gfx::BufferFormat::RGBA_8888, + gfx::BufferFormat::BGRX_8888, gfx::BufferFormat::BGRA_8888, + gfx::BufferFormat::BGR_565, gfx::BufferFormat::YUV_420_BIPLANAR}; + +enum Axis { NONE, AXIS_POS_X, AXIS_NEG_X, AXIS_POS_Y, AXIS_NEG_Y }; + +Axis VectorToAxis(const gfx::Vector3dF& vec) { + if (std::abs(vec.z()) > kEpsilon) + return NONE; + const bool x_zero = (std::abs(vec.x()) <= kEpsilon); + const bool y_zero = (std::abs(vec.y()) <= kEpsilon); + if (x_zero && !y_zero) + return (vec.y() > 0) ? AXIS_POS_Y : AXIS_NEG_Y; + else if (y_zero && !x_zero) + return (vec.x() > 0) ? AXIS_POS_X : AXIS_NEG_X; + else + return NONE; +} + +gfx::OverlayTransform GetOverlayTransform(const gfx::Transform& quad_transform, + bool y_flipped) { + if (!quad_transform.Preserves2dAxisAlignment()) { + return gfx::OVERLAY_TRANSFORM_INVALID; + } + + gfx::Vector3dF x_axis = cc::MathUtil::GetXAxis(quad_transform); + gfx::Vector3dF y_axis = cc::MathUtil::GetYAxis(quad_transform); + if (y_flipped) { + y_axis.Scale(-1); + } + + Axis x_to = VectorToAxis(x_axis); + Axis y_to = VectorToAxis(y_axis); + + if (x_to == AXIS_POS_X && y_to == AXIS_POS_Y) + return gfx::OVERLAY_TRANSFORM_NONE; + else if (x_to == AXIS_NEG_X && y_to == AXIS_POS_Y) + return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL; + else if (x_to == AXIS_POS_X && y_to == AXIS_NEG_Y) + return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL; + else if (x_to == AXIS_NEG_Y && y_to == AXIS_POS_X) + return gfx::OVERLAY_TRANSFORM_ROTATE_270; + else if (x_to == AXIS_NEG_X && y_to == AXIS_NEG_Y) + return gfx::OVERLAY_TRANSFORM_ROTATE_180; + else if (x_to == AXIS_POS_Y && y_to == AXIS_NEG_X) + return gfx::OVERLAY_TRANSFORM_ROTATE_90; + else + return gfx::OVERLAY_TRANSFORM_INVALID; +} + +// Apply transform |delta| to |in| and return the resulting transform, +// or OVERLAY_TRANSFORM_INVALID. +gfx::OverlayTransform ComposeTransforms(gfx::OverlayTransform delta, + gfx::OverlayTransform in) { + // There are 8 different possible transforms. We can characterize these + // by looking at where the origin moves and the direction the horizontal goes. + // (TL=top-left, BR=bottom-right, H=horizontal, V=vertical). + // NONE: TL, H + // FLIP_VERTICAL: BL, H + // FLIP_HORIZONTAL: TR, H + // ROTATE_90: TR, V + // ROTATE_180: BR, H + // ROTATE_270: BL, V + // Missing transforms: TL, V & BR, V + // Basic combinations: + // Flip X & Y -> Rotate 180 (TL,H -> TR,H -> BR,H or TL,H -> BL,H -> BR,H) + // Flip X or Y + Rotate 180 -> other flip (eg, TL,H -> TR,H -> BL,H) + // Rotate + Rotate simply adds values. + // Rotate 90/270 + flip is invalid because we can only have verticals with + // the origin in TR or BL. + if (delta == gfx::OVERLAY_TRANSFORM_NONE) + return in; + switch (in) { + case gfx::OVERLAY_TRANSFORM_NONE: + return delta; + case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL: + switch (delta) { + case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL: + return gfx::OVERLAY_TRANSFORM_NONE; + case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL: + return gfx::OVERLAY_TRANSFORM_ROTATE_180; + case gfx::OVERLAY_TRANSFORM_ROTATE_180: + return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL; + default: + return gfx::OVERLAY_TRANSFORM_INVALID; + } + break; + case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL: + switch (delta) { + case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL: + return gfx::OVERLAY_TRANSFORM_NONE; + case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL: + return gfx::OVERLAY_TRANSFORM_ROTATE_180; + case gfx::OVERLAY_TRANSFORM_ROTATE_90: + case gfx::OVERLAY_TRANSFORM_ROTATE_180: + return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL; + case gfx::OVERLAY_TRANSFORM_ROTATE_270: + default: + return gfx::OVERLAY_TRANSFORM_INVALID; + } + break; + case gfx::OVERLAY_TRANSFORM_ROTATE_90: + switch (delta) { + case gfx::OVERLAY_TRANSFORM_ROTATE_90: + return gfx::OVERLAY_TRANSFORM_ROTATE_180; + case gfx::OVERLAY_TRANSFORM_ROTATE_180: + return gfx::OVERLAY_TRANSFORM_ROTATE_270; + case gfx::OVERLAY_TRANSFORM_ROTATE_270: + return gfx::OVERLAY_TRANSFORM_NONE; + default: + return gfx::OVERLAY_TRANSFORM_INVALID; + } + break; + case gfx::OVERLAY_TRANSFORM_ROTATE_180: + switch (delta) { + case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL: + return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL; + case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL: + return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL; + case gfx::OVERLAY_TRANSFORM_ROTATE_90: + return gfx::OVERLAY_TRANSFORM_ROTATE_270; + case gfx::OVERLAY_TRANSFORM_ROTATE_180: + return gfx::OVERLAY_TRANSFORM_NONE; + case gfx::OVERLAY_TRANSFORM_ROTATE_270: + return gfx::OVERLAY_TRANSFORM_ROTATE_90; + default: + return gfx::OVERLAY_TRANSFORM_INVALID; + } + break; + case gfx::OVERLAY_TRANSFORM_ROTATE_270: + switch (delta) { + case gfx::OVERLAY_TRANSFORM_ROTATE_90: + return gfx::OVERLAY_TRANSFORM_NONE; + case gfx::OVERLAY_TRANSFORM_ROTATE_180: + return gfx::OVERLAY_TRANSFORM_ROTATE_90; + case gfx::OVERLAY_TRANSFORM_ROTATE_270: + return gfx::OVERLAY_TRANSFORM_ROTATE_180; + default: + return gfx::OVERLAY_TRANSFORM_INVALID; + } + break; + default: + return gfx::OVERLAY_TRANSFORM_INVALID; + } +} + +} // namespace + +OverlayCandidate::OverlayCandidate() + : transform(gfx::OVERLAY_TRANSFORM_NONE), + format(gfx::BufferFormat::RGBA_8888), + uv_rect(0.f, 0.f, 1.f, 1.f), + is_clipped(false), + is_opaque(false), + use_output_surface_for_resource(false), + resource_id(0), +#if defined(OS_ANDROID) + is_backed_by_surface_texture(false), + is_promotable_hint(false), +#endif + plane_z_order(0), + is_unoccluded(false), + overlay_handled(false), + gpu_fence_id(0) { +} + +OverlayCandidate::OverlayCandidate(const OverlayCandidate& other) = default; + +OverlayCandidate::~OverlayCandidate() = default; + +// static +bool OverlayCandidate::FromDrawQuad(DisplayResourceProvider* resource_provider, + const SkMatrix44& output_color_matrix, + const DrawQuad* quad, + OverlayCandidate* candidate) { + // It is currently not possible to set a color conversion matrix on an HW + // overlay plane. + // TODO(https://crbug.com/792757): Remove this check once the bug is resolved. + if (!output_color_matrix.isIdentity()) + return false; + + // We don't support an opacity value different than one for an overlay plane. + if (quad->shared_quad_state->opacity != 1.f) + return false; + // We support only kSrc (no blending) and kSrcOver (blending with premul). + if (!(quad->shared_quad_state->blend_mode == SkBlendMode::kSrc || + quad->shared_quad_state->blend_mode == SkBlendMode::kSrcOver)) + return false; + + switch (quad->material) { + case DrawQuad::TEXTURE_CONTENT: + return FromTextureQuad(resource_provider, + TextureDrawQuad::MaterialCast(quad), candidate); + case DrawQuad::TILED_CONTENT: + return FromTileQuad(resource_provider, TileDrawQuad::MaterialCast(quad), + candidate); + case DrawQuad::STREAM_VIDEO_CONTENT: + return FromStreamVideoQuad(resource_provider, + StreamVideoDrawQuad::MaterialCast(quad), + candidate); + default: + break; + } + + return false; +} + +// static +bool OverlayCandidate::IsInvisibleQuad(const DrawQuad* quad) { + float opacity = quad->shared_quad_state->opacity; + if (opacity < std::numeric_limits<float>::epsilon()) + return true; + if (quad->material == DrawQuad::SOLID_COLOR) { + SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color; + float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity; + return quad->ShouldDrawWithBlending() && + alpha < std::numeric_limits<float>::epsilon(); + } + return false; +} + +// static +bool OverlayCandidate::IsOccluded(const OverlayCandidate& candidate, + QuadList::ConstIterator quad_list_begin, + QuadList::ConstIterator quad_list_end) { + // Check that no visible quad overlaps the candidate. + for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end; + ++overlap_iter) { + gfx::RectF overlap_rect = cc::MathUtil::MapClippedRect( + overlap_iter->shared_quad_state->quad_to_target_transform, + gfx::RectF(overlap_iter->rect)); + if (candidate.display_rect.Intersects(overlap_rect) && + !OverlayCandidate::IsInvisibleQuad(*overlap_iter)) + return true; + } + return false; +} + +// static +bool OverlayCandidate::FromDrawQuadResource( + DisplayResourceProvider* resource_provider, + const DrawQuad* quad, + ResourceId resource_id, + bool y_flipped, + OverlayCandidate* candidate) { + if (!resource_provider->IsOverlayCandidate(resource_id)) + return false; + + candidate->format = resource_provider->GetBufferFormat(resource_id); + if (std::find(std::begin(kOverlayFormats), std::end(kOverlayFormats), + candidate->format) == std::end(kOverlayFormats)) + return false; + + gfx::OverlayTransform overlay_transform = GetOverlayTransform( + quad->shared_quad_state->quad_to_target_transform, y_flipped); + if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID) + return false; + + auto& transform = quad->shared_quad_state->quad_to_target_transform; + candidate->display_rect = gfx::RectF(quad->rect); + transform.TransformRect(&candidate->display_rect); + + candidate->clip_rect = quad->shared_quad_state->clip_rect; + candidate->is_clipped = quad->shared_quad_state->is_clipped; + candidate->is_opaque = !quad->ShouldDrawWithBlending(); + + candidate->resource_id = resource_id; + candidate->transform = overlay_transform; + + return true; +} + +// static +bool OverlayCandidate::FromTextureQuad( + DisplayResourceProvider* resource_provider, + const TextureDrawQuad* quad, + OverlayCandidate* candidate) { + if (quad->background_color != SK_ColorTRANSPARENT) + return false; + if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(), + quad->y_flipped, candidate)) { + return false; + } + candidate->resource_size_in_pixels = quad->resource_size_in_pixels(); + candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right); + return true; +} + +// static +bool OverlayCandidate::FromTileQuad(DisplayResourceProvider* resource_provider, + const TileDrawQuad* quad, + OverlayCandidate* candidate) { + if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(), false, + candidate)) { + return false; + } + candidate->resource_size_in_pixels = quad->texture_size; + candidate->uv_rect = quad->tex_coord_rect; + return true; +} + +// static +bool OverlayCandidate::FromStreamVideoQuad( + DisplayResourceProvider* resource_provider, + const StreamVideoDrawQuad* quad, + OverlayCandidate* candidate) { + if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(), false, + candidate)) { + return false; + } + if (!quad->matrix.IsScaleOrTranslation()) { + // We cannot handle anything other than scaling & translation for texture + // coordinates yet. + return false; + } + candidate->resource_id = quad->resource_id(); + candidate->resource_size_in_pixels = quad->resource_size_in_pixels(); +#if defined(OS_ANDROID) + candidate->is_backed_by_surface_texture = + resource_provider->IsBackedBySurfaceTexture(quad->resource_id()); +#endif + + gfx::Point3F uv0 = gfx::Point3F(0, 0, 0); + gfx::Point3F uv1 = gfx::Point3F(1, 1, 0); + quad->matrix.TransformPoint(&uv0); + quad->matrix.TransformPoint(&uv1); + gfx::Vector3dF delta = uv1 - uv0; + if (delta.x() < 0) { + candidate->transform = ComposeTransforms( + gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL, candidate->transform); + float x0 = uv0.x(); + uv0.set_x(uv1.x()); + uv1.set_x(x0); + delta.set_x(-delta.x()); + } + + if (delta.y() < 0) { + // In this situation, uv0y < uv1y. Since we overlay inverted, a request + // to invert the source texture means we can just output the texture + // normally and it will be correct. + candidate->uv_rect = gfx::RectF(uv0.x(), uv1.y(), delta.x(), -delta.y()); + } else { + candidate->transform = ComposeTransforms( + gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL, candidate->transform); + candidate->uv_rect = gfx::RectF(uv0.x(), uv0.y(), delta.x(), delta.y()); + } + return true; +} + +OverlayCandidateList::OverlayCandidateList() = default; + +OverlayCandidateList::OverlayCandidateList(const OverlayCandidateList& other) = + default; + +OverlayCandidateList::OverlayCandidateList(OverlayCandidateList&& other) = + default; + +OverlayCandidateList::~OverlayCandidateList() = default; + +OverlayCandidateList& OverlayCandidateList::operator=( + const OverlayCandidateList& other) = default; + +OverlayCandidateList& OverlayCandidateList::operator=( + OverlayCandidateList&& other) = default; + +void OverlayCandidateList::AddPromotionHint(const OverlayCandidate& candidate) { + promotion_hint_info_map_[candidate.resource_id] = candidate.display_rect; +} + +} // namespace viz diff --git a/chromium/components/viz/service/display/overlay_candidate.h b/chromium/components/viz/service/display/overlay_candidate.h new file mode 100644 index 00000000000..27217c69892 --- /dev/null +++ b/chromium/components/viz/service/display/overlay_candidate.h @@ -0,0 +1,144 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_H_ + +#include <map> +#include <vector> + +#include "build/build_config.h" +#include "components/viz/common/quads/render_pass.h" +#include "components/viz/common/resources/resource_id.h" +#include "components/viz/service/viz_service_export.h" +#include "ui/gfx/buffer_types.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/rect_f.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/overlay_transform.h" +#include "ui/gfx/transform.h" + +namespace gfx { +class Rect; +} + +namespace viz { +class DisplayResourceProvider; +class StreamVideoDrawQuad; +class TextureDrawQuad; +class TileDrawQuad; + +class VIZ_SERVICE_EXPORT OverlayCandidate { + public: + // Returns true and fills in |candidate| if |draw_quad| is of a known quad + // type and contains an overlayable resource. + static bool FromDrawQuad(DisplayResourceProvider* resource_provider, + const SkMatrix44& output_color_matrix, + const DrawQuad* quad, + OverlayCandidate* candidate); + // Returns true if |quad| will not block quads underneath from becoming + // an overlay. + static bool IsInvisibleQuad(const DrawQuad* quad); + + // Returns true if any any of the quads in the list given by |quad_list_begin| + // and |quad_list_end| are visible and on top of |candidate|. + static bool IsOccluded(const OverlayCandidate& candidate, + QuadList::ConstIterator quad_list_begin, + QuadList::ConstIterator quad_list_end); + + OverlayCandidate(); + OverlayCandidate(const OverlayCandidate& other); + ~OverlayCandidate(); + + // Transformation to apply to layer during composition. + gfx::OverlayTransform transform; + // Format of the buffer to scanout. + gfx::BufferFormat format; + // Size of the resource, in pixels. + gfx::Size resource_size_in_pixels; + // Rect on the display to position the overlay to. Implementer must convert + // to integer coordinates if setting |overlay_handled| to true. + gfx::RectF display_rect; + // Crop within the buffer to be placed inside |display_rect|. + gfx::RectF uv_rect; + // Clip rect in the target content space after composition. + gfx::Rect clip_rect; + // If the quad is clipped after composition. + bool is_clipped; + // If the quad doesn't require blending. + bool is_opaque; + // True if the texture for this overlay should be the same one used by the + // output surface's main overlay. + bool use_output_surface_for_resource; + // Texture resource to present in an overlay. + unsigned resource_id; + +#if defined(OS_ANDROID) + // For candidates from StreamVideoDrawQuads, this records whether the quad is + // marked as being backed by a SurfaceTexture or not. If so, it's not really + // promotable to an overlay. + bool is_backed_by_surface_texture; + + // Filled in by the OverlayCandidateValidator to indicate whether this is a + // promotable candidate or not. + bool is_promotable_hint; +#endif + + // Stacking order of the overlay plane relative to the main surface, + // which is 0. Signed to allow for "underlays". + int plane_z_order; + // True if the overlay does not have any visible quads on top of it. Set by + // the strategy so the OverlayProcessor can consider subtracting damage caused + // by underlay quads. + bool is_unoccluded; + + // To be modified by the implementer if this candidate can go into + // an overlay. + bool overlay_handled; + + // Gpu fence to wait for before overlay is ready for display. + unsigned gpu_fence_id; + + private: + static bool FromDrawQuadResource(DisplayResourceProvider* resource_provider, + const DrawQuad* quad, + ResourceId resource_id, + bool y_flipped, + OverlayCandidate* candidate); + static bool FromTextureQuad(DisplayResourceProvider* resource_provider, + const TextureDrawQuad* quad, + OverlayCandidate* candidate); + static bool FromTileQuad(DisplayResourceProvider* resource_provider, + const TileDrawQuad* quad, + OverlayCandidate* candidate); + static bool FromStreamVideoQuad(DisplayResourceProvider* resource_provider, + const StreamVideoDrawQuad* quad, + OverlayCandidate* candidate); +}; + +class VIZ_SERVICE_EXPORT OverlayCandidateList + : public std::vector<OverlayCandidate> { + public: + OverlayCandidateList(); + OverlayCandidateList(const OverlayCandidateList&); + OverlayCandidateList(OverlayCandidateList&&); + ~OverlayCandidateList(); + + OverlayCandidateList& operator=(const OverlayCandidateList&); + OverlayCandidateList& operator=(OverlayCandidateList&&); + + // [id] == candidate's |display_rect| for all promotable resources. + using PromotionHintInfoMap = std::map<ResourceId, gfx::RectF>; + + // For android, this provides a set of resources that could be promoted to + // overlay, if one backs them with a SurfaceView. + PromotionHintInfoMap promotion_hint_info_map_; + + // Helper to insert |candidate| into |promotion_hint_info_|. + void AddPromotionHint(const OverlayCandidate& candidate); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_H_ diff --git a/chromium/components/viz/service/display/overlay_candidate_validator.h b/chromium/components/viz/service/display/overlay_candidate_validator.h index d053dbe8a73..8407cb9a36e 100644 --- a/chromium/components/viz/service/display/overlay_candidate_validator.h +++ b/chromium/components/viz/service/display/overlay_candidate_validator.h @@ -7,7 +7,7 @@ #include <vector> -#include "cc/output/overlay_candidate.h" +#include "components/viz/service/display/overlay_candidate.h" #include "components/viz/service/display/overlay_processor.h" #include "components/viz/service/viz_service_export.h" @@ -33,7 +33,7 @@ class VIZ_SERVICE_EXPORT OverlayCandidateValidator { // to be traditionally composited. Candidates with |overlay_handled| set to // true must also have their |display_rect| converted to integer // coordinates if necessary. - virtual void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) = 0; + virtual void CheckOverlaySupport(OverlayCandidateList* surfaces) = 0; virtual ~OverlayCandidateValidator() {} }; diff --git a/chromium/components/viz/service/display/overlay_processor.cc b/chromium/components/viz/service/display/overlay_processor.cc index 002e0535d9e..f43a211444a 100644 --- a/chromium/components/viz/service/display/overlay_processor.cc +++ b/chromium/components/viz/service/display/overlay_processor.cc @@ -4,16 +4,19 @@ #include "components/viz/service/display/overlay_processor.h" +#include "base/metrics/histogram_macros.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" -#include "cc/resources/display_resource_provider.h" #include "components/viz/service/display/dc_layer_overlay.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/overlay_strategy_single_on_top.h" #include "components/viz/service/display/overlay_strategy_underlay.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/transform.h" +namespace viz { + namespace { #if defined(OS_ANDROID) @@ -21,9 +24,8 @@ namespace { // before returning from ProcessForOverlays. class SendPromotionHintsBeforeReturning { public: - SendPromotionHintsBeforeReturning( - cc::DisplayResourceProvider* resource_provider, - cc::OverlayCandidateList* candidates) + SendPromotionHintsBeforeReturning(DisplayResourceProvider* resource_provider, + OverlayCandidateList* candidates) : resource_provider_(resource_provider), candidates_(candidates) {} ~SendPromotionHintsBeforeReturning() { resource_provider_->SendPromotionHints( @@ -31,8 +33,8 @@ class SendPromotionHintsBeforeReturning { } private: - cc::DisplayResourceProvider* resource_provider_; - cc::OverlayCandidateList* candidates_; + DisplayResourceProvider* resource_provider_; + OverlayCandidateList* candidates_; DISALLOW_COPY_AND_ASSIGN(SendPromotionHintsBeforeReturning); }; @@ -40,7 +42,9 @@ class SendPromotionHintsBeforeReturning { } // namespace -namespace viz { +OverlayProcessor::StrategyType OverlayProcessor::Strategy::GetUMAEnum() const { + return StrategyType::kUnknown; +} OverlayProcessor::OverlayProcessor(OutputSurface* surface) : surface_(surface) {} @@ -62,11 +66,11 @@ gfx::Rect OverlayProcessor::GetAndResetOverlayDamage() { } bool OverlayProcessor::ProcessForCALayers( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, const OverlayProcessor::FilterOperationsMap& render_pass_filters, const OverlayProcessor::FilterOperationsMap& render_pass_background_filters, - cc::OverlayCandidateList* overlay_candidates, + OverlayCandidateList* overlay_candidates, CALayerOverlayList* ca_layer_overlays, gfx::Rect* damage_rect) { OverlayCandidateValidator* overlay_validator = @@ -90,11 +94,11 @@ bool OverlayProcessor::ProcessForCALayers( } bool OverlayProcessor::ProcessForDCLayers( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPassList* render_passes, const OverlayProcessor::FilterOperationsMap& render_pass_filters, const OverlayProcessor::FilterOperationsMap& render_pass_background_filters, - cc::OverlayCandidateList* overlay_candidates, + OverlayCandidateList* overlay_candidates, DCLayerOverlayList* dc_layer_overlays, gfx::Rect* damage_rect) { OverlayCandidateValidator* overlay_validator = @@ -111,12 +115,12 @@ bool OverlayProcessor::ProcessForDCLayers( } void OverlayProcessor::ProcessForOverlays( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPassList* render_passes, const SkMatrix44& output_color_matrix, const OverlayProcessor::FilterOperationsMap& render_pass_filters, const OverlayProcessor::FilterOperationsMap& render_pass_background_filters, - cc::OverlayCandidateList* candidates, + OverlayCandidateList* candidates, CALayerOverlayList* ca_layer_overlays, DCLayerOverlayList* dc_layer_overlays, gfx::Rect* damage_rect, @@ -158,16 +162,23 @@ void OverlayProcessor::ProcessForOverlays( } // Only if that fails, attempt hardware overlay strategies. + Strategy* successful_strategy = nullptr; for (const auto& strategy : strategies_) { if (!strategy->Attempt(output_color_matrix, resource_provider, render_passes->back().get(), candidates, content_bounds)) { continue; } - + successful_strategy = strategy.get(); UpdateDamageRect(candidates, previous_frame_underlay_rect, damage_rect); break; } + + UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayStrategy", + successful_strategy + ? successful_strategy->GetUMAEnum() + : StrategyType::kNoStrategyUsed); + TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("viz.debug.overlay_planes"), "Scheduled overlay planes", candidates->size()); } @@ -181,12 +192,12 @@ void OverlayProcessor::ProcessForOverlays( // previous frame. This only handles the common case of a single underlay quad // for fullscreen video. void OverlayProcessor::UpdateDamageRect( - cc::OverlayCandidateList* candidates, + OverlayCandidateList* candidates, const gfx::Rect& previous_frame_underlay_rect, gfx::Rect* damage_rect) { gfx::Rect output_surface_overlay_damage_rect; gfx::Rect this_frame_underlay_rect; - for (const cc::OverlayCandidate& overlay : *candidates) { + for (const OverlayCandidate& overlay : *candidates) { if (overlay.plane_z_order >= 0) { const gfx::Rect overlay_display_rect = ToEnclosedRect(overlay.display_rect); diff --git a/chromium/components/viz/service/display/overlay_processor.h b/chromium/components/viz/service/display/overlay_processor.h index 3822f52fed4..a8ee4b71e95 100644 --- a/chromium/components/viz/service/display/overlay_processor.h +++ b/chromium/components/viz/service/display/overlay_processor.h @@ -9,10 +9,10 @@ #include "base/containers/flat_map.h" #include "base/macros.h" -#include "cc/output/overlay_candidate.h" #include "components/viz/common/quads/render_pass.h" #include "components/viz/service/display/ca_layer_overlay.h" #include "components/viz/service/display/dc_layer_overlay.h" +#include "components/viz/service/display/overlay_candidate.h" #include "components/viz/service/viz_service_export.h" namespace cc { @@ -24,6 +24,18 @@ class OutputSurface; class VIZ_SERVICE_EXPORT OverlayProcessor { public: + // Enum used for UMA histogram. These enum values must not be changed or + // reused. + enum class StrategyType { + kUnknown = 0, + kNoStrategyUsed = 1, + kFullscreen = 2, + kSingleOnTop = 3, + kUnderlay = 4, + kUnderlayCast = 5, + kMaxValue = kUnderlayCast, + }; + class VIZ_SERVICE_EXPORT Strategy { public: virtual ~Strategy() {} @@ -32,10 +44,12 @@ class VIZ_SERVICE_EXPORT OverlayProcessor { // and adds any additional passes necessary to represent overlays to // |render_passes|. virtual bool Attempt(const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidates, + OverlayCandidateList* candidates, std::vector<gfx::Rect>* content_bounds) = 0; + + virtual StrategyType GetUMAEnum() const; }; using StrategyList = std::vector<std::unique_ptr<Strategy>>; @@ -52,12 +66,12 @@ class VIZ_SERVICE_EXPORT OverlayProcessor { // Attempt to replace quads from the specified root render pass with overlays // or CALayers. This must be called every frame. void ProcessForOverlays( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPassList* render_passes, const SkMatrix44& output_color_matrix, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_background_filters, - cc::OverlayCandidateList* overlay_candidates, + OverlayCandidateList* overlay_candidates, CALayerOverlayList* ca_layer_overlays, DCLayerOverlayList* dc_layer_overlays, gfx::Rect* damage_rect, @@ -71,23 +85,23 @@ class VIZ_SERVICE_EXPORT OverlayProcessor { private: bool ProcessForCALayers( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_background_filters, - cc::OverlayCandidateList* overlay_candidates, + OverlayCandidateList* overlay_candidates, CALayerOverlayList* ca_layer_overlays, gfx::Rect* damage_rect); bool ProcessForDCLayers( - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPassList* render_passes, const FilterOperationsMap& render_pass_filters, const FilterOperationsMap& render_pass_background_filters, - cc::OverlayCandidateList* overlay_candidates, + OverlayCandidateList* overlay_candidates, DCLayerOverlayList* dc_layer_overlays, gfx::Rect* damage_rect); // Update |damage_rect| by removing damage casued by |candidates|. - void UpdateDamageRect(cc::OverlayCandidateList* candidates, + void UpdateDamageRect(OverlayCandidateList* candidates, const gfx::Rect& previous_frame_underlay_rect, gfx::Rect* damage_rect); diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc index d7bd9f61428..aa5e125acca 100644 --- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc +++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc @@ -22,15 +22,15 @@ OverlayStrategyFullscreen::~OverlayStrategyFullscreen() {} bool OverlayStrategyFullscreen::Attempt( const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) { QuadList* quad_list = &render_pass->quad_list; // First quad of quad_list is the top most quad. auto front = quad_list->begin(); while (front != quad_list->end()) { - if (!cc::OverlayCandidate::IsInvisibleQuad(*front)) + if (!OverlayCandidate::IsInvisibleQuad(*front)) break; ++front; } @@ -42,22 +42,20 @@ bool OverlayStrategyFullscreen::Attempt( if (quad->ShouldDrawWithBlending()) return false; - cc::OverlayCandidate candidate; - if (!cc::OverlayCandidate::FromDrawQuad( - resource_provider, output_color_matrix, quad, &candidate)) { + OverlayCandidate candidate; + if (!OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix, + quad, &candidate)) { return false; } if (!candidate.display_rect.origin().IsOrigin() || gfx::ToRoundedSize(candidate.display_rect.size()) != - render_pass->output_rect.size() || - render_pass->output_rect.size() != candidate.resource_size_in_pixels) { + render_pass->output_rect.size()) { return false; } candidate.is_opaque = true; candidate.plane_z_order = 0; - candidate.overlay_handled = true; - cc::OverlayCandidateList new_candidate_list; + OverlayCandidateList new_candidate_list; new_candidate_list.push_back(candidate); capability_checker_->CheckOverlaySupport(&new_candidate_list); if (!new_candidate_list.front().overlay_handled) @@ -69,4 +67,8 @@ bool OverlayStrategyFullscreen::Attempt( return true; } +OverlayProcessor::StrategyType OverlayStrategyFullscreen::GetUMAEnum() const { + return OverlayProcessor::StrategyType::kFullscreen; +} + } // namespace viz diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h index 1ce04efa6bb..62bf1232d32 100644 --- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h +++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h @@ -23,11 +23,13 @@ class VIZ_SERVICE_EXPORT OverlayStrategyFullscreen ~OverlayStrategyFullscreen() override; bool Attempt(const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; + OverlayProcessor::StrategyType GetUMAEnum() const override; + private: OverlayCandidateValidator* capability_checker_; // Weak. diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc index 8888d6b4d95..573f48207f9 100644 --- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc +++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc @@ -20,19 +20,19 @@ OverlayStrategySingleOnTop::~OverlayStrategySingleOnTop() {} bool OverlayStrategySingleOnTop::Attempt( const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) { QuadList* quad_list = &render_pass->quad_list; // Build a list of candidates with the associated quad. - cc::OverlayCandidate best_candidate; + OverlayCandidate best_candidate; auto best_quad_it = quad_list->end(); for (auto it = quad_list->begin(); it != quad_list->end(); ++it) { - cc::OverlayCandidate candidate; - if (cc::OverlayCandidate::FromDrawQuad( - resource_provider, output_color_matrix, *it, &candidate) && - !cc::OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) { + OverlayCandidate candidate; + if (OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix, + *it, &candidate) && + !OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) { if (candidate.display_rect.size().GetArea() > best_candidate.display_rect.size().GetArea()) { best_candidate = candidate; @@ -51,18 +51,18 @@ bool OverlayStrategySingleOnTop::Attempt( bool OverlayStrategySingleOnTop::TryOverlay( QuadList* quad_list, - cc::OverlayCandidateList* candidate_list, - const cc::OverlayCandidate& candidate, + OverlayCandidateList* candidate_list, + const OverlayCandidate& candidate, QuadList::Iterator candidate_iterator) { // Add the overlay. - cc::OverlayCandidateList new_candidate_list = *candidate_list; + OverlayCandidateList new_candidate_list = *candidate_list; new_candidate_list.push_back(candidate); new_candidate_list.back().plane_z_order = 1; // Check for support. capability_checker_->CheckOverlaySupport(&new_candidate_list); - const cc::OverlayCandidate& overlay_candidate = new_candidate_list.back(); + const OverlayCandidate& overlay_candidate = new_candidate_list.back(); // If the candidate can be handled by an overlay, create a pass for it. if (overlay_candidate.overlay_handled) { quad_list->EraseAndInvalidateAllPointers(candidate_iterator); @@ -73,4 +73,8 @@ bool OverlayStrategySingleOnTop::TryOverlay( return false; } +OverlayProcessor::StrategyType OverlayStrategySingleOnTop::GetUMAEnum() const { + return OverlayProcessor::StrategyType::kSingleOnTop; +} + } // namespace viz diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h index 0a50ffa5bd0..9a9c07d4d95 100644 --- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h +++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h @@ -21,15 +21,17 @@ class VIZ_SERVICE_EXPORT OverlayStrategySingleOnTop ~OverlayStrategySingleOnTop() override; bool Attempt(const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; + OverlayProcessor::StrategyType GetUMAEnum() const override; + private: bool TryOverlay(QuadList* quad_list, - cc::OverlayCandidateList* candidate_list, - const cc::OverlayCandidate& candidate, + OverlayCandidateList* candidate_list, + const OverlayCandidate& candidate, QuadList::Iterator candidate_iterator); OverlayCandidateValidator* capability_checker_; // Weak. diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.cc b/chromium/components/viz/service/display/overlay_strategy_underlay.cc index 0460321e86d..846ad14eaba 100644 --- a/chromium/components/viz/service/display/overlay_strategy_underlay.cc +++ b/chromium/components/viz/service/display/overlay_strategy_underlay.cc @@ -4,6 +4,7 @@ #include "components/viz/service/display/overlay_strategy_underlay.h" +#include "build/build_config.h" #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/service/display/overlay_candidate_validator.h" @@ -11,8 +12,9 @@ namespace viz { OverlayStrategyUnderlay::OverlayStrategyUnderlay( - OverlayCandidateValidator* capability_checker) - : capability_checker_(capability_checker) { + OverlayCandidateValidator* capability_checker, + OpaqueMode opaque_mode) + : capability_checker_(capability_checker), opaque_mode_(opaque_mode) { DCHECK(capability_checker); } @@ -20,22 +22,25 @@ OverlayStrategyUnderlay::~OverlayStrategyUnderlay() {} bool OverlayStrategyUnderlay::Attempt( const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) { QuadList& quad_list = render_pass->quad_list; for (auto it = quad_list.begin(); it != quad_list.end(); ++it) { - cc::OverlayCandidate candidate; - if (!cc::OverlayCandidate::FromDrawQuad( - resource_provider, output_color_matrix, *it, &candidate)) { + OverlayCandidate candidate; + if (!OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix, + *it, &candidate) || + (opaque_mode_ == OpaqueMode::RequireOpaqueCandidates && + !candidate.is_opaque)) { continue; } // Add the overlay. - cc::OverlayCandidateList new_candidate_list = *candidate_list; + OverlayCandidateList new_candidate_list = *candidate_list; new_candidate_list.push_back(candidate); new_candidate_list.back().plane_z_order = -1; + new_candidate_list.front().is_opaque = false; // Check for support. capability_checker_->CheckOverlaySupport(&new_candidate_list); @@ -44,7 +49,7 @@ bool OverlayStrategyUnderlay::Attempt( // need to switch out the video quad with a black transparent one. if (new_candidate_list.back().overlay_handled) { new_candidate_list.back().is_unoccluded = - !cc::OverlayCandidate::IsOccluded(candidate, quad_list.cbegin(), it); + !OverlayCandidate::IsOccluded(candidate, quad_list.cbegin(), it); quad_list.ReplaceExistingQuadWithOpaqueTransparentSolidColor(it); candidate_list->swap(new_candidate_list); @@ -66,4 +71,8 @@ bool OverlayStrategyUnderlay::Attempt( return false; } +OverlayProcessor::StrategyType OverlayStrategyUnderlay::GetUMAEnum() const { + return OverlayProcessor::StrategyType::kUnderlay; +} + } // namespace viz diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.h b/chromium/components/viz/service/display/overlay_strategy_underlay.h index 45371779d29..7dce1364b79 100644 --- a/chromium/components/viz/service/display/overlay_strategy_underlay.h +++ b/chromium/components/viz/service/display/overlay_strategy_underlay.h @@ -21,18 +21,32 @@ class OverlayCandidateValidator; class VIZ_SERVICE_EXPORT OverlayStrategyUnderlay : public OverlayProcessor::Strategy { public: - explicit OverlayStrategyUnderlay( - OverlayCandidateValidator* capability_checker); + enum class OpaqueMode { + // Require candidates to be |is_opaque|. + RequireOpaqueCandidates, + + // Allow non-|is_opaque| candidates to be promoted. + AllowTransparentCandidates, + }; + + // If |allow_nonopaque_overlays| is true, then we don't require that the + // the candidate is_opaque. + OverlayStrategyUnderlay( + OverlayCandidateValidator* capability_checker, + OpaqueMode opaque_mode = OpaqueMode::RequireOpaqueCandidates); ~OverlayStrategyUnderlay() override; bool Attempt(const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; + OverlayProcessor::StrategyType GetUMAEnum() const override; + private: OverlayCandidateValidator* capability_checker_; // Weak. + OpaqueMode opaque_mode_; DISALLOW_COPY_AND_ASSIGN(OverlayStrategyUnderlay); }; 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 cc7ba761d87..b585b1c9f2e 100644 --- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc +++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc @@ -26,15 +26,15 @@ OverlayStrategyUnderlayCast::~OverlayStrategyUnderlayCast() {} bool OverlayStrategyUnderlayCast::Attempt( const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) { QuadList& quad_list = render_pass->quad_list; bool found_underlay = false; gfx::Rect content_rect; for (const auto* quad : base::Reversed(quad_list)) { - if (cc::OverlayCandidate::IsInvisibleQuad(quad)) + if (OverlayCandidate::IsInvisibleQuad(quad)) continue; const auto& transform = quad->shared_quad_state->quad_to_target_transform; @@ -43,8 +43,8 @@ bool OverlayStrategyUnderlayCast::Attempt( bool is_underlay = false; if (!found_underlay) { - cc::OverlayCandidate candidate; - is_underlay = cc::OverlayCandidate::FromDrawQuad( + OverlayCandidate candidate; + is_underlay = OverlayCandidate::FromDrawQuad( resource_provider, output_color_matrix, quad, &candidate); found_underlay = is_underlay; } @@ -63,9 +63,17 @@ bool OverlayStrategyUnderlayCast::Attempt( } if (found_underlay) { + // If the primary plane shows up in the candidates list make sure it isn't + // opaque otherwise the video underlay won't be visible. + if (!candidate_list->empty()) { + DCHECK_EQ(1u, candidate_list->size()); + DCHECK(candidate_list->front().use_output_surface_for_resource); + candidate_list->front().is_opaque = false; + } + for (auto it = quad_list.begin(); it != quad_list.end(); ++it) { - cc::OverlayCandidate candidate; - if (!cc::OverlayCandidate::FromDrawQuad( + OverlayCandidate candidate; + if (!OverlayCandidate::FromDrawQuad( resource_provider, output_color_matrix, *it, &candidate)) { continue; } @@ -89,6 +97,10 @@ bool OverlayStrategyUnderlayCast::Attempt( return found_underlay; } +OverlayProcessor::StrategyType OverlayStrategyUnderlayCast::GetUMAEnum() const { + return OverlayProcessor::StrategyType::kUnderlayCast; +} + // static void OverlayStrategyUnderlayCast::SetOverlayCompositedCallback( const OverlayCompositedCallback& cb) { diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h index 0ea20e6c4f1..ea73e340b5d 100644 --- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h +++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h @@ -24,9 +24,9 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlayCast ~OverlayStrategyUnderlayCast() override; bool Attempt(const SkMatrix44& output_color_matrix, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, RenderPass* render_pass, - cc::OverlayCandidateList* candidate_list, + OverlayCandidateList* candidate_list, std::vector<gfx::Rect>* content_bounds) override; // Callback that's made whenever an overlay quad is processed in the @@ -36,6 +36,8 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlayCast base::RepeatingCallback<void(const gfx::RectF&, gfx::OverlayTransform)>; static void SetOverlayCompositedCallback(const OverlayCompositedCallback& cb); + OverlayProcessor::StrategyType GetUMAEnum() const override; + private: DISALLOW_COPY_AND_ASSIGN(OverlayStrategyUnderlayCast); }; diff --git a/chromium/components/viz/service/display/overlay_unittest.cc b/chromium/components/viz/service/display/overlay_unittest.cc index 5cb75117474..119841fc713 100644 --- a/chromium/components/viz/service/display/overlay_unittest.cc +++ b/chromium/components/viz/service/display/overlay_unittest.cc @@ -9,7 +9,6 @@ #include "base/containers/flat_map.h" #include "base/test/scoped_feature_list.h" -#include "cc/resources/display_resource_provider.h" #include "cc/resources/layer_tree_resource_provider.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_resource_provider.h" @@ -22,6 +21,7 @@ #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/resources/transferable_resource.h" #include "components/viz/service/display/ca_layer_overlay.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/output_surface_client.h" @@ -72,7 +72,9 @@ class FullscreenOverlayValidator : public OverlayCandidateValidator { } bool AllowCALayerOverlays() override { return false; } bool AllowDCLayerOverlays() override { return false; } - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {} + void CheckOverlaySupport(OverlayCandidateList* surfaces) override { + surfaces->back().overlay_handled = true; + } }; class SingleOverlayValidator : public OverlayCandidateValidator { @@ -86,13 +88,13 @@ class SingleOverlayValidator : public OverlayCandidateValidator { bool AllowCALayerOverlays() override { return false; } bool AllowDCLayerOverlays() override { return false; } - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override { + void CheckOverlaySupport(OverlayCandidateList* surfaces) override { // We may have 1 or 2 surfaces depending on whether this ran through the // full renderer and picked up the output surface, or not. ASSERT_LE(1U, surfaces->size()); ASSERT_GE(2U, surfaces->size()); - cc::OverlayCandidate& candidate = surfaces->back(); + OverlayCandidate& candidate = surfaces->back(); EXPECT_TRUE(!candidate.use_output_surface_for_resource); for (const auto& r : expected_rects_) { const float kAbsoluteError = 0.01f; @@ -129,7 +131,7 @@ class CALayerValidator : public OverlayCandidateValidator { void GetStrategies(OverlayProcessor::StrategyList* strategies) override {} bool AllowCALayerOverlays() override { return true; } bool AllowDCLayerOverlays() override { return false; } - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {} + void CheckOverlaySupport(OverlayCandidateList* surfaces) override {} }; class DCLayerValidator : public OverlayCandidateValidator { @@ -137,7 +139,7 @@ class DCLayerValidator : public OverlayCandidateValidator { void GetStrategies(OverlayProcessor::StrategyList* strategies) override {} bool AllowCALayerOverlays() override { return false; } bool AllowDCLayerOverlays() override { return true; } - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {} + void CheckOverlaySupport(OverlayCandidateList* surfaces) override {} }; class SingleOnTopOverlayValidator : public SingleOverlayValidator { @@ -154,6 +156,14 @@ class UnderlayOverlayValidator : public SingleOverlayValidator { } }; +class TransparentUnderlayOverlayValidator : public SingleOverlayValidator { + public: + void GetStrategies(OverlayProcessor::StrategyList* strategies) override { + strategies->push_back(std::make_unique<OverlayStrategyUnderlay>( + this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates)); + } +}; + class UnderlayCastOverlayValidator : public SingleOverlayValidator { public: void GetStrategies(OverlayProcessor::StrategyList* strategies) override { @@ -211,7 +221,7 @@ class OverlayOutputSurface : public OutputSurface { gfx::BufferFormat GetOverlayBufferFormat() const override { return gfx::BufferFormat::RGBX_8888; } - bool SurfaceIsSuspendForRecycle() const override { return false; } + unsigned UpdateGpuFence() override { return 0; } void set_is_displayed_as_overlay_plane(bool value) { is_displayed_as_overlay_plane_ = value; @@ -272,8 +282,9 @@ static ResourceId CreateResourceInLayerTree( } ResourceId CreateResource( - cc::DisplayResourceProvider* parent_resource_provider, + DisplayResourceProvider* parent_resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider, const gfx::Size& size, bool is_overlay_candidate) { ResourceId resource_id = CreateResourceInLayerTree( @@ -283,14 +294,15 @@ ResourceId CreateResource( base::BindRepeating([](const std::vector<ReturnedResource>&) {})); // Transfer resource to the parent. - cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer; + std::vector<ResourceId> resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource_id); std::vector<TransferableResource> list; - child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list); + child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list, + child_context_provider); parent_resource_provider->ReceiveFromChild(child_id, list); // In DisplayResourceProvider's namespace, use the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = parent_resource_provider->GetChildToParentMap(child_id); return resource_map[list[0].id]; } @@ -307,8 +319,9 @@ SolidColorDrawQuad* CreateSolidColorQuadAt( } TextureDrawQuad* CreateCandidateQuadAt( - cc::DisplayResourceProvider* parent_resource_provider, + DisplayResourceProvider* parent_resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass, const gfx::Rect& rect) { @@ -319,9 +332,9 @@ TextureDrawQuad* CreateCandidateQuadAt( float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; gfx::Size resource_size_in_pixels = rect.size(); bool is_overlay_candidate = true; - ResourceId resource_id = - CreateResource(parent_resource_provider, child_resource_provider, - resource_size_in_pixels, is_overlay_candidate); + ResourceId resource_id = CreateResource( + parent_resource_provider, child_resource_provider, child_context_provider, + resource_size_in_pixels, is_overlay_candidate); auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending, @@ -334,8 +347,9 @@ TextureDrawQuad* CreateCandidateQuadAt( } TextureDrawQuad* CreateTransparentCandidateQuadAt( - cc::DisplayResourceProvider* parent_resource_provider, + DisplayResourceProvider* parent_resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass, const gfx::Rect& rect) { @@ -346,9 +360,9 @@ TextureDrawQuad* CreateTransparentCandidateQuadAt( float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; gfx::Size resource_size_in_pixels = rect.size(); bool is_overlay_candidate = true; - ResourceId resource_id = - CreateResource(parent_resource_provider, child_resource_provider, - resource_size_in_pixels, is_overlay_candidate); + ResourceId resource_id = CreateResource( + parent_resource_provider, child_resource_provider, child_context_provider, + resource_size_in_pixels, is_overlay_candidate); auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending, @@ -361,8 +375,9 @@ TextureDrawQuad* CreateTransparentCandidateQuadAt( } StreamVideoDrawQuad* CreateCandidateVideoQuadAt( - cc::DisplayResourceProvider* parent_resource_provider, + DisplayResourceProvider* parent_resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass, const gfx::Rect& rect, @@ -370,9 +385,9 @@ StreamVideoDrawQuad* CreateCandidateVideoQuadAt( bool needs_blending = false; gfx::Size resource_size_in_pixels = rect.size(); bool is_overlay_candidate = true; - ResourceId resource_id = - CreateResource(parent_resource_provider, child_resource_provider, - resource_size_in_pixels, is_overlay_candidate); + ResourceId resource_id = CreateResource( + parent_resource_provider, child_resource_provider, child_context_provider, + resource_size_in_pixels, is_overlay_candidate); auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>(); @@ -383,29 +398,32 @@ StreamVideoDrawQuad* CreateCandidateVideoQuadAt( } TextureDrawQuad* CreateFullscreenCandidateQuad( - cc::DisplayResourceProvider* parent_resource_provider, + DisplayResourceProvider* parent_resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass) { - return CreateCandidateQuadAt(parent_resource_provider, - child_resource_provider, shared_quad_state, - render_pass, render_pass->output_rect); + return CreateCandidateQuadAt( + parent_resource_provider, child_resource_provider, child_context_provider, + shared_quad_state, render_pass, render_pass->output_rect); } StreamVideoDrawQuad* CreateFullscreenCandidateVideoQuad( - cc::DisplayResourceProvider* parent_resource_provider, + DisplayResourceProvider* parent_resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass, const gfx::Transform& transform) { return CreateCandidateVideoQuadAt( - parent_resource_provider, child_resource_provider, shared_quad_state, - render_pass, render_pass->output_rect, transform); + parent_resource_provider, child_resource_provider, child_context_provider, + shared_quad_state, render_pass, render_pass->output_rect, transform); } YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad( - cc::DisplayResourceProvider* parent_resource_provider, + DisplayResourceProvider* parent_resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass) { bool needs_blending = false; @@ -413,9 +431,9 @@ YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad( gfx::Rect rect = render_pass->output_rect; gfx::Size resource_size_in_pixels = rect.size(); bool is_overlay_candidate = true; - ResourceId resource_id = - CreateResource(parent_resource_provider, child_resource_provider, - resource_size_in_pixels, is_overlay_candidate); + ResourceId resource_id = CreateResource( + parent_resource_provider, child_resource_provider, child_context_provider, + resource_size_in_pixels, is_overlay_candidate); auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>(); overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending, @@ -427,7 +445,7 @@ YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad( return overlay_quad; } -void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider, +void CreateOpaqueQuadAt(DisplayResourceProvider* resource_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass, const gfx::Rect& rect) { @@ -435,7 +453,7 @@ void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider, color_quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false); } -void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider, +void CreateOpaqueQuadAt(DisplayResourceProvider* resource_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass, const gfx::Rect& rect, @@ -445,7 +463,7 @@ void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider, color_quad->SetNew(shared_quad_state, rect, rect, color, false); } -void CreateFullscreenOpaqueQuad(cc::ResourceProvider* resource_provider, +void CreateFullscreenOpaqueQuad(DisplayResourceProvider* resource_provider, const SharedQuadState* shared_quad_state, RenderPass* render_pass) { CreateOpaqueQuadAt(resource_provider, shared_quad_state, render_pass, @@ -514,7 +532,7 @@ class OverlayTest : public testing::Test { child_provider_->BindToCurrentThread(); child_resource_provider_ = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - child_provider_.get(), shared_bitmap_manager_.get()); + child_provider_.get()); overlay_processor_ = std::make_unique<OverlayProcessor>(output_surface_.get()); @@ -525,7 +543,7 @@ class OverlayTest : public testing::Test { std::unique_ptr<OutputSurfaceType> output_surface_; cc::FakeOutputSurfaceClient client_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; scoped_refptr<TestContextProvider> child_provider_; std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_; std::unique_ptr<OverlayProcessor> overlay_processor_; @@ -536,6 +554,8 @@ class OverlayTest : public testing::Test { using FullscreenOverlayTest = OverlayTest<FullscreenOverlayValidator>; using SingleOverlayOnTopTest = OverlayTest<SingleOnTopOverlayValidator>; using UnderlayTest = OverlayTest<UnderlayOverlayValidator>; +using TransparentUnderlayTest = + OverlayTest<TransparentUnderlayOverlayValidator>; using UnderlayCastTest = OverlayTest<UnderlayCastOverlayValidator>; using CALayerOverlayTest = OverlayTest<CALayerValidator>; @@ -557,7 +577,7 @@ TEST(OverlayTest, OverlaysProcessorHasStrategy) { output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator); auto shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>(); - std::unique_ptr<cc::DisplayResourceProvider> resource_provider = + std::unique_ptr<DisplayResourceProvider> resource_provider = cc::FakeResourceProvider::CreateDisplayResourceProvider( provider.get(), shared_bitmap_manager.get()); @@ -572,7 +592,7 @@ TEST_F(FullscreenOverlayTest, SuccessfulOverlay) { gfx::Rect output_rect = pass->output_rect; TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); unsigned original_resource_id = original_quad->resource_id(); // Add something behind it. @@ -580,7 +600,7 @@ TEST_F(FullscreenOverlayTest, SuccessfulOverlay) { pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -608,14 +628,14 @@ TEST_F(FullscreenOverlayTest, FailOnOutputColorMatrix) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); // Add something behind it. CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -638,10 +658,11 @@ TEST_F(FullscreenOverlayTest, AlphaFail) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateTransparentCandidateQuadAt( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), pass.get()->output_rect); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + pass.get()->output_rect); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -659,15 +680,15 @@ TEST_F(FullscreenOverlayTest, AlphaFail) { EXPECT_EQ(0U, candidate_list.size()); } -TEST_F(FullscreenOverlayTest, ResourceSizeInPixelsFail) { +TEST_F(FullscreenOverlayTest, SuccessfulResourceSizeInPixels) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); original_quad->set_resource_size_in_pixels(gfx::Size(64, 64)); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -678,10 +699,10 @@ TEST_F(FullscreenOverlayTest, ResourceSizeInPixelsFail) { resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), render_pass_filters, render_pass_background_filters, &candidate_list, nullptr, nullptr, &damage_rect_, &content_bounds_); - ASSERT_EQ(0U, candidate_list.size()); + ASSERT_EQ(1U, candidate_list.size()); - // Check that the quad is not gone. - EXPECT_EQ(1U, main_pass->quad_list.size()); + // Check that the quad is gone. + EXPECT_EQ(0U, main_pass->quad_list.size()); } TEST_F(FullscreenOverlayTest, OnTopFail) { @@ -694,10 +715,10 @@ TEST_F(FullscreenOverlayTest, OnTopFail) { CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -718,12 +739,13 @@ TEST_F(FullscreenOverlayTest, NotCoveringFullscreenFail) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); gfx::Rect inset_rect = pass->output_rect; inset_rect.Inset(0, 1, 0, 1); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), inset_rect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + inset_rect); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -752,10 +774,10 @@ TEST_F(FullscreenOverlayTest, RemoveFullscreenQuadFromQuadList) { shared_state->opacity = 1.f; CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -777,7 +799,7 @@ TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); unsigned original_resource_id = original_quad->resource_id(); // Add something behind it. @@ -787,7 +809,7 @@ TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) { pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -815,9 +837,10 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); // Add a small quad. const auto kSmallCandidateRect = gfx::Rect(0, 0, 16, 16); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kSmallCandidateRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kSmallCandidateRect); output_surface_->GetOverlayCandidateValidator()->AddExpectedRect( gfx::RectF(kSmallCandidateRect)); @@ -825,7 +848,8 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) { const auto kBigCandidateRect = gfx::Rect(20, 20, 32, 32); TextureDrawQuad* quad_big = CreateCandidateQuadAt( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kBigCandidateRect); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + kBigCandidateRect); output_surface_->GetOverlayCandidateValidator()->AddExpectedRect( gfx::RectF(kBigCandidateRect)); @@ -836,7 +860,7 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) { pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -860,7 +884,7 @@ TEST_F(SingleOverlayOnTopTest, DamageRect) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); damage_rect_ = kOverlayRect; // Add something behind it. @@ -870,10 +894,10 @@ TEST_F(SingleOverlayOnTopTest, DamageRect) { pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; // Primary plane. - cc::OverlayCandidate output_surface_plane; + OverlayCandidate output_surface_plane; output_surface_plane.display_rect = gfx::RectF(kOverlayRect); output_surface_plane.use_output_surface_for_resource = true; output_surface_plane.overlay_handled = true; @@ -903,7 +927,7 @@ TEST_F(SingleOverlayOnTopTest, NoCandidates) { RenderPassList original_pass_list; RenderPass::CopyAll(pass_list, &original_pass_list); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; overlay_processor_->ProcessForOverlays( @@ -924,7 +948,7 @@ TEST_F(SingleOverlayOnTopTest, OccludedCandidates) { CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -932,7 +956,7 @@ TEST_F(SingleOverlayOnTopTest, OccludedCandidates) { RenderPassList original_pass_list; RenderPass::CopyAll(pass_list, &original_pass_list); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; overlay_processor_->ProcessForOverlays( @@ -949,7 +973,7 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); // Add something behind it. CreateFullscreenOpaqueQuad(resource_provider_.get(), @@ -958,7 +982,7 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) { pass->shared_quad_state_list.back(), pass.get()); // Check for potential candidates. - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -974,10 +998,10 @@ TEST_F(SingleOverlayOnTopTest, AcceptBlending) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); TextureDrawQuad* quad = CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); quad->needs_blending = true; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = quad->rect; @@ -998,10 +1022,10 @@ TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); TextureDrawQuad* quad = CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); quad->background_color = SK_ColorBLACK; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1017,10 +1041,10 @@ TEST_F(SingleOverlayOnTopTest, RejectBlendMode) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kScreen; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1036,10 +1060,10 @@ TEST_F(SingleOverlayOnTopTest, RejectOpacity) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back()->opacity = 0.5f; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1055,11 +1079,11 @@ TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutXAxis(45.f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1075,11 +1099,11 @@ TEST_F(SingleOverlayOnTopTest, AllowClipped) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back()->is_clipped = true; pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1097,11 +1121,11 @@ TEST_F(UnderlayTest, AllowVerticalFlip) { rect.Offset(0, -rect.height()); std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), rect); pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f, -1.0f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1121,12 +1145,12 @@ TEST_F(UnderlayTest, AllowHorizontalFlip) { rect.Offset(-rect.width(), 0); std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), rect); pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(-1.0f, 2.0f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1145,11 +1169,11 @@ TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) { rect.set_width(rect.width() / 2); std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), rect); pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f, 1.0f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1166,12 +1190,12 @@ TEST_F(SingleOverlayOnTopTest, AcceptMirrorYTransform) { rect.Offset(0, -rect.height()); std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), rect); pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(1.f, -1.f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1188,12 +1212,12 @@ TEST_F(UnderlayTest, Allow90DegreeRotation) { rect.Offset(0, -rect.height()); std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), rect); pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutZAxis(90.f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1211,12 +1235,12 @@ TEST_F(UnderlayTest, Allow180DegreeRotation) { rect.Offset(-rect.width(), -rect.height()); std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), rect); pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutZAxis(180.f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1234,12 +1258,12 @@ TEST_F(UnderlayTest, Allow270DegreeRotation) { rect.Offset(-rect.width(), 0); std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), rect); pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutZAxis(270.f); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1252,6 +1276,84 @@ TEST_F(UnderlayTest, Allow270DegreeRotation) { EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform); } +TEST_F(UnderlayTest, AllowsOpaqueCandidates) { + std::unique_ptr<RenderPass> pass = CreateRenderPass(); + CreateFullscreenCandidateQuad( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()) + ->needs_blending = false; + pass->shared_quad_state_list.front()->opacity = 1.0; + + OverlayCandidateList candidate_list; + OverlayProcessor::FilterOperationsMap render_pass_filters; + OverlayProcessor::FilterOperationsMap render_pass_background_filters; + RenderPassList pass_list; + pass_list.push_back(std::move(pass)); + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_background_filters, &candidate_list, + nullptr, nullptr, &damage_rect_, &content_bounds_); + ASSERT_EQ(1U, candidate_list.size()); +} + +TEST_F(UnderlayTest, DisallowsTransparentCandidates) { + std::unique_ptr<RenderPass> pass = CreateRenderPass(); + CreateFullscreenCandidateQuad( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()) + ->needs_blending = true; + + OverlayCandidateList candidate_list; + OverlayProcessor::FilterOperationsMap render_pass_filters; + OverlayProcessor::FilterOperationsMap render_pass_background_filters; + RenderPassList pass_list; + pass_list.push_back(std::move(pass)); + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_background_filters, &candidate_list, + nullptr, nullptr, &damage_rect_, &content_bounds_); + ASSERT_EQ(0U, candidate_list.size()); +} + +TEST_F(TransparentUnderlayTest, AllowsOpaqueCandidates) { + std::unique_ptr<RenderPass> pass = CreateRenderPass(); + CreateFullscreenCandidateQuad( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()) + ->needs_blending = false; + pass->shared_quad_state_list.front()->opacity = 1.0; + + OverlayCandidateList candidate_list; + OverlayProcessor::FilterOperationsMap render_pass_filters; + OverlayProcessor::FilterOperationsMap render_pass_background_filters; + RenderPassList pass_list; + pass_list.push_back(std::move(pass)); + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_background_filters, &candidate_list, + nullptr, nullptr, &damage_rect_, &content_bounds_); + ASSERT_EQ(1U, candidate_list.size()); +} + +TEST_F(TransparentUnderlayTest, AllowsTransparentCandidates) { + std::unique_ptr<RenderPass> pass = CreateRenderPass(); + CreateFullscreenCandidateQuad( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()) + ->needs_blending = true; + + OverlayCandidateList candidate_list; + OverlayProcessor::FilterOperationsMap render_pass_filters; + OverlayProcessor::FilterOperationsMap render_pass_background_filters; + RenderPassList pass_list; + pass_list.push_back(std::move(pass)); + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_background_filters, &candidate_list, + nullptr, nullptr, &damage_rect_, &content_bounds_); + ASSERT_EQ(1U, candidate_list.size()); +} + TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) { output_surface_->GetOverlayCandidateValidator()->AddExpectedRect( gfx::RectF(kOverlayBottomRightRect)); @@ -1260,11 +1362,12 @@ TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) { CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), kOverlayTopLeftRect); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayBottomRightRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1288,10 +1391,10 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) { shared_state = pass->CreateAndAppendSharedQuadState(); shared_state->opacity = 1.f; CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), shared_state, - pass.get(), kOverlayBottomRightRect); + child_resource_provider_.get(), child_provider_.get(), + shared_state, pass.get(), kOverlayBottomRightRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1311,11 +1414,12 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) { CreateSolidColorQuadAt(pass->shared_quad_state_list.back(), SK_ColorTRANSPARENT, pass.get(), kOverlayBottomRightRect); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayBottomRightRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1336,10 +1440,10 @@ TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) { shared_state = pass->CreateAndAppendSharedQuadState(); shared_state->opacity = 1.f; CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), shared_state, - pass.get(), kOverlayBottomRightRect); + child_resource_provider_.get(), child_provider_.get(), + shared_state, pass.get(), kOverlayBottomRightRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1358,10 +1462,10 @@ TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) { kOverlayBottomRightRect) ->needs_blending = false; CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), shared_state, - pass.get(), kOverlayBottomRightRect); + child_resource_provider_.get(), child_provider_.get(), + shared_state, pass.get(), kOverlayBottomRightRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1377,9 +1481,10 @@ TEST_F(SingleOverlayOnTopTest, RejectVideoSwapTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kSwapTransform); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + kSwapTransform); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1395,9 +1500,10 @@ TEST_F(UnderlayTest, AllowVideoXMirrorTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kXMirrorTransform); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + kXMirrorTransform); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1413,9 +1519,10 @@ TEST_F(UnderlayTest, AllowVideoBothMirrorTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kBothMirrorTransform); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + kBothMirrorTransform); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1431,9 +1538,10 @@ TEST_F(UnderlayTest, AllowVideoNormalTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kNormalTransform); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + kNormalTransform); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1449,9 +1557,10 @@ TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kYMirrorTransform); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), + kYMirrorTransform); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1470,11 +1579,12 @@ TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayBottomRightRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1499,12 +1609,12 @@ TEST_F(UnderlayTest, AllowOnTop) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->CreateAndAppendSharedQuadState()->opacity = 0.5f; CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1529,11 +1639,11 @@ TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); damage_rect_ = kOverlayRect; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1553,7 +1663,7 @@ TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); damage_rect_ = kOverlayRect; @@ -1561,7 +1671,7 @@ TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) { CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1587,13 +1697,14 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), overlay_rects[i]); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + overlay_rects[i]); damage_rect_ = overlay_rects[i]; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1618,7 +1729,8 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonConsecutiveIdenticalUnderlays) { if (has_fullscreen_candidate[i]) { CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), + pass.get()); } damage_rect_ = kOverlayRect; @@ -1627,7 +1739,7 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonConsecutiveIdenticalUnderlays) { CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1649,11 +1761,11 @@ TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) { pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); damage_rect_ = kOverlayRect; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1678,13 +1790,13 @@ TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) { pass->shared_quad_state_list.back(), pass.get(), kOverlayTopLeftRect); CreateCandidateQuadAt(resource_provider_.get(), - child_resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); damage_rect_ = kOverlayBottomRightRect; - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1698,6 +1810,37 @@ TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) { EXPECT_TRUE(damage_rect_.IsEmpty()); } +TEST_F(UnderlayTest, PrimaryPlaneOverlayIsTransparentWithUnderlay) { + std::unique_ptr<RenderPass> pass = CreateRenderPass(); + gfx::Rect output_rect = pass->output_rect; + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + output_rect, SK_ColorWHITE); + + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); + + OverlayCandidateList candidate_list; + OverlayCandidate candidate; + candidate.use_output_surface_for_resource = true; + candidate.is_opaque = true; + candidate_list.push_back(candidate); + + OverlayProcessor::FilterOperationsMap render_pass_filters; + OverlayProcessor::FilterOperationsMap render_pass_background_filters; + RenderPassList pass_list; + pass_list.push_back(std::move(pass)); + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_background_filters, &candidate_list, + nullptr, nullptr, &damage_rect_, &content_bounds_); + + EXPECT_EQ(2U, candidate_list.size()); + ASSERT_EQ(false, candidate_list[0].is_opaque); +} + TEST_F(UnderlayCastTest, NoOverlayContentBounds) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); @@ -1705,7 +1848,7 @@ TEST_F(UnderlayCastTest, NoOverlayContentBounds) { pass->shared_quad_state_list.back(), pass.get(), kOverlayTopLeftRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1719,11 +1862,12 @@ TEST_F(UnderlayCastTest, NoOverlayContentBounds) { TEST_F(UnderlayCastTest, FullScreenOverlayContentBounds) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1745,9 +1889,10 @@ TEST_F(UnderlayCastTest, BlackOutsideOverlayContentBounds) { const gfx::Rect kTopRight(128, 0, 128, 128); std::unique_ptr<RenderPass> pass = CreateRenderPass(); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayBottomRightRect); CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), kLeftSide, SK_ColorBLACK); @@ -1755,7 +1900,7 @@ TEST_F(UnderlayCastTest, BlackOutsideOverlayContentBounds) { pass->shared_quad_state_list.back(), pass.get(), kTopRight, SK_ColorBLACK); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1774,11 +1919,12 @@ TEST_F(UnderlayCastTest, OverlayOccludedContentBounds) { CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), kOverlayTopLeftRect); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1800,11 +1946,12 @@ TEST_F(UnderlayCastTest, OverlayOccludedUnionContentBounds) { CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1829,14 +1976,15 @@ TEST_F(UnderlayCastTest, RoundOverlayContentBounds) { transform.Translate(0.5f, 0.5f); std::unique_ptr<RenderPass> pass = CreateRenderPassWithTransform(transform); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), overlay_rect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + overlay_rect); CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), gfx::Rect(0, 0, 10, 10), SK_ColorWHITE); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1862,14 +2010,15 @@ TEST_F(UnderlayCastTest, RoundContentBounds) { transform.Translate(0.5f, 0.5f); std::unique_ptr<RenderPass> pass = CreateRenderPassWithTransform(transform); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), overlay_rect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + overlay_rect); CreateOpaqueQuadAt(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get(), gfx::Rect(0, 0, 255, 255), SK_ColorWHITE); - cc::OverlayCandidateList candidate_list; + OverlayCandidateList candidate_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1883,10 +2032,41 @@ TEST_F(UnderlayCastTest, RoundContentBounds) { EXPECT_EQ(kOverlayRect, content_bounds_[0]); } -cc::OverlayCandidateList BackbufferOverlayList( - const RenderPass* root_render_pass) { - cc::OverlayCandidateList list; - cc::OverlayCandidate output_surface_plane; +TEST_F(UnderlayCastTest, PrimaryPlaneOverlayIsTransparentWithUnderlay) { + std::unique_ptr<RenderPass> pass = CreateRenderPass(); + gfx::Rect output_rect = pass->output_rect; + CreateOpaqueQuadAt(resource_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + output_rect, SK_ColorWHITE); + + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayRect); + + OverlayCandidateList candidate_list; + OverlayCandidate candidate; + candidate.use_output_surface_for_resource = true; + candidate.is_opaque = true; + candidate_list.push_back(candidate); + + OverlayProcessor::FilterOperationsMap render_pass_filters; + OverlayProcessor::FilterOperationsMap render_pass_background_filters; + RenderPassList pass_list; + pass_list.push_back(std::move(pass)); + overlay_processor_->ProcessForOverlays( + resource_provider_.get(), &pass_list, GetIdentityColorMatrix(), + render_pass_filters, render_pass_background_filters, &candidate_list, + nullptr, nullptr, &damage_rect_, &content_bounds_); + + ASSERT_EQ(false, candidate_list[0].is_opaque); + EXPECT_EQ(1U, content_bounds_.size()); + EXPECT_EQ(output_rect, content_bounds_[0]); +} + +OverlayCandidateList BackbufferOverlayList(const RenderPass* root_render_pass) { + OverlayCandidateList list; + OverlayCandidate output_surface_plane; output_surface_plane.display_rect = gfx::RectF(root_render_pass->output_rect); output_surface_plane.use_output_surface_for_resource = true; output_surface_plane.overlay_handled = true; @@ -1898,13 +2078,13 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutZAxis(45.f); gfx::Rect damage_rect; CALayerOverlayList ca_layer_list; - cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); + OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1923,12 +2103,12 @@ TEST_F(CALayerOverlayTest, ThreeDTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutXAxis(45.f); CALayerOverlayList ca_layer_list; - cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); + OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1950,13 +2130,13 @@ TEST_F(CALayerOverlayTest, AllowContainingClip) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back()->is_clipped = true; pass->shared_quad_state_list.back()->clip_rect = kOverlayRect; gfx::Rect damage_rect; CALayerOverlayList ca_layer_list; - cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); + OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -1975,13 +2155,13 @@ TEST_F(CALayerOverlayTest, NontrivialClip) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back()->is_clipped = true; pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(64, 64, 128, 128); gfx::Rect damage_rect; CALayerOverlayList ca_layer_list; - cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); + OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -2003,12 +2183,12 @@ TEST_F(CALayerOverlayTest, SkipTransparent) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back()->opacity = 0; gfx::Rect damage_rect; CALayerOverlayList ca_layer_list; - cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); + OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get())); OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -2043,13 +2223,13 @@ TEST_P(DCLayerOverlayTest, AllowNonAxisAlignedTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutZAxis(45.f); gfx::Rect damage_rect; DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = gfx::Rect(1, 1, 10, 10); @@ -2074,14 +2254,14 @@ TEST_P(DCLayerOverlayTest, AllowRequiredNonAxisAlignedTransform) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); YUVVideoDrawQuad* yuv_quad = CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); yuv_quad->require_overlay = true; pass->shared_quad_state_list.back() ->quad_to_target_transform.RotateAboutZAxis(45.f); gfx::Rect damage_rect; DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = gfx::Rect(1, 1, 10, 10); @@ -2109,11 +2289,11 @@ TEST_P(DCLayerOverlayTest, Occluded) { gfx::Rect(0, 2, 100, 100), SK_ColorWHITE); CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); gfx::Rect damage_rect; DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = gfx::Rect(1, 1, 10, 10); @@ -2138,11 +2318,11 @@ TEST_P(DCLayerOverlayTest, Occluded) { gfx::Rect(2, 2, 100, 100), SK_ColorWHITE); CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); gfx::Rect damage_rect; DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = gfx::Rect(1, 1, 10, 10); @@ -2168,11 +2348,11 @@ TEST_P(DCLayerOverlayTest, DamageRect) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); gfx::Rect damage_rect; DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = gfx::Rect(1, 1, 10, 10); @@ -2204,7 +2384,8 @@ TEST_P(DCLayerOverlayTest, MultiplePassDamageRect) { pass1->id = child_pass_id; YUVVideoDrawQuad* yuv_quad = CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass1->shared_quad_state_list.back(), pass1.get()); + child_provider_.get(), pass1->shared_quad_state_list.back(), + pass1.get()); yuv_quad->require_overlay = true; pass1->damage_rect = gfx::Rect(); pass1->transform_to_root_target.Translate(0, 100); @@ -2226,7 +2407,7 @@ TEST_P(DCLayerOverlayTest, MultiplePassDamageRect) { gfx::Rect damage_rect; DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = gfx::Rect(); @@ -2281,15 +2462,15 @@ TEST_P(DCLayerOverlayTest, ClipRect) { pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(0, 3, 100, 100); SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState(); shared_state->opacity = 1.f; - CreateFullscreenCandidateYUVVideoQuad(resource_provider_.get(), - child_resource_provider_.get(), - shared_state, pass.get()); + CreateFullscreenCandidateYUVVideoQuad( + resource_provider_.get(), child_resource_provider_.get(), + child_provider_.get(), shared_state, pass.get()); shared_state->is_clipped = true; // Clipped rect shouldn't be overlapped by clipped opaque quad rect. shared_state->clip_rect = gfx::Rect(0, 0, 100, 3); DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; RenderPassList pass_list; @@ -2322,11 +2503,11 @@ TEST_P(DCLayerOverlayTest, TransparentOnTop) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); CreateFullscreenCandidateYUVVideoQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); pass->shared_quad_state_list.back()->opacity = 0.5f; DCLayerOverlayList dc_layer_list; - cc::OverlayCandidateList overlay_list; + OverlayCandidateList overlay_list; OverlayProcessor::FilterOperationsMap render_pass_filters; OverlayProcessor::FilterOperationsMap render_pass_background_filters; damage_rect_ = gfx::Rect(1, 1, 10, 10); @@ -2350,7 +2531,7 @@ class OverlayInfoRendererGL : public GLRenderer { public: OverlayInfoRendererGL(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider) + DisplayResourceProvider* resource_provider) : GLRenderer(settings, output_surface, resource_provider, nullptr), expect_overlays_(false) {} @@ -2385,12 +2566,14 @@ class OverlayInfoRendererGL : public GLRenderer { class MockOverlayScheduler { public: - MOCK_METHOD5(Schedule, + MOCK_METHOD7(Schedule, void(int plane_z_order, gfx::OverlayTransform plane_transform, unsigned overlay_texture_id, const gfx::Rect& display_bounds, - const gfx::RectF& uv_rect)); + const gfx::RectF& uv_rect, + bool enable_blend, + unsigned gpu_fence_id)); }; class GLRendererWithOverlaysTest : public testing::Test { @@ -2413,7 +2596,7 @@ class GLRendererWithOverlaysTest : public testing::Test { child_provider_->BindToCurrentThread(); child_resource_provider_ = cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - child_provider_.get(), nullptr); + child_provider_.get()); } void Init(bool use_validator) { @@ -2430,16 +2613,16 @@ class GLRendererWithOverlaysTest : public testing::Test { renderer_->DrawFrame(pass_list, 1.f, viewport_size); } void SwapBuffers() { - renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false); renderer_->SwapBuffersComplete(); } void SwapBuffersWithoutComplete() { - renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); + renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false); } void SwapBuffersComplete() { renderer_->SwapBuffersComplete(); } void ReturnResourceInUseQuery(ResourceId id) { - cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), - id); + DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(), + id); gpu::TextureInUseResponse response; response.texture = lock.texture_id(); response.in_use = false; @@ -2451,7 +2634,7 @@ class GLRendererWithOverlaysTest : public testing::Test { RendererSettings settings_; cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<OutputSurfaceType> output_surface_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<OverlayInfoRendererGL> renderer_; scoped_refptr<TestContextProvider> provider_; scoped_refptr<TestContextProvider> child_provider_; @@ -2468,9 +2651,10 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) { std::unique_ptr<RenderPass> pass = CreateRenderPass(); - CreateCandidateQuadAt( - resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect); + CreateCandidateQuadAt(resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get(), + pass->shared_quad_state_list.back(), pass.get(), + kOverlayBottomRightRect); CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenOpaqueQuad(resource_provider_.get(), @@ -2484,11 +2668,12 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) { EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(2); EXPECT_CALL(scheduler_, Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _, - gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1))) + gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1), _, _)) .Times(1); - EXPECT_CALL(scheduler_, Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, - kOverlayBottomRightRect, - BoundingRect(kUVTopLeft, kUVBottomRight))) + EXPECT_CALL( + scheduler_, + Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayBottomRightRect, + BoundingRect(kUVTopLeft, kUVBottomRight), _, _)) .Times(1); DrawFrame(&pass_list, kDisplaySize); EXPECT_EQ(1U, output_surface_->bind_framebuffer_count()); @@ -2513,7 +2698,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) { CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -2523,11 +2708,11 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) { EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3); EXPECT_CALL(scheduler_, Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _, - gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1))) + gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1), _, _)) .Times(1); EXPECT_CALL(scheduler_, Schedule(-1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayRect, - BoundingRect(kUVTopLeft, kUVBottomRight))) + BoundingRect(kUVTopLeft, kUVBottomRight), _, _)) .Times(1); DrawFrame(&pass_list, kDisplaySize); EXPECT_EQ(1U, output_surface_->bind_framebuffer_count()); @@ -2547,7 +2732,7 @@ TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) { CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); @@ -2560,7 +2745,7 @@ TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) { // Should not see the primary surface's overlay. output_surface_->set_is_displayed_as_overlay_plane(false); EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0); DrawFrame(&pass_list, kDisplaySize); EXPECT_EQ(1U, output_surface_->bind_framebuffer_count()); SwapBuffers(); @@ -2580,7 +2765,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenPartialSwapEnabled) { CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenOpaqueQuad(resource_provider_.get(), @@ -2591,7 +2776,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenPartialSwapEnabled) { output_surface_->set_is_displayed_as_overlay_plane(true); EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); DrawFrame(&pass_list, kDisplaySize); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); SwapBuffers(); @@ -2610,7 +2795,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenEmptySwapAllowed) { CreateFullscreenCandidateQuad( resource_provider_.get(), child_resource_provider_.get(), - pass->shared_quad_state_list.back(), pass.get()); + child_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); CreateFullscreenOpaqueQuad(resource_provider_.get(), pass->shared_quad_state_list.back(), pass.get()); @@ -2622,7 +2807,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenEmptySwapAllowed) { output_surface_->set_is_displayed_as_overlay_plane(true); EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); DrawFrame(&pass_list, kDisplaySize); EXPECT_EQ(0U, output_surface_->bind_framebuffer_count()); SwapBuffers(); @@ -2643,10 +2828,10 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { child_resource_provider_.get(), gfx::Size(32, 32), true); // Return the resource map. - cc::ResourceProvider::ResourceIdMap resource_map = - SendResourceAndGetChildToParentMap({resource1, resource2, resource3}, - resource_provider_.get(), - child_resource_provider_.get()); + std::unordered_map<ResourceId, ResourceId> resource_map = + SendResourceAndGetChildToParentMap( + {resource1, resource2, resource3}, resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get()); ResourceId mapped_resource1 = resource_map[resource1]; ResourceId mapped_resource2 = resource_map[resource2]; @@ -2660,7 +2845,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { frame1.render_passes_in_draw_order = &pass_list; frame1.overlay_list.resize(2); frame1.overlay_list.front().use_output_surface_for_resource = true; - cc::OverlayCandidate& overlay1 = frame1.overlay_list.back(); + OverlayCandidate& overlay1 = frame1.overlay_list.back(); overlay1.resource_id = mapped_resource1; overlay1.plane_z_order = 1; @@ -2668,7 +2853,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { frame2.render_passes_in_draw_order = &pass_list; frame2.overlay_list.resize(2); frame2.overlay_list.front().use_output_surface_for_resource = true; - cc::OverlayCandidate& overlay2 = frame2.overlay_list.back(); + OverlayCandidate& overlay2 = frame2.overlay_list.back(); overlay2.resource_id = mapped_resource2; overlay2.plane_z_order = 1; @@ -2676,11 +2861,11 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { frame3.render_passes_in_draw_order = &pass_list; frame3.overlay_list.resize(2); frame3.overlay_list.front().use_output_surface_for_resource = true; - cc::OverlayCandidate& overlay3 = frame3.overlay_list.back(); + OverlayCandidate& overlay3 = frame3.overlay_list.back(); overlay3.resource_id = mapped_resource3; overlay3.plane_z_order = 1; - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame1); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2704,7 +2889,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { EXPECT_FALSE(resource_provider_->InUse(mapped_resource2)); EXPECT_FALSE(resource_provider_->InUse(mapped_resource3)); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame2); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2720,7 +2905,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { EXPECT_TRUE(resource_provider_->InUse(mapped_resource2)); EXPECT_FALSE(resource_provider_->InUse(mapped_resource3)); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame3); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2738,7 +2923,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { EXPECT_FALSE(resource_provider_->InUse(mapped_resource2)); EXPECT_TRUE(resource_provider_->InUse(mapped_resource3)); // No overlays, release the resource. - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0); DirectRenderer::DrawingFrame frame_no_overlays; frame_no_overlays.render_passes_in_draw_order = &pass_list; renderer_->set_expect_overlays(false); @@ -2761,7 +2946,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { // Use the same buffer twice. renderer_->set_expect_overlays(true); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame1); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2779,7 +2964,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { EXPECT_FALSE(resource_provider_->InUse(mapped_resource2)); EXPECT_FALSE(resource_provider_->InUse(mapped_resource3)); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame1); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2797,7 +2982,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) { EXPECT_FALSE(resource_provider_->InUse(mapped_resource2)); EXPECT_FALSE(resource_provider_->InUse(mapped_resource3)); - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0); renderer_->set_expect_overlays(false); renderer_->SetCurrentFrame(frame_no_overlays); renderer_->BeginDrawingFrame(); @@ -2832,10 +3017,10 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) { child_resource_provider_.get(), gfx::Size(32, 32), true); // Return the resource map. - cc::ResourceProvider::ResourceIdMap resource_map = - SendResourceAndGetChildToParentMap({resource1, resource2, resource3}, - resource_provider_.get(), - child_resource_provider_.get()); + std::unordered_map<ResourceId, ResourceId> resource_map = + SendResourceAndGetChildToParentMap( + {resource1, resource2, resource3}, resource_provider_.get(), + child_resource_provider_.get(), child_provider_.get()); ResourceId mapped_resource1 = resource_map[resource1]; ResourceId mapped_resource2 = resource_map[resource2]; ResourceId mapped_resource3 = resource_map[resource3]; @@ -2848,7 +3033,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) { frame1.render_passes_in_draw_order = &pass_list; frame1.overlay_list.resize(2); frame1.overlay_list.front().use_output_surface_for_resource = true; - cc::OverlayCandidate& overlay1 = frame1.overlay_list.back(); + OverlayCandidate& overlay1 = frame1.overlay_list.back(); overlay1.resource_id = mapped_resource1; overlay1.plane_z_order = 1; @@ -2856,7 +3041,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) { frame2.render_passes_in_draw_order = &pass_list; frame2.overlay_list.resize(2); frame2.overlay_list.front().use_output_surface_for_resource = true; - cc::OverlayCandidate& overlay2 = frame2.overlay_list.back(); + OverlayCandidate& overlay2 = frame2.overlay_list.back(); overlay2.resource_id = mapped_resource2; overlay2.plane_z_order = 1; @@ -2864,12 +3049,12 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) { frame3.render_passes_in_draw_order = &pass_list; frame3.overlay_list.resize(2); frame3.overlay_list.front().use_output_surface_for_resource = true; - cc::OverlayCandidate& overlay3 = frame3.overlay_list.back(); + OverlayCandidate& overlay3 = frame3.overlay_list.back(); overlay3.resource_id = mapped_resource3; overlay3.plane_z_order = 1; // First frame, with no swap completion. - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame1); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2879,7 +3064,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) { Mock::VerifyAndClearExpectations(&scheduler_); // Second frame, with no swap completion. - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame2); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2892,7 +3077,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) { // Third frame, still with no swap completion (where the resources would // otherwise have been released). - EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2); + EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2); renderer_->SetCurrentFrame(frame3); renderer_->BeginDrawingFrame(); renderer_->FinishDrawingFrame(); @@ -2958,7 +3143,7 @@ class CALayerOverlayRPDQTest : public CALayerOverlayTest { OverlayProcessor::FilterOperationsMap render_pass_filters_; OverlayProcessor::FilterOperationsMap render_pass_background_filters_; CALayerOverlayList ca_layer_list_; - cc::OverlayCandidateList overlay_list_; + OverlayCandidateList overlay_list_; }; TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadNoFilters) { diff --git a/chromium/components/viz/service/display/renderer_pixeltest.cc b/chromium/components/viz/service/display/renderer_pixeltest.cc index f939419f0f2..5a4c00d3e26 100644 --- a/chromium/components/viz/service/display/renderer_pixeltest.cc +++ b/chromium/components/viz/service/display/renderer_pixeltest.cc @@ -8,7 +8,6 @@ #include <tuple> #include "base/memory/aligned_memory.h" -#include "base/message_loop/message_loop.h" #include "build/build_config.h" #include "cc/base/math_util.h" #include "cc/paint/paint_flags.h" @@ -21,8 +20,11 @@ #include "cc/test/render_pass_test_utils.h" #include "cc/test/resource_provider_test_utils.h" #include "cc/test/test_in_process_context_provider.h" +#include "components/viz/common/gpu/texture_allocation.h" #include "components/viz/common/quads/picture_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" +#include "components/viz/common/resources/bitmap_allocation.h" +#include "components/viz/common/resources/resource_format_utils.h" #include "components/viz/service/display/gl_renderer.h" #include "components/viz/test/test_shared_bitmap_manager.h" #include "gpu/command_buffer/client/gles2_interface.h" @@ -46,6 +48,72 @@ namespace viz { namespace { #if !defined(OS_ANDROID) +std::unique_ptr<base::SharedMemory> AllocateAndRegisterSharedBitmapMemory( + const SharedBitmapId& id, + const gfx::Size& size, + SharedBitmapManager* shared_bitmap_manager) { + std::unique_ptr<base::SharedMemory> shm = + bitmap_allocation::AllocateMappedBitmap(size, RGBA_8888); + shared_bitmap_manager->ChildAllocatedSharedBitmap( + bitmap_allocation::DuplicateAndCloseMappedBitmap(shm.get(), size, + RGBA_8888), + id); + return shm; +} + +void DeleteTexture(scoped_refptr<ContextProvider> context_provider, + GLuint texture, + const gpu::SyncToken& sync_token, + bool is_lost) { + DCHECK(context_provider); + gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); + DCHECK(gl); + gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); + gl->DeleteTextures(1, &texture); +} + +ResourceId CreateGpuResource(scoped_refptr<ContextProvider> context_provider, + cc::LayerTreeResourceProvider* resource_provider, + const gfx::Size& size, + ResourceFormat format, + gfx::ColorSpace color_space, + const void* pixels = nullptr) { + DCHECK(context_provider); + gpu::gles2::GLES2Interface* gl = context_provider->ContextGL(); + DCHECK(gl); + const gpu::Capabilities& caps = context_provider->ContextCapabilities(); + auto allocation = TextureAllocation::MakeTextureId( + gl, caps, format, + /*use_gpu_memory_buffer_resources=*/false, + /*for_framebuffer_attachment=*/false); + if (pixels) { + TextureAllocation::UploadStorage(gl, caps, format, size, allocation, + color_space, pixels); + } else { + TextureAllocation::AllocateStorage(gl, caps, format, size, allocation, + color_space); + } + gpu::Mailbox mailbox; + gl->GenMailboxCHROMIUM(mailbox.name); + gl->ProduceTextureDirectCHROMIUM(allocation.texture_id, mailbox.name); + gpu::SyncToken sync_token; + gl->GenSyncTokenCHROMIUM(sync_token.GetData()); + TransferableResource gl_resource = TransferableResource::MakeGL( + mailbox, GL_LINEAR, allocation.texture_target, sync_token); + gl_resource.size = size; + gl_resource.format = format; + // We didn't allocate a GpuMemoryBuffer, but we want to set buffer_format for + // consistency with other callsites. + // TODO(piman): See if we can remove TransferableResource::buffer_format + // altogether, it looks redundant with format. crbug.com/836488 + gl_resource.buffer_format = BufferFormat(format); + gl_resource.color_space = std::move(color_space); + auto release_callback = SingleReleaseCallback::Create(base::BindOnce( + &DeleteTexture, std::move(context_provider), allocation.texture_id)); + return resource_provider->ImportResource(gl_resource, + std::move(release_callback)); +} + std::unique_ptr<RenderPass> CreateTestRootRenderPass(int id, const gfx::Rect& rect) { std::unique_ptr<RenderPass> pass = RenderPass::Create(); @@ -128,8 +196,10 @@ void CreateTestTwoColoredTextureDrawQuad( SkColor background_color, bool premultiplied_alpha, const SharedQuadState* shared_state, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + SharedBitmapManager* shared_bitmap_manager, + scoped_refptr<ContextProvider> child_context_provider, RenderPass* render_pass) { SkPMColor pixel_color = premultiplied_alpha ? SkPreMultiplyColor(texel_color) @@ -153,20 +223,28 @@ void CreateTestTwoColoredTextureDrawQuad( ResourceId resource; if (gpu_resource) { - resource = child_resource_provider->CreateGpuTextureResource( - rect.size(), ResourceTextureHint::kDefault, RGBA_8888, - gfx::ColorSpace()); + resource = CreateGpuResource(std::move(child_context_provider), + child_resource_provider, rect.size(), + RGBA_8888, gfx::ColorSpace(), &pixels.front()); } else { - resource = child_resource_provider->CreateBitmapResource( - rect.size(), gfx::ColorSpace(), RGBA_8888); + SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); + std::unique_ptr<base::SharedMemory> shm = + AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(), + shared_bitmap_manager); + resource = child_resource_provider->ImportResource( + TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(), + RGBA_8888), + SingleReleaseCallback::Create(base::DoNothing())); + + for (int i = 0; i < rect.size().GetArea(); ++i) + static_cast<uint32_t*>(shm->memory())[i] = pixels[i]; } - child_resource_provider->CopyToResource( - resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size()); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, resource_provider, - child_resource_provider); + child_resource_provider, + child_context_provider.get()); ResourceId mapped_resource = resource_map[resource]; bool needs_blending = true; @@ -190,8 +268,10 @@ void CreateTestTextureDrawQuad( SkColor background_color, bool premultiplied_alpha, const SharedQuadState* shared_state, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + SharedBitmapManager* shared_bitmap_manager, + scoped_refptr<ContextProvider> child_context_provider, RenderPass* render_pass) { SkPMColor pixel_color = premultiplied_alpha ? SkPreMultiplyColor(texel_color) @@ -204,20 +284,28 @@ void CreateTestTextureDrawQuad( ResourceId resource; if (gpu_resource) { - resource = child_resource_provider->CreateGpuTextureResource( - rect.size(), ResourceTextureHint::kDefault, RGBA_8888, - gfx::ColorSpace()); + resource = CreateGpuResource(std::move(child_context_provider), + child_resource_provider, rect.size(), + RGBA_8888, gfx::ColorSpace(), &pixels.front()); } else { - resource = child_resource_provider->CreateBitmapResource( - rect.size(), gfx::ColorSpace(), RGBA_8888); + SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); + std::unique_ptr<base::SharedMemory> shm = + AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(), + shared_bitmap_manager); + resource = child_resource_provider->ImportResource( + TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(), + RGBA_8888), + SingleReleaseCallback::Create(base::DoNothing())); + + for (int i = 0; i < rect.size().GetArea(); ++i) + static_cast<uint32_t*>(shm->memory())[i] = pixels[i]; } - child_resource_provider->CopyToResource( - resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size()); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, resource_provider, - child_resource_provider); + child_resource_provider, + child_context_provider.get()); ResourceId mapped_resource = resource_map[resource]; bool needs_blending = true; @@ -239,14 +327,17 @@ void CreateTestTextureDrawQuad( SkColor background_color, bool premultiplied_alpha, const SharedQuadState* shared_state, - cc::DisplayResourceProvider* resource_provider, + DisplayResourceProvider* resource_provider, cc::LayerTreeResourceProvider* child_resource_provider, + SharedBitmapManager* shared_bitmap_manager, + scoped_refptr<ContextProvider> child_context_provider, RenderPass* render_pass) { float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; CreateTestTextureDrawQuad(gpu_resource, rect, texel_color, vertex_opacity, background_color, premultiplied_alpha, shared_state, resource_provider, child_resource_provider, - render_pass); + shared_bitmap_manager, + std::move(child_context_provider), render_pass); } void CreateTestYUVVideoDrawQuad_FromVideoFrame( @@ -258,8 +349,9 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame( cc::VideoResourceUpdater* video_resource_updater, const gfx::Rect& rect, const gfx::Rect& visible_rect, - cc::DisplayResourceProvider* resource_provider, - cc::LayerTreeResourceProvider* child_resource_provider) { + DisplayResourceProvider* resource_provider, + cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider) { const bool with_alpha = (video_frame->format() == media::PIXEL_FORMAT_I420A); gfx::ColorSpace video_color_space = video_frame->ColorSpace(); @@ -303,16 +395,17 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame( resources.release_callbacks[media::VideoFrame::kAPlane]))); } - cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer; + std::vector<ResourceId> resource_ids_to_transfer; resource_ids_to_transfer.push_back(resource_y); resource_ids_to_transfer.push_back(resource_u); resource_ids_to_transfer.push_back(resource_v); if (with_alpha) resource_ids_to_transfer.push_back(resource_a); // Transfer resources to the parent, and get the resource map. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap( - resource_ids_to_transfer, resource_provider, child_resource_provider); + resource_ids_to_transfer, resource_provider, child_resource_provider, + child_context_provider); ResourceId mapped_resource_y = resource_map[resource_y]; ResourceId mapped_resource_u = resource_map[resource_u]; @@ -351,7 +444,7 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame( } ResourceFormat yuv_highbit_resource_format = - child_resource_provider->YuvResourceFormat(bits_per_channel); + video_resource_updater->YuvResourceFormat(bits_per_channel); float multiplier = 1.0; @@ -375,8 +468,9 @@ void CreateTestY16TextureDrawQuad_FromVideoFrame( cc::VideoResourceUpdater* video_resource_updater, const gfx::Rect& rect, const gfx::Rect& visible_rect, - cc::DisplayResourceProvider* resource_provider, - cc::LayerTreeResourceProvider* child_resource_provider) { + DisplayResourceProvider* resource_provider, + cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider) { cc::VideoFrameExternalResources resources = video_resource_updater->CreateExternalResourcesFromVideoFrame( video_frame); @@ -390,9 +484,10 @@ void CreateTestY16TextureDrawQuad_FromVideoFrame( SingleReleaseCallback::Create(std::move(resources.release_callbacks[0]))); // Transfer resources to the parent, and get the resource map. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource_y}, resource_provider, - child_resource_provider); + child_resource_provider, + child_context_provider); ResourceId mapped_resource_y = resource_map[resource_y]; auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); @@ -458,8 +553,9 @@ void CreateTestYUVVideoDrawQuad_Striped( cc::VideoResourceUpdater* video_resource_updater, const gfx::Rect& rect, const gfx::Rect& visible_rect, - cc::DisplayResourceProvider* resource_provider, - cc::LayerTreeResourceProvider* child_resource_provider) { + DisplayResourceProvider* resource_provider, + cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider) { scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( format, rect.size(), rect, rect.size(), base::TimeDelta()); @@ -497,7 +593,7 @@ void CreateTestYUVVideoDrawQuad_Striped( CreateTestYUVVideoDrawQuad_FromVideoFrame( shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, video_resource_updater, rect, visible_rect, resource_provider, - child_resource_provider); + child_resource_provider, child_context_provider); } // Creates a video frame of size background_size filled with yuv_background, @@ -521,8 +617,9 @@ void CreateTestYUVVideoDrawQuad_TwoColor( uint8_t v_foreground, RenderPass* render_pass, cc::VideoResourceUpdater* video_resource_updater, - cc::DisplayResourceProvider* resource_provider, - cc::LayerTreeResourceProvider* child_resource_provider) { + DisplayResourceProvider* resource_provider, + cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider) { const gfx::Rect rect(background_size); scoped_refptr<media::VideoFrame> video_frame = @@ -566,7 +663,7 @@ void CreateTestYUVVideoDrawQuad_TwoColor( CreateTestYUVVideoDrawQuad_FromVideoFrame( shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, video_resource_updater, rect, visible_rect, resource_provider, - child_resource_provider); + child_resource_provider, child_context_provider); } void CreateTestYUVVideoDrawQuad_Solid( @@ -582,8 +679,9 @@ void CreateTestYUVVideoDrawQuad_Solid( cc::VideoResourceUpdater* video_resource_updater, const gfx::Rect& rect, const gfx::Rect& visible_rect, - cc::DisplayResourceProvider* resource_provider, - cc::LayerTreeResourceProvider* child_resource_provider) { + DisplayResourceProvider* resource_provider, + cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider) { scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame( format, rect.size(), rect, rect.size(), base::TimeDelta()); video_frame->metadata()->SetInteger(media::VideoFrameMetadata::COLOR_SPACE, @@ -605,7 +703,7 @@ void CreateTestYUVVideoDrawQuad_Solid( CreateTestYUVVideoDrawQuad_FromVideoFrame( shared_state, video_frame, alpha_value, tex_coord_rect, render_pass, video_resource_updater, rect, visible_rect, resource_provider, - child_resource_provider); + child_resource_provider, child_context_provider); } void CreateTestYUVVideoDrawQuad_NV12( @@ -617,10 +715,12 @@ void CreateTestYUVVideoDrawQuad_NV12( uint8_t u, uint8_t v, RenderPass* render_pass, + cc::VideoResourceUpdater* video_resource_updater, const gfx::Rect& rect, const gfx::Rect& visible_rect, - cc::DisplayResourceProvider* resource_provider, - cc::LayerTreeResourceProvider* child_resource_provider) { + DisplayResourceProvider* resource_provider, + cc::LayerTreeResourceProvider* child_resource_provider, + scoped_refptr<ContextProvider> child_context_provider) { gfx::ColorSpace gfx_color_space = gfx::ColorSpace::CreateREC601(); if (video_frame_color_space == media::COLOR_SPACE_JPEG) { gfx_color_space = gfx::ColorSpace::CreateJpeg(); @@ -631,29 +731,26 @@ void CreateTestYUVVideoDrawQuad_NV12( const gfx::Size uv_tex_size = media::VideoFrame::PlaneSize( media::PIXEL_FORMAT_NV12, media::VideoFrame::kUVPlane, rect.size()); - ResourceId resource_y = child_resource_provider->CreateGpuTextureResource( - rect.size(), ResourceTextureHint::kDefault, - child_resource_provider->YuvResourceFormat(8), gfx_color_space); - ResourceId resource_u = child_resource_provider->CreateGpuTextureResource( - uv_tex_size, ResourceTextureHint::kDefault, RGBA_8888, gfx_color_space); - ResourceId resource_v = resource_u; - ResourceId resource_a = 0; - std::vector<uint8_t> y_pixels(ya_tex_size.GetArea(), y); - child_resource_provider->CopyToResource(resource_y, y_pixels.data(), - ya_tex_size); + ResourceId resource_y = CreateGpuResource( + child_context_provider, child_resource_provider, ya_tex_size, + video_resource_updater->YuvResourceFormat(8), gfx_color_space, + y_pixels.data()); // U goes in the R component and V goes in the G component. uint32_t rgba_pixel = (u << 24) | (v << 16); std::vector<uint32_t> uv_pixels(uv_tex_size.GetArea(), rgba_pixel); - child_resource_provider->CopyToResource( - resource_u, reinterpret_cast<uint8_t*>(uv_pixels.data()), uv_tex_size); + ResourceId resource_u = CreateGpuResource( + child_context_provider, child_resource_provider, uv_tex_size, RGBA_8888, + gfx_color_space, uv_pixels.data()); + ResourceId resource_v = resource_u; + ResourceId resource_a = 0; // Transfer resources to the parent, and get the resource map. - cc::ResourceProvider::ResourceIdMap resource_map = - SendResourceAndGetChildToParentMap({resource_y, resource_u, resource_v}, - resource_provider, - child_resource_provider); + std::unordered_map<ResourceId, ResourceId> resource_map = + SendResourceAndGetChildToParentMap( + {resource_y, resource_u, resource_v}, resource_provider, + child_resource_provider, child_context_provider.get()); ResourceId mapped_resource_y = resource_map[resource_y]; ResourceId mapped_resource_u = resource_map[resource_u]; @@ -686,8 +783,9 @@ void CreateTestY16TextureDrawQuad_TwoColor( const gfx::Rect& rect, const gfx::Rect& visible_rect, const gfx::Rect& foreground_rect, - cc::DisplayResourceProvider* resource_provider, - cc::LayerTreeResourceProvider* child_resource_provider) { + DisplayResourceProvider* resource_provider, + cc::LayerTreeResourceProvider* child_resource_provider, + ContextProvider* child_context_provider) { std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory( static_cast<unsigned char*>( base::AlignedAlloc(rect.size().GetArea() * 2, @@ -730,7 +828,7 @@ void CreateTestY16TextureDrawQuad_TwoColor( CreateTestY16TextureDrawQuad_FromVideoFrame( shared_state, video_frame, tex_coord_rect, render_pass, video_resource_updater, rect, visible_rect, resource_provider, - child_resource_provider); + child_resource_provider, child_context_provider); } using RendererTypes = @@ -783,6 +881,13 @@ bool FuzzyForSoftwareOnlyPixelComparator<SoftwareRenderer>::Compare( } template <> +bool FuzzyForSoftwareOnlyPixelComparator<SkiaRenderer>::Compare( + const SkBitmap& actual_bmp, + const SkBitmap& expected_bmp) const { + return fuzzy_.Compare(actual_bmp, expected_bmp); +} + +template <> bool FuzzyForSoftwareOnlyPixelComparator< cc::SoftwareRendererWithExpandedViewport>:: Compare(const SkBitmap& actual_bmp, const SkBitmap& expected_bmp) const { @@ -861,13 +966,14 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithoutBackground) { SharedQuadState* shared_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); - CreateTestTextureDrawQuad(this->use_gpu(), - gfx::Rect(this->device_viewport_size_), - SkColorSetARGB(128, 0, 255, 0), // Texel color. - SK_ColorTRANSPARENT, // Background color. - true, // Premultiplied alpha. - shared_state, this->resource_provider_.get(), - this->child_resource_provider_.get(), pass.get()); + CreateTestTextureDrawQuad( + this->use_gpu(), gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(128, 0, 255, 0), // Texel color. + SK_ColorTRANSPARENT, // Background color. + true, // Premultiplied alpha. + shared_state, this->resource_provider_.get(), + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, pass.get()); auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); @@ -890,13 +996,14 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithBackground) { CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); texture_quad_state->opacity = 0.8f; - CreateTestTextureDrawQuad(this->use_gpu(), - gfx::Rect(this->device_viewport_size_), - SkColorSetARGB(204, 120, 255, 120), // Texel color. - SK_ColorGREEN, // Background color. - true, // Premultiplied alpha. - texture_quad_state, this->resource_provider_.get(), - this->child_resource_provider_.get(), pass.get()); + CreateTestTextureDrawQuad( + this->use_gpu(), gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(204, 120, 255, 120), // Texel color. + SK_ColorGREEN, // Background color. + true, // Premultiplied alpha. + texture_quad_state, this->resource_provider_.get(), + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, pass.get()); SharedQuadState* color_quad_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); @@ -1022,14 +1129,15 @@ TEST_F(GLRendererPixelTest, texture_quad_state->opacity = 0.8f; float vertex_opacity[4] = {1.f, 1.f, 0.f, 0.f}; - CreateTestTextureDrawQuad(this->use_gpu(), - gfx::Rect(this->device_viewport_size_), - SkColorSetARGB(204, 120, 255, 120), // Texel color. - vertex_opacity, - SK_ColorGREEN, // Background color. - true, // Premultiplied alpha. - texture_quad_state, this->resource_provider_.get(), - this->child_resource_provider_.get(), pass.get()); + CreateTestTextureDrawQuad( + this->use_gpu(), gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(204, 120, 255, 120), // Texel color. + vertex_opacity, + SK_ColorGREEN, // Background color. + true, // Premultiplied alpha. + texture_quad_state, this->resource_provider_.get(), + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, pass.get()); SharedQuadState* color_quad_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); @@ -1109,12 +1217,6 @@ class IntersectingQuadPixelTest : public RendererPixelTest<TypeParam> { RenderPassList pass_list_; }; -// TODO(weiliangc): Move these tests to normal RendererPixelTest as they pass -// with SkiaRenderer. Failed test list recorded in crbug.com/821176. -template <typename TypeParam> -class IntersectingQuadNonSkiaPixelTest - : public IntersectingQuadPixelTest<TypeParam> {}; - template <typename TypeParam> class IntersectingQuadGLPixelTest : public IntersectingQuadPixelTest<TypeParam> { @@ -1123,15 +1225,17 @@ class IntersectingQuadGLPixelTest IntersectingQuadPixelTest<TypeParam>::SetUp(); constexpr bool kUseStreamVideoDrawQuad = false; constexpr bool kUseGpuMemoryBufferResources = false; + constexpr bool kUseR16Texture = false; + constexpr int kMaxResourceSize = 10000; video_resource_updater_ = std::make_unique<cc::VideoResourceUpdater>( this->child_context_provider_.get(), nullptr, this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, - kUseGpuMemoryBufferResources); + kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize); video_resource_updater2_ = std::make_unique<cc::VideoResourceUpdater>( this->child_context_provider_.get(), nullptr, this->child_resource_provider_.get(), kUseStreamVideoDrawQuad, - kUseGpuMemoryBufferResources); + kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize); } protected: @@ -1150,7 +1254,6 @@ using GLRendererTypes = ::testing::Types<GLRenderer, cc::GLRendererWithExpandedViewport>; TYPED_TEST_CASE(IntersectingQuadPixelTest, RendererTypes); -TYPED_TEST_CASE(IntersectingQuadNonSkiaPixelTest, NonSkiaRendererTypes); TYPED_TEST_CASE(IntersectingQuadGLPixelTest, GLRendererTypes); TYPED_TEST_CASE(IntersectingQuadSoftwareTest, SoftwareRendererTypes); @@ -1170,6 +1273,11 @@ TYPED_TEST(IntersectingQuadPixelTest, SolidColorQuads) { FILE_PATH_LITERAL("intersecting_blue_green.png")); } +static inline SkColor GetSkiaOrGLColor(const SkColor& color) { + return SkColorSetARGB(SkColorGetA(color), SkColorGetB(color), + SkColorGetG(color), SkColorGetR(color)); +} + template <typename TypeParam> SkColor GetColor(const SkColor& color) { return color; @@ -1177,28 +1285,35 @@ SkColor GetColor(const SkColor& color) { template <> SkColor GetColor<GLRenderer>(const SkColor& color) { - return SkColorSetARGB(SkColorGetA(color), SkColorGetB(color), - SkColorGetG(color), SkColorGetR(color)); + return GetSkiaOrGLColor(color); } + +template <> +SkColor GetColor<SkiaRenderer>(const SkColor& color) { + return GetSkiaOrGLColor(color); +} + template <> SkColor GetColor<cc::GLRendererWithExpandedViewport>(const SkColor& color) { - return GetColor<GLRenderer>(color); + return GetSkiaOrGLColor(color); } -TYPED_TEST(IntersectingQuadNonSkiaPixelTest, TexturedQuads) { +TYPED_TEST(IntersectingQuadPixelTest, TexturedQuads) { this->SetupQuadStateAndRenderPass(); CreateTestTwoColoredTextureDrawQuad( this->use_gpu(), this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT, true, this->front_quad_state_, this->resource_provider_.get(), - this->child_resource_provider_.get(), this->render_pass_.get()); + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, this->render_pass_.get()); CreateTestTwoColoredTextureDrawQuad( this->use_gpu(), this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)), GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT, true, this->back_quad_state_, this->resource_provider_.get(), - this->child_resource_provider_.get(), this->render_pass_.get()); + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, this->render_pass_.get()); SCOPED_TRACE("IntersectingTexturedQuads"); this->AppendBackgroundAndRunTest( @@ -1261,7 +1376,7 @@ TYPED_TEST(IntersectingQuadSoftwareTest, PictureQuads) { FILE_PATH_LITERAL("intersecting_blue_green_squares.png")); } -TYPED_TEST(IntersectingQuadNonSkiaPixelTest, RenderPassQuads) { +TYPED_TEST(IntersectingQuadPixelTest, RenderPassQuads) { this->SetupQuadStateAndRenderPass(); int child_pass_id1 = 2; int child_pass_id2 = 3; @@ -1278,13 +1393,15 @@ TYPED_TEST(IntersectingQuadNonSkiaPixelTest, RenderPassQuads) { GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT, true, child1_quad_state, this->resource_provider_.get(), - this->child_resource_provider_.get(), child_pass1.get()); + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, child_pass1.get()); CreateTestTwoColoredTextureDrawQuad( this->use_gpu(), this->quad_rect_, GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)), GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT, true, child2_quad_state, this->resource_provider_.get(), - this->child_resource_provider_.get(), child_pass2.get()); + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, child_pass2.get()); CreateTestRenderPassDrawQuad(this->front_quad_state_, this->quad_rect_, child_pass_id1, this->render_pass_.get()); @@ -1312,14 +1429,16 @@ TYPED_TEST(IntersectingQuadGLPixelTest, YUVVideoQuads) { media::COLOR_SPACE_JPEG, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(), this->quad_rect_, 0, 128, 128, inner_rect, 29, 255, 107, this->render_pass_.get(), this->video_resource_updater_.get(), - this->resource_provider_.get(), this->child_resource_provider_.get()); + this->resource_provider_.get(), this->child_resource_provider_.get(), + this->child_context_provider_.get()); CreateTestYUVVideoDrawQuad_TwoColor( this->back_quad_state_, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(), this->quad_rect_, 149, 43, 21, inner_rect, 0, 128, 128, this->render_pass_.get(), this->video_resource_updater2_.get(), - this->resource_provider_.get(), this->child_resource_provider_.get()); + this->resource_provider_.get(), this->child_resource_provider_.get(), + this->child_context_provider_.get()); SCOPED_TRACE("IntersectingVideoQuads"); this->AppendBackgroundAndRunTest( @@ -1339,13 +1458,15 @@ TYPED_TEST(IntersectingQuadGLPixelTest, Y16VideoQuads) { this->front_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 18, 0, this->render_pass_.get(), this->video_resource_updater_.get(), this->quad_rect_, this->quad_rect_, inner_rect, - this->resource_provider_.get(), this->child_resource_provider_.get()); + this->resource_provider_.get(), this->child_resource_provider_.get(), + this->child_context_provider_.get()); CreateTestY16TextureDrawQuad_TwoColor( this->back_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 0, 182, this->render_pass_.get(), this->video_resource_updater2_.get(), this->quad_rect_, this->quad_rect_, inner_rect, - this->resource_provider_.get(), this->child_resource_provider_.get()); + this->resource_provider_.get(), this->child_resource_provider_.get(), + this->child_context_provider_.get()); SCOPED_TRACE("IntersectingVideoQuads"); this->AppendBackgroundAndRunTest( @@ -1363,13 +1484,14 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) { SharedQuadState* shared_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); - CreateTestTextureDrawQuad(this->use_gpu(), - gfx::Rect(this->device_viewport_size_), - SkColorSetARGB(128, 0, 255, 0), // Texel color. - SK_ColorTRANSPARENT, // Background color. - false, // Premultiplied alpha. - shared_state, this->resource_provider_.get(), - this->child_resource_provider_.get(), pass.get()); + CreateTestTextureDrawQuad( + this->use_gpu(), gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(128, 0, 255, 0), // Texel color. + SK_ColorTRANSPARENT, // Background color. + false, // Premultiplied alpha. + shared_state, this->resource_provider_.get(), + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, pass.get()); auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); @@ -1393,13 +1515,14 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) { CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); texture_quad_state->opacity = 0.8f; - CreateTestTextureDrawQuad(this->use_gpu(), - gfx::Rect(this->device_viewport_size_), - SkColorSetARGB(204, 120, 255, 120), // Texel color. - SK_ColorGREEN, // Background color. - false, // Premultiplied alpha. - texture_quad_state, this->resource_provider_.get(), - this->child_resource_provider_.get(), pass.get()); + CreateTestTextureDrawQuad( + this->use_gpu(), gfx::Rect(this->device_viewport_size_), + SkColorSetARGB(204, 120, 255, 120), // Texel color. + SK_ColorGREEN, // Background color. + false, // Premultiplied alpha. + texture_quad_state, this->resource_provider_.get(), + this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(), + this->child_context_provider_, pass.get()); SharedQuadState* color_quad_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); @@ -1449,7 +1572,8 @@ class VideoGLRendererPixelTest : public cc::GLRendererPixelTest { shared_state, format, color_space, false, tex_coord_rect, background_size, gfx::Rect(background_size), 128, 128, 128, green_rect, 149, 43, 21, pass.get(), video_resource_updater_.get(), - resource_provider_.get(), child_resource_provider_.get()); + resource_provider_.get(), child_resource_provider_.get(), + child_context_provider_.get()); pass_list->push_back(std::move(pass)); } @@ -1457,9 +1581,12 @@ class VideoGLRendererPixelTest : public cc::GLRendererPixelTest { GLRendererPixelTest::SetUp(); constexpr bool kUseStreamVideoDrawQuad = false; constexpr bool kUseGpuMemoryBufferResources = false; + constexpr bool kUseR16Texture = false; + constexpr int kMaxResourceSize = 10000; video_resource_updater_ = std::make_unique<cc::VideoResourceUpdater>( child_context_provider_.get(), nullptr, child_resource_provider_.get(), - kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources); + kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources, kUseR16Texture, + kMaxResourceSize); } std::unique_ptr<cc::VideoResourceUpdater> video_resource_updater_; @@ -1487,7 +1614,7 @@ TEST_P(VideoGLRendererPixelHiLoTest, SimpleYUVRect) { shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), child_context_provider_.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1515,7 +1642,8 @@ TEST_P(VideoGLRendererPixelHiLoTest, ClippedYUVRect) { shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), draw_rect, viewport, - resource_provider_.get(), child_resource_provider_.get()); + resource_provider_.get(), child_resource_provider_.get(), + child_context_provider_.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1541,7 +1669,7 @@ TEST_F(VideoGLRendererPixelHiLoTest, OffsetYUVRect) { shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, false, false, gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), child_context_provider_.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1568,7 +1696,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) { shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), child_context_provider_.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1597,7 +1725,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) { shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), child_context_provider_.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1619,8 +1747,9 @@ TEST_F(VideoGLRendererPixelTest, SimpleNV12JRect) { // YUV of (149,43,21) should be green (0,255,0) in RGB. CreateTestYUVVideoDrawQuad_NV12( shared_state, media::COLOR_SPACE_JPEG, gfx::ColorSpace::CreateJpeg(), - gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(), rect, rect, - resource_provider_.get(), child_resource_provider_.get()); + gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(), + video_resource_updater_.get(), rect, rect, resource_provider_.get(), + child_resource_provider_.get(), child_context_provider_); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1668,7 +1797,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) { shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), child_context_provider_.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1694,7 +1823,7 @@ TEST_F(VideoGLRendererPixelHiLoTest, SimpleYUVARect) { shared_state, media::PIXEL_FORMAT_I420A, media::COLOR_SPACE_SD_REC601, false, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), child_context_provider_.get()); auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); @@ -1723,7 +1852,7 @@ TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) { shared_state, media::PIXEL_FORMAT_I420A, media::COLOR_SPACE_SD_REC601, true, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(), video_resource_updater_.get(), rect, rect, resource_provider_.get(), - child_resource_provider_.get()); + child_resource_provider_.get(), child_context_provider_.get()); auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false); @@ -1749,7 +1878,8 @@ TEST_F(VideoGLRendererPixelTest, TwoColorY16Rect) { CreateTestY16TextureDrawQuad_TwoColor( shared_state, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 68, 123, pass.get(), video_resource_updater_.get(), rect, rect, upper_rect, - resource_provider_.get(), child_resource_provider_.get()); + resource_provider_.get(), child_resource_provider_.get(), + child_context_provider_.get()); RenderPassList pass_list; pass_list.push_back(std::move(pass)); @@ -1760,7 +1890,7 @@ TEST_F(VideoGLRendererPixelTest, TwoColorY16Rect) { cc::FuzzyPixelOffByOneComparator(true))); } -TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlpha) { +TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) { gfx::Rect viewport_rect(this->device_viewport_size_); int root_pass_id = 1; @@ -1838,7 +1968,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlpha) { FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); } -TYPED_TEST(NonSkiaRendererPixelTest, FastPassSaturateFilter) { +TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) { gfx::Rect viewport_rect(this->device_viewport_size_); int root_pass_id = 1; @@ -1898,7 +2028,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, FastPassSaturateFilter) { FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); } -TYPED_TEST(NonSkiaRendererPixelTest, FastPassFilterChain) { +TYPED_TEST(RendererPixelTest, FastPassFilterChain) { gfx::Rect viewport_rect(this->device_viewport_size_); int root_pass_id = 1; @@ -1960,7 +2090,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, FastPassFilterChain) { FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false))); } -TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlphaTranslation) { +TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) { gfx::Rect viewport_rect(this->device_viewport_size_); int root_pass_id = 1; @@ -2142,7 +2272,7 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) { // This tests the case where we have a RenderPass with a mask, but the quad // for the masked surface does not include the full surface texture. -TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad) { +TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) { gfx::Rect viewport_rect(this->device_viewport_size_); int root_pass_id = 1; @@ -2186,23 +2316,20 @@ TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad) { ResourceId mask_resource_id; if (this->use_gpu()) { - mask_resource_id = this->child_resource_provider_->CreateGpuTextureResource( - mask_rect.size(), ResourceTextureHint::kDefault, RGBA_8888, - gfx::ColorSpace()); + mask_resource_id = CreateGpuResource( + this->child_context_provider_, this->child_resource_provider_.get(), + mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); } else { - mask_resource_id = this->child_resource_provider_->CreateBitmapResource( - mask_rect.size(), gfx::ColorSpace(), RGBA_8888); + mask_resource_id = + this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap); } - this->child_resource_provider_->CopyToResource( - mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()), - mask_rect.size()); - // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({mask_resource_id}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_mask_resource_id = resource_map[mask_resource_id]; // This RenderPassDrawQuad does not include the full |viewport_rect| @@ -2241,7 +2368,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad) { // This tests the case where we have a RenderPass with a mask, but the quad // for the masked surface does not include the full surface texture. -TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad2) { +TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad2) { gfx::Rect viewport_rect(this->device_viewport_size_); int root_pass_id = 1; @@ -2285,23 +2412,20 @@ TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad2) { ResourceId mask_resource_id; if (this->use_gpu()) { - mask_resource_id = this->child_resource_provider_->CreateGpuTextureResource( - mask_rect.size(), ResourceTextureHint::kDefault, RGBA_8888, - gfx::ColorSpace()); + mask_resource_id = CreateGpuResource( + this->child_context_provider_, this->child_resource_provider_.get(), + mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); } else { - mask_resource_id = this->child_resource_provider_->CreateBitmapResource( - mask_rect.size(), gfx::ColorSpace(), RGBA_8888); + mask_resource_id = + this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap); } - this->child_resource_provider_->CopyToResource( - mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()), - mask_rect.size()); - // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({mask_resource_id}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_mask_resource_id = resource_map[mask_resource_id]; // This RenderPassDrawQuad does not include the full |viewport_rect| @@ -2440,16 +2564,14 @@ class RendererPixelTestWithBackgroundFilter gfx::Rect filter_pass_layer_rect_; }; +// The software renderer does not support background filters yet. using BackgroundFilterRendererTypes = - ::testing::Types<GLRenderer, SoftwareRenderer>; + ::testing::Types<GLRenderer, SkiaRenderer>; + TYPED_TEST_CASE(RendererPixelTestWithBackgroundFilter, BackgroundFilterRendererTypes); -using GLRendererPixelTestWithBackgroundFilter = - RendererPixelTestWithBackgroundFilter<GLRenderer>; - -// TODO(skaslev): The software renderer does not support filters yet. -TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) { +TYPED_TEST(RendererPixelTestWithBackgroundFilter, InvertFilter) { this->background_filters_.Append( cc::FilterOperation::CreateInvertFilter(1.f)); @@ -2771,21 +2893,19 @@ TEST_F(GLRendererPixelTest, TileDrawQuadForceAntiAliasingOff) { gfx::Size tile_size(32, 32); ResourceId resource; if (this->use_gpu()) { - resource = this->child_resource_provider_->CreateGpuTextureResource( - tile_size, ResourceTextureHint::kDefault, RGBA_8888, gfx::ColorSpace()); + resource = CreateGpuResource( + this->child_context_provider_, this->child_resource_provider_.get(), + tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); } else { - resource = this->child_resource_provider_->CreateBitmapResource( - tile_size, gfx::ColorSpace(), RGBA_8888); + resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap); } - this->child_resource_provider_->CopyToResource( - resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size); - // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_resource = resource_map[resource]; int id = 1; @@ -3207,19 +3327,18 @@ TYPED_TEST(NonSkiaRendererPixelTest, TileDrawQuadNearestNeighbor) { gfx::Size tile_size(2, 2); ResourceId resource; if (this->use_gpu()) { - resource = this->child_resource_provider_->CreateGpuTextureResource( - tile_size, ResourceTextureHint::kDefault, RGBA_8888, gfx::ColorSpace()); + resource = CreateGpuResource( + this->child_context_provider_, this->child_resource_provider_.get(), + tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); } else { - resource = this->child_resource_provider_->CreateBitmapResource( - tile_size, gfx::ColorSpace(), RGBA_8888); + resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap); } - this->child_resource_provider_->CopyToResource( - resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_resource = resource_map[resource]; int id = 1; @@ -3262,17 +3381,15 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadNearestNeighbor) { draw_point_color(&canvas, 1, 1, SK_ColorGREEN); gfx::Size tile_size(2, 2); - ResourceId resource = this->child_resource_provider_->CreateBitmapResource( - tile_size, gfx::ColorSpace(), RGBA_8888); - - this->child_resource_provider_->CopyToResource( - resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size); + ResourceId resource = + this->AllocateAndFillSoftwareResource(tile_size, bitmap); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_resource = resource_map[resource]; int id = 1; @@ -3317,17 +3434,15 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadLinear) { } gfx::Size tile_size(2, 2); - ResourceId resource = this->child_resource_provider_->CreateBitmapResource( - tile_size, gfx::ColorSpace(), RGBA_8888); - - this->child_resource_provider_->CopyToResource( - resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size); + ResourceId resource = + this->AllocateAndFillSoftwareResource(tile_size, bitmap); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_resource = resource_map[resource]; int id = 1; @@ -3666,20 +3781,16 @@ TEST_F(GLRendererPixelTest, TextureQuadBatching) { inset_rect.Inset(6, 6, 4, 4); } - ResourceId resource = - this->child_resource_provider_->CreateGpuTextureResource( - mask_rect.size(), ResourceTextureHint::kDefault, RGBA_8888, - gfx::ColorSpace()); - - this->child_resource_provider_->CopyToResource( - resource, reinterpret_cast<uint8_t*>(bitmap.getPixels()), - mask_rect.size()); + ResourceId resource = CreateGpuResource( + this->child_context_provider_, this->child_resource_provider_.get(), + mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_resource = resource_map[resource]; // Arbitrary dividing lengths to divide up the resource into 16 quads. @@ -3748,19 +3859,18 @@ TEST_F(GLRendererPixelTest, TileQuadClamping) { ResourceId resource; if (this->use_gpu()) { - resource = this->child_resource_provider_->CreateGpuTextureResource( - tile_size, ResourceTextureHint::kDefault, RGBA_8888, gfx::ColorSpace()); + resource = CreateGpuResource( + this->child_context_provider_, this->child_resource_provider_.get(), + tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels()); } else { - resource = this->child_resource_provider_->CreateBitmapResource( - tile_size, gfx::ColorSpace(), RGBA_8888); + resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap); } - this->child_resource_provider_->CopyToResource( - resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_resource = resource_map[resource]; int id = 1; @@ -3847,7 +3957,7 @@ TEST_F(GLRendererPixelTestWithOverdrawFeedback, TranslucentRectangles) { cc::ExactPixelComparator(true))); } -using ColorSpacePair = std::tuple<gfx::ColorSpace, gfx::ColorSpace>; +using ColorSpacePair = std::tuple<gfx::ColorSpace, gfx::ColorSpace, bool>; class ColorTransformPixelTest : public GLRendererPixelTest, @@ -3857,7 +3967,7 @@ class ColorTransformPixelTest // Note that this size of 17 is not random -- it is chosen to match the // size of LUTs that are created. If we did not match the LUT size exactly, // then the error for LUT based transforms is much larger. - device_viewport_size_ = gfx::Size(17, 4); + device_viewport_size_ = gfx::Size(17, 5); src_color_space_ = std::get<0>(GetParam()); dst_color_space_ = std::get<1>(GetParam()); if (!src_color_space_.IsValid()) { @@ -3868,9 +3978,11 @@ class ColorTransformPixelTest dst_color_space_ = gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace(); } + premultiplied_alpha_ = std::get<2>(GetParam()); } gfx::ColorSpace src_color_space_; gfx::ColorSpace dst_color_space_; + bool premultiplied_alpha_ = false; }; TEST_P(ColorTransformPixelTest, Basic) { @@ -3883,15 +3995,25 @@ TEST_P(ColorTransformPixelTest, Basic) { // Row 1: Gradient of green from 0 to 255 // Row 2: Gradient of blue from 0 to 255 // Row 3: Gradient of grey from 0 to 255 + // Row 4: Gradient of alpha from 0 to 255 with mixed colors. for (int x = 0; x < rect.width(); ++x) { - int v = (x * 255) / (rect.width() - 1); + int gradient_value = (x * 255) / (rect.width() - 1); for (int y = 0; y < rect.height(); ++y) { - for (int c = 0; c < 3; ++c) { - if (y == c || y == rect.height() - 1) { - input_colors[c + 4 * (x + rect.width() * y)] = v; + uint8_t* pixel = &input_colors[4 * (x + rect.width() * y)]; + pixel[3] = 255; + if (y < 3) { + pixel[y] = gradient_value; + } else if (y == 3) { + pixel[0] = pixel[1] = pixel[2] = gradient_value; + } else { + if (premultiplied_alpha_) { + pixel[x % 3] = gradient_value; + pixel[3] = gradient_value; + } else { + pixel[x % 3] = 0xFF; + pixel[3] = gradient_value; } } - input_colors[3 + 4 * (x + rect.width() * y)] = 255; } } @@ -3915,30 +4037,30 @@ TEST_P(ColorTransformPixelTest, Basic) { color.set_y(std::min(std::max(0.f, color.y()), 1.f)); color.set_z(std::min(std::max(0.f, color.z()), 1.f)); expected_output_colors[i] = - SkColorSetARGBInline(255, static_cast<size_t>(255.f * color.x() + 0.5f), - static_cast<size_t>(255.f * color.y() + 0.5f), - static_cast<size_t>(255.f * color.z() + 0.5f)); + SkColorSetARGB(255, static_cast<size_t>(255.f * color.x() + 0.5f), + static_cast<size_t>(255.f * color.y() + 0.5f), + static_cast<size_t>(255.f * color.z() + 0.5f)); } int id = 1; std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect); pass->color_space = dst_color_space_; + // Append a quad to execute the transform. { SharedQuadState* shared_state = CreateTestSharedQuadState(gfx::Transform(), rect, pass.get()); - ResourceId resource = child_resource_provider_->CreateGpuTextureResource( - rect.size(), ResourceTextureHint::kDefault, RGBA_8888, - src_color_space_); - this->child_resource_provider_->CopyToResource( - resource, input_colors.data(), rect.size()); + ResourceId resource = CreateGpuResource( + this->child_context_provider_, this->child_resource_provider_.get(), + rect.size(), RGBA_8888, src_color_space_, input_colors.data()); // Return the mapped resource id. - cc::ResourceProvider::ResourceIdMap resource_map = - SendResourceAndGetChildToParentMap( - {resource}, this->resource_provider_.get(), - this->child_resource_provider_.get()); + std::unordered_map<ResourceId, ResourceId> resource_map = + SendResourceAndGetChildToParentMap({resource}, + this->resource_provider_.get(), + this->child_resource_provider_.get(), + this->child_context_provider_.get()); ResourceId mapped_resource = resource_map[resource]; bool needs_blending = true; @@ -3946,17 +4068,16 @@ TEST_P(ColorTransformPixelTest, Basic) { const gfx::PointF uv_bottom_right(1.0f, 1.0f); const bool flipped = false; const bool nearest_neighbor = false; - const bool premultiplied_alpha = false; auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>(); float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f}; quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource, - premultiplied_alpha, uv_top_left, uv_bottom_right, + premultiplied_alpha_, uv_top_left, uv_bottom_right, SK_ColorBLACK, vertex_opacity, flipped, nearest_neighbor, false); auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>(); - color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false); + color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false); } RenderPassList pass_list; @@ -4033,17 +4154,23 @@ gfx::ColorSpace intermediate_color_spaces[] = { gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::IEC61966_2_1_HDR), }; +bool color_space_premul_values[] = { + true, false, +}; + INSTANTIATE_TEST_CASE_P( FromColorSpace, ColorTransformPixelTest, testing::Combine(testing::ValuesIn(src_color_spaces), - testing::ValuesIn(intermediate_color_spaces))); + testing::ValuesIn(intermediate_color_spaces), + testing::ValuesIn(color_space_premul_values))); INSTANTIATE_TEST_CASE_P( ToColorSpace, ColorTransformPixelTest, testing::Combine(testing::ValuesIn(intermediate_color_spaces), - testing::ValuesIn(dst_color_spaces))); + testing::ValuesIn(dst_color_spaces), + testing::ValuesIn(color_space_premul_values))); #endif // !defined(OS_ANDROID) diff --git a/chromium/components/viz/service/display/scoped_render_pass_texture.h b/chromium/components/viz/service/display/scoped_render_pass_texture.h index b3a79e2067d..5700c68745e 100644 --- a/chromium/components/viz/service/display/scoped_render_pass_texture.h +++ b/chromium/components/viz/service/display/scoped_render_pass_texture.h @@ -7,7 +7,6 @@ #include "base/macros.h" #include "components/viz/common/resources/resource_format.h" -#include "components/viz/common/resources/resource_texture_hint.h" #include "components/viz/service/viz_service_export.h" #include "third_party/khronos/GLES2/gl2.h" #include "ui/gfx/color_space.h" diff --git a/chromium/components/viz/service/display/shader.cc b/chromium/components/viz/service/display/shader.cc index e7a927d140e..62bab35ad8b 100644 --- a/chromium/components/viz/service/display/shader.cc +++ b/chromium/components/viz/service/display/shader.cc @@ -11,6 +11,7 @@ #include <vector> #include "base/logging.h" +#include "base/strings/char_traits.h" #include "base/strings/stringprintf.h" #include "components/viz/service/display/static_geometry_binding.h" #include "gpu/command_buffer/client/gles2_interface.h" @@ -18,29 +19,18 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" -constexpr bool ConstexprEqual(const char* a, const char* b, size_t length) { - for (size_t i = 0; i < length; i++) { - if (a[i] != b[i]) - return false; - } - return true; -} - constexpr base::StringPiece StripLambda(base::StringPiece shader) { - // Must contain at least "[]() {}" and trailing null (included in size). - // TODO(jbroman): Simplify this once we're in a post-C++17 world, where - // starts_with and ends_with can easily be made constexpr. - DCHECK(shader.size() >= 7); // NOLINT - DCHECK(ConstexprEqual(shader.data(), "[]() {", 6)); + // Must contain at least "[]() {}". + DCHECK(shader.starts_with("[]() {")); + DCHECK(shader.ends_with("}")); shader.remove_prefix(6); - DCHECK(shader[shader.size() - 1] == '}'); // NOLINT shader.remove_suffix(1); return shader; } // Shaders are passed in with lambda syntax, which tricks clang-format into // handling them correctly. StripLambda removes this. -#define SHADER0(Src) StripLambda(base::StringPiece(#Src, sizeof(#Src) - 1)) +#define SHADER0(Src) StripLambda(#Src) #define HDR(x) \ do { \ @@ -535,11 +525,7 @@ void FragmentShader::Init(GLES2Interface* context, } void FragmentShader::SetBlendModeFunctions(std::string* shader_string) const { - if (shader_string->find("ApplyBlendMode") == std::string::npos) - return; - if (!has_blend_mode()) { - shader_string->insert(0, "#define ApplyBlendMode(X, Y) (X)\n"); return; } @@ -549,48 +535,39 @@ void FragmentShader::SetBlendModeFunctions(std::string* shader_string) const { uniform TexCoordPrecision vec4 backdropRect; }); - base::StringPiece mixFunction; + base::StringPiece function_apply_blend_mode; if (mask_for_background_) { - static constexpr base::StringPiece kMixFunctionWithMask = SHADER0([]() { - vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) { + static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() { + vec4 ApplyBlendMode(vec4 src, float mask) { + TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy; + bgTexCoord *= backdropRect.zw; vec4 backdrop = texture2D(s_backdropTexture, bgTexCoord); vec4 original_backdrop = texture2D(s_originalBackdropTexture, bgTexCoord); - return mix(original_backdrop, backdrop, mask); + vec4 dst = mix(original_backdrop, backdrop, mask); + return Blend(src, dst); } }); - mixFunction = kMixFunctionWithMask; + function_apply_blend_mode = kFunctionApplyBlendMode; } else { - static constexpr base::StringPiece kMixFunctionWithoutMask = SHADER0([]() { - vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) { - return texture2D(s_backdropTexture, bgTexCoord); + static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() { + vec4 ApplyBlendMode(vec4 src) { + TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy; + bgTexCoord *= backdropRect.zw; + vec4 dst = texture2D(s_backdropTexture, bgTexCoord); + return Blend(src, dst); } }); - mixFunction = kMixFunctionWithoutMask; + function_apply_blend_mode = kFunctionApplyBlendMode; } - static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() { - vec4 GetBackdropColor(float mask) { - TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy; - bgTexCoord.x /= backdropRect.z; - bgTexCoord.y /= backdropRect.w; - return MixBackdrop(bgTexCoord, mask); - } - - vec4 ApplyBlendMode(vec4 src, float mask) { - vec4 dst = GetBackdropColor(mask); - return Blend(src, dst); - } - }); - std::string shader; shader.reserve(shader_string->size() + 1024); shader += "precision mediump float;"; AppendHelperFunctions(&shader); AppendBlendFunction(&shader); kUniforms.AppendToString(&shader); - mixFunction.AppendToString(&shader); - kFunctionApplyBlendMode.AppendToString(&shader); + function_apply_blend_mode.AppendToString(&shader); shader += *shader_string; *shader_string = std::move(shader); } @@ -1015,12 +992,6 @@ std::string FragmentShader::GetShaderSource() const { SRC("float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);"); } - // Premultiply by alpha. - if (premultiply_alpha_mode_ == NON_PREMULTIPLIED_ALPHA) { - SRC("// Premultiply alpha"); - SRC("texColor.rgb *= texColor.a;"); - } - // Apply background texture. if (has_background_color_) { HDR("uniform vec4 background_color;"); @@ -1087,10 +1058,16 @@ std::string FragmentShader::GetShaderSource() const { SRC("gl_FragColor = vec4(texColor.rgb, 1.0);"); break; case FRAG_COLOR_MODE_APPLY_BLEND_MODE: - if (mask_mode_ != NO_MASK) - SRC("gl_FragColor = ApplyBlendMode(texColor, maskColor.w);"); - else - SRC("gl_FragColor = ApplyBlendMode(texColor, 0.0);"); + if (!has_blend_mode()) { + SRC("gl_FragColor = texColor;"); + } else if (mask_mode_ != NO_MASK) { + if (mask_for_background_) + SRC("gl_FragColor = ApplyBlendMode(texColor, maskColor.w);"); + else + SRC("gl_FragColor = ApplyBlendMode(texColor);"); + } else { + SRC("gl_FragColor = ApplyBlendMode(texColor);"); + } break; } source += "}\n"; diff --git a/chromium/components/viz/service/display/shader_unittest.cc b/chromium/components/viz/service/display/shader_unittest.cc index c05da251fe5..6990cbf14de 100644 --- a/chromium/components/viz/service/display/shader_unittest.cc +++ b/chromium/components/viz/service/display/shader_unittest.cc @@ -4,8 +4,8 @@ #include "components/viz/service/display/shader.h" +#include "components/viz/test/test_context_provider.h" #include "components/viz/test/test_gles2_interface.h" -#include "components/viz/test/test_web_graphics_context_3d.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/size.h" @@ -13,12 +13,11 @@ namespace viz { TEST(ShaderTest, HighpThresholds) { - // The test context always uses a mediump precision of 10 bits which + // The test gl always uses a mediump precision of 10 bits which // corresponds to a native highp threshold of 2^10 = 1024 - std::unique_ptr<TestWebGraphicsContext3D> test_context = - TestWebGraphicsContext3D::Create(); - TestGLES2Interface test_gl; - test_gl.set_test_context(test_context.get()); + scoped_refptr<TestContextProvider> provider = TestContextProvider::Create(); + provider->BindToCurrentThread(); + gpu::gles2::GLES2Interface* test_gl = provider->ContextGL(); int threshold_cache = 0; int threshold_min; @@ -29,30 +28,30 @@ TEST(ShaderTest, HighpThresholds) { threshold_min = 0; EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, closePoint)); EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, smallSize)); EXPECT_EQ(TEX_COORD_PRECISION_HIGH, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, farPoint)); EXPECT_EQ(TEX_COORD_PRECISION_HIGH, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, bigSize)); threshold_min = 3000; EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, closePoint)); EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, smallSize)); EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, farPoint)); EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM, - TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min, + TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min, bigSize)); } diff --git a/chromium/components/viz/service/display/skia_output_surface.cc b/chromium/components/viz/service/display/skia_output_surface.cc new file mode 100644 index 00000000000..abc0a6cdc1c --- /dev/null +++ b/chromium/components/viz/service/display/skia_output_surface.cc @@ -0,0 +1,15 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display/skia_output_surface.h" + +namespace viz { + +SkiaOutputSurface::SkiaOutputSurface( + scoped_refptr<ContextProvider> context_provider) + : OutputSurface(std::move(context_provider)) {} + +SkiaOutputSurface::~SkiaOutputSurface() = default; + +} // namespace viz diff --git a/chromium/components/viz/service/display/skia_output_surface.h b/chromium/components/viz/service/display/skia_output_surface.h new file mode 100644 index 00000000000..a93bfc26d66 --- /dev/null +++ b/chromium/components/viz/service/display/skia_output_surface.h @@ -0,0 +1,98 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_OUTPUT_SURFACE_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_OUTPUT_SURFACE_H_ + +#include "components/viz/common/resources/resource_format.h" +#include "components/viz/service/display/output_surface.h" +#include "third_party/skia/include/core/SkRefCnt.h" + +class SkCanvas; +class SkImage; + +namespace viz { + +struct ResourceMetadata; + +// This class extends the OutputSurface for SkiaRenderer needs. In future, the +// SkiaRenderer will be the only renderer. When other renderers are removed, +// we will replace OutputSurface with SkiaOutputSurface, and remove all +// OutputSurface's methods which are not useful for SkiaRenderer. +class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface { + public: + explicit SkiaOutputSurface(scoped_refptr<ContextProvider> context_provider); + ~SkiaOutputSurface() override; + + // Get a SkCanvas for the current frame. The SkiaRenderer will use this + // SkCanvas to draw quads. This class retains the ownership of the SkCanvas, + // And this SkCanvas may become invalid, when the frame is swapped out. + virtual SkCanvas* GetSkCanvasForCurrentFrame() = 0; + + // Make a promise SkImage from the given |metadata|. The SkiaRenderer can use + // the image with SkCanvas returned by |GetSkCanvasForCurrentFrame|, but Skia + // will not read the content of the resource until the sync token in the + // |metadata| is satisfied. The SwapBuffers should take care of this by + // scheduling a GPU task with all resource sync tokens recorded by + // MakePromiseSkImage for the current frame. + virtual sk_sp<SkImage> MakePromiseSkImage(ResourceMetadata metadata) = 0; + + // Make a promise SkImage from the given |metadata| and the |yuv_color_space|. + // For YUV format, three resource metadatas should be provided. metadatas[0] + // contains pixels from y panel, metadatas[1] contains pixels from u panel, + // metadatas[2] contains pixels from v panel. + // For NV12 format, two resource metadatas should be provided. metadatas[0] + // contains pixels from y panel, metadatas[1] contains pixels from u and v + // panels. + virtual sk_sp<SkImage> MakePromiseSkImageFromYUV( + std::vector<ResourceMetadata> metadatas, + SkYUVColorSpace yuv_color_space) = 0; + + // Swaps the current backbuffer to the screen and return a sync token which + // can be waited on in a command buffer to ensure the frame is completed. This + // token is released when the GPU ops from drawing the frame have been seen + // and processed by the GPU main. + // TODO(penghuang): replace OutputSurface::SwapBuffers with this method when + // SkiaRenderer and DDL are used everywhere. + virtual gpu::SyncToken SkiaSwapBuffers(OutputSurfaceFrame frame) = 0; + + // Begin painting a render pass. This method will create a + // SkDeferredDisplayListRecorder and return a SkCanvas of it. The SkiaRenderer + // will use this SkCanvas to paint the render pass. + // Note: BeginPaintRenderPass cannot be called without finishing the prior + // paint render pass. + virtual SkCanvas* BeginPaintRenderPass(const RenderPassId& id, + const gfx::Size& size, + ResourceFormat format, + bool mipmap) = 0; + + // Finish painting a render pass. It should be paired with + // BeginPaintRenderPass. This method will schedule a GPU task to play the DDL + // back on GPU thread on a cached SkSurface. This method returns a sync token + // which can be waited on in a command buffer to ensure the paint operation is + // completed. This token is released when the GPU ops from painting the render + // pass have been seen and processed by the GPU main. + virtual gpu::SyncToken FinishPaintRenderPass() = 0; + + // Make a promise SkImage from a render pass id. The render pass has been + // painted with BeginPaintRenderPass and FinishPaintRenderPass. The format + // and mipmap must match arguments used for BeginPaintRenderPass() to paint + // this render pass. + virtual sk_sp<SkImage> MakePromiseSkImageFromRenderPass( + const RenderPassId& id, + const gfx::Size& size, + ResourceFormat format, + bool mipmap) = 0; + + // Remove cached resources generated by BeginPaintRenderPass and + // FinishPaintRenderPass. + virtual void RemoveRenderPassResource(std::vector<RenderPassId> ids) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurface); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_OUTPUT_SURFACE_H_ diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc index 452b0146409..783fb7f778e 100644 --- a/chromium/components/viz/service/display/skia_renderer.cc +++ b/chromium/components/viz/service/display/skia_renderer.cc @@ -17,13 +17,16 @@ #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/quads/tile_draw_quad.h" +#include "components/viz/common/quads/yuv_video_draw_quad.h" #include "components/viz/common/resources/platform_color.h" #include "components/viz/common/resources/resource_fence.h" #include "components/viz/common/resources/resource_format_utils.h" +#include "components/viz/common/resources/resource_metadata.h" #include "components/viz/common/skia_helper.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display/output_surface_frame.h" #include "components/viz/service/display/renderer_utils.h" +#include "components/viz/service/display/skia_output_surface.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "skia/ext/opacity_filter_canvas.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -34,32 +37,20 @@ #include "third_party/skia/include/core/SkPath.h" #include "third_party/skia/include/core/SkShader.h" #include "third_party/skia/include/effects/SkOverdrawColorFilter.h" +#include "third_party/skia/include/effects/SkShaderMaskFilter.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" -#include "third_party/skia/include/gpu/GrContext.h" #include "ui/gfx/geometry/axis_transform2d.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/skia_util.h" #include "ui/gfx/transform.h" -#if BUILDFLAG(ENABLE_VULKAN) -#include "components/viz/common/gpu/vulkan_in_process_context_provider.h" -#include "gpu/vulkan/vulkan_device_queue.h" -#include "gpu/vulkan/vulkan_implementation.h" -#include "gpu/vulkan/vulkan_surface.h" -#include "gpu/vulkan/vulkan_swap_chain.h" -#include "third_party/skia/include/gpu/GrContext.h" -#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" -#include "third_party/skia/include/gpu/vk/GrVkTypes.h" -#endif - namespace viz { // Parameters needed to draw a RenderPassDrawQuad. struct SkiaRenderer::DrawRenderPassDrawQuadParams { // The "in" parameters that will be used when apply filters. const cc::FilterOperations* filters = nullptr; - const cc::FilterOperations* background_filters = nullptr; - // The "out" parameters that will be returned for future use. + // The "out" parameters returned by filters. // A Skia image that should be sampled from instead of the original // contents. sk_sp<SkImage> filter_image; @@ -68,32 +59,141 @@ struct SkiaRenderer::DrawRenderPassDrawQuadParams { gfx::RectF tex_coord_rect; }; +namespace { + +bool IsTextureResource(DisplayResourceProvider* resource_provider, + ResourceId resource_id) { + return resource_provider->GetResourceType(resource_id) == + ResourceType::kTexture; +} + +} // namespace + +// Scoped helper class for building SkImage from resource id. +class SkiaRenderer::ScopedSkImageBuilder { + public: + ScopedSkImageBuilder(SkiaRenderer* skia_renderer, ResourceId resource_id); + ~ScopedSkImageBuilder() = default; + + const SkImage* sk_image() const { return sk_image_; } + + private: + std::unique_ptr<DisplayResourceProvider::ScopedReadLockSkImage> lock_; + const SkImage* sk_image_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(ScopedSkImageBuilder); +}; + +SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder( + SkiaRenderer* skia_renderer, + ResourceId resource_id) { + auto* resource_provider = skia_renderer->resource_provider_; + if (!skia_renderer->skia_output_surface_ || + skia_renderer->non_root_surface_ || + !IsTextureResource(resource_provider, resource_id)) { + // TODO(penghuang): remove this code when DDL is used everywhere. + lock_ = std::make_unique<DisplayResourceProvider::ScopedReadLockSkImage>( + resource_provider, resource_id); + sk_image_ = lock_->sk_image(); + } else { + // Look up the image from promise_images_by resource_id and return the + // reference. If the resource_id doesn't exist, this statement will + // allocate it and return reference of it, and the reference will be used + // to store the new created image later. + auto& image = skia_renderer->promise_images_[resource_id]; + if (!image) { + auto metadata = + skia_renderer->lock_set_for_external_use_.LockResource(resource_id); + DCHECK(!metadata.mailbox.IsZero()); + image = skia_renderer->skia_output_surface_->MakePromiseSkImage( + std::move(metadata)); + DCHECK(image); + } + sk_image_ = image.get(); + } +} + +class SkiaRenderer::ScopedYUVSkImageBuilder { + public: + ScopedYUVSkImageBuilder(SkiaRenderer* skia_renderer, + const YUVVideoDrawQuad* quad) { + DCHECK(skia_renderer->skia_output_surface_); + DCHECK(IsTextureResource(skia_renderer->resource_provider_, + quad->y_plane_resource_id())); + DCHECK(IsTextureResource(skia_renderer->resource_provider_, + quad->u_plane_resource_id())); + DCHECK(IsTextureResource(skia_renderer->resource_provider_, + quad->v_plane_resource_id())); + DCHECK(quad->a_plane_resource_id() == kInvalidResourceId || + IsTextureResource(skia_renderer->resource_provider_, + quad->a_plane_resource_id())); + + YUVIds ids(quad->y_plane_resource_id(), quad->u_plane_resource_id(), + quad->v_plane_resource_id(), quad->a_plane_resource_id()); + auto& image = skia_renderer->yuv_promise_images_[std::move(ids)]; + + if (!image) { + auto yuv_color_space = kRec601_SkYUVColorSpace; + quad->video_color_space.ToSkYUVColorSpace(&yuv_color_space); + + std::vector<ResourceMetadata> metadatas; + bool is_yuv = quad->u_plane_resource_id() != quad->v_plane_resource_id(); + metadatas.reserve(is_yuv ? 3 : 2); + auto y_metadata = skia_renderer->lock_set_for_external_use_.LockResource( + quad->y_plane_resource_id()); + metadatas.push_back(std::move(y_metadata)); + auto u_metadata = skia_renderer->lock_set_for_external_use_.LockResource( + quad->u_plane_resource_id()); + metadatas.push_back(std::move(u_metadata)); + if (is_yuv) { + auto v_metadata = + skia_renderer->lock_set_for_external_use_.LockResource( + quad->v_plane_resource_id()); + metadatas.push_back(std::move(v_metadata)); + } + + if (quad->a_plane_resource_id() != kInvalidResourceId) { + // TODO(penghuang): Handle alpha channel when Skia supports YUVA format. + NOTIMPLEMENTED(); + } + + image = skia_renderer->skia_output_surface_->MakePromiseSkImageFromYUV( + std::move(metadatas), yuv_color_space); + DCHECK(image); + } + sk_image_ = image.get(); + } + + ~ScopedYUVSkImageBuilder() = default; + + const SkImage* sk_image() const { return sk_image_; } + + private: + std::unique_ptr<DisplayResourceProvider::ScopedReadLockSkImage> lock_; + SkImage* sk_image_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(ScopedYUVSkImageBuilder); +}; + SkiaRenderer::SkiaRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider) - : DirectRenderer(settings, output_surface, resource_provider) { -#if BUILDFLAG(ENABLE_VULKAN) - use_swap_with_bounds_ = false; -#else + DisplayResourceProvider* resource_provider, + SkiaOutputSurface* skia_output_surface) + : DirectRenderer(settings, output_surface, resource_provider), + skia_output_surface_(skia_output_surface), + lock_set_for_external_use_(resource_provider) { const auto& context_caps = output_surface_->context_provider()->ContextCapabilities(); use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds; - if (context_caps.sync_query) + if (context_caps.sync_query) { sync_queries_ = base::Optional<SyncQueryCollection>( - output_surface->context_provider()->ContextGL()); -#endif + output_surface_->context_provider()->ContextGL()); + } } -SkiaRenderer::~SkiaRenderer() { -#if BUILDFLAG(ENABLE_VULKAN) - return; -#endif -} +SkiaRenderer::~SkiaRenderer() = default; bool SkiaRenderer::CanPartialSwap() { -#if BUILDFLAG(ENABLE_VULKAN) - return false; -#endif if (use_swap_with_bounds_) return false; auto* context_provider = output_surface_->context_provider(); @@ -102,29 +202,28 @@ bool SkiaRenderer::CanPartialSwap() { void SkiaRenderer::BeginDrawingFrame() { TRACE_EVENT0("viz", "SkiaRenderer::BeginDrawingFrame"); -#if BUILDFLAG(ENABLE_VULKAN) - return; -#else // Copied from GLRenderer. scoped_refptr<ResourceFence> read_lock_fence; if (sync_queries_) { read_lock_fence = sync_queries_->StartNewFrame(); } else { read_lock_fence = - base::MakeRefCounted<cc::DisplayResourceProvider::SynchronousFence>( + base::MakeRefCounted<DisplayResourceProvider::SynchronousFence>( output_surface_->context_provider()->ContextGL()); } resource_provider_->SetReadLockFence(read_lock_fence.get()); - // Insert WaitSyncTokenCHROMIUM on quad resources prior to drawing the frame, - // so that drawing can proceed without GL context switching interruptions. - for (const auto& pass : *current_frame()->render_passes_in_draw_order) { - for (auto* quad : pass->quad_list) { - for (ResourceId resource_id : quad->resources) - resource_provider_->WaitSyncToken(resource_id); + if (!skia_output_surface_) { + // Insert WaitSyncTokenCHROMIUM on quad resources prior to drawing the + // frame, so that drawing can proceed without GL context switching + // interruptions. + for (const auto& pass : *current_frame()->render_passes_in_draw_order) { + for (auto* quad : pass->quad_list) { + for (ResourceId resource_id : quad->resources) + resource_provider_->WaitSyncToken(resource_id); + } } } -#endif } void SkiaRenderer::FinishDrawingFrame() { @@ -154,12 +253,14 @@ void SkiaRenderer::FinishDrawingFrame() { swap_content_bounds_ = current_frame()->root_content_bounds; } -void SkiaRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) { +void SkiaRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info, + bool need_presentation_feedback) { DCHECK(visible_); TRACE_EVENT0("cc,benchmark", "SkiaRenderer::SwapBuffers"); OutputSurfaceFrame output_frame; output_frame.latency_info = std::move(latency_info); output_frame.size = surface_size_for_swap_buffers(); + output_frame.need_presentation_feedback = need_presentation_feedback; if (use_swap_with_bounds_) { output_frame.content_bounds = std::move(swap_content_bounds_); } else if (use_partial_swap_) { @@ -168,7 +269,17 @@ void SkiaRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) { } else if (swap_buffer_rect_.IsEmpty() && allow_empty_swap_) { output_frame.sub_buffer_rect = swap_buffer_rect_; } - output_surface_->SwapBuffers(std::move(output_frame)); + + if (skia_output_surface_) { + auto sync_token = + skia_output_surface_->SkiaSwapBuffers(std::move(output_frame)); + promise_images_.clear(); + yuv_promise_images_.clear(); + lock_set_for_external_use_.UnlockResources(sync_token); + } else { + // TODO(penghuang): remove it when SkiaRenderer and SkDDL are always used. + output_surface_->SwapBuffers(std::move(output_frame)); + } swap_buffer_rect_ = gfx::Rect(); } @@ -195,36 +306,16 @@ void SkiaRenderer::BindFramebufferToOutputSurface() { SkSurfaceProps surface_props = SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); -#if BUILDFLAG(ENABLE_VULKAN) - gpu::VulkanSurface* vulkan_surface = output_surface_->GetVulkanSurface(); - gpu::VulkanSwapChain* swap_chain = vulkan_surface->GetSwapChain(); - VkImage image = swap_chain->GetCurrentImage(swap_chain->current_image()); - - GrVkImageInfo info_; - info_.fImage = image; - info_.fAlloc = {VK_NULL_HANDLE, 0, 0, 0}; - info_.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - info_.fImageTiling = VK_IMAGE_TILING_OPTIMAL; - info_.fFormat = VK_FORMAT_B8G8R8A8_UNORM; - info_.fLevelCount = 1; - - GrBackendRenderTarget render_target( - current_frame()->device_viewport_size.width(), - current_frame()->device_viewport_size.height(), 0, 0, info_); - - GrContext* gr_context = - output_surface_->vulkan_context_provider()->GetGrContext(); - root_surface_ = SkSurface::MakeFromBackendRenderTarget( - gr_context, render_target, kTopLeft_GrSurfaceOrigin, - kBGRA_8888_SkColorType, nullptr, &surface_props); -#else // TODO(weiliangc): Set up correct can_use_lcd_text for SkSurfaceProps flags. // How to setup is in ResourceProvider. (http://crbug.com/644851) GrContext* gr_context = output_surface_->context_provider()->GrContext(); - if (!root_canvas_ || root_canvas_->getGrContext() != gr_context || - gfx::SkISizeToSize(root_canvas_->getBaseLayerSize()) != - current_frame()->device_viewport_size) { + if (skia_output_surface_) { + root_canvas_ = skia_output_surface_->GetSkCanvasForCurrentFrame(); + DCHECK(root_canvas_); + } else if (!root_canvas_ || root_canvas_->getGrContext() != gr_context || + gfx::SkISizeToSize(root_canvas_->getBaseLayerSize()) != + current_frame()->device_viewport_size) { // Either no SkSurface setup yet, or new GrContext, need to create new // surface. GrGLFramebufferInfo framebuffer_info; @@ -237,13 +328,12 @@ void SkiaRenderer::BindFramebufferToOutputSurface() { root_surface_ = SkSurface::MakeFromBackendRenderTarget( gr_context, render_target, kBottomLeft_GrSurfaceOrigin, kRGB_888x_SkColorType, nullptr, &surface_props); + root_canvas_ = root_surface_->getCanvas(); } -#endif - root_canvas_ = root_surface_->getCanvas(); if (settings_->show_overdraw_feedback) { - const gfx::Size size(root_surface_->width(), root_surface_->height()); - overdraw_surface_ = root_surface_->makeSurface( + const auto& size = current_frame()->device_viewport_size; + overdraw_surface_ = root_canvas_->makeSurface( SkImageInfo::MakeA8(size.width(), size.height())); nway_canvas_ = std::make_unique<SkNWayCanvas>(size.width(), size.height()); overdraw_canvas_ = @@ -264,9 +354,16 @@ void SkiaRenderer::BindFramebufferToTexture(const RenderPassId render_pass_id) { // This function is called after AllocateRenderPassResourceIfNeeded, so there // should be backing ready. RenderPassBacking& backing = iter->second; - non_root_surface_ = backing.render_pass_surface; - current_canvas_ = non_root_surface_->getCanvas(); - current_surface_ = non_root_surface_.get(); + if (skia_output_surface_) { + non_root_surface_ = nullptr; + current_canvas_ = skia_output_surface_->BeginPaintRenderPass( + render_pass_id, backing.size, backing.format, backing.mipmap); + } else { + non_root_surface_ = backing.render_pass_surface; + current_surface_ = non_root_surface_.get(); + current_canvas_ = non_root_surface_->getCanvas(); + } + is_drawing_render_pass_ = true; } void SkiaRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) { @@ -420,8 +517,15 @@ void SkiaRenderer::DoDrawQuad(const DrawQuad* quad, // reaching a direct renderer. NOTREACHED(); break; - case DrawQuad::INVALID: case DrawQuad::YUV_VIDEO_CONTENT: + if (skia_output_surface_) { + DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad)); + } else { + DrawUnsupportedQuad(quad); + NOTIMPLEMENTED(); + } + break; + case DrawQuad::INVALID: case DrawQuad::STREAM_VIDEO_CONTENT: DrawUnsupportedQuad(quad); NOTREACHED(); @@ -509,10 +613,8 @@ void SkiaRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad) { } void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad) { - // TODO(skaslev): Add support for non-premultiplied alpha. - cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_, - quad->resource_id()); - const SkImage* image = lock.sk_image(); + ScopedSkImageBuilder builder(this, quad->resource_id()); + const SkImage* image = builder.sk_image(); if (!image) return; gfx::RectF uv_rect = gfx::ScaleRect( @@ -551,9 +653,9 @@ void SkiaRenderer::DrawTileQuad(const TileDrawQuad* quad) { // |resource_provider_| can be NULL in resourceless software draws, which // should never produce tile quads in the first place. DCHECK(resource_provider_); - cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_, - quad->resource_id()); - if (!lock.sk_image()) + ScopedSkImageBuilder builder(this, quad->resource_id()); + const SkImage* image = builder.sk_image(); + if (!image) return; gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional( quad->tex_coord_rect, gfx::RectF(quad->rect), @@ -564,7 +666,27 @@ void SkiaRenderer::DrawTileQuad(const TileDrawQuad* quad) { SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect); current_paint_.setFilterQuality( quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality); - current_canvas_->drawImageRect(lock.sk_image(), uv_rect, + current_canvas_->drawImageRect(image, uv_rect, + gfx::RectFToSkRect(visible_quad_vertex_rect), + ¤t_paint_); +} + +void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad) { + DCHECK(resource_provider_); + ScopedYUVSkImageBuilder builder(this, quad); + const SkImage* image = builder.sk_image(); + if (!image) + return; + gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional( + quad->ya_tex_coord_rect, gfx::RectF(quad->rect), + gfx::RectF(quad->visible_rect)); + gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional( + QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect)); + + SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect); + // TODO(penghuang): figure out how to set correct filter quality. + current_paint_.setFilterQuality(kLow_SkFilterQuality); + current_canvas_->drawImageRect(image, uv_rect, gfx::RectFToSkRect(visible_quad_vertex_rect), ¤t_paint_); } @@ -582,10 +704,8 @@ bool SkiaRenderer::CalculateRPDQParams(sk_sp<SkImage> content, // should be backing ready. RenderPassBacking& content_texture = iter->second; DCHECK(!params->filters->IsEmpty()); - gfx::Size size(content_texture.render_pass_surface->width(), - content_texture.render_pass_surface->height()); auto paint_filter = cc::RenderSurfaceFilters::BuildImageFilter( - *params->filters, gfx::SizeF(size)); + *params->filters, gfx::SizeF(content_texture.size)); auto filter = paint_filter ? paint_filter->cached_sk_filter_ : nullptr; // Apply filters to the content texture. @@ -641,17 +761,20 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) { DCHECK(render_pass_backings_.end() != iter); // This function is called after AllocateRenderPassResourceIfNeeded, so there // should be backing ready. - RenderPassBacking& content_texture = iter->second; + RenderPassBacking& backing = iter->second; // TODO(weiliangc): GL Renderer has optimization that when Render Pass has a // single quad inside we would draw that directly. We could add similar // optimization here by using the quad's SkImage. sk_sp<SkImage> content = - content_texture.render_pass_surface->makeImageSnapshot(); + skia_output_surface_ + ? skia_output_surface_->MakePromiseSkImageFromRenderPass( + quad->render_pass_id, backing.size, backing.format, + backing.mipmap) + : backing.render_pass_surface->makeImageSnapshot(); DrawRenderPassDrawQuadParams params; params.filters = FiltersForPass(quad->render_pass_id); - params.background_filters = BackgroundFiltersForPass(quad->render_pass_id); bool can_draw = CalculateRPDQParams(content, quad, ¶ms); if (!can_draw) @@ -670,8 +793,6 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) { QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect))); } - current_canvas_->drawImageRect(content, content_rect, dest_visible_rect, - ¤t_paint_); SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect()); @@ -680,20 +801,42 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) { SkMatrix::kFill_ScaleToFit); sk_sp<SkShader> shader; - shader = content->makeShader(SkShader::kClamp_TileMode, - SkShader::kClamp_TileMode, &content_mat); + shader = content->makeShader(&content_mat); - // TODO(weiliangc): Implement mask. (https://crbug.com/644851) if (quad->mask_resource_id()) { - NOTIMPLEMENTED(); + ScopedSkImageBuilder builder(this, quad->mask_resource_id()); + const SkImage* image = builder.sk_image(); + if (!image) + return; + + // Scale normalized uv rect into absolute texel coordinates. + SkRect mask_rect = gfx::RectFToSkRect( + gfx::ScaleRect(quad->mask_uv_rect, quad->mask_texture_size.width(), + quad->mask_texture_size.height())); + + SkMatrix mask_mat; + mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit); + current_paint_.setMaskFilter( + SkShaderMaskFilter::Make((image->makeShader(&mask_mat)))); + current_paint_.setShader(std::move(shader)); + current_canvas_->drawRect(dest_visible_rect, current_paint_); + return; } - // TODO(weiliangc): If we have a background filter shader, render its - // results first. (https://crbug.com/644851) - if (ShouldApplyBackgroundFilters(quad, params.background_filters)) { + // If we have a background filter shader, render its results first. + sk_sp<SkShader> background_filter_shader = + GetBackgroundFilterShader(quad, SkShader::kClamp_TileMode); + if (background_filter_shader) { + SkPaint paint; + paint.setShader(std::move(background_filter_shader)); + paint.setMaskFilter(current_paint_.refMaskFilter()); + current_canvas_->drawRect(dest_visible_rect, paint); current_paint_.setShader(std::move(shader)); current_canvas_->drawRect(dest_visible_rect, current_paint_); + return; } + current_canvas_->drawImageRect(content, content_rect, dest_visible_rect, + ¤t_paint_); } void SkiaRenderer::DrawUnsupportedQuad(const DrawQuad* quad) { @@ -714,6 +857,12 @@ void SkiaRenderer::CopyDrawnRenderPass( // TODO(weiliangc): Make copy request work. (crbug.com/644851) TRACE_EVENT0("viz", "SkiaRenderer::CopyDrawnRenderPass"); + if (skia_output_surface_) { + // TODO(penghuang): Support it with SkDDL. + NOTIMPLEMENTED(); + return; + } + gfx::Rect copy_rect = current_frame()->current_render_pass->output_rect; if (request->has_area()) copy_rect.Intersect(request->area()); @@ -752,7 +901,17 @@ void SkiaRenderer::DidChangeVisibility() { } void SkiaRenderer::FinishDrawingQuadList() { - current_canvas_->flush(); + if (skia_output_surface_) { + if (is_drawing_render_pass_) { + gpu::SyncToken sync_token = skia_output_surface_->FinishPaintRenderPass(); + promise_images_.clear(); + yuv_promise_images_.clear(); + lock_set_for_external_use_.UnlockResources(sync_token); + is_drawing_render_pass_ = false; + } + } else { + current_canvas_->flush(); + } } void SkiaRenderer::GenerateMipmap() { @@ -773,20 +932,17 @@ bool SkiaRenderer::ShouldApplyBackgroundFilters( return true; } -SkBitmap SkiaRenderer::GetBackdropBitmap(const gfx::Rect& bounding_rect) const { - SkBitmap bitmap; - bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounding_rect.width(), - bounding_rect.height())); - if (!current_canvas_->readPixels(bitmap, bounding_rect.x(), - bounding_rect.y())) - bitmap.reset(); - return bitmap; +sk_sp<SkImage> SkiaRenderer::GetBackdropImage( + const gfx::Rect& bounding_rect) const { + return root_surface_->makeImageSnapshot()->makeSubset( + gfx::RectToSkIRect(bounding_rect)); } gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad( const RenderPassDrawQuad* quad, const gfx::Transform& contents_device_transform, - const cc::FilterOperations* background_filters) const { + const cc::FilterOperations* background_filters, + gfx::Rect* unclipped_rect) const { DCHECK(ShouldApplyBackgroundFilters(quad, background_filters)); gfx::Rect backdrop_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect( contents_device_transform, QuadVertexRect())); @@ -795,18 +951,105 @@ gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad( matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y()); backdrop_rect = background_filters->MapRectReverse(backdrop_rect, matrix); + *unclipped_rect = backdrop_rect; backdrop_rect.Intersect(MoveFromDrawToWindowSpace( current_frame()->current_render_pass->output_rect)); return backdrop_rect; } +// If non-null, auto_bounds will be filled with the automatically-computed +// destination bounds. If null, the output will be the same size as the +// input image. +sk_sp<SkImage> SkiaRenderer::ApplyBackgroundFilters( + SkImageFilter* filter, + const RenderPassDrawQuad* quad, + sk_sp<SkImage> src_image, + const gfx::Rect& rect) const { + if (!filter) + return nullptr; + + SkMatrix local_matrix; + local_matrix.setTranslate(quad->filters_origin.x(), quad->filters_origin.y()); + local_matrix.postScale(quad->filters_scale.x(), quad->filters_scale.y()); + + SkImageInfo image_info = + SkImageInfo::Make(rect.width(), rect.height(), src_image->colorType(), + src_image->alphaType(), nullptr); + + GrContext* gr_context = output_surface_->context_provider()->GrContext(); + // TODO(weiliangc): Set up correct can_use_lcd_text for SkSurfaceProps flags. + // How to setup is in ResourceProvider. (http://crbug.com/644851) + // LegacyFontHost will get LCD text and skia figures out what type to use. + SkSurfaceProps surface_props(0, SkSurfaceProps::kLegacyFontHost_InitType); + sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget( + gr_context, SkBudgeted::kNo, image_info, 0, kBottomLeft_GrSurfaceOrigin, + &surface_props, false); + + if (!surface) { + return nullptr; + } + + SkPaint paint; + // Treat subnormal float values as zero for performance. + cc::ScopedSubnormalFloatDisabler disabler; + paint.setImageFilter(filter->makeWithLocalMatrix(local_matrix)); + surface->getCanvas()->translate(-rect.x(), -rect.y()); + surface->getCanvas()->drawImage(src_image, rect.x(), rect.y(), &paint); + + return surface->makeImageSnapshot(); +} + sk_sp<SkShader> SkiaRenderer::GetBackgroundFilterShader( const RenderPassDrawQuad* quad, SkShader::TileMode content_tile_mode) const { - // TODO(weiliangc): properly implement background filters. (crbug.com/644851) - NOTIMPLEMENTED(); - return nullptr; + const cc::FilterOperations* background_filters = + BackgroundFiltersForPass(quad->render_pass_id); + if (!ShouldApplyBackgroundFilters(quad, background_filters)) + return nullptr; + + gfx::Transform quad_rect_matrix; + QuadRectTransform(&quad_rect_matrix, + quad->shared_quad_state->quad_to_target_transform, + gfx::RectF(quad->rect)); + gfx::Transform contents_device_transform = + current_frame()->window_matrix * current_frame()->projection_matrix * + quad_rect_matrix; + contents_device_transform.FlattenTo2d(); + + gfx::Rect unclipped_rect; + gfx::Rect backdrop_rect = GetBackdropBoundingBoxForRenderPassQuad( + quad, contents_device_transform, background_filters, &unclipped_rect); + + // Figure out the transformations to move it back to pixel space. + gfx::Transform contents_device_transform_inverse; + if (!contents_device_transform.GetInverse(&contents_device_transform_inverse)) + return nullptr; + + SkMatrix filter_backdrop_transform = + contents_device_transform_inverse.matrix(); + filter_backdrop_transform.preTranslate(backdrop_rect.x(), backdrop_rect.y()); + + // Apply the filter to the backdrop. + sk_sp<SkImage> backdrop_image = GetBackdropImage(backdrop_rect); + + gfx::Vector2dF clipping_offset = + (unclipped_rect.top_right() - backdrop_rect.top_right()) + + (backdrop_rect.bottom_left() - unclipped_rect.bottom_left()); + sk_sp<SkImageFilter> filter = + cc::RenderSurfaceFilters::BuildImageFilter( + *background_filters, + gfx::SizeF(backdrop_image->width(), backdrop_image->height()), + clipping_offset) + ->cached_sk_filter_; + sk_sp<SkImage> filter_backdrop_image = + ApplyBackgroundFilters(filter.get(), quad, backdrop_image, backdrop_rect); + + if (!filter_backdrop_image) + return nullptr; + + return filter_backdrop_image->makeShader(content_tile_mode, content_tile_mode, + &filter_backdrop_transform); } void SkiaRenderer::UpdateRenderPassTextures( @@ -823,10 +1066,8 @@ void SkiaRenderer::UpdateRenderPassTextures( const RenderPassRequirements& requirements = render_pass_it->second; const RenderPassBacking& backing = pair.second; - SkSurface* backing_surface = pair.second.render_pass_surface.get(); - bool size_appropriate = - backing_surface->width() >= requirements.size.width() && - backing_surface->height() >= requirements.size.height(); + bool size_appropriate = backing.size.width() >= requirements.size.width() && + backing.size.height() >= requirements.size.height(); bool mipmap_appropriate = !requirements.mipmap || backing.mipmap; if (!size_appropriate || !mipmap_appropriate) passes_to_delete.push_back(pair.first); @@ -838,6 +1079,10 @@ void SkiaRenderer::UpdateRenderPassTextures( auto it = render_pass_backings_.find(passes_to_delete[i]); render_pass_backings_.erase(it); } + + if (skia_output_surface_ && !passes_to_delete.empty()) { + skia_output_surface_->RemoveRenderPassResource(std::move(passes_to_delete)); + } } void SkiaRenderer::AllocateRenderPassResourceIfNeeded( @@ -847,32 +1092,30 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded( if (it != render_pass_backings_.end()) return; -#if BUILDFLAG(ENABLE_VULKAN) - GrContext* gr_context = - output_surface_->vulkan_context_provider()->GetGrContext(); // TODO(penghuang): check supported format correctly. - bool capability_bgra8888 = true; -#else - ContextProvider* context_provider = output_surface_->context_provider(); - bool capability_bgra8888 = - context_provider->ContextCapabilities().texture_format_bgra8888; - GrContext* gr_context = context_provider->GrContext(); -#endif + gpu::Capabilities caps; + caps.texture_format_bgra8888 = true; + GrContext* gr_context = nullptr; + if (!skia_output_surface_) { + ContextProvider* context_provider = output_surface_->context_provider(); + caps.texture_format_bgra8888 = + context_provider->ContextCapabilities().texture_format_bgra8888; + gr_context = context_provider->GrContext(); + } render_pass_backings_.insert(std::pair<RenderPassId, RenderPassBacking>( render_pass_id, - RenderPassBacking(gr_context, requirements.size, requirements.mipmap, - capability_bgra8888, + RenderPassBacking(gr_context, caps, requirements.size, + requirements.mipmap, current_frame()->current_render_pass->color_space))); } SkiaRenderer::RenderPassBacking::RenderPassBacking( GrContext* gr_context, + const gpu::Capabilities& caps, const gfx::Size& size, bool mipmap, - bool capability_bgra8888, const gfx::ColorSpace& color_space) - : mipmap(mipmap), color_space(color_space) { - ResourceFormat format; + : size(size), mipmap(mipmap), color_space(color_space) { if (color_space.IsHDR()) { // If a platform does not support half-float renderbuffers then it should // not should request HDR rendering. @@ -880,14 +1123,20 @@ SkiaRenderer::RenderPassBacking::RenderPassBacking( // DCHECK(caps.color_buffer_half_float_rgba); format = RGBA_F16; } else { - format = PlatformColor::BestSupportedTextureFormat(capability_bgra8888); + format = PlatformColor::BestSupportedTextureFormat(caps); } - SkColorType color_type = ResourceFormatToClosestSkColorType(format); + + // For DDL, we don't need create teh render_pass_surface here, and we will + // create the SkSurface by SkiaOutputSurface on Gpu thread. + if (!gr_context) + return; constexpr uint32_t flags = 0; // LegacyFontHost will get LCD text and skia figures out what type to use. SkSurfaceProps surface_props(flags, SkSurfaceProps::kLegacyFontHost_InitType); int msaa_sample_count = 0; + SkColorType color_type = + ResourceFormatToClosestSkColorType(true /* gpu_compositing*/, format); SkImageInfo image_info = SkImageInfo::Make( size.width(), size.height(), color_type, kPremul_SkAlphaType, nullptr); render_pass_surface = SkSurface::MakeRenderTarget( @@ -899,15 +1148,20 @@ SkiaRenderer::RenderPassBacking::~RenderPassBacking() {} SkiaRenderer::RenderPassBacking::RenderPassBacking( SkiaRenderer::RenderPassBacking&& other) - : mipmap(other.mipmap), color_space(other.color_space) { + : size(other.size), + mipmap(other.mipmap), + color_space(other.color_space), + format(other.format) { render_pass_surface = other.render_pass_surface; other.render_pass_surface = nullptr; } SkiaRenderer::RenderPassBacking& SkiaRenderer::RenderPassBacking::operator=( SkiaRenderer::RenderPassBacking&& other) { + size = other.size; mipmap = other.mipmap; color_space = other.color_space; + format = other.format; render_pass_surface = other.render_pass_surface; other.render_pass_surface = nullptr; return *this; @@ -923,8 +1177,7 @@ gfx::Size SkiaRenderer::GetRenderPassBackingPixelSize( const RenderPassId& render_pass_id) { auto it = render_pass_backings_.find(render_pass_id); DCHECK(it != render_pass_backings_.end()); - SkSurface* texture = it->second.render_pass_surface.get(); - return gfx::Size(texture->width(), texture->height()); + return it->second.size; } } // namespace viz diff --git a/chromium/components/viz/service/display/skia_renderer.h b/chromium/components/viz/service/display/skia_renderer.h index 08a8a3de61d..63fdef52ea9 100644 --- a/chromium/components/viz/service/display/skia_renderer.h +++ b/chromium/components/viz/service/display/skia_renderer.h @@ -5,37 +5,41 @@ #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_ #define COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_ +#include <tuple> + #include "base/macros.h" #include "cc/cc_export.h" #include "components/viz/service/display/direct_renderer.h" #include "components/viz/service/display/sync_query_collection.h" #include "components/viz/service/viz_service_export.h" -#include "gpu/vulkan/buildflags.h" #include "ui/latency/latency_info.h" class SkNWayCanvas; -namespace cc { -class OutputSurface; -class RenderPassDrawQuad; -} // namespace cc +namespace gpu { +struct Capabilities; +} namespace viz { class DebugBorderDrawQuad; class PictureDrawQuad; +class SkiaOutputSurface; class SolidColorDrawQuad; class TextureDrawQuad; class TileDrawQuad; +class YUVVideoDrawQuad; class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { public: + // TODO(penghuang): Remove skia_output_surface when DDL is used everywhere. SkiaRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider); - + DisplayResourceProvider* resource_provider, + SkiaOutputSurface* skia_output_surface = nullptr); ~SkiaRenderer() override; - void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override; + void SwapBuffers(std::vector<ui::LatencyInfo> latency_info, + bool need_presentation_feedback) override; void SetDisablePictureQuadImageFiltering(bool disable) { disable_picture_quad_image_filtering_ = disable; @@ -73,6 +77,8 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { private: struct DrawRenderPassDrawQuadParams; + class ScopedSkImageBuilder; + class ScopedYUVSkImageBuilder; void ClearCanvas(SkColor color); void ClearFramebuffer(); @@ -84,6 +90,7 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { void DrawSolidColorQuad(const SolidColorDrawQuad* quad); void DrawTextureQuad(const TextureDrawQuad* quad); void DrawTileQuad(const TileDrawQuad* quad); + void DrawYUVVideoQuad(const YUVVideoDrawQuad* quad); void DrawUnsupportedQuad(const DrawQuad* quad); bool CalculateRPDQParams(sk_sp<SkImage> src_image, const RenderPassDrawQuad* quad, @@ -95,8 +102,14 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { gfx::Rect GetBackdropBoundingBoxForRenderPassQuad( const RenderPassDrawQuad* quad, const gfx::Transform& contents_device_transform, - const cc::FilterOperations* background_filters) const; - SkBitmap GetBackdropBitmap(const gfx::Rect& bounding_rect) const; + const cc::FilterOperations* background_filters, + gfx::Rect* unclipped_rect) const; + sk_sp<SkImage> ApplyBackgroundFilters(SkImageFilter* filter, + const RenderPassDrawQuad* quad, + sk_sp<SkImage> src_image, + const gfx::Rect& rect) const; + + sk_sp<SkImage> GetBackdropImage(const gfx::Rect& bounding_rect) const; sk_sp<SkShader> GetBackgroundFilterShader( const RenderPassDrawQuad* quad, SkShader::TileMode content_tile_mode) const; @@ -104,12 +117,14 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { // A map from RenderPass id to the texture used to draw the RenderPass from. struct RenderPassBacking { sk_sp<SkSurface> render_pass_surface; + gfx::Size size; bool mipmap; gfx::ColorSpace color_space; + ResourceFormat format; RenderPassBacking(GrContext* gr_context, + const gpu::Capabilities& caps, const gfx::Size& size, bool mipmap, - bool capability_bgra8888, const gfx::ColorSpace& color_space); ~RenderPassBacking(); RenderPassBacking(RenderPassBacking&&); @@ -117,11 +132,13 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { }; base::flat_map<RenderPassId, RenderPassBacking> render_pass_backings_; + SkiaOutputSurface* const skia_output_surface_ = nullptr; bool disable_picture_quad_image_filtering_ = false; - bool is_scissor_enabled_ = false; + gfx::Rect scissor_rect_; + bool is_drawing_render_pass_ = false; sk_sp<SkSurface> root_surface_; sk_sp<SkSurface> non_root_surface_; sk_sp<SkSurface> overdraw_surface_; @@ -138,6 +155,22 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer { gfx::Rect swap_buffer_rect_; std::vector<gfx::Rect> swap_content_bounds_; + // Lock set for resources that are used for the current frame. All resources + // in this set will be unlocked with a sync token when the frame is done in + // the compositor thread. And the sync token will be released when the DDL + // for the current frame is replayed on the GPU thread. + // It is only used with DDL. + DisplayResourceProvider::LockSetForExternalUse lock_set_for_external_use_; + + // Promise images created from resources used in the current frame. This map + // will be cleared when the frame is done and before all resources in + // |lock_set_for_external_use_| are unlocked on the compositor thread. + // It is only used with DDL. + base::flat_map<ResourceId, sk_sp<SkImage>> promise_images_; + + using YUVIds = std::tuple<ResourceId, ResourceId, ResourceId, ResourceId>; + base::flat_map<YUVIds, sk_sp<SkImage>> yuv_promise_images_; + DISALLOW_COPY_AND_ASSIGN(SkiaRenderer); }; diff --git a/chromium/components/viz/service/display/software_output_device.cc b/chromium/components/viz/service/display/software_output_device.cc index 7f8e8fd8504..6508266d977 100644 --- a/chromium/components/viz/service/display/software_output_device.cc +++ b/chromium/components/viz/service/display/software_output_device.cc @@ -5,14 +5,27 @@ #include "components/viz/service/display/software_output_device.h" #include "base/logging.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/vsync_provider.h" namespace viz { -SoftwareOutputDevice::SoftwareOutputDevice() = default; +SoftwareOutputDevice::SoftwareOutputDevice() + : SoftwareOutputDevice(base::SequencedTaskRunnerHandle::Get()) {} + +SoftwareOutputDevice::SoftwareOutputDevice( + scoped_refptr<base::SequencedTaskRunner> task_runner) + : task_runner_(std::move(task_runner)) {} + SoftwareOutputDevice::~SoftwareOutputDevice() = default; +void SoftwareOutputDevice::BindToClient(SoftwareOutputDeviceClient* client) { + DCHECK(client); + DCHECK(!client_); + client_ = client; +} + void SoftwareOutputDevice::Resize(const gfx::Size& viewport_pixel_size, float scale_factor) { if (viewport_pixel_size_ == viewport_pixel_size) @@ -36,4 +49,8 @@ gfx::VSyncProvider* SoftwareOutputDevice::GetVSyncProvider() { return vsync_provider_.get(); } +void SoftwareOutputDevice::OnSwapBuffers(base::OnceClosure swap_ack_callback) { + task_runner_->PostTask(FROM_HERE, std::move(swap_ack_callback)); +} + } // namespace viz diff --git a/chromium/components/viz/service/display/software_output_device.h b/chromium/components/viz/service/display/software_output_device.h index 63e233deb7d..ac80d97157e 100644 --- a/chromium/components/viz/service/display/software_output_device.h +++ b/chromium/components/viz/service/display/software_output_device.h @@ -7,7 +7,10 @@ #include <memory> +#include "base/callback.h" #include "base/macros.h" +#include "base/sequenced_task_runner.h" +#include "components/viz/service/display/software_output_device_client.h" #include "components/viz/service/viz_service_export.h" #include "third_party/skia/include/core/SkSurface.h" #include "ui/gfx/geometry/rect.h" @@ -18,17 +21,25 @@ class SkCanvas; namespace gfx { class VSyncProvider; -} +} // namespace gfx namespace viz { +class SoftwareOutputDeviceClient; + // This is a "tear-off" class providing software drawing support to // OutputSurface, such as to a platform-provided window framebuffer. class VIZ_SERVICE_EXPORT SoftwareOutputDevice { public: + // Uses TaskRunner returned from SequencedTaskRunnerHandle::Get(). SoftwareOutputDevice(); + explicit SoftwareOutputDevice( + scoped_refptr<base::SequencedTaskRunner> task_runner); virtual ~SoftwareOutputDevice(); + // This may be called only once, and requires a non-nullptr argument. + void BindToClient(SoftwareOutputDeviceClient* client); + // Discards any pre-existing backing buffers and allocates memory for a // software device of |size|. This must be called before the // |SoftwareOutputDevice| can be used in other ways. @@ -55,7 +66,15 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDevice { // hardware vsync. Return null if a provider doesn't exist. virtual gfx::VSyncProvider* GetVSyncProvider(); + // Called from OutputSurface::SwapBuffers(). The default implementation will + // immediately run |swap_ack_callback| via PostTask. If swap isn't synchronous + // this can be overriden so that |swap_ack_callback| is run after swap + // completes. + virtual void OnSwapBuffers(base::OnceClosure swap_ack_callback); + protected: + scoped_refptr<base::SequencedTaskRunner> task_runner_; + SoftwareOutputDeviceClient* client_ = nullptr; gfx::Size viewport_pixel_size_; gfx::Rect damage_rect_; sk_sp<SkSurface> surface_; diff --git a/chromium/components/viz/service/display/software_output_device_client.h b/chromium/components/viz/service/display/software_output_device_client.h new file mode 100644 index 00000000000..695354d2e08 --- /dev/null +++ b/chromium/components/viz/service/display/software_output_device_client.h @@ -0,0 +1,26 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_ + +namespace gfx { +struct CALayerParams; +} // namespace gfx + +namespace viz { + +class SoftwareOutputDeviceClient { + public: + virtual ~SoftwareOutputDeviceClient() {} + + // Specify the CALayer parameters used to display the content drawn by this + // device on macOS. + virtual void SoftwareDeviceUpdatedCALayerParams( + const gfx::CALayerParams& ca_layer_params) = 0; +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_ diff --git a/chromium/components/viz/service/display/software_renderer.cc b/chromium/components/viz/service/display/software_renderer.cc index a107b5be1f9..bc958f621cc 100644 --- a/chromium/components/viz/service/display/software_renderer.cc +++ b/chromium/components/viz/service/display/software_renderer.cc @@ -38,10 +38,9 @@ namespace viz { -SoftwareRenderer::SoftwareRenderer( - const RendererSettings* settings, - OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider) +SoftwareRenderer::SoftwareRenderer(const RendererSettings* settings, + OutputSurface* output_surface, + DisplayResourceProvider* resource_provider) : DirectRenderer(settings, output_surface, resource_provider), output_device_(output_surface->software_device()) {} @@ -65,11 +64,13 @@ void SoftwareRenderer::FinishDrawingFrame() { output_device_->EndPaint(); } -void SoftwareRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) { +void SoftwareRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info, + bool need_presentation_feedback) { DCHECK(visible_); TRACE_EVENT0("viz", "SoftwareRenderer::SwapBuffers"); OutputSurfaceFrame output_frame; output_frame.latency_info = std::move(latency_info); + output_frame.need_presentation_feedback = need_presentation_feedback; output_surface_->SwapBuffers(std::move(output_frame)); } @@ -168,16 +169,8 @@ void SoftwareRenderer::PrepareSurfaceForPass( } bool SoftwareRenderer::IsSoftwareResource(ResourceId resource_id) const { - switch (resource_provider_->GetResourceType(resource_id)) { - case ResourceType::kGpuMemoryBuffer: - case ResourceType::kTexture: - return false; - case ResourceType::kBitmap: - return true; - } - - LOG(FATAL) << "Invalid resource type."; - return false; + return resource_provider_->GetResourceType(resource_id) == + ResourceType::kBitmap; } void SoftwareRenderer::DoDrawQuad(const DrawQuad* quad, @@ -359,8 +352,8 @@ void SoftwareRenderer::DrawTextureQuad(const TextureDrawQuad* quad) { } // TODO(skaslev): Add support for non-premultiplied alpha. - cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_, - quad->resource_id()); + DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_, + quad->resource_id()); if (!lock.valid()) return; const SkImage* image = lock.sk_image(); @@ -402,8 +395,8 @@ void SoftwareRenderer::DrawTileQuad(const TileDrawQuad* quad) { DCHECK(resource_provider_); DCHECK(IsSoftwareResource(quad->resource_id())); - cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_, - quad->resource_id()); + DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_, + quad->resource_id()); if (!lock.valid()) return; @@ -476,11 +469,10 @@ void SoftwareRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) { SkShader::kClamp_TileMode, &content_mat); } - std::unique_ptr<cc::DisplayResourceProvider::ScopedReadLockSoftware> - mask_lock; + std::unique_ptr<DisplayResourceProvider::ScopedReadLockSoftware> mask_lock; if (quad->mask_resource_id()) { mask_lock = - std::make_unique<cc::DisplayResourceProvider::ScopedReadLockSoftware>( + std::make_unique<DisplayResourceProvider::ScopedReadLockSoftware>( resource_provider_, quad->mask_resource_id()); if (!mask_lock->valid()) diff --git a/chromium/components/viz/service/display/software_renderer.h b/chromium/components/viz/service/display/software_renderer.h index 3e7d634b077..0b901e7b7ed 100644 --- a/chromium/components/viz/service/display/software_renderer.h +++ b/chromium/components/viz/service/display/software_renderer.h @@ -10,13 +10,10 @@ #include "components/viz/service/viz_service_export.h" #include "ui/latency/latency_info.h" -namespace cc { -class OutputSurface; -class DisplayResourceProvider; -} // namespace cc - namespace viz { class DebugBorderDrawQuad; +class DisplayResourceProvider; +class OutputSurface; class PictureDrawQuad; class RenderPassDrawQuad; class SoftwareOutputDevice; @@ -28,11 +25,12 @@ class VIZ_SERVICE_EXPORT SoftwareRenderer : public DirectRenderer { public: SoftwareRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider); + DisplayResourceProvider* resource_provider); ~SoftwareRenderer() override; - void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override; + void SwapBuffers(std::vector<ui::LatencyInfo> latency_info, + bool need_presentation_feedback) override; void SetDisablePictureQuadImageFiltering(bool disable) { disable_picture_quad_image_filtering_ = disable; diff --git a/chromium/components/viz/service/display/software_renderer_unittest.cc b/chromium/components/viz/service/display/software_renderer_unittest.cc index e14a27766a7..86210a12099 100644 --- a/chromium/components/viz/service/display/software_renderer_unittest.cc +++ b/chromium/components/viz/service/display/software_renderer_unittest.cc @@ -7,6 +7,8 @@ #include <stdint.h> #include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/shared_memory.h" #include "base/run_loop.h" #include "cc/test/animation_test_common.h" #include "cc/test/fake_output_surface_client.h" @@ -20,8 +22,10 @@ #include "components/viz/common/quads/compositor_frame_metadata.h" #include "components/viz/common/quads/render_pass.h" #include "components/viz/common/quads/render_pass_draw_quad.h" +#include "components/viz/common/quads/shared_bitmap.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/tile_draw_quad.h" +#include "components/viz/common/resources/bitmap_allocation.h" #include "components/viz/service/display/software_output_device.h" #include "components/viz/test/fake_output_surface.h" #include "components/viz/test/test_shared_bitmap_manager.h" @@ -52,11 +56,10 @@ class SoftwareRendererTest : public testing::Test { renderer_->SetVisible(true); child_resource_provider_ = - cc::FakeResourceProvider::CreateLayerTreeResourceProvider( - nullptr, shared_bitmap_manager_.get()); + cc::FakeResourceProvider::CreateLayerTreeResourceProvider(nullptr); } - cc::DisplayResourceProvider* resource_provider() const { + DisplayResourceProvider* resource_provider() const { return resource_provider_.get(); } @@ -66,6 +69,26 @@ class SoftwareRendererTest : public testing::Test { SoftwareRenderer* renderer() const { return renderer_.get(); } + ResourceId AllocateAndFillSoftwareResource(const gfx::Size& size, + const SkBitmap& source) { + std::unique_ptr<base::SharedMemory> shm = + bitmap_allocation::AllocateMappedBitmap(size, RGBA_8888); + SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height()); + source.readPixels(info, shm->memory(), info.minRowBytes(), 0, 0); + + // Registers the SharedBitmapId in the display compositor. + SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId(); + shared_bitmap_manager_->ChildAllocatedSharedBitmap( + bitmap_allocation::DuplicateAndCloseMappedBitmap(shm.get(), size, + RGBA_8888), + shared_bitmap_id); + + // Makes a resource id that refers to the registered SharedBitmapId. + return child_resource_provider_->ImportResource( + TransferableResource::MakeSoftware(shared_bitmap_id, size, RGBA_8888), + SingleReleaseCallback::Create(base::DoNothing())); + } + std::unique_ptr<SkBitmap> DrawAndCopyOutput(RenderPassList* list, float device_scale_factor, gfx::Size viewport_size) { @@ -97,7 +120,7 @@ class SoftwareRendererTest : public testing::Test { cc::FakeOutputSurfaceClient output_surface_client_; std::unique_ptr<FakeOutputSurface> output_surface_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_; std::unique_ptr<SoftwareRenderer> renderer_; }; @@ -156,11 +179,6 @@ TEST_F(SoftwareRendererTest, TileQuad) { bool needs_blending = false; InitializeRenderer(std::make_unique<SoftwareOutputDevice>()); - ResourceId resource_yellow = child_resource_provider()->CreateBitmapResource( - outer_size, gfx::ColorSpace(), RGBA_8888); - ResourceId resource_cyan = child_resource_provider()->CreateBitmapResource( - inner_size, gfx::ColorSpace(), RGBA_8888); - SkBitmap yellow_tile; yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height()); yellow_tile.eraseColor(SK_ColorYELLOW); @@ -169,17 +187,16 @@ TEST_F(SoftwareRendererTest, TileQuad) { cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height()); cyan_tile.eraseColor(SK_ColorCYAN); - child_resource_provider()->CopyToResource( - resource_yellow, static_cast<uint8_t*>(yellow_tile.getPixels()), - outer_size); - child_resource_provider()->CopyToResource( - resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), inner_size); + ResourceId resource_yellow = + this->AllocateAndFillSoftwareResource(outer_size, yellow_tile); + ResourceId resource_cyan = + this->AllocateAndFillSoftwareResource(inner_size, cyan_tile); // Transfer resources to the parent, and get the resource map. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource_yellow, resource_cyan}, resource_provider(), - child_resource_provider()); + child_resource_provider(), nullptr); ResourceId mapped_resource_yellow = resource_map[resource_yellow]; ResourceId mapped_resource_cyan = resource_map[resource_cyan]; @@ -228,9 +245,6 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { visible_rect.Inset(1, 2, 3, 4); InitializeRenderer(std::make_unique<SoftwareOutputDevice>()); - ResourceId resource_cyan = child_resource_provider()->CreateBitmapResource( - tile_size, gfx::ColorSpace(), RGBA_8888); - SkBitmap cyan_tile; // The lowest five rows are yellow. cyan_tile.allocN32Pixels(tile_size.width(), tile_size.height()); cyan_tile.eraseColor(SK_ColorCYAN); @@ -238,13 +252,13 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) { tile_rect.width(), tile_rect.bottom()), SK_ColorYELLOW); - child_resource_provider()->CopyToResource( - resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), tile_size); + ResourceId resource_cyan = + AllocateAndFillSoftwareResource(tile_size, cyan_tile); // Transfer resources to the parent, and get the resource map. - cc::ResourceProvider::ResourceIdMap resource_map = + std::unordered_map<ResourceId, ResourceId> resource_map = SendResourceAndGetChildToParentMap({resource_cyan}, resource_provider(), - child_resource_provider()); + child_resource_provider(), nullptr); ResourceId mapped_resource_cyan = resource_map[resource_cyan]; gfx::Rect root_rect(tile_size); diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc index 5c41b6d48b8..c021630d66f 100644 --- a/chromium/components/viz/service/display/surface_aggregator.cc +++ b/chromium/components/viz/service/display/surface_aggregator.cc @@ -13,10 +13,10 @@ #include "base/logging.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" +#include "base/numerics/ranges.h" #include "base/stl_util.h" #include "base/trace_event/trace_event.h" #include "cc/base/math_util.h" -#include "cc/resources/display_resource_provider.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/render_pass_draw_quad.h" @@ -24,6 +24,7 @@ #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/quads/surface_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/surfaces/surface.h" #include "components/viz/service/surfaces/surface_client.h" #include "components/viz/service/surfaces/surface_manager.h" @@ -34,6 +35,10 @@ namespace { // Maximum bucket size for the UMA stats. constexpr int kUmaStatMaxSurfaces = 30; +// Used for determine when to treat opacity close to 1.f as opaque. The value is +// chosen to be smaller than 1/255. +constexpr float kOpacityEpsilon = 0.001f; + const char kUmaValidSurface[] = "Compositing.SurfaceAggregator.SurfaceDrawQuad.ValidSurface"; const char kUmaMissingSurface[] = @@ -77,7 +82,7 @@ bool CalculateQuadSpaceDamageRect( } // namespace SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager, - cc::DisplayResourceProvider* provider, + DisplayResourceProvider* provider, bool aggregate_only_damaged) : manager_(manager), provider_(provider), @@ -323,14 +328,15 @@ void SurfaceAggregator::EmitSurfaceContent( referenced_surfaces_.insert(surface_id); // TODO(vmpstr): provider check is a hack for unittests that don't set up a // resource provider. - cc::ResourceProvider::ResourceIdMap empty_map; + std::unordered_map<ResourceId, ResourceId> empty_map; const auto& child_to_parent_map = provider_ ? provider_->GetChildToParentMap(ChildIdForSurface(surface)) : empty_map; gfx::Transform combined_transform = scaled_quad_to_target_transform; combined_transform.ConcatTransform(target_transform); - bool merge_pass = source_sqs->opacity == 1.f && copy_requests.empty() && - combined_transform.Preserves2dAxisAlignment(); + bool merge_pass = + base::IsApproximatelyEqual(source_sqs->opacity, 1.f, kOpacityEpsilon) && + copy_requests.empty() && combined_transform.Preserves2dAxisAlignment(); const RenderPassList& referenced_passes = render_pass_list; // TODO(fsamuel): Move this to a separate helper function. @@ -763,7 +769,7 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame, // TODO(vmpstr): provider check is a hack for unittests that don't set up a // resource provider. - cc::ResourceProvider::ResourceIdMap empty_map; + std::unordered_map<ResourceId, ResourceId> empty_map; const auto& child_to_parent_map = provider_ ? provider_->GetChildToParentMap(ChildIdForSurface(surface)) : empty_map; @@ -841,11 +847,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, int parent_pass_id, bool will_draw, PrewalkResult* result) { - // This is for debugging a possible use after free. - // TODO(jbauman): Remove this once we have enough information. - // http://crbug.com/560181 - base::WeakPtr<SurfaceAggregator> debug_weak_this = weak_factory_.GetWeakPtr(); - if (referenced_surfaces_.count(surface->surface_id())) return gfx::Rect(); @@ -864,18 +865,16 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, surface->RefResources(frame.resource_list); provider_->ReceiveFromChild(child_id, frame.resource_list); } - CHECK(debug_weak_this.get()); std::vector<ResourceId> referenced_resources; size_t reserve_size = frame.resource_list.size(); referenced_resources.reserve(reserve_size); bool invalid_frame = false; - cc::ResourceProvider::ResourceIdMap empty_map; + std::unordered_map<ResourceId, ResourceId> empty_map; const auto& child_to_parent_map = provider_ ? provider_->GetChildToParentMap(child_id) : empty_map; - CHECK(debug_weak_this.get()); RenderPassId remapped_pass_id = RemapPassId(frame.render_pass_list.back()->id, surface->surface_id()); if (in_moved_pixel_surface) @@ -976,14 +975,12 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, if (invalid_frame) return gfx::Rect(); - CHECK(debug_weak_this.get()); valid_surfaces_.insert(surface->surface_id()); ResourceIdSet resource_set(std::move(referenced_resources), base::KEEP_FIRST_OF_DUPES); if (provider_) provider_->DeclareUsedResourcesFromChild(child_id, resource_set); - CHECK(debug_weak_this.get()); gfx::Rect damage_rect; gfx::Rect full_damage; @@ -1050,8 +1047,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, surface_info.target_to_surface_transform, surface_damage)); } - CHECK(debug_weak_this.get()); - if (!damage_rect.IsEmpty()) { // The following call can cause one or more copy requests to be added to the // Surface. Therefore, no code before this point should have assumed @@ -1066,8 +1061,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, if (will_draw) surface->OnWillBeDrawn(); - CHECK(debug_weak_this.get()); - for (const auto& surface_id : frame.metadata.referenced_surfaces) { if (!contained_surfaces_.count(surface_id)) { result->undrawn_surfaces.insert(surface_id); @@ -1077,7 +1070,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, } } - CHECK(debug_weak_this.get()); for (const auto& render_pass : frame.render_pass_list) { if (!render_pass->copy_requests.empty()) { RenderPassId remapped_pass_id = @@ -1089,8 +1081,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface, } auto it = referenced_surfaces_.find(surface->surface_id()); - // TODO(jbauman): Remove when https://crbug.com/745684 fixed. - CHECK(referenced_surfaces_.end() != it); referenced_surfaces_.erase(it); if (!damage_rect.IsEmpty() && frame.metadata.may_contain_video) result->may_contain_video = true; diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h index fc2c379e225..14b4bfe907d 100644 --- a/chromium/components/viz/service/display/surface_aggregator.h +++ b/chromium/components/viz/service/display/surface_aggregator.h @@ -19,12 +19,9 @@ #include "components/viz/service/viz_service_export.h" #include "ui/gfx/color_space.h" -namespace cc { -class DisplayResourceProvider; -} // namespace cc - namespace viz { class CompositorFrame; +class DisplayResourceProvider; class Surface; class SurfaceClient; class SurfaceDrawQuad; @@ -36,7 +33,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator { using FrameSinkIdMap = base::flat_map<FrameSinkId, LocalSurfaceId>; SurfaceAggregator(SurfaceManager* manager, - cc::DisplayResourceProvider* provider, + DisplayResourceProvider* provider, bool aggregate_only_damaged); ~SurfaceAggregator(); @@ -202,7 +199,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator { const std::vector<ReturnedResource>& resources); SurfaceManager* manager_; - cc::DisplayResourceProvider* provider_; + DisplayResourceProvider* provider_; // Every Surface has its own RenderPass ID namespace. This structure maps // each source (SurfaceId, RenderPass id) to a unified ID namespace that's diff --git a/chromium/components/viz/service/display/surface_aggregator_perftest.cc b/chromium/components/viz/service/display/surface_aggregator_perftest.cc index 9ae9e880f2f..ca2a7834ed1 100644 --- a/chromium/components/viz/service/display/surface_aggregator_perftest.cc +++ b/chromium/components/viz/service/display/surface_aggregator_perftest.cc @@ -3,13 +3,13 @@ // found in the LICENSE file. #include "cc/base/lap_timer.h" -#include "cc/resources/display_resource_provider.h" #include "cc/test/fake_output_surface_client.h" #include "cc/test/fake_resource_provider.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/quads/surface_draw_quad.h" #include "components/viz/common/quads/texture_draw_quad.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/display/surface_aggregator.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" @@ -150,7 +150,7 @@ class SurfaceAggregatorPerfTest : public testing::Test { FrameSinkManagerImpl manager_; scoped_refptr<TestContextProvider> context_provider_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<SurfaceAggregator> aggregator_; cc::LapTimer timer_; }; diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc index d25d5115d4a..23db64eab7b 100644 --- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc +++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc @@ -14,7 +14,6 @@ #include "base/memory/weak_ptr.h" #include "base/strings/stringprintf.h" #include "base/time/time.h" -#include "cc/resources/display_resource_provider.h" #include "cc/test/fake_resource_provider.h" #include "cc/test/render_pass_test_utils.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" @@ -27,6 +26,7 @@ #include "components/viz/common/quads/texture_draw_quad.h" #include "components/viz/common/resources/shared_bitmap_manager.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" +#include "components/viz/service/display/display_resource_provider.h" #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "components/viz/service/surfaces/surface.h" @@ -378,7 +378,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest { void SetUp() override { SurfaceAggregatorTest::SetUp(); - root_local_surface_id_ = allocator_.GenerateId(); + root_local_surface_id_ = allocator_.GetCurrentLocalSurfaceId(); root_surface_ = manager_.surface_manager()->GetSurfaceForId( SurfaceId(support_->frame_sink_id(), root_local_surface_id_)); } @@ -533,29 +533,44 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) { SubmitCompositorFrame(embedded_support.get(), embedded_passes, arraysize(embedded_passes), embedded_local_surface_id, device_scale_factor); + SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_); + { + Quad quads[] = {Quad::SurfaceQuad(embedded_surface_id, InvalidSurfaceId(), + SK_ColorWHITE, gfx::Rect(5, 5), .5f, + gfx::Transform(), false)}; + Pass passes[] = {Pass(quads, arraysize(quads), SurfaceSize())}; - Quad quads[] = {Quad::SurfaceQuad(embedded_surface_id, InvalidSurfaceId(), - SK_ColorWHITE, gfx::Rect(5, 5), .5f, - gfx::Transform(), false)}; - Pass passes[] = {Pass(quads, arraysize(quads), SurfaceSize())}; + SubmitCompositorFrame(support_.get(), passes, arraysize(passes), + root_local_surface_id_, device_scale_factor); - SubmitCompositorFrame(support_.get(), passes, arraysize(passes), - root_local_surface_id_, device_scale_factor); + CompositorFrame aggregated_frame = aggregator_.Aggregate( + root_surface_id, GetNextDisplayTimeAndIncrement()); - SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_); - CompositorFrame aggregated_frame = - aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement()); + auto& render_pass_list = aggregated_frame.render_pass_list; + EXPECT_EQ(2u, render_pass_list.size()); - auto& render_pass_list = aggregated_frame.render_pass_list; - ASSERT_EQ(2u, render_pass_list.size()); - auto& shared_quad_state_list = render_pass_list[0]->shared_quad_state_list; - ASSERT_EQ(2u, shared_quad_state_list.size()); - EXPECT_EQ(1.f, shared_quad_state_list.ElementAt(0)->opacity); - EXPECT_EQ(1.f, shared_quad_state_list.ElementAt(1)->opacity); - - auto& shared_quad_state_list2 = render_pass_list[1]->shared_quad_state_list; - ASSERT_EQ(1u, shared_quad_state_list2.size()); - EXPECT_EQ(.5f, shared_quad_state_list2.ElementAt(0)->opacity); + auto& shared_quad_state_list2 = render_pass_list[1]->shared_quad_state_list; + ASSERT_EQ(1u, shared_quad_state_list2.size()); + EXPECT_EQ(.5f, shared_quad_state_list2.ElementAt(0)->opacity); + } + + // For the case where opacity is close to 1.f, we treat it as opaque, and not + // use a render surface. + { + Quad quads[] = {Quad::SurfaceQuad(embedded_surface_id, InvalidSurfaceId(), + SK_ColorWHITE, gfx::Rect(5, 5), .9999f, + gfx::Transform(), false)}; + Pass passes[] = {Pass(quads, arraysize(quads), SurfaceSize())}; + + SubmitCompositorFrame(support_.get(), passes, arraysize(passes), + root_local_surface_id_, device_scale_factor); + + CompositorFrame aggregated_frame = aggregator_.Aggregate( + root_surface_id, GetNextDisplayTimeAndIncrement()); + + auto& render_pass_list = aggregated_frame.render_pass_list; + EXPECT_EQ(1u, render_pass_list.size()); + } } // Test that when surface is rotated and we need the render surface to apply the @@ -2952,7 +2967,7 @@ class SurfaceAggregatorWithResourcesTest : public testing::Test, protected: FrameSinkManagerImpl manager_; std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_; - std::unique_ptr<cc::DisplayResourceProvider> resource_provider_; + std::unique_ptr<DisplayResourceProvider> resource_provider_; std::unique_ptr<SurfaceAggregator> aggregator_; }; diff --git a/chromium/components/viz/service/display/vulkan_renderer.cc b/chromium/components/viz/service/display/vulkan_renderer.cc index 87ede657bd4..1ddd1d36e24 100644 --- a/chromium/components/viz/service/display/vulkan_renderer.cc +++ b/chromium/components/viz/service/display/vulkan_renderer.cc @@ -19,7 +19,7 @@ void VulkanRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) { VulkanRenderer::VulkanRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider) + DisplayResourceProvider* resource_provider) : DirectRenderer(settings, output_surface, resource_provider) {} void VulkanRenderer::DidChangeVisibility() { diff --git a/chromium/components/viz/service/display/vulkan_renderer.h b/chromium/components/viz/service/display/vulkan_renderer.h index ce07ecce7b7..4e7ff89a7ab 100644 --- a/chromium/components/viz/service/display/vulkan_renderer.h +++ b/chromium/components/viz/service/display/vulkan_renderer.h @@ -9,17 +9,15 @@ #include "components/viz/service/viz_service_export.h" #include "ui/latency/latency_info.h" -namespace cc { -class OutputSurface; -} // namespace cc - namespace viz { +class OutputSurface; + class VIZ_SERVICE_EXPORT VulkanRenderer : public DirectRenderer { public: VulkanRenderer(const RendererSettings* settings, OutputSurface* output_surface, - cc::DisplayResourceProvider* resource_provider); + DisplayResourceProvider* resource_provider); ~VulkanRenderer() override; // Implementation of public DirectRenderer functions. diff --git a/chromium/components/viz/service/display_embedder/DEPS b/chromium/components/viz/service/display_embedder/DEPS index 5fc1a52037e..38bf218cf88 100644 --- a/chromium/components/viz/service/display_embedder/DEPS +++ b/chromium/components/viz/service/display_embedder/DEPS @@ -2,7 +2,6 @@ include_rules = [ "+cc/base", - "+cc/ipc", "+cc/output", "+cc/resources", "+cc/scheduler", @@ -10,18 +9,21 @@ include_rules = [ "+components/viz/service/display/output_surface_frame.h", "+components/viz/service/display/output_surface.h", "+components/viz/service/display/overlay_candidate_validator.h", + "+components/viz/service/display/skia_output_surface.h", "+components/viz/service/display/software_output_device.h", + "+gpu/config/gpu_feature_info.h", + "+components/viz/service/gl/gpu_service_impl.h", "+gpu/GLES2", "+gpu/command_buffer/client", "+gpu/command_buffer/common", "+gpu/command_buffer/service", - "+gpu/ipc/client", - "+gpu/ipc/common", - "+gpu/ipc/in_process_command_buffer.h", - "+gpu/ipc/service", + "+gpu/ipc", + "+gpu/skia_bindings", "+mojo/public/cpp/bindings", "+mojo/public/cpp/system", "+skia", + "+third_party/khronos/GLES2/gl2.h", + "+third_party/khronos/GLES2/gl2ext.h", "+third_party/skia", "+ui/accelerated_widget_mac", "+ui/display", diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc index a91ebec2695..f0af20b4c82 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc @@ -20,11 +20,19 @@ CompositorOverlayCandidateValidatorAndroid:: void CompositorOverlayCandidateValidatorAndroid::GetStrategies( OverlayProcessor::StrategyList* strategies) { - strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(this)); + // For Android, we do not have the ability to skip an overlay, since the + // texture is already in a SurfaceView. Ideally, we would honor a 'force + // overlay' flag that FromDrawQuad would also check. + // For now, though, just skip the opacity check. We really have no idea if + // the underlying overlay is opaque anyway; the candidate is referring to + // a dummy resource that has no relation to what the overlay contains. + // https://crbug.com/842931 . + strategies->push_back(std::make_unique<OverlayStrategyUnderlay>( + this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates)); } void CompositorOverlayCandidateValidatorAndroid::CheckOverlaySupport( - cc::OverlayCandidateList* candidates) { + OverlayCandidateList* candidates) { // There should only be at most a single overlay candidate: the video quad. // There's no check that the presented candidate is really a video frame for // a fullscreen video. Instead it's assumed that if a quad is marked as @@ -32,7 +40,7 @@ void CompositorOverlayCandidateValidatorAndroid::CheckOverlaySupport( DCHECK_LE(candidates->size(), 1u); if (!candidates->empty()) { - cc::OverlayCandidate& candidate = candidates->front(); + OverlayCandidate& candidate = candidates->front(); // This quad either will be promoted, or would be if it were backed by a // SurfaceView. Record that it should get a promotion hint. diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h index df053dce733..2b30937d787 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h @@ -26,7 +26,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorAndroid ~CompositorOverlayCandidateValidatorAndroid() override; void GetStrategies(OverlayProcessor::StrategyList* strategies) override; - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override; + void CheckOverlaySupport(OverlayCandidateList* surfaces) override; bool AllowCALayerOverlays() override; bool AllowDCLayerOverlays() override; diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc index 07bc790a298..ebe761bab99 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc @@ -27,7 +27,7 @@ bool CompositorOverlayCandidateValidatorMac::AllowDCLayerOverlays() { } void CompositorOverlayCandidateValidatorMac::CheckOverlaySupport( - cc::OverlayCandidateList* surfaces) {} + OverlayCandidateList* surfaces) {} void CompositorOverlayCandidateValidatorMac::SetSoftwareMirrorMode( bool enabled) { diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h index b2a01c46c19..7d6ad9e5b20 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h @@ -23,7 +23,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorMac void GetStrategies(OverlayProcessor::StrategyList* strategies) override; bool AllowCALayerOverlays() override; bool AllowDCLayerOverlays() override; - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override; + void CheckOverlaySupport(OverlayCandidateList* surfaces) override; // CompositorOverlayCandidateValidator implementation. void SetSoftwareMirrorMode(bool enabled) override; diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc index 88f74d0f352..e0bdbf80fae 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc @@ -29,8 +29,8 @@ std::unique_ptr<OverlayProcessor::Strategy> MakeOverlayStrategy( } // namespace // |overlay_candidates| is an object used to answer questions about possible -// overlays configuarations. -// |strategies_string| is a comma-separated string containing all the overaly +// overlays configurations. +// |strategies_string| is a comma-separated string containing all the overlay // strategies that should be returned by GetStrategies. // If |strategies_string| is empty "single-on-top,underlay" will be used as // default. @@ -82,7 +82,7 @@ bool CompositorOverlayCandidateValidatorOzone::AllowDCLayerOverlays() { } void CompositorOverlayCandidateValidatorOzone::CheckOverlaySupport( - cc::OverlayCandidateList* surfaces) { + OverlayCandidateList* surfaces) { // SW mirroring copies out of the framebuffer, so we can't remove any // quads for overlaying, otherwise the output is incorrect. if (software_mirror_active_) { diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h index 13fcbc9c039..3c03de00fe8 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h @@ -31,7 +31,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorOzone void GetStrategies(OverlayProcessor::StrategyList* strategies) override; bool AllowCALayerOverlays() override; bool AllowDCLayerOverlays() override; - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override; + void CheckOverlaySupport(OverlayCandidateList* surfaces) override; // CompositorOverlayCandidateValidator implementation. void SetSoftwareMirrorMode(bool enabled) override; diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc index 44494ef59c5..28663e891fa 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc @@ -18,7 +18,7 @@ void CompositorOverlayCandidateValidatorWin::GetStrategies( OverlayProcessor::StrategyList* strategies) {} void CompositorOverlayCandidateValidatorWin::CheckOverlaySupport( - cc::OverlayCandidateList* candidates) { + OverlayCandidateList* candidates) { NOTIMPLEMENTED(); } diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h index fe25ef93771..2685709a9b6 100644 --- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h +++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h @@ -20,7 +20,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorWin ~CompositorOverlayCandidateValidatorWin() override; void GetStrategies(OverlayProcessor::StrategyList* strategies) override; - void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override; + void CheckOverlaySupport(OverlayCandidateList* surfaces) override; bool AllowCALayerOverlays() override; bool AllowDCLayerOverlays() override; diff --git a/chromium/components/viz/service/display_embedder/display_provider.h b/chromium/components/viz/service/display_embedder/display_provider.h index eaae5ac0805..12fa6146fef 100644 --- a/chromium/components/viz/service/display_embedder/display_provider.h +++ b/chromium/components/viz/service/display_embedder/display_provider.h @@ -8,6 +8,7 @@ #include <memory> #include "gpu/ipc/common/surface_handle.h" +#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h" namespace viz { @@ -29,6 +30,7 @@ class DisplayProvider { const FrameSinkId& frame_sink_id, gpu::SurfaceHandle surface_handle, bool gpu_compositing, + mojom::DisplayClient* display_client, ExternalBeginFrameControllerImpl* external_begin_frame_controller, const RendererSettings& renderer_settings, std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) = 0; diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.cc b/chromium/components/viz/service/display_embedder/gl_output_surface.cc index ef2e3675d25..55fc38aabac 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface.cc +++ b/chromium/components/viz/service/display_embedder/gl_output_surface.cc @@ -15,33 +15,34 @@ #include "gpu/command_buffer/client/context_support.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "gpu/command_buffer/common/swap_buffers_complete_params.h" +#include "gpu/command_buffer/common/swap_buffers_flags.h" #include "ui/gl/gl_utils.h" namespace viz { GLOutputSurface::GLOutputSurface( - scoped_refptr<InProcessContextProvider> context_provider, + scoped_refptr<VizProcessContextProvider> context_provider, SyntheticBeginFrameSource* synthetic_begin_frame_source) : OutputSurface(context_provider), synthetic_begin_frame_source_(synthetic_begin_frame_source), - latency_tracker_(true), - latency_info_cache_(this), + use_gpu_fence_( + context_provider->ContextCapabilities().chromium_gpu_fence && + context_provider->ContextCapabilities() + .use_gpu_fences_for_overlay_planes), weak_ptr_factory_(this) { capabilities_.flipped_output_surface = context_provider->ContextCapabilities().flips_vertically; capabilities_.supports_stencil = context_provider->ContextCapabilities().num_stencil_bits > 0; - context_provider->SetSwapBuffersCompletionCallback( - base::BindRepeating(&GLOutputSurface::OnGpuSwapBuffersCompleted, - weak_ptr_factory_.GetWeakPtr())); context_provider->SetUpdateVSyncParametersCallback( base::BindRepeating(&GLOutputSurface::OnVSyncParametersUpdated, weak_ptr_factory_.GetWeakPtr())); - context_provider->SetPresentationCallback(base::BindRepeating( - &GLOutputSurface::OnPresentation, weak_ptr_factory_.GetWeakPtr())); } -GLOutputSurface::~GLOutputSurface() {} +GLOutputSurface::~GLOutputSurface() { + if (gpu_fence_id_ > 0) + context_provider()->ContextGL()->DestroyGpuFenceCHROMIUM(gpu_fence_id_); +} void GLOutputSurface::BindToClient(OutputSurfaceClient* client) { DCHECK(client); @@ -86,21 +87,37 @@ void GLOutputSurface::Reshape(const gfx::Size& size, void GLOutputSurface::SwapBuffers(OutputSurfaceFrame frame) { DCHECK(context_provider_); - if (latency_info_cache_.WillSwap(std::move(frame.latency_info))) + uint32_t flags = 0; + if (synthetic_begin_frame_source_) + flags |= gpu::SwapBuffersFlags::kVSyncParams; + + if (LatencyInfoHasSnapshotRequest(frame.latency_info)) context_provider_->ContextSupport()->SetSnapshotRequested(); + auto swap_callback = base::BindOnce( + &GLOutputSurface::OnGpuSwapBuffersCompleted, + weak_ptr_factory_.GetWeakPtr(), std::move(frame.latency_info)); + gpu::ContextSupport::PresentationCallback presentation_callback; + if (frame.need_presentation_feedback) { + flags |= gpu::SwapBuffersFlags::kPresentationFeedback; + presentation_callback = base::BindOnce(&GLOutputSurface::OnPresentation, + weak_ptr_factory_.GetWeakPtr()); + } + set_draw_rectangle_for_frame_ = false; if (frame.sub_buffer_rect) { context_provider_->ContextSupport()->PartialSwapBuffers( - *frame.sub_buffer_rect); + *frame.sub_buffer_rect, flags, std::move(swap_callback), + std::move(presentation_callback)); } else { - context_provider_->ContextSupport()->Swap(); + context_provider_->ContextSupport()->Swap(flags, std::move(swap_callback), + std::move(presentation_callback)); } } uint32_t GLOutputSurface::GetFramebufferCopyTextureFormat() { // TODO(danakj): What attributes are used for the default framebuffer here? - // Can it have alpha? InProcessContextProvider doesn't take any + // Can it have alpha? VizProcessContextProvider doesn't take any // attributes. return GL_RGB; } @@ -122,37 +139,28 @@ gfx::BufferFormat GLOutputSurface::GetOverlayBufferFormat() const { return gfx::BufferFormat::RGBX_8888; } -bool GLOutputSurface::SurfaceIsSuspendForRecycle() const { - return false; -} - bool GLOutputSurface::HasExternalStencilTest() const { return false; } void GLOutputSurface::ApplyExternalStencil() {} -void GLOutputSurface::DidReceiveSwapBuffersAck(gfx::SwapResult result, - uint64_t swap_id) { - client_->DidReceiveSwapBuffersAck(swap_id); +void GLOutputSurface::DidReceiveSwapBuffersAck(gfx::SwapResult result) { + client_->DidReceiveSwapBuffersAck(); } void GLOutputSurface::OnGpuSwapBuffersCompleted( + std::vector<ui::LatencyInfo> latency_info, const gpu::SwapBuffersCompleteParams& params) { if (!params.texture_in_use_responses.empty()) client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses); if (!params.ca_layer_params.is_empty) client_->DidReceiveCALayerParams(params.ca_layer_params); - DidReceiveSwapBuffersAck(params.swap_response.result, - params.swap_response.swap_id); - latency_info_cache_.OnSwapBuffersCompleted(params.swap_response); -} + DidReceiveSwapBuffersAck(params.swap_response.result); -void GLOutputSurface::LatencyInfoCompleted( - const std::vector<ui::LatencyInfo>& latency_info) { - for (const auto& latency : latency_info) { - latency_tracker_.OnGpuSwapBuffersCompleted(latency); - } + UpdateLatencyInfoOnSwap(params.swap_response, &latency_info); + latency_tracker_.OnGpuSwapBuffersCompleted(latency_info); + client_->DidFinishLatencyInfo(latency_info); } void GLOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase, @@ -166,9 +174,8 @@ void GLOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase, } void GLOutputSurface::OnPresentation( - uint64_t swap_id, const gfx::PresentationFeedback& feedback) { - client_->DidReceivePresentationFeedback(swap_id, feedback); + client_->DidReceivePresentationFeedback(feedback); } #if BUILDFLAG(ENABLE_VULKAN) @@ -178,4 +185,16 @@ gpu::VulkanSurface* GLOutputSurface::GetVulkanSurface() { } #endif +unsigned GLOutputSurface::UpdateGpuFence() { + if (!use_gpu_fence_) + return 0; + + if (gpu_fence_id_ > 0) + context_provider()->ContextGL()->DestroyGpuFenceCHROMIUM(gpu_fence_id_); + + gpu_fence_id_ = context_provider()->ContextGL()->CreateGpuFenceCHROMIUM(); + + return gpu_fence_id_; +} + } // namespace viz diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.h b/chromium/components/viz/service/display_embedder/gl_output_surface.h index c2e58bb7dca..06f87f581c3 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface.h +++ b/chromium/components/viz/service/display_embedder/gl_output_surface.h @@ -7,8 +7,8 @@ #include <memory> -#include "components/viz/common/gpu/in_process_context_provider.h" #include "components/viz/service/display/output_surface.h" +#include "components/viz/service/display_embedder/viz_process_context_provider.h" #include "ui/latency/latency_tracker.h" namespace viz { @@ -17,10 +17,9 @@ class SyntheticBeginFrameSource; // An OutputSurface implementation that directly draws and // swaps to an actual GL surface. -class GLOutputSurface : public OutputSurface, - public OutputSurface::LatencyInfoCache::Client { +class GLOutputSurface : public OutputSurface { public: - GLOutputSurface(scoped_refptr<InProcessContextProvider> context_provider, + GLOutputSurface(scoped_refptr<VizProcessContextProvider> context_provider, SyntheticBeginFrameSource* synthetic_begin_frame_source); ~GLOutputSurface() override; @@ -41,31 +40,26 @@ class GLOutputSurface : public OutputSurface, bool IsDisplayedAsOverlayPlane() const override; unsigned GetOverlayTextureId() const override; gfx::BufferFormat GetOverlayBufferFormat() const override; - bool SurfaceIsSuspendForRecycle() const override; bool HasExternalStencilTest() const override; void ApplyExternalStencil() override; #if BUILDFLAG(ENABLE_VULKAN) gpu::VulkanSurface* GetVulkanSurface() override; #endif - - // OutputSurface::LatencyInfoCache::Client implementation. - void LatencyInfoCompleted( - const std::vector<ui::LatencyInfo>& latency_info) override; + unsigned UpdateGpuFence() override; protected: OutputSurfaceClient* client() const { return client_; } // Called when a swap completion is signaled from ImageTransportSurface. - virtual void DidReceiveSwapBuffersAck(gfx::SwapResult result, - uint64_t swap_id); + virtual void DidReceiveSwapBuffersAck(gfx::SwapResult result); private: // Called when a swap completion is signaled from ImageTransportSurface. - void OnGpuSwapBuffersCompleted(const gpu::SwapBuffersCompleteParams& params); + void OnGpuSwapBuffersCompleted(std::vector<ui::LatencyInfo> latency_info, + const gpu::SwapBuffersCompleteParams& params); void OnVSyncParametersUpdated(base::TimeTicks timebase, base::TimeDelta interval); - void OnPresentation(uint64_t swap_id, - const gfx::PresentationFeedback& feedback); + void OnPresentation(const gfx::PresentationFeedback& feedback); OutputSurfaceClient* client_ = nullptr; SyntheticBeginFrameSource* const synthetic_begin_frame_source_; @@ -75,7 +69,8 @@ class GLOutputSurface : public OutputSurface, // True if the draw rectangle has been set at all since the last resize. bool has_set_draw_rectangle_since_last_resize_ = false; gfx::Size size_; - LatencyInfoCache latency_info_cache_; + bool use_gpu_fence_; + unsigned gpu_fence_id_ = 0; base::WeakPtrFactory<GLOutputSurface> weak_ptr_factory_; }; 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 cf02039d4b4..279daf5f4ff 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 @@ -18,7 +18,7 @@ namespace viz { GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue( - scoped_refptr<InProcessContextProvider> context_provider, + scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, SyntheticBeginFrameSource* synthetic_begin_frame_source, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, @@ -105,8 +105,7 @@ gfx::BufferFormat GLOutputSurfaceBufferQueue::GetOverlayBufferFormat() const { } void GLOutputSurfaceBufferQueue::DidReceiveSwapBuffersAck( - gfx::SwapResult result, - uint64_t swap_id) { + gfx::SwapResult result) { bool force_swap = false; if (result == gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS) { // Even through the swap failed, this is a fixable error so we can pretend @@ -117,7 +116,7 @@ void GLOutputSurfaceBufferQueue::DidReceiveSwapBuffersAck( } buffer_queue_->PageFlipComplete(); - client()->DidReceiveSwapBuffersAck(swap_id); + client()->DidReceiveSwapBuffersAck(); if (force_swap) client()->SetNeedsRedrawRect(gfx::Rect(swap_size_)); diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h index ff22c17ad31..3703297b1c7 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h +++ b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h @@ -10,9 +10,9 @@ #include "base/memory/weak_ptr.h" #include "components/viz/common/gl_helper.h" #include "components/viz/common/gpu/context_provider.h" -#include "components/viz/common/gpu/in_process_context_provider.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/display_embedder/gl_output_surface.h" +#include "components/viz/service/display_embedder/viz_process_context_provider.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/swap_result.h" @@ -34,7 +34,7 @@ class SyntheticBeginFrameSource; class GLOutputSurfaceBufferQueue : public GLOutputSurface { public: GLOutputSurfaceBufferQueue( - scoped_refptr<InProcessContextProvider> context_provider, + scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, SyntheticBeginFrameSource* synthetic_begin_frame_source, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, @@ -61,8 +61,7 @@ class GLOutputSurfaceBufferQueue : public GLOutputSurface { gfx::BufferFormat GetOverlayBufferFormat() const override; // GLOutputSurface: - void DidReceiveSwapBuffersAck(gfx::SwapResult result, - uint64_t swap_id) override; + void DidReceiveSwapBuffersAck(gfx::SwapResult result) override; GLHelper gl_helper_; std::unique_ptr<BufferQueue> buffer_queue_; diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc index e1a1c23f4dd..cb0fa658934 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc +++ b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc @@ -9,7 +9,7 @@ namespace viz { GLOutputSurfaceMac::GLOutputSurfaceMac( - scoped_refptr<InProcessContextProvider> context_provider, + scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, SyntheticBeginFrameSource* synthetic_begin_frame_source, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h index f26801f584b..5e2e8b20542 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h +++ b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h @@ -12,7 +12,7 @@ namespace viz { class GLOutputSurfaceMac : public GLOutputSurfaceBufferQueue { public: - GLOutputSurfaceMac(scoped_refptr<InProcessContextProvider> context_provider, + GLOutputSurfaceMac(scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, SyntheticBeginFrameSource* synthetic_begin_frame_source, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc index 50deccee3f7..8c42482ba2c 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc +++ b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc @@ -9,7 +9,7 @@ namespace viz { GLOutputSurfaceOzone::GLOutputSurfaceOzone( - scoped_refptr<InProcessContextProvider> context_provider, + scoped_refptr<VizProcessContextProvider> context_provider, gpu::SurfaceHandle surface_handle, SyntheticBeginFrameSource* synthetic_begin_frame_source, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h index 69544d0a23f..47a7cffb50f 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h +++ b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h @@ -11,12 +11,13 @@ namespace viz { class GLOutputSurfaceOzone : public GLOutputSurfaceBufferQueue { public: - GLOutputSurfaceOzone(scoped_refptr<InProcessContextProvider> context_provider, - gpu::SurfaceHandle surface_handle, - SyntheticBeginFrameSource* synthetic_begin_frame_source, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - uint32_t target, - uint32_t internal_format); + GLOutputSurfaceOzone( + scoped_refptr<VizProcessContextProvider> context_provider, + gpu::SurfaceHandle surface_handle, + SyntheticBeginFrameSource* synthetic_begin_frame_source, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + uint32_t target, + uint32_t internal_format); ~GLOutputSurfaceOzone() override; private: diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc index da3fde6007a..5e79df4b94e 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc +++ b/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc @@ -9,7 +9,7 @@ namespace viz { GLOutputSurfaceWin::GLOutputSurfaceWin( - scoped_refptr<InProcessContextProvider> context_provider, + scoped_refptr<VizProcessContextProvider> context_provider, SyntheticBeginFrameSource* synthetic_begin_frame_source, bool use_overlays) : GLOutputSurface(context_provider, synthetic_begin_frame_source) { diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_win.h b/chromium/components/viz/service/display_embedder/gl_output_surface_win.h index c62a7498b47..e71a7b0bd40 100644 --- a/chromium/components/viz/service/display_embedder/gl_output_surface_win.h +++ b/chromium/components/viz/service/display_embedder/gl_output_surface_win.h @@ -16,7 +16,7 @@ class CompositorOverlayCandidateValidatorWin; class GLOutputSurfaceWin : public GLOutputSurface { public: - GLOutputSurfaceWin(scoped_refptr<InProcessContextProvider> context_provider, + GLOutputSurfaceWin(scoped_refptr<VizProcessContextProvider> context_provider, SyntheticBeginFrameSource* synthetic_begin_frame_source, bool use_overlays); ~GLOutputSurfaceWin() override; diff --git a/chromium/components/viz/service/display_embedder/gpu_display_provider.cc b/chromium/components/viz/service/display_embedder/gpu_display_provider.cc index 45b178149bf..3da085bc5df 100644 --- a/chromium/components/viz/service/display_embedder/gpu_display_provider.cc +++ b/chromium/components/viz/service/display_embedder/gpu_display_provider.cc @@ -7,18 +7,20 @@ #include <utility> #include "base/command_line.h" +#include "base/compiler_specific.h" #include "base/threading/thread_task_runner_handle.h" #include "cc/base/switches.h" #include "components/viz/common/display/renderer_settings.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" -#include "components/viz/common/gpu/in_process_context_provider.h" #include "components/viz/service/display/display.h" #include "components/viz/service/display/display_scheduler.h" #include "components/viz/service/display_embedder/external_begin_frame_controller_impl.h" #include "components/viz/service/display_embedder/gl_output_surface.h" #include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" +#include "components/viz/service/display_embedder/skia_output_surface_impl.h" #include "components/viz/service/display_embedder/software_output_surface.h" +#include "components/viz/service/display_embedder/viz_process_context_provider.h" #include "gpu/command_buffer/client/shared_memory_limits.h" #include "gpu/command_buffer/service/image_factory.h" #include "gpu/ipc/common/surface_handle.h" @@ -64,11 +66,13 @@ namespace viz { GpuDisplayProvider::GpuDisplayProvider( uint32_t restart_id, + GpuServiceImpl* gpu_service_impl, scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service, gpu::GpuChannelManager* gpu_channel_manager, bool headless, bool wait_for_all_pipeline_stages_before_draw) : restart_id_(restart_id), + gpu_service_impl_(gpu_service_impl), gpu_service_(std::move(gpu_service)), gpu_channel_manager_delegate_(gpu_channel_manager->delegate()), gpu_memory_buffer_manager_( @@ -88,6 +92,7 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay( const FrameSinkId& frame_sink_id, gpu::SurfaceHandle surface_handle, bool gpu_compositing, + mojom::DisplayClient* display_client, ExternalBeginFrameControllerImpl* external_begin_frame_controller, const RendererSettings& renderer_settings, std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) { @@ -103,21 +108,46 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay( display_begin_frame_source = synthetic_begin_frame_source.get(); } + // TODO(penghuang): Merge two output surfaces into one when GLRenderer and + // software compositor is removed. std::unique_ptr<OutputSurface> output_surface; + SkiaOutputSurface* skia_output_surface = nullptr; if (!gpu_compositing) { output_surface = std::make_unique<SoftwareOutputSurface>( - CreateSoftwareOutputDeviceForPlatform(surface_handle), task_runner_); + CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client)); + } else if (renderer_settings.use_skia_renderer && + renderer_settings.use_skia_deferred_display_list) { +#if defined(OS_MACOSX) || defined(OS_WIN) + // TODO(penghuang): Support DDL for all platforms. + NOTIMPLEMENTED(); + // Workaround compile error: private field 'gpu_service_impl_' is not used. + ALLOW_UNUSED_LOCAL(gpu_service_impl_); +#else + // Create an offscreen context_provider for SkiaOutputSurfaceImpl, because + // SkiaRenderer still needs it to draw RenderPass into a texture. + // TODO(penghuang): Remove this context_provider. https://crbug.com/825901 + auto context_provider = base::MakeRefCounted<VizProcessContextProvider>( + gpu_service_, gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(), + image_factory_, gpu_channel_manager_delegate_, + gpu::SharedMemoryLimits()); + auto result = context_provider->BindToCurrentThread(); + CHECK_EQ(result, gpu::ContextResult::kSuccess); + output_surface = std::make_unique<SkiaOutputSurfaceImpl>( + gpu_service_impl_, surface_handle, std::move(context_provider), + synthetic_begin_frame_source.get()); + skia_output_surface = static_cast<SkiaOutputSurface*>(output_surface.get()); +#endif } else { - scoped_refptr<InProcessContextProvider> context_provider; + scoped_refptr<VizProcessContextProvider> context_provider; // Retry creating and binding |context_provider| on transient failures. gpu::ContextResult context_result = gpu::ContextResult::kTransientFailure; while (context_result != gpu::ContextResult::kSuccess) { - context_provider = base::MakeRefCounted<InProcessContextProvider>( + context_provider = base::MakeRefCounted<VizProcessContextProvider>( gpu_service_, surface_handle, gpu_memory_buffer_manager_.get(), image_factory_, gpu_channel_manager_delegate_, - gpu::SharedMemoryLimits(), nullptr /* shared_context */); + gpu::SharedMemoryLimits()); context_result = context_provider->BindToCurrentThread(); // TODO(crbug.com/819474): Don't crash here, instead fallback to software @@ -166,34 +196,22 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay( return std::make_unique<Display>( ServerSharedBitmapManager::current(), renderer_settings, frame_sink_id, - std::move(output_surface), std::move(scheduler), task_runner_); + std::move(output_surface), std::move(scheduler), task_runner_, + skia_output_surface); } std::unique_ptr<SoftwareOutputDevice> GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform( - gpu::SurfaceHandle surface_handle) { + gpu::SurfaceHandle surface_handle, + mojom::DisplayClient* display_client) { if (headless_) return std::make_unique<SoftwareOutputDevice>(); -#if defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW) - gfx::AcceleratedWidget widget = surface_handle; -#endif - #if defined(OS_WIN) - if (!output_device_backing_) - output_device_backing_ = std::make_unique<OutputDeviceBacking>(); - return std::make_unique<SoftwareOutputDeviceWin>(output_device_backing_.get(), - widget); + return CreateSoftwareOutputDeviceWinGpu( + surface_handle, &output_device_backing_, display_client); #elif defined(OS_MACOSX) - // TODO(crbug.com/730660): What do we do to get something we can draw to? Can - // we use an IO surface? Can we use CA layers and overlays like we do for gpu - // compositing? See https://crrev.com/c/792295 to no longer have - // GpuSurfaceTracker. Part of the SoftwareOutputDeviceMac::EndPaint probably - // needs to move to the browser process, and we need to set up transport of an - // IO surface to here? - NOTIMPLEMENTED(); - (void)widget; - return nullptr; + return std::make_unique<SoftwareOutputDeviceMac>(task_runner_); #elif defined(OS_ANDROID) // Android does not do software compositing, so we can't get here. NOTREACHED(); @@ -202,11 +220,11 @@ GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform( ui::SurfaceFactoryOzone* factory = ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone(); std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone = - factory->CreateCanvasForWidget(widget); + factory->CreateCanvasForWidget(surface_handle); CHECK(surface_ozone); return std::make_unique<SoftwareOutputDeviceOzone>(std::move(surface_ozone)); #elif defined(USE_X11) - return std::make_unique<SoftwareOutputDeviceX11>(widget); + return std::make_unique<SoftwareOutputDeviceX11>(surface_handle); #endif } diff --git a/chromium/components/viz/service/display_embedder/gpu_display_provider.h b/chromium/components/viz/service/display_embedder/gpu_display_provider.h index 0a4c19bbfa8..f714ee18a64 100644 --- a/chromium/components/viz/service/display_embedder/gpu_display_provider.h +++ b/chromium/components/viz/service/display_embedder/gpu_display_provider.h @@ -18,6 +18,10 @@ #include "gpu/ipc/common/surface_handle.h" #include "gpu/ipc/in_process_command_buffer.h" +#if defined(OS_WIN) +#include "components/viz/service/display_embedder/output_device_backing.h" +#endif + namespace gpu { class GpuChannelManager; class GpuChannelManagerDelegate; @@ -27,7 +31,7 @@ class ImageFactory; namespace viz { class Display; class ExternalBeginFrameControllerImpl; -class OutputDeviceBacking; +class GpuServiceImpl; class SoftwareOutputDevice; // In-process implementation of DisplayProvider. @@ -35,6 +39,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider { public: GpuDisplayProvider( uint32_t restart_id, + GpuServiceImpl* gpu_service_impl, scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service, gpu::GpuChannelManager* gpu_channel_manager, bool headless, @@ -46,6 +51,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider { const FrameSinkId& frame_sink_id, gpu::SurfaceHandle surface_handle, bool gpu_compositing, + mojom::DisplayClient* display_client, ExternalBeginFrameControllerImpl* external_begin_frame_controller, const RendererSettings& renderer_settings, std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) @@ -53,9 +59,11 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider { private: std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceForPlatform( - gpu::SurfaceHandle surface_handle); + gpu::SurfaceHandle surface_handle, + mojom::DisplayClient* display_client); const uint32_t restart_id_; + GpuServiceImpl* const gpu_service_impl_; scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_; gpu::GpuChannelManagerDelegate* const gpu_channel_manager_delegate_; std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_; @@ -63,7 +71,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider { #if defined(OS_WIN) // Used for software compositing output on Windows. - std::unique_ptr<OutputDeviceBacking> output_device_backing_; + OutputDeviceBacking output_device_backing_; #endif scoped_refptr<base::SingleThreadTaskRunner> task_runner_; diff --git a/chromium/components/viz/service/display_embedder/output_device_backing.cc b/chromium/components/viz/service/display_embedder/output_device_backing.cc new file mode 100644 index 00000000000..68e3aca8758 --- /dev/null +++ b/chromium/components/viz/service/display_embedder/output_device_backing.cc @@ -0,0 +1,102 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display_embedder/output_device_backing.h" + +#include <algorithm> + +#include "base/debug/alias.h" +#include "base/memory/shared_memory.h" +#include "base/stl_util.h" +#include "components/viz/common/resources/resource_sizes.h" + +namespace viz { +namespace { + +// If a window is larger than this in bytes, don't even try to create a backing +// bitmap for it. +constexpr size_t kMaxBitmapSizeBytes = 4 * (16384 * 8192); + +// Finds the size in bytes to hold |viewport_size| pixels. If |viewport_size| is +// a valid size this will return true and |out_bytes| will contain the size in +// bytes. If |viewport_size| is not a valid size then this will return false. +bool GetViewportSizeInBytes(const gfx::Size& viewport_size, size_t* out_bytes) { + size_t bytes; + if (!ResourceSizes::MaybeSizeInBytes(viewport_size, RGBA_8888, &bytes)) + return false; + if (bytes > kMaxBitmapSizeBytes) + return false; + *out_bytes = bytes; + return true; +} + +} // namespace + +OutputDeviceBacking::OutputDeviceBacking() = default; + +OutputDeviceBacking::~OutputDeviceBacking() { + DCHECK(clients_.empty()); +} + +void OutputDeviceBacking::ClientResized() { + // If the max viewport size doesn't change then nothing here changes. + if (GetMaxViewportBytes() == created_shm_bytes_) + return; + + // Otherwise we need to allocate a new SharedMemory segment and clients + // should re-request it. + for (auto* client : clients_) + client->ReleaseCanvas(); + + shm_.reset(); + created_shm_bytes_ = 0; +} + +void OutputDeviceBacking::RegisterClient(Client* client) { + clients_.push_back(client); +} + +void OutputDeviceBacking::UnregisterClient(Client* client) { + DCHECK(base::ContainsValue(clients_, client)); + base::Erase(clients_, client); + ClientResized(); +} + +base::SharedMemory* OutputDeviceBacking::GetSharedMemory( + const gfx::Size& viewport_size) { + // If |viewport_size| is empty or too big don't try to allocate SharedMemory. + size_t viewport_bytes; + if (!GetViewportSizeInBytes(viewport_size, &viewport_bytes)) + return nullptr; + + // Allocate a new SharedMemory segment that can fit the largest viewport. + if (!shm_) { + size_t max_viewport_bytes = GetMaxViewportBytes(); + DCHECK_LE(viewport_bytes, max_viewport_bytes); + + shm_ = std::make_unique<base::SharedMemory>(); + base::debug::Alias(&max_viewport_bytes); + CHECK(shm_->CreateAnonymous(max_viewport_bytes)); + created_shm_bytes_ = max_viewport_bytes; + } else { + // Clients must call Resize() for new |viewport_size|. + DCHECK_LE(viewport_bytes, created_shm_bytes_); + } + + return shm_.get(); +} + +size_t OutputDeviceBacking::GetMaxViewportBytes() { + // Minimum byte size is 1 because creating a 0-byte-long SharedMemory fails. + size_t max_bytes = 1; + for (auto* client : clients_) { + size_t current_bytes; + if (!GetViewportSizeInBytes(client->GetViewportPixelSize(), ¤t_bytes)) + continue; + max_bytes = std::max(max_bytes, current_bytes); + } + return max_bytes; +} + +} // namespace viz diff --git a/chromium/components/viz/service/display_embedder/output_device_backing.h b/chromium/components/viz/service/display_embedder/output_device_backing.h new file mode 100644 index 00000000000..b3a9b1cb81c --- /dev/null +++ b/chromium/components/viz/service/display_embedder/output_device_backing.h @@ -0,0 +1,65 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_DEVICE_BACKING_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_DEVICE_BACKING_H_ + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "components/viz/service/viz_service_export.h" +#include "ui/gfx/geometry/size.h" + +namespace base { +class SharedMemory; +} + +namespace viz { + +// Allocates and owns a SharedMemory backing for multiple SoftwareOutputDevices. +// The backing will be big enough to hold the largest size returned by a +// client's GetViewportPixelSize(). +class VIZ_SERVICE_EXPORT OutputDeviceBacking { + public: + class Client { + public: + virtual const gfx::Size& GetViewportPixelSize() const = 0; + virtual void ReleaseCanvas() = 0; + + protected: + virtual ~Client() = default; + }; + + OutputDeviceBacking(); + ~OutputDeviceBacking(); + + void RegisterClient(Client* client); + void UnregisterClient(Client* client); + + // Called when a client has resized. Clients should call Resize() after being + // registered when they have a valid size. Will potential invalidate + // SharedMemory and call ReleaseCanvas() on clients. + void ClientResized(); + + // Requests a SharedMemory segment large enough to fit |viewport_size|. Will + // return null if |viewport_size| is too large to safely allocate SharedMemory + // for. + base::SharedMemory* GetSharedMemory(const gfx::Size& viewport_size); + + // Returns the maximum size in bytes needed for the largest viewport from + // registered clients. + size_t GetMaxViewportBytes(); + + private: + std::vector<Client*> clients_; + std::unique_ptr<base::SharedMemory> shm_; + size_t created_shm_bytes_ = 0; + + DISALLOW_COPY_AND_ASSIGN(OutputDeviceBacking); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_DEVICE_BACKING_H_ diff --git a/chromium/components/viz/service/display_embedder/output_device_backing_unittest.cc b/chromium/components/viz/service/display_embedder/output_device_backing_unittest.cc new file mode 100644 index 00000000000..916573333a6 --- /dev/null +++ b/chromium/components/viz/service/display_embedder/output_device_backing_unittest.cc @@ -0,0 +1,112 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display_embedder/output_device_backing.h" + +#include <limits> +#include <memory> + +#include "components/viz/common/resources/resource_sizes.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace viz { +namespace { + +size_t GetViewportSizeInBytes(const gfx::Size& viewport_size) { + size_t bytes = std::numeric_limits<size_t>::max(); + CHECK(ResourceSizes::MaybeSizeInBytes(viewport_size, RGBA_8888, &bytes)); + return bytes; +} + +// Test implementation with a set viewport size. +class TestBackingClient : public OutputDeviceBacking::Client { + public: + TestBackingClient(OutputDeviceBacking* backing, + const gfx::Size& viewport_size) + : backing_(backing), viewport_size_(viewport_size) { + backing_->RegisterClient(this); + backing_->ClientResized(); + backing_->GetSharedMemory(viewport_size_); + } + ~TestBackingClient() override { backing_->UnregisterClient(this); } + + const gfx::Size& viewport_size() const { return viewport_size_; } + bool release_canvas_called() const { return release_canvas_called_; } + + // OutputDeviceBacking::Client implementation. + const gfx::Size& GetViewportPixelSize() const override { + return viewport_size_; + } + void ReleaseCanvas() override { release_canvas_called_ = true; } + + private: + OutputDeviceBacking* const backing_; + gfx::Size viewport_size_; + bool release_canvas_called_ = false; + + DISALLOW_COPY_AND_ASSIGN(TestBackingClient); +}; + +} // namespace + +// Verify GetMaxViewportBytes() returns the size in bytes of the largest +// viewport. +TEST(OutputDeviceBackingTest, GetMaxViewportBytes) { + OutputDeviceBacking backing; + TestBackingClient client_a(&backing, gfx::Size(1024, 768)); + TestBackingClient client_b(&backing, gfx::Size(1920, 1080)); + + EXPECT_EQ(GetViewportSizeInBytes(client_b.viewport_size()), + backing.GetMaxViewportBytes()); +} + +// Verify that unregistering a client works as expected. +TEST(OutputDeviceBackingTest, UnregisterClient) { + OutputDeviceBacking backing; + auto client_a = + std::make_unique<TestBackingClient>(&backing, gfx::Size(1920, 1080)); + auto client_b = + std::make_unique<TestBackingClient>(&backing, gfx::Size(1080, 1920)); + auto client_c = + std::make_unique<TestBackingClient>(&backing, gfx::Size(1024, 768)); + + // Unregister one of the clients with the 1920x1080 viewport size. + client_a.reset(); + + // After removing |client_a| the max viewport didn't change so ReleaseCanvas() + // shouldn't be have been called. + EXPECT_FALSE(client_b->release_canvas_called()); + EXPECT_FALSE(client_c->release_canvas_called()); + + // Unregister the second client with 1920x1080 viewport. + client_b.reset(); + + // After removing |client_b| then max viewport did change so ReleaseCanvas() + // should have been called. + EXPECT_TRUE(client_c->release_canvas_called()); + + EXPECT_EQ(GetViewportSizeInBytes(client_c->viewport_size()), + backing.GetMaxViewportBytes()); +} + +// Verify that a client with a viewport that is too large doesn't allocate +// SharedMemory. +TEST(OutputDeviceBackingTest, ViewportSizeBiggerThanMax) { + OutputDeviceBacking backing; + + // The viewport is bigger than |kMaxBitmapSizeBytes| and OutputDeviceBacking + // won't try to create SharedMemory for it. + TestBackingClient client_a(&backing, gfx::Size(16385, 8193)); + EXPECT_EQ(nullptr, backing.GetSharedMemory(client_a.viewport_size())); + + // This should cause SharedMemory to get allocated. + TestBackingClient client_b(&backing, gfx::Size(1024, 768)); + EXPECT_NE(nullptr, backing.GetSharedMemory(client_b.viewport_size())); + + // Even though SharedMemory was allocated to fit |client_b|, it will be too + // small for |client_a| and GetSharedMemory() should still return null. + EXPECT_EQ(nullptr, backing.GetSharedMemory(client_a.viewport_size())); +} + +} // namespace viz diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc index a9745b91c9c..9d84f91109a 100644 --- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc +++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc @@ -23,10 +23,7 @@ namespace viz { class BitmapData : public base::RefCountedThreadSafe<BitmapData> { public: explicit BitmapData(size_t buffer_size) : buffer_size(buffer_size) {} - // For shm allocated and shared from a client out-of-process. std::unique_ptr<base::SharedMemory> memory; - // For memory allocated by the ServerSharedBitmapManager for in-process. - std::unique_ptr<uint8_t[]> pixels; size_t buffer_size; private: @@ -39,31 +36,23 @@ namespace { class ServerSharedBitmap : public SharedBitmap { public: - ServerSharedBitmap(uint8_t* pixels, - scoped_refptr<BitmapData> bitmap_data, - const SharedBitmapId& id, - ServerSharedBitmapManager* manager) - : SharedBitmap(pixels, id, 0 /* sequence_number */), - bitmap_data_(bitmap_data), - manager_(manager) {} + ServerSharedBitmap(scoped_refptr<BitmapData> bitmap_data, + const SharedBitmapId& id) + : SharedBitmap(static_cast<uint8_t*>(bitmap_data->memory->memory()), + id, + 0 /* sequence_number */), + bitmap_data_(std::move(bitmap_data)) {} ~ServerSharedBitmap() override { - if (manager_) - manager_->FreeSharedMemoryFromMap(id()); } // SharedBitmap implementation. base::UnguessableToken GetCrossProcessGUID() const override { - if (!bitmap_data_->memory) { - // Locally allocated for in-process use. - return {}; - } return bitmap_data_->memory->mapped_id(); } private: scoped_refptr<BitmapData> bitmap_data_; - ServerSharedBitmapManager* manager_; }; } // namespace @@ -81,26 +70,6 @@ ServerSharedBitmapManager* ServerSharedBitmapManager::current() { return g_shared_memory_manager.Pointer(); } -std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::AllocateSharedBitmap( - const gfx::Size& size, - ResourceFormat format) { - DCHECK(IsBitmapFormatSupported(format)); - base::AutoLock lock(lock_); - size_t bitmap_size; - if (!ResourceSizes::MaybeSizeInBytes(size, format, &bitmap_size)) - return nullptr; - - scoped_refptr<BitmapData> data(new BitmapData(bitmap_size)); - // Bitmaps allocated in server don't need to be shared to other processes, so - // allocate them with new instead. - data->pixels = std::unique_ptr<uint8_t[]>(new uint8_t[bitmap_size]); - - SharedBitmapId id = SharedBitmap::GenerateId(); - handle_map_[id] = data; - return std::make_unique<ServerSharedBitmap>(data->pixels.get(), data, id, - this); -} - std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId( const gfx::Size& size, ResourceFormat format, @@ -117,16 +86,11 @@ std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId( bitmap_size > data->buffer_size) return nullptr; - if (data->pixels) { - return std::make_unique<ServerSharedBitmap>(data->pixels.get(), data, id, - nullptr); - } if (!data->memory->memory()) { return nullptr; } - return std::make_unique<ServerSharedBitmap>( - static_cast<uint8_t*>(data->memory->memory()), data, id, nullptr); + return std::make_unique<ServerSharedBitmap>(data, id); } bool ServerSharedBitmapManager::ChildAllocatedSharedBitmap( diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h index af9be4360b3..57810735850 100644 --- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h +++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h @@ -36,9 +36,6 @@ class VIZ_SERVICE_EXPORT ServerSharedBitmapManager static ServerSharedBitmapManager* current(); // SharedBitmapManager implementation. - std::unique_ptr<SharedBitmap> AllocateSharedBitmap( - const gfx::Size& size, - ResourceFormat format) override; std::unique_ptr<SharedBitmap> GetSharedBitmapFromId( const gfx::Size& size, ResourceFormat format, diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc index cce61d24a22..b5923739380 100644 --- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc +++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc @@ -5,7 +5,6 @@ #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/common/resources/resource_sizes.h" -#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h" #include "mojo/public/cpp/system/platform_handle.h" #include "testing/gtest/include/gtest/gtest.h" @@ -36,12 +35,11 @@ TEST_F(ServerSharedBitmapManagerTest, TestCreate) { memset(bitmap->memory(), 0xff, size_in_bytes); SharedBitmapId id = SharedBitmap::GenerateId(); - SharedBitmapAllocationNotifierImpl notifier(manager()); base::SharedMemoryHandle handle = bitmap->handle().Duplicate(); mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle( handle, size_in_bytes, mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); - notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id); + manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id); std::unique_ptr<SharedBitmap> large_bitmap; large_bitmap = @@ -81,7 +79,7 @@ TEST_F(ServerSharedBitmapManagerTest, TestCreate) { EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), 0); - notifier.DidDeleteSharedBitmap(id); + manager()->ChildDeletedSharedBitmap(id); memset(bitmap->memory(), 0, size_in_bytes); @@ -91,42 +89,6 @@ TEST_F(ServerSharedBitmapManagerTest, TestCreate) { shared_bitmap.reset(); } -TEST_F(ServerSharedBitmapManagerTest, ServiceDestroyed) { - gfx::Size bitmap_size(1, 1); - size_t size_in_bytes; - EXPECT_TRUE( - ResourceSizes::MaybeSizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes)); - std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory()); - bitmap->CreateAndMapAnonymous(size_in_bytes); - memset(bitmap->memory(), 0xff, size_in_bytes); - SharedBitmapId id = SharedBitmap::GenerateId(); - - // This outlives the SharedBitmapAllocationNotifier. - std::unique_ptr<SharedBitmap> shared_bitmap; - - { - SharedBitmapAllocationNotifierImpl notifier(manager()); - base::SharedMemoryHandle handle = bitmap->handle().Duplicate(); - mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle( - handle, size_in_bytes, - mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); - notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id); - - shared_bitmap = - manager()->GetSharedBitmapFromId(bitmap_size, RGBA_8888, id); - ASSERT_TRUE(shared_bitmap.get() != nullptr); - - EXPECT_EQ(1u, manager()->AllocatedBitmapCount()); - } - EXPECT_EQ(0u, manager()->AllocatedBitmapCount()); - - std::unique_ptr<SharedBitmap> shared_bitmap2; - shared_bitmap2 = manager()->GetSharedBitmapFromId(bitmap_size, RGBA_8888, id); - EXPECT_FALSE(!!shared_bitmap2); - EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), - 0); -} - TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) { gfx::Size bitmap_size(1, 1); size_t size_in_bytes; @@ -137,13 +99,11 @@ TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) { memset(bitmap->memory(), 0xff, size_in_bytes); SharedBitmapId id = SharedBitmap::GenerateId(); - SharedBitmapAllocationNotifierImpl notifier(manager()); - base::SharedMemoryHandle handle = bitmap->handle().Duplicate(); mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle( handle, size_in_bytes, mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); - notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id); + manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id); std::unique_ptr<base::SharedMemory> bitmap2(new base::SharedMemory()); bitmap2->CreateAndMapAnonymous(size_in_bytes); @@ -153,14 +113,14 @@ TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) { buffer_handle = mojo::WrapSharedMemoryHandle( handle2, size_in_bytes, mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); - notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id); + manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id); std::unique_ptr<SharedBitmap> shared_bitmap; shared_bitmap = manager()->GetSharedBitmapFromId(bitmap_size, RGBA_8888, id); ASSERT_TRUE(shared_bitmap.get() != nullptr); EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes), 0); - notifier.DidDeleteSharedBitmap(id); + manager()->ChildDeletedSharedBitmap(id); } TEST_F(ServerSharedBitmapManagerTest, SharedMemoryHandle) { @@ -174,21 +134,19 @@ TEST_F(ServerSharedBitmapManagerTest, SharedMemoryHandle) { base::UnguessableToken shared_memory_guid = bitmap->handle().GetGUID(); EXPECT_FALSE(shared_memory_guid.is_empty()); - SharedBitmapAllocationNotifierImpl notifier(manager()); - SharedBitmapId id = SharedBitmap::GenerateId(); base::SharedMemoryHandle handle = bitmap->handle().Duplicate(); mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle( handle, size_in_bytes, mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); - notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id); + manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id); std::unique_ptr<SharedBitmap> shared_bitmap; shared_bitmap = manager()->GetSharedBitmapFromId(gfx::Size(1, 1), RGBA_8888, id); EXPECT_EQ(shared_bitmap->GetCrossProcessGUID(), shared_memory_guid); - notifier.DidDeleteSharedBitmap(id); + manager()->ChildDeletedSharedBitmap(id); } } // namespace diff --git a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc deleted file mode 100644 index fa5468d37a3..00000000000 --- a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h" - -#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" -#include "mojo/public/cpp/system/platform_handle.h" - -namespace viz { - -SharedBitmapAllocationNotifierImpl::SharedBitmapAllocationNotifierImpl( - ServerSharedBitmapManager* manager) - : manager_(manager), binding_(this) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -SharedBitmapAllocationNotifierImpl::~SharedBitmapAllocationNotifierImpl() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - ChildDied(); -} - -void SharedBitmapAllocationNotifierImpl::Bind( - mojom::SharedBitmapAllocationNotifierRequest request) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (binding_.is_bound()) { - DLOG(ERROR) << "Only one SharedBitmapAllocationNotifierRequest is " - << "expected from the renderer."; - return; - } - binding_.Bind(std::move(request)); -} - -void SharedBitmapAllocationNotifierImpl::DidAllocateSharedBitmap( - mojo::ScopedSharedBufferHandle buffer, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - this->ChildAllocatedSharedBitmap(std::move(buffer), id); - last_sequence_number_++; - for (SharedBitmapAllocationObserver& observer : observers_) - observer.OnSharedBitmapAllocatedByChild(last_sequence_number_); -} - -void SharedBitmapAllocationNotifierImpl::DidDeleteSharedBitmap( - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - manager_->ChildDeletedSharedBitmap(id); - owned_bitmaps_.erase(id); -} - -void SharedBitmapAllocationNotifierImpl::ChildAllocatedSharedBitmap( - mojo::ScopedSharedBufferHandle buffer, - const SharedBitmapId& id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (manager_->ChildAllocatedSharedBitmap(std::move(buffer), id)) - owned_bitmaps_.insert(id); -} - -void SharedBitmapAllocationNotifierImpl::ChildDied() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - for (const auto& id : owned_bitmaps_) - manager_->ChildDeletedSharedBitmap(id); - owned_bitmaps_.clear(); - binding_.Close(); -} - -void SharedBitmapAllocationNotifierImpl::AddObserver( - SharedBitmapAllocationObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.AddObserver(observer); -} - -void SharedBitmapAllocationNotifierImpl::RemoveObserver( - SharedBitmapAllocationObserver* observer) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - observers_.RemoveObserver(observer); -} - -} // namespace viz diff --git a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h deleted file mode 100644 index 0b4e32ddaf8..00000000000 --- a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SHARED_BITMAP_ALLOCATION_NOTIFIER_IMPL_H_ -#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SHARED_BITMAP_ALLOCATION_NOTIFIER_IMPL_H_ - -#include <unordered_set> - -#include "base/observer_list.h" -#include "base/threading/thread_checker.h" -#include "components/viz/common/quads/shared_bitmap.h" -#include "components/viz/service/viz_service_export.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "services/viz/public/interfaces/compositing/shared_bitmap_allocation_notifier.mojom.h" - -namespace viz { -class ServerSharedBitmapManager; - -class SharedBitmapAllocationObserver { - public: - virtual void OnSharedBitmapAllocatedByChild(uint32_t sequence_number) = 0; -}; - -class VIZ_SERVICE_EXPORT SharedBitmapAllocationNotifierImpl - : public mojom::SharedBitmapAllocationNotifier { - public: - explicit SharedBitmapAllocationNotifierImpl( - ServerSharedBitmapManager* manager); - - ~SharedBitmapAllocationNotifierImpl() override; - - void AddObserver(SharedBitmapAllocationObserver* observer); - void RemoveObserver(SharedBitmapAllocationObserver* observer); - - void Bind(mojom::SharedBitmapAllocationNotifierRequest request); - - // mojom::SharedBitmapAllocationNotifier overrides: - void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer, - const SharedBitmapId& id) override; - void DidDeleteSharedBitmap(const SharedBitmapId& id) override; - - void ChildAllocatedSharedBitmap(mojo::ScopedSharedBufferHandle buffer, - const SharedBitmapId& id); - - void ChildDied(); - - uint32_t last_sequence_number() const { return last_sequence_number_; } - - private: - THREAD_CHECKER(thread_checker_); - ServerSharedBitmapManager* const manager_; - mojo::Binding<mojom::SharedBitmapAllocationNotifier> binding_; - std::unordered_set<SharedBitmapId, SharedBitmapIdHash> owned_bitmaps_; - base::ObserverList<SharedBitmapAllocationObserver> observers_; - uint32_t last_sequence_number_ = 0; - - DISALLOW_COPY_AND_ASSIGN(SharedBitmapAllocationNotifierImpl); -}; - -} // namespace viz - -#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SHARED_BITMAP_ALLOCATION_NOTIFIER_IMPL_H_ 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 new file mode 100644 index 00000000000..ac7b616b261 --- /dev/null +++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc @@ -0,0 +1,516 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display_embedder/skia_output_surface_impl.h" + +#include "base/callback_helpers.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/viz/common/frame_sinks/begin_frame_source.h" +#include "components/viz/common/resources/resource_format_utils.h" +#include "components/viz/common/resources/resource_metadata.h" +#include "components/viz/service/display/output_surface_client.h" +#include "components/viz/service/display/output_surface_frame.h" +#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h" +#include "components/viz/service/display_embedder/viz_process_context_provider.h" +#include "components/viz/service/gl/gpu_service_impl.h" +#include "gpu/command_buffer/common/swap_buffers_complete_params.h" +#include "gpu/command_buffer/service/scheduler.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_gl_api_implementation.h" + +namespace viz { + +namespace { + +template <typename... Args> +void PostAsyncTask( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + const base::RepeatingCallback<void(Args...)>& callback, + Args... args) { + task_runner->PostTask(FROM_HERE, base::BindOnce(callback, args...)); +} + +template <typename... Args> +base::RepeatingCallback<void(Args...)> CreateSafeCallback( + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + const base::RepeatingCallback<void(Args...)>& callback) { + return base::BindRepeating(&PostAsyncTask<Args...>, task_runner, callback); +} + +} // namespace + +// A helper class for fullfilling promise image on the GPU thread. +template <class FullfillContextType> +class SkiaOutputSurfaceImpl::PromiseTextureHelper { + public: + using HelperType = PromiseTextureHelper<FullfillContextType>; + + PromiseTextureHelper(base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu, + FullfillContextType context) + : impl_on_gpu_(impl_on_gpu), context_(std::move(context)) {} + ~PromiseTextureHelper() = default; + + static sk_sp<SkImage> MakePromiseSkImage( + SkiaOutputSurfaceImpl* impl, + SkDeferredDisplayListRecorder* recorder, + const GrBackendFormat& backend_format, + gfx::Size size, + GrMipMapped mip_mapped, + GrSurfaceOrigin origin, + SkColorType color_type, + SkAlphaType alpha_type, + sk_sp<SkColorSpace> color_space, + FullfillContextType context) { + DCHECK_CALLED_ON_VALID_THREAD(impl->thread_checker_); + auto helper = std::make_unique<HelperType>(impl->impl_on_gpu_->weak_ptr(), + std::move(context)); + auto image = recorder->makePromiseTexture( + backend_format, size.width(), size.height(), mip_mapped, origin, + color_type, alpha_type, color_space, HelperType::Fullfill, + HelperType::Release, HelperType::Done, helper.get()); + if (image) { + helper->Init(impl); + helper.release(); + } + return image; + } + + private: + void Init(SkiaOutputSurfaceImpl* impl); + + static void Fullfill(void* texture_context, + GrBackendTexture* backend_texture) { + DCHECK(texture_context); + auto* helper = static_cast<HelperType*>(texture_context); + // The fullfill is always called by SkiaOutputSurfaceImplOnGpu::SwapBuffers + // or SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass, so impl_on_gpu_ + // should be always valid. + DCHECK(helper->impl_on_gpu_); + helper->impl_on_gpu_->FullfillPromiseTexture(helper->context_, + backend_texture); + } + + static void Release(void* texture_context) { DCHECK(texture_context); } + + static void Done(void* texture_context) { + DCHECK(texture_context); + std::unique_ptr<HelperType> helper( + static_cast<HelperType*>(texture_context)); + } + + base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_; + + // The data for calling the fullfill methods in SkiaOutputSurfaceImpl. + FullfillContextType context_; + + DISALLOW_COPY_AND_ASSIGN(PromiseTextureHelper); +}; + +template <class T> +void SkiaOutputSurfaceImpl::PromiseTextureHelper<T>::Init( + SkiaOutputSurfaceImpl* impl) {} + +// For YUVResourceMetadata, we need to record the |context_| pointer in +// |impl->yuv_resource_metadatas_|, because we have to create SkImage from YUV +// textures before drawing the ddl to a SKSurface. +// TODO(penghuang): Remove this hack when Skia supports drawing YUV textures +// directly. +template <> +void SkiaOutputSurfaceImpl::PromiseTextureHelper<YUVResourceMetadata>::Init( + SkiaOutputSurfaceImpl* impl) { + impl->yuv_resource_metadatas_.push_back(&context_); +} + +SkiaOutputSurfaceImpl::SkiaOutputSurfaceImpl( + GpuServiceImpl* gpu_service, + gpu::SurfaceHandle surface_handle, + scoped_refptr<VizProcessContextProvider> context_provider, + SyntheticBeginFrameSource* synthetic_begin_frame_source) + : SkiaOutputSurface(context_provider), + gpu_service_(gpu_service), + surface_handle_(surface_handle), + synthetic_begin_frame_source_(synthetic_begin_frame_source), + weak_ptr_factory_(this) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +SkiaOutputSurfaceImpl::~SkiaOutputSurfaceImpl() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + recorder_ = nullptr; + // Use GPU scheduler to release impl_on_gpu_ on the GPU thread, so all + // scheduled tasks for the impl_on_gpu_ will be executed, before releasing + // it. The GPU thread is the main thread of the viz process. It outlives the + // compositor thread. We don't need worry about it for now. + auto sequence_id = gpu_service_->skia_output_surface_sequence_id(); + auto callback = + base::BindOnce([](std::unique_ptr<SkiaOutputSurfaceImplOnGpu>) {}, + std::move(impl_on_gpu_)); + gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task( + sequence_id, std::move(callback), std::vector<gpu::SyncToken>())); +} + +void SkiaOutputSurfaceImpl::BindToClient(OutputSurfaceClient* client) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(client); + DCHECK(!client_); + + client_ = client; + weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); + client_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get(); + + base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + auto sequence_id = gpu_service_->skia_output_surface_sequence_id(); + auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread, + base::Unretained(this), &event); + gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task( + sequence_id, std::move(callback), std::vector<gpu::SyncToken>())); + event.Wait(); +} + +void SkiaOutputSurfaceImpl::EnsureBackbuffer() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); +} + +void SkiaOutputSurfaceImpl::DiscardBackbuffer() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); +} + +void SkiaOutputSurfaceImpl::BindFramebuffer() { + // TODO(penghuang): remove this method when GLRenderer is removed. +} + +void SkiaOutputSurfaceImpl::SetDrawRectangle(const gfx::Rect& draw_rectangle) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); +} + +void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size, + float device_scale_factor, + const gfx::ColorSpace& color_space, + bool has_alpha, + bool use_stencil) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + recorder_ = nullptr; + SkSurfaceCharacterization* characterization = nullptr; + std::unique_ptr<base::WaitableEvent> event; + if (characterization_.isValid()) { + characterization_ = + characterization_.createResized(size.width(), size.height()); + } else { + characterization = &characterization_; + // TODO(penghuang): avoid blocking compositor thread. + // We don't have a valid surface characterization, so we have to wait + // until reshape is finished on Gpu thread. + event = std::make_unique<base::WaitableEvent>( + base::WaitableEvent::ResetPolicy::MANUAL, + base::WaitableEvent::InitialState::NOT_SIGNALED); + } + + auto sequence_id = gpu_service_->skia_output_surface_sequence_id(); + // impl_on_gpu_ is released on the GPU thread by a posted task from + // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained. + auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::Reshape, + base::Unretained(impl_on_gpu_.get()), size, + device_scale_factor, color_space, has_alpha, + use_stencil, characterization, event.get()); + gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task( + sequence_id, std::move(callback), std::vector<gpu::SyncToken>())); + + if (event) + event->Wait(); + RecreateRecorder(); +} + +void SkiaOutputSurfaceImpl::SwapBuffers(OutputSurfaceFrame frame) { + NOTREACHED(); +} + +uint32_t SkiaOutputSurfaceImpl::GetFramebufferCopyTextureFormat() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + return GL_RGB; +} + +OverlayCandidateValidator* SkiaOutputSurfaceImpl::GetOverlayCandidateValidator() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return nullptr; +} + +bool SkiaOutputSurfaceImpl::IsDisplayedAsOverlayPlane() const { + return false; +} + +unsigned SkiaOutputSurfaceImpl::GetOverlayTextureId() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return 0; +} + +gfx::BufferFormat SkiaOutputSurfaceImpl::GetOverlayBufferFormat() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + return gfx::BufferFormat::RGBX_8888; +} + +bool SkiaOutputSurfaceImpl::HasExternalStencilTest() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + return false; +} + +void SkiaOutputSurfaceImpl::ApplyExternalStencil() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +#if BUILDFLAG(ENABLE_VULKAN) +gpu::VulkanSurface* SkiaOutputSurfaceImpl::GetVulkanSurface() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + return nullptr; +} +#endif + +unsigned SkiaOutputSurfaceImpl::UpdateGpuFence() { + return 0; +} + +SkCanvas* SkiaOutputSurfaceImpl::GetSkCanvasForCurrentFrame() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(recorder_); + DCHECK_EQ(current_render_pass_id_, 0u); + + return recorder_->getCanvas(); +} + +sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImage( + ResourceMetadata metadata) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(recorder_); + + // Convert internal format from GLES2 to platform GL. + const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo(); + metadata.backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, + *metadata.backend_format.getGLFormat()), + *metadata.backend_format.getGLTarget()); + + DCHECK(!metadata.mailbox.IsZero()); + resource_sync_tokens_.push_back(metadata.sync_token); + + return PromiseTextureHelper<ResourceMetadata>::MakePromiseSkImage( + this, recorder_.get(), metadata.backend_format, metadata.size, + metadata.mip_mapped, metadata.origin, metadata.color_type, + metadata.alpha_type, metadata.color_space, std::move(metadata)); +} + +sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromYUV( + std::vector<ResourceMetadata> metadatas, + SkYUVColorSpace yuv_color_space) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(recorder_); + + DCHECK(metadatas.size() == 2 || metadatas.size() == 3); + + // TODO(penghuang): Create SkImage from YUV textures directly when it is + // supported by Skia. + YUVResourceMetadata yuv_metadata(std::move(metadatas), yuv_color_space); + + // Convert internal format from GLES2 to platform GL. + const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo(); + auto backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, GL_BGRA8_EXT), GL_TEXTURE_2D); + + return PromiseTextureHelper<YUVResourceMetadata>::MakePromiseSkImage( + this, recorder_.get(), backend_format, yuv_metadata.size(), + GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, + kPremul_SkAlphaType, nullptr /* color_space */, std::move(yuv_metadata)); +} + +gpu::SyncToken SkiaOutputSurfaceImpl::SkiaSwapBuffers( + OutputSurfaceFrame frame) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(recorder_); + + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE, + impl_on_gpu_->command_buffer_id(), + ++sync_fence_release_); + sync_token.SetVerifyFlush(); + + auto ddl = recorder_->detach(); + DCHECK(ddl); + RecreateRecorder(); + auto sequence_id = gpu_service_->skia_output_surface_sequence_id(); + // impl_on_gpu_ is released on the GPU thread by a posted task from + // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained. + auto callback = base::BindOnce( + &SkiaOutputSurfaceImplOnGpu::SwapBuffers, + base::Unretained(impl_on_gpu_.get()), std::move(frame), std::move(ddl), + std::move(yuv_resource_metadatas_), sync_fence_release_); + gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task( + sequence_id, std::move(callback), std::move(resource_sync_tokens_))); + return sync_token; +} + +SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass( + const RenderPassId& id, + const gfx::Size& surface_size, + ResourceFormat format, + bool mipmap) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(gpu_service_->gr_context()); + DCHECK(!current_render_pass_id_); + DCHECK(!offscreen_surface_recorder_); + DCHECK(resource_sync_tokens_.empty()); + + current_render_pass_id_ = id; + + auto gr_context_thread_safe = gpu_service_->gr_context()->threadSafeProxy(); + constexpr uint32_t flags = 0; + // LegacyFontHost will get LCD text and skia figures out what type to use. + SkSurfaceProps surface_props(flags, SkSurfaceProps::kLegacyFontHost_InitType); + int msaa_sample_count = 0; + SkColorType color_type = + ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format); + SkImageInfo image_info = + SkImageInfo::Make(surface_size.width(), surface_size.height(), color_type, + kPremul_SkAlphaType, nullptr /* color_space */); + + // TODO(penghuang): Figure out how to choose the right size. + constexpr size_t kCacheMaxResourceBytes = 90 * 1024 * 1024; + const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo(); + unsigned int texture_storage_format = TextureStorageFormat(format); + auto backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, texture_storage_format), + GL_TEXTURE_2D); + auto characterization = gr_context_thread_safe->createCharacterization( + kCacheMaxResourceBytes, image_info, backend_format, msaa_sample_count, + kTopLeft_GrSurfaceOrigin, surface_props, mipmap); + DCHECK(characterization.isValid()); + offscreen_surface_recorder_ = + std::make_unique<SkDeferredDisplayListRecorder>(characterization); + return offscreen_surface_recorder_->getCanvas(); +} + +gpu::SyncToken SkiaOutputSurfaceImpl::FinishPaintRenderPass() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(gpu_service_->gr_context()); + DCHECK(current_render_pass_id_); + DCHECK(offscreen_surface_recorder_); + + gpu::SyncToken sync_token(gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE, + impl_on_gpu_->command_buffer_id(), + ++sync_fence_release_); + sync_token.SetVerifyFlush(); + + auto ddl = offscreen_surface_recorder_->detach(); + offscreen_surface_recorder_ = nullptr; + DCHECK(ddl); + + auto sequence_id = gpu_service_->skia_output_surface_sequence_id(); + // impl_on_gpu_ is released on the GPU thread by a posted task from + // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained. + auto callback = base::BindOnce( + &SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass, + base::Unretained(impl_on_gpu_.get()), current_render_pass_id_, + std::move(ddl), std::move(yuv_resource_metadatas_), sync_fence_release_); + gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task( + sequence_id, std::move(callback), std::move(resource_sync_tokens_))); + current_render_pass_id_ = 0; + return sync_token; +} + +sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromRenderPass( + const RenderPassId& id, + const gfx::Size& size, + ResourceFormat format, + bool mipmap) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(recorder_); + + // Convert internal format from GLES2 to platform GL. + const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo(); + unsigned int texture_storage_format = TextureStorageFormat(format); + auto backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, texture_storage_format), + GL_TEXTURE_2D); + SkColorType color_type = + ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format); + return PromiseTextureHelper<RenderPassId>::MakePromiseSkImage( + this, recorder_.get(), backend_format, size, + mipmap ? GrMipMapped::kYes : GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin, + color_type, kPremul_SkAlphaType, nullptr /* color_space */, id); +} + +void SkiaOutputSurfaceImpl::RemoveRenderPassResource( + std::vector<RenderPassId> ids) { + DCHECK(!ids.empty()); + auto sequence_id = gpu_service_->skia_output_surface_sequence_id(); + // impl_on_gpu_ is released on the GPU thread by a posted task from + // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained. + auto callback = + base::BindOnce(&SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource, + base::Unretained(impl_on_gpu_.get()), std::move(ids)); + gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task( + sequence_id, std::move(callback), std::vector<gpu::SyncToken>())); +} + +void SkiaOutputSurfaceImpl::InitializeOnGpuThread(base::WaitableEvent* event) { + base::ScopedClosureRunner scoped_runner( + base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event))); + auto did_swap_buffer_complete_callback = base::BindRepeating( + &SkiaOutputSurfaceImpl::DidSwapBuffersComplete, weak_ptr_); + auto buffer_presented_callback = + base::BindRepeating(&SkiaOutputSurfaceImpl::BufferPresented, weak_ptr_); + impl_on_gpu_ = std::make_unique<SkiaOutputSurfaceImplOnGpu>( + gpu_service_, surface_handle_, + CreateSafeCallback(client_thread_task_runner_, + did_swap_buffer_complete_callback), + CreateSafeCallback(client_thread_task_runner_, + buffer_presented_callback)); + capabilities_ = impl_on_gpu_->capabilities(); +} + +void SkiaOutputSurfaceImpl::RecreateRecorder() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(characterization_.isValid()); + recorder_ = + std::make_unique<SkDeferredDisplayListRecorder>(characterization_); + // TODO(penghuang): remove the unnecessary getCanvas() call, when the + // recorder crash is fixed in skia. + recorder_->getCanvas(); +} + +void SkiaOutputSurfaceImpl::DidSwapBuffersComplete( + gpu::SwapBuffersCompleteParams params) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(client_); + + if (!params.texture_in_use_responses.empty()) + client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses); + if (!params.ca_layer_params.is_empty) + client_->DidReceiveCALayerParams(params.ca_layer_params); + client_->DidReceiveSwapBuffersAck(); +} + +void SkiaOutputSurfaceImpl::BufferPresented( + const gfx::PresentationFeedback& feedback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(client_); + client_->DidReceivePresentationFeedback(feedback); + if (synthetic_begin_frame_source_ && + feedback.flags & gfx::PresentationFeedback::kVSync) { + // TODO(brianderson): We should not be receiving 0 intervals. + synthetic_begin_frame_source_->OnUpdateVSyncParameters( + feedback.timestamp, feedback.interval.is_zero() + ? BeginFrameArgs::DefaultInterval() + : feedback.interval); + } +} + +} // namespace viz 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 new file mode 100644 index 00000000000..3309aa30433 --- /dev/null +++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h @@ -0,0 +1,141 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_ + +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "components/viz/service/display/skia_output_surface.h" +#include "gpu/command_buffer/common/sync_token.h" +#include "gpu/ipc/common/surface_handle.h" +#include "gpu/ipc/in_process_command_buffer.h" +#include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h" +#include "third_party/skia/include/core/SkSurfaceCharacterization.h" + +namespace base { +class WaitableEvent; +} + +namespace viz { + +class GpuServiceImpl; +class VizProcessContextProvider; +class SkiaOutputSurfaceImplOnGpu; +class SyntheticBeginFrameSource; + +class YUVResourceMetadata; + +// The SkiaOutputSurface implementation. It is the output surface for +// SkiaRenderer. It lives on the compositor thread, but it will post tasks +// to the GPU thread for initializing. Currently, SkiaOutputSurfaceImpl +// create a SkiaOutputSurfaceImplOnGpu on the GPU thread. It will be used +// for creating a SkSurface from the default framebuffer and providing the +// SkSurfaceCharacterization for the SkSurface. And then SkiaOutputSurfaceImpl +// will create SkDeferredDisplayListRecorder and SkCanvas for SkiaRenderer to +// render into. In SwapBuffers, it detaches a SkDeferredDisplayList from the +// recorder and plays it back on the framebuffer SkSurface on the GPU thread +// through SkiaOutputSurfaceImpleOnGpu. +class SkiaOutputSurfaceImpl : public SkiaOutputSurface { + public: + SkiaOutputSurfaceImpl( + GpuServiceImpl* gpu_service, + gpu::SurfaceHandle surface_handle, + scoped_refptr<VizProcessContextProvider> context_provider, + SyntheticBeginFrameSource* synthetic_begin_frame_source); + ~SkiaOutputSurfaceImpl() override; + + // OutputSurface implementation: + void BindToClient(OutputSurfaceClient* client) override; + void EnsureBackbuffer() override; + void DiscardBackbuffer() override; + void BindFramebuffer() override; + void SetDrawRectangle(const gfx::Rect& draw_rectangle) override; + void Reshape(const gfx::Size& size, + float device_scale_factor, + const gfx::ColorSpace& color_space, + bool has_alpha, + bool use_stencil) override; + void SwapBuffers(OutputSurfaceFrame frame) override; + uint32_t GetFramebufferCopyTextureFormat() override; + OverlayCandidateValidator* GetOverlayCandidateValidator() const override; + bool IsDisplayedAsOverlayPlane() const override; + unsigned GetOverlayTextureId() const override; + gfx::BufferFormat GetOverlayBufferFormat() const override; + bool HasExternalStencilTest() const override; + void ApplyExternalStencil() override; +#if BUILDFLAG(ENABLE_VULKAN) + gpu::VulkanSurface* GetVulkanSurface() override; +#endif + unsigned UpdateGpuFence() override; + + // SkiaOutputSurface implementation: + SkCanvas* GetSkCanvasForCurrentFrame() override; + sk_sp<SkImage> MakePromiseSkImage(ResourceMetadata metadata) override; + sk_sp<SkImage> MakePromiseSkImageFromYUV( + std::vector<ResourceMetadata> metadatas, + SkYUVColorSpace yuv_color_space) override; + gpu::SyncToken SkiaSwapBuffers(OutputSurfaceFrame frame) override; + SkCanvas* BeginPaintRenderPass(const RenderPassId& id, + const gfx::Size& surface_size, + ResourceFormat format, + bool mipmap) override; + gpu::SyncToken FinishPaintRenderPass() override; + sk_sp<SkImage> MakePromiseSkImageFromRenderPass(const RenderPassId& id, + const gfx::Size& size, + ResourceFormat format, + bool mipmap) override; + void RemoveRenderPassResource(std::vector<RenderPassId> ids) override; + + private: + template <class T> + class PromiseTextureHelper; + void InitializeOnGpuThread(base::WaitableEvent* event); + void RecreateRecorder(); + void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params); + void BufferPresented(const gfx::PresentationFeedback& feedback); + + uint64_t sync_fence_release_ = 0; + GpuServiceImpl* const gpu_service_; + const gpu::SurfaceHandle surface_handle_; + SyntheticBeginFrameSource* const synthetic_begin_frame_source_; + OutputSurfaceClient* client_ = nullptr; + + SkSurfaceCharacterization characterization_; + std::unique_ptr<SkDeferredDisplayListRecorder> recorder_; + + // The current render pass id set by BeginPaintRenderPass. + RenderPassId current_render_pass_id_ = 0; + + // The SkDDL recorder created by BeginPaintRenderPass, and + // FinishPaintRenderPass will turn it into a SkDDL and play the SkDDL back on + // the GPU thread. + std::unique_ptr<SkDeferredDisplayListRecorder> offscreen_surface_recorder_; + + // Sync tokens for resources which are used for the current frame. + std::vector<gpu::SyncToken> resource_sync_tokens_; + + // YUV resource metadatas for the current frame or the current render pass. + // They should be preprocessed for playing recorded frame into a surface. + // TODO(penghuang): Remove it when Skia supports drawing YUV textures + // directly. + std::vector<YUVResourceMetadata*> yuv_resource_metadatas_; + + // The task runner for running task on the client (compositor) thread. + scoped_refptr<base::SingleThreadTaskRunner> client_thread_task_runner_; + + // |impl_on_gpu| is created and destroyed on the GPU thread. + std::unique_ptr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_; + + THREAD_CHECKER(thread_checker_); + + base::WeakPtr<SkiaOutputSurfaceImpl> weak_ptr_; + base::WeakPtrFactory<SkiaOutputSurfaceImpl> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurfaceImpl); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_ 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 new file mode 100644 index 00000000000..eccdf7f1a9b --- /dev/null +++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc @@ -0,0 +1,398 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h" + +#include "base/atomic_sequence_num.h" +#include "base/callback_helpers.h" +#include "base/synchronization/waitable_event.h" +#include "components/viz/service/display/output_surface_frame.h" +#include "components/viz/service/gl/gpu_service_impl.h" +#include "gpu/command_buffer/common/swap_buffers_complete_params.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/scheduler.h" +#include "gpu/command_buffer/service/sync_point_manager.h" +#include "gpu/command_buffer/service/texture_base.h" +#include "gpu/command_buffer/service/texture_manager.h" +#include "gpu/ipc/service/image_transport_surface.h" +#include "third_party/skia/include/private/SkDeferredDisplayList.h" +#include "ui/gl/gl_bindings.h" +#include "ui/gl/gl_context.h" +#include "ui/gl/gl_surface.h" +#include "ui/gl/gl_version_info.h" + +namespace viz { +namespace { + +base::AtomicSequenceNumber g_next_command_buffer_id; + +} // namespace + +YUVResourceMetadata::YUVResourceMetadata( + std::vector<ResourceMetadata> metadatas, + SkYUVColorSpace yuv_color_space) + : metadatas_(std::move(metadatas)), yuv_color_space_(yuv_color_space) { + DCHECK(metadatas_.size() == 2 || metadatas_.size() == 3); +} + +YUVResourceMetadata::YUVResourceMetadata(YUVResourceMetadata&& other) = default; + +YUVResourceMetadata::~YUVResourceMetadata() = default; + +YUVResourceMetadata& YUVResourceMetadata::operator=( + YUVResourceMetadata&& other) = default; + +SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu( + GpuServiceImpl* gpu_service, + gpu::SurfaceHandle surface_handle, + const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback, + const BufferPresentedCallback& buffer_presented_callback) + : command_buffer_id_(gpu::CommandBufferId::FromUnsafeValue( + g_next_command_buffer_id.GetNext() + 1)), + gpu_service_(gpu_service), + surface_handle_(surface_handle), + did_swap_buffer_complete_callback_(did_swap_buffer_complete_callback), + buffer_presented_callback_(buffer_presented_callback), + weak_ptr_factory_(this) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + weak_ptr_ = weak_ptr_factory_.GetWeakPtr(); + + sync_point_client_state_ = + gpu_service_->sync_point_manager()->CreateSyncPointClientState( + gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE, command_buffer_id_, + gpu_service_->skia_output_surface_sequence_id()); + + surface_ = gpu::ImageTransportSurface::CreateNativeSurface( + weak_ptr_factory_.GetWeakPtr(), surface_handle_, gl::GLSurfaceFormat()); + DCHECK(surface_); + + if (!gpu_service_->CreateGrContextIfNecessary(surface_.get())) { + LOG(FATAL) << "Failed to create GrContext"; + // TODO(penghuang): handle the failure. + } + + DCHECK(gpu_service_->context_for_skia()); + DCHECK(gpu_service_->gr_context()); + + if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) { + LOG(FATAL) << "Failed to make current."; + // TODO(penghuang): Handle the failure. + } + + capabilities_.flipped_output_surface = surface_->FlipsVertically(); + + // Get stencil bits from the default frame buffer. + auto* current_gl = gpu_service_->context_for_skia()->GetCurrentGL(); + const auto* version = current_gl->Version; + auto* api = current_gl->Api; + GLint stencil_bits = 0; + if (version->is_desktop_core_profile) { + api->glGetFramebufferAttachmentParameterivEXTFn( + GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, + &stencil_bits); + } else { + api->glGetIntegervFn(GL_STENCIL_BITS, &stencil_bits); + } + + capabilities_.supports_stencil = stencil_bits > 0; +} + +SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); +} + +void SkiaOutputSurfaceImplOnGpu::Reshape( + const gfx::Size& size, + float device_scale_factor, + const gfx::ColorSpace& color_space, + bool has_alpha, + bool use_stencil, + SkSurfaceCharacterization* characterization, + base::WaitableEvent* event) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + std::unique_ptr<base::ScopedClosureRunner> scoped_runner; + if (event) { + scoped_runner = std::make_unique<base::ScopedClosureRunner>( + base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event))); + } + + if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) { + LOG(FATAL) << "Failed to make current."; + // TODO(penghuang): Handle the failure. + } + gl::GLSurface::ColorSpace surface_color_space = + color_space == gfx::ColorSpace::CreateSCRGBLinear() + ? gl::GLSurface::ColorSpace::SCRGB_LINEAR + : gl::GLSurface::ColorSpace::UNSPECIFIED; + if (!surface_->Resize(size, device_scale_factor, surface_color_space, + has_alpha)) { + LOG(FATAL) << "Failed to resize."; + // TODO(penghuang): Handle the failure. + } + DCHECK(gpu_service_->context_for_skia()->IsCurrent(surface_.get())); + DCHECK(gpu_service_->gr_context()); + + SkSurfaceProps surface_props = + SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType); + + GrGLFramebufferInfo framebuffer_info; + framebuffer_info.fFBOID = 0; + const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo(); + framebuffer_info.fFormat = version_info->is_es ? GL_BGRA8_EXT : GL_RGBA8; + + GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8, + framebuffer_info); + + sk_surface_ = SkSurface::MakeFromBackendRenderTarget( + gpu_service_->gr_context(), render_target, kBottomLeft_GrSurfaceOrigin, + kBGRA_8888_SkColorType, nullptr, &surface_props); + DCHECK(sk_surface_); + + if (characterization) { + sk_surface_->characterize(characterization); + DCHECK(characterization->isValid()); + } +} + +void SkiaOutputSurfaceImplOnGpu::SwapBuffers( + OutputSurfaceFrame frame, + std::unique_ptr<SkDeferredDisplayList> ddl, + std::vector<YUVResourceMetadata*> yuv_resource_metadatas, + uint64_t sync_fence_release) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(ddl); + DCHECK(sk_surface_); + + if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) { + LOG(FATAL) << "Failed to make current."; + // TODO(penghuang): Handle the failure. + } + + PreprocessYUVResources(std::move(yuv_resource_metadatas)); + + sk_surface_->draw(ddl.get()); + gpu_service_->gr_context()->flush(); + OnSwapBuffers(); + surface_->SwapBuffers( + base::BindRepeating([](const gfx::PresentationFeedback&) {})); + sync_point_client_state_->ReleaseFenceSync(sync_fence_release); +} + +void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass( + RenderPassId id, + std::unique_ptr<SkDeferredDisplayList> ddl, + std::vector<YUVResourceMetadata*> yuv_resource_metadatas, + uint64_t sync_fence_release) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(ddl); + + if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) { + LOG(FATAL) << "Failed to make current."; + // TODO(penghuang): Handle resize failure. + } + + PreprocessYUVResources(std::move(yuv_resource_metadatas)); + + auto& surface = offscreen_surfaces_[id]; + SkSurfaceCharacterization characterization; + // TODO(penghuang): Using characterization != ddl->characterization(), when + // the SkSurfaceCharacterization::operator!= is implemented in Skia. + if (!surface || !surface->characterize(&characterization) || + characterization != ddl->characterization()) { + surface = SkSurface::MakeRenderTarget( + gpu_service_->gr_context(), ddl->characterization(), SkBudgeted::kNo); + DCHECK(surface); + } + surface->draw(ddl.get()); + surface->flush(); + sync_point_client_state_->ReleaseFenceSync(sync_fence_release); +} + +void SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource( + std::vector<RenderPassId> ids) { + DCHECK(!ids.empty()); + for (const auto& id : ids) { + auto it = offscreen_surfaces_.find(id); + DCHECK(it != offscreen_surfaces_.end()); + offscreen_surfaces_.erase(it); + } +} + +void SkiaOutputSurfaceImplOnGpu::FullfillPromiseTexture( + const ResourceMetadata& metadata, + GrBackendTexture* backend_texture) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + auto* mailbox_manager = gpu_service_->mailbox_manager(); + auto* texture_base = mailbox_manager->ConsumeTexture(metadata.mailbox); + if (!texture_base) { + DLOG(ERROR) << "Failed to full fill the promise texture."; + return; + } + BindOrCopyTextureIfNecessary(texture_base); + GrGLTextureInfo texture_info; + texture_info.fTarget = texture_base->target(); + texture_info.fID = texture_base->service_id(); + texture_info.fFormat = *metadata.backend_format.getGLFormat(); + *backend_texture = + GrBackendTexture(metadata.size.width(), metadata.size.height(), + metadata.mip_mapped, texture_info); +} + +void SkiaOutputSurfaceImplOnGpu::FullfillPromiseTexture( + const YUVResourceMetadata& yuv_metadata, + GrBackendTexture* backend_texture) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + + if (yuv_metadata.image()) + *backend_texture = yuv_metadata.image()->getBackendTexture(true); + DLOG_IF(ERROR, !backend_texture->isValid()) + << "Failed to full fill the promise texture from yuv resources."; +} + +void SkiaOutputSurfaceImplOnGpu::FullfillPromiseTexture( + const RenderPassId id, + GrBackendTexture* backend_texture) { + auto it = offscreen_surfaces_.find(id); + DCHECK(it != offscreen_surfaces_.end()); + sk_sp<SkSurface>& surface = it->second; + *backend_texture = + surface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess); + DLOG_IF(ERROR, !backend_texture->isValid()) + << "Failed to full fill the promise texture created from RenderPassId:" + << id; +} + +#if defined(OS_WIN) +void SkiaOutputSurfaceImplOnGpu::DidCreateAcceleratedSurfaceChildWindow( + gpu::SurfaceHandle parent_window, + gpu::SurfaceHandle child_window) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); +} +#endif + +void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersComplete( + gpu::SwapBuffersCompleteParams params) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + params.swap_response.swap_id = pending_swap_completed_ids_.front(); + pending_swap_completed_ids_.pop_front(); + did_swap_buffer_complete_callback_.Run(params); +} + +const gpu::gles2::FeatureInfo* SkiaOutputSurfaceImplOnGpu::GetFeatureInfo() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); + return nullptr; +} + +const gpu::GpuPreferences& SkiaOutputSurfaceImplOnGpu::GetGpuPreferences() + const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); + return gpu_preferences_; +} + +void SkiaOutputSurfaceImplOnGpu::SetSnapshotRequestedCallback( + const base::Closure& callback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); +} + +void SkiaOutputSurfaceImplOnGpu::BufferPresented( + const gfx::PresentationFeedback& feedback) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + buffer_presented_callback_.Run(feedback); +} + +void SkiaOutputSurfaceImplOnGpu::AddFilter(IPC::MessageFilter* message_filter) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); +} + +int32_t SkiaOutputSurfaceImplOnGpu::GetRouteID() const { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + NOTIMPLEMENTED(); + return 0; +} + +void SkiaOutputSurfaceImplOnGpu::BindOrCopyTextureIfNecessary( + gpu::TextureBase* texture_base) { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + if (gpu_service_->gpu_preferences().use_passthrough_cmd_decoder) + return; + // If a texture created with non-passthrough command buffer and bind with + // an image, the Chrome will defer copying the image to the texture until + // the texture is used. It is for implementing low latency drawing and + // avoiding unnecessary texture copy. So we need check the texture image + // state, and bind or copy the image to the texture if necessary. + auto* texture = static_cast<gpu::gles2::Texture*>(texture_base); + gpu::gles2::Texture::ImageState image_state; + auto* image = texture->GetLevelImage(GL_TEXTURE_2D, 0, &image_state); + if (image && image_state == gpu::gles2::Texture::UNBOUND) { + glBindTexture(texture_base->target(), texture_base->service_id()); + if (image->BindTexImage(texture_base->target())) { + } else { + texture->SetLevelImageState(texture_base->target(), 0, + gpu::gles2::Texture::COPIED); + if (!image->CopyTexImage(texture_base->target())) + LOG(ERROR) << "Failed to copy a gl image to texture."; + } + } +} + +void SkiaOutputSurfaceImplOnGpu::PreprocessYUVResources( + std::vector<YUVResourceMetadata*> yuv_resource_metadatas) { + // Create SkImage for fullfilling YUV promise image, before drawing the ddl. + // TODO(penghuang): Remove the extra step when Skia supports drawing YUV + // textures directly. + auto* mailbox_manager = gpu_service_->mailbox_manager(); + for (auto* yuv_metadata : yuv_resource_metadatas) { + const auto& metadatas = yuv_metadata->metadatas(); + DCHECK(metadatas.size() == 2 || metadatas.size() == 3); + GrBackendTexture backend_textures[3]; + size_t i = 0; + for (const auto& metadata : metadatas) { + auto* texture_base = mailbox_manager->ConsumeTexture(metadata.mailbox); + if (!texture_base) + break; + BindOrCopyTextureIfNecessary(texture_base); + GrGLTextureInfo texture_info; + texture_info.fTarget = texture_base->target(); + texture_info.fID = texture_base->service_id(); + texture_info.fFormat = *metadata.backend_format.getGLFormat(); + backend_textures[i++] = + GrBackendTexture(metadata.size.width(), metadata.size.height(), + GrMipMapped::kNo, texture_info); + } + + if (i != metadatas.size()) + continue; + + sk_sp<SkImage> image; + if (metadatas.size() == 2) { + image = SkImage::MakeFromNV12TexturesCopy( + gpu_service_->gr_context(), yuv_metadata->yuv_color_space(), + backend_textures, kTopLeft_GrSurfaceOrigin, + nullptr /* image_color_space */); + DCHECK(image); + } else { + image = SkImage::MakeFromYUVTexturesCopy( + gpu_service_->gr_context(), yuv_metadata->yuv_color_space(), + backend_textures, kTopLeft_GrSurfaceOrigin, + nullptr /* image_color_space */); + DCHECK(image); + } + yuv_metadata->set_image(std::move(image)); + } +} + +void SkiaOutputSurfaceImplOnGpu::OnSwapBuffers() { + uint64_t swap_id = swap_id_++; + pending_swap_completed_ids_.push_back(swap_id); +} + +} // namespace viz diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h new file mode 100644 index 00000000000..82462b0bf9b --- /dev/null +++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h @@ -0,0 +1,173 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_ + +#include "base/containers/circular_deque.h" +#include "base/macros.h" +#include "base/threading/thread_checker.h" +#include "build/build_config.h" +#include "components/viz/common/quads/render_pass.h" +#include "components/viz/common/resources/resource_metadata.h" +#include "components/viz/service/display/output_surface.h" +#include "components/viz/service/display/output_surface_frame.h" +#include "gpu/command_buffer/common/sync_token.h" +#include "gpu/ipc/common/surface_handle.h" +#include "gpu/ipc/in_process_command_buffer.h" +#include "gpu/ipc/service/image_transport_surface_delegate.h" +#include "third_party/skia/include/core/SkSurface.h" + +class SkDeferredDisplayList; + +namespace base { +class WaitableEvent; +} + +namespace gl { +class GLSurface; +} + +namespace gpu { +class SyncPointClientState; +} + +namespace viz { + +class GpuServiceImpl; + +// Metadata for YUV promise SkImage. +class YUVResourceMetadata { + public: + YUVResourceMetadata(std::vector<ResourceMetadata> metadatas, + SkYUVColorSpace yuv_color_space); + YUVResourceMetadata(YUVResourceMetadata&& other); + ~YUVResourceMetadata(); + YUVResourceMetadata& operator=(YUVResourceMetadata&& other); + + const std::vector<ResourceMetadata>& metadatas() const { return metadatas_; } + SkYUVColorSpace yuv_color_space() const { return yuv_color_space_; } + const sk_sp<SkImage> image() const { return image_; } + void set_image(sk_sp<SkImage> image) { image_ = image; } + const gfx::Size size() const { return metadatas_[0].size; } + + private: + // Metadatas for YUV planes. + std::vector<ResourceMetadata> metadatas_; + + SkYUVColorSpace yuv_color_space_; + + // The image copied from YUV textures, it is for fullfilling the promise + // image. + // TODO(penghuang): Remove it when Skia supports drawing YUV textures + // directly. + sk_sp<SkImage> image_; + + DISALLOW_COPY_AND_ASSIGN(YUVResourceMetadata); +}; + +// The SkiaOutputSurface implementation running on the GPU thread. This class +// should be created, used and destroyed on the GPU thread. +class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate { + public: + using DidSwapBufferCompleteCallback = + base::RepeatingCallback<void(gpu::SwapBuffersCompleteParams)>; + using BufferPresentedCallback = + base::RepeatingCallback<void(const gfx::PresentationFeedback& feedback)>; + SkiaOutputSurfaceImplOnGpu( + GpuServiceImpl* gpu_service, + gpu::SurfaceHandle surface_handle, + const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback, + const BufferPresentedCallback& buffer_presented_callback); + ~SkiaOutputSurfaceImplOnGpu() override; + + gpu::CommandBufferId command_buffer_id() const { return command_buffer_id_; } + const OutputSurface::Capabilities capabilities() const { + return capabilities_; + } + const base::WeakPtr<SkiaOutputSurfaceImplOnGpu>& weak_ptr() const { + return weak_ptr_; + } + + void Reshape(const gfx::Size& size, + float device_scale_factor, + const gfx::ColorSpace& color_space, + bool has_alpha, + bool use_stencil, + SkSurfaceCharacterization* characterization, + base::WaitableEvent* event); + void SwapBuffers(OutputSurfaceFrame frame, + std::unique_ptr<SkDeferredDisplayList> ddl, + std::vector<YUVResourceMetadata*> yuv_resource_metadatas, + uint64_t sync_fence_release); + void FinishPaintRenderPass( + RenderPassId id, + std::unique_ptr<SkDeferredDisplayList> ddl, + std::vector<YUVResourceMetadata*> yuv_resource_metadatas, + uint64_t sync_fence_release); + void RemoveRenderPassResource(std::vector<RenderPassId> ids); + + // Fullfill callback for promise SkImage created from a resource. + void FullfillPromiseTexture(const ResourceMetadata& metadata, + GrBackendTexture* backend_texture); + // Fullfill callback for promise SkImage created from YUV resources. + void FullfillPromiseTexture(const YUVResourceMetadata& metadata, + GrBackendTexture* backend_texture); + // Fullfill callback for promise SkImage created from a render pass. + void FullfillPromiseTexture(const RenderPassId id, + GrBackendTexture* backend_texture); + + private: +// gpu::ImageTransportSurfaceDelegate implementation: +#if defined(OS_WIN) + void DidCreateAcceleratedSurfaceChildWindow( + gpu::SurfaceHandle parent_window, + gpu::SurfaceHandle child_window) override; +#endif + void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params) override; + const gpu::gles2::FeatureInfo* GetFeatureInfo() const override; + const gpu::GpuPreferences& GetGpuPreferences() const override; + void SetSnapshotRequestedCallback(const base::Closure& callback) override; + void BufferPresented(const gfx::PresentationFeedback& feedback) override; + void AddFilter(IPC::MessageFilter* message_filter) override; + int32_t GetRouteID() const override; + + void BindOrCopyTextureIfNecessary(gpu::TextureBase* texture_base); + void PreprocessYUVResources( + std::vector<YUVResourceMetadata*> yuv_resource_metadatas); + + // Generage the next swap ID and push it to our pending swap ID queues. + void OnSwapBuffers(); + + const gpu::CommandBufferId command_buffer_id_; + GpuServiceImpl* const gpu_service_; + const gpu::SurfaceHandle surface_handle_; + DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_; + BufferPresentedCallback buffer_presented_callback_; + scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_; + gpu::GpuPreferences gpu_preferences_; + scoped_refptr<gl::GLSurface> surface_; + sk_sp<SkSurface> sk_surface_; + OutputSurface::Capabilities capabilities_; + + // Offscreen surfaces for render passes. It can only be accessed on GPU + // thread. + base::flat_map<RenderPassId, sk_sp<SkSurface>> offscreen_surfaces_; + + // ID is pushed each time we begin a swap, and popped each time we present or + // complete a swap. + base::circular_deque<uint64_t> pending_swap_completed_ids_; + uint64_t swap_id_ = 0; + + THREAD_CHECKER(thread_checker_); + + base::WeakPtr<SkiaOutputSurfaceImplOnGpu> weak_ptr_; + base::WeakPtrFactory<SkiaOutputSurfaceImplOnGpu> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurfaceImplOnGpu); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_ diff --git a/chromium/components/viz/service/display_embedder/software_output_device_mac.cc b/chromium/components/viz/service/display_embedder/software_output_device_mac.cc index b256bf2d60f..b9357082293 100644 --- a/chromium/components/viz/service/display_embedder/software_output_device_mac.cc +++ b/chromium/components/viz/service/display_embedder/software_output_device_mac.cc @@ -7,7 +7,7 @@ #include "base/mac/foundation_util.h" #include "base/trace_event/trace_event.h" #include "third_party/skia/include/core/SkCanvas.h" -#include "ui/accelerated_widget_mac/ca_layer_frame_sink.h" +#include "ui/gfx/ca_layer_params.h" #include "ui/gfx/mac/io_surface.h" #include "ui/gfx/skia_util.h" @@ -16,8 +16,9 @@ namespace viz { SoftwareOutputDeviceMac::Buffer::Buffer() = default; SoftwareOutputDeviceMac::Buffer::~Buffer() = default; -SoftwareOutputDeviceMac::SoftwareOutputDeviceMac(gfx::AcceleratedWidget widget) - : widget_(widget) {} +SoftwareOutputDeviceMac::SoftwareOutputDeviceMac( + scoped_refptr<base::SequencedTaskRunner> task_runner) + : SoftwareOutputDevice(std::move(task_runner)) {} SoftwareOutputDeviceMac::~SoftwareOutputDeviceMac() {} @@ -178,24 +179,14 @@ void SoftwareOutputDeviceMac::EndPaint() { } current_paint_canvas_.reset(); - if (widget_ != gfx::kNullAcceleratedWidget) { + if (client_) { gfx::CALayerParams ca_layer_params; ca_layer_params.is_empty = false; ca_layer_params.scale_factor = scale_factor_; ca_layer_params.pixel_size = pixel_size_; ca_layer_params.io_surface_mach_port.reset( IOSurfaceCreateMachPort(current_paint_buffer_->io_surface)); - ui::CALayerFrameSink* ca_layer_frame_sink = - ui::CALayerFrameSink::FromAcceleratedWidget(widget_); - if (ca_layer_frame_sink) { - ca_layer_frame_sink->SetSuspended(false); - ca_layer_frame_sink->UpdateCALayerTree(ca_layer_params); - base::TimeTicks vsync_timebase; - base::TimeDelta vsync_interval; - ca_layer_frame_sink->GetVSyncParameters(&vsync_timebase, &vsync_interval); - if (!update_vsync_callback_.is_null()) - update_vsync_callback_.Run(vsync_timebase, vsync_interval); - } + client_->SoftwareDeviceUpdatedCALayerParams(ca_layer_params); } current_paint_buffer_ = nullptr; @@ -208,26 +199,7 @@ void SoftwareOutputDeviceMac::DiscardBackbuffer() { void SoftwareOutputDeviceMac::EnsureBackbuffer() {} gfx::VSyncProvider* SoftwareOutputDeviceMac::GetVSyncProvider() { - return this; -} - -void SoftwareOutputDeviceMac::GetVSyncParameters( - const gfx::VSyncProvider::UpdateVSyncCallback& callback) { - update_vsync_callback_ = callback; -} - -bool SoftwareOutputDeviceMac::GetVSyncParametersIfAvailable( - base::TimeTicks* timebase, - base::TimeDelta* interval) { - return false; -} - -bool SoftwareOutputDeviceMac::SupportGetVSyncParametersIfAvailable() const { - return false; -} - -bool SoftwareOutputDeviceMac::IsHWClock() const { - return false; + return nullptr; } } // namespace viz diff --git a/chromium/components/viz/service/display_embedder/software_output_device_mac.h b/chromium/components/viz/service/display_embedder/software_output_device_mac.h index 4066ac56600..f3867356e3d 100644 --- a/chromium/components/viz/service/display_embedder/software_output_device_mac.h +++ b/chromium/components/viz/service/display_embedder/software_output_device_mac.h @@ -14,17 +14,15 @@ #include "components/viz/service/viz_service_export.h" #include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkRegion.h" -#include "ui/gfx/native_widget_types.h" -#include "ui/gfx/vsync_provider.h" class SkCanvas; namespace viz { -class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice, - public gfx::VSyncProvider { +class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice { public: - explicit SoftwareOutputDeviceMac(gfx::AcceleratedWidget widget); + explicit SoftwareOutputDeviceMac( + scoped_refptr<base::SequencedTaskRunner> task_runner); ~SoftwareOutputDeviceMac() override; // SoftwareOutputDevice implementation. @@ -35,14 +33,6 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice, void EnsureBackbuffer() override; gfx::VSyncProvider* GetVSyncProvider() override; - // gfx::VSyncProvider implementation. - void GetVSyncParameters( - const gfx::VSyncProvider::UpdateVSyncCallback& callback) override; - bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase, - base::TimeDelta* interval) override; - bool SupportGetVSyncParametersIfAvailable() const override; - bool IsHWClock() const override; - // Testing methods. SkRegion LastCopyRegionForTesting() const { return last_copy_region_for_testing_; @@ -66,7 +56,6 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice, void UpdateAndCopyBufferDamage(Buffer* previous_paint_buffer, const SkRegion& new_damage_rect); - gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget; gfx::Size pixel_size_; float scale_factor_ = 1; @@ -83,8 +72,6 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice, // valid only between BeginPaint and EndPaint. std::unique_ptr<SkCanvas> current_paint_canvas_; - gfx::VSyncProvider::UpdateVSyncCallback update_vsync_callback_; - SkRegion last_copy_region_for_testing_; DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceMac); diff --git a/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm b/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm index ed0b8ad3a49..217bf3a2f7f 100644 --- a/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm +++ b/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm @@ -4,6 +4,7 @@ #include "components/viz/service/display_embedder/software_output_device_mac.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/skia_util.h" @@ -12,8 +13,8 @@ namespace viz { namespace { TEST(SoftwareOutputDeviceMacTest, Basics) { - std::unique_ptr<SoftwareOutputDeviceMac> device( - new SoftwareOutputDeviceMac(gfx::kNullAcceleratedWidget)); + auto device = std::make_unique<SoftwareOutputDeviceMac>( + base::SequencedTaskRunnerHandle::Get()); gfx::Size pixel_size(512, 512); float scale_factor = 1; diff --git a/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc b/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc index ee5986fdfb6..46cd8125266 100644 --- a/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc +++ b/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc @@ -46,7 +46,8 @@ class TestPlatformWindowDelegate : public ui::PlatformWindowDelegate { float device_pixel_ratio) override { widget_ = widget; } - void OnAcceleratedWidgetDestroyed() override { NOTREACHED(); } + void OnAcceleratedWidgetDestroying() override {} + void OnAcceleratedWidgetDestroyed() override {} void OnActivationChanged(bool active) override {} private: diff --git a/chromium/components/viz/service/display_embedder/software_output_device_win.cc b/chromium/components/viz/service/display_embedder/software_output_device_win.cc index 61213e77e24..ba84cac14b3 100644 --- a/chromium/components/viz/service/display_embedder/software_output_device_win.cc +++ b/chromium/components/viz/service/display_embedder/software_output_device_win.cc @@ -4,109 +4,59 @@ #include "components/viz/service/display_embedder/software_output_device_win.h" -#include "base/debug/alias.h" #include "base/memory/shared_memory.h" +#include "base/threading/thread_checker.h" +#include "components/viz/common/display/use_layered_window.h" #include "components/viz/common/resources/resource_sizes.h" +#include "components/viz/service/display_embedder/output_device_backing.h" +#include "mojo/public/cpp/system/platform_handle.h" +#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h" #include "skia/ext/platform_canvas.h" #include "skia/ext/skia_utils_win.h" -#include "ui/base/win/internal_constants.h" +#include "third_party/skia/include/core/SkCanvas.h" #include "ui/gfx/gdi_util.h" #include "ui/gfx/skia_util.h" namespace viz { +namespace { -// If a window is larger than this in bytes, don't even try to create a -// backing bitmap for it. -static const size_t kMaxBitmapSizeBytes = 4 * (16384 * 8192); +// Shared base class for Windows SoftwareOutputDevice implementations. +class SoftwareOutputDeviceWinBase : public SoftwareOutputDevice { + public: + explicit SoftwareOutputDeviceWinBase(HWND hwnd) : hwnd_(hwnd) {} + ~SoftwareOutputDeviceWinBase() override { + DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); + DCHECK(!in_paint_); + } -OutputDeviceBacking::OutputDeviceBacking() : created_byte_size_(0) {} + HWND hwnd() const { return hwnd_; } -OutputDeviceBacking::~OutputDeviceBacking() { - DCHECK(devices_.empty()); -} + // SoftwareOutputDevice implementation. + void Resize(const gfx::Size& viewport_pixel_size, + float scale_factor) override; + SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override; + void EndPaint() override; -void OutputDeviceBacking::Resized() { - size_t new_size = GetMaxByteSize(); - if (new_size == created_byte_size_) - return; - for (SoftwareOutputDeviceWin* device : devices_) { - device->ReleaseContents(); - } - backing_.reset(); - created_byte_size_ = 0; -} - -void OutputDeviceBacking::RegisterOutputDevice( - SoftwareOutputDeviceWin* device) { - devices_.push_back(device); -} - -void OutputDeviceBacking::UnregisterOutputDevice( - SoftwareOutputDeviceWin* device) { - auto it = std::find(devices_.begin(), devices_.end(), device); - DCHECK(it != devices_.end()); - devices_.erase(it); - Resized(); -} - -base::SharedMemory* OutputDeviceBacking::GetSharedMemory( - const gfx::Size& size) { - if (backing_) - return backing_.get(); - size_t expected_byte_size = GetMaxByteSize(); - size_t required_size; - if (!ResourceSizes::MaybeSizeInBytes(size, RGBA_8888, &required_size)) - return nullptr; - if (required_size > expected_byte_size) - return nullptr; - - created_byte_size_ = expected_byte_size; - - backing_.reset(new base::SharedMemory); - base::debug::Alias(&expected_byte_size); - CHECK(backing_->CreateAnonymous(created_byte_size_)); - return backing_.get(); -} - -size_t OutputDeviceBacking::GetMaxByteSize() { - // Minimum byte size is 1 because creating a 0-byte-long SharedMemory fails. - size_t max_size = 1; - for (const SoftwareOutputDeviceWin* device : devices_) { - size_t current_size; - if (!ResourceSizes::MaybeSizeInBytes(device->viewport_pixel_size(), - RGBA_8888, ¤t_size)) - continue; - if (current_size > kMaxBitmapSizeBytes) - continue; - max_size = std::max(max_size, current_size); - } - return max_size; -} + // Called from Resize() if |viewport_pixel_size_| has changed. + virtual void ResizeDelegated() = 0; -SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(OutputDeviceBacking* backing, - gfx::AcceleratedWidget widget) - : hwnd_(widget), - is_hwnd_composited_(false), - backing_(backing), - in_paint_(false) { - is_hwnd_composited_ = !!::GetProp(hwnd_, ui::kWindowTranslucent); - // Layered windows must be completely updated every time, so they can't - // share contents with other windows. - if (is_hwnd_composited_) - backing_ = nullptr; - if (backing_) - backing_->RegisterOutputDevice(this); -} + // Called from BeginPaint() and should return an SkCanvas. + virtual SkCanvas* BeginPaintDelegated() = 0; -SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!in_paint_); - if (backing_) - backing_->UnregisterOutputDevice(this); -} + // Called from EndPaint() if there is damage. + virtual void EndPaintDelegated(const gfx::Rect& damage_rect) = 0; + + private: + const HWND hwnd_; + bool in_paint_ = false; + + THREAD_CHECKER(thread_checker_); + + DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinBase); +}; -void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size, - float scale_factor) { +void SoftwareOutputDeviceWinBase::Resize(const gfx::Size& viewport_pixel_size, + float scale_factor) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!in_paint_); @@ -114,84 +64,301 @@ void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size, return; viewport_pixel_size_ = viewport_pixel_size; - if (backing_) - backing_->Resized(); - contents_.reset(); + ResizeDelegated(); } -SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) { +SkCanvas* SoftwareOutputDeviceWinBase::BeginPaint( + const gfx::Rect& damage_rect) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!in_paint_); - if (!contents_) { - HANDLE shared_section = NULL; - bool can_create_contents = true; - if (backing_) { - base::SharedMemory* memory = - backing_->GetSharedMemory(viewport_pixel_size_); - if (memory) { - shared_section = memory->handle().GetHandle(); - } else { - can_create_contents = false; - } - } - if (can_create_contents) { - contents_ = skia::CreatePlatformCanvasWithSharedSection( - viewport_pixel_size_.width(), viewport_pixel_size_.height(), true, - shared_section, skia::CRASH_ON_FAILURE); - } - } damage_rect_ = damage_rect; in_paint_ = true; - return contents_.get(); + return BeginPaintDelegated(); } -void SoftwareOutputDeviceWin::EndPaint() { +void SoftwareOutputDeviceWinBase::EndPaint() { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(in_paint_); in_paint_ = false; - SoftwareOutputDevice::EndPaint(); - if (!contents_) + gfx::Rect intersected_damage_rect = damage_rect_; + intersected_damage_rect.Intersect(gfx::Rect(viewport_pixel_size_)); + if (intersected_damage_rect.IsEmpty()) return; - gfx::Rect rect = damage_rect_; - rect.Intersect(gfx::Rect(viewport_pixel_size_)); - if (rect.IsEmpty()) + EndPaintDelegated(intersected_damage_rect); +} + +// SoftwareOutputDevice implementation that draws directly to the provided HWND. +class SoftwareOutputDeviceWinDirect : public SoftwareOutputDeviceWinBase, + public OutputDeviceBacking::Client { + public: + SoftwareOutputDeviceWinDirect(HWND hwnd, OutputDeviceBacking* backing); + ~SoftwareOutputDeviceWinDirect() override; + + // SoftwareOutputDeviceWinBase implementation. + void ResizeDelegated() override; + SkCanvas* BeginPaintDelegated() override; + void EndPaintDelegated(const gfx::Rect& damage_rect) override; + + // OutputDeviceBacking::Client implementation. + const gfx::Size& GetViewportPixelSize() const override { + return viewport_pixel_size_; + } + void ReleaseCanvas() override { canvas_.reset(); } + + private: + OutputDeviceBacking* const backing_; + std::unique_ptr<SkCanvas> canvas_; + + DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinDirect); +}; + +SoftwareOutputDeviceWinDirect::SoftwareOutputDeviceWinDirect( + HWND hwnd, + OutputDeviceBacking* backing) + : SoftwareOutputDeviceWinBase(hwnd), backing_(backing) { + backing_->RegisterClient(this); +} + +SoftwareOutputDeviceWinDirect::~SoftwareOutputDeviceWinDirect() { + backing_->UnregisterClient(this); +} + +void SoftwareOutputDeviceWinDirect::ResizeDelegated() { + canvas_.reset(); + backing_->ClientResized(); +} + +SkCanvas* SoftwareOutputDeviceWinDirect::BeginPaintDelegated() { + if (!canvas_) { + // Share pixel backing with other SoftwareOutputDeviceWinDirect instances. + // All work happens on the same thread so this is safe. + base::SharedMemory* memory = + backing_->GetSharedMemory(viewport_pixel_size_); + if (memory) { + canvas_ = skia::CreatePlatformCanvasWithSharedSection( + viewport_pixel_size_.width(), viewport_pixel_size_.height(), true, + memory->handle().GetHandle(), skia::CRASH_ON_FAILURE); + } + } + return canvas_.get(); +} + +void SoftwareOutputDeviceWinDirect::EndPaintDelegated( + const gfx::Rect& damage_rect) { + if (!canvas_) return; - HDC dib_dc = skia::GetNativeDrawingContext(contents_.get()); - - if (is_hwnd_composited_) { - RECT wr; - GetWindowRect(hwnd_, &wr); - SIZE size = {wr.right - wr.left, wr.bottom - wr.top}; - POINT position = {wr.left, wr.top}; - POINT zero = {0, 0}; - BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA}; - - DWORD style = GetWindowLong(hwnd_, GWL_EXSTYLE); - DCHECK(!(style & WS_EX_COMPOSITED)); - style |= WS_EX_LAYERED; - SetWindowLong(hwnd_, GWL_EXSTYLE, style); - - ::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero, - RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); - } else { - HDC hdc = ::GetDC(hwnd_); - RECT src_rect = rect.ToRECT(); - skia::CopyHDC(dib_dc, hdc, rect.x(), rect.y(), - contents_.get()->imageInfo().isOpaque(), src_rect, - contents_.get()->getTotalMatrix()); - - ::ReleaseDC(hwnd_, hdc); + HDC dib_dc = skia::GetNativeDrawingContext(canvas_.get()); + HDC hdc = ::GetDC(hwnd()); + RECT src_rect = damage_rect.ToRECT(); + skia::CopyHDC(dib_dc, hdc, damage_rect.x(), damage_rect.y(), + canvas_->imageInfo().isOpaque(), src_rect, + canvas_->getTotalMatrix()); + + ::ReleaseDC(hwnd(), hdc); +} + +// SoftwareOutputDevice implementation that uses layered window API to draw to +// the provided HWND. +class SoftwareOutputDeviceWinLayered : public SoftwareOutputDeviceWinBase { + public: + explicit SoftwareOutputDeviceWinLayered(HWND hwnd) + : SoftwareOutputDeviceWinBase(hwnd) {} + ~SoftwareOutputDeviceWinLayered() override = default; + + // SoftwareOutputDeviceWinBase implementation. + void ResizeDelegated() override; + SkCanvas* BeginPaintDelegated() override; + void EndPaintDelegated(const gfx::Rect& damage_rect) override; + + private: + std::unique_ptr<SkCanvas> canvas_; + + DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinLayered); +}; + +void SoftwareOutputDeviceWinLayered::ResizeDelegated() { + canvas_.reset(); +} + +SkCanvas* SoftwareOutputDeviceWinLayered::BeginPaintDelegated() { + if (!canvas_) { + // Layered windows can't share a pixel backing. + canvas_ = skia::CreatePlatformCanvasWithSharedSection( + viewport_pixel_size_.width(), viewport_pixel_size_.height(), true, + nullptr, skia::CRASH_ON_FAILURE); } + return canvas_.get(); } -void SoftwareOutputDeviceWin::ReleaseContents() { - DCHECK(!in_paint_); - contents_.reset(); +void SoftwareOutputDeviceWinLayered::EndPaintDelegated( + const gfx::Rect& damage_rect) { + if (!canvas_) + return; + + // Set WS_EX_LAYERED extended window style if not already set. + DWORD style = GetWindowLong(hwnd(), GWL_EXSTYLE); + DCHECK(!(style & WS_EX_COMPOSITED)); + if (!(style & WS_EX_LAYERED)) + SetWindowLong(hwnd(), GWL_EXSTYLE, style | WS_EX_LAYERED); + + RECT wr; + GetWindowRect(hwnd(), &wr); + SIZE size = {wr.right - wr.left, wr.bottom - wr.top}; + POINT position = {wr.left, wr.top}; + POINT zero = {0, 0}; + BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA}; + + HDC dib_dc = skia::GetNativeDrawingContext(canvas_.get()); + UpdateLayeredWindow(hwnd(), nullptr, &position, &size, dib_dc, &zero, + RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA); +} + +// SoftwareOutputDevice implementation that uses layered window API to draw +// indirectly. Since UpdateLayeredWindow() is blocked by the GPU sandbox an +// implementation of mojom::LayeredWindowUpdater in the browser process handles +// calling UpdateLayeredWindow. Pixel backing is in SharedMemory so no copying +// between processes is required. +class SoftwareOutputDeviceWinProxy : public SoftwareOutputDeviceWinBase { + public: + SoftwareOutputDeviceWinProxy( + HWND hwnd, + mojom::LayeredWindowUpdaterPtr layered_window_updater); + ~SoftwareOutputDeviceWinProxy() override = default; + + // SoftwareOutputDevice implementation. + void OnSwapBuffers(base::OnceClosure swap_ack_callback) override; + + // SoftwareOutputDeviceWinBase implementation. + void ResizeDelegated() override; + SkCanvas* BeginPaintDelegated() override; + void EndPaintDelegated(const gfx::Rect& rect) override; + + private: + // Runs |swap_ack_callback_| after draw has happened. + void DrawAck(); + + mojom::LayeredWindowUpdaterPtr layered_window_updater_; + + std::unique_ptr<SkCanvas> canvas_; + bool waiting_on_draw_ack_ = false; + base::OnceClosure swap_ack_callback_; + + DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinProxy); +}; + +SoftwareOutputDeviceWinProxy::SoftwareOutputDeviceWinProxy( + HWND hwnd, + mojom::LayeredWindowUpdaterPtr layered_window_updater) + : SoftwareOutputDeviceWinBase(hwnd), + layered_window_updater_(std::move(layered_window_updater)) { + DCHECK(layered_window_updater_.is_bound()); +} + +void SoftwareOutputDeviceWinProxy::OnSwapBuffers( + base::OnceClosure swap_ack_callback) { + DCHECK(swap_ack_callback_.is_null()); + + // We aren't waiting on DrawAck() and can immediately run the callback. + if (!waiting_on_draw_ack_) { + task_runner_->PostTask(FROM_HERE, std::move(swap_ack_callback)); + return; + } + + swap_ack_callback_ = std::move(swap_ack_callback); +} + +void SoftwareOutputDeviceWinProxy::ResizeDelegated() { + canvas_.reset(); + + size_t required_bytes; + if (!ResourceSizes::MaybeSizeInBytes( + viewport_pixel_size_, ResourceFormat::RGBA_8888, &required_bytes)) { + DLOG(ERROR) << "Invalid viewport size " << viewport_pixel_size_.ToString(); + return; + } + + base::SharedMemory shm; + if (!shm.CreateAnonymous(required_bytes)) { + DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes"; + return; + } + + // The SkCanvas maps shared memory on creation and unmaps on destruction. + canvas_ = skia::CreatePlatformCanvasWithSharedSection( + viewport_pixel_size_.width(), viewport_pixel_size_.height(), true, + shm.handle().GetHandle(), skia::CRASH_ON_FAILURE); + + // Transfer handle ownership to the browser process. + mojo::ScopedSharedBufferHandle scoped_handle = mojo::WrapSharedMemoryHandle( + shm.TakeHandle(), required_bytes, + mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite); + + layered_window_updater_->OnAllocatedSharedMemory(viewport_pixel_size_, + std::move(scoped_handle)); +} + +SkCanvas* SoftwareOutputDeviceWinProxy::BeginPaintDelegated() { + return canvas_.get(); +} + +void SoftwareOutputDeviceWinProxy::EndPaintDelegated( + const gfx::Rect& damage_rect) { + DCHECK(!waiting_on_draw_ack_); + + if (!canvas_) + return; + + layered_window_updater_->Draw(base::BindOnce( + &SoftwareOutputDeviceWinProxy::DrawAck, base::Unretained(this))); + waiting_on_draw_ack_ = true; + + TRACE_EVENT_ASYNC_BEGIN0("viz", "SoftwareOutputDeviceWinProxy::Draw", this); +} + +void SoftwareOutputDeviceWinProxy::DrawAck() { + DCHECK(waiting_on_draw_ack_); + DCHECK(!swap_ack_callback_.is_null()); + + TRACE_EVENT_ASYNC_END0("viz", "SoftwareOutputDeviceWinProxy::Draw", this); + + waiting_on_draw_ack_ = false; + std::move(swap_ack_callback_).Run(); +} + +} // namespace + +std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinBrowser( + HWND hwnd, + OutputDeviceBacking* backing) { + if (NeedsToUseLayerWindow(hwnd)) + return std::make_unique<SoftwareOutputDeviceWinLayered>(hwnd); + + return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing); +} + +std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinGpu( + HWND hwnd, + OutputDeviceBacking* backing, + mojom::DisplayClient* display_client) { + if (NeedsToUseLayerWindow(hwnd)) { + DCHECK(display_client); + + // Setup mojom::LayeredWindowUpdater implementation in the browser process + // to draw to the HWND. + mojom::LayeredWindowUpdaterPtr layered_window_updater; + display_client->CreateLayeredWindowUpdater( + mojo::MakeRequest(&layered_window_updater)); + + return std::make_unique<SoftwareOutputDeviceWinProxy>( + hwnd, std::move(layered_window_updater)); + } + + return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing); } } // namespace viz diff --git a/chromium/components/viz/service/display_embedder/software_output_device_win.h b/chromium/components/viz/service/display_embedder/software_output_device_win.h index ad2a049fc77..aa2dd64bb0d 100644 --- a/chromium/components/viz/service/display_embedder/software_output_device_win.h +++ b/chromium/components/viz/service/display_embedder/software_output_device_win.h @@ -5,71 +5,29 @@ #ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_WIN_H_ #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_WIN_H_ -#include <stddef.h> #include <windows.h> #include <memory> -#include <vector> -#include "base/macros.h" -#include "base/threading/thread_checker.h" #include "components/viz/service/display/software_output_device.h" #include "components/viz/service/viz_service_export.h" -#include "third_party/skia/include/core/SkCanvas.h" -#include "third_party/skia/include/core/SkRefCnt.h" -#include "ui/gfx/native_widget_types.h" - -namespace base { -class SharedMemory; -} +#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h" namespace viz { -class SoftwareOutputDeviceWin; - -class VIZ_SERVICE_EXPORT OutputDeviceBacking { - public: - OutputDeviceBacking(); - ~OutputDeviceBacking(); - - void Resized(); - void RegisterOutputDevice(SoftwareOutputDeviceWin* device); - void UnregisterOutputDevice(SoftwareOutputDeviceWin* device); - base::SharedMemory* GetSharedMemory(const gfx::Size& size); - - private: - size_t GetMaxByteSize(); - - std::vector<SoftwareOutputDeviceWin*> devices_; - std::unique_ptr<base::SharedMemory> backing_; - size_t created_byte_size_; - - DISALLOW_COPY_AND_ASSIGN(OutputDeviceBacking); -}; - -class VIZ_SERVICE_EXPORT SoftwareOutputDeviceWin : public SoftwareOutputDevice { - public: - SoftwareOutputDeviceWin(OutputDeviceBacking* backing, - gfx::AcceleratedWidget widget); - ~SoftwareOutputDeviceWin() override; - - void Resize(const gfx::Size& viewport_pixel_size, - float scale_factor) override; - SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override; - void EndPaint() override; - gfx::Size viewport_pixel_size() const { return viewport_pixel_size_; } - void ReleaseContents(); +class OutputDeviceBacking; - private: - HWND hwnd_; - std::unique_ptr<SkCanvas> contents_; - bool is_hwnd_composited_; - OutputDeviceBacking* backing_; - bool in_paint_; - THREAD_CHECKER(thread_checker_); +// Creates an appropriate SoftwareOutputDevice implementation for the browser +// process. +VIZ_SERVICE_EXPORT std::unique_ptr<SoftwareOutputDevice> +CreateSoftwareOutputDeviceWinBrowser(HWND hwnd, OutputDeviceBacking* backing); - DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWin); -}; +// Creates an appropriate SoftwareOutputDevice implementation for the GPU +// process. +VIZ_SERVICE_EXPORT std::unique_ptr<SoftwareOutputDevice> +CreateSoftwareOutputDeviceWinGpu(HWND hwnd, + OutputDeviceBacking* backing, + mojom::DisplayClient* display_client); } // namespace viz diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.cc b/chromium/components/viz/service/display_embedder/software_output_surface.cc index 370829010ea..fff590968c5 100644 --- a/chromium/components/viz/service/display_embedder/software_output_surface.cc +++ b/chromium/components/viz/service/display_embedder/software_output_surface.cc @@ -9,7 +9,6 @@ #include "base/bind.h" #include "base/location.h" #include "base/memory/ref_counted.h" -#include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" #include "build/build_config.h" #include "components/viz/service/display/output_surface_client.h" @@ -22,11 +21,8 @@ namespace viz { SoftwareOutputSurface::SoftwareOutputSurface( - std::unique_ptr<SoftwareOutputDevice> software_device, - scoped_refptr<base::SequencedTaskRunner> task_runner) - : OutputSurface(std::move(software_device)), - task_runner_(std::move(task_runner)), - weak_factory_(this) {} + std::unique_ptr<SoftwareOutputDevice> software_device) + : OutputSurface(std::move(software_device)), weak_factory_(this) {} SoftwareOutputSurface::~SoftwareOutputSurface() = default; @@ -66,14 +62,16 @@ void SoftwareOutputSurface::SwapBuffers(OutputSurfaceFrame frame) { base::TimeTicks swap_time = base::TimeTicks::Now(); for (auto& latency : frame.latency_info) { latency.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1); + ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, swap_time, 1); latency.AddLatencyNumberWithTimestamp( - ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0, - swap_time, 1); + ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, swap_time, + 1); } - // TODO(danakj): Send frame.latency_info somewhere like - // RenderWidgetHostImpl::OnGpuSwapBuffersCompleted. It should go to the - // ui::LatencyTracker in the viz process. + + DCHECK(stored_latency_info_.empty()) + << "A second frame is not expected to " + << "arrive before the previous latency info is processed."; + stored_latency_info_ = std::move(frame.latency_info); // TODO(danakj): Update vsync params. // gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider(); @@ -81,10 +79,9 @@ void SoftwareOutputSurface::SwapBuffers(OutputSurfaceFrame frame) { // vsync_provider->GetVSyncParameters(update_vsync_parameters_callback_); // Update refresh_interval_ as well. - ++swap_id_; - task_runner_->PostTask( - FROM_HERE, base::BindOnce(&SoftwareOutputSurface::SwapBuffersCallback, - weak_factory_.GetWeakPtr(), swap_id_)); + software_device()->OnSwapBuffers(base::BindOnce( + &SoftwareOutputSurface::SwapBuffersCallback, weak_factory_.GetWeakPtr(), + frame.need_presentation_feedback)); } bool SoftwareOutputSurface::IsDisplayedAsOverlayPlane() const { @@ -111,21 +108,22 @@ bool SoftwareOutputSurface::HasExternalStencilTest() const { void SoftwareOutputSurface::ApplyExternalStencil() {} -bool SoftwareOutputSurface::SurfaceIsSuspendForRecycle() const { - return false; -} - uint32_t SoftwareOutputSurface::GetFramebufferCopyTextureFormat() { // Not used for software surfaces. NOTREACHED(); return 0; } -void SoftwareOutputSurface::SwapBuffersCallback(uint64_t swap_id) { - client_->DidReceiveSwapBuffersAck(swap_id); - client_->DidReceivePresentationFeedback( - swap_id, - gfx::PresentationFeedback(base::TimeTicks::Now(), refresh_interval_, 0u)); +void SoftwareOutputSurface::SwapBuffersCallback( + bool need_presentation_feedback) { + latency_tracker_.OnGpuSwapBuffersCompleted(stored_latency_info_); + client_->DidFinishLatencyInfo(stored_latency_info_); + std::vector<ui::LatencyInfo>().swap(stored_latency_info_); + client_->DidReceiveSwapBuffersAck(); + if (need_presentation_feedback) { + client_->DidReceivePresentationFeedback(gfx::PresentationFeedback( + base::TimeTicks::Now(), refresh_interval_, 0u)); + } } #if BUILDFLAG(ENABLE_VULKAN) @@ -135,4 +133,8 @@ gpu::VulkanSurface* SoftwareOutputSurface::GetVulkanSurface() { } #endif +unsigned SoftwareOutputSurface::UpdateGpuFence() { + return 0; +} + } // namespace viz diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.h b/chromium/components/viz/service/display_embedder/software_output_surface.h index 70b20326e25..2c78d933167 100644 --- a/chromium/components/viz/service/display_embedder/software_output_surface.h +++ b/chromium/components/viz/service/display_embedder/software_output_surface.h @@ -6,17 +6,18 @@ #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_ #include "base/memory/weak_ptr.h" -#include "base/single_thread_task_runner.h" #include "components/viz/service/display/output_surface.h" #include "components/viz/service/viz_service_export.h" +#include "ui/latency/latency_info.h" +#include "ui/latency/latency_tracker.h" namespace viz { class SoftwareOutputDevice; class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface { public: - SoftwareOutputSurface(std::unique_ptr<SoftwareOutputDevice> software_device, - scoped_refptr<base::SequencedTaskRunner> task_runner); + explicit SoftwareOutputSurface( + std::unique_ptr<SoftwareOutputDevice> software_device); ~SoftwareOutputSurface() override; // OutputSurface implementation. @@ -37,19 +38,19 @@ class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface { gfx::BufferFormat GetOverlayBufferFormat() const override; bool HasExternalStencilTest() const override; void ApplyExternalStencil() override; - bool SurfaceIsSuspendForRecycle() const override; uint32_t GetFramebufferCopyTextureFormat() override; #if BUILDFLAG(ENABLE_VULKAN) gpu::VulkanSurface* GetVulkanSurface() override; #endif + unsigned UpdateGpuFence() override; private: - void SwapBuffersCallback(uint64_t swap_id); + void SwapBuffersCallback(bool need_presentation_feedback); OutputSurfaceClient* client_ = nullptr; - scoped_refptr<base::SequencedTaskRunner> task_runner_; base::TimeDelta refresh_interval_; - uint64_t swap_id_ = 0; + std::vector<ui::LatencyInfo> stored_latency_info_; + ui::LatencyTracker latency_tracker_; base::WeakPtrFactory<SoftwareOutputSurface> weak_factory_; DISALLOW_COPY_AND_ASSIGN(SoftwareOutputSurface); diff --git a/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc new file mode 100644 index 00000000000..e32a6e1864e --- /dev/null +++ b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc @@ -0,0 +1,151 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/display_embedder/viz_process_context_provider.h" + +#include <stdint.h> + +#include <utility> + +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "base/single_thread_task_runner.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/viz/common/resources/platform_color.h" +#include "gpu/GLES2/gl2extchromium.h" +#include "gpu/command_buffer/client/gles2_implementation.h" +#include "gpu/command_buffer/client/raster_implementation_gles.h" +#include "gpu/command_buffer/common/context_creation_attribs.h" +#include "gpu/command_buffer/service/gpu_preferences.h" +#include "gpu/command_buffer/service/mailbox_manager.h" +#include "gpu/command_buffer/service/sync_point_manager.h" +#include "gpu/config/gpu_feature_info.h" +#include "gpu/ipc/common/surface_handle.h" +#include "gpu/ipc/gl_in_process_context.h" +#include "gpu/ipc/gpu_in_process_thread_service.h" +#include "gpu/ipc/in_process_command_buffer.h" +#include "gpu/skia_bindings/grcontext_for_gles2_interface.h" +#include "third_party/khronos/GLES2/gl2.h" +#include "third_party/khronos/GLES2/gl2ext.h" +#include "third_party/skia/include/gpu/GrContext.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" + +namespace viz { + +namespace { + +gpu::ContextCreationAttribs CreateAttributes() { + gpu::ContextCreationAttribs attributes; + attributes.alpha_size = -1; + attributes.depth_size = 0; + attributes.stencil_size = 8; + attributes.samples = 0; + attributes.sample_buffers = 0; + attributes.fail_if_major_perf_caveat = false; + attributes.bind_generates_resource = false; + return attributes; +} + +} // namespace + +VizProcessContextProvider::VizProcessContextProvider( + scoped_refptr<gpu::InProcessCommandBuffer::Service> service, + gpu::SurfaceHandle surface_handle, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + gpu::ImageFactory* image_factory, + gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate, + const gpu::SharedMemoryLimits& limits) + : attributes_(CreateAttributes()), + context_(gpu::GLInProcessContext::CreateWithoutInit()), + context_result_( + context_->Initialize(std::move(service), + nullptr, + (surface_handle == gpu::kNullSurfaceHandle), + surface_handle, + attributes_, + limits, + gpu_memory_buffer_manager, + image_factory, + gpu_channel_manager_delegate, + base::ThreadTaskRunnerHandle::Get())), + cache_controller_(std::make_unique<ContextCacheController>( + context_->GetImplementation(), + base::ThreadTaskRunnerHandle::Get())) {} + +VizProcessContextProvider::~VizProcessContextProvider() = default; + +void VizProcessContextProvider::AddRef() const { + base::RefCountedThreadSafe<VizProcessContextProvider>::AddRef(); +} + +void VizProcessContextProvider::Release() const { + base::RefCountedThreadSafe<VizProcessContextProvider>::Release(); +} + +gpu::ContextResult VizProcessContextProvider::BindToCurrentThread() { + return context_result_; +} + +gpu::gles2::GLES2Interface* VizProcessContextProvider::ContextGL() { + return context_->GetImplementation(); +} + +gpu::ContextSupport* VizProcessContextProvider::ContextSupport() { + return context_->GetImplementation(); +} + +class GrContext* VizProcessContextProvider::GrContext() { + if (gr_context_) + return gr_context_->get(); + + size_t max_resource_cache_bytes; + size_t max_glyph_cache_texture_bytes; + skia_bindings::GrContextForGLES2Interface:: + DetermineCacheLimitsFromAvailableMemory(&max_resource_cache_bytes, + &max_glyph_cache_texture_bytes); + + gr_context_.reset(new skia_bindings::GrContextForGLES2Interface( + ContextGL(), ContextSupport(), ContextCapabilities(), + max_resource_cache_bytes, max_glyph_cache_texture_bytes)); + return gr_context_->get(); +} + +ContextCacheController* VizProcessContextProvider::CacheController() { + return cache_controller_.get(); +} + +base::Lock* VizProcessContextProvider::GetLock() { + return &context_lock_; +} + +const gpu::Capabilities& VizProcessContextProvider::ContextCapabilities() + const { + return context_->GetCapabilities(); +} + +const gpu::GpuFeatureInfo& VizProcessContextProvider::GetGpuFeatureInfo() + const { + return context_->GetGpuFeatureInfo(); +} + +void VizProcessContextProvider::AddObserver(ContextLostObserver* obs) {} + +void VizProcessContextProvider::RemoveObserver(ContextLostObserver* obs) {} + +uint32_t VizProcessContextProvider::GetCopyTextureInternalFormat() { + if (attributes_.alpha_size > 0) + return GL_RGBA; + DCHECK_NE(attributes_.red_size, 0); + DCHECK_NE(attributes_.green_size, 0); + DCHECK_NE(attributes_.blue_size, 0); + return GL_RGB; +} + +void VizProcessContextProvider::SetUpdateVSyncParametersCallback( + const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback& + callback) { + context_->SetUpdateVSyncParametersCallback(callback); +} + +} // namespace viz diff --git a/chromium/components/viz/service/display_embedder/viz_process_context_provider.h b/chromium/components/viz/service/display_embedder/viz_process_context_provider.h new file mode 100644 index 00000000000..a25423e16fe --- /dev/null +++ b/chromium/components/viz/service/display_embedder/viz_process_context_provider.h @@ -0,0 +1,87 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_ +#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_ + +#include <stdint.h> + +#include <memory> + +#include "base/compiler_specific.h" +#include "base/synchronization/lock.h" +#include "components/viz/common/gpu/context_cache_controller.h" +#include "components/viz/common/gpu/context_provider.h" +#include "components/viz/service/viz_service_export.h" +#include "gpu/command_buffer/common/context_creation_attribs.h" +#include "gpu/ipc/in_process_command_buffer.h" +#include "ui/gfx/native_widget_types.h" + +class GrContext; + +namespace gpu { +class GLInProcessContext; +class GpuChannelManagerDelegate; +class GpuMemoryBufferManager; +class ImageFactory; +struct SharedMemoryLimits; +} // namespace gpu + +namespace skia_bindings { +class GrContextForGLES2Interface; +} + +namespace viz { + +// A ContextProvider used in the viz process to setup an InProcessCommandBuffer +// for the display compositor. +class VIZ_SERVICE_EXPORT VizProcessContextProvider + : public base::RefCountedThreadSafe<VizProcessContextProvider>, + public ContextProvider { + public: + VizProcessContextProvider( + scoped_refptr<gpu::InProcessCommandBuffer::Service> service, + gpu::SurfaceHandle surface_handle, + gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, + gpu::ImageFactory* image_factory, + gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate, + const gpu::SharedMemoryLimits& limits); + + // ContextProvider implementation. + void AddRef() const override; + void Release() const override; + gpu::ContextResult BindToCurrentThread() override; + gpu::gles2::GLES2Interface* ContextGL() override; + gpu::ContextSupport* ContextSupport() override; + class GrContext* GrContext() override; + ContextCacheController* CacheController() override; + base::Lock* GetLock() override; + const gpu::Capabilities& ContextCapabilities() const override; + const gpu::GpuFeatureInfo& GetGpuFeatureInfo() const override; + void AddObserver(ContextLostObserver* obs) override; + void RemoveObserver(ContextLostObserver* obs) override; + + uint32_t GetCopyTextureInternalFormat(); + + void SetUpdateVSyncParametersCallback( + const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback& + callback); + + protected: + friend class base::RefCountedThreadSafe<VizProcessContextProvider>; + ~VizProcessContextProvider() override; + + private: + const gpu::ContextCreationAttribs attributes_; + + base::Lock context_lock_; + std::unique_ptr<gpu::GLInProcessContext> context_; + gpu::ContextResult context_result_; + std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_; + std::unique_ptr<ContextCacheController> cache_controller_; +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_ diff --git a/chromium/components/viz/service/frame_sinks/DEPS b/chromium/components/viz/service/frame_sinks/DEPS index 90500834623..5d7cb869719 100644 --- a/chromium/components/viz/service/frame_sinks/DEPS +++ b/chromium/components/viz/service/frame_sinks/DEPS @@ -2,7 +2,6 @@ include_rules = [ "+cc/base", - "+cc/ipc", "+cc/scheduler", "+components/viz/service/display", "+components/viz/service/display_embedder", @@ -11,3 +10,9 @@ include_rules = [ "+gpu/ipc/common", "+mojo/public", ] + +specific_include_rules = { + ".*unittest\.cc": [ + "+third_party/khronos/GLES2", + ] +} diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc index 052ac635cd0..b086112b6b0 100644 --- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc +++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc @@ -41,10 +41,33 @@ void CompositorFrameSinkImpl::SetWantsAnimateOnlyBeginFrames() { void CompositorFrameSinkImpl::SubmitCompositorFrame( const LocalSurfaceId& local_surface_id, CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list, + base::Optional<HitTestRegionList> hit_test_region_list, uint64_t submit_time) { + SubmitCompositorFrameInternal(local_surface_id, std::move(frame), + std::move(hit_test_region_list), submit_time, + SubmitCompositorFrameSyncCallback()); +} + +void CompositorFrameSinkImpl::SubmitCompositorFrameSync( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time, + SubmitCompositorFrameSyncCallback callback) { + SubmitCompositorFrameInternal(local_surface_id, std::move(frame), + std::move(hit_test_region_list), submit_time, + std::move(callback)); +} + +void CompositorFrameSinkImpl::SubmitCompositorFrameInternal( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback callback) { const auto result = support_->MaybeSubmitCompositorFrame( - local_surface_id, std::move(frame), std::move(hit_test_region_list)); + local_surface_id, std::move(frame), std::move(hit_test_region_list), + std::move(callback)); if (result == CompositorFrameSinkSupport::ACCEPTED) return; diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h index a03e101cc88..b05aaea3d51 100644 --- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h +++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h @@ -30,16 +30,30 @@ class CompositorFrameSinkImpl : public mojom::CompositorFrameSink { // mojom::CompositorFrameSink: void SetNeedsBeginFrame(bool needs_begin_frame) override; void SetWantsAnimateOnlyBeginFrames() override; - void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id, - CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list, - uint64_t submit_time) override; + void SubmitCompositorFrame( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time) override; + void SubmitCompositorFrameSync( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time, + SubmitCompositorFrameSyncCallback callback) override; void DidNotProduceFrame(const BeginFrameAck& begin_frame_ack) override; void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer, const SharedBitmapId& id) override; void DidDeleteSharedBitmap(const SharedBitmapId& id) override; private: + void SubmitCompositorFrameInternal( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback); + void OnClientConnectionLost(); mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client_; 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 4d98fd2eaf2..44baa1dae5e 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 @@ -44,6 +44,8 @@ CompositorFrameSinkSupport::~CompositorFrameSinkSupport() { // Unregister |this| as a BeginFrameObserver so that the // BeginFrameSource does not call into |this| after it's deleted. + callback_received_begin_frame_ = true; + callback_received_receive_ack_ = true; SetNeedsBeginFrame(false); // For display root surfaces the surface is no longer going to be visible. @@ -207,7 +209,7 @@ void CompositorFrameSinkSupport::EvictLastActivatedSurface() { } void CompositorFrameSinkSupport::SetNeedsBeginFrame(bool needs_begin_frame) { - needs_begin_frame_ = needs_begin_frame; + client_needs_begin_frame_ = needs_begin_frame; UpdateNeedsBeginFramesInternal(); } @@ -239,10 +241,11 @@ void CompositorFrameSinkSupport::DidNotProduceFrame(const BeginFrameAck& ack) { void CompositorFrameSinkSupport::SubmitCompositorFrame( const LocalSurfaceId& local_surface_id, CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list, + base::Optional<HitTestRegionList> hit_test_region_list, uint64_t submit_time) { const auto result = MaybeSubmitCompositorFrame( - local_surface_id, std::move(frame), std::move(hit_test_region_list)); + local_surface_id, std::move(frame), std::move(hit_test_region_list), + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); DCHECK_EQ(result, ACCEPTED); } @@ -267,13 +270,24 @@ CompositorFrameSinkSupport::SubmitResult CompositorFrameSinkSupport::MaybeSubmitCompositorFrame( const LocalSurfaceId& local_surface_id, CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list) { + base::Optional<HitTestRegionList> hit_test_region_list, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback callback) { TRACE_EVENT1("viz", "CompositorFrameSinkSupport::MaybeSubmitCompositorFrame", "FrameSinkId", frame_sink_id_.ToString()); DCHECK(local_surface_id.is_valid()); DCHECK(!frame.render_pass_list.empty()); DCHECK(!frame.size_in_pixels().IsEmpty()); + CHECK(callback_received_begin_frame_); + CHECK(callback_received_receive_ack_); + + compositor_frame_callback_ = std::move(callback); + if (compositor_frame_callback_) { + callback_received_begin_frame_ = false; + callback_received_receive_ack_ = false; + UpdateNeedsBeginFramesInternal(); + } + // Ensure no CopyOutputRequests have been submitted if they are banned. if (!allow_copy_output_requests_ && frame.HasCopyOutputRequests()) { TRACE_EVENT_INSTANT0("viz", "CopyOutputRequests not allowed", @@ -296,7 +310,7 @@ CompositorFrameSinkSupport::MaybeSubmitCompositorFrame( for (ui::LatencyInfo& latency : frame.metadata.latency_info) { if (latency.latency_components().size() > 0) { latency.AddLatencyNumber(ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT, - 0, 0); + 0); } } @@ -422,12 +436,31 @@ SurfaceReference CompositorFrameSinkSupport::MakeTopLevelRootReference( return SurfaceReference(surface_manager_->GetRootSurfaceId(), surface_id); } +void CompositorFrameSinkSupport::HandleCallback() { + if (!compositor_frame_callback_ || !callback_received_begin_frame_ || + !callback_received_receive_ack_) { + return; + } + + std::move(compositor_frame_callback_) + .Run(std::move(surface_returned_resources_)); + surface_returned_resources_.clear(); +} + void CompositorFrameSinkSupport::DidReceiveCompositorFrameAck() { DCHECK_GT(ack_pending_count_, 0); ack_pending_count_--; if (!client_) return; + // If we have a callback, we only return the resource on onBeginFrame. + if (compositor_frame_callback_) { + callback_received_receive_ack_ = true; + UpdateNeedsBeginFramesInternal(); + HandleCallback(); + return; + } + client_->DidReceiveCompositorFrameAck(surface_returned_resources_); surface_returned_resources_.clear(); } @@ -449,11 +482,17 @@ void CompositorFrameSinkSupport::DidPresentCompositorFrame( } void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) { - UpdateNeedsBeginFramesInternal(); if (last_activated_surface_id_.is_valid()) surface_manager_->SurfaceDamageExpected(last_activated_surface_id_, args); last_begin_frame_args_ = args; - if (client_) + + if (compositor_frame_callback_) { + callback_received_begin_frame_ = true; + UpdateNeedsBeginFramesInternal(); + HandleCallback(); + } + + if (client_ && client_needs_begin_frame_) client_->OnBeginFrame(args); } @@ -471,11 +510,17 @@ void CompositorFrameSinkSupport::UpdateNeedsBeginFramesInternal() { if (!begin_frame_source_) return; - if (needs_begin_frame_ == added_frame_observer_) + // We require a begin frame if there's a callback pending, or if the client + // requested it. + bool needs_begin_frame = + client_needs_begin_frame_ || + (compositor_frame_callback_ && !callback_received_begin_frame_); + + if (needs_begin_frame == added_frame_observer_) return; - added_frame_observer_ = needs_begin_frame_; - if (needs_begin_frame_) + added_frame_observer_ = needs_begin_frame; + if (needs_begin_frame) begin_frame_source_->AddObserver(this); else begin_frame_source_->RemoveObserver(this); @@ -507,6 +552,7 @@ gfx::Size CompositorFrameSinkSupport::GetActiveFrameSize() { if (last_activated_surface_id_.is_valid()) { Surface* current_surface = surface_manager_->GetSurfaceForId(last_activated_surface_id_); + DCHECK(current_surface); if (current_surface->HasActiveFrame()) { DCHECK(current_surface->GetActiveFrame().size_in_pixels() == current_surface->size_in_pixels()); @@ -528,6 +574,16 @@ void CompositorFrameSinkSupport::RequestCopyOfOutput( } } +const CompositorFrameMetadata* +CompositorFrameSinkSupport::GetLastActivatedFrameMetadata() { + if (!last_activated_surface_id_.is_valid()) + return nullptr; + Surface* surface = + surface_manager_->GetSurfaceForId(last_activated_surface_id_); + DCHECK(surface); + return &surface->GetActiveFrame().metadata; +} + HitTestAggregator* CompositorFrameSinkSupport::GetHitTestAggregator() { DCHECK(is_root_); return hit_test_aggregator_.get(); @@ -554,11 +610,12 @@ const char* CompositorFrameSinkSupport::GetSubmitResultAsString( void CompositorFrameSinkSupport::OnAggregatedDamage( const LocalSurfaceId& local_surface_id, - const gfx::Size& frame_size_in_pixels, + const CompositorFrame& frame, const gfx::Rect& damage_rect, base::TimeTicks expected_display_time) const { DCHECK(!damage_rect.IsEmpty()); + const gfx::Size& frame_size_in_pixels = frame.size_in_pixels(); if (aggregated_damage_callback_) { aggregated_damage_callback_.Run(local_surface_id, frame_size_in_pixels, damage_rect, expected_display_time); @@ -566,7 +623,7 @@ void CompositorFrameSinkSupport::OnAggregatedDamage( for (CapturableFrameSink::Client* client : capture_clients_) { client->OnFrameDamaged(frame_size_in_pixels, damage_rect, - expected_display_time); + expected_display_time, frame.metadata); } } diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h index 863b4b8b998..8317b21c9e6 100644 --- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h +++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h @@ -11,6 +11,7 @@ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/time/time.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" #include "components/viz/common/quads/compositor_frame.h" @@ -110,7 +111,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport void SubmitCompositorFrame( const LocalSurfaceId& local_surface_id, CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list = nullptr, + base::Optional<HitTestRegionList> hit_test_region_list = base::nullopt, uint64_t submit_time = 0); // Returns false if the notification was not valid (a duplicate). bool DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer, @@ -130,7 +131,8 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport SubmitResult MaybeSubmitCompositorFrame( const LocalSurfaceId& local_surface_id, CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list); + base::Optional<HitTestRegionList> hit_test_region_list, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback); // CapturableFrameSink implementation. void AttachCaptureClient(CapturableFrameSink::Client* client) override; @@ -138,6 +140,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport gfx::Size GetActiveFrameSize() override; void RequestCopyOfOutput(const LocalSurfaceId& local_surface_id, std::unique_ptr<CopyOutputRequest> request) override; + const CompositorFrameMetadata* GetLastActivatedFrameMetadata() override; HitTestAggregator* GetHitTestAggregator(); @@ -183,10 +186,14 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport Surface* CreateSurface(const SurfaceInfo& surface_info); void OnAggregatedDamage(const LocalSurfaceId& local_surface_id, - const gfx::Size& frame_size_in_pixels, + const CompositorFrame& frame, const gfx::Rect& damage_rect, base::TimeTicks expected_display_time) const; + // For the sync API calls, if we are blocking a client callback, runs it once + // BeginFrame and FrameAck are done. + void HandleCallback(); + mojom::CompositorFrameSinkClient* const client_; FrameSinkManagerImpl* const frame_sink_manager_; @@ -218,7 +225,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport BeginFrameArgs last_begin_frame_args_; // Whether a request for begin frames has been issued. - bool needs_begin_frame_ = false; + bool client_needs_begin_frame_ = false; // Whether or not a frame observer has been added. bool added_frame_observer_ = false; @@ -263,6 +270,11 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport std::vector<std::pair<LocalSurfaceId, std::unique_ptr<CopyOutputRequest>>> copy_output_requests_; + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback + compositor_frame_callback_; + bool callback_received_begin_frame_ = true; + bool callback_received_receive_ack_ = true; + base::WeakPtrFactory<CompositorFrameSinkSupport> weak_factory_; DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupport); 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 f9d67412f48..9852c9b2f18 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 @@ -5,7 +5,6 @@ #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h" #include "base/macros.h" -#include "cc/resources/resource_provider.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" @@ -23,6 +22,7 @@ #include "services/viz/public/interfaces/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; @@ -70,13 +70,7 @@ class MockFrameSinkManagerClient : public mojom::FrameSinkManagerClient { MOCK_METHOD1(OnFirstSurfaceActivation, void(const SurfaceInfo&)); void OnAggregatedHitTestRegionListUpdated( const FrameSinkId& frame_sink_id, - mojo::ScopedSharedBufferHandle active_handle, - uint32_t active_handle_size, - mojo::ScopedSharedBufferHandle idle_handle, - uint32_t idle_handle_sizes) override {} - void SwitchActiveAggregatedHitTestRegionList( - const FrameSinkId& frame_sink_id, - uint8_t active_handle_index) override {} + const std::vector<AggregatedHitTestRegion>& hit_test_data) override {} void OnFrameTokenChanged(const FrameSinkId& frame_sink_id, uint32_t frame_token) override {} @@ -130,7 +124,8 @@ class CompositorFrameSinkSupportTest : public testing::Test { auto frame = MakeDefaultCompositorFrame(); frame.render_pass_list.back()->copy_requests.push_back(std::move(request)); const auto result = support_->MaybeSubmitCompositorFrame( - local_surface_id_, std::move(frame), nullptr); + local_surface_id_, std::move(frame), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); switch (result) { case CompositorFrameSinkSupport::ACCEPTED: return true; @@ -540,22 +535,28 @@ TEST_F(CompositorFrameSinkSupportTest, MonotonicallyIncreasingLocalSurfaceIds) { LocalSurfaceId local_surface_id5(8, 1, kArbitraryToken); LocalSurfaceId local_surface_id6(9, 3, kArbitraryToken); auto result = support->MaybeSubmitCompositorFrame( - local_surface_id1, MakeDefaultCompositorFrame(), nullptr); + local_surface_id1, MakeDefaultCompositorFrame(), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result); result = support->MaybeSubmitCompositorFrame( - local_surface_id2, MakeDefaultCompositorFrame(), nullptr); + local_surface_id2, MakeDefaultCompositorFrame(), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result); result = support->MaybeSubmitCompositorFrame( - local_surface_id3, MakeDefaultCompositorFrame(), nullptr); + local_surface_id3, MakeDefaultCompositorFrame(), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result); result = support->MaybeSubmitCompositorFrame( - local_surface_id4, MakeDefaultCompositorFrame(), nullptr); + local_surface_id4, MakeDefaultCompositorFrame(), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result); result = support->MaybeSubmitCompositorFrame( - local_surface_id5, MakeDefaultCompositorFrame(), nullptr); + local_surface_id5, MakeDefaultCompositorFrame(), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result); result = support->MaybeSubmitCompositorFrame( - local_surface_id6, MakeDefaultCompositorFrame(), nullptr); + local_surface_id6, MakeDefaultCompositorFrame(), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result); manager_.InvalidateFrameSinkId(kAnotherArbitraryFrameSinkId); @@ -775,7 +776,8 @@ TEST_F(CompositorFrameSinkSupportTest, ZeroDeviceScaleFactor) { .SetDeviceScaleFactor(0.f) .Build(); const auto result = support_->MaybeSubmitCompositorFrame( - local_surface_id_, std::move(frame), nullptr); + local_surface_id_, std::move(frame), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result); EXPECT_FALSE(GetSurfaceForId(id)); } @@ -789,8 +791,9 @@ TEST_F(CompositorFrameSinkSupportTest, FrameSizeMismatch) { auto frame = CompositorFrameBuilder() .AddRenderPass(gfx::Rect(5, 5), gfx::Rect()) .Build(); - auto result = support_->MaybeSubmitCompositorFrame(local_surface_id_, - std::move(frame), nullptr); + auto result = support_->MaybeSubmitCompositorFrame( + local_surface_id_, std::move(frame), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result); EXPECT_TRUE(GetSurfaceForId(id)); @@ -799,8 +802,9 @@ TEST_F(CompositorFrameSinkSupportTest, FrameSizeMismatch) { frame = CompositorFrameBuilder() .AddRenderPass(gfx::Rect(5, 4), gfx::Rect()) .Build(); - result = support_->MaybeSubmitCompositorFrame(local_surface_id_, - std::move(frame), nullptr); + result = support_->MaybeSubmitCompositorFrame( + local_surface_id_, std::move(frame), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result); } @@ -815,8 +819,9 @@ TEST_F(CompositorFrameSinkSupportTest, DeviceScaleFactorMismatch) { .AddDefaultRenderPass() .SetDeviceScaleFactor(0.5f) .Build(); - auto result = support_->MaybeSubmitCompositorFrame(local_surface_id_, - std::move(frame), nullptr); + auto result = support_->MaybeSubmitCompositorFrame( + local_surface_id_, std::move(frame), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result); EXPECT_TRUE(GetSurfaceForId(id)); @@ -826,8 +831,9 @@ TEST_F(CompositorFrameSinkSupportTest, DeviceScaleFactorMismatch) { .AddDefaultRenderPass() .SetDeviceScaleFactor(0.4f) .Build(); - result = support_->MaybeSubmitCompositorFrame(local_surface_id_, - std::move(frame), nullptr); + result = support_->MaybeSubmitCompositorFrame( + local_surface_id_, std::move(frame), base::nullopt, + mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback()); EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result); } diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc index 56be759068b..ed6ac7abfaf 100644 --- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc +++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc @@ -8,6 +8,7 @@ #include "base/bind.h" #include "cc/trees/layer_tree_frame_sink_client.h" +#include "components/viz/common/hit_test/hit_test_region_list.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/surface_draw_quad.h" @@ -30,13 +31,11 @@ DirectLayerTreeFrameSink::DirectLayerTreeFrameSink( scoped_refptr<RasterContextProvider> worker_context_provider, scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - SharedBitmapManager* shared_bitmap_manager, bool use_viz_hit_test) : LayerTreeFrameSink(std::move(context_provider), std::move(worker_context_provider), std::move(compositor_task_runner), - gpu_memory_buffer_manager, - shared_bitmap_manager), + gpu_memory_buffer_manager), frame_sink_id_(frame_sink_id), support_manager_(support_manager), frame_sink_manager_(frame_sink_manager), @@ -90,23 +89,79 @@ void DirectLayerTreeFrameSink::DetachFromClient() { cc::LayerTreeFrameSink::DetachFromClient(); } +static HitTestRegionList CreateHitTestData(const CompositorFrame& frame) { + HitTestRegionList hit_test_region_list; + hit_test_region_list.flags = HitTestRegionFlags::kHitTestMouse | + HitTestRegionFlags::kHitTestTouch | + HitTestRegionFlags::kHitTestMine; + hit_test_region_list.bounds.set_size(frame.size_in_pixels()); + + for (const auto& render_pass : frame.render_pass_list) { + // Skip the render_pass if the transform is not invertible (i.e. it will not + // be able to receive events). + gfx::Transform transform_from_root_target; + if (!render_pass->transform_to_root_target.GetInverse( + &transform_from_root_target)) { + continue; + } + + for (const DrawQuad* quad : render_pass->quad_list) { + if (quad->material == DrawQuad::SURFACE_CONTENT) { + const SurfaceDrawQuad* surface_quad = + SurfaceDrawQuad::MaterialCast(quad); + + // Skip the quad if the FrameSinkId between fallback and primary is not + // the same, because we don't know which FrameSinkId would be used to + // draw this quad. + if (surface_quad->fallback_surface_id.has_value() && + surface_quad->fallback_surface_id->frame_sink_id() != + surface_quad->primary_surface_id.frame_sink_id()) { + continue; + } + + // Skip the quad if the transform is not invertible (i.e. it will not + // be able to receive events). + gfx::Transform target_to_quad_transform; + if (!quad->shared_quad_state->quad_to_target_transform.GetInverse( + &target_to_quad_transform)) { + continue; + } + + hit_test_region_list.regions.emplace_back(); + HitTestRegion* hit_test_region = &hit_test_region_list.regions.back(); + hit_test_region->frame_sink_id = + surface_quad->primary_surface_id.frame_sink_id(); + hit_test_region->flags = HitTestRegionFlags::kHitTestMouse | + HitTestRegionFlags::kHitTestTouch | + HitTestRegionFlags::kHitTestChildSurface; + hit_test_region->rect = surface_quad->rect; + hit_test_region->transform = + target_to_quad_transform * transform_from_root_target; + } + } + } + return hit_test_region_list; +} + void DirectLayerTreeFrameSink::SubmitCompositorFrame(CompositorFrame frame) { DCHECK(frame.metadata.begin_frame_ack.has_damage); DCHECK_LE(BeginFrameArgs::kStartingFrameNumber, frame.metadata.begin_frame_ack.sequence_number); - if (!local_surface_id_.is_valid() || - frame.size_in_pixels() != last_swap_frame_size_ || + if (frame.size_in_pixels() != last_swap_frame_size_ || frame.device_scale_factor() != device_scale_factor_) { - local_surface_id_ = parent_local_surface_id_allocator_.GenerateId(); + parent_local_surface_id_allocator_.GenerateId(); last_swap_frame_size_ = frame.size_in_pixels(); device_scale_factor_ = frame.device_scale_factor(); - display_->SetLocalSurfaceId(local_surface_id_, device_scale_factor_); + display_->SetLocalSurfaceId( + parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId(), + device_scale_factor_); } - auto hit_test_region_list = CreateHitTestData(frame); - support_->SubmitCompositorFrame(local_surface_id_, std::move(frame), - std::move(hit_test_region_list)); + HitTestRegionList hit_test_region_list = CreateHitTestData(frame); + support_->SubmitCompositorFrame( + parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId(), + std::move(frame), std::move(hit_test_region_list)); } void DirectLayerTreeFrameSink::DidNotProduceFrame(const BeginFrameAck& ack) { @@ -153,6 +208,12 @@ void DirectLayerTreeFrameSink::DisplayDidReceiveCALayerParams( display_client_->OnDisplayReceivedCALayerParams(ca_layer_params); } +void DirectLayerTreeFrameSink::DidSwapAfterSnapshotRequestReceived( + const std::vector<ui::LatencyInfo>& latency_info) { + // TODO(samans): Implement this method once the plumbing for latency info also + // works for non-OOP-D. +} + void DirectLayerTreeFrameSink::DidReceiveCompositorFrameAck( const std::vector<ReturnedResource>& resources) { // Submitting a CompositorFrame can synchronously draw and dispatch a frame @@ -204,57 +265,4 @@ void DirectLayerTreeFrameSink::OnContextLost() { // The display will be listening for OnContextLost(). Do nothing here. } -mojom::HitTestRegionListPtr DirectLayerTreeFrameSink::CreateHitTestData( - const CompositorFrame& frame) const { - auto hit_test_region_list = mojom::HitTestRegionList::New(); - hit_test_region_list->flags = - mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine; - hit_test_region_list->bounds.set_size(frame.size_in_pixels()); - - for (const auto& render_pass : frame.render_pass_list) { - // Skip the render_pass if the transform is not invertible (i.e. it will not - // be able to receive events). - gfx::Transform transform_from_root_target; - if (!render_pass->transform_to_root_target.GetInverse( - &transform_from_root_target)) { - continue; - } - - for (const DrawQuad* quad : render_pass->quad_list) { - if (quad->material == DrawQuad::SURFACE_CONTENT) { - const SurfaceDrawQuad* surface_quad = - SurfaceDrawQuad::MaterialCast(quad); - - // Skip the quad if the FrameSinkId between fallback and primary is not - // the same, because we don't know which FrameSinkId would be used to - // draw this quad. - if (surface_quad->fallback_surface_id.has_value() && - surface_quad->fallback_surface_id->frame_sink_id() != - surface_quad->primary_surface_id.frame_sink_id()) { - continue; - } - - // Skip the quad if the transform is not invertible (i.e. it will not - // be able to receive events). - gfx::Transform target_to_quad_transform; - if (!quad->shared_quad_state->quad_to_target_transform.GetInverse( - &target_to_quad_transform)) { - continue; - } - - auto hit_test_region = mojom::HitTestRegion::New(); - hit_test_region->frame_sink_id = - surface_quad->primary_surface_id.frame_sink_id(); - hit_test_region->flags = mojom::kHitTestMouse | mojom::kHitTestTouch | - mojom::kHitTestChildSurface; - hit_test_region->rect = surface_quad->rect; - hit_test_region->transform = - target_to_quad_transform * transform_from_root_target; - hit_test_region_list->regions.push_back(std::move(hit_test_region)); - } - } - } - return hit_test_region_list; -} - } // namespace viz diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h index 1bdfcf37560..a37812702df 100644 --- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h +++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h @@ -6,6 +6,7 @@ #define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_DIRECT_LAYER_TREE_FRAME_SINK_H_ #include "base/macros.h" +#include "base/single_thread_task_runner.h" #include "base/threading/thread_checker.h" #include "cc/trees/layer_tree_frame_sink.h" #include "components/viz/common/frame_sinks/begin_frame_source.h" @@ -16,14 +17,10 @@ #include "services/viz/privileged/interfaces/compositing/display_private.mojom.h" #include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h" -namespace cc { -class LocalSurfaceIdAllocator; -class FrameSinkManagerImpl; -} // namespace cc - namespace viz { class CompositorFrameSinkSupportManager; class Display; +class FrameSinkManagerImpl; // This class submits compositor frames to an in-process Display, with the // client's frame being the root surface of the Display. @@ -45,7 +42,6 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink scoped_refptr<RasterContextProvider> worker_context_provider, scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner, gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - SharedBitmapManager* shared_bitmap_manager, bool use_viz_hit_test); ~DirectLayerTreeFrameSink() override; @@ -65,6 +61,8 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink void DisplayDidDrawAndSwap() override; void DisplayDidReceiveCALayerParams( const gfx::CALayerParams& ca_layer_params) override; + void DidSwapAfterSnapshotRequestReceived( + const std::vector<ui::LatencyInfo>& latency_info) override; private: // mojom::CompositorFrameSinkClient implementation: @@ -86,8 +84,6 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink // ContextLostObserver implementation: void OnContextLost() override; - mojom::HitTestRegionListPtr CreateHitTestData( - const CompositorFrame& frame) const; void DidReceiveCompositorFrameAckInternal( const std::vector<ReturnedResource>& resources); @@ -97,7 +93,6 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink std::unique_ptr<CompositorFrameSinkSupport> support_; const FrameSinkId frame_sink_id_; - LocalSurfaceId local_surface_id_; CompositorFrameSinkSupportManager* const support_manager_; FrameSinkManagerImpl* frame_sink_manager_; ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_; diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc index 2ab44fe66c1..26f1c30b484 100644 --- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc +++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc @@ -86,7 +86,7 @@ class DirectLayerTreeFrameSinkTest : public testing::Test { layer_tree_frame_sink_ = std::make_unique<TestDirectLayerTreeFrameSink>( kArbitraryFrameSinkId, &support_manager_, &frame_sink_manager_, display_.get(), nullptr /* display_client */, context_provider_, - nullptr, task_runner_, &gpu_memory_buffer_manager_, &bitmap_manager_, + nullptr, task_runner_, &gpu_memory_buffer_manager_, false /* use_viz_hit_test */); layer_tree_frame_sink_->BindToClient(&layer_tree_frame_sink_client_); display_->Resize(display_size_); @@ -157,21 +157,6 @@ TEST_F(DirectLayerTreeFrameSinkTest, NoDamageDoesNotTriggerSwapBuffers) { EXPECT_EQ(1u, display_output_surface_->num_sent_frames()); } -TEST_F(DirectLayerTreeFrameSinkTest, SuspendedDoesNotTriggerSwapBuffers) { - SwapBuffersWithDamage(display_rect_); - EXPECT_EQ(1u, display_output_surface_->num_sent_frames()); - display_output_surface_->set_suspended_for_recycle(true); - task_runner_->RunUntilIdle(); - EXPECT_EQ(1u, display_output_surface_->num_sent_frames()); - SwapBuffersWithDamage(display_rect_); - task_runner_->RunUntilIdle(); - EXPECT_EQ(1u, display_output_surface_->num_sent_frames()); - display_output_surface_->set_suspended_for_recycle(false); - SwapBuffersWithDamage(display_rect_); - task_runner_->RunUntilIdle(); - EXPECT_EQ(2u, display_output_surface_->num_sent_frames()); -} - // Test that hit_test_region_list are created correctly for the browser. TEST_F(DirectLayerTreeFrameSinkTest, HitTestRegionList) { RenderPassList pass_list; @@ -200,7 +185,9 @@ TEST_F(DirectLayerTreeFrameSinkTest, HitTestRegionList) { display_.get(), display_->CurrentSurfaceId().frame_sink_id()); EXPECT_TRUE(hit_test_region_list); EXPECT_EQ(display_rect_, hit_test_region_list->bounds); - EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine, + EXPECT_EQ(HitTestRegionFlags::kHitTestMouse | + HitTestRegionFlags::kHitTestTouch | + HitTestRegionFlags::kHitTestMine, hit_test_region_list->flags); EXPECT_FALSE(hit_test_region_list->regions.size()); @@ -276,18 +263,21 @@ TEST_F(DirectLayerTreeFrameSinkTest, HitTestRegionList) { display_.get(), display_->CurrentSurfaceId().frame_sink_id()); EXPECT_TRUE(hit_test_region_list1); EXPECT_EQ(display_rect_, hit_test_region_list1->bounds); - EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine, + EXPECT_EQ(HitTestRegionFlags::kHitTestMouse | + HitTestRegionFlags::kHitTestTouch | + HitTestRegionFlags::kHitTestMine, hit_test_region_list1->flags); EXPECT_EQ(1u, hit_test_region_list1->regions.size()); EXPECT_EQ(child_surface_id.frame_sink_id(), - hit_test_region_list1->regions[0]->frame_sink_id); - EXPECT_EQ( - mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestChildSurface, - hit_test_region_list1->regions[0]->flags); - EXPECT_EQ(gfx::Rect(20, 20), hit_test_region_list1->regions[0]->rect); + hit_test_region_list1->regions[0].frame_sink_id); + EXPECT_EQ(HitTestRegionFlags::kHitTestMouse | + HitTestRegionFlags::kHitTestTouch | + HitTestRegionFlags::kHitTestChildSurface, + hit_test_region_list1->regions[0].flags); + EXPECT_EQ(gfx::Rect(20, 20), hit_test_region_list1->regions[0].rect); gfx::Transform transform2_inverse; EXPECT_TRUE(transform2.GetInverse(&transform2_inverse)); - EXPECT_EQ(transform2_inverse, hit_test_region_list1->regions[0]->transform); + EXPECT_EQ(transform2_inverse, hit_test_region_list1->regions[0].transform); } } // namespace diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc index ac084ea4666..bb147945b45 100644 --- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc +++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc @@ -144,11 +144,13 @@ void FrameSinkManagerImpl::CreateRootCompositorFrameSink( std::move(params->external_begin_frame_controller_client))); } + mojom::DisplayClientPtr display_client(std::move(params->display_client)); + std::unique_ptr<SyntheticBeginFrameSource> begin_frame_source; auto display = display_provider_->CreateDisplay( params->frame_sink_id, params->widget, params->gpu_compositing, - external_begin_frame_controller.get(), params->renderer_settings, - &begin_frame_source); + display_client.get(), external_begin_frame_controller.get(), + params->renderer_settings, &begin_frame_source); // Creating display failed. Drop the CompositorFrameSink message pipes here // and let host send a new request, potential with a different compositing @@ -164,8 +166,7 @@ void FrameSinkManagerImpl::CreateRootCompositorFrameSink( std::move(params->compositor_frame_sink), mojom::CompositorFrameSinkClientPtr( std::move(params->compositor_frame_sink_client)), - std::move(params->display_private), - mojom::DisplayClientPtr(std::move(params->display_client))); + std::move(params->display_private), std::move(display_client)); } void FrameSinkManagerImpl::CreateCompositorFrameSink( @@ -352,25 +353,10 @@ void FrameSinkManagerImpl::OnSurfaceDamageExpected(const SurfaceId& surface_id, void FrameSinkManagerImpl::OnAggregatedHitTestRegionListUpdated( const FrameSinkId& frame_sink_id, - mojo::ScopedSharedBufferHandle active_handle, - uint32_t active_handle_size, - mojo::ScopedSharedBufferHandle idle_handle, - uint32_t idle_handle_size) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - if (client_) { - client_->OnAggregatedHitTestRegionListUpdated( - frame_sink_id, std::move(active_handle), active_handle_size, - std::move(idle_handle), idle_handle_size); - } -} - -void FrameSinkManagerImpl::SwitchActiveAggregatedHitTestRegionList( - const FrameSinkId& frame_sink_id, - uint8_t active_handle_index) { + const std::vector<AggregatedHitTestRegion>& hit_test_data) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); if (client_) { - client_->SwitchActiveAggregatedHitTestRegionList(frame_sink_id, - active_handle_index); + client_->OnAggregatedHitTestRegionListUpdated(frame_sink_id, hit_test_data); } } @@ -526,7 +512,7 @@ bool FrameSinkManagerImpl::ChildContains( void FrameSinkManagerImpl::SubmitHitTestRegionList( const SurfaceId& surface_id, uint64_t frame_index, - mojom::HitTestRegionListPtr hit_test_region_list) { + base::Optional<HitTestRegionList> hit_test_region_list) { hit_test_manager_.SubmitHitTestRegionList(surface_id, frame_index, std::move(hit_test_region_list)); } 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 e4821698459..7f2352e9367 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 @@ -16,6 +16,8 @@ #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" #include "base/threading/thread_checker.h" #include "components/viz/common/constants.h" #include "components/viz/common/surfaces/frame_sink_id.h" @@ -112,13 +114,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl // HitTestAggregatorDelegate implementation: void OnAggregatedHitTestRegionListUpdated( const FrameSinkId& frame_sink_id, - mojo::ScopedSharedBufferHandle active_handle, - uint32_t active_handle_size, - mojo::ScopedSharedBufferHandle idle_handle, - uint32_t idle_handle_size) override; - void SwitchActiveAggregatedHitTestRegionList( - const FrameSinkId& frame_sink_id, - uint8_t active_handle_index) override; + const std::vector<AggregatedHitTestRegion>& hit_test_data) override; // CompositorFrameSinkSupport, hierarchy, and BeginFrameSource can be // registered and unregistered in any order with respect to each other. @@ -152,7 +148,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl void SubmitHitTestRegionList( const SurfaceId& surface_id, uint64_t frame_index, - mojom::HitTestRegionListPtr hit_test_region_list); + base::Optional<HitTestRegionList> hit_test_region_list); // Instantiates |video_detector_| for tests where we simulate the passage of // time. 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 731741e3bec..654022b75a3 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 @@ -103,7 +103,7 @@ void RootCompositorFrameSinkImpl::SetWantsAnimateOnlyBeginFrames() { void RootCompositorFrameSinkImpl::SubmitCompositorFrame( const LocalSurfaceId& local_surface_id, CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list, + base::Optional<HitTestRegionList> hit_test_region_list, uint64_t submit_time) { // Update display when size or local surface id changes. if (support_->last_activated_local_surface_id() != local_surface_id) { @@ -112,7 +112,8 @@ void RootCompositorFrameSinkImpl::SubmitCompositorFrame( } const auto result = support_->MaybeSubmitCompositorFrame( - local_surface_id, std::move(frame), std::move(hit_test_region_list)); + local_surface_id, std::move(frame), std::move(hit_test_region_list), + SubmitCompositorFrameSyncCallback()); if (result == CompositorFrameSinkSupport::ACCEPTED) return; @@ -125,6 +126,15 @@ void RootCompositorFrameSinkImpl::SubmitCompositorFrame( OnClientConnectionLost(); } +void RootCompositorFrameSinkImpl::SubmitCompositorFrameSync( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time, + SubmitCompositorFrameSyncCallback callback) { + NOTIMPLEMENTED(); +} + void RootCompositorFrameSinkImpl::DidNotProduceFrame( const BeginFrameAck& begin_frame_ack) { support_->DidNotProduceFrame(begin_frame_ack); @@ -167,6 +177,11 @@ void RootCompositorFrameSinkImpl::DisplayDidReceiveCALayerParams( display_client_->OnDisplayReceivedCALayerParams(ca_layer_params); } +void RootCompositorFrameSinkImpl::DidSwapAfterSnapshotRequestReceived( + const std::vector<ui::LatencyInfo>& latency_info) { + display_client_->DidSwapAfterSnapshotRequestReceived(latency_info); +} + void RootCompositorFrameSinkImpl::DisplayDidDrawAndSwap() {} void RootCompositorFrameSinkImpl::OnClientConnectionLost() { diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h index c5f72f85568..35295866214 100644 --- a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h +++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h @@ -55,14 +55,21 @@ class RootCompositorFrameSinkImpl : public mojom::CompositorFrameSink, // mojom::CompositorFrameSink: void SetNeedsBeginFrame(bool needs_begin_frame) override; void SetWantsAnimateOnlyBeginFrames() override; - void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id, - CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list, - uint64_t submit_time) override; + void SubmitCompositorFrame( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time) override; void DidNotProduceFrame(const BeginFrameAck& begin_frame_ack) override; void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer, const SharedBitmapId& id) override; void DidDeleteSharedBitmap(const SharedBitmapId& id) override; + void SubmitCompositorFrameSync( + const LocalSurfaceId& local_surface_id, + CompositorFrame frame, + base::Optional<HitTestRegionList> hit_test_region_list, + uint64_t submit_time, + SubmitCompositorFrameSyncCallback callback) override; private: // DisplayClient: @@ -72,6 +79,8 @@ class RootCompositorFrameSinkImpl : public mojom::CompositorFrameSink, void DisplayDidDrawAndSwap() override; void DisplayDidReceiveCALayerParams( const gfx::CALayerParams& ca_layer_params) override; + void DidSwapAfterSnapshotRequestReceived( + const std::vector<ui::LatencyInfo>& latency_info) override; void OnClientConnectionLost(); diff --git a/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc b/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc index 860743d07bc..8b83cea05dd 100644 --- a/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc +++ b/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc @@ -868,16 +868,14 @@ TEST_F(SurfaceSynchronizationTest, LimitLatencyInfo) { const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); const ui::LatencyComponentType latency_type1 = - ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; + ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT; const int64_t latency_id1 = 234; - const int64_t latency_sequence_number1 = 5645432; const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; const int64_t latency_id2 = 31434351; - const int64_t latency_sequence_number2 = 663788; // Submit a frame with latency info ui::LatencyInfo info; - info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); + info.AddLatencyNumber(latency_type1, latency_id1); CompositorFrameBuilder builder; builder.AddDefaultRenderPass(); @@ -897,7 +895,7 @@ TEST_F(SurfaceSynchronizationTest, LimitLatencyInfo) { // Submit another frame with some other latency info and a different // LocalSurfaceId. ui::LatencyInfo info2; - info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); + info2.AddLatencyNumber(latency_type2, latency_id2); builder.AddDefaultRenderPass(); for (int i = 0; i < 60; ++i) @@ -927,16 +925,14 @@ TEST_F(SurfaceSynchronizationTest, const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1); const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2); const ui::LatencyComponentType latency_type1 = - ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; + ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT; const int64_t latency_id1 = 234; - const int64_t latency_sequence_number1 = 5645432; const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; const int64_t latency_id2 = 31434351; - const int64_t latency_sequence_number2 = 663788; // Submit a frame with latency info ui::LatencyInfo info; - info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); + info.AddLatencyNumber(latency_type1, latency_id1); CompositorFrame frame = CompositorFrameBuilder() .AddDefaultRenderPass() @@ -955,7 +951,7 @@ TEST_F(SurfaceSynchronizationTest, // Submit another frame with some other latency info and a different // LocalSurfaceId. ui::LatencyInfo info2; - info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); + info2.AddLatencyNumber(latency_type2, latency_id2); CompositorFrame frame2 = CompositorFrameBuilder() .AddDefaultRenderPass() @@ -987,7 +983,6 @@ TEST_F(SurfaceSynchronizationTest, ui::LatencyInfo::LatencyComponent comp1; EXPECT_TRUE( aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); - EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); EXPECT_TRUE( aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); EXPECT_TRUE(aggregated_latency_info.FindLatency( @@ -1004,16 +999,14 @@ TEST_F(SurfaceSynchronizationTest, const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); const ui::LatencyComponentType latency_type1 = - ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; + ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT; const int64_t latency_id1 = 234; - const int64_t latency_sequence_number1 = 5645432; const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; const int64_t latency_id2 = 31434351; - const int64_t latency_sequence_number2 = 663788; // Submit a frame with no unresolved dependecy. ui::LatencyInfo info; - info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); + info.AddLatencyNumber(latency_type1, latency_id1); CompositorFrame frame = MakeDefaultCompositorFrame(); frame.metadata.latency_info.push_back(info); @@ -1023,7 +1016,7 @@ TEST_F(SurfaceSynchronizationTest, // Submit a frame with unresolved dependencies. ui::LatencyInfo info2; - info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); + info2.AddLatencyNumber(latency_type2, latency_id2); CompositorFrame frame2 = MakeCompositorFrame( {child_id}, empty_surface_ids(), std::vector<TransferableResource>()); @@ -1065,7 +1058,6 @@ TEST_F(SurfaceSynchronizationTest, ui::LatencyInfo::LatencyComponent comp1; EXPECT_TRUE( aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); - EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); EXPECT_TRUE( aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); EXPECT_TRUE(aggregated_latency_info.FindLatency( @@ -1082,16 +1074,14 @@ TEST_F(SurfaceSynchronizationTest, const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1); const ui::LatencyComponentType latency_type1 = - ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT; + ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT; const int64_t latency_id1 = 234; - const int64_t latency_sequence_number1 = 5645432; const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT; const int64_t latency_id2 = 31434351; - const int64_t latency_sequence_number2 = 663788; // Submit a frame with no unresolved dependencies. ui::LatencyInfo info; - info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1); + info.AddLatencyNumber(latency_type1, latency_id1); CompositorFrame frame = MakeDefaultCompositorFrame(); frame.metadata.latency_info.push_back(info); @@ -1108,7 +1098,7 @@ TEST_F(SurfaceSynchronizationTest, // Submit a frame with a new local surface id and with unresolved // dependencies. ui::LatencyInfo info2; - info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2); + info2.AddLatencyNumber(latency_type2, latency_id2); CompositorFrame frame2 = MakeCompositorFrame( {child_id}, empty_surface_ids(), std::vector<TransferableResource>()); @@ -1146,7 +1136,6 @@ TEST_F(SurfaceSynchronizationTest, ui::LatencyInfo::LatencyComponent comp1; EXPECT_TRUE( aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1)); - EXPECT_EQ(latency_sequence_number1, comp1.sequence_number); EXPECT_TRUE( aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr)); EXPECT_TRUE(aggregated_latency_info.FindLatency( diff --git a/chromium/components/viz/service/frame_sinks/video_capture/OWNERS b/chromium/components/viz/service/frame_sinks/video_capture/OWNERS index 02bdb39030f..e837b5fcb0d 100644 --- a/chromium/components/viz/service/frame_sinks/video_capture/OWNERS +++ b/chromium/components/viz/service/frame_sinks/video_capture/OWNERS @@ -1 +1,3 @@ miu@chromium.org + +# COMPONENT: Internals>Media>ScreenCapture diff --git a/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h b/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h index 908d2756891..ed9e14e507f 100644 --- a/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h +++ b/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h @@ -16,6 +16,7 @@ class Rect; namespace viz { +class CompositorFrameMetadata; class CopyOutputRequest; class LocalSurfaceId; @@ -35,9 +36,11 @@ class CapturableFrameSink { // |damage_rect| being the region within that has changed (never empty). // |expected_display_time| indicates when the content change was expected to // appear on the Display. - virtual void OnFrameDamaged(const gfx::Size& frame_size, - const gfx::Rect& damage_rect, - base::TimeTicks expected_display_time) = 0; + virtual void OnFrameDamaged( + const gfx::Size& frame_size, + const gfx::Rect& damage_rect, + base::TimeTicks expected_display_time, + const CompositorFrameMetadata& frame_metadata) = 0; }; virtual ~CapturableFrameSink() = default; @@ -59,6 +62,10 @@ class CapturableFrameSink { virtual void RequestCopyOfOutput( const LocalSurfaceId& local_surface_id, std::unique_ptr<CopyOutputRequest> request) = 0; + + // Returns the CompositorFrameMetadata of the last activated CompositorFrame. + // Return null if no CompositorFrame has activated yet. + virtual const CompositorFrameMetadata* GetLastActivatedFrameMetadata() = 0; }; } // namespace viz 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 c93861ff014..7a8c0af9c0d 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 @@ -311,13 +311,15 @@ void FrameSinkVideoCapturerImpl::RefreshSoon() { } MaybeCaptureFrame(VideoCaptureOracle::kRefreshRequest, - gfx::Rect(oracle_.source_size()), clock_->NowTicks()); + gfx::Rect(oracle_.source_size()), clock_->NowTicks(), + *resolved_target_->GetLastActivatedFrameMetadata()); } void FrameSinkVideoCapturerImpl::OnFrameDamaged( const gfx::Size& frame_size, const gfx::Rect& damage_rect, - base::TimeTicks expected_display_time) { + base::TimeTicks expected_display_time, + const CompositorFrameMetadata& frame_metadata) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(!frame_size.IsEmpty()); DCHECK(!damage_rect.IsEmpty()); @@ -332,13 +334,14 @@ void FrameSinkVideoCapturerImpl::OnFrameDamaged( } MaybeCaptureFrame(VideoCaptureOracle::kCompositorUpdate, damage_rect, - expected_display_time); + expected_display_time, frame_metadata); } void FrameSinkVideoCapturerImpl::MaybeCaptureFrame( VideoCaptureOracle::Event event, const gfx::Rect& damage_rect, - base::TimeTicks event_time) { + base::TimeTicks event_time, + const CompositorFrameMetadata& frame_metadata) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(resolved_target_); @@ -436,6 +439,14 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame( 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()); oracle_.RecordCapture(utilization); const int64_t frame_number = next_capture_frame_number_++; @@ -542,18 +553,11 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame( frame = nullptr; } } else { - // TODO(samans): Avoid doing an extra copy by implementing a method similar - // to ReadI420Planes() that copies directly from GPU memory into shared - // memory. https://crbug.com/822264 + int stride = frame->stride(VideoFrame::kARGBPlane); DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format_); - const SkBitmap& bitmap = result->AsSkBitmap(); - if (bitmap.readyToDraw()) { - SkImageInfo image_info = SkImageInfo::MakeN32( - bitmap.width(), bitmap.height(), kPremul_SkAlphaType); - const int stride = frame->stride(VideoFrame::kARGBPlane); - uint8_t* const pixels = frame->visible_data(VideoFrame::kARGBPlane) + - content_rect.y() * stride + content_rect.x() * 4; - bitmap.readPixels(image_info, pixels, stride, 0, 0); + uint8_t* const pixels = frame->visible_data(VideoFrame::kARGBPlane) + + content_rect.y() * stride + content_rect.x() * 4; + if (result->ReadRGBAPlane(pixels, stride)) { media::LetterboxVideoFrame( frame.get(), gfx::Rect(content_rect.origin(), AdjustSizeForPixelFormat(result->size()))); @@ -643,7 +647,6 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame( info->timestamp = frame->timestamp(); info->metadata = frame->metadata()->GetInternalValues().Clone(); info->pixel_format = frame->format(); - info->storage_type = media::VideoPixelStorage::CPU; info->coded_size = frame->coded_size(); info->visible_rect = frame->visible_rect(); const gfx::Rect update_rect = frame->visible_rect(); diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h index 8dbfb0525ee..c1c552d4b51 100644 --- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h +++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h @@ -17,6 +17,8 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "base/unguessable_token.h" +#include "components/viz/common/frame_sinks/begin_frame_args.h" +#include "components/viz/common/quads/compositor_frame_metadata.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h" #include "components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h" @@ -27,6 +29,7 @@ #include "mojo/public/cpp/bindings/binding.h" #include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/vector2d_f.h" namespace gfx { class Size; @@ -156,14 +159,16 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final // CapturableFrameSink::Client implementation: void OnFrameDamaged(const gfx::Size& frame_size, const gfx::Rect& damage_rect, - base::TimeTicks target_display_time) final; + base::TimeTicks target_display_time, + const CompositorFrameMetadata& frame_metadata) final; // Consults the VideoCaptureOracle to decide whether to capture a frame, // then ensures prerequisites are met before initiating the capture: that // there is a consumer present and that the pipeline is not already full. void MaybeCaptureFrame(media::VideoCaptureOracle::Event event, const gfx::Rect& damage_rect, - base::TimeTicks event_time); + base::TimeTicks event_time, + const CompositorFrameMetadata& frame_metadata); // Extracts the image data from the copy output |result|, populating the // |content_rect| region of a [possibly letterboxed] video |frame|. 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 e5efebcfac0..babe29ca1b1 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 @@ -39,6 +39,29 @@ using testing::Return; namespace viz { namespace { +// Returns true if |frame|'s device scale factor, page scale factor and root +// scroll offset are equal to the expected values. +bool CompareVarsInCompositorFrameMetadata( + const VideoFrame& frame, + 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; +} + // Dummy frame sink ID. constexpr FrameSinkId kFrameSinkId = FrameSinkId(1, 1); @@ -52,6 +75,10 @@ constexpr gfx::Size kSourceSize = gfx::Size(100, 100); // The size of the VideoFrames produced by the capturer. constexpr gfx::Size kCaptureSize = gfx::Size(32, 18); +constexpr float kDefaultDeviceScaleFactor = 1.f; +constexpr float kDefaultPageScaleFactor = 1.f; +constexpr gfx::Vector2dF kDefaultRootScrollOffset = gfx::Vector2dF(0, 0); + // The location of the letterboxed content within each VideoFrame. All pixels // outside of this region should be black. constexpr gfx::Rect kContentRect = gfx::Rect(6, 0, 18, 18); @@ -182,6 +209,12 @@ class SolidColorI420Result : public CopyOutputResult { class FakeCapturableFrameSink : public CapturableFrameSink { public: + FakeCapturableFrameSink() { + metadata_.root_scroll_offset = kDefaultRootScrollOffset; + metadata_.page_scale_factor = kDefaultPageScaleFactor; + metadata_.device_scale_factor = kDefaultDeviceScaleFactor; + } + Client* attached_client() const { return client_; } void AttachCaptureClient(Client* client) override { @@ -216,6 +249,14 @@ class FakeCapturableFrameSink : public CapturableFrameSink { std::move(request), std::move(result))); } + const CompositorFrameMetadata* GetLastActivatedFrameMetadata() override { + return &metadata_; + } + + void set_metadata(const CompositorFrameMetadata& metadata) { + metadata_ = metadata.Clone(); + } + void SetCopyOutputColor(YUVColor color) { color_ = color; } int num_copy_results() const { return results_.size(); } @@ -229,6 +270,7 @@ class FakeCapturableFrameSink : public CapturableFrameSink { private: CapturableFrameSink::Client* client_ = nullptr; YUVColor color_ = {0xde, 0xad, 0xbf}; + CompositorFrameMetadata metadata_; std::vector<base::OnceClosure> results_; }; @@ -335,9 +377,20 @@ class FrameSinkVideoCapturerTest : public testing::Test { task_runner_->FastForwardBy(GetNextVsync() - task_runner_->NowTicks()); } - void NotifyFrameDamaged() { + void NotifyFrameDamaged( + float device_scale_factor = kDefaultDeviceScaleFactor, + float page_scale_factor = kDefaultPageScaleFactor, + gfx::Vector2dF root_scroll_offset = kDefaultRootScrollOffset) { + CompositorFrameMetadata metadata; + + metadata.device_scale_factor = device_scale_factor; + metadata.page_scale_factor = page_scale_factor; + metadata.root_scroll_offset = root_scroll_offset; + + frame_sink_.set_metadata(metadata); + capturer_.OnFrameDamaged(kSourceSize, gfx::Rect(kSourceSize), - GetNextVsync()); + GetNextVsync(), metadata); } void NotifyTargetWentAway() { @@ -363,7 +416,7 @@ class FrameSinkVideoCapturerTest : public testing::Test { }; // Tests that the capturer attaches to a frame sink immediately, in the case -// where the frame sink was already known by the manger. +// where the frame sink was already known by the manager. TEST_F(FrameSinkVideoCapturerTest, ResolvesTargetImmediately) { EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId)) .WillRepeatedly(Return(&frame_sink_)); @@ -857,4 +910,65 @@ TEST_F(FrameSinkVideoCapturerTest, EventuallySendsARefreshFrame) { StopCapture(); } +// Tests that CompositorFrameMetadata variables (|device_scale_factor|, +// |page_scale_factor| and |root_scroll_offset|) are sent along with each frame, +// and refreshes cause variables of the cached CompositorFrameMetadata +// (|last_frame_metadata|) to be used. +TEST_F(FrameSinkVideoCapturerTest, CompositorFrameMetadataReachesConsumer) { + EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId)) + .WillRepeatedly(Return(&frame_sink_)); + capturer_.ChangeTarget(kFrameSinkId); + + MockConsumer consumer; + // Initial refresh frame for starting capture, plus later refresh. + const int num_refresh_frames = 2; + const int num_update_frames = 1; + EXPECT_CALL(consumer, OnFrameCapturedMock(_, _, _)) + .Times(num_refresh_frames + num_update_frames); + EXPECT_CALL(consumer, OnTargetLost(_)).Times(0); + EXPECT_CALL(consumer, OnStopped()).Times(1); + StartCapture(&consumer); + + // With the start, an immediate refresh occurred. Simulate a copy result. + // Expect to see the refresh frame delivered to the consumer, along with + // default metadata values. + int cur_frame_index = 0, expected_frames_count = 1; + frame_sink_.SendCopyOutputResult(cur_frame_index); + EXPECT_EQ(expected_frames_count, consumer.num_frames_received()); + EXPECT_TRUE(CompareVarsInCompositorFrameMetadata( + *(consumer.TakeFrame(cur_frame_index)), kDefaultDeviceScaleFactor, + kDefaultPageScaleFactor, kDefaultRootScrollOffset)); + consumer.SendDoneNotification(cur_frame_index); + + // The metadata used to signal a frame damage and verify that it reaches the + // consumer. + const float kNewDeviceScaleFactor = 3.5; + const float kNewPageScaleFactor = 1.5; + const gfx::Vector2dF kNewRootScrollOffset = gfx::Vector2dF(100, 200); + + // Notify frame damage with new metadata, and expect that the refresh frame + // is delivered to the consumer with this new metadata. + AdvanceClockToNextVsync(); + NotifyFrameDamaged(kNewDeviceScaleFactor, kNewPageScaleFactor, + kNewRootScrollOffset); + frame_sink_.SendCopyOutputResult(++cur_frame_index); + EXPECT_EQ(++expected_frames_count, consumer.num_frames_received()); + EXPECT_TRUE(CompareVarsInCompositorFrameMetadata( + *(consumer.TakeFrame(cur_frame_index)), kNewDeviceScaleFactor, + kNewPageScaleFactor, kNewRootScrollOffset)); + consumer.SendDoneNotification(cur_frame_index); + + // Request a refresh frame. Because the refresh request was made just after + // the last frame capture, the refresh retry timer should be started. + // Expect that the refresh frame is delivered to the consumer with the same + // metadata from the previous frame. + capturer_.RequestRefreshFrame(); + AdvanceClockForRefreshTimer(); + EXPECT_EQ(++expected_frames_count, consumer.num_frames_received()); + EXPECT_TRUE(CompareVarsInCompositorFrameMetadata( + *(consumer.TakeFrame(++cur_frame_index)), kNewDeviceScaleFactor, + kNewPageScaleFactor, kNewRootScrollOffset)); + StopCapture(); +} + } // namespace viz 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 cb888449836..383a616c7c1 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 @@ -207,10 +207,10 @@ bool InterprocessFramePool::CanLogSharedMemoryFailure() { } InterprocessFramePool::PooledBuffer::PooledBuffer() = default; -InterprocessFramePool::PooledBuffer::PooledBuffer(PooledBuffer&& other) = - default; +InterprocessFramePool::PooledBuffer::PooledBuffer( + PooledBuffer&& other) noexcept = default; InterprocessFramePool::PooledBuffer& InterprocessFramePool::PooledBuffer:: -operator=(PooledBuffer&& other) = default; +operator=(PooledBuffer&& other) noexcept = default; InterprocessFramePool::PooledBuffer::~PooledBuffer() = default; } // namespace viz diff --git a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h index f75d9214bfe..c1882e16b23 100644 --- a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h +++ b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h @@ -72,8 +72,8 @@ class VIZ_SERVICE_EXPORT InterprocessFramePool { mojo::ScopedSharedBufferMapping mapping; PooledBuffer(); - PooledBuffer(PooledBuffer&&); - PooledBuffer& operator=(PooledBuffer&&); + PooledBuffer(PooledBuffer&&) noexcept; + PooledBuffer& operator=(PooledBuffer&&) noexcept; ~PooledBuffer(); }; diff --git a/chromium/components/viz/service/frame_sinks/video_detector.h b/chromium/components/viz/service/frame_sinks/video_detector.h index 90e240e39cc..c0119ebb240 100644 --- a/chromium/components/viz/service/frame_sinks/video_detector.h +++ b/chromium/components/viz/service/frame_sinks/video_detector.h @@ -7,6 +7,7 @@ #include <unordered_map> +#include "base/sequenced_task_runner.h" #include "base/time/default_tick_clock.h" #include "base/timer/timer.h" #include "components/viz/common/surfaces/frame_sink_id.h" diff --git a/chromium/components/viz/service/gl/gpu_service_impl.cc b/chromium/components/viz/service/gl/gpu_service_impl.cc index 811eda2f35b..9beb6b89684 100644 --- a/chromium/components/viz/service/gl/gpu_service_impl.cc +++ b/chromium/components/viz/service/gl/gpu_service_impl.cc @@ -17,7 +17,6 @@ #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "components/crash/core/common/crash_key.h" -#include "components/viz/common/gpu/in_process_context_provider.h" #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" #include "gpu/command_buffer/service/gpu_switches.h" #include "gpu/command_buffer/service/scheduler.h" @@ -115,7 +114,10 @@ GpuServiceImpl::GpuServiceImpl( std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread, scoped_refptr<base::SingleThreadTaskRunner> io_runner, const gpu::GpuFeatureInfo& gpu_feature_info, - const gpu::GpuPreferences& gpu_preferences) + const gpu::GpuPreferences& gpu_preferences, + const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu, + const base::Optional<gpu::GpuFeatureInfo>& + gpu_feature_info_for_hardware_gpu) : main_runner_(base::ThreadTaskRunnerHandle::Get()), io_runner_(std::move(io_runner)), watchdog_thread_(std::move(watchdog_thread)), @@ -124,6 +126,8 @@ GpuServiceImpl::GpuServiceImpl( gpu_preferences_(gpu_preferences), gpu_info_(gpu_info), gpu_feature_info_(gpu_feature_info), + gpu_info_for_hardware_gpu_(gpu_info_for_hardware_gpu), + gpu_feature_info_for_hardware_gpu_(gpu_feature_info_for_hardware_gpu), bindings_(std::make_unique<mojo::BindingSet<mojom::GpuService>>()), weak_ptr_factory_(this) { DCHECK(!io_runner_->BelongsToCurrentThread()); @@ -191,7 +195,9 @@ void GpuServiceImpl::InitializeWithHost( gpu::SyncPointManager* sync_point_manager, base::WaitableEvent* shutdown_event) { DCHECK(main_runner_->BelongsToCurrentThread()); - gpu_host->DidInitialize(gpu_info_, gpu_feature_info_); + gpu_host->DidInitialize(gpu_info_, gpu_feature_info_, + gpu_info_for_hardware_gpu_, + gpu_feature_info_for_hardware_gpu_); gpu_host_ = mojom::ThreadSafeGpuHostPtr::Create(gpu_host.PassInterface(), io_runner_); if (!in_host_process()) { @@ -436,13 +442,15 @@ void GpuServiceImpl::GetVideoMemoryUsageStats( } // Currently, this function only supports the Windows platform. -void GpuServiceImpl::GetGpuSupportedRuntimeVersion() { +void GpuServiceImpl::GetGpuSupportedRuntimeVersion( + GetGpuSupportedRuntimeVersionCallback callback) { #if defined(OS_WIN) if (io_runner_->BelongsToCurrentThread()) { + auto wrap_callback = WrapCallback(io_runner_, std::move(callback)); main_runner_->PostTask( FROM_HERE, base::BindOnce(&GpuServiceImpl::GetGpuSupportedRuntimeVersion, - weak_ptr_)); + weak_ptr_, std::move(wrap_callback))); return; } DCHECK(main_runner_->BelongsToCurrentThread()); @@ -453,6 +461,7 @@ void GpuServiceImpl::GetGpuSupportedRuntimeVersion() { DCHECK(command_line->HasSwitch("disable-gpu-sandbox") || in_host_process()); gpu::RecordGpuSupportedRuntimeVersionHistograms(&gpu_info_); + std::move(callback).Run(gpu_info_); if (!in_host_process()) { // The unsandboxed GPU process fulfilled its duty. Rest // in peace. @@ -535,9 +544,6 @@ void GpuServiceImpl::UpdateGpuInfoPlatform( base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); DCHECK(command_line->HasSwitch("disable-gpu-sandbox") || in_host_process()); - gpu::GetGpuSupportedD3DVersion(&gpu_info_); - gpu::GetGpuSupportedVulkanVersion(&gpu_info_); - // We can continue on shutdown here because we're not writing any critical // state in this task. base::PostTaskAndReplyWithResult( @@ -714,12 +720,13 @@ void GpuServiceImpl::DestroyAllChannels() { gpu_channel_manager_->DestroyAllChannels(); } -void GpuServiceImpl::OnBackgrounded() { +void GpuServiceImpl::OnBackgroundCleanup() { // Currently only called on Android. #if defined(OS_ANDROID) if (io_runner_->BelongsToCurrentThread()) { main_runner_->PostTask( - FROM_HERE, base::BindOnce(&GpuServiceImpl::OnBackgrounded, weak_ptr_)); + FROM_HERE, + base::BindOnce(&GpuServiceImpl::OnBackgroundCleanup, weak_ptr_)); return; } DVLOG(1) << "GPU: Performing background cleanup"; @@ -729,6 +736,16 @@ void GpuServiceImpl::OnBackgrounded() { #endif } +void GpuServiceImpl::OnBackgrounded() { + if (watchdog_thread_) + watchdog_thread_->OnBackgrounded(); +} + +void GpuServiceImpl::OnForegrounded() { + if (watchdog_thread_) + watchdog_thread_->OnForegrounded(); +} + void GpuServiceImpl::Crash() { DCHECK(io_runner_->BelongsToCurrentThread()); DVLOG(1) << "GPU: Simulating GPU crash"; diff --git a/chromium/components/viz/service/gl/gpu_service_impl.h b/chromium/components/viz/service/gl/gpu_service_impl.h index a29e320f906..15c1bb76964 100644 --- a/chromium/components/viz/service/gl/gpu_service_impl.h +++ b/chromium/components/viz/service/gl/gpu_service_impl.h @@ -62,7 +62,10 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate, std::unique_ptr<gpu::GpuWatchdogThread> watchdog, scoped_refptr<base::SingleThreadTaskRunner> io_runner, const gpu::GpuFeatureInfo& gpu_feature_info, - const gpu::GpuPreferences& gpu_preferences); + const gpu::GpuPreferences& gpu_preferences, + const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu, + const base::Optional<gpu::GpuFeatureInfo>& + gpu_feature_info_for_hardware_gpu); ~GpuServiceImpl() override; @@ -184,7 +187,8 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate, void GetVideoMemoryUsageStats( GetVideoMemoryUsageStatsCallback callback) override; void RequestCompleteGpuInfo(RequestCompleteGpuInfoCallback callback) override; - void GetGpuSupportedRuntimeVersion() override; + void GetGpuSupportedRuntimeVersion( + GetGpuSupportedRuntimeVersionCallback callback) override; void RequestHDRStatus(RequestHDRStatusCallback callback) override; void LoadedShader(const std::string& key, const std::string& data) override; void DestroyingVideoSurface(int32_t surface_id, @@ -192,7 +196,9 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate, void WakeUpGpu() override; void GpuSwitched() override; void DestroyAllChannels() override; + void OnBackgroundCleanup() override; void OnBackgrounded() override; + void OnForegrounded() override; void Crash() override; void Hang() override; void ThrowJavaException() override; @@ -226,6 +232,11 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate, // Information about general chrome feature support for the GPU. gpu::GpuFeatureInfo gpu_feature_info_; + // 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_; + base::Optional<gpu::GpuFeatureInfo> gpu_feature_info_for_hardware_gpu_; + scoped_refptr<mojom::ThreadSafeGpuHostPtr> gpu_host_; std::unique_ptr<gpu::GpuChannelManager> gpu_channel_manager_; std::unique_ptr<media::MediaGpuChannelManager> media_gpu_channel_manager_; diff --git a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc index c36a072fc58..5120ef5d7f1 100644 --- a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc +++ b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc @@ -8,7 +8,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" -#include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" #include "gpu/config/gpu_info.h" @@ -51,7 +50,8 @@ class GpuServiceTest : public testing::Test { ASSERT_TRUE(io_thread_.Start()); gpu_service_ = std::make_unique<GpuServiceImpl>( gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_.task_runner(), - gpu::GpuFeatureInfo(), gpu::GpuPreferences()); + gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(), + gpu::GpuFeatureInfo()); } void TearDown() override { diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc index 11f6db2762d..d598f2cdb57 100644 --- a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc +++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc @@ -5,7 +5,7 @@ #include "components/viz/service/hit_test/hit_test_aggregator.h" #include "base/metrics/histogram_macros.h" -#include "components/viz/common/hit_test/aggregated_hit_test_region.h" +#include "components/viz/common/hit_test/hit_test_region_list.h" #include "components/viz/service/hit_test/hit_test_aggregator_delegate.h" #include "third_party/skia/include/core/SkMatrix44.h" @@ -25,78 +25,34 @@ HitTestAggregator::HitTestAggregator( initial_region_size_(initial_region_size), incremental_region_size_(initial_region_size), max_region_size_(max_region_size), - weak_ptr_factory_(this) { - AllocateHitTestRegionArray(); -} + weak_ptr_factory_(this) {} HitTestAggregator::~HitTestAggregator() = default; void HitTestAggregator::Aggregate(const SurfaceId& display_surface_id) { DCHECK(referenced_child_regions_.empty()); - AppendRoot(display_surface_id); - referenced_child_regions_.clear(); - Swap(); -} - -void HitTestAggregator::GrowRegionList() { - ResizeHitTestRegionArray(write_size_ + incremental_region_size_); -} - -void HitTestAggregator::Swap() { - SwapHandles(); - if (!handle_replaced_) { - delegate_->SwitchActiveAggregatedHitTestRegionList(root_frame_sink_id_, - active_handle_index_); - return; - } - delegate_->OnAggregatedHitTestRegionListUpdated( - root_frame_sink_id_, - read_handle_->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY), - read_size_, - write_handle_->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY), - write_size_); - active_handle_index_ = 0; - handle_replaced_ = false; -} + // Reset states. + hit_test_data_.clear(); + hit_test_data_capacity_ = initial_region_size_; + hit_test_data_size_ = 0; + hit_test_data_.resize(hit_test_data_capacity_); -void HitTestAggregator::AllocateHitTestRegionArray() { - ResizeHitTestRegionArray(initial_region_size_); - SwapHandles(); - ResizeHitTestRegionArray(initial_region_size_); + AppendRoot(display_surface_id); + referenced_child_regions_.clear(); + SendHitTestData(); } -void HitTestAggregator::ResizeHitTestRegionArray(uint32_t size) { - size_t num_bytes = size * sizeof(AggregatedHitTestRegion); - write_handle_ = mojo::SharedBufferHandle::Create(num_bytes); - DCHECK(write_handle_.is_valid()); - auto new_buffer_ = write_handle_->Map(num_bytes); - DCHECK(new_buffer_); - handle_replaced_ = true; - - AggregatedHitTestRegion* region = (AggregatedHitTestRegion*)new_buffer_.get(); - if (write_size_) - memcpy(region, write_buffer_.get(), write_size_); - else - region[0].child_count = kEndOfList; - - write_size_ = size; - write_buffer_ = std::move(new_buffer_); -} - -void HitTestAggregator::SwapHandles() { - using std::swap; - - swap(read_handle_, write_handle_); - swap(read_size_, write_size_); - swap(read_buffer_, write_buffer_); - active_handle_index_ = !active_handle_index_; +void HitTestAggregator::SendHitTestData() { + hit_test_data_.resize(hit_test_data_size_); + delegate_->OnAggregatedHitTestRegionListUpdated(root_frame_sink_id_, + hit_test_data_); } void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) { SCOPED_UMA_HISTOGRAM_TIMER("Event.VizHitTest.AggregateTime"); - const mojom::HitTestRegionList* hit_test_region_list = + const HitTestRegionList* hit_test_region_list = hit_test_manager_->GetActiveHitTestRegionList( local_surface_id_lookup_delegate_, surface_id.frame_sink_id()); if (!hit_test_region_list) @@ -106,7 +62,7 @@ void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) { size_t region_index = 1; for (const auto& region : hit_test_region_list->regions) { - if (region_index >= write_size_ - 1) + if (region_index >= hit_test_data_capacity_ - 1) break; region_index = AppendRegion(region_index, region); } @@ -117,31 +73,30 @@ void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) { SetRegionAt(0, surface_id.frame_sink_id(), hit_test_region_list->flags, hit_test_region_list->bounds, hit_test_region_list->transform, child_count); - MarkEndAt(region_index); } size_t HitTestAggregator::AppendRegion(size_t region_index, - const mojom::HitTestRegionPtr& region) { + const HitTestRegion& region) { size_t parent_index = region_index++; - if (region_index >= write_size_ - 1) { - if (write_size_ > max_region_size_) { - MarkEndAt(parent_index); + if (region_index >= hit_test_data_capacity_ - 1) { + if (hit_test_data_capacity_ > max_region_size_) { return region_index; } else { - GrowRegionList(); + hit_test_data_capacity_ += incremental_region_size_; + hit_test_data_.resize(hit_test_data_capacity_); } } - uint32_t flags = region->flags; - gfx::Transform transform = region->transform; + uint32_t flags = region.flags; + gfx::Transform transform = region.transform; - if (region->flags & mojom::kHitTestChildSurface) { - if (referenced_child_regions_.count(region->frame_sink_id)) + if (region.flags & HitTestRegionFlags::kHitTestChildSurface) { + if (referenced_child_regions_.count(region.frame_sink_id)) return parent_index; - const mojom::HitTestRegionList* hit_test_region_list = + const HitTestRegionList* hit_test_region_list = hit_test_manager_->GetActiveHitTestRegionList( - local_surface_id_lookup_delegate_, region->frame_sink_id); + local_surface_id_lookup_delegate_, region.frame_sink_id); if (!hit_test_region_list) { // Hit-test data not found with this FrameSinkId. This means that it // failed to find a surface corresponding to this FrameSinkId at surface @@ -149,7 +104,7 @@ size_t HitTestAggregator::AppendRegion(size_t region_index, return parent_index; } - referenced_child_regions_.insert(region->frame_sink_id); + referenced_child_regions_.insert(region.frame_sink_id); // Rather than add a node in the tree for this hit_test_region_list // element we can simplify the tree by merging the flags and transform @@ -161,14 +116,14 @@ size_t HitTestAggregator::AppendRegion(size_t region_index, for (const auto& child_region : hit_test_region_list->regions) { region_index = AppendRegion(region_index, child_region); - if (region_index >= write_size_ - 1) + if (region_index >= hit_test_data_capacity_ - 1) break; } } DCHECK_GE(region_index - parent_index - 1, 0u); int32_t child_count = region_index - parent_index - 1; - SetRegionAt(parent_index, region->frame_sink_id, flags, region->rect, - transform, child_count); + SetRegionAt(parent_index, region.frame_sink_id, flags, region.rect, transform, + child_count); return region_index; } @@ -178,21 +133,9 @@ void HitTestAggregator::SetRegionAt(size_t index, const gfx::Rect& rect, const gfx::Transform& transform, int32_t child_count) { - AggregatedHitTestRegion* regions = - static_cast<AggregatedHitTestRegion*>(write_buffer_.get()); - AggregatedHitTestRegion* element = ®ions[index]; - - element->frame_sink_id = frame_sink_id; - element->flags = flags; - element->rect = rect; - element->child_count = child_count; - element->set_transform(transform); -} - -void HitTestAggregator::MarkEndAt(size_t index) { - AggregatedHitTestRegion* regions = - static_cast<AggregatedHitTestRegion*>(write_buffer_.get()); - regions[index].child_count = kEndOfList; + hit_test_data_[index] = AggregatedHitTestRegion(frame_sink_id, flags, rect, + transform, child_count); + hit_test_data_size_++; } } // namespace viz diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.h b/chromium/components/viz/service/hit_test/hit_test_aggregator.h index 4eb67bb5a48..b4999a0ddcf 100644 --- a/chromium/components/viz/service/hit_test/hit_test_aggregator.h +++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.h @@ -10,19 +10,16 @@ #include "components/viz/service/hit_test/hit_test_manager.h" #include "components/viz/service/surfaces/surface_observer.h" #include "components/viz/service/viz_service_export.h" -#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h" namespace viz { class HitTestAggregatorDelegate; +struct HitTestRegion; // HitTestAggregator assembles the list of HitTestRegion objects that define the // hit test information required for one display. Active HitTestRegionList -// information is obtained from the HitTestManager. The resulting list is made -// available in shared memory and used by HitTestQuery to enable efficient hit -// testing across processes. -// -// This is intended to be created in the viz or GPU process. For mus+ash this -// will be true after the mus process split. +// information is obtained from the HitTestManager. The resulting list is sent +// to HitTestQuery for event targeting. This is intended to be created in the +// viz or GPU process. class VIZ_SERVICE_EXPORT HitTestAggregator { public: // |delegate| owns and outlives HitTestAggregator. @@ -31,71 +28,38 @@ class VIZ_SERVICE_EXPORT HitTestAggregator { HitTestAggregatorDelegate* delegate, LatestLocalSurfaceIdLookupDelegate* local_surface_id_lookup_delegate, const FrameSinkId& frame_sink_id, - uint32_t initial_region_size = 1024, - uint32_t max_region_size = 100 * 1024); + uint32_t initial_region_size = 100, + uint32_t max_region_size = 100 * 100); ~HitTestAggregator(); // Called after surfaces have been aggregated into the DisplayFrame. // In this call HitTestRegionList structures received from active surfaces - // are aggregated into the HitTestRegionList structure in - // shared memory used for event targetting. + // are aggregated into |hit_test_data_|. void Aggregate(const SurfaceId& display_surface_id); - // Called at BeginFrame. Swaps buffers in shared memory and tells its - // delegate. - void Swap(); - private: friend class TestHitTestAggregator; - // Allocates memory for the AggregatedHitTestRegion array. - void AllocateHitTestRegionArray(); - - // Resizes memory for the AggregatedHitTestRegion array. |size| indicates the - // number of elements. - void ResizeHitTestRegionArray(uint32_t size); - - void GrowRegionList(); - void SwapHandles(); + void SendHitTestData(); // Appends the root element to the AggregatedHitTestRegion array. void AppendRoot(const SurfaceId& surface_id); // Appends a |region| to the HitTestRegionList structure to recursively - // build the tree. |region_index| indicates the current index of the end of + // build the tree. |region_index| indicates the current index of the end of // the list. - size_t AppendRegion(size_t region_index, - const mojom::HitTestRegionPtr& region); + size_t AppendRegion(size_t region_index, const HitTestRegion& region); // Populates the HitTestRegion element at the given element |index|. - // Access to the HitTestRegion list is localized to this call - // in order to prevent errors if the array is resized during aggregation. void SetRegionAt(size_t index, const FrameSinkId& frame_sink_id, uint32_t flags, const gfx::Rect& rect, const gfx::Transform& transform, int32_t child_count); - // Marks the element at the given index as the end of list. - void MarkEndAt(size_t index); const HitTestManager* const hit_test_manager_; - mojo::ScopedSharedBufferHandle read_handle_; - mojo::ScopedSharedBufferHandle write_handle_; - - // The number of elements allocated. - uint32_t read_size_ = 0; - uint32_t write_size_ = 0; - - mojo::ScopedSharedBufferMapping read_buffer_; - mojo::ScopedSharedBufferMapping write_buffer_; - - bool handle_replaced_ = false; - - // Can only be 0 or 1 when we only have two buffers. - uint8_t active_handle_index_ = 0; - HitTestAggregatorDelegate* const delegate_; LatestLocalSurfaceIdLookupDelegate* const local_surface_id_lookup_delegate_; @@ -110,6 +74,10 @@ class VIZ_SERVICE_EXPORT HitTestAggregator { const uint32_t incremental_region_size_; const uint32_t max_region_size_; + uint32_t hit_test_data_capacity_ = 0; + uint32_t hit_test_data_size_ = 0; + std::vector<AggregatedHitTestRegion> hit_test_data_; + // This is the set of FrameSinkIds referenced in the aggregation so far, used // to detect cycles. base::flat_set<FrameSinkId> referenced_child_regions_; diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h b/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h index 51b9b338c79..c6b06cc6992 100644 --- a/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h +++ b/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h @@ -5,23 +5,16 @@ #ifndef COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_DELEGATE_H_ #define COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_DELEGATE_H_ +#include "components/viz/common/hit_test/aggregated_hit_test_region.h" + namespace viz { // Used by HitTestAggregator to talk to FrameSinkManagerImpl. class HitTestAggregatorDelegate { public: - // Called if any of the buffer that stores the aggregated hit-test data is - // updated (e.g. destroyed, reallocated etc.). |active_handle| and - // |idle_handle| both must be valid. + // Called to send |hit_test_data| when we receive new data. virtual void OnAggregatedHitTestRegionListUpdated( const FrameSinkId& frame_sink_id, - mojo::ScopedSharedBufferHandle active_handle, - uint32_t active_handle_size, - mojo::ScopedSharedBufferHandle idle_handle, - uint32_t idle_handle_size) = 0; - - virtual void SwitchActiveAggregatedHitTestRegionList( - const FrameSinkId& frame_sink_id, - uint8_t active_handle_index) = 0; + const std::vector<AggregatedHitTestRegion>& hit_test_data) = 0; protected: // The dtor is protected so that HitTestAggregator does not take ownership. diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc index 08135e64416..d59985209db 100644 --- a/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc +++ b/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc @@ -7,6 +7,7 @@ #include <map> #include <memory> +#include "components/viz/common/hit_test/hit_test_region_list.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/host/host_frame_sink_manager.h" @@ -40,34 +41,18 @@ class TestHostFrameSinkManager : public HostFrameSinkManager { void OnAggregatedHitTestRegionListUpdated( const FrameSinkId& frame_sink_id, - mojo::ScopedSharedBufferHandle active_handle, - uint32_t active_handle_size, - mojo::ScopedSharedBufferHandle idle_handle, - uint32_t idle_handle_size) override { - DCHECK(active_handle.is_valid() && idle_handle.is_valid()); + const std::vector<AggregatedHitTestRegion>& hit_test_data) override { buffer_frame_sink_id_ = frame_sink_id; - handle_buffers_[0] = active_handle->Map(active_handle_size * - sizeof(AggregatedHitTestRegion)); - handle_buffers_[1] = - idle_handle->Map(idle_handle_size * sizeof(AggregatedHitTestRegion)); - SwitchActiveAggregatedHitTestRegionList(buffer_frame_sink_id_, 0); + active_list_ = hit_test_data; } - void SwitchActiveAggregatedHitTestRegionList( - const FrameSinkId& frame_sink_id, - uint8_t active_handle_index) override { - active_list_ = static_cast<AggregatedHitTestRegion*>( - handle_buffers_[active_handle_index].get()); - } - - AggregatedHitTestRegion* regions() { return active_list_; } + const std::vector<AggregatedHitTestRegion>& regions() { return active_list_; } const FrameSinkId& buffer_frame_sink_id() { return buffer_frame_sink_id_; } private: FrameSinkId buffer_frame_sink_id_; - mojo::ScopedSharedBufferMapping handle_buffers_[2]; - AggregatedHitTestRegion* active_list_; + std::vector<AggregatedHitTestRegion> active_list_; DISALLOW_COPY_AND_ASSIGN(TestHostFrameSinkManager); }; @@ -83,25 +68,11 @@ class TestFrameSinkManagerImpl : public FrameSinkManagerImpl { void OnAggregatedHitTestRegionListUpdated( const FrameSinkId& frame_sink_id, - mojo::ScopedSharedBufferHandle active_handle, - uint32_t active_handle_size, - mojo::ScopedSharedBufferHandle idle_handle, - uint32_t idle_handle_size) override { - // Do not check if it's on valid thread for tests. - if (host_client_) { - host_client_->OnAggregatedHitTestRegionListUpdated( - frame_sink_id, std::move(active_handle), active_handle_size, - std::move(idle_handle), idle_handle_size); - } - } - - void SwitchActiveAggregatedHitTestRegionList( - const FrameSinkId& frame_sink_id, - uint8_t active_handle_index) override { + const std::vector<AggregatedHitTestRegion>& hit_test_data) override { // Do not check if it's on valid thread for tests. if (host_client_) { - host_client_->SwitchActiveAggregatedHitTestRegionList( - frame_sink_id, active_handle_index); + host_client_->OnAggregatedHitTestRegionListUpdated(frame_sink_id, + hit_test_data); } } @@ -127,28 +98,8 @@ class TestHitTestAggregator final : public HitTestAggregator { frame_sink_id_(frame_sink_id) {} ~TestHitTestAggregator() = default; - int GetRegionCount() const { - AggregatedHitTestRegion* start = - static_cast<AggregatedHitTestRegion*>(read_buffer_.get()); - AggregatedHitTestRegion* end = start; - while (end->child_count != kEndOfList) - end++; - return end - start; - } - int GetHitTestRegionListSize() { return read_size_; } - void SwapHandles() { - delegate_->SwitchActiveAggregatedHitTestRegionList(frame_sink_id_, - active_handle_index_); - } - - void Reset() { - AggregatedHitTestRegion* regions = - static_cast<AggregatedHitTestRegion*>(write_buffer_.get()); - regions[0].child_count = kEndOfList; - - regions = static_cast<AggregatedHitTestRegion*>(read_buffer_.get()); - regions[0].child_count = kEndOfList; - } + int GetRegionCount() const { return hit_test_data_size_; } + int GetHitTestRegionListCapacity() { return hit_test_data_capacity_; } private: const FrameSinkId frame_sink_id_; @@ -187,24 +138,24 @@ class HitTestAggregatorTest : public testing::Test { SurfaceId surface_id = MakeSurfaceId(client_id); client_id++; - auto hit_test_region_list = mojom::HitTestRegionList::New(); - hit_test_region_list->flags = mojom::kHitTestMine; - hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList hit_test_region_list; + hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); for (int i = 0; i < 8; i++) { - auto hit_test_region = mojom::HitTestRegion::New(); - hit_test_region->rect.SetRect(100, 100, 100, 100); + HitTestRegion hit_test_region; + hit_test_region.rect.SetRect(100, 100, 100, 100); SurfaceId child_surface_id = MakeSurfaceId(client_id); - hit_test_region->frame_sink_id = child_surface_id.frame_sink_id(); + hit_test_region.frame_sink_id = child_surface_id.frame_sink_id(); if (depth > 0) { - hit_test_region->flags = mojom::kHitTestChildSurface; + hit_test_region.flags = HitTestRegionFlags::kHitTestChildSurface; client_id = CreateAndSubmitHitTestRegionListWith8Children(client_id, depth - 1); } else { - hit_test_region->flags = mojom::kHitTestMine; + hit_test_region.flags = HitTestRegionFlags::kHitTestMine; } - hit_test_region_list->regions.push_back(std::move(hit_test_region)); + hit_test_region_list.regions.push_back(std::move(hit_test_region)); } if (surface_id.frame_sink_id() == kDisplayFrameSink) { @@ -229,7 +180,7 @@ class HitTestAggregatorTest : public testing::Test { return hit_test_aggregator_.get(); } - AggregatedHitTestRegion* host_regions() { + const std::vector<AggregatedHitTestRegion>& host_regions() { return host_frame_sink_manager_->regions(); } @@ -284,30 +235,26 @@ TEST_F(HitTestAggregatorTest, OneSurface) { SurfaceId display_surface_id = MakeSurfaceId(kDisplayClientId); - auto hit_test_region_list = mojom::HitTestRegionList::New(); - hit_test_region_list->flags = mojom::kHitTestMine; - hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList hit_test_region_list; + hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); support()->SubmitCompositorFrame(display_surface_id.local_surface_id(), MakeDefaultCompositorFrame(), std::move(hit_test_region_list)); local_surface_id_lookup_delegate()->SetSurfaceIdMap(display_surface_id); aggregator->Aggregate(display_surface_id); - aggregator->SwapHandles(); // Expect 1 entry routing all events to the one surface (display root). EXPECT_EQ(aggregator->GetRegionCount(), 1); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - AggregatedHitTestRegion* region = nullptr; - - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, display_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 0); + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, display_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 0); } // One opaque embedder with two regions. @@ -325,22 +272,22 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) { SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_r1 = mojom::HitTestRegion::New(); - e_hit_test_region_r1->frame_sink_id = e_surface_id.frame_sink_id(); - e_hit_test_region_r1->flags = mojom::kHitTestMine; - e_hit_test_region_r1->rect.SetRect(100, 100, 200, 400); + HitTestRegion e_hit_test_region_r1; + e_hit_test_region_r1.frame_sink_id = e_surface_id.frame_sink_id(); + e_hit_test_region_r1.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_r1.rect.SetRect(100, 100, 200, 400); - auto e_hit_test_region_r2 = mojom::HitTestRegion::New(); - e_hit_test_region_r2->frame_sink_id = e_surface_id.frame_sink_id(); - e_hit_test_region_r2->flags = mojom::kHitTestMine; - e_hit_test_region_r2->rect.SetRect(400, 100, 300, 400); + HitTestRegion e_hit_test_region_r2; + e_hit_test_region_r2.frame_sink_id = e_surface_id.frame_sink_id(); + e_hit_test_region_r2.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_r2.rect.SetRect(400, 100, 300, 400); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_r1)); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_r2)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_r1)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_r2)); support()->SubmitCompositorFrame(e_surface_id.local_surface_id(), MakeDefaultCompositorFrame(), @@ -348,30 +295,26 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); EXPECT_EQ(aggregator->GetRegionCount(), 3); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - - AggregatedHitTestRegion* region = nullptr; - - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 2); - - region = ®ions[1]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 400)); - EXPECT_EQ(region->child_count, 0); - region = ®ions[2]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->rect, gfx::Rect(400, 100, 300, 400)); - EXPECT_EQ(region->child_count, 0); + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 2); + + region = host_regions()[1]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 400)); + EXPECT_EQ(region.child_count, 0); + + region = host_regions()[2]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.rect, gfx::Rect(400, 100, 300, 400)); + EXPECT_EQ(region.child_count, 0); } // One embedder with two children. @@ -392,26 +335,26 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) { SurfaceId c1_surface_id = MakeSurfaceId(kDisplayClientId + 1); SurfaceId c2_surface_id = MakeSurfaceId(kDisplayClientId + 2); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_c1 = mojom::HitTestRegion::New(); - e_hit_test_region_c1->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id(); - e_hit_test_region_c1->rect.SetRect(100, 100, 200, 300); + HitTestRegion e_hit_test_region_c1; + e_hit_test_region_c1.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c1.frame_sink_id = c1_surface_id.frame_sink_id(); + e_hit_test_region_c1.rect.SetRect(100, 100, 200, 300); - auto e_hit_test_region_c2 = mojom::HitTestRegion::New(); - e_hit_test_region_c2->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id(); - e_hit_test_region_c2->rect.SetRect(400, 100, 400, 300); + HitTestRegion e_hit_test_region_c2; + e_hit_test_region_c2.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c2.frame_sink_id = c2_surface_id.frame_sink_id(); + e_hit_test_region_c2.rect.SetRect(400, 100, 400, 300); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1)); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c2)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c1)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c2)); - auto c1_hit_test_region_list = mojom::HitTestRegionList::New(); + HitTestRegionList c1_hit_test_region_list; - auto c2_hit_test_region_list = mojom::HitTestRegionList::New(); + HitTestRegionList c2_hit_test_region_list; // Submit in unexpected order. @@ -435,32 +378,28 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(c2_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); EXPECT_EQ(aggregator->GetRegionCount(), 3); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - - AggregatedHitTestRegion* region = nullptr; - - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 2); - - region = ®ions[1]; - EXPECT_EQ(region->flags, mojom::kHitTestChildSurface); - EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 300)); - EXPECT_EQ(region->child_count, 0); - - region = ®ions[2]; - EXPECT_EQ(region->flags, mojom::kHitTestChildSurface); - EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(400, 100, 400, 300)); - EXPECT_EQ(region->child_count, 0); + + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 2); + + region = host_regions()[1]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestChildSurface); + EXPECT_EQ(region.frame_sink_id, c1_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 300)); + EXPECT_EQ(region.child_count, 0); + + region = host_regions()[2]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestChildSurface); + EXPECT_EQ(region.frame_sink_id, c2_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(400, 100, 400, 300)); + EXPECT_EQ(region.child_count, 0); } // Occluded child frame (OOPIF). @@ -481,26 +420,26 @@ TEST_F(HitTestAggregatorTest, OccludedChildFrame) { SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId); SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_div = mojom::HitTestRegion::New(); - e_hit_test_region_div->flags = mojom::kHitTestMine; - e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id(); - e_hit_test_region_div->rect.SetRect(200, 200, 300, 200); + HitTestRegion e_hit_test_region_div; + e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id(); + e_hit_test_region_div.rect.SetRect(200, 200, 300, 200); - auto e_hit_test_region_c = mojom::HitTestRegion::New(); - e_hit_test_region_c->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id(); - e_hit_test_region_c->rect.SetRect(100, 100, 200, 500); + HitTestRegion e_hit_test_region_c; + e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id(); + e_hit_test_region_c.rect.SetRect(100, 100, 200, 500); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div)); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c)); - auto c_hit_test_region_list = mojom::HitTestRegionList::New(); - c_hit_test_region_list->flags = mojom::kHitTestMine; - c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500); + HitTestRegionList c_hit_test_region_list; + c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500); // Submit in unexpected order. auto support2 = std::make_unique<CompositorFrameSinkSupport>( @@ -516,32 +455,30 @@ TEST_F(HitTestAggregatorTest, OccludedChildFrame) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); EXPECT_EQ(aggregator->GetRegionCount(), 3); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - - AggregatedHitTestRegion* region = nullptr; - - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 2); - - region = ®ions[1]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200)); - EXPECT_EQ(region->child_count, 0); - - region = ®ions[2]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags); - EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500)); - EXPECT_EQ(region->child_count, 0); + + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 2); + + region = host_regions()[1]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(200, 200, 300, 200)); + EXPECT_EQ(region.child_count, 0); + + region = host_regions()[2]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestMine, + region.flags); + EXPECT_EQ(region.frame_sink_id, c_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 500)); + EXPECT_EQ(region.child_count, 0); } // Foreground child frame (OOPIF). @@ -563,26 +500,26 @@ TEST_F(HitTestAggregatorTest, ForegroundChildFrame) { SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId); SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_div = mojom::HitTestRegion::New(); - e_hit_test_region_div->flags = mojom::kHitTestMine; - e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id(); - e_hit_test_region_div->rect.SetRect(200, 200, 300, 200); + HitTestRegion e_hit_test_region_div; + e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id(); + e_hit_test_region_div.rect.SetRect(200, 200, 300, 200); - auto e_hit_test_region_c = mojom::HitTestRegion::New(); - e_hit_test_region_c->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id(); - e_hit_test_region_c->rect.SetRect(100, 100, 200, 500); + HitTestRegion e_hit_test_region_c; + e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id(); + e_hit_test_region_c.rect.SetRect(100, 100, 200, 500); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c)); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div)); - auto c_hit_test_region_list = mojom::HitTestRegionList::New(); - c_hit_test_region_list->flags = mojom::kHitTestMine; - c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500); + HitTestRegionList c_hit_test_region_list; + c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500); // Submit in unexpected order. @@ -599,32 +536,30 @@ TEST_F(HitTestAggregatorTest, ForegroundChildFrame) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); EXPECT_EQ(aggregator->GetRegionCount(), 3); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - - AggregatedHitTestRegion* region = nullptr; - - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 2); - - region = ®ions[1]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags); - EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500)); - EXPECT_EQ(region->child_count, 0); - - region = ®ions[2]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200)); - EXPECT_EQ(region->child_count, 0); + + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 2); + + region = host_regions()[1]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestMine, + region.flags); + EXPECT_EQ(region.frame_sink_id, c_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 500)); + EXPECT_EQ(region.child_count, 0); + + region = host_regions()[2]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(200, 200, 300, 200)); + EXPECT_EQ(region.child_count, 0); } // One embedder with a clipped child with a tab and transparent background. @@ -648,42 +583,42 @@ TEST_F(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) { SurfaceId a_surface_id = MakeSurfaceId(kDisplayClientId + 2); SurfaceId b_surface_id = MakeSurfaceId(kDisplayClientId + 3); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_c = mojom::HitTestRegion::New(); - e_hit_test_region_c->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id(); - e_hit_test_region_c->rect.SetRect(300, 100, 1600, 800); - e_hit_test_region_c->transform.Translate(200, 100); + HitTestRegion e_hit_test_region_c; + e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id(); + e_hit_test_region_c.rect.SetRect(300, 100, 1600, 800); + e_hit_test_region_c.transform.Translate(200, 100); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c)); - auto c_hit_test_region_list = mojom::HitTestRegionList::New(); - c_hit_test_region_list->flags = mojom::kHitTestIgnore; - c_hit_test_region_list->bounds.SetRect(0, 0, 1600, 800); + HitTestRegionList c_hit_test_region_list; + c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestIgnore; + c_hit_test_region_list.bounds.SetRect(0, 0, 1600, 800); - auto c_hit_test_region_a = mojom::HitTestRegion::New(); - c_hit_test_region_a->flags = mojom::kHitTestChildSurface; - c_hit_test_region_a->frame_sink_id = a_surface_id.frame_sink_id(); - c_hit_test_region_a->rect.SetRect(0, 0, 200, 100); + HitTestRegion c_hit_test_region_a; + c_hit_test_region_a.flags = HitTestRegionFlags::kHitTestChildSurface; + c_hit_test_region_a.frame_sink_id = a_surface_id.frame_sink_id(); + c_hit_test_region_a.rect.SetRect(0, 0, 200, 100); - auto c_hit_test_region_b = mojom::HitTestRegion::New(); - c_hit_test_region_b->flags = mojom::kHitTestChildSurface; - c_hit_test_region_b->frame_sink_id = b_surface_id.frame_sink_id(); - c_hit_test_region_b->rect.SetRect(0, 100, 800, 600); + HitTestRegion c_hit_test_region_b; + c_hit_test_region_b.flags = HitTestRegionFlags::kHitTestChildSurface; + c_hit_test_region_b.frame_sink_id = b_surface_id.frame_sink_id(); + c_hit_test_region_b.rect.SetRect(0, 100, 800, 600); - c_hit_test_region_list->regions.push_back(std::move(c_hit_test_region_a)); - c_hit_test_region_list->regions.push_back(std::move(c_hit_test_region_b)); + c_hit_test_region_list.regions.push_back(std::move(c_hit_test_region_a)); + c_hit_test_region_list.regions.push_back(std::move(c_hit_test_region_b)); - auto a_hit_test_region_list = mojom::HitTestRegionList::New(); - a_hit_test_region_list->flags = mojom::kHitTestMine; - a_hit_test_region_list->bounds.SetRect(0, 0, 200, 100); + HitTestRegionList a_hit_test_region_list; + a_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + a_hit_test_region_list.bounds.SetRect(0, 0, 200, 100); - auto b_hit_test_region_list = mojom::HitTestRegionList::New(); - b_hit_test_region_list->flags = mojom::kHitTestMine; - b_hit_test_region_list->bounds.SetRect(0, 100, 800, 600); + HitTestRegionList b_hit_test_region_list; + b_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + b_hit_test_region_list.bounds.SetRect(0, 100, 800, 600); // Submit in unexpected order. @@ -714,43 +649,45 @@ TEST_F(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); EXPECT_EQ(aggregator->GetRegionCount(), 4); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - AggregatedHitTestRegion* region = nullptr; + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 3); - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 3); - - region = ®ions[1]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestIgnore, region->flags); - EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(300, 100, 1600, 800)); - EXPECT_EQ(region->child_count, 2); + region = host_regions()[1]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestIgnore, + region.flags); + EXPECT_EQ(region.frame_sink_id, c_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(300, 100, 1600, 800)); + EXPECT_EQ(region.child_count, 2); gfx::Point point(300, 300); - gfx::Transform transform(region->transform()); + gfx::Transform transform(region.transform()); transform.TransformPointReverse(&point); EXPECT_TRUE(point == gfx::Point(100, 200)); - region = ®ions[2]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags); - EXPECT_EQ(region->frame_sink_id, a_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 200, 100)); - EXPECT_EQ(region->child_count, 0); - - region = ®ions[3]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags); - EXPECT_EQ(region->frame_sink_id, b_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 100, 800, 600)); - EXPECT_EQ(region->child_count, 0); + region = host_regions()[2]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestMine, + region.flags); + EXPECT_EQ(region.frame_sink_id, a_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 200, 100)); + EXPECT_EQ(region.child_count, 0); + + region = host_regions()[3]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestMine, + region.flags); + EXPECT_EQ(region.frame_sink_id, b_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 100, 800, 600)); + EXPECT_EQ(region.child_count, 0); } // Three children deep. @@ -775,42 +712,42 @@ TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) { SurfaceId c2_surface_id = MakeSurfaceId(kDisplayClientId + 2); SurfaceId c3_surface_id = MakeSurfaceId(kDisplayClientId + 3); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_c1 = mojom::HitTestRegion::New(); - e_hit_test_region_c1->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id(); - e_hit_test_region_c1->rect.SetRect(100, 100, 700, 700); + HitTestRegion e_hit_test_region_c1; + e_hit_test_region_c1.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c1.frame_sink_id = c1_surface_id.frame_sink_id(); + e_hit_test_region_c1.rect.SetRect(100, 100, 700, 700); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c1)); - auto c1_hit_test_region_list = mojom::HitTestRegionList::New(); - c1_hit_test_region_list->flags = mojom::kHitTestMine; - c1_hit_test_region_list->bounds.SetRect(0, 0, 600, 600); + HitTestRegionList c1_hit_test_region_list; + c1_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + c1_hit_test_region_list.bounds.SetRect(0, 0, 600, 600); - auto c1_hit_test_region_c2 = mojom::HitTestRegion::New(); - c1_hit_test_region_c2->flags = mojom::kHitTestChildSurface; - c1_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id(); - c1_hit_test_region_c2->rect.SetRect(100, 100, 500, 500); + HitTestRegion c1_hit_test_region_c2; + c1_hit_test_region_c2.flags = HitTestRegionFlags::kHitTestChildSurface; + c1_hit_test_region_c2.frame_sink_id = c2_surface_id.frame_sink_id(); + c1_hit_test_region_c2.rect.SetRect(100, 100, 500, 500); - c1_hit_test_region_list->regions.push_back(std::move(c1_hit_test_region_c2)); + c1_hit_test_region_list.regions.push_back(std::move(c1_hit_test_region_c2)); - auto c2_hit_test_region_list = mojom::HitTestRegionList::New(); - c2_hit_test_region_list->flags = mojom::kHitTestMine; - c2_hit_test_region_list->bounds.SetRect(0, 0, 400, 400); + HitTestRegionList c2_hit_test_region_list; + c2_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + c2_hit_test_region_list.bounds.SetRect(0, 0, 400, 400); - auto c2_hit_test_region_c3 = mojom::HitTestRegion::New(); - c2_hit_test_region_c3->flags = mojom::kHitTestChildSurface; - c2_hit_test_region_c3->frame_sink_id = c3_surface_id.frame_sink_id(); - c2_hit_test_region_c3->rect.SetRect(100, 100, 300, 300); + HitTestRegion c2_hit_test_region_c3; + c2_hit_test_region_c3.flags = HitTestRegionFlags::kHitTestChildSurface; + c2_hit_test_region_c3.frame_sink_id = c3_surface_id.frame_sink_id(); + c2_hit_test_region_c3.rect.SetRect(100, 100, 300, 300); - c2_hit_test_region_list->regions.push_back(std::move(c2_hit_test_region_c3)); + c2_hit_test_region_list.regions.push_back(std::move(c2_hit_test_region_c3)); - auto c3_hit_test_region_list = mojom::HitTestRegionList::New(); - c3_hit_test_region_list->flags = mojom::kHitTestMine; - c3_hit_test_region_list->bounds.SetRect(0, 0, 200, 200); + HitTestRegionList c3_hit_test_region_list; + c3_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + c3_hit_test_region_list.bounds.SetRect(0, 0, 200, 200); // Submit in unexpected order. @@ -841,38 +778,40 @@ TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(c2_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); EXPECT_EQ(aggregator->GetRegionCount(), 4); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - - AggregatedHitTestRegion* region = nullptr; - - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 3); - - region = ®ions[1]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags); - EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(100, 100, 700, 700)); - EXPECT_EQ(region->child_count, 2); - - region = ®ions[2]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags); - EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(100, 100, 500, 500)); - EXPECT_EQ(region->child_count, 1); - - region = ®ions[3]; - EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags); - EXPECT_EQ(region->frame_sink_id, c3_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(100, 100, 300, 300)); - EXPECT_EQ(region->child_count, 0); + + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 3); + + region = host_regions()[1]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestMine, + region.flags); + EXPECT_EQ(region.frame_sink_id, c1_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(100, 100, 700, 700)); + EXPECT_EQ(region.child_count, 2); + + region = host_regions()[2]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestMine, + region.flags); + EXPECT_EQ(region.frame_sink_id, c2_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(100, 100, 500, 500)); + EXPECT_EQ(region.child_count, 1); + + region = host_regions()[3]; + EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface | + HitTestRegionFlags::kHitTestMine, + region.flags); + EXPECT_EQ(region.frame_sink_id, c3_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(100, 100, 300, 300)); + EXPECT_EQ(region.child_count, 0); } // Missing / late child. @@ -893,26 +832,26 @@ TEST_F(HitTestAggregatorTest, MissingChildFrame) { SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId); SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_div = mojom::HitTestRegion::New(); - e_hit_test_region_div->flags = mojom::kHitTestMine; - e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id(); - e_hit_test_region_div->rect.SetRect(200, 200, 300, 200); + HitTestRegion e_hit_test_region_div; + e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id(); + e_hit_test_region_div.rect.SetRect(200, 200, 300, 200); - auto e_hit_test_region_c = mojom::HitTestRegion::New(); - e_hit_test_region_c->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id(); - e_hit_test_region_c->rect.SetRect(100, 100, 200, 500); + HitTestRegion e_hit_test_region_c; + e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id(); + e_hit_test_region_c.rect.SetRect(100, 100, 200, 500); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c)); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div)); - auto c_hit_test_region_list = mojom::HitTestRegionList::New(); - c_hit_test_region_list->flags = mojom::kHitTestMine; - c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500); + HitTestRegionList c_hit_test_region_list; + c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500); // Submit in unexpected order. @@ -922,27 +861,23 @@ TEST_F(HitTestAggregatorTest, MissingChildFrame) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); // Child c didn't submit any CompositorFrame. Events should go to parent. EXPECT_EQ(aggregator->GetRegionCount(), 2); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - - AggregatedHitTestRegion* region = nullptr; - region = ®ions[0]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768)); - EXPECT_EQ(region->child_count, 1); - - region = ®ions[1]; - EXPECT_EQ(region->flags, mojom::kHitTestMine); - EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id()); - EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200)); - EXPECT_EQ(region->child_count, 0); + AggregatedHitTestRegion region = host_regions()[0]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768)); + EXPECT_EQ(region.child_count, 1); + + region = host_regions()[1]; + EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine); + EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id()); + EXPECT_EQ(region.rect, gfx::Rect(200, 200, 300, 200)); + EXPECT_EQ(region.child_count, 0); } // Exceed limits to ensure that bounds and resize work. @@ -970,14 +905,13 @@ TEST_F(HitTestAggregatorTest, ExceedLimits) { TestHitTestAggregator* aggregator = hit_test_aggregator(); EXPECT_EQ(aggregator->GetRegionCount(), 0); - EXPECT_LT(aggregator->GetHitTestRegionListSize(), 4096); + EXPECT_LT(aggregator->GetHitTestRegionListCapacity(), 4096); SurfaceId display_surface_id = MakeSurfaceId(kDisplayClientId); CreateAndSubmitHitTestRegionListWith8Children(kDisplayClientId, 3); aggregator->Aggregate(display_surface_id); - aggregator->SwapHandles(); // Expect 4680 regions: // 8 children 4 levels deep 8*8*8*8 is 4096 @@ -985,17 +919,10 @@ TEST_F(HitTestAggregatorTest, ExceedLimits) { // 1 root + 1 // ----- // 4681. - EXPECT_GE(aggregator->GetHitTestRegionListSize(), 4681); + EXPECT_GE(aggregator->GetHitTestRegionListCapacity(), 4681); EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink); - AggregatedHitTestRegion* regions = host_regions(); - - uint32_t count = 0; - while (regions->child_count != kEndOfList) { - regions++; - count++; - } - EXPECT_EQ(count, 4681u); + EXPECT_EQ(host_regions().size(), 4681u); } TEST_F(HitTestAggregatorTest, DiscardedSurfaces) { @@ -1004,26 +931,26 @@ TEST_F(HitTestAggregatorTest, DiscardedSurfaces) { SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId); SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1); - auto e_hit_test_region_list = mojom::HitTestRegionList::New(); - e_hit_test_region_list->flags = mojom::kHitTestMine; - e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768); + HitTestRegionList e_hit_test_region_list; + e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768); - auto e_hit_test_region_div = mojom::HitTestRegion::New(); - e_hit_test_region_div->flags = mojom::kHitTestMine; - e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id(); - e_hit_test_region_div->rect.SetRect(200, 200, 300, 200); + HitTestRegion e_hit_test_region_div; + e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine; + e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id(); + e_hit_test_region_div.rect.SetRect(200, 200, 300, 200); - auto e_hit_test_region_c = mojom::HitTestRegion::New(); - e_hit_test_region_c->flags = mojom::kHitTestChildSurface; - e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id(); - e_hit_test_region_c->rect.SetRect(100, 100, 200, 500); + HitTestRegion e_hit_test_region_c; + e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface; + e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id(); + e_hit_test_region_c.rect.SetRect(100, 100, 200, 500); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c)); - e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c)); + e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div)); - auto c_hit_test_region_list = mojom::HitTestRegionList::New(); - c_hit_test_region_list->flags = mojom::kHitTestMine; - c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500); + HitTestRegionList c_hit_test_region_list; + c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine; + c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500); EXPECT_FALSE(hit_test_manager()->GetActiveHitTestRegionList( local_surface_id_lookup_delegate(), e_surface_id.frame_sink_id())); @@ -1045,7 +972,6 @@ TEST_F(HitTestAggregatorTest, DiscardedSurfaces) { local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id); aggregator->Aggregate(e_surface_id); - aggregator->SwapHandles(); EXPECT_TRUE(hit_test_manager()->GetActiveHitTestRegionList( local_surface_id_lookup_delegate(), e_surface_id.frame_sink_id())); diff --git a/chromium/components/viz/service/hit_test/hit_test_manager.cc b/chromium/components/viz/service/hit_test/hit_test_manager.cc index 886ac9f42c3..4f3e7e1ae9d 100644 --- a/chromium/components/viz/service/hit_test/hit_test_manager.cc +++ b/chromium/components/viz/service/hit_test/hit_test_manager.cc @@ -54,17 +54,19 @@ void HitTestManager::OnSurfaceActivated( void HitTestManager::SubmitHitTestRegionList( const SurfaceId& surface_id, const uint64_t frame_index, - mojom::HitTestRegionListPtr hit_test_region_list) { - if (!ValidateHitTestRegionList(surface_id, hit_test_region_list)) + base::Optional<HitTestRegionList> hit_test_region_list) { + if (!hit_test_region_list) + return; + if (!ValidateHitTestRegionList(surface_id, &*hit_test_region_list)) return; // TODO(gklassen): Runtime validation that hit_test_region_list is valid. // TODO(gklassen): Inform FrameSink that the hit_test_region_list is invalid. // TODO(gklassen): FrameSink needs to inform the host of a difficult renderer. hit_test_region_lists_[surface_id][frame_index] = - std::move(hit_test_region_list); + std::move(*hit_test_region_list); } -const mojom::HitTestRegionList* HitTestManager::GetActiveHitTestRegionList( +const HitTestRegionList* HitTestManager::GetActiveHitTestRegionList( LatestLocalSurfaceIdLookupDelegate* delegate, const FrameSinkId& frame_sink_id) const { if (!delegate) @@ -89,23 +91,20 @@ const mojom::HitTestRegionList* HitTestManager::GetActiveHitTestRegionList( if (search2 == frame_index_map.end()) return nullptr; - return search2->second.get(); + return &search2->second; } bool HitTestManager::ValidateHitTestRegionList( const SurfaceId& surface_id, - const mojom::HitTestRegionListPtr& hit_test_region_list) { - if (!hit_test_region_list) - return false; + HitTestRegionList* hit_test_region_list) { if (hit_test_region_list->regions.size() > kMaxRegionsPerSurface) return false; for (auto& region : hit_test_region_list->regions) { // TODO(gklassen): Ensure that |region->frame_sink_id| is a child of // |frame_sink_id|. - if (region->frame_sink_id.client_id() == 0) { - region->frame_sink_id = - FrameSinkId(surface_id.frame_sink_id().client_id(), - region->frame_sink_id.sink_id()); + if (region.frame_sink_id.client_id() == 0) { + region.frame_sink_id = FrameSinkId(surface_id.frame_sink_id().client_id(), + region.frame_sink_id.sink_id()); } } return true; diff --git a/chromium/components/viz/service/hit_test/hit_test_manager.h b/chromium/components/viz/service/hit_test/hit_test_manager.h index 457f846c1bf..ae4ae6064ad 100644 --- a/chromium/components/viz/service/hit_test/hit_test_manager.h +++ b/chromium/components/viz/service/hit_test/hit_test_manager.h @@ -5,6 +5,7 @@ #ifndef COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_MANAGER_H_ #define COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_MANAGER_H_ +#include "base/optional.h" #include "components/viz/common/hit_test/aggregated_hit_test_region.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/service/surfaces/surface_manager.h" @@ -40,22 +41,23 @@ class VIZ_SERVICE_EXPORT HitTestManager : public SurfaceObserver { void SubmitHitTestRegionList( const SurfaceId& surface_id, const uint64_t frame_index, - mojom::HitTestRegionListPtr hit_test_region_list); + base::Optional<HitTestRegionList> hit_test_region_list); // Returns the HitTestRegionList corresponding to the given // |frame_sink_id| and the active CompositorFrame matched by frame_index. - const mojom::HitTestRegionList* GetActiveHitTestRegionList( + // The returned pointer is not stable and should not be stored or used after + // calling any non-const methods on this class. + const HitTestRegionList* GetActiveHitTestRegionList( LatestLocalSurfaceIdLookupDelegate* delegate, const FrameSinkId& frame_sink_id) const; private: - bool ValidateHitTestRegionList( - const SurfaceId& surface_id, - const mojom::HitTestRegionListPtr& hit_test_region_list); + bool ValidateHitTestRegionList(const SurfaceId& surface_id, + HitTestRegionList* hit_test_region_list); SurfaceManager* const surface_manager_; - std::map<SurfaceId, base::flat_map<uint64_t, mojom::HitTestRegionListPtr>> + std::map<SurfaceId, base::flat_map<uint64_t, HitTestRegionList>> hit_test_region_lists_; DISALLOW_COPY_AND_ASSIGN(HitTestManager); diff --git a/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc b/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc index da94df12037..734d626750d 100644 --- a/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc +++ b/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc @@ -14,7 +14,6 @@ #include "components/viz/service/hit_test/hit_test_manager.h" #include "components/viz/test/compositor_frame_helpers.h" #include "components/viz/test/test_latest_local_surface_id_lookup_delegate.h" -#include "mojo/edk/embedder/embedder.h" namespace { @@ -44,7 +43,7 @@ void SubmitHitTestRegionList( const uint32_t depth); void AddHitTestRegion(base::FuzzedDataProvider* fuzz, - std::vector<viz::mojom::HitTestRegionPtr>* regions, + std::vector<viz::HitTestRegion>* regions, uint32_t child_count, viz::TestLatestLocalSurfaceIdLookupDelegate* delegate, viz::FrameSinkManagerImpl* frame_sink_manager, @@ -54,22 +53,22 @@ void AddHitTestRegion(base::FuzzedDataProvider* fuzz, return; // If there's not enough space left for a HitTestRegion, then skip. - if (fuzz->remaining_bytes() < sizeof(viz::mojom::HitTestRegion)) + if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegion)) return; - auto hit_test_region = viz::mojom::HitTestRegion::New(); - hit_test_region->flags = fuzz->ConsumeUint16(); + viz::HitTestRegion hit_test_region; + hit_test_region.flags = fuzz->ConsumeUint16(); if (fuzz->ConsumeBool()) - hit_test_region->flags |= viz::mojom::kHitTestChildSurface; - hit_test_region->frame_sink_id = + hit_test_region.flags |= viz::HitTestRegionFlags::kHitTestChildSurface; + hit_test_region.frame_sink_id = viz::FrameSinkId(fuzz->ConsumeUint8(), fuzz->ConsumeUint8()); - hit_test_region->rect = + hit_test_region.rect = gfx::Rect(fuzz->ConsumeUint8(), fuzz->ConsumeUint8(), fuzz->ConsumeUint16(), fuzz->ConsumeUint16()); - hit_test_region->transform = GetNextTransform(fuzz); + hit_test_region.transform = GetNextTransform(fuzz); if (fuzz->ConsumeBool() && - (hit_test_region->flags & viz::mojom::kHitTestChildSurface)) { + (hit_test_region.flags & viz::HitTestRegionFlags::kHitTestChildSurface)) { // If there's not enough space left for a LocalSurfaceId, then skip. if (fuzz->remaining_bytes() < sizeof(viz::LocalSurfaceId)) return; @@ -100,49 +99,40 @@ void SubmitHitTestRegionList( bool support_is_root, const uint32_t depth) { // If there's not enough space left for a HitTestRegionList, then skip. - if ((fuzz->remaining_bytes() < sizeof(viz::mojom::HitTestRegionList)) || + if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegionList) + sizeof(bool) || depth > kMaxDepthAllowed) { return; } - auto hit_test_region_list = viz::mojom::HitTestRegionList::New(); - hit_test_region_list->flags = fuzz->ConsumeUint16(); - if (fuzz->ConsumeBool()) - hit_test_region_list->flags |= viz::mojom::kHitTestChildSurface; - hit_test_region_list->bounds = - gfx::Rect(fuzz->ConsumeUint8(), fuzz->ConsumeUint8(), - fuzz->ConsumeUint16(), fuzz->ConsumeUint16()); - hit_test_region_list->transform = GetNextTransform(fuzz); - - uint32_t child_count = fuzz->ConsumeUint16(); - AddHitTestRegion(fuzz, &hit_test_region_list->regions, child_count, delegate, - frame_sink_manager, surface_id, depth + 1); + base::Optional<viz::HitTestRegionList> hit_test_region_list; + if (fuzz->ConsumeBool()) { + hit_test_region_list.emplace(); + hit_test_region_list->flags = fuzz->ConsumeUint16(); + if (fuzz->ConsumeBool()) + hit_test_region_list->flags |= + viz::HitTestRegionFlags::kHitTestChildSurface; + hit_test_region_list->bounds = + gfx::Rect(fuzz->ConsumeUint8(), fuzz->ConsumeUint8(), + fuzz->ConsumeUint16(), fuzz->ConsumeUint16()); + hit_test_region_list->transform = GetNextTransform(fuzz); + + uint32_t child_count = fuzz->ConsumeUint16(); + AddHitTestRegion(fuzz, &hit_test_region_list->regions, child_count, + delegate, frame_sink_manager, surface_id, depth + 1); + } delegate->SetSurfaceIdMap(surface_id); viz::CompositorFrameSinkSupport support( nullptr /* client */, frame_sink_manager, surface_id.frame_sink_id(), support_is_root, false /* needs_sync_points */); - support.SubmitCompositorFrame( - surface_id.local_surface_id(), viz::MakeDefaultCompositorFrame(), - fuzz->ConsumeBool() ? std::move(hit_test_region_list) : nullptr); + support.SubmitCompositorFrame(surface_id.local_surface_id(), + viz::MakeDefaultCompositorFrame(), + std::move(hit_test_region_list)); } -class Environment { - public: - Environment() { - // Initialize environment so that we can create the mojo shared memory - // handles. - base::CommandLine::Init(0, nullptr); - mojo::edk::Init(); - } -}; - } // namespace extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t num_bytes) { - // Initialize the environment only once. - static Environment environment; - base::FuzzedDataProvider fuzz(data, num_bytes); viz::FrameSinkManagerImpl frame_sink_manager; viz::TestLatestLocalSurfaceIdLookupDelegate delegate; diff --git a/chromium/components/viz/service/main/viz_main_impl.cc b/chromium/components/viz/service/main/viz_main_impl.cc index 82cb08d85fc..72b26afce32 100644 --- a/chromium/components/viz/service/main/viz_main_impl.cc +++ b/chromium/components/viz/service/main/viz_main_impl.cc @@ -143,7 +143,9 @@ VizMainImpl::VizMainImpl(Delegate* delegate, gpu_service_ = std::make_unique<GpuServiceImpl>( gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(), io_task_runner(), - gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences()); + gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences(), + gpu_init_->gpu_info_for_hardware_gpu(), + gpu_init_->gpu_feature_info_for_hardware_gpu()); } VizMainImpl::~VizMainImpl() { @@ -259,11 +261,10 @@ void VizMainImpl::CreateFrameSinkManagerInternal( DCHECK(gpu_service_); DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread()); - constexpr bool use_virtualized_gl_context = false; gpu_command_service_ = base::MakeRefCounted<gpu::GpuInProcessThreadService>( - use_virtualized_gl_context, gpu_thread_task_runner_, - gpu_service_->sync_point_manager(), gpu_service_->mailbox_manager(), - gpu_service_->share_group(), gpu_service_->gpu_feature_info(), + gpu_thread_task_runner_, gpu_service_->sync_point_manager(), + gpu_service_->mailbox_manager(), gpu_service_->share_group(), + gpu_service_->gpu_feature_info(), gpu_service_->gpu_channel_manager()->gpu_preferences()); compositor_thread_task_runner_->PostTask( @@ -279,7 +280,7 @@ void VizMainImpl::CreateFrameSinkManagerOnCompositorThread( base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); display_provider_ = std::make_unique<GpuDisplayProvider>( - params->restart_id, gpu_command_service_, + params->restart_id, gpu_service_.get(), gpu_command_service_, gpu_service_->gpu_channel_manager(), command_line->HasSwitch(switches::kHeadless), command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw)); diff --git a/chromium/components/viz/service/main/viz_main_impl.h b/chromium/components/viz/service/main/viz_main_impl.h index 96b04e47911..fcb3f5680ba 100644 --- a/chromium/components/viz/service/main/viz_main_impl.h +++ b/chromium/components/viz/service/main/viz_main_impl.h @@ -6,6 +6,7 @@ #define COMPONENTS_VIZ_SERVICE_MAIN_VIZ_MAIN_IMPL_H_ #include "base/power_monitor/power_monitor.h" +#include "base/single_thread_task_runner.h" #include "base/threading/thread.h" #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" #include "gpu/ipc/in_process_command_buffer.h" diff --git a/chromium/components/viz/service/surfaces/surface.cc b/chromium/components/viz/service/surfaces/surface.cc index de5eeb930a3..9f8a1bc373e 100644 --- a/chromium/components/viz/service/surfaces/surface.cc +++ b/chromium/components/viz/service/surfaces/surface.cc @@ -494,8 +494,7 @@ void Surface::NotifyAggregatedDamage(const gfx::Rect& damage_rect, return; active_frame_data_->aggregated_damage_callback.Run( - surface_id().local_surface_id(), - active_frame_data_->frame.size_in_pixels(), damage_rect, + surface_id().local_surface_id(), active_frame_data_->frame, damage_rect, expected_display_time); } diff --git a/chromium/components/viz/service/surfaces/surface.h b/chromium/components/viz/service/surfaces/surface.h index 4d9a63a029f..b0331b956e9 100644 --- a/chromium/components/viz/service/surfaces/surface.h +++ b/chromium/components/viz/service/surfaces/surface.h @@ -72,7 +72,7 @@ class VIZ_SERVICE_EXPORT Surface final : public SurfaceDeadlineClient { public: using AggregatedDamageCallback = base::RepeatingCallback<void(const LocalSurfaceId& local_surface_id, - const gfx::Size& frame_size_in_pixels, + const CompositorFrame& frame, const gfx::Rect& damage_rect, base::TimeTicks expected_display_time)>; using PresentedCallback = diff --git a/chromium/components/viz/service/surfaces/surface_client.h b/chromium/components/viz/service/surfaces/surface_client.h index 7c1fcdd8299..a4d2a6a7a1d 100644 --- a/chromium/components/viz/service/surfaces/surface_client.h +++ b/chromium/components/viz/service/surfaces/surface_client.h @@ -10,14 +10,10 @@ #include "base/macros.h" #include "components/viz/service/viz_service_export.h" -namespace cc { -struct ReturnedResource; -struct TransferableResource; -} // namespace cc - namespace viz { - +struct ReturnedResource; class Surface; +struct TransferableResource; class VIZ_SERVICE_EXPORT SurfaceClient { public: diff --git a/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc index f60a39b08af..4e86b838144 100644 --- a/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc +++ b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc @@ -59,7 +59,7 @@ void SurfaceDependencyDeadline::InheritFrom( } bool SurfaceDependencyDeadline::operator==( - const SurfaceDependencyDeadline& other) { + const SurfaceDependencyDeadline& other) const { return begin_frame_source_ == other.begin_frame_source_ && deadline_ == other.deadline_; } diff --git a/chromium/components/viz/service/surfaces/surface_dependency_deadline.h b/chromium/components/viz/service/surfaces/surface_dependency_deadline.h index bc5913b7ed3..9c0349dfdd8 100644 --- a/chromium/components/viz/service/surfaces/surface_dependency_deadline.h +++ b/chromium/components/viz/service/surfaces/surface_dependency_deadline.h @@ -45,8 +45,8 @@ class VIZ_SERVICE_EXPORT SurfaceDependencyDeadline : public BeginFrameObserver { // Takes on the same BeginFrameSource and deadline as |other|. void InheritFrom(const SurfaceDependencyDeadline& other); - bool operator==(const SurfaceDependencyDeadline& other); - bool operator!=(const SurfaceDependencyDeadline& other) { + bool operator==(const SurfaceDependencyDeadline& other) const; + bool operator!=(const SurfaceDependencyDeadline& other) const { return !(*this == other); } diff --git a/chromium/components/viz/service/surfaces/surface_hittest.cc b/chromium/components/viz/service/surfaces/surface_hittest.cc index 9ba95d40956..14c50d37f84 100644 --- a/chromium/components/viz/service/surfaces/surface_hittest.cc +++ b/chromium/components/viz/service/surfaces/surface_hittest.cc @@ -137,13 +137,13 @@ bool SurfaceHittest::GetTargetSurfaceAtPointInternal( continue; } - // If a point hits a Surface after hitting a non-Surface quad, we should - // defer to the renderer. Some DrawQuads are not valid hit test targets - // and information needed to distinguish them is not available here. - if (non_surface_was_hit) { - *out_query_renderer = true; + // For any point that hits a Surface, we should defer to the renderer. + // Some DrawQuads are not valid hit test targets and information + // needed to distinguish them is not available here. + *out_query_renderer = true; + + if (non_surface_was_hit) return true; - } gfx::Transform transform_to_child_space; if (GetTargetSurfaceAtPointInternal( diff --git a/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc b/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc index ed2cf41fd84..e82a5050c29 100644 --- a/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc +++ b/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc @@ -121,10 +121,10 @@ TEST_F(SurfaceHittestTest, Hittest_BadCompositorFrameDoesNotCrash) { // Submit the root frame. ParentLocalSurfaceIdAllocator root_allocator; - LocalSurfaceId root_local_surface_id = root_allocator.GenerateId(); - SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + SurfaceId root_surface_id(kRootFrameSink, + root_allocator.GetCurrentLocalSurfaceId()); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); { SurfaceHittest hittest(nullptr, surface_manager()); @@ -145,10 +145,10 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface) { // Submit the root frame. ParentLocalSurfaceIdAllocator root_allocator; - LocalSurfaceId root_local_surface_id = root_allocator.GenerateId(); - SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + SurfaceId root_surface_id(kRootFrameSink, + root_allocator.GetCurrentLocalSurfaceId()); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); TestCase tests[] = { {root_surface_id, gfx::Point(100, 100), root_surface_id, gfx::Point(100, 100), false}, @@ -165,8 +165,8 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) { // Add a reference to the child surface on the root surface. ParentLocalSurfaceIdAllocator child_allocator; - LocalSurfaceId child_local_surface_id = child_allocator.GenerateId(); - SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id); + SurfaceId child_surface_id(kChildFrameSink, + child_allocator.GetCurrentLocalSurfaceId()); gfx::Rect child_rect(200, 200); CreateSurfaceDrawQuad( root_pass, @@ -176,10 +176,10 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) { // Submit the root frame. ParentLocalSurfaceIdAllocator root_allocator; - LocalSurfaceId root_local_surface_id = root_allocator.GenerateId(); - SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + SurfaceId root_surface_id(kRootFrameSink, + root_allocator.GetCurrentLocalSurfaceId()); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); // Creates a child surface. RenderPass* child_pass = nullptr; @@ -194,19 +194,19 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) { root_rect, child_solid_quad_rect); // Submit the frame. - child_support().SubmitCompositorFrame(child_local_surface_id, - std::move(child_frame)); + child_support().SubmitCompositorFrame( + child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame)); TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, gfx::Point(10, 10), false}, {root_surface_id, gfx::Point(99, 99), root_surface_id, - gfx::Point(99, 99), false}, + gfx::Point(99, 99), true}, {root_surface_id, gfx::Point(100, 100), child_surface_id, gfx::Point(50, 50), true}, {root_surface_id, gfx::Point(199, 199), child_surface_id, gfx::Point(149, 149), true}, {root_surface_id, gfx::Point(200, 200), root_surface_id, - gfx::Point(200, 200), false}, + gfx::Point(200, 200), true}, {root_surface_id, gfx::Point(290, 290), root_surface_id, gfx::Point(290, 290), false}}; @@ -219,8 +219,8 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) { gfx::Transform(1.0f, 0.0f, 0.0f, 75.0f, 0.0f, 1.0f, 0.0f, 75.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f), root_rect, child_rect, child_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); // Verify that point (100, 100) no longer falls on the child surface. // Verify that the transform to the child surface's space has also shifted. @@ -235,7 +235,7 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) { &transform, &query_renderer)); transform.TransformPoint(&point); EXPECT_EQ(gfx::Point(100, 100), point); - EXPECT_EQ(query_renderer, false); + EXPECT_EQ(query_renderer, true); gfx::Point point_in_target_space(100, 100); gfx::Transform target_transform; @@ -263,8 +263,8 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) { // Add a reference to the child surface on the root surface. ParentLocalSurfaceIdAllocator child_allocator; - LocalSurfaceId child_local_surface_id = child_allocator.GenerateId(); - SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id); + SurfaceId child_surface_id(kChildFrameSink, + child_allocator.GetCurrentLocalSurfaceId()); gfx::Rect child_rect(200, 200); CreateSurfaceDrawQuad( root_pass, @@ -274,10 +274,10 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) { // Submit the root frame. ParentLocalSurfaceIdAllocator root_allocator; - LocalSurfaceId root_local_surface_id = root_allocator.GenerateId(); - SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + SurfaceId root_surface_id(kRootFrameSink, + root_allocator.GetCurrentLocalSurfaceId()); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); // Creates a child surface. RenderPass* child_pass = nullptr; @@ -292,8 +292,8 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) { root_rect, child_solid_quad_rect); // Submit the frame. - child_support().SubmitCompositorFrame(child_local_surface_id, - std::move(child_frame)); + child_support().SubmitCompositorFrame( + child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame)); TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, gfx::Point(10, 10), false}, @@ -304,7 +304,7 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) { {root_surface_id, gfx::Point(199, 199), child_surface_id, gfx::Point(149, 149), true}, {root_surface_id, gfx::Point(200, 200), root_surface_id, - gfx::Point(200, 200), false}, + gfx::Point(200, 200), true}, {root_surface_id, gfx::Point(290, 290), root_surface_id, gfx::Point(290, 290), false}}; @@ -326,7 +326,8 @@ TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) { // Add a reference to the child surface on the root surface. ParentLocalSurfaceIdAllocator child_allocator; - LocalSurfaceId child_local_surface_id = child_allocator.GenerateId(); + LocalSurfaceId child_local_surface_id = + child_allocator.GetCurrentLocalSurfaceId(); SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id); gfx::Rect child_rect(200, 200); CreateSurfaceDrawQuad( @@ -337,10 +338,10 @@ TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) { // Submit the root frame. ParentLocalSurfaceIdAllocator root_allocator; - LocalSurfaceId root_local_surface_id = root_allocator.GenerateId(); - SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + SurfaceId root_surface_id(kRootFrameSink, + root_allocator.GetCurrentLocalSurfaceId()); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); // Creates a child surface. RenderPass* child_pass = nullptr; @@ -355,19 +356,19 @@ TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) { root_rect, child_solid_quad_rect); // Submit the frame. - child_support().SubmitCompositorFrame(child_local_surface_id, - std::move(child_frame)); + child_support().SubmitCompositorFrame( + child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame)); TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id, gfx::Point(10, 10), false}, {root_surface_id, gfx::Point(99, 99), root_surface_id, - gfx::Point(99, 99), false}, + gfx::Point(99, 99), true}, {root_surface_id, gfx::Point(100, 100), child_surface_id, gfx::Point(50, 50), true}, {root_surface_id, gfx::Point(199, 199), child_surface_id, gfx::Point(149, 149), true}, {root_surface_id, gfx::Point(200, 200), root_surface_id, - gfx::Point(200, 200), false}, + gfx::Point(200, 200), true}, {root_surface_id, gfx::Point(290, 290), root_surface_id, gfx::Point(290, 290), false}}; @@ -409,10 +410,10 @@ TEST_F(SurfaceHittestTest, Hittest_RenderPassDrawQuad) { // Submit the root frame. ParentLocalSurfaceIdAllocator root_allocator; - LocalSurfaceId root_local_surface_id = root_allocator.GenerateId(); - SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + SurfaceId root_surface_id(kRootFrameSink, + root_allocator.GetCurrentLocalSurfaceId()); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); TestCase tests[] = {// These tests just miss the RenderPassDrawQuad. {root_surface_id, gfx::Point(49, 49), root_surface_id, @@ -443,8 +444,8 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) { // Add a reference to the child surface on the root surface. ParentLocalSurfaceIdAllocator child_allocator; - LocalSurfaceId child_local_surface_id = child_allocator.GenerateId(); - SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id); + SurfaceId child_surface_id(kChildFrameSink, + child_allocator.GetCurrentLocalSurfaceId()); gfx::Rect child_rect(200, 200); CreateSurfaceDrawQuad( root_pass, @@ -454,10 +455,10 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) { // Submit the root frame. ParentLocalSurfaceIdAllocator root_allocator; - LocalSurfaceId root_local_surface_id = root_allocator.GenerateId(); - SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id); - root_support().SubmitCompositorFrame(root_local_surface_id, - std::move(root_frame)); + SurfaceId root_surface_id(kRootFrameSink, + root_allocator.GetCurrentLocalSurfaceId()); + root_support().SubmitCompositorFrame( + root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame)); // Creates a child surface. RenderPass* child_pass = nullptr; @@ -472,8 +473,8 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) { root_rect, child_solid_quad_rect); // Submit the frame. - child_support().SubmitCompositorFrame(child_local_surface_id, - std::move(child_frame)); + child_support().SubmitCompositorFrame( + child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame)); TestCase test_expectations_without_insets[] = { {root_surface_id, gfx::Point(55, 55), child_surface_id, gfx::Point(5, 5), @@ -485,9 +486,9 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) { {root_surface_id, gfx::Point(244, 244), child_surface_id, gfx::Point(194, 194), true}, {root_surface_id, gfx::Point(50, 50), root_surface_id, gfx::Point(50, 50), - false}, + true}, {root_surface_id, gfx::Point(249, 249), root_surface_id, - gfx::Point(249, 249), false}, + gfx::Point(249, 249), true}, }; TestSurfaceHittestDelegate empty_delegate; |