From 3427060de395ec4dfd45b1d4727df8c2c24a2d50 Mon Sep 17 00:00:00 2001 From: Kevin Haslett Date: Mon, 23 Jan 2023 22:50:22 +0000 Subject: [PATCH] Support BufferQueue on Mac This CL does NOT enable BQ on Mac. - Don't call PrepareRenderPassOverlay for root render passes - Ignore InUseByWindowServer for root rp overlays - Don't bother calling DidReceiveReleasedOverlays for root rp overlays - Also cleanup some render pass backing code for root rps, making logic simpler. Bug: 1322528 Change-Id: I4ae0897a5803ded347d05159ddc1b06031948595 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4089938 Commit-Queue: Kevin Haslett Reviewed-by: Vasiliy Telezhnikov Reviewed-by: Kyle Charbonneau Cr-Commit-Position: refs/heads/main@{#1095874} --- .../viz/service/display/ca_layer_overlay.h | 5 +- .../viz/service/display/direct_renderer.cc | 43 ++++++++------ .../viz/service/display/skia_renderer.cc | 59 ++++++++++++------- .../skia_output_device_buffer_queue.cc | 44 ++++++++++---- .../skia_output_device_buffer_queue.h | 1 + 5 files changed, 100 insertions(+), 52 deletions(-) diff --git a/components/viz/service/display/ca_layer_overlay.h b/components/viz/service/display/ca_layer_overlay.h index 713474a1f152a8..9076cfa0a06669 100644 --- a/components/viz/service/display/ca_layer_overlay.h +++ b/components/viz/service/display/ca_layer_overlay.h @@ -62,7 +62,8 @@ class VIZ_SERVICE_EXPORT CALayerOverlay { scoped_refptr shared_state; // Texture that corresponds to an IOSurface to set as the content of the - // CALayer. If this is 0 then the CALayer is a solid color. + // CALayer. If this is 0 then the CALayer is a solid color, or it's the root + // render pass if |is_root_render_pass| = true. ResourceId contents_resource_id = kInvalidResourceId; // Mailbox from contents_resource_id. It is used by SkiaRenderer. gpu::Mailbox mailbox; @@ -88,6 +89,8 @@ class VIZ_SERVICE_EXPORT CALayerOverlay { // If |rpdq| is present, then the renderer must draw the filter effects and // copy the result into an IOSurface. const AggregatedRenderPassDrawQuad* rpdq = nullptr; + // Whether this overlay candidate represents the root render pass. + bool is_root_render_pass = false; }; typedef std::vector CALayerOverlayList; diff --git a/components/viz/service/display/direct_renderer.cc b/components/viz/service/display/direct_renderer.cc index 395b18c29970a7..589dd221db660b 100644 --- a/components/viz/service/display/direct_renderer.cc +++ b/components/viz/service/display/direct_renderer.cc @@ -29,6 +29,7 @@ #include "components/viz/common/quads/draw_quad.h" #include "components/viz/common/quads/solid_color_draw_quad.h" #include "components/viz/common/resources/platform_color.h" +#include "components/viz/common/resources/resource_format_utils.h" #include "components/viz/common/viz_utils.h" #include "components/viz/service/display/bsp_tree.h" #include "components/viz/service/display/bsp_walk_action.h" @@ -191,10 +192,15 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame( base::flat_map render_passes_in_frame; for (const auto& pass : render_passes_in_draw_order) { + // The root render pass doesn't need to be updated here because the backing + // is reused and updated in AllocateRenderPassResourceIfNeeded(). + if (pass == root_render_pass) { + continue; + } + // If there's a copy request, we need an explicit renderpass backing so // only try to draw directly if there are no copy requests. - bool is_root = pass == root_render_pass; - if (!is_root && pass->copy_requests.empty()) { + if (pass->copy_requests.empty()) { if (const DrawQuad* quad = CanPassBeDrawnDirectly(pass.get())) { // If the render pass is drawn directly, it will not be drawn from as // a render pass so it's not added to the map. @@ -202,12 +208,7 @@ void DirectRenderer::DecideRenderPassAllocationsForFrame( continue; } } - gfx::Size size = pass->output_rect.size(); - // We should not change the buffer size for the root render pass. - // The requirement is used for non-root render pass only. - if (!is_root) { - size = CalculateTextureSizeForRenderPass(pass.get()); - } + gfx::Size size = CalculateTextureSizeForRenderPass(pass.get()); auto color_space = RenderPassColorSpace(pass.get()); auto format = GetColorSpaceResourceFormat(color_space); @@ -784,20 +785,24 @@ void DirectRenderer::UseRenderPass(const AggregatedRenderPass* render_pass) { return; } - gfx::Size size = render_pass->output_rect.size(); - // We should not change the buffer size for the root render pass. + RenderPassRequirements requirements; + // The root pass will use values from |reshape_params_| so this doesn't + // matter. if (!is_root) { - size = CalculateTextureSizeForRenderPass(render_pass); - size.Enlarge(enlarge_pass_texture_amount_.width(), - enlarge_pass_texture_amount_.height()); + requirements.size = CalculateTextureSizeForRenderPass(render_pass); + requirements.size.Enlarge(enlarge_pass_texture_amount_.width(), + enlarge_pass_texture_amount_.height()); + requirements.generate_mipmap = render_pass->generate_mipmap; + requirements.color_space = CurrentRenderPassColorSpace(); + requirements.format = GetColorSpaceResourceFormat(requirements.color_space); + } else { + requirements.size = surface_size_for_swap_buffers(); + requirements.generate_mipmap = false; + requirements.color_space = reshape_color_space(); + requirements.format = GetResourceFormat(reshape_buffer_format()); } - auto color_space = CurrentRenderPassColorSpace(); - auto format = GetColorSpaceResourceFormat(color_space); - - AllocateRenderPassResourceIfNeeded( - render_pass->id, - {size, render_pass->generate_mipmap, format, color_space}); + AllocateRenderPassResourceIfNeeded(render_pass->id, requirements); // TODO(crbug.com/582554): This change applies only when Vulkan is enabled and // it will be removed once SkiaRenderer has complete support for Vulkan. diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc index 7edc61a77b1ebe..223a556f6237f7 100644 --- a/components/viz/service/display/skia_renderer.cc +++ b/components/viz/service/display/skia_renderer.cc @@ -871,19 +871,24 @@ void SkiaRenderer::FinishDrawingFrame() { if (!buffer_queue_) { skia_output_surface_->ScheduleOutputSurfaceAsOverlay(surface_plane); } else { -#if BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) - // Windows and Mac have different OverlayList types, but those platforms - // aren't supported by buffer_queue_ yet, so this won't be reached. +#if BUILDFLAG(IS_WIN) + // Windows does not use buffer_queue_ so this won't be reached. NOTREACHED(); #else - auto root_pass_backing = - render_pass_backings_.find(current_frame()->root_render_pass->id); - // The root pass backing should always exist. - DCHECK(root_pass_backing != render_pass_backings_.end()); +#if BUILDFLAG(IS_MAC) + CALayerOverlay surface_candidate; + surface_candidate.shared_state = + base::MakeRefCounted(); + surface_candidate.shared_state->sorting_context_id = 0; + surface_candidate.shared_state->rounded_corner_bounds = + surface_plane.rounded_corners; + surface_candidate.contents_rect = surface_plane.uv_rect; + surface_candidate.bounds_rect = surface_plane.display_rect; + surface_candidate.opacity = surface_plane.opacity; + surface_candidate.filter = GL_LINEAR; +#else OverlayCandidate surface_candidate; - surface_candidate.mailbox = root_pass_backing->second.mailbox; - surface_candidate.is_root_render_pass = true; surface_candidate.transform = surface_plane.transform; surface_candidate.display_rect = surface_plane.display_rect; surface_candidate.uv_rect = surface_plane.uv_rect; @@ -897,10 +902,19 @@ void SkiaRenderer::FinishDrawingFrame() { surface_candidate.damage_rect = gfx::RectF(surface_plane.damage_rect.value_or( gfx::Rect(surface_plane.resource_size))); +#endif // BUILDFLAG(IS_MAC) + + auto root_pass_backing = + render_pass_backings_.find(current_frame()->root_render_pass->id); + // The root pass backing should always exist. + DCHECK(root_pass_backing != render_pass_backings_.end()); + + surface_candidate.mailbox = root_pass_backing->second.mailbox; + surface_candidate.is_root_render_pass = true; current_frame()->overlay_list.insert( current_frame()->overlay_list.begin(), surface_candidate); -#endif // BUILDFLAG(IS_APPLE) || BUILDFLAG(IS_WIN) +#endif // BUILDFLAG(IS_WIN) } } else { #if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_MAC) @@ -2717,6 +2731,10 @@ void SkiaRenderer::ScheduleOverlays() { } #elif BUILDFLAG(IS_APPLE) for (CALayerOverlay& ca_layer_overlay : current_frame()->overlay_list) { + if (ca_layer_overlay.is_root_render_pass) { + continue; + } + if (ca_layer_overlay.rpdq) { PrepareRenderPassOverlay(&ca_layer_overlay); locks.emplace_back(ca_layer_overlay.mailbox); @@ -3159,6 +3177,12 @@ void SkiaRenderer::UpdateRenderPassTextures( render_passes_in_frame) { std::vector passes_to_delete; for (const auto& pair : render_pass_backings_) { + // The single root render pass backing is updated in + // AllocateRenderPassResourceIfNeeded(), so we should never erase it here. + if (pair.second.is_root) { + continue; + } + auto render_pass_it = render_passes_in_frame.find(pair.first); if (render_pass_it == render_passes_in_frame.end()) { passes_to_delete.push_back(pair.first); @@ -3186,12 +3210,7 @@ void SkiaRenderer::UpdateRenderPassTextures( for (size_t i = 0; i < passes_to_delete.size(); ++i) { auto it = render_pass_backings_.find(passes_to_delete[i]); auto& backing = it->second; - // Buffers for root render pass backings are managed by |buffer_queue_|, not - // DisplayResourceProvider, so we should not destroy them here. This - // reallocation is done in Reshape before drawing the frame - if (!backing.is_root) { - skia_output_surface_->DestroySharedImage(backing.mailbox); - } + skia_output_surface_->DestroySharedImage(backing.mailbox); render_pass_backings_.erase(it); } @@ -3208,10 +3227,10 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded( auto& root_pass_backing = render_pass_backings_[render_pass_id]; root_pass_backing.is_root = true; root_pass_backing.mailbox = buffer_queue_->GetCurrentBuffer(); - root_pass_backing.generate_mipmap = false; - root_pass_backing.size = surface_size_for_swap_buffers(); - root_pass_backing.format = GetResourceFormat(reshape_buffer_format()); - root_pass_backing.color_space = reshape_color_space(); + root_pass_backing.generate_mipmap = requirements.generate_mipmap; + root_pass_backing.size = requirements.size; + root_pass_backing.format = requirements.format; + root_pass_backing.color_space = requirements.color_space; return; } diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc index c65ae0a73814b1..47e9ee0457ec2d 100644 --- a/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc +++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue.cc @@ -62,10 +62,12 @@ class SkiaOutputDeviceBufferQueue::OverlayData { OverlayData(std::unique_ptr representation, std::unique_ptr - scoped_read_access) + scoped_read_access, + bool is_root_render_pass) : representation_(std::move(representation)), scoped_read_access_(std::move(scoped_read_access)), - ref_(1) { + ref_(1), + is_root_render_pass_(is_root_render_pass) { DCHECK(representation_); DCHECK(scoped_read_access_); } @@ -75,7 +77,7 @@ class SkiaOutputDeviceBufferQueue::OverlayData { ~OverlayData() { Reset(); } OverlayData& operator=(OverlayData&& other) { - DCHECK(!IsInUseByWindowServer()); + DCHECK(is_root_render_pass_ || !IsInUseByWindowServer()); DCHECK(!ref_); DCHECK(!scoped_read_access_); DCHECK(!representation_); @@ -83,13 +85,20 @@ class SkiaOutputDeviceBufferQueue::OverlayData { representation_ = std::move(other.representation_); ref_ = other.ref_; other.ref_ = 0; + is_root_render_pass_ = other.is_root_render_pass_; return *this; } bool IsInUseByWindowServer() const { #if BUILDFLAG(IS_MAC) - if (!scoped_read_access_) + if (!scoped_read_access_) { return false; + } + // The root render pass buffers are managed by SkiaRenderer so we don't care + // if they're in use by the window server. + if (is_root_render_pass_) { + return false; + } return scoped_read_access_->IsInUseByWindowServer(); #else return false; @@ -103,7 +112,7 @@ class SkiaOutputDeviceBufferQueue::OverlayData { if (ref_ > 1) { --ref_; } else if (ref_ == 1) { - DCHECK(!IsInUseByWindowServer()); + DCHECK(is_root_render_pass_ || !IsInUseByWindowServer()); Reset(); } } @@ -117,6 +126,8 @@ class SkiaOutputDeviceBufferQueue::OverlayData { return scoped_read_access_.get(); } + bool IsRootRenderPass() { return is_root_render_pass_; } + private: void Reset() { scoped_read_access_.reset(); @@ -128,6 +139,7 @@ class SkiaOutputDeviceBufferQueue::OverlayData { std::unique_ptr scoped_read_access_; int ref_ = 0; + bool is_root_render_pass_ = false; }; SkiaOutputDeviceBufferQueue::SkiaOutputDeviceBufferQueue( @@ -321,6 +333,7 @@ void SkiaOutputDeviceBufferQueue::SchedulePrimaryPlane( SkiaOutputDeviceBufferQueue::OverlayData* SkiaOutputDeviceBufferQueue::GetOrCreateOverlayData(const gpu::Mailbox& mailbox, + bool is_root_render_pass, bool* is_existing) { if (is_existing) *is_existing = false; @@ -354,8 +367,9 @@ SkiaOutputDeviceBufferQueue::GetOrCreateOverlayData(const gpu::Mailbox& mailbox, } bool result; - std::tie(it, result) = overlays_.emplace(std::move(shared_image), - std::move(shared_image_access)); + std::tie(it, result) = + overlays_.emplace(std::move(shared_image), std::move(shared_image_access), + is_root_render_pass); DCHECK(result); DCHECK(it->unique()); @@ -394,8 +408,8 @@ void SkiaOutputDeviceBufferQueue::ScheduleOverlays( OutputPresenter::ScopedOverlayAccess* access = nullptr; bool overlay_has_been_submitted; - auto* overlay_data = - GetOrCreateOverlayData(mailbox, &overlay_has_been_submitted); + auto* overlay_data = GetOrCreateOverlayData( + mailbox, overlay.is_root_render_pass, &overlay_has_been_submitted); if (overlay_data) { access = overlay_data->scoped_read_access(); pending_overlay_mailboxes_.emplace_back(mailbox); @@ -589,11 +603,17 @@ void SkiaOutputDeviceBufferQueue::DoFinishSwapBuffers( // Go through backings of all overlays, and release overlay backings which are // not used. base::EraseIf(overlays_, [&on_overlay_release](auto& overlay) { - if (!overlay.unique()) + if (!overlay.unique()) { return false; - if (overlay.IsInUseByWindowServer()) + } + if (overlay.IsInUseByWindowServer()) { return false; - on_overlay_release(overlay); + } + // The root render pass buffers are managed by SkiaRenderer so we don't need + // to explicitly return them via callback. + if (!overlay.IsRootRenderPass()) { + on_overlay_release(overlay); + } overlay.Unref(); return true; }); diff --git a/components/viz/service/display_embedder/skia_output_device_buffer_queue.h b/components/viz/service/display_embedder/skia_output_device_buffer_queue.h index a5717d9f0a01bd..f4a766d994cb69 100644 --- a/components/viz/service/display_embedder/skia_output_device_buffer_queue.h +++ b/components/viz/service/display_embedder/skia_output_device_buffer_queue.h @@ -93,6 +93,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputDeviceBufferQueue : public SkiaOutputDevice { // Given an overlay mailbox, returns the corresponding OverlayData* from // |overlays_|. Inserts an OverlayData if mailbox is not in |overlays_|. OverlayData* GetOrCreateOverlayData(const gpu::Mailbox& mailbox, + bool is_root_render_pass, bool* is_existing = nullptr); std::unique_ptr presenter_;