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_offscreen.h"
6 
7 #include <utility>
8 
9 #include "gpu/command_buffer/service/skia_utils.h"
10 #include "third_party/skia/include/core/SkSurface.h"
11 
12 namespace viz {
13 
14 namespace {
15 
16 // Some Vulkan drivers do not support kRGB_888x_SkColorType. Always use
17 // kRGBA_8888_SkColorType instead and initialize surface to opaque as necessary.
18 constexpr SkColorType kSurfaceColorType = kRGBA_8888_SkColorType;
19 
20 }  // namespace
21 
SkiaOutputDeviceOffscreen(scoped_refptr<gpu::SharedContextState> context_state,gfx::SurfaceOrigin origin,bool has_alpha,gpu::MemoryTracker * memory_tracker,DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)22 SkiaOutputDeviceOffscreen::SkiaOutputDeviceOffscreen(
23     scoped_refptr<gpu::SharedContextState> context_state,
24     gfx::SurfaceOrigin origin,
25     bool has_alpha,
26     gpu::MemoryTracker* memory_tracker,
27     DidSwapBufferCompleteCallback did_swap_buffer_complete_callback)
28     : SkiaOutputDevice(memory_tracker, did_swap_buffer_complete_callback),
29       context_state_(context_state),
30       has_alpha_(has_alpha) {
31   capabilities_.uses_default_gl_framebuffer = false;
32   capabilities_.output_surface_origin = origin;
33   capabilities_.supports_post_sub_buffer = true;
34 
35   capabilities_.sk_color_type = kSurfaceColorType;
36   capabilities_.gr_backend_format =
37       context_state_->gr_context()->defaultBackendFormat(kSurfaceColorType,
38                                                          GrRenderable::kYes);
39 }
40 
~SkiaOutputDeviceOffscreen()41 SkiaOutputDeviceOffscreen::~SkiaOutputDeviceOffscreen() {
42   DiscardBackbuffer();
43 }
44 
Reshape(const gfx::Size & size,float device_scale_factor,const gfx::ColorSpace & color_space,gfx::BufferFormat format,gfx::OverlayTransform transform)45 bool SkiaOutputDeviceOffscreen::Reshape(const gfx::Size& size,
46                                         float device_scale_factor,
47                                         const gfx::ColorSpace& color_space,
48                                         gfx::BufferFormat format,
49                                         gfx::OverlayTransform transform) {
50   DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE);
51 
52   DiscardBackbuffer();
53   size_ = size;
54   sk_color_space_ = color_space.ToSkColorSpace();
55   EnsureBackbuffer();
56   return true;
57 }
58 
SwapBuffers(BufferPresentedCallback feedback,std::vector<ui::LatencyInfo> latency_info)59 void SkiaOutputDeviceOffscreen::SwapBuffers(
60     BufferPresentedCallback feedback,
61     std::vector<ui::LatencyInfo> latency_info) {
62   // Reshape should have been called first.
63   DCHECK(backend_texture_.isValid());
64 
65   StartSwapBuffers(std::move(feedback));
66   FinishSwapBuffers(gfx::SwapResult::SWAP_ACK,
67                     gfx::Size(size_.width(), size_.height()),
68                     std::move(latency_info));
69 }
70 
PostSubBuffer(const gfx::Rect & rect,BufferPresentedCallback feedback,std::vector<ui::LatencyInfo> latency_info)71 void SkiaOutputDeviceOffscreen::PostSubBuffer(
72     const gfx::Rect& rect,
73     BufferPresentedCallback feedback,
74     std::vector<ui::LatencyInfo> latency_info) {
75   return SwapBuffers(std::move(feedback), std::move(latency_info));
76 }
77 
EnsureBackbuffer()78 void SkiaOutputDeviceOffscreen::EnsureBackbuffer() {
79   // Ignore EnsureBackbuffer if Reshape has not been called yet.
80   if (size_.IsEmpty())
81     return;
82 
83   if (has_alpha_) {
84     backend_texture_ = context_state_->gr_context()->createBackendTexture(
85         size_.width(), size_.height(), kSurfaceColorType, GrMipMapped::kNo,
86         GrRenderable::kYes);
87   } else {
88     is_emulated_rgbx_ = true;
89     // Initialize alpha channel to opaque.
90     backend_texture_ = context_state_->gr_context()->createBackendTexture(
91         size_.width(), size_.height(), kSurfaceColorType, SkColors::kBlack,
92         GrMipMapped::kNo, GrRenderable::kYes);
93   }
94   DCHECK(backend_texture_.isValid());
95 
96   DCHECK(!backbuffer_estimated_size_);
97   if (backend_texture_.backend() == GrBackendApi::kVulkan) {
98     GrVkImageInfo vk_image_info;
99     bool result = backend_texture_.getVkImageInfo(&vk_image_info);
100     DCHECK(result);
101     backbuffer_estimated_size_ = vk_image_info.fAlloc.fSize;
102   } else {
103     auto info = SkImageInfo::Make(size_.width(), size_.height(),
104                                   kSurfaceColorType, kUnpremul_SkAlphaType);
105     size_t estimated_size = info.computeMinByteSize();
106     backbuffer_estimated_size_ = estimated_size;
107   }
108   memory_type_tracker_->TrackMemAlloc(backbuffer_estimated_size_);
109 }
110 
DiscardBackbuffer()111 void SkiaOutputDeviceOffscreen::DiscardBackbuffer() {
112   if (backend_texture_.isValid()) {
113     sk_surface_.reset();
114     DeleteGrBackendTexture(context_state_.get(), &backend_texture_);
115     backend_texture_ = GrBackendTexture();
116     memory_type_tracker_->TrackMemFree(backbuffer_estimated_size_);
117     backbuffer_estimated_size_ = 0u;
118   }
119 }
120 
BeginPaint(std::vector<GrBackendSemaphore> * end_semaphores)121 SkSurface* SkiaOutputDeviceOffscreen::BeginPaint(
122     std::vector<GrBackendSemaphore>* end_semaphores) {
123   DCHECK(backend_texture_.isValid());
124   if (!sk_surface_) {
125     // LegacyFontHost will get LCD text and skia figures out what type to use.
126     SkSurfaceProps surface_props(0 /* flags */,
127                                  SkSurfaceProps::kLegacyFontHost_InitType);
128     sk_surface_ = SkSurface::MakeFromBackendTexture(
129         context_state_->gr_context(), backend_texture_,
130         capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft
131             ? kTopLeft_GrSurfaceOrigin
132             : kBottomLeft_GrSurfaceOrigin,
133         0 /* sampleCount */, kSurfaceColorType, sk_color_space_,
134         &surface_props);
135   }
136   return sk_surface_.get();
137 }
138 
EndPaint()139 void SkiaOutputDeviceOffscreen::EndPaint() {}
140 
141 }  // namespace viz
142