Commit b0478d0c authored by Peng Huang's avatar Peng Huang Committed by Commit Bot

SkiaRenderer: Add SkiaOutputSurface to allow SkiaRenderer to use SkDDL

This CL adds a new interface viz::SkiaOutputSurface which extends
viz::OutputSurface for SkiaRenderer to support compositing with SkDDL
(skia deferred display list). SkiaRenderer draws quads into a DDL SkCanvas,
and draw operations will be recorded into a DDL.
In OutputSurface::SwapBuffers(), a GPU task will be scheduled with
gpu::Schduler. The task will be executed on the GPU thread when all resource
sync tokes are satisfied. The task will play the DDL back on a GrContext
which is backed by a native platform GL context.

We have a goal to use SkiaRenderer everywhere, and remove GLRenderer and
Software Compositor. The new viz::SkiaOutputSurface interface and
viz::OutputSurface interface will be merged into one interface when DirectRenderer
subclasses are removed. The new interface is for making development
faster because when we change methods in viz::SkiaOutputSurface, we will not break
all other existing OutputSurface implementations.

Bug: 824382
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel;master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I776a76dc8496d40f88950856867596f5c44f735f
Reviewed-on: https://chromium-review.googlesource.com/978366
Commit-Queue: Peng Huang <penghuang@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553815}
parent df34887d
......@@ -69,6 +69,8 @@ viz_component("service") {
"display/scoped_render_pass_texture.h",
"display/shader.cc",
"display/shader.h",
"display/skia_output_surface.cc",
"display/skia_output_surface.h",
"display/skia_renderer.cc",
"display/skia_renderer.h",
"display/software_output_device.cc",
......@@ -101,6 +103,8 @@ viz_component("service") {
"display_embedder/in_process_gpu_memory_buffer_manager.h",
"display_embedder/server_shared_bitmap_manager.cc",
"display_embedder/server_shared_bitmap_manager.h",
"display_embedder/skia_output_surface_impl.cc",
"display_embedder/skia_output_surface_impl.h",
"display_embedder/software_output_surface.cc",
"display_embedder/software_output_surface.h",
"display_embedder/viz_process_context_provider.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)) {
......@@ -214,8 +217,10 @@ 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)
......
......@@ -40,6 +40,7 @@ class DirectRenderer;
class DisplayClient;
class OutputSurface;
class SharedBitmapManager;
class SkiaOutputSurface;
class SoftwareRenderer;
class VIZ_SERVICE_EXPORT DisplayObserver {
......@@ -61,12 +62,15 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
// 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;
......@@ -146,6 +150,7 @@ 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_;
......
// 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
// 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/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 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;
// 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;
private:
DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurface);
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_OUTPUT_SURFACE_H_
......@@ -20,10 +20,12 @@
#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"
......@@ -66,19 +68,81 @@ struct SkiaRenderer::DrawRenderPassDrawQuadParams {
gfx::RectF tex_coord_rect;
};
namespace {
bool IsTextureResource(cc::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();
const SkImage* sk_image() const { return sk_image_; }
private:
std::unique_ptr<cc::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<cc::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);
if (!metadata.mailbox.IsZero()) {
image = skia_renderer->skia_output_surface_->MakePromiseSkImage(
std::move(metadata));
DCHECK(image);
}
}
sk_image_ = image.get();
}
}
SkiaRenderer::ScopedSkImageBuilder::~ScopedSkImageBuilder() = default;
SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
cc::DisplayResourceProvider* resource_provider)
: DirectRenderer(settings, output_surface, resource_provider) {
cc::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) {
#if BUILDFLAG(ENABLE_VULKAN)
use_swap_with_bounds_ = false;
#else
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());
output_surface_->context_provider()->ContextGL());
}
#endif
}
......@@ -114,14 +178,17 @@ void SkiaRenderer::BeginDrawingFrame() {
}
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.
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
}
......@@ -166,7 +233,16 @@ 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_;
}
if (skia_output_surface_) {
auto sync_token =
skia_output_surface_->SkiaSwapBuffers(std::move(output_frame));
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();
}
......@@ -215,12 +291,16 @@ void SkiaRenderer::BindFramebufferToOutputSurface() {
root_surface_ = SkSurface::MakeFromBackendRenderTarget(
gr_context, render_target, kTopLeft_GrSurfaceOrigin,
kBGRA_8888_SkColorType, nullptr, &surface_props);
root_canvas_ = root_surface_->getCanvas();
#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 ||
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
......@@ -235,10 +315,10 @@ 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(
......@@ -257,6 +337,14 @@ void SkiaRenderer::BindFramebufferToOutputSurface() {
}
void SkiaRenderer::BindFramebufferToTexture(const RenderPassId render_pass_id) {
if (skia_output_surface_) {
// TODO(penghuang): Support it with DDL.
non_root_surface_ = nullptr;
current_canvas_ = nullptr;
current_surface_ = nullptr;
NOTIMPLEMENTED();
return;
}
auto iter = render_pass_backings_.find(render_pass_id);
DCHECK(render_pass_backings_.end() != iter);
// This function is called after AllocateRenderPassResourceIfNeeded, so there
......@@ -507,10 +595,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(
......@@ -549,9 +635,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),
......@@ -562,7 +648,7 @@ 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),
&current_paint_);
}
......@@ -635,6 +721,11 @@ bool SkiaRenderer::CalculateRPDQParams(sk_sp<SkImage> content,
}
void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
if (skia_output_surface_) {
// TODO(penghuang): Support render pass quad.
DrawUnsupportedQuad(quad);
return;
}
auto iter = render_pass_backings_.find(quad->render_pass_id);
DCHECK(render_pass_backings_.end() != iter);
// This function is called after AllocateRenderPassResourceIfNeeded, so there
......@@ -717,6 +808,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());
......@@ -755,6 +852,10 @@ void SkiaRenderer::DidChangeVisibility() {
}
void SkiaRenderer::FinishDrawingQuadList() {
// TODO(penghuang): Flush a SkDDL surface will crash. Remove it when the issue
// is fixed in skia.
if (skia_output_surface_)
return;
current_canvas_->flush();
}
......
......@@ -15,11 +15,6 @@
class SkNWayCanvas;
namespace cc {
class OutputSurface;
class RenderPassDrawQuad;
} // namespace cc
namespace gpu {
struct Capabilities;
}
......@@ -27,16 +22,18 @@ struct Capabilities;
namespace viz {
class DebugBorderDrawQuad;
class PictureDrawQuad;
class SkiaOutputSurface;
class SolidColorDrawQuad;
class TextureDrawQuad;
class TileDrawQuad;
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);
cc::DisplayResourceProvider* resource_provider,
SkiaOutputSurface* skia_output_surface = nullptr);
~SkiaRenderer() override;
void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override;
......@@ -77,6 +74,7 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
private:
struct DrawRenderPassDrawQuadParams;
class ScopedSkImageBuilder;
void ClearCanvas(SkColor color);
void ClearFramebuffer();
......@@ -127,9 +125,10 @@ 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_;
sk_sp<SkSurface> root_surface_;
......@@ -148,6 +147,19 @@ 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.
cc::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_;
DISALLOW_COPY_AND_ASSIGN(SkiaRenderer);
};
......
......@@ -10,8 +10,10 @@ include_rules = [
"+components/viz/service/display/output_surface_frame.h",
"+components/viz/service/display/output_surface.h",
"+components/viz/service/display/overlay_candidate_validator.h",
"+components/viz/service/display/skia_output_surface.h",
"+components/viz/service/display/software_output_device.h",
"+gpu/config/gpu_feature_info.h",
"+components/viz/service/gl/gpu_service_impl.h",
"+gpu/GLES2",
"+gpu/command_buffer/client",
"+gpu/command_buffer/common",
......
......@@ -7,6 +7,7 @@
#include <utility>
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/base/switches.h"
#include "components/viz/common/display/renderer_settings.h"
......@@ -17,6 +18,7 @@
#include "components/viz/service/display_embedder/gl_output_surface.h"
#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
#include "components/viz/service/display_embedder/software_output_surface.h"
#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "gpu/command_buffer/client/shared_memory_limits.h"
......@@ -64,11 +66,13 @@ namespace viz {
GpuDisplayProvider::GpuDisplayProvider(
uint32_t restart_id,
GpuServiceImpl* gpu_service_impl,
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
gpu::GpuChannelManager* gpu_channel_manager,
bool headless,
bool wait_for_all_pipeline_stages_before_draw)
: restart_id_(restart_id),
gpu_service_impl_(gpu_service_impl),
gpu_service_(std::move(gpu_service)),
gpu_channel_manager_delegate_(gpu_channel_manager->delegate()),
gpu_memory_buffer_manager_(
......@@ -103,11 +107,37 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
display_begin_frame_source = synthetic_begin_frame_source.get();
}
// TODO(penghuang): Merge two output surfaces into one when GLRenderer and
// software compositor is removed.
std::unique_ptr<OutputSurface> output_surface;
SkiaOutputSurface* skia_output_surface = nullptr;
if (!gpu_compositing) {
output_surface = std::make_unique<SoftwareOutputSurface>(
CreateSoftwareOutputDeviceForPlatform(surface_handle), task_runner_);
} else if (renderer_settings.use_skia_renderer &&
renderer_settings.use_skia_deferred_display_list) {
#if defined(OS_MACOSX) || defined(OS_WIN)
// TODO(penghuang): Support DDL for all platforms.
NOTIMPLEMENTED();
// Workaround compile error: private field 'gpu_service_impl_' is not used.
ALLOW_UNUSED_LOCAL(gpu_service_impl_);
#else
// Create an offscreen context_provider for SkiaOutputSurfaceImpl, because
// SkiaRenderer still needs it to draw RenderPass into a texture.
// TODO(penghuang): remove this context when we figure out how to use DDL
// to draw RenderPass. https://crbug.com/825901
auto context_provider = base::MakeRefCounted<VizProcessContextProvider>(
gpu_service_, gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(),
image_factory_, gpu_channel_manager_delegate_,
gpu::SharedMemoryLimits());
auto result = context_provider->BindToCurrentThread();
CHECK_EQ(result, gpu::ContextResult::kSuccess);
output_surface = std::make_unique<SkiaOutputSurfaceImpl>(
gpu_service_impl_, surface_handle, std::move(context_provider),
synthetic_begin_frame_source.get());
skia_output_surface = static_cast<SkiaOutputSurface*>(output_surface.get());
#endif
} else {
scoped_refptr<VizProcessContextProvider> context_provider;
......@@ -166,7 +196,8 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
return std::make_unique<Display>(
ServerSharedBitmapManager::current(), renderer_settings, frame_sink_id,
std::move(output_surface), std::move(scheduler), task_runner_);
std::move(output_surface), std::move(scheduler), task_runner_,
skia_output_surface);
}
std::unique_ptr<SoftwareOutputDevice>
......
......@@ -27,6 +27,7 @@ class ImageFactory;
namespace viz {
class Display;
class ExternalBeginFrameControllerImpl;
class GpuServiceImpl;
class OutputDeviceBacking;
class SoftwareOutputDevice;
......@@ -35,6 +36,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
public:
GpuDisplayProvider(
uint32_t restart_id,
GpuServiceImpl* gpu_service_impl,
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
gpu::GpuChannelManager* gpu_channel_manager,
bool headless,
......@@ -56,6 +58,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
gpu::SurfaceHandle surface_handle);
const uint32_t restart_id_;
GpuServiceImpl* const gpu_service_impl_;
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_;
gpu::GpuChannelManagerDelegate* const gpu_channel_manager_delegate_;
std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
#include "base/atomic_sequence_num.h"
#include "base/callback_helpers.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/resources/resource_metadata.h"
#include "components/viz/service/display/output_surface_client.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
#include "gpu/command_buffer/service/gpu_preferences.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/scheduler.h"
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "gpu/command_buffer/service/texture_base.h"
#include "gpu/ipc/service/image_transport_surface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_version_info.h"
namespace viz {
namespace {
base::AtomicSequenceNumber g_next_command_buffer_id;
} // namespace
struct SkiaOutputSurfaceImpl::PromiseTextureInfo {
PromiseTextureInfo(SkiaOutputSurfaceImpl* skia_renderer,
ResourceMetadata&& metadata)
: skia_renderer(skia_renderer), resource_metadata(std::move(metadata)) {}
~PromiseTextureInfo() = default;
SkiaOutputSurfaceImpl* const skia_renderer;
ResourceMetadata resource_metadata;
};
SkiaOutputSurfaceImpl::SkiaOutputSurfaceImpl(
GpuServiceImpl* gpu_service,
gpu::SurfaceHandle surface_handle,
scoped_refptr<VizProcessContextProvider> context_provider,
SyntheticBeginFrameSource* synthetic_begin_frame_source)
: SkiaOutputSurface(context_provider),
command_buffer_id_(gpu::CommandBufferId::FromUnsafeValue(
g_next_command_buffer_id.GetNext() + 1)),
gpu_service_(gpu_service),
surface_handle_(surface_handle),
synthetic_begin_frame_source_(synthetic_begin_frame_source),
gpu_thread_weak_ptr_factory_(this),
client_thread_weak_ptr_factory_(this) {
DETACH_FROM_THREAD(client_thread_checker_);
DETACH_FROM_THREAD(gpu_thread_checker_);
}
SkiaOutputSurfaceImpl::~SkiaOutputSurfaceImpl() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
recorder_ = nullptr;
// TODO(penghuang): avoid blocking compositor thread.
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::DestroyOnGpuThread,
base::Unretained(this), &event);
gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
event.Wait();
}
void SkiaOutputSurfaceImpl::BindToClient(OutputSurfaceClient* client) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
DCHECK(client);
DCHECK(!client_);
client_ = client;
client_thread_weak_ptr_ = client_thread_weak_ptr_factory_.GetWeakPtr();
client_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
// TODO(penghuang): avoid blocking compositor thread.
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
base::Unretained(this), &event);
gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
event.Wait();
}
void SkiaOutputSurfaceImpl::EnsureBackbuffer() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
NOTIMPLEMENTED();
}
void SkiaOutputSurfaceImpl::DiscardBackbuffer() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
NOTIMPLEMENTED();
}
void SkiaOutputSurfaceImpl::BindFramebuffer() {
// TODO(penghuang): remove this method when GLRenderer is removed.
}
void SkiaOutputSurfaceImpl::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
NOTIMPLEMENTED();
}
void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
bool has_alpha,
bool use_stencil) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
recorder_ = nullptr;
SkSurfaceCharacterization* characterization = nullptr;
std::unique_ptr<base::WaitableEvent> event;
if (characterization_.isValid()) {
characterization_ =
characterization_.createResized(size.width(), size.height());
} else {
characterization = &characterization_;
// TODO(penghuang): avoid blocking compositor thread.
// We don't have a valid surface characterization, so we have to wait until
// reshape is finished on Gpu thread.
event = std::make_unique<base::WaitableEvent>(
base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
}
auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::ReshapeOnGpuThread,
base::Unretained(this), size,
device_scale_factor, color_space, has_alpha,
use_stencil, characterization, event.get());
gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
if (event)
event->Wait();
RecreateRecorder();
}
void SkiaOutputSurfaceImpl::SwapBuffers(OutputSurfaceFrame frame) {
NOTREACHED();
}
uint32_t SkiaOutputSurfaceImpl::GetFramebufferCopyTextureFormat() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
return GL_RGB;
}
OverlayCandidateValidator* SkiaOutputSurfaceImpl::GetOverlayCandidateValidator()
const {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
return nullptr;
}
bool SkiaOutputSurfaceImpl::IsDisplayedAsOverlayPlane() const {
return false;
}
unsigned SkiaOutputSurfaceImpl::GetOverlayTextureId() const {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
return 0;
}
gfx::BufferFormat SkiaOutputSurfaceImpl::GetOverlayBufferFormat() const {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
return gfx::BufferFormat::RGBX_8888;
}
bool SkiaOutputSurfaceImpl::SurfaceIsSuspendForRecycle() const {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
return false;
}
bool SkiaOutputSurfaceImpl::HasExternalStencilTest() const {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
return false;
}
void SkiaOutputSurfaceImpl::ApplyExternalStencil() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
}
#if BUILDFLAG(ENABLE_VULKAN)
gpu::VulkanSurface* SkiaOutputSurfaceImpl::GetVulkanSurface() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
return nullptr;
}
#endif
SkCanvas* SkiaOutputSurfaceImpl::GetSkCanvasForCurrentFrame() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
DCHECK(recorder_);
return recorder_->getCanvas();
}
sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImage(
ResourceMetadata metadata) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
DCHECK(recorder_);
// Convert internal format from GLES2 to platform GL.
const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo();
metadata.backend_format = GrBackendFormat::MakeGL(
gl::GetInternalFormat(version_info,
*metadata.backend_format.getGLFormat()),
*metadata.backend_format.getGLTarget());
DCHECK(!metadata.mailbox.IsZero());
resource_sync_tokens_.push_back(metadata.sync_token);
auto texture_info =
std::make_unique<PromiseTextureInfo>(this, std::move(metadata));
const auto& data = texture_info->resource_metadata;
auto image = recorder_->makePromiseTexture(
data.backend_format, data.size.width(), data.size.height(),
data.mip_mapped, data.origin, data.color_type, data.alpha_type,
data.color_space, SkiaOutputSurfaceImpl::PromiseTextureFullfillStub,
SkiaOutputSurfaceImpl::PromiseTextureReleaseStub,
SkiaOutputSurfaceImpl::PromiseTextureDoneStub, texture_info.get());
if (image)
texture_info.release();
return image;
}
gpu::SyncToken SkiaOutputSurfaceImpl::SkiaSwapBuffers(
OutputSurfaceFrame frame) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
DCHECK(recorder_);
gpu::SyncToken sync_token(gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE,
command_buffer_id_, ++sync_fence_release_);
sync_token.SetVerifyFlush();
auto ddl = recorder_->detach();
DCHECK(ddl);
RecreateRecorder();
auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::SwapBuffersOnGpuThread,
base::Unretained(this), base::Passed(&frame),
base::Passed(&ddl), sync_fence_release_);
gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
sequence_id, std::move(callback), std::move(resource_sync_tokens_)));
return sync_token;
}
void SkiaOutputSurfaceImpl::DidSwapBuffersComplete(
gpu::SwapBuffersCompleteParams params) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
client_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SkiaOutputSurfaceImpl::DidSwapBuffersCompleteOnClientThread,
client_thread_weak_ptr_, params));
}
const gpu::gles2::FeatureInfo* SkiaOutputSurfaceImpl::GetFeatureInfo() const {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
NOTIMPLEMENTED();
return nullptr;
}
const gpu::GpuPreferences& SkiaOutputSurfaceImpl::GetGpuPreferences() const {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
NOTIMPLEMENTED();
return gpu_preferences_;
}
void SkiaOutputSurfaceImpl::SetSnapshotRequestedCallback(
const base::Closure& callback) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
NOTIMPLEMENTED();
}
void SkiaOutputSurfaceImpl::UpdateVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
client_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&SkiaOutputSurfaceImpl::UpdateVSyncParametersOnClientThread,
client_thread_weak_ptr_, timebase, interval));
}
void SkiaOutputSurfaceImpl::BufferPresented(
uint64_t swap_id,
const gfx::PresentationFeedback& feedback) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
client_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&SkiaOutputSurfaceImpl::BufferPresentedOnClientThread,
client_thread_weak_ptr_, swap_id, feedback));
}
void SkiaOutputSurfaceImpl::AddFilter(IPC::MessageFilter* message_filter) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
NOTIMPLEMENTED();
}
int32_t SkiaOutputSurfaceImpl::GetRouteID() const {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
NOTIMPLEMENTED();
return 0;
}
void SkiaOutputSurfaceImpl::InitializeOnGpuThread(base::WaitableEvent* event) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
base::ScopedClosureRunner scoped_runner(
base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
sync_point_client_state_ =
gpu_service_->sync_point_manager()->CreateSyncPointClientState(
gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE, command_buffer_id_,
gpu_service_->skia_output_surface_sequence_id());
surface_ = gpu::ImageTransportSurface::CreateNativeSurface(
gpu_thread_weak_ptr_factory_.GetWeakPtr(), surface_handle_,
gl::GLSurfaceFormat());
DCHECK(surface_);
if (!gpu_service_->CreateGrContextIfNecessary(surface_.get())) {
LOG(FATAL) << "Failed to create GrContext";
// TODO(penghuang): handle the failure.
}
DCHECK(gpu_service_->context_for_skia());
DCHECK(gpu_service_->gr_context());
if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
LOG(FATAL) << "Failed to make current.";
// TODO(penghuang): Handle the failure.
}
capabilities_.flipped_output_surface = surface_->FlipsVertically();
// Get stencil bits from the default frame buffer.
auto* current_gl = gpu_service_->context_for_skia()->GetCurrentGL();
const auto* version = current_gl->Version;
auto* api = current_gl->Api;
GLint stencil_bits = 0;
if (version->is_desktop_core_profile) {
api->glGetFramebufferAttachmentParameterivEXTFn(
GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
&stencil_bits);
} else {
api->glGetIntegervFn(GL_STENCIL_BITS, &stencil_bits);
}
capabilities_.supports_stencil = stencil_bits > 0;
}
void SkiaOutputSurfaceImpl::DestroyOnGpuThread(base::WaitableEvent* event) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
base::ScopedClosureRunner scoped_runner(
base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
gpu_thread_weak_ptr_factory_.InvalidateWeakPtrs();
// Destroy the surface with the context current, some surface destructors make
// GL calls.
if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
LOG(FATAL) << "Failed to make current.";
// TODO(penghuang): Handle the failure.
}
surface_ = nullptr;
sync_point_client_state_ = nullptr;
}
void SkiaOutputSurfaceImpl::ReshapeOnGpuThread(
const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
bool has_alpha,
bool use_stencil,
SkSurfaceCharacterization* characterization,
base::WaitableEvent* event) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
std::unique_ptr<base::ScopedClosureRunner> scoped_runner;
if (event) {
scoped_runner = std::make_unique<base::ScopedClosureRunner>(
base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
}
if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
LOG(FATAL) << "Failed to make current.";
// TODO(penghuang): Handle the failure.
}
gl::GLSurface::ColorSpace surface_color_space =
color_space == gfx::ColorSpace::CreateSCRGBLinear()
? gl::GLSurface::ColorSpace::SCRGB_LINEAR
: gl::GLSurface::ColorSpace::UNSPECIFIED;
if (!surface_->Resize(size, device_scale_factor, surface_color_space,
has_alpha)) {
LOG(FATAL) << "Failed to resize.";
// TODO(penghuang): Handle the failure.
}
DCHECK(gpu_service_->context_for_skia()->IsCurrent(surface_.get()));
DCHECK(gpu_service_->gr_context());
SkSurfaceProps surface_props =
SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
GrGLFramebufferInfo framebuffer_info;
framebuffer_info.fFBOID = 0;
const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo();
framebuffer_info.fFormat = version_info->is_es ? GL_BGRA8_EXT : GL_RGBA8;
GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8,
framebuffer_info);
sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
gpu_service_->gr_context(), render_target, kBottomLeft_GrSurfaceOrigin,
kBGRA_8888_SkColorType, nullptr, &surface_props);
DCHECK(sk_surface_);
if (characterization) {
sk_surface_->characterize(characterization);
DCHECK(characterization->isValid());
}
}
void SkiaOutputSurfaceImpl::SwapBuffersOnGpuThread(
OutputSurfaceFrame frame,
std::unique_ptr<SkDeferredDisplayList> ddl,
uint64_t sync_fence_release) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
DCHECK(ddl);
DCHECK(sk_surface_);
if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
LOG(FATAL) << "Failed to make current.";
// TODO(penghuang): Handle the failure.
}
sk_surface_->draw(ddl.get());
gpu_service_->gr_context()->flush();
surface_->SwapBuffers(
base::BindRepeating([](const gfx::PresentationFeedback&) {}));
sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
}
void SkiaOutputSurfaceImpl::RecreateRecorder() {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
DCHECK(characterization_.isValid());
recorder_ =
std::make_unique<SkDeferredDisplayListRecorder>(characterization_);
// TODO(penghuang): remove the unnecessary getCanvas() call, when the recorder
// crash is fixed in skia.
recorder_->getCanvas();
}
void SkiaOutputSurfaceImpl::DidSwapBuffersCompleteOnClientThread(
gpu::SwapBuffersCompleteParams params) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
DCHECK(client_);
if (!params.texture_in_use_responses.empty())
client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses);
if (!params.ca_layer_params.is_empty)
client_->DidReceiveCALayerParams(params.ca_layer_params);
client_->DidReceiveSwapBuffersAck(params.swap_response.swap_id);
}
void SkiaOutputSurfaceImpl::UpdateVSyncParametersOnClientThread(
base::TimeTicks timebase,
base::TimeDelta interval) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
if (synthetic_begin_frame_source_) {
// TODO(brianderson): We should not be receiving 0 intervals.
synthetic_begin_frame_source_->OnUpdateVSyncParameters(
timebase,
interval.is_zero() ? BeginFrameArgs::DefaultInterval() : interval);
}
}
void SkiaOutputSurfaceImpl::BufferPresentedOnClientThread(
uint64_t swap_id,
const gfx::PresentationFeedback& feedback) {
DCHECK_CALLED_ON_VALID_THREAD(client_thread_checker_);
DCHECK(client_);
client_->DidReceivePresentationFeedback(swap_id, feedback);
}
// static
void SkiaOutputSurfaceImpl::PromiseTextureFullfillStub(
void* texture_context,
GrBackendTexture* backend_texture) {
DCHECK(texture_context);
auto* info = static_cast<PromiseTextureInfo*>(texture_context);
info->skia_renderer->OnPromiseTextureFullfill(info->resource_metadata,
backend_texture);
}
// static
void SkiaOutputSurfaceImpl::PromiseTextureReleaseStub(void* texture_context) {
DCHECK(texture_context);
auto* info = static_cast<PromiseTextureInfo*>(texture_context);
info->skia_renderer->OnPromiseTextureRelease(info->resource_metadata);
}
// static
void SkiaOutputSurfaceImpl::PromiseTextureDoneStub(void* texture_context) {
DCHECK(texture_context);
std::unique_ptr<PromiseTextureInfo> info(
static_cast<PromiseTextureInfo*>(texture_context));
}
void SkiaOutputSurfaceImpl::OnPromiseTextureFullfill(
const ResourceMetadata& metadata,
GrBackendTexture* backend_texture) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
auto* mailbox_manager = gpu_service_->mailbox_manager();
auto* texture_base = mailbox_manager->ConsumeTexture(metadata.mailbox);
if (!texture_base) {
DLOG(ERROR) << "Failed to full fill the promise texture.";
return;
}
GrGLTextureInfo texture_info;
texture_info.fTarget = texture_base->target();
texture_info.fID = texture_base->service_id();
// TODO(penghuang): Get the format correctly.
texture_info.fFormat = GL_RGBA8;
*backend_texture =
GrBackendTexture(metadata.size.width(), metadata.size.height(),
metadata.mip_mapped, texture_info);
}
void SkiaOutputSurfaceImpl::OnPromiseTextureRelease(
const ResourceMetadata& metadata) {
DCHECK_CALLED_ON_VALID_THREAD(gpu_thread_checker_);
}
} // namespace viz
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "components/viz/service/display/skia_output_surface.h"
#include "gpu/command_buffer/common/sync_token.h"
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "gpu/ipc/service/image_transport_surface_delegate.h"
#include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h"
#include "third_party/skia/include/core/SkSurface.h"
namespace base {
class WaitableEvent;
}
namespace gl {
class GLSurface;
}
namespace gpu {
class SyncPointClientState;
}
namespace viz {
class GpuServiceImpl;
class VizProcessContextProvider;
class SyntheticBeginFrameSource;
// The SkiaOutputSurface implementation. It is the output surface for
// SkiaRenderer. It lives on the compositor thread, but it will post tasks
// to the GPU thread for initializing, reshaping and swapping buffers, etc.
// Currently, SkiaOutputSurfaceImpl sets up SkSurface from the default GL
// framebuffer, creates SkDeferredDisplayListRecorder and SkCanvas for
// SkiaRenderer to render into. In SwapBuffers, it detaches a
// SkDeferredDisplayList from the recorder and plays it back on the framebuffer
// SkSurface on the GPU thread.
class SkiaOutputSurfaceImpl : public SkiaOutputSurface,
public gpu::ImageTransportSurfaceDelegate {
public:
SkiaOutputSurfaceImpl(
GpuServiceImpl* gpu_service,
gpu::SurfaceHandle surface_handle,
scoped_refptr<VizProcessContextProvider> context_provider,
SyntheticBeginFrameSource* synthetic_begin_frame_source);
~SkiaOutputSurfaceImpl() override;
// OutputSurface implementation:
void BindToClient(OutputSurfaceClient* client) override;
void EnsureBackbuffer() override;
void DiscardBackbuffer() override;
void BindFramebuffer() override;
void SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
void Reshape(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
bool has_alpha,
bool use_stencil) override;
void SwapBuffers(OutputSurfaceFrame frame) override;
uint32_t GetFramebufferCopyTextureFormat() override;
OverlayCandidateValidator* GetOverlayCandidateValidator() const override;
bool IsDisplayedAsOverlayPlane() const override;
unsigned GetOverlayTextureId() const override;
gfx::BufferFormat GetOverlayBufferFormat() const override;
bool SurfaceIsSuspendForRecycle() const override;
bool HasExternalStencilTest() const override;
void ApplyExternalStencil() override;
#if BUILDFLAG(ENABLE_VULKAN)
gpu::VulkanSurface* GetVulkanSurface() override;
#endif
// SkiaOutputSurface implementation:
SkCanvas* GetSkCanvasForCurrentFrame() override;
sk_sp<SkImage> MakePromiseSkImage(ResourceMetadata metadata) override;
gpu::SyncToken SkiaSwapBuffers(OutputSurfaceFrame frame) override;
// gpu::ImageTransportSurfaceDelegate implementation:
void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params) override;
const gpu::gles2::FeatureInfo* GetFeatureInfo() const override;
const gpu::GpuPreferences& GetGpuPreferences() const override;
void SetSnapshotRequestedCallback(const base::Closure& callback) override;
void UpdateVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
void BufferPresented(uint64_t swap_id,
const gfx::PresentationFeedback& feedback) override;
void AddFilter(IPC::MessageFilter* message_filter) override;
int32_t GetRouteID() const override;
private:
void InitializeOnGpuThread(base::WaitableEvent* event);
void DestroyOnGpuThread(base::WaitableEvent* event);
void ReshapeOnGpuThread(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
bool has_alpha,
bool use_stencil,
SkSurfaceCharacterization* characterization,
base::WaitableEvent* event);
void SwapBuffersOnGpuThread(OutputSurfaceFrame frame,
std::unique_ptr<SkDeferredDisplayList> ddl,
uint64_t sync_fence_release);
void RecreateRecorder();
void DidSwapBuffersCompleteOnClientThread(
gpu::SwapBuffersCompleteParams params);
void UpdateVSyncParametersOnClientThread(base::TimeTicks timebase,
base::TimeDelta interval);
void BufferPresentedOnClientThread(uint64_t swap_id,
const gfx::PresentationFeedback& feedback);
struct PromiseTextureInfo;
static void PromiseTextureFullfillStub(void* texture_context,
GrBackendTexture* backend_texture);
static void PromiseTextureReleaseStub(void* texture_context);
static void PromiseTextureDoneStub(void* texture_context);
void OnPromiseTextureFullfill(const ResourceMetadata& metadata,
GrBackendTexture* backend_texture);
void OnPromiseTextureRelease(const ResourceMetadata& metadata);
const gpu::CommandBufferId command_buffer_id_;
uint64_t sync_fence_release_ = 0;
GpuServiceImpl* const gpu_service_;
const gpu::SurfaceHandle surface_handle_;
SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
OutputSurfaceClient* client_ = nullptr;
scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_;
gpu::GpuPreferences gpu_preferences_;
scoped_refptr<gl::GLSurface> surface_;
sk_sp<SkSurface> sk_surface_;
SkSurfaceCharacterization characterization_;
std::unique_ptr<SkDeferredDisplayListRecorder> recorder_;
// Sync tokens for resources which are used for the current frame.
std::vector<gpu::SyncToken> resource_sync_tokens_;
scoped_refptr<base::SingleThreadTaskRunner> client_thread_task_runner_;
THREAD_CHECKER(client_thread_checker_);
THREAD_CHECKER(gpu_thread_checker_);
base::WeakPtr<SkiaOutputSurfaceImpl> client_thread_weak_ptr_;
base::WeakPtrFactory<SkiaOutputSurfaceImpl> gpu_thread_weak_ptr_factory_;
base::WeakPtrFactory<SkiaOutputSurfaceImpl> client_thread_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurfaceImpl);
};
} // namespace viz
#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_
......@@ -280,7 +280,7 @@ void VizMainImpl::CreateFrameSinkManagerOnCompositorThread(
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
display_provider_ = std::make_unique<GpuDisplayProvider>(
params->restart_id, gpu_command_service_,
params->restart_id, gpu_service_.get(), gpu_command_service_,
gpu_service_->gpu_channel_manager(),
command_line->HasSwitch(switches::kHeadless),
command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw));
......
......@@ -84,8 +84,7 @@ enum CommandBufferNamespace : int8_t {
GPU_IO,
IN_PROCESS,
MOJO,
MOJO_LOCAL,
VIZ_OUTPUT_SURFACE,
NUM_COMMAND_BUFFER_NAMESPACES
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment