diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-24 12:15:48 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2018-08-28 13:30:04 +0000 |
commit | b014812705fc80bff0a5c120dfcef88f349816dc (patch) | |
tree | 25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/components/viz/service/display | |
parent | 9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff) | |
download | qtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz |
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/viz/service/display')
58 files changed, 5764 insertions, 1602 deletions
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. |