1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/viz/service/display_embedder/skia_output_device_dawn.h"
6 
7 #include "base/logging.h"
8 #include "build/build_config.h"
9 #include "components/viz/common/gpu/dawn_context_provider.h"
10 
11 #if defined(OS_WIN)
12 #include <dawn_native/D3D12Backend.h>
13 #elif defined(OS_LINUX)
14 #include <dawn_native/VulkanBackend.h>
15 #endif
16 
17 namespace viz {
18 
19 namespace {
20 
21 // Some Vulkan drivers do not support kRGB_888x_SkColorType. Always use
22 // kRGBA_8888_SkColorType instead and initialize surface to opaque as necessary.
23 constexpr SkColorType kSurfaceColorType = kRGBA_8888_SkColorType;
24 constexpr wgpu::TextureFormat kSwapChainFormat =
25     wgpu::TextureFormat::RGBA8Unorm;
26 
27 constexpr wgpu::TextureUsage kUsage =
28     wgpu::TextureUsage::OutputAttachment | wgpu::TextureUsage::CopySrc;
29 
30 }  // namespace
31 
SkiaOutputDeviceDawn(DawnContextProvider * context_provider,gfx::AcceleratedWidget widget,gfx::SurfaceOrigin origin,gpu::MemoryTracker * memory_tracker,DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)32 SkiaOutputDeviceDawn::SkiaOutputDeviceDawn(
33     DawnContextProvider* context_provider,
34     gfx::AcceleratedWidget widget,
35     gfx::SurfaceOrigin origin,
36     gpu::MemoryTracker* memory_tracker,
37     DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
38     : SkiaOutputDevice(memory_tracker, did_swap_buffer_complete_callback),
39       context_provider_(context_provider),
40       widget_(widget) {
41   capabilities_.output_surface_origin = origin;
42   capabilities_.uses_default_gl_framebuffer = false;
43   capabilities_.supports_post_sub_buffer = false;
44 
45   capabilities_.sk_color_type = kSurfaceColorType;
46   capabilities_.gr_backend_format =
47       context_provider_->GetGrContext()->defaultBackendFormat(
48           kSurfaceColorType, GrRenderable::kYes);
49 }
50 
51 SkiaOutputDeviceDawn::~SkiaOutputDeviceDawn() = default;
52 
Reshape(const gfx::Size & size,float device_scale_factor,const gfx::ColorSpace & color_space,gfx::BufferFormat format,gfx::OverlayTransform transform)53 bool SkiaOutputDeviceDawn::Reshape(const gfx::Size& size,
54                                    float device_scale_factor,
55                                    const gfx::ColorSpace& color_space,
56                                    gfx::BufferFormat format,
57                                    gfx::OverlayTransform transform) {
58   DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE);
59 
60   size_ = size;
61   sk_color_space_ = color_space.ToSkColorSpace();
62 
63   CreateSwapChainImplementation();
64   wgpu::SwapChainDescriptor desc;
65   desc.implementation = reinterpret_cast<int64_t>(&swap_chain_implementation_);
66   // TODO(sgilhuly): Use a wgpu::Surface in this call once the Surface-based
67   // SwapChain API is ready.
68   swap_chain_ = context_provider_->GetDevice().CreateSwapChain(nullptr, &desc);
69   if (!swap_chain_)
70     return false;
71   swap_chain_.Configure(kSwapChainFormat, kUsage, size_.width(),
72                         size_.height());
73   return true;
74 }
75 
SwapBuffers(BufferPresentedCallback feedback,std::vector<ui::LatencyInfo> latency_info)76 void SkiaOutputDeviceDawn::SwapBuffers(
77     BufferPresentedCallback feedback,
78     std::vector<ui::LatencyInfo> latency_info) {
79   StartSwapBuffers(std::move(feedback));
80   swap_chain_.Present();
81   FinishSwapBuffers(gfx::SwapResult::SWAP_ACK,
82                     gfx::Size(size_.width(), size_.height()),
83                     std::move(latency_info));
84 }
85 
BeginPaint(std::vector<GrBackendSemaphore> * end_semaphores)86 SkSurface* SkiaOutputDeviceDawn::BeginPaint(
87     std::vector<GrBackendSemaphore>* end_semaphores) {
88   GrDawnRenderTargetInfo info;
89   info.fTextureView = swap_chain_.GetCurrentTextureView();
90   info.fFormat = kSwapChainFormat;
91   info.fLevelCount = 1;
92   GrBackendRenderTarget backend_target(
93       size_.width(), size_.height(), /*sampleCnt=*/0, /*stencilBits=*/0, info);
94   DCHECK(backend_target.isValid());
95   // LegacyFontHost will get LCD text and skia figures out what type to use.
96   SkSurfaceProps surface_props(/*flags=*/0,
97                                SkSurfaceProps::kLegacyFontHost_InitType);
98   sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
99       context_provider_->GetGrContext(), backend_target,
100       capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft
101           ? kTopLeft_GrSurfaceOrigin
102           : kBottomLeft_GrSurfaceOrigin,
103       kSurfaceColorType, sk_color_space_, &surface_props);
104   return sk_surface_.get();
105 }
106 
EndPaint()107 void SkiaOutputDeviceDawn::EndPaint() {
108   GrFlushInfo flush_info;
109   sk_surface_->flush(SkSurface::BackendSurfaceAccess::kPresent, flush_info);
110   sk_surface_.reset();
111 }
112 
CreateSwapChainImplementation()113 void SkiaOutputDeviceDawn::CreateSwapChainImplementation() {
114 #if defined(OS_WIN)
115   swap_chain_implementation_ = dawn_native::d3d12::CreateNativeSwapChainImpl(
116       context_provider_->GetDevice().Get(), widget_);
117 #else
118   NOTREACHED();
119   ALLOW_UNUSED_LOCAL(widget_);
120 #endif
121 }
122 
123 }  // namespace viz
124