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