0

Use mailboxes for RenderPass in SkiaOutputSurfaceImpl

SkiaOutputSurfaceImpl currently uses offscreen_surfaces for reading
and writing shared images for RenderPass. This CL replaces offscreen
surfaces to use mailboxes for reading and writing to shared images for
RenderPass. It also uses USAGE_MIPMAP for supporting render passes
using mipmap.

Bug: 991659
Change-Id: I2d12952c51a759bb792f44444b858b32c92f2a7c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2987218
Commit-Queue: Saifuddin Hitawala <hitawala@chromium.org>
Reviewed-by: Vasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#899778}
This commit is contained in:
Saifuddin Hitawala
2021-07-09 00:21:03 +00:00
committed by Chromium LUCI CQ
parent 3bc5c5609c
commit 0188a4d64f
14 changed files with 223 additions and 186 deletions

@ -1088,6 +1088,22 @@ class LayerTreeHostCopyRequestTestCountSharedImages
}
}
std::unique_ptr<TestLayerTreeFrameSink> CreateLayerTreeFrameSink(
const viz::RendererSettings& renderer_settings,
double refresh_rate,
scoped_refptr<viz::ContextProvider> compositor_context_provider,
scoped_refptr<viz::RasterContextProvider> worker_context_provider)
override {
// Since this test counts shared images and SkiaRenderer uses shared images
// for render passes, we need render pass allocation to be stable.
auto settings = renderer_settings;
settings.disable_render_pass_bypassing = true;
auto frame_sink = LayerTreeHostCopyRequestTest::CreateLayerTreeFrameSink(
settings, refresh_rate, std::move(compositor_context_provider),
std::move(worker_context_provider));
return frame_sink;
}
void DisplayDidDrawAndSwapOnThread() override {
auto* sii = display_context_provider_->SharedImageInterface();
switch (num_swaps_++) {

@ -36,6 +36,7 @@ class VIZ_COMMON_EXPORT RendererSettings {
int highp_threshold_min = 0;
bool auto_resize_output_surface = true;
bool requires_alpha_channel = false;
bool disable_render_pass_bypassing = false;
int slow_down_compositing_scale_factor = 1;

@ -116,7 +116,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
const gfx::Size& size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) = 0;
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) = 0;
// Finish painting the current frame or current render pass, depends on which
// BeginPaint function is called last. This method will schedule a GPU task to
@ -135,7 +136,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
const gfx::Size& size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) = 0;
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) = 0;
// Remove cached resources generated by BeginPaintRenderPass and
// FinishPaintRenderPass.
@ -147,7 +149,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
virtual void CopyOutput(AggregatedRenderPassId id,
const copy_output::RenderPassGeometry& geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) = 0;
std::unique_ptr<CopyOutputRequest> request,
const gpu::Mailbox& mailbox) = 0;
// Schedule drawing overlays at next SwapBuffers() call. Waits on
// |sync_tokens| for the overlay textures to be ready before scheduling.
@ -179,6 +182,9 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface,
// the GPU main thread.
virtual gpu::SyncToken Flush() = 0;
// Only used for creating and destroying shared images for render passes
virtual gpu::SharedImageInterface* GetSharedImageInterface() = 0;
#if defined(OS_APPLE) || defined(USE_OZONE)
virtual SkCanvas* BeginPaintRenderPassOverlay(
const gfx::Size& size,

@ -43,6 +43,8 @@
#include "components/viz/service/display/resource_fence.h"
#include "components/viz/service/display/skia_output_surface.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/client/shared_image_interface.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "skia/ext/opacity_filter_canvas.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@ -900,7 +902,7 @@ void SkiaRenderer::BindFramebufferToTexture(
RenderPassBacking& backing = iter->second;
current_canvas_ = skia_output_surface_->BeginPaintRenderPass(
render_pass_id, backing.size, backing.format, backing.generate_mipmap,
backing.color_space.ToSkColorSpace());
backing.color_space.ToSkColorSpace(), backing.mailbox);
}
void SkiaRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
@ -1391,6 +1393,10 @@ bool SkiaRenderer::CanExplicitlyScissor(
const DrawQuad* SkiaRenderer::CanPassBeDrawnDirectly(
const AggregatedRenderPass* pass) {
// If render pass bypassing is disabled for testing
if (settings_->disable_render_pass_bypassing)
return nullptr;
// TODO(michaelludwig) - For now, this only supports opaque, src-over quads
// with invertible transforms and simple content (image or color only).
// Can only collapse a single tile quad.
@ -2612,7 +2618,8 @@ void SkiaRenderer::DrawRenderPassQuad(const AggregatedRenderPassDrawQuad* quad,
sk_sp<SkImage> content_image =
skia_output_surface_->MakePromiseSkImageFromRenderPass(
quad->render_pass_id, backing.size, backing.format,
backing.generate_mipmap, backing.color_space.ToSkColorSpace());
backing.generate_mipmap, backing.color_space.ToSkColorSpace(),
backing.mailbox);
DLOG_IF(ERROR, !content_image)
<< "MakePromiseSkImageFromRenderPass() failed for render pass";
@ -2656,13 +2663,18 @@ void SkiaRenderer::CopyDrawnRenderPass(
// Root framebuffer uses id 0 in SkiaOutputSurface.
AggregatedRenderPassId render_pass_id;
gpu::Mailbox mailbox;
const auto* const render_pass = current_frame()->current_render_pass;
if (render_pass != current_frame()->root_render_pass) {
render_pass_id = render_pass->id;
auto it = render_pass_backings_.find(render_pass_id);
DCHECK(it != render_pass_backings_.end());
mailbox = it->second.mailbox;
}
skia_output_surface_->CopyOutput(render_pass_id, geometry,
CurrentRenderPassColorSpace(),
std::move(request));
std::move(request), mailbox);
}
void SkiaRenderer::DidChangeVisibility() {
@ -2741,6 +2753,8 @@ void SkiaRenderer::UpdateRenderPassTextures(
// again.
for (size_t i = 0; i < passes_to_delete.size(); ++i) {
auto it = render_pass_backings_.find(passes_to_delete[i]);
skia_output_surface_->GetSharedImageInterface()->DestroySharedImage(
gpu::SyncToken(), it->second.mailbox);
render_pass_backings_.erase(it);
}
@ -2765,10 +2779,18 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
auto format = color_space.IsHDR()
? RGBA_F16
: PlatformColor::BestSupportedTextureFormat(caps);
uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY;
if (requirements.generate_mipmap)
usage |= gpu::SHARED_IMAGE_USAGE_MIPMAP;
auto mailbox =
skia_output_surface_->GetSharedImageInterface()->CreateSharedImage(
format, requirements.size, color_space,
GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin,
SkAlphaType::kPremul_SkAlphaType, usage, gpu::kNullSurfaceHandle);
render_pass_backings_.emplace(
render_pass_id,
RenderPassBacking({requirements.size, requirements.generate_mipmap,
color_space, format}));
color_space, format, mailbox}));
}
void SkiaRenderer::FlushOutputSurface() {
@ -2942,7 +2964,8 @@ void SkiaRenderer::PrepareRenderPassOverlay(
DCHECK(backing);
auto content_image = skia_output_surface_->MakePromiseSkImageFromRenderPass(
quad->render_pass_id, backing->size, backing->format,
backing->generate_mipmap, backing->color_space.ToSkColorSpace());
backing->generate_mipmap, backing->color_space.ToSkColorSpace(),
backing->mailbox);
if (!content_image) {
DLOG(ERROR)
<< "MakePromiseSkImageFromRenderPass() failed for render pass";

@ -267,6 +267,7 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
bool generate_mipmap;
gfx::ColorSpace color_space;
ResourceFormat format;
gpu::Mailbox mailbox;
};
base::flat_map<AggregatedRenderPassId, RenderPassBacking>
render_pass_backings_;

@ -24,26 +24,15 @@ ImageContextImpl::ImageContextImpl(
ResourceFormat resource_format,
bool maybe_concurrent_reads,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
sk_sp<SkColorSpace> color_space)
sk_sp<SkColorSpace> color_space,
const bool allow_keeping_read_access)
: ImageContext(mailbox_holder,
size,
resource_format,
ycbcr_info,
color_space),
maybe_concurrent_reads_(maybe_concurrent_reads) {}
ImageContextImpl::ImageContextImpl(AggregatedRenderPassId render_pass_id,
const gfx::Size& size,
ResourceFormat resource_format,
bool mipmap,
sk_sp<SkColorSpace> color_space)
: ImageContext(gpu::MailboxHolder(),
size,
resource_format,
/*ycbcr_info=*/absl::nullopt,
std::move(color_space)),
render_pass_id_(render_pass_id),
mipmap_(mipmap ? GrMipMapped::kYes : GrMipMapped::kNo) {}
maybe_concurrent_reads_(maybe_concurrent_reads),
allow_keeping_read_access_(allow_keeping_read_access) {}
ImageContextImpl::~ImageContextImpl() {
if (fallback_context_state_)
@ -267,7 +256,8 @@ void ImageContextImpl::EndAccessIfNecessary() {
// Avoid unnecessary read access churn for representations that
// support multiple readers.
if (representation_->SupportsMultipleConcurrentReadAccess())
if (representation_->SupportsMultipleConcurrentReadAccess() &&
allow_keeping_read_access_)
return;
representation_scoped_read_access_.reset();

@ -51,17 +51,9 @@ class ImageContextImpl final : public ExternalUseClient::ImageContext {
ResourceFormat resource_format,
bool maybe_concurrent_reads,
const absl::optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
sk_sp<SkColorSpace> color_space);
sk_sp<SkColorSpace> color_space,
const bool allow_keeping_read_access = true);
// TODO(https://crbug.com/991659): The use of ImageContext for
// SkiaOutputSurfaceImplOnGpu::OffscreenSurface can be factored out. This
// would make ImageContextImpl cleaner and handling of render passes less
// confusing.
ImageContextImpl(AggregatedRenderPassId render_pass_id,
const gfx::Size& size,
ResourceFormat resource_format,
bool mipmap,
sk_sp<SkColorSpace> color_space);
~ImageContextImpl() final;
void OnContextLost() final;
@ -69,9 +61,6 @@ class ImageContextImpl final : public ExternalUseClient::ImageContext {
// Returns true if there might be concurrent reads to the backing texture.
bool maybe_concurrent_reads() const { return maybe_concurrent_reads_; }
AggregatedRenderPassId render_pass_id() const { return render_pass_id_; }
GrMipMapped mipmap() const { return mipmap_; }
void set_promise_image_texture(
sk_sp<SkPromiseImageTexture> promise_image_texture) {
owned_promise_image_texture_ = std::move(promise_image_texture);
@ -108,10 +97,8 @@ class ImageContextImpl final : public ExternalUseClient::ImageContext {
bool BindOrCopyTextureIfNecessary(gpu::TextureBase* texture_base,
gfx::Size* size);
const AggregatedRenderPassId render_pass_id_;
const GrMipMapped mipmap_ = GrMipMapped::kNo;
const bool maybe_concurrent_reads_ = false;
const bool allow_keeping_read_access_ = true;
// Fallback in case we cannot produce a |representation_|.
gpu::SharedContextState* fallback_context_state_ = nullptr;

@ -19,6 +19,7 @@
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_util.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/service/display/external_use_client.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/overlay_candidate.h"
@ -78,12 +79,14 @@ SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
SkSurfaceCharacterization characterization)
: ScopedPaint(characterization, AggregatedRenderPassId(0)) {}
: ScopedPaint(characterization, AggregatedRenderPassId(0), gpu::Mailbox()) {
}
SkiaOutputSurfaceImpl::ScopedPaint::ScopedPaint(
SkSurfaceCharacterization characterization,
AggregatedRenderPassId render_pass_id)
: render_pass_id_(render_pass_id) {
AggregatedRenderPassId render_pass_id,
gpu::Mailbox mailbox)
: render_pass_id_(render_pass_id), mailbox_(mailbox) {
recorder_storage_.emplace(characterization);
recorder_ = &recorder_storage_.value();
}
@ -562,7 +565,8 @@ SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
const gfx::Size& surface_size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) {
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Make sure there is no unsubmitted PaintFrame or PaintRenderPass.
DCHECK(!current_paint_);
@ -574,7 +578,7 @@ SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
if (!characterization.isValid())
return nullptr;
current_paint_.emplace(characterization, id);
current_paint_.emplace(characterization, id, mailbox);
return current_paint_->recorder()->getCanvas();
}
@ -632,7 +636,7 @@ void SkiaOutputSurfaceImpl::EndPaint(base::OnceClosure on_finished) {
auto task = base::BindOnce(
&SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass,
base::Unretained(impl_on_gpu_.get()), current_paint_->render_pass_id(),
base::Unretained(impl_on_gpu_.get()), current_paint_->mailbox(),
std::move(ddl), std::move(images_in_current_paint_),
resource_sync_tokens_, std::move(on_finished));
EnqueueGpuTask(std::move(task), std::move(resource_sync_tokens_),
@ -672,14 +676,18 @@ sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromRenderPass(
const gfx::Size& size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) {
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(current_paint_);
auto& image_context = render_pass_image_cache_[id];
if (!image_context) {
image_context = std::make_unique<ImageContextImpl>(id, size, format, mipmap,
std::move(color_space));
gpu::MailboxHolder mailbox_holder(mailbox, gpu::SyncToken(), 0);
image_context = std::make_unique<ImageContextImpl>(
mailbox_holder, size, format, /*maybe_concurrent_reads=*/false,
/*ycbcr_info=*/absl::nullopt, std::move(color_space),
/*allow_keeping_read_access=*/false);
}
if (!image_context->has_image()) {
SkColorType color_type =
@ -689,7 +697,8 @@ sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromRenderPass(
image_context->SetImage(
current_paint_->recorder()->makePromiseTexture(
backend_format, image_context->size().width(),
image_context->size().height(), image_context->mipmap(),
image_context->size().height(),
mipmap ? GrMipMapped::kYes : GrMipMapped::kNo,
image_context->origin(), color_type, image_context->alpha_type(),
image_context->color_space(), Fulfill,
/*releaseTextureProc=*/nullptr, image_context.get()),
@ -707,7 +716,7 @@ void SkiaOutputSurfaceImpl::RemoveRenderPassResource(
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!ids.empty());
std::vector<std::unique_ptr<ImageContextImpl>> image_contexts;
std::vector<std::unique_ptr<ExternalUseClient::ImageContext>> image_contexts;
image_contexts.reserve(ids.size());
for (const auto id : ids) {
auto it = render_pass_image_cache_.find(id);
@ -720,26 +729,29 @@ void SkiaOutputSurfaceImpl::RemoveRenderPassResource(
}
}
// impl_on_gpu_ is released on the GPU thread by a posted task from
// SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
auto callback =
base::BindOnce(&SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource,
base::Unretained(impl_on_gpu_.get()), std::move(ids),
std::move(image_contexts));
// RemoveRenderPassResources will delete gpu resources and needs MakeCurrent.
EnqueueGpuTask(std::move(callback), {}, /*make_current=*/true,
/*need_framebuffer=*/false);
if (!image_contexts.empty()) {
// impl_on_gpu_ is released on the GPU thread by a posted task from
// SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
auto callback = base::BindOnce(
&SkiaOutputSurfaceImplOnGpu::ReleaseImageContexts,
base::Unretained(impl_on_gpu_.get()), std::move(image_contexts));
// ReleaseImageContexts will delete gpu resources and needs MakeCurrent.
EnqueueGpuTask(std::move(callback), {}, /*make_current=*/true,
/*need_framebuffer=*/false);
}
}
void SkiaOutputSurfaceImpl::CopyOutput(
AggregatedRenderPassId id,
const copy_output::RenderPassGeometry& geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) {
std::unique_ptr<CopyOutputRequest> request,
const gpu::Mailbox& mailbox) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::CopyOutput,
base::Unretained(impl_on_gpu_.get()), id,
geometry, color_space, std::move(request));
auto callback =
base::BindOnce(&SkiaOutputSurfaceImplOnGpu::CopyOutput,
base::Unretained(impl_on_gpu_.get()), id, geometry,
color_space, std::move(request), mailbox);
EnqueueGpuTask(std::move(callback), std::move(resource_sync_tokens_),
/*make_current=*/true, /*need_framebuffer=*/!id);
}
@ -1178,6 +1190,10 @@ base::ScopedClosureRunner SkiaOutputSurfaceImpl::GetCacheBackBufferCb() {
return dependency_->CacheGLSurface(impl_on_gpu_->gl_surface());
}
gpu::SharedImageInterface* SkiaOutputSurfaceImpl::GetSharedImageInterface() {
return display_compositor_controller_->shared_image_interface();
}
void SkiaOutputSurfaceImpl::AddContextLostObserver(
ContextLostObserver* observer) {
observers_.AddObserver(observer);

@ -115,7 +115,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
const gfx::Size& surface_size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) override;
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) override;
void EndPaint(base::OnceClosure on_finished) override;
void MakePromiseSkImage(ImageContext* image_context) override;
sk_sp<SkImage> MakePromiseSkImageFromRenderPass(
@ -123,7 +124,8 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
const gfx::Size& size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) override;
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) override;
void RemoveRenderPassResource(
std::vector<AggregatedRenderPassId> ids) override;
@ -134,10 +136,12 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
void CopyOutput(AggregatedRenderPassId id,
const copy_output::RenderPassGeometry& geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) override;
std::unique_ptr<CopyOutputRequest> request,
const gpu::Mailbox& mailbox) override;
void AddContextLostObserver(ContextLostObserver* observer) override;
void RemoveContextLostObserver(ContextLostObserver* observer) override;
void PreserveChildSurfaceControls() override;
gpu::SharedImageInterface* GetSharedImageInterface() override;
gpu::SyncToken Flush() override;
#if defined(OS_APPLE) || defined(USE_OZONE)
@ -240,11 +244,13 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
explicit ScopedPaint(SkDeferredDisplayListRecorder* root_recorder);
explicit ScopedPaint(SkSurfaceCharacterization characterization);
ScopedPaint(SkSurfaceCharacterization characterization,
AggregatedRenderPassId render_pass_id);
AggregatedRenderPassId render_pass_id,
gpu::Mailbox mailbox);
~ScopedPaint();
SkDeferredDisplayListRecorder* recorder() { return recorder_; }
AggregatedRenderPassId render_pass_id() { return render_pass_id_; }
gpu::Mailbox mailbox() { return mailbox_; }
private:
// This is recorder being used for current paint
@ -253,6 +259,7 @@ class VIZ_SERVICE_EXPORT SkiaOutputSurfaceImpl : public SkiaOutputSurface {
// it's stored here
absl::optional<SkDeferredDisplayListRecorder> recorder_storage_;
const AggregatedRenderPassId render_pass_id_;
const gpu::Mailbox mailbox_;
};
// Tracks damage across at most `number_of_buffers`. Note this implementation

@ -3,11 +3,11 @@
// found in the LICENSE file.
#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h"
#include <memory>
#include "base/atomic_sequence_num.h"
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/containers/cxx20_erase.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
@ -41,6 +41,7 @@
#include "gpu/ipc/common/gpu_surface_lookup.h"
#include "gpu/vulkan/buildflags.h"
#include "skia/buildflags.h"
#include "skia/ext/legacy_display_globals.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/libyuv/include/libyuv/planar_functions.h"
#include "third_party/skia/include/core/SkDeferredDisplayList.h"
@ -444,44 +445,6 @@ CreateSharedImageRepresentationFactory(SkiaOutputSurfaceDependency* deps,
} // namespace
// Offscreen surfaces for render passes. It can only be accessed on GPU
// thread.
class SkiaOutputSurfaceImplOnGpu::OffscreenSurface {
public:
OffscreenSurface() = default;
OffscreenSurface(const OffscreenSurface& offscreen_surface) = delete;
OffscreenSurface(OffscreenSurface&& offscreen_surface) = default;
OffscreenSurface& operator=(const OffscreenSurface& offscreen_surface) =
delete;
OffscreenSurface& operator=(OffscreenSurface&& offscreen_surface) = default;
~OffscreenSurface() = default;
SkSurface* surface() { return surface_.get(); }
void set_surface(sk_sp<SkSurface> surface) {
surface_ = std::move(surface);
promise_texture_ = {};
}
SkPromiseImageTexture* fulfill() {
DCHECK(surface_);
if (!promise_texture_) {
promise_texture_ =
SkPromiseImageTexture::Make(surface_->getBackendTexture(
SkSurface::kFlushRead_BackendHandleAccess));
}
return promise_texture_.get();
}
sk_sp<SkSurface> TakeSurface() {
promise_texture_ = {};
return std::move(surface_);
}
private:
sk_sp<SkSurface> surface_;
sk_sp<SkPromiseImageTexture> promise_texture_;
};
SkiaOutputSurfaceImplOnGpu::ReleaseCurrent::ReleaseCurrent(
scoped_refptr<gl::GLSurface> gl_surface,
scoped_refptr<gpu::SharedContextState> context_state)
@ -709,7 +672,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintCurrentFrame(
if (!begin_semaphores.empty()) {
auto result = scoped_output_device_paint_->Wait(
begin_semaphores.size(), begin_semaphores.data(),
/*deleteSemaphoresAfterWait=*/false);
/*delete_semaphores_after_wait=*/false);
DCHECK(result);
}
@ -789,7 +752,7 @@ void SkiaOutputSurfaceImplOnGpu::SwapBuffersSkipped() {
}
void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
AggregatedRenderPassId id,
const gpu::Mailbox& mailbox,
sk_sp<SkDeferredDisplayList> ddl,
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
@ -806,30 +769,41 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
return;
}
auto& offscreen = offscreen_surfaces_[id];
if (!offscreen.surface()) {
offscreen.set_surface(SkSurface::MakeRenderTarget(
gr_context(), ddl->characterization(), SkBudgeted::kNo));
DCHECK(offscreen.surface());
auto backing_representation =
shared_image_representation_factory_->ProduceSkia(mailbox,
context_state_.get());
DCHECK(backing_representation);
std::vector<GrBackendSemaphore> begin_semaphores;
std::vector<GrBackendSemaphore> end_semaphores;
auto scoped_access = backing_representation->BeginScopedWriteAccess(
/*final_msaa_count=*/0, ddl->characterization().surfaceProps(),
&begin_semaphores, &end_semaphores,
gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
if (!scoped_access) {
MarkContextLost(CONTEXT_LOST_UNKNOWN);
return;
}
SkSurface* surface = scoped_access->surface();
DCHECK(surface);
{
absl::optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
if (dependency_->GetGrShaderCache()) {
cache_use.emplace(dependency_->GetGrShaderCache(),
gpu::kDisplayCompositorClientId);
}
std::vector<GrBackendSemaphore> begin_semaphores;
std::vector<GrBackendSemaphore> end_semaphores;
promise_image_access_helper_.BeginAccess(
std::move(image_contexts), &begin_semaphores, &end_semaphores);
if (!begin_semaphores.empty()) {
auto result = offscreen.surface()->wait(
begin_semaphores.size(), begin_semaphores.data(),
/*deleteSemaphoresAfterWait=*/false);
auto result =
surface->wait(begin_semaphores.size(), begin_semaphores.data(),
/*deleteSemaphoresAfterWait=*/false);
DCHECK(result);
}
offscreen.surface()->draw(ddl);
surface->draw(ddl);
backing_representation->SetCleared();
destroy_after_swap_.emplace_back(std::move(ddl));
GrFlushInfo flush_info = {
@ -840,7 +814,7 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
&flush_info);
if (on_finished)
gpu::AddCleanupTaskForSkiaFlush(std::move(on_finished), &flush_info);
auto result = offscreen.surface()->flush(flush_info);
auto result = surface->flush(flush_info);
if (result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
@ -855,26 +829,6 @@ void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
}
}
void SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource(
std::vector<AggregatedRenderPassId> ids,
std::vector<std::unique_ptr<ImageContextImpl>> image_contexts) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource");
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!ids.empty());
for (AggregatedRenderPassId id : ids) {
// It's possible that |offscreen_surfaces_| won't contain an entry for the
// render pass if draw failed early.
auto it = offscreen_surfaces_.find(id);
if (it != offscreen_surfaces_.end()) {
DeleteSkSurface(context_state_.get(), it->second.TakeSurface());
offscreen_surfaces_.erase(it);
}
}
// |image_contexts| will go out of scope and be destroyed now.
}
static void PostTaskFromMainToImplThread(
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
ReleaseCallback callback,
@ -888,7 +842,8 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
AggregatedRenderPassId id,
copy_output::RenderPassGeometry geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) {
std::unique_ptr<CopyOutputRequest> request,
const gpu::Mailbox& mailbox) {
TRACE_EVENT0("viz", "SkiaOutputSurfaceImplOnGpu::CopyOutput");
// TODO(crbug.com/898595): Do this on the GPU instead of CPU with Vulkan.
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@ -899,11 +854,33 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
bool from_framebuffer = !id;
DCHECK(scoped_output_device_paint_ || !from_framebuffer);
DCHECK(from_framebuffer ||
offscreen_surfaces_.find(id) != offscreen_surfaces_.end());
SkSurface* surface = from_framebuffer
? scoped_output_device_paint_->sk_surface()
: offscreen_surfaces_[id].surface();
SkSurface* surface;
std::unique_ptr<gpu::SharedImageRepresentationSkia> backing_representation;
std::unique_ptr<gpu::SharedImageRepresentationSkia::ScopedWriteAccess>
scoped_access;
std::vector<GrBackendSemaphore> begin_semaphores;
std::vector<GrBackendSemaphore> end_semaphores;
if (from_framebuffer) {
surface = scoped_output_device_paint_->sk_surface();
} else {
backing_representation = shared_image_representation_factory_->ProduceSkia(
mailbox, context_state_.get());
DCHECK(backing_representation);
// TODO(crbug.com/1226672): Use BeginScopedReadAccess instead
scoped_access = backing_representation->BeginScopedWriteAccess(
/*final_msaa_count=*/0, skia::LegacyDisplayGlobals::GetSkSurfaceProps(),
&begin_semaphores, &end_semaphores,
gpu::SharedImageRepresentation::AllowUnclearedAccess::kNo);
surface = scoped_access->surface();
if (!begin_semaphores.empty()) {
auto result =
surface->wait(begin_semaphores.size(), begin_semaphores.data(),
/*deleteSemaphoresAfterWait=*/false);
DCHECK(result);
}
}
// Do not support reading back from vulkan secondary command buffer.
if (!surface)
return;
@ -1080,6 +1057,23 @@ void SkiaOutputSurfaceImplOnGpu::CopyOutput(
} else {
NOTREACHED();
}
if (!end_semaphores.empty()) {
GrFlushInfo flush_info;
flush_info.fNumSemaphores = end_semaphores.size();
flush_info.fSignalSemaphores = end_semaphores.data();
gpu::AddVulkanCleanupTaskForSkiaFlush(vulkan_context_provider_,
&flush_info);
auto flush_result =
surface->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flush_info);
if (flush_result != GrSemaphoresSubmitted::kYes &&
!(begin_semaphores.empty() && end_semaphores.empty())) {
// TODO(penghuang): handle vulkan device lost.
DLOG(ERROR) << "surface->flush() failed.";
return;
}
}
ScheduleCheckReadbackCompletion();
}
@ -1103,32 +1097,19 @@ void SkiaOutputSurfaceImplOnGpu::BeginAccessImages(
for (auto* context : image_contexts) {
// Prepare for accessing render pass.
if (context->render_pass_id()) {
// We don't cache promise image for render pass, so the it should always
// be nullptr.
auto it = offscreen_surfaces_.find(context->render_pass_id());
DCHECK(it != offscreen_surfaces_.end());
context->set_promise_image_texture(sk_ref_sp(it->second.fulfill()));
if (!context->promise_image_texture()) {
DLOG(ERROR) << "Failed to fulfill the promise texture created from "
"CompositorRenderPassId:"
<< context->render_pass_id();
}
} else {
context->BeginAccessIfNecessary(
context_state_.get(), shared_image_representation_factory_.get(),
dependency_->GetMailboxManager(), begin_semaphores, end_semaphores);
if (context->end_access_state())
image_contexts_with_end_access_state_.emplace(context);
context->BeginAccessIfNecessary(
context_state_.get(), shared_image_representation_factory_.get(),
dependency_->GetMailboxManager(), begin_semaphores, end_semaphores);
if (context->end_access_state())
image_contexts_with_end_access_state_.emplace(context);
// Texture parameters can be modified by concurrent reads so reset them
// before compositing from the texture. See https://crbug.com/1092080.
if (is_gl && context->maybe_concurrent_reads()) {
auto* promise_texture = context->promise_image_texture();
if (promise_texture) {
GrBackendTexture backend_texture = promise_texture->backendTexture();
backend_texture.glTextureParametersModified();
}
// Texture parameters can be modified by concurrent reads so reset them
// before compositing from the texture. See https://crbug.com/1092080.
if (is_gl && context->maybe_concurrent_reads()) {
auto* promise_texture = context->promise_image_texture();
if (promise_texture) {
GrBackendTexture backend_texture = promise_texture->backendTexture();
backend_texture.glTextureParametersModified();
}
}
}

@ -147,7 +147,7 @@ class SkiaOutputSurfaceImplOnGpu
void SwapBuffersSkipped();
void EnsureBackbuffer() { output_device_->EnsureBackbuffer(); }
void DiscardBackbuffer() { output_device_->DiscardBackbuffer(); }
void FinishPaintRenderPass(AggregatedRenderPassId id,
void FinishPaintRenderPass(const gpu::Mailbox& mailbox,
sk_sp<SkDeferredDisplayList> ddl,
std::vector<ImageContextImpl*> image_contexts,
std::vector<gpu::SyncToken> sync_tokens,
@ -160,7 +160,8 @@ class SkiaOutputSurfaceImplOnGpu
void CopyOutput(AggregatedRenderPassId id,
copy_output::RenderPassGeometry geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request);
std::unique_ptr<CopyOutputRequest> request,
const gpu::Mailbox& mailbox);
void BeginAccessImages(const std::vector<ImageContextImpl*>& image_contexts,
std::vector<GrBackendSemaphore>* begin_semaphores,
@ -228,7 +229,6 @@ class SkiaOutputSurfaceImplOnGpu
pending_receiver);
private:
class OffscreenSurface;
class DisplayContext;
bool Initialize();
@ -355,8 +355,6 @@ class SkiaOutputSurfaceImplOnGpu
absl::optional<OverlayProcessorInterface::OutputSurfaceOverlayPlane>
output_surface_plane_;
base::flat_map<AggregatedRenderPassId, OffscreenSurface> offscreen_surfaces_;
// Micro-optimization to get to issuing GPU SwapBuffers as soon as possible.
std::vector<sk_sp<SkDeferredDisplayList>> destroy_after_swap_;

@ -164,7 +164,7 @@ TEST_F(SkiaOutputSurfaceImplTest, EndPaint) {
geometry.readback_offset = gfx::Vector2d(0, 0);
output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
std::move(request));
std::move(request), gpu::Mailbox());
output_surface_->SwapBuffersSkipped(kSurfaceRect);
output_surface_->Flush();
BlockMainThread();
@ -231,7 +231,7 @@ TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapSupportedColorSpace) {
PaintRootRenderPass(kSurfaceRect, base::DoNothing::Once());
output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
std::move(request));
std::move(request), gpu::Mailbox());
output_surface_->SwapBuffersSkipped(kSurfaceRect);
output_surface_->Flush();
run_loop.Run();
@ -270,7 +270,7 @@ TEST_F(SkiaOutputSurfaceImplTest, CopyOutputBitmapUnsupportedColorSpace) {
PaintRootRenderPass(kSurfaceRect, base::DoNothing::Once());
output_surface_->CopyOutput(AggregatedRenderPassId{0}, geometry, color_space,
std::move(request));
std::move(request), gpu::Mailbox());
output_surface_->SwapBuffersSkipped(kSurfaceRect);
output_surface_->Flush();
run_loop.Run();

@ -193,7 +193,8 @@ SkCanvas* FakeSkiaOutputSurface::BeginPaintRenderPass(
const gfx::Size& surface_size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) {
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
// Make sure there is no unsubmitted PaintFrame or PaintRenderPass.
DCHECK_EQ(current_render_pass_id_, AggregatedRenderPassId{0u});
@ -225,7 +226,8 @@ sk_sp<SkImage> FakeSkiaOutputSurface::MakePromiseSkImageFromRenderPass(
const gfx::Size& size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) {
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto it = sk_surfaces_.find(id);
@ -249,7 +251,8 @@ void FakeSkiaOutputSurface::CopyOutput(
AggregatedRenderPassId id,
const copy_output::RenderPassGeometry& geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) {
std::unique_ptr<CopyOutputRequest> request,
const gpu::Mailbox& mailbox) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(sk_surfaces_.find(id) != sk_surfaces_.end());
@ -305,6 +308,10 @@ void FakeSkiaOutputSurface::CopyOutput(
geometry.result_bounds, std::move(bitmap)));
}
gpu::SharedImageInterface* FakeSkiaOutputSurface::GetSharedImageInterface() {
return context_provider_->SharedImageInterface();
}
void FakeSkiaOutputSurface::AddContextLostObserver(
ContextLostObserver* observer) {
NOTIMPLEMENTED();

@ -79,7 +79,8 @@ class FakeSkiaOutputSurface : public SkiaOutputSurface {
const gfx::Size& surface_size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) override;
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) override;
void EndPaint(base::OnceClosure on_finished) override;
void MakePromiseSkImage(ImageContext* image_context) override;
sk_sp<SkImage> MakePromiseSkImageFromRenderPass(
@ -87,7 +88,8 @@ class FakeSkiaOutputSurface : public SkiaOutputSurface {
const gfx::Size& size,
ResourceFormat format,
bool mipmap,
sk_sp<SkColorSpace> color_space) override;
sk_sp<SkColorSpace> color_space,
const gpu::Mailbox& mailbox) override;
void RemoveRenderPassResource(
std::vector<AggregatedRenderPassId> ids) override;
void ScheduleOverlays(OverlayList overlays,
@ -99,9 +101,11 @@ class FakeSkiaOutputSurface : public SkiaOutputSurface {
void CopyOutput(AggregatedRenderPassId id,
const copy_output::RenderPassGeometry& geometry,
const gfx::ColorSpace& color_space,
std::unique_ptr<CopyOutputRequest> request) override;
std::unique_ptr<CopyOutputRequest> request,
const gpu::Mailbox& mailbox) override;
void AddContextLostObserver(ContextLostObserver* observer) override;
void RemoveContextLostObserver(ContextLostObserver* observer) override;
gpu::SharedImageInterface* GetSharedImageInterface() override;
gpu::SyncToken Flush() override;
#if defined(OS_APPLE) || defined(USE_OZONE)
SkCanvas* BeginPaintRenderPassOverlay(