1 // Copyright 2017 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 "third_party/blink/renderer/platform/graphics/canvas_resource.h"
6
7 #include <utility>
8
9 #include "base/memory/read_only_shared_memory_region.h"
10 #include "build/build_config.h"
11 #include "components/viz/common/resources/bitmap_allocation.h"
12 #include "components/viz/common/resources/resource_format_utils.h"
13 #include "components/viz/common/resources/single_release_callback.h"
14 #include "components/viz/common/resources/transferable_resource.h"
15 #include "gpu/GLES2/gl2extchromium.h"
16 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
17 #include "gpu/command_buffer/client/raster_interface.h"
18 #include "gpu/command_buffer/client/shared_image_interface.h"
19 #include "gpu/command_buffer/client/webgpu_interface.h"
20 #include "gpu/command_buffer/common/capabilities.h"
21 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
22 #include "gpu/command_buffer/common/shared_image_usage.h"
23 #include "gpu/command_buffer/common/sync_token.h"
24 #include "third_party/blink/public/platform/platform.h"
25 #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
26 #include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
27 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
28 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
29 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
30 #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
31 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
32 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
33 #include "third_party/blink/renderer/platform/wtf/functional.h"
34 #include "third_party/skia/include/gpu/GrDirectContext.h"
35 #include "ui/gfx/buffer_format_util.h"
36 #include "ui/gfx/color_space.h"
37
38 #if BUILDFLAG(SKIA_USE_DAWN)
39 namespace {
40 // TODO(senorblanco): This should be using RequestDeviceAsync(), but
41 // those callbacks don't seem to work currently. Assume device 1
42 // and use it in all the WebGPUInterface calls. http://crbug.com/1078775
43 constexpr uint64_t kWebGPUDeviceClientID = 1;
44 } // namespace
45 #endif
46
47 namespace blink {
48
CanvasResource(base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,const CanvasColorParams & color_params)49 CanvasResource::CanvasResource(base::WeakPtr<CanvasResourceProvider> provider,
50 SkFilterQuality filter_quality,
51 const CanvasColorParams& color_params)
52 : owning_thread_ref_(base::PlatformThread::CurrentRef()),
53 owning_thread_task_runner_(Thread::Current()->GetTaskRunner()),
54 provider_(std::move(provider)),
55 filter_quality_(filter_quality),
56 color_params_(color_params) {}
57
~CanvasResource()58 CanvasResource::~CanvasResource() {
59 #if DCHECK_IS_ON()
60 DCHECK(did_call_on_destroy_);
61 #endif
62 }
63
OnDestroy()64 void CanvasResource::OnDestroy() {
65 if (is_cross_thread()) {
66 // Destroyed on wrong thread. This can happen when the thread of origin was
67 // torn down, in which case the GPU context owning any underlying resources
68 // no longer exists.
69 Abandon();
70 } else {
71 if (provider_)
72 provider_->OnDestroyResource();
73 TearDown();
74 }
75 #if DCHECK_IS_ON()
76 did_call_on_destroy_ = true;
77 #endif
78 }
79
InterfaceBase() const80 gpu::InterfaceBase* CanvasResource::InterfaceBase() const {
81 if (!ContextProviderWrapper())
82 return nullptr;
83 return ContextProviderWrapper()->ContextProvider()->InterfaceBase();
84 }
85
ContextGL() const86 gpu::gles2::GLES2Interface* CanvasResource::ContextGL() const {
87 if (!ContextProviderWrapper())
88 return nullptr;
89 return ContextProviderWrapper()->ContextProvider()->ContextGL();
90 }
91
RasterInterface() const92 gpu::raster::RasterInterface* CanvasResource::RasterInterface() const {
93 if (!ContextProviderWrapper())
94 return nullptr;
95 return ContextProviderWrapper()->ContextProvider()->RasterInterface();
96 }
97
WebGPUInterface() const98 gpu::webgpu::WebGPUInterface* CanvasResource::WebGPUInterface() const {
99 if (!ContextProviderWrapper())
100 return nullptr;
101 return ContextProviderWrapper()->ContextProvider()->WebGPUInterface();
102 }
103
WaitSyncToken(const gpu::SyncToken & sync_token)104 void CanvasResource::WaitSyncToken(const gpu::SyncToken& sync_token) {
105 if (sync_token.HasData()) {
106 if (auto* interface_base = InterfaceBase())
107 interface_base->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
108 }
109 }
110
ReleaseFrameResources(base::WeakPtr<CanvasResourceProvider> resource_provider,scoped_refptr<CanvasResource> resource,const gpu::SyncToken & sync_token,bool lost_resource)111 static void ReleaseFrameResources(
112 base::WeakPtr<CanvasResourceProvider> resource_provider,
113 scoped_refptr<CanvasResource> resource,
114 const gpu::SyncToken& sync_token,
115 bool lost_resource) {
116 resource->WaitSyncToken(sync_token);
117
118 if (resource_provider)
119 resource_provider->NotifyTexParamsModified(resource.get());
120
121 // TODO(khushalsagar): If multiple readers had access to this resource, losing
122 // it once should make sure subsequent releases don't try to recycle this
123 // resource.
124 if (lost_resource)
125 resource->NotifyResourceLost();
126 if (resource_provider && !lost_resource && resource->IsRecycleable())
127 resource_provider->RecycleResource(std::move(resource));
128 }
129
PrepareTransferableResource(viz::TransferableResource * out_resource,std::unique_ptr<viz::SingleReleaseCallback> * out_callback,MailboxSyncMode sync_mode)130 bool CanvasResource::PrepareTransferableResource(
131 viz::TransferableResource* out_resource,
132 std::unique_ptr<viz::SingleReleaseCallback>* out_callback,
133 MailboxSyncMode sync_mode) {
134 DCHECK(IsValid());
135
136 DCHECK(out_callback);
137 auto func = WTF::Bind(&ReleaseFrameResources, provider_,
138 WTF::Passed(base::WrapRefCounted(this)));
139 *out_callback = viz::SingleReleaseCallback::Create(std::move(func));
140
141 if (!out_resource)
142 return true;
143 if (SupportsAcceleratedCompositing())
144 return PrepareAcceleratedTransferableResource(out_resource, sync_mode);
145 return PrepareUnacceleratedTransferableResource(out_resource);
146 }
147
PrepareAcceleratedTransferableResource(viz::TransferableResource * out_resource,MailboxSyncMode sync_mode)148 bool CanvasResource::PrepareAcceleratedTransferableResource(
149 viz::TransferableResource* out_resource,
150 MailboxSyncMode sync_mode) {
151 TRACE_EVENT0("blink",
152 "CanvasResource::PrepareAcceleratedTransferableResource");
153 // Gpu compositing is a prerequisite for compositing an accelerated resource
154 DCHECK(SharedGpuContext::IsGpuCompositingEnabled());
155 if (!ContextProviderWrapper())
156 return false;
157 const gpu::Mailbox& mailbox = GetOrCreateGpuMailbox(sync_mode);
158 if (mailbox.IsZero())
159 return false;
160
161 *out_resource = viz::TransferableResource::MakeGL(
162 mailbox, GLFilter(), TextureTarget(), GetSyncToken(), gfx::Size(Size()),
163 IsOverlayCandidate());
164
165 out_resource->color_space = color_params_.GetSamplerGfxColorSpace();
166 out_resource->format = color_params_.TransferableResourceFormat();
167 out_resource->read_lock_fences_enabled = NeedsReadLockFences();
168
169 return true;
170 }
171
PrepareUnacceleratedTransferableResource(viz::TransferableResource * out_resource)172 bool CanvasResource::PrepareUnacceleratedTransferableResource(
173 viz::TransferableResource* out_resource) {
174 TRACE_EVENT0("blink",
175 "CanvasResource::PrepareUnacceleratedTransferableResource");
176 const gpu::Mailbox& mailbox = GetOrCreateGpuMailbox(kVerifiedSyncToken);
177 if (mailbox.IsZero())
178 return false;
179
180 // For software compositing, the display compositor assumes an N32 format for
181 // the resource type and completely ignores the format set on the
182 // TransferableResource. Clients are expected to render in N32 format but use
183 // RGBA as the tagged format on resources.
184 *out_resource = viz::TransferableResource::MakeSoftware(
185 mailbox, gfx::Size(Size()), viz::RGBA_8888);
186
187 out_resource->color_space = color_params_.GetSamplerGfxColorSpace();
188
189 return true;
190 }
191
GetGrContext() const192 GrDirectContext* CanvasResource::GetGrContext() const {
193 if (!ContextProviderWrapper())
194 return nullptr;
195 return ContextProviderWrapper()->ContextProvider()->GetGrContext();
196 }
197
CreateSkImageInfo() const198 SkImageInfo CanvasResource::CreateSkImageInfo() const {
199 return SkImageInfo::Make(
200 Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
201 ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
202 }
203
GLFilter() const204 GLenum CanvasResource::GLFilter() const {
205 return filter_quality_ == kNone_SkFilterQuality ? GL_NEAREST : GL_LINEAR;
206 }
207
208 // CanvasResourceSharedBitmap
209 //==============================================================================
210
CanvasResourceSharedBitmap(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)211 CanvasResourceSharedBitmap::CanvasResourceSharedBitmap(
212 const IntSize& size,
213 const CanvasColorParams& color_params,
214 base::WeakPtr<CanvasResourceProvider> provider,
215 SkFilterQuality filter_quality)
216 : CanvasResource(std::move(provider), filter_quality, color_params),
217 size_(size) {
218 // Software compositing lazily uses RGBA_8888 as the resource format
219 // everywhere but the content is expected to be rendered in N32 format.
220 base::MappedReadOnlyRegion shm = viz::bitmap_allocation::AllocateSharedBitmap(
221 gfx::Size(Size()), viz::RGBA_8888);
222
223 if (!shm.IsValid())
224 return;
225
226 shared_mapping_ = std::move(shm.mapping);
227 shared_bitmap_id_ = viz::SharedBitmap::GenerateId();
228
229 CanvasResourceDispatcher* resource_dispatcher =
230 Provider() ? Provider()->ResourceDispatcher() : nullptr;
231 if (resource_dispatcher) {
232 resource_dispatcher->DidAllocateSharedBitmap(std::move(shm.region),
233 shared_bitmap_id_);
234 }
235 }
236
~CanvasResourceSharedBitmap()237 CanvasResourceSharedBitmap::~CanvasResourceSharedBitmap() {
238 OnDestroy();
239 }
240
IsValid() const241 bool CanvasResourceSharedBitmap::IsValid() const {
242 return shared_mapping_.IsValid();
243 }
244
Size() const245 IntSize CanvasResourceSharedBitmap::Size() const {
246 return size_;
247 }
248
Bitmap()249 scoped_refptr<StaticBitmapImage> CanvasResourceSharedBitmap::Bitmap() {
250 if (!IsValid())
251 return nullptr;
252 // Construct an SkImage that references the shared memory buffer.
253 // The release callback holds a reference to |this| to ensure that the
254 // canvas resource that owns the shared memory stays alive at least until
255 // the SkImage is destroyed.
256 SkImageInfo image_info = SkImageInfo::Make(
257 Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
258 ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
259 SkPixmap pixmap(image_info, shared_mapping_.memory(),
260 image_info.minRowBytes());
261 this->AddRef();
262 sk_sp<SkImage> sk_image = SkImage::MakeFromRaster(
263 pixmap,
264 [](const void*, SkImage::ReleaseContext resource_to_unref) {
265 static_cast<CanvasResourceSharedBitmap*>(resource_to_unref)->Release();
266 },
267 this);
268 auto image = UnacceleratedStaticBitmapImage::Create(sk_image);
269 image->SetOriginClean(is_origin_clean_);
270 return image;
271 }
272
Create(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)273 scoped_refptr<CanvasResourceSharedBitmap> CanvasResourceSharedBitmap::Create(
274 const IntSize& size,
275 const CanvasColorParams& color_params,
276 base::WeakPtr<CanvasResourceProvider> provider,
277 SkFilterQuality filter_quality) {
278 auto resource = AdoptRef(new CanvasResourceSharedBitmap(
279 size, color_params, std::move(provider), filter_quality));
280 return resource->IsValid() ? resource : nullptr;
281 }
282
TearDown()283 void CanvasResourceSharedBitmap::TearDown() {
284 CanvasResourceDispatcher* resource_dispatcher =
285 Provider() ? Provider()->ResourceDispatcher() : nullptr;
286 if (resource_dispatcher && !shared_bitmap_id_.IsZero())
287 resource_dispatcher->DidDeleteSharedBitmap(shared_bitmap_id_);
288 shared_mapping_ = {};
289 }
290
Abandon()291 void CanvasResourceSharedBitmap::Abandon() {
292 shared_mapping_ = {};
293 }
294
NotifyResourceLost()295 void CanvasResourceSharedBitmap::NotifyResourceLost() {
296 // Release our reference to the shared memory mapping since the resource can
297 // no longer be safely recycled and this memory is needed for copy-on-write.
298 shared_mapping_ = {};
299 }
300
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)301 const gpu::Mailbox& CanvasResourceSharedBitmap::GetOrCreateGpuMailbox(
302 MailboxSyncMode sync_mode) {
303 return shared_bitmap_id_;
304 }
305
HasGpuMailbox() const306 bool CanvasResourceSharedBitmap::HasGpuMailbox() const {
307 return !shared_bitmap_id_.IsZero();
308 }
309
TakeSkImage(sk_sp<SkImage> image)310 void CanvasResourceSharedBitmap::TakeSkImage(sk_sp<SkImage> image) {
311 SkImageInfo image_info = SkImageInfo::Make(
312 Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
313 ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
314
315 bool read_pixels_successful = image->readPixels(
316 image_info, shared_mapping_.memory(), image_info.minRowBytes(), 0, 0);
317 DCHECK(read_pixels_successful);
318 }
319
320 // CanvasResourceSharedImage
321 //==============================================================================
322
CanvasResourceSharedImage(base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,const CanvasColorParams & color_params)323 CanvasResourceSharedImage::CanvasResourceSharedImage(
324 base::WeakPtr<CanvasResourceProvider> provider,
325 SkFilterQuality filter_quality,
326 const CanvasColorParams& color_params)
327 : CanvasResource(provider, filter_quality, color_params) {}
328
329 // CanvasResourceRasterSharedImage
330 //==============================================================================
331
CanvasResourceRasterSharedImage(const IntSize & size,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,const CanvasColorParams & color_params,bool is_origin_top_left,bool is_accelerated,uint32_t shared_image_usage_flags)332 CanvasResourceRasterSharedImage::CanvasResourceRasterSharedImage(
333 const IntSize& size,
334 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
335 base::WeakPtr<CanvasResourceProvider> provider,
336 SkFilterQuality filter_quality,
337 const CanvasColorParams& color_params,
338 bool is_origin_top_left,
339 bool is_accelerated,
340 uint32_t shared_image_usage_flags)
341 : CanvasResourceSharedImage(std::move(provider),
342 filter_quality,
343 color_params),
344 context_provider_wrapper_(std::move(context_provider_wrapper)),
345 size_(size),
346 is_origin_top_left_(is_origin_top_left),
347 is_accelerated_(is_accelerated),
348 is_overlay_candidate_(shared_image_usage_flags &
349 gpu::SHARED_IMAGE_USAGE_SCANOUT),
350 texture_target_(
351 is_overlay_candidate_
352 ? gpu::GetBufferTextureTarget(
353 gfx::BufferUsage::SCANOUT,
354 BufferFormat(ColorParams().TransferableResourceFormat()),
355 context_provider_wrapper_->ContextProvider()
356 ->GetCapabilities())
357 : GL_TEXTURE_2D),
358 use_oop_rasterization_(context_provider_wrapper_->ContextProvider()
359 ->GetCapabilities()
360 .supports_oop_raster) {
361 auto* gpu_memory_buffer_manager =
362 Platform::Current()->GetGpuMemoryBufferManager();
363 if (!is_accelerated_) {
364 DCHECK(gpu_memory_buffer_manager);
365 DCHECK(shared_image_usage_flags & gpu::SHARED_IMAGE_USAGE_DISPLAY);
366
367 gpu_memory_buffer_ = gpu_memory_buffer_manager->CreateGpuMemoryBuffer(
368 gfx::Size(size), ColorParams().GetBufferFormat(),
369 gfx::BufferUsage::SCANOUT_CPU_READ_WRITE, gpu::kNullSurfaceHandle);
370 if (!gpu_memory_buffer_)
371 return;
372
373 gpu_memory_buffer_->SetColorSpace(color_params.GetStorageGfxColorSpace());
374 }
375
376 auto* shared_image_interface =
377 context_provider_wrapper_->ContextProvider()->SharedImageInterface();
378 DCHECK(shared_image_interface);
379
380 // The GLES2 flag is needed for rendering via GL using a GrContext.
381 if (use_oop_rasterization_) {
382 shared_image_usage_flags = shared_image_usage_flags |
383 gpu::SHARED_IMAGE_USAGE_RASTER |
384 gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
385 } else {
386 shared_image_usage_flags = shared_image_usage_flags |
387 gpu::SHARED_IMAGE_USAGE_GLES2 |
388 gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
389 }
390
391 GrSurfaceOrigin surface_origin = is_origin_top_left_
392 ? kTopLeft_GrSurfaceOrigin
393 : kBottomLeft_GrSurfaceOrigin;
394 SkAlphaType surface_alpha_type = ColorParams().GetSkAlphaType();
395 gpu::Mailbox shared_image_mailbox;
396 if (gpu_memory_buffer_) {
397 shared_image_mailbox = shared_image_interface->CreateSharedImage(
398 gpu_memory_buffer_.get(), gpu_memory_buffer_manager,
399 ColorParams().GetStorageGfxColorSpace(), surface_origin,
400 surface_alpha_type, shared_image_usage_flags);
401 } else {
402 shared_image_mailbox = shared_image_interface->CreateSharedImage(
403 ColorParams().TransferableResourceFormat(), gfx::Size(size),
404 ColorParams().GetStorageGfxColorSpace(), surface_origin,
405 surface_alpha_type, shared_image_usage_flags, gpu::kNullSurfaceHandle);
406 }
407
408 // Wait for the mailbox to be ready to be used.
409 WaitSyncToken(shared_image_interface->GenUnverifiedSyncToken());
410
411 auto* raster_interface = RasterInterface();
412 DCHECK(raster_interface);
413 owning_thread_data().shared_image_mailbox = shared_image_mailbox;
414
415 if (use_oop_rasterization_)
416 return;
417
418 owning_thread_data().texture_id_for_read_access =
419 raster_interface->CreateAndConsumeForGpuRaster(shared_image_mailbox);
420
421 // For the non-accelerated case, writes are done on the CPU. So we don't need
422 // a texture for writes.
423 if (!is_accelerated_)
424 return;
425 if (shared_image_usage_flags &
426 gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE) {
427 owning_thread_data().texture_id_for_write_access =
428 raster_interface->CreateAndConsumeForGpuRaster(shared_image_mailbox);
429 } else {
430 owning_thread_data().texture_id_for_write_access =
431 owning_thread_data().texture_id_for_read_access;
432 }
433 }
434
435 scoped_refptr<CanvasResourceRasterSharedImage>
Create(const IntSize & size,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,const CanvasColorParams & color_params,bool is_origin_top_left,bool is_accelerated,uint32_t shared_image_usage_flags)436 CanvasResourceRasterSharedImage::Create(
437 const IntSize& size,
438 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
439 base::WeakPtr<CanvasResourceProvider> provider,
440 SkFilterQuality filter_quality,
441 const CanvasColorParams& color_params,
442 bool is_origin_top_left,
443 bool is_accelerated,
444 uint32_t shared_image_usage_flags) {
445 TRACE_EVENT0("blink", "CanvasResourceRasterSharedImage::Create");
446 auto resource = base::AdoptRef(new CanvasResourceRasterSharedImage(
447 size, std::move(context_provider_wrapper), std::move(provider),
448 filter_quality, color_params, is_origin_top_left, is_accelerated,
449 shared_image_usage_flags));
450 return resource->IsValid() ? resource : nullptr;
451 }
452
IsValid() const453 bool CanvasResourceRasterSharedImage::IsValid() const {
454 return !mailbox().IsZero();
455 }
456
BeginReadAccess()457 void CanvasResourceRasterSharedImage::BeginReadAccess() {
458 RasterInterface()->BeginSharedImageAccessDirectCHROMIUM(
459 GetTextureIdForReadAccess(), GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
460 }
461
EndReadAccess()462 void CanvasResourceRasterSharedImage::EndReadAccess() {
463 RasterInterface()->EndSharedImageAccessDirectCHROMIUM(
464 GetTextureIdForReadAccess());
465 }
466
BeginWriteAccess()467 void CanvasResourceRasterSharedImage::BeginWriteAccess() {
468 RasterInterface()->BeginSharedImageAccessDirectCHROMIUM(
469 GetTextureIdForWriteAccess(),
470 GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
471 }
472
EndWriteAccess()473 void CanvasResourceRasterSharedImage::EndWriteAccess() {
474 RasterInterface()->EndSharedImageAccessDirectCHROMIUM(
475 GetTextureIdForWriteAccess());
476 }
477
CreateGrTexture() const478 GrBackendTexture CanvasResourceRasterSharedImage::CreateGrTexture() const {
479 GrGLTextureInfo texture_info = {};
480 texture_info.fID = GetTextureIdForWriteAccess();
481 texture_info.fTarget = TextureTarget();
482 texture_info.fFormat = ColorParams().GLSizedInternalFormat();
483 return GrBackendTexture(Size().Width(), Size().Height(), GrMipMapped::kNo,
484 texture_info);
485 }
486
~CanvasResourceRasterSharedImage()487 CanvasResourceRasterSharedImage::~CanvasResourceRasterSharedImage() {
488 OnDestroy();
489 }
490
TearDown()491 void CanvasResourceRasterSharedImage::TearDown() {
492 DCHECK(!is_cross_thread());
493
494 // The context deletes all shared images on destruction which means no
495 // cleanup is needed if the context was lost.
496 if (ContextProviderWrapper()) {
497 auto* raster_interface = RasterInterface();
498 auto* shared_image_interface =
499 ContextProviderWrapper()->ContextProvider()->SharedImageInterface();
500 if (raster_interface && shared_image_interface) {
501 gpu::SyncToken shared_image_sync_token;
502 raster_interface->GenUnverifiedSyncTokenCHROMIUM(
503 shared_image_sync_token.GetData());
504 shared_image_interface->DestroySharedImage(shared_image_sync_token,
505 mailbox());
506 }
507 if (raster_interface) {
508 if (owning_thread_data().texture_id_for_read_access) {
509 raster_interface->DeleteGpuRasterTexture(
510 owning_thread_data().texture_id_for_read_access);
511 }
512 if (owning_thread_data().texture_id_for_write_access &&
513 owning_thread_data().texture_id_for_write_access !=
514 owning_thread_data().texture_id_for_read_access) {
515 raster_interface->DeleteGpuRasterTexture(
516 owning_thread_data().texture_id_for_write_access);
517 }
518 }
519 }
520
521 owning_thread_data().texture_id_for_read_access = 0u;
522 owning_thread_data().texture_id_for_write_access = 0u;
523 }
524
Abandon()525 void CanvasResourceRasterSharedImage::Abandon() {
526 // Called when the owning thread has been torn down which will destroy the
527 // context on which the shared image was created so no cleanup is necessary.
528 }
529
WillDraw()530 void CanvasResourceRasterSharedImage::WillDraw() {
531 DCHECK(!is_cross_thread())
532 << "Write access is only allowed on the owning thread";
533
534 // Sync token for software mode is generated from SharedImageInterface each
535 // time the GMB is updated.
536 if (!is_accelerated_)
537 return;
538
539 owning_thread_data().mailbox_needs_new_sync_token = true;
540 }
541
542 // static
OnBitmapImageDestroyed(scoped_refptr<CanvasResourceRasterSharedImage> resource,bool has_read_ref_on_texture,const gpu::SyncToken & sync_token,bool is_lost)543 void CanvasResourceRasterSharedImage::OnBitmapImageDestroyed(
544 scoped_refptr<CanvasResourceRasterSharedImage> resource,
545 bool has_read_ref_on_texture,
546 const gpu::SyncToken& sync_token,
547 bool is_lost) {
548 DCHECK(!resource->is_cross_thread());
549
550 if (has_read_ref_on_texture) {
551 DCHECK(!resource->use_oop_rasterization_);
552 DCHECK_GT(resource->owning_thread_data().bitmap_image_read_refs, 0u);
553
554 resource->owning_thread_data().bitmap_image_read_refs--;
555 if (resource->owning_thread_data().bitmap_image_read_refs == 0u &&
556 resource->RasterInterface()) {
557 resource->RasterInterface()->EndSharedImageAccessDirectCHROMIUM(
558 resource->owning_thread_data().texture_id_for_read_access);
559 }
560 }
561
562 auto weak_provider = resource->WeakProvider();
563 ReleaseFrameResources(std::move(weak_provider), std::move(resource),
564 sync_token, is_lost);
565 }
566
Transfer()567 void CanvasResourceRasterSharedImage::Transfer() {
568 if (is_cross_thread() || !ContextProviderWrapper())
569 return;
570
571 // TODO(khushalsagar): This is for consistency with MailboxTextureHolder
572 // transfer path. Its unclear why the verification can not be deferred until
573 // the resource needs to be transferred cross-process.
574 owning_thread_data().mailbox_sync_mode = kVerifiedSyncToken;
575 GetSyncToken();
576 }
577
Bitmap()578 scoped_refptr<StaticBitmapImage> CanvasResourceRasterSharedImage::Bitmap() {
579 TRACE_EVENT0("blink", "CanvasResourceRasterSharedImage::Bitmap");
580
581 SkImageInfo image_info = CreateSkImageInfo();
582 if (!is_accelerated_) {
583 if (!gpu_memory_buffer_->Map())
584 return nullptr;
585
586 SkPixmap pixmap(CreateSkImageInfo(), gpu_memory_buffer_->memory(0),
587 gpu_memory_buffer_->stride(0));
588 auto sk_image = SkImage::MakeRasterCopy(pixmap);
589 gpu_memory_buffer_->Unmap();
590 return sk_image ? UnacceleratedStaticBitmapImage::Create(sk_image)
591 : nullptr;
592 }
593
594 // In order to avoid creating multiple representations for this shared image
595 // on the same context, the AcceleratedStaticBitmapImage uses the texture id
596 // of the resource here. We keep a count of pending shared image releases to
597 // correctly scope the read lock for this texture.
598 // If this resource is accessed across threads, or the
599 // AcceleratedStaticBitmapImage is accessed on a different thread after being
600 // created here, the image will create a new representation from the mailbox
601 // rather than referring to the shared image's texture ID if it was provided
602 // below.
603 const bool has_read_ref_on_texture =
604 !is_cross_thread() && !use_oop_rasterization_;
605 GLuint texture_id_for_image = 0u;
606 if (has_read_ref_on_texture) {
607 texture_id_for_image = owning_thread_data().texture_id_for_read_access;
608 owning_thread_data().bitmap_image_read_refs++;
609 if (owning_thread_data().bitmap_image_read_refs == 1u &&
610 RasterInterface()) {
611 RasterInterface()->BeginSharedImageAccessDirectCHROMIUM(
612 texture_id_for_image, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
613 }
614 }
615
616 // The |release_callback| keeps a ref on this resource to ensure the backing
617 // shared image is kept alive until the lifetime of the image.
618 // Note that the code in CanvasResourceProvider::RecycleResource also uses the
619 // ref-count on the resource as a proxy for a read lock to allow recycling the
620 // resource once all refs have been released.
621 auto release_callback = viz::SingleReleaseCallback::Create(
622 base::BindOnce(&OnBitmapImageDestroyed,
623 scoped_refptr<CanvasResourceRasterSharedImage>(this),
624 has_read_ref_on_texture));
625
626 scoped_refptr<StaticBitmapImage> image;
627
628 // If its cross thread, then the sync token was already verified.
629 if (!is_cross_thread()) {
630 owning_thread_data().mailbox_sync_mode = kUnverifiedSyncToken;
631 }
632 image = AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
633 mailbox(), GetSyncToken(), texture_id_for_image, image_info, texture_target_,
634 is_origin_top_left_, context_provider_wrapper_, owning_thread_ref_,
635 owning_thread_task_runner_, std::move(release_callback));
636
637 DCHECK(image);
638 return image;
639 }
640
CopyRenderingResultsToGpuMemoryBuffer(const sk_sp<SkImage> & image)641 void CanvasResourceRasterSharedImage::CopyRenderingResultsToGpuMemoryBuffer(
642 const sk_sp<SkImage>& image) {
643 DCHECK(!is_cross_thread());
644
645 if (!ContextProviderWrapper() || !gpu_memory_buffer_->Map())
646 return;
647
648 auto surface = SkSurface::MakeRasterDirect(CreateSkImageInfo(),
649 gpu_memory_buffer_->memory(0),
650 gpu_memory_buffer_->stride(0));
651 surface->getCanvas()->drawImage(image, 0, 0);
652 auto* sii =
653 ContextProviderWrapper()->ContextProvider()->SharedImageInterface();
654 gpu_memory_buffer_->Unmap();
655 sii->UpdateSharedImage(gpu::SyncToken(), mailbox());
656 owning_thread_data().sync_token = sii->GenUnverifiedSyncToken();
657 }
658
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)659 const gpu::Mailbox& CanvasResourceRasterSharedImage::GetOrCreateGpuMailbox(
660 MailboxSyncMode sync_mode) {
661 if (!is_cross_thread()) {
662 owning_thread_data().mailbox_sync_mode = sync_mode;
663 }
664 return mailbox();
665 }
666
HasGpuMailbox() const667 bool CanvasResourceRasterSharedImage::HasGpuMailbox() const {
668 return !mailbox().IsZero();
669 }
670
GetSyncToken()671 const gpu::SyncToken CanvasResourceRasterSharedImage::GetSyncToken() {
672 if (is_cross_thread()) {
673 // Sync token should be generated at Transfer time, which must always be
674 // called before cross-thread usage. And since we don't allow writes on
675 // another thread, the sync token generated at Transfer time shouldn't
676 // have been invalidated.
677 DCHECK(!mailbox_needs_new_sync_token());
678 DCHECK(sync_token().verified_flush());
679
680 return sync_token();
681 }
682
683 if (mailbox_needs_new_sync_token()) {
684 auto* raster_interface = RasterInterface();
685 DCHECK(raster_interface); // caller should already have early exited if
686 // !raster_interface.
687 raster_interface->GenUnverifiedSyncTokenCHROMIUM(
688 owning_thread_data().sync_token.GetData());
689 owning_thread_data().mailbox_needs_new_sync_token = false;
690 }
691
692 if (owning_thread_data().mailbox_sync_mode == kVerifiedSyncToken &&
693 !owning_thread_data().sync_token.verified_flush()) {
694 int8_t* token_data = owning_thread_data().sync_token.GetData();
695 auto* raster_interface = RasterInterface();
696 raster_interface->ShallowFlushCHROMIUM();
697 raster_interface->VerifySyncTokensCHROMIUM(&token_data, 1);
698 owning_thread_data().sync_token.SetVerifyFlush();
699 }
700
701 return sync_token();
702 }
703
NotifyResourceLost()704 void CanvasResourceRasterSharedImage::NotifyResourceLost() {
705 owning_thread_data().is_lost = true;
706
707 if (WeakProvider())
708 Provider()->NotifyTexParamsModified(this);
709 }
710
711 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const712 CanvasResourceRasterSharedImage::ContextProviderWrapper() const {
713 DCHECK(!is_cross_thread());
714 return context_provider_wrapper_;
715 }
716
717 // CanvasResourceSkiaDawnSharedImage
718 //==============================================================================
719
720 #if BUILDFLAG(SKIA_USE_DAWN)
CanvasResourceSkiaDawnSharedImage(const IntSize & size,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,const CanvasColorParams & color_params,bool is_origin_top_left,uint32_t shared_image_usage_flags)721 CanvasResourceSkiaDawnSharedImage::CanvasResourceSkiaDawnSharedImage(
722 const IntSize& size,
723 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
724 base::WeakPtr<CanvasResourceProvider> provider,
725 SkFilterQuality filter_quality,
726 const CanvasColorParams& color_params,
727 bool is_origin_top_left,
728 uint32_t shared_image_usage_flags)
729 : CanvasResourceSharedImage(std::move(provider),
730 filter_quality,
731 color_params),
732 context_provider_wrapper_(std::move(context_provider_wrapper)),
733 size_(size),
734 owning_thread_task_runner_(Thread::Current()->GetTaskRunner()),
735 is_origin_top_left_(is_origin_top_left) {
736 if (!context_provider_wrapper_)
737 return;
738
739 auto* shared_image_interface =
740 context_provider_wrapper_->ContextProvider()->SharedImageInterface();
741 DCHECK(shared_image_interface);
742
743 shared_image_usage_flags =
744 shared_image_usage_flags | gpu::SHARED_IMAGE_USAGE_WEBGPU;
745 GrSurfaceOrigin surface_origin = is_origin_top_left_
746 ? kTopLeft_GrSurfaceOrigin
747 : kBottomLeft_GrSurfaceOrigin;
748
749 gpu::Mailbox shared_image_mailbox;
750
751 shared_image_mailbox = shared_image_interface->CreateSharedImage(
752 ColorParams().TransferableResourceFormat(), gfx::Size(size),
753 ColorParams().GetStorageGfxColorSpace(), surface_origin,
754 ColorParams().GetSkAlphaType(), shared_image_usage_flags,
755 gpu::kNullSurfaceHandle);
756
757 auto* webgpu = WebGPUInterface();
758
759 // Wait for the mailbox to be ready to be used.
760 WaitSyncToken(shared_image_interface->GenUnverifiedSyncToken());
761
762 // Ensure Dawn wire is initialized.
763 webgpu->RequestAdapterAsync(gpu::webgpu::PowerPreference::kHighPerformance,
764 base::DoNothing());
765 WGPUDeviceProperties properties{};
766 webgpu->RequestDeviceAsync(0, properties, base::DoNothing());
767
768 owning_thread_data().shared_image_mailbox = shared_image_mailbox;
769 }
770
771 scoped_refptr<CanvasResourceSkiaDawnSharedImage>
Create(const IntSize & size,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,const CanvasColorParams & color_params,bool is_origin_top_left,uint32_t shared_image_usage_flags)772 CanvasResourceSkiaDawnSharedImage::Create(
773 const IntSize& size,
774 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
775 base::WeakPtr<CanvasResourceProvider> provider,
776 SkFilterQuality filter_quality,
777 const CanvasColorParams& color_params,
778 bool is_origin_top_left,
779 uint32_t shared_image_usage_flags) {
780 TRACE_EVENT0("blink", "CanvasResourceSkiaDawnSharedImage::Create");
781 auto resource = base::AdoptRef(new CanvasResourceSkiaDawnSharedImage(
782 size, std::move(context_provider_wrapper), std::move(provider),
783 filter_quality, color_params, is_origin_top_left,
784 shared_image_usage_flags));
785 return resource->IsValid() ? resource : nullptr;
786 }
787
IsValid() const788 bool CanvasResourceSkiaDawnSharedImage::IsValid() const {
789 return !mailbox().IsZero();
790 }
791
TextureTarget() const792 GLenum CanvasResourceSkiaDawnSharedImage::TextureTarget() const {
793 #if defined(OS_MAC)
794 return GL_TEXTURE_RECTANGLE_ARB;
795 #else
796 return GL_TEXTURE_2D;
797 #endif
798 }
799
~CanvasResourceSkiaDawnSharedImage()800 CanvasResourceSkiaDawnSharedImage::~CanvasResourceSkiaDawnSharedImage() {
801 OnDestroy();
802 }
803
TearDown()804 void CanvasResourceSkiaDawnSharedImage::TearDown() {
805 DCHECK(!is_cross_thread());
806
807 if (ContextProviderWrapper()) {
808 auto* webgpu = WebGPUInterface();
809 auto* shared_image_interface =
810 ContextProviderWrapper()->ContextProvider()->SharedImageInterface();
811 if (webgpu && shared_image_interface) {
812 gpu::SyncToken shared_image_sync_token;
813 webgpu->GenUnverifiedSyncTokenCHROMIUM(shared_image_sync_token.GetData());
814 shared_image_interface->DestroySharedImage(shared_image_sync_token,
815 mailbox());
816 }
817 }
818 }
819
Abandon()820 void CanvasResourceSkiaDawnSharedImage::Abandon() {
821 if (auto context_provider = SharedGpuContext::ContextProviderWrapper()) {
822 auto* sii = context_provider->ContextProvider()->SharedImageInterface();
823 if (sii)
824 sii->DestroySharedImage(gpu::SyncToken(), mailbox());
825 }
826 }
827
WillDraw()828 void CanvasResourceSkiaDawnSharedImage::WillDraw() {
829 DCHECK(!is_cross_thread())
830 << "Write access is only allowed on the owning thread";
831
832 owning_thread_data().mailbox_needs_new_sync_token = true;
833 }
834
BeginAccess()835 void CanvasResourceSkiaDawnSharedImage::BeginAccess() {
836 auto* webgpu = WebGPUInterface();
837 gpu::webgpu::ReservedTexture reservation =
838 webgpu->ReserveTexture(kWebGPUDeviceClientID);
839 DCHECK(reservation.texture);
840
841 owning_thread_data().texture = wgpu::Texture(reservation.texture);
842 owning_thread_data().id = reservation.id;
843 owning_thread_data().generation = reservation.generation;
844 webgpu->FlushCommands();
845 webgpu->AssociateMailbox(
846 kWebGPUDeviceClientID, 0, owning_thread_data().id,
847 owning_thread_data().generation,
848 WGPUTextureUsage_Sampled | WGPUTextureUsage_OutputAttachment,
849 reinterpret_cast<GLbyte*>(&owning_thread_data().shared_image_mailbox));
850 }
851
EndAccess()852 void CanvasResourceSkiaDawnSharedImage::EndAccess() {
853 auto* webgpu = WebGPUInterface();
854 webgpu->FlushCommands();
855 webgpu->DissociateMailbox(kWebGPUDeviceClientID, owning_thread_data().id,
856 owning_thread_data().generation);
857
858 owning_thread_data().texture = nullptr;
859 owning_thread_data().id = 0;
860 owning_thread_data().generation = 0;
861 }
862
CreateGrTexture() const863 GrBackendTexture CanvasResourceSkiaDawnSharedImage::CreateGrTexture() const {
864 GrDawnTextureInfo info = {};
865 info.fTexture = texture();
866 #if defined(OS_MAC)
867 info.fFormat = wgpu::TextureFormat::BGRA8Unorm;
868 #else
869 info.fFormat = wgpu::TextureFormat::RGBA8Unorm;
870 #endif
871 info.fLevelCount = 1;
872 return GrBackendTexture(Size().Width(), Size().Height(), info);
873 }
874
CopyRenderingResultsToGpuMemoryBuffer(const sk_sp<SkImage> &)875 void CanvasResourceSkiaDawnSharedImage::CopyRenderingResultsToGpuMemoryBuffer(
876 const sk_sp<SkImage>&) {
877 DCHECK(false);
878 }
879
880 // static
OnBitmapImageDestroyed(scoped_refptr<CanvasResourceSkiaDawnSharedImage> resource,bool has_read_ref_on_texture,const gpu::SyncToken & sync_token,bool is_lost)881 void CanvasResourceSkiaDawnSharedImage::OnBitmapImageDestroyed(
882 scoped_refptr<CanvasResourceSkiaDawnSharedImage> resource,
883 bool has_read_ref_on_texture,
884 const gpu::SyncToken& sync_token,
885 bool is_lost) {
886 if (resource->is_cross_thread()) {
887 auto& task_runner = *resource->owning_thread_task_runner_;
888 PostCrossThreadTask(
889 task_runner, FROM_HERE,
890 CrossThreadBindOnce(
891 &CanvasResourceSkiaDawnSharedImage::OnBitmapImageDestroyed,
892 std::move(resource), has_read_ref_on_texture, sync_token, is_lost));
893 return;
894 }
895
896 if (has_read_ref_on_texture) {
897 DCHECK_GT(resource->owning_thread_data().bitmap_image_read_refs, 0u);
898
899 resource->owning_thread_data().bitmap_image_read_refs--;
900 }
901
902 // The StaticBitmapImage is used for readbacks which may modify the texture
903 // params. Note that this is racy, since the modification and resetting of the
904 // param is not atomic so the display may draw with incorrect params, but its
905 // a good enough fix for now.
906 resource->owning_thread_data().needs_gl_filter_reset = true;
907 auto weak_provider = resource->WeakProvider();
908 ReleaseFrameResources(std::move(weak_provider), std::move(resource),
909 sync_token, is_lost);
910 }
911
Transfer()912 void CanvasResourceSkiaDawnSharedImage::Transfer() {
913 if (is_cross_thread() || !ContextProviderWrapper())
914 return;
915
916 // TODO(khushalsagar): This is for consistency with MailboxTextureHolder
917 // transfer path. Its unclear why the verification can not be deferred until
918 // the resource needs to be transferred cross-process.
919 owning_thread_data().mailbox_sync_mode = kVerifiedSyncToken;
920 GetSyncToken();
921 }
922
Bitmap()923 scoped_refptr<StaticBitmapImage> CanvasResourceSkiaDawnSharedImage::Bitmap() {
924 TRACE_EVENT0("blink", "CanvasResourceSkiaDawnSharedImage::Bitmap");
925
926 SkImageInfo image_info = CreateSkImageInfo();
927
928 // In order to avoid creating multiple representations for this shared image
929 // on the same context, the AcceleratedStaticBitmapImage uses the texture id
930 // of the resource here. We keep a count of pending shared image releases to
931 // correctly scope the read lock for this texture.
932 // If this resource is accessed across threads, or the
933 // AcceleratedStaticBitmapImage is accessed on a different thread after being
934 // created here, the image will create a new representation from the mailbox
935 // rather than referring to the shared image's texture ID if it was provided
936 // below.
937 const bool has_read_ref_on_texture = !is_cross_thread();
938 if (has_read_ref_on_texture) {
939 owning_thread_data().bitmap_image_read_refs++;
940 if (owning_thread_data().bitmap_image_read_refs == 1u) {
941 BeginAccess();
942 }
943 }
944
945 // The |release_callback| keeps a ref on this resource to ensure the backing
946 // shared image is kept alive until the lifetime of the image.
947 // Note that the code in CanvasResourceProvider::RecycleResource also uses the
948 // ref-count on the resource as a proxy for a read lock to allow recycling the
949 // resource once all refs have been released.
950 auto release_callback = viz::SingleReleaseCallback::Create(
951 base::BindOnce(&OnBitmapImageDestroyed,
952 scoped_refptr<CanvasResourceSkiaDawnSharedImage>(this),
953 has_read_ref_on_texture));
954
955 scoped_refptr<StaticBitmapImage> image;
956
957 // If its cross thread, then the sync token was already verified.
958 if (!is_cross_thread()) {
959 owning_thread_data().mailbox_sync_mode = kUnverifiedSyncToken;
960 }
961 image = AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
962 mailbox(), GetSyncToken(), 0, image_info, GL_TEXTURE_2D,
963 is_origin_top_left_, context_provider_wrapper_, owning_thread_ref_,
964 owning_thread_task_runner_, std::move(release_callback));
965
966 DCHECK(image);
967 return image;
968 }
969
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)970 const gpu::Mailbox& CanvasResourceSkiaDawnSharedImage::GetOrCreateGpuMailbox(
971 MailboxSyncMode sync_mode) {
972 if (!is_cross_thread()) {
973 owning_thread_data().mailbox_sync_mode = sync_mode;
974 }
975 return mailbox();
976 }
977
HasGpuMailbox() const978 bool CanvasResourceSkiaDawnSharedImage::HasGpuMailbox() const {
979 return !mailbox().IsZero();
980 }
981
GetSyncToken()982 const gpu::SyncToken CanvasResourceSkiaDawnSharedImage::GetSyncToken() {
983 if (is_cross_thread()) {
984 // Sync token should be generated at Transfer time, which must always be
985 // called before cross-thread usage. And since we don't allow writes on
986 // another thread, the sync token generated at Transfer time shouldn't
987 // have been invalidated.
988 DCHECK(!mailbox_needs_new_sync_token());
989 DCHECK(sync_token().verified_flush());
990
991 return sync_token();
992 }
993
994 if (mailbox_needs_new_sync_token()) {
995 auto* webgpu = WebGPUInterface();
996 DCHECK(webgpu); // caller should already have early exited if !gl.
997 webgpu->GenUnverifiedSyncTokenCHROMIUM(
998 owning_thread_data().sync_token.GetData());
999 owning_thread_data().mailbox_needs_new_sync_token = false;
1000 }
1001
1002 if (owning_thread_data().mailbox_sync_mode == kVerifiedSyncToken &&
1003 !owning_thread_data().sync_token.verified_flush()) {
1004 int8_t* token_data = owning_thread_data().sync_token.GetData();
1005 auto* webgpu = WebGPUInterface();
1006 webgpu->VerifySyncTokensCHROMIUM(&token_data, 1);
1007 owning_thread_data().sync_token.SetVerifyFlush();
1008 }
1009
1010 return sync_token();
1011 }
1012
NotifyResourceLost()1013 void CanvasResourceSkiaDawnSharedImage::NotifyResourceLost() {
1014 owning_thread_data().is_lost = true;
1015
1016 // Since the texture params are in an unknown state, reset the cached tex
1017 // params state for the resource.
1018 owning_thread_data().needs_gl_filter_reset = true;
1019 if (WeakProvider())
1020 Provider()->NotifyTexParamsModified(this);
1021 }
1022
1023 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const1024 CanvasResourceSkiaDawnSharedImage::ContextProviderWrapper() const {
1025 DCHECK(!is_cross_thread());
1026 return context_provider_wrapper_;
1027 }
1028 #endif
1029
1030 // ExternalCanvasResource
1031 //==============================================================================
Create(const gpu::Mailbox & mailbox,const IntSize & size,GLenum texture_target,const CanvasColorParams & color_params,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,bool is_origin_top_left)1032 scoped_refptr<ExternalCanvasResource> ExternalCanvasResource::Create(
1033 const gpu::Mailbox& mailbox,
1034 const IntSize& size,
1035 GLenum texture_target,
1036 const CanvasColorParams& color_params,
1037 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
1038 base::WeakPtr<CanvasResourceProvider> provider,
1039 SkFilterQuality filter_quality,
1040 bool is_origin_top_left) {
1041 TRACE_EVENT0("blink", "ExternalCanvasResource::Create");
1042 auto resource = AdoptRef(new ExternalCanvasResource(
1043 mailbox, size, texture_target, color_params,
1044 std::move(context_provider_wrapper), std::move(provider), filter_quality,
1045 is_origin_top_left));
1046 return resource->IsValid() ? resource : nullptr;
1047 }
1048
~ExternalCanvasResource()1049 ExternalCanvasResource::~ExternalCanvasResource() {
1050 OnDestroy();
1051 }
1052
IsValid() const1053 bool ExternalCanvasResource::IsValid() const {
1054 return context_provider_wrapper_ && !mailbox_.IsZero();
1055 }
1056
Abandon()1057 void ExternalCanvasResource::Abandon() {
1058 // We don't need to destroy the shared image mailbox since we don't own it.
1059 }
1060
TakeSkImage(sk_sp<SkImage> image)1061 void ExternalCanvasResource::TakeSkImage(sk_sp<SkImage> image) {
1062 NOTREACHED();
1063 }
1064
Bitmap()1065 scoped_refptr<StaticBitmapImage> ExternalCanvasResource::Bitmap() {
1066 TRACE_EVENT0("blink", "ExternalCanvasResource::Bitmap");
1067 if (!IsValid())
1068 return nullptr;
1069
1070 // The |release_callback| keeps a ref on this resource to ensure the backing
1071 // shared image is kept alive until the lifetime of the image.
1072 auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
1073 [](scoped_refptr<ExternalCanvasResource> resource,
1074 const gpu::SyncToken& sync_token, bool is_lost) {
1075 // Do nothing but hold onto the refptr.
1076 },
1077 base::RetainedRef(this)));
1078
1079 return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
1080 mailbox_, GetSyncToken(), /*shared_image_texture_id=*/0u,
1081 CreateSkImageInfo(), texture_target_, is_origin_top_left_,
1082 context_provider_wrapper_, owning_thread_ref_, owning_thread_task_runner_,
1083 std::move(release_callback));
1084 }
1085
TearDown()1086 void ExternalCanvasResource::TearDown() {
1087 Abandon();
1088 }
1089
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)1090 const gpu::Mailbox& ExternalCanvasResource::GetOrCreateGpuMailbox(
1091 MailboxSyncMode sync_mode) {
1092 TRACE_EVENT0("blink", "ExternalCanvasResource::GetOrCreateGpuMailbox");
1093 DCHECK_EQ(sync_mode, kVerifiedSyncToken);
1094 return mailbox_;
1095 }
1096
HasGpuMailbox() const1097 bool ExternalCanvasResource::HasGpuMailbox() const {
1098 return !mailbox_.IsZero();
1099 }
1100
GetSyncToken()1101 const gpu::SyncToken ExternalCanvasResource::GetSyncToken() {
1102 TRACE_EVENT0("blink", "ExternalCanvasResource::GetSyncToken");
1103 if (!sync_token_.HasData()) {
1104 auto* gl = ContextGL();
1105 if (gl)
1106 gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
1107 }
1108 return sync_token_;
1109 }
1110
1111 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const1112 ExternalCanvasResource::ContextProviderWrapper() const {
1113 return context_provider_wrapper_;
1114 }
1115
ExternalCanvasResource(const gpu::Mailbox & mailbox,const IntSize & size,GLenum texture_target,const CanvasColorParams & color_params,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality,bool is_origin_top_left)1116 ExternalCanvasResource::ExternalCanvasResource(
1117 const gpu::Mailbox& mailbox,
1118 const IntSize& size,
1119 GLenum texture_target,
1120 const CanvasColorParams& color_params,
1121 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
1122 base::WeakPtr<CanvasResourceProvider> provider,
1123 SkFilterQuality filter_quality,
1124 bool is_origin_top_left)
1125 : CanvasResource(std::move(provider), filter_quality, color_params),
1126 context_provider_wrapper_(std::move(context_provider_wrapper)),
1127 size_(size),
1128 mailbox_(mailbox),
1129 texture_target_(texture_target),
1130 is_origin_top_left_(is_origin_top_left) {}
1131
1132 // CanvasResourceSwapChain
1133 //==============================================================================
Create(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)1134 scoped_refptr<CanvasResourceSwapChain> CanvasResourceSwapChain::Create(
1135 const IntSize& size,
1136 const CanvasColorParams& color_params,
1137 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
1138 base::WeakPtr<CanvasResourceProvider> provider,
1139 SkFilterQuality filter_quality) {
1140 TRACE_EVENT0("blink", "CanvasResourceSwapChain::Create");
1141 auto resource = AdoptRef(new CanvasResourceSwapChain(
1142 size, color_params, std::move(context_provider_wrapper),
1143 std::move(provider), filter_quality));
1144 return resource->IsValid() ? resource : nullptr;
1145 }
1146
~CanvasResourceSwapChain()1147 CanvasResourceSwapChain::~CanvasResourceSwapChain() {
1148 OnDestroy();
1149 }
1150
IsValid() const1151 bool CanvasResourceSwapChain::IsValid() const {
1152 return context_provider_wrapper_ && HasGpuMailbox();
1153 }
1154
TakeSkImage(sk_sp<SkImage> image)1155 void CanvasResourceSwapChain::TakeSkImage(sk_sp<SkImage> image) {
1156 NOTREACHED();
1157 }
1158
Bitmap()1159 scoped_refptr<StaticBitmapImage> CanvasResourceSwapChain::Bitmap() {
1160 SkImageInfo image_info = SkImageInfo::Make(
1161 Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
1162 ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
1163
1164 // It's safe to share the back buffer texture id if we're on the same thread
1165 // since the |release_callback| ensures this resource will be alive.
1166 GLuint shared_texture_id = !is_cross_thread() ? back_buffer_texture_id_ : 0u;
1167
1168 // The |release_callback| keeps a ref on this resource to ensure the backing
1169 // shared image is kept alive until the lifetime of the image.
1170 auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
1171 [](scoped_refptr<CanvasResourceSwapChain>, const gpu::SyncToken&, bool) {
1172 // Do nothing but hold onto the refptr.
1173 },
1174 base::RetainedRef(this)));
1175
1176 return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
1177 back_buffer_mailbox_, GetSyncToken(), shared_texture_id, image_info,
1178 GL_TEXTURE_2D, true /*is_origin_top_left*/, context_provider_wrapper_,
1179 owning_thread_ref_, owning_thread_task_runner_,
1180 std::move(release_callback));
1181 }
1182
Abandon()1183 void CanvasResourceSwapChain::Abandon() {
1184 // Called when the owning thread has been torn down which will destroy the
1185 // context on which the shared image was created so no cleanup is necessary.
1186 }
1187
TearDown()1188 void CanvasResourceSwapChain::TearDown() {
1189 // The context deletes all shared images on destruction which means no
1190 // cleanup is needed if the context was lost.
1191 if (!context_provider_wrapper_)
1192 return;
1193
1194 auto* raster_interface =
1195 context_provider_wrapper_->ContextProvider()->RasterInterface();
1196 DCHECK(raster_interface);
1197 raster_interface->EndSharedImageAccessDirectCHROMIUM(back_buffer_texture_id_);
1198 raster_interface->DeleteGpuRasterTexture(back_buffer_texture_id_);
1199 // No synchronization is needed here because the GL SharedImageRepresentation
1200 // will keep the backing alive on the service until the textures are deleted.
1201 auto* sii =
1202 context_provider_wrapper_->ContextProvider()->SharedImageInterface();
1203 DCHECK(sii);
1204 sii->DestroySharedImage(gpu::SyncToken(), front_buffer_mailbox_);
1205 sii->DestroySharedImage(gpu::SyncToken(), back_buffer_mailbox_);
1206 }
1207
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)1208 const gpu::Mailbox& CanvasResourceSwapChain::GetOrCreateGpuMailbox(
1209 MailboxSyncMode sync_mode) {
1210 DCHECK_EQ(sync_mode, kVerifiedSyncToken);
1211 return front_buffer_mailbox_;
1212 }
1213
HasGpuMailbox() const1214 bool CanvasResourceSwapChain::HasGpuMailbox() const {
1215 return !front_buffer_mailbox_.IsZero();
1216 }
1217
GetSyncToken()1218 const gpu::SyncToken CanvasResourceSwapChain::GetSyncToken() {
1219 DCHECK(sync_token_.verified_flush());
1220 return sync_token_;
1221 }
1222
PresentSwapChain()1223 void CanvasResourceSwapChain::PresentSwapChain() {
1224 DCHECK(!is_cross_thread());
1225 DCHECK(context_provider_wrapper_);
1226 TRACE_EVENT0("blink", "CanvasResourceSwapChain::PresentSwapChain");
1227
1228 auto* raster_interface =
1229 context_provider_wrapper_->ContextProvider()->RasterInterface();
1230 DCHECK(raster_interface);
1231
1232 auto* sii =
1233 context_provider_wrapper_->ContextProvider()->SharedImageInterface();
1234 DCHECK(sii);
1235
1236 // Synchronize presentation and rendering.
1237 raster_interface->GenUnverifiedSyncTokenCHROMIUM(sync_token_.GetData());
1238 sii->PresentSwapChain(sync_token_, back_buffer_mailbox_);
1239 // This only gets called via the CanvasResourceDispatcher export path so a
1240 // verified sync token will be needed ultimately.
1241 sync_token_ = sii->GenVerifiedSyncToken();
1242 raster_interface->WaitSyncTokenCHROMIUM(sync_token_.GetData());
1243
1244 // PresentSwapChain() flips the front and back buffers, but the mailboxes
1245 // still refer to the current front and back buffer after present. So the
1246 // front buffer contains the content we just rendered, and it needs to be
1247 // copied into the back buffer to support a retained mode like canvas expects.
1248 // The wait sync token ensure that the present executes before we do the copy.
1249 raster_interface->CopySubTexture(front_buffer_mailbox_, back_buffer_mailbox_,
1250 GL_TEXTURE_2D, 0, 0, 0, 0, size_.Width(),
1251 size_.Height(), false /* unpack_flip_y */,
1252 false /* unpack_premultiply_alpha */);
1253 // Don't generate sync token here so that the copy is not on critical path.
1254 }
1255
1256 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const1257 CanvasResourceSwapChain::ContextProviderWrapper() const {
1258 return context_provider_wrapper_;
1259 }
1260
CanvasResourceSwapChain(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)1261 CanvasResourceSwapChain::CanvasResourceSwapChain(
1262 const IntSize& size,
1263 const CanvasColorParams& color_params,
1264 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
1265 base::WeakPtr<CanvasResourceProvider> provider,
1266 SkFilterQuality filter_quality)
1267 : CanvasResource(std::move(provider), filter_quality, color_params),
1268 context_provider_wrapper_(std::move(context_provider_wrapper)),
1269 size_(size) {
1270 if (!context_provider_wrapper_)
1271 return;
1272
1273 uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY |
1274 gpu::SHARED_IMAGE_USAGE_GLES2 |
1275 gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT |
1276 gpu::SHARED_IMAGE_USAGE_SCANOUT;
1277
1278 auto* sii =
1279 context_provider_wrapper_->ContextProvider()->SharedImageInterface();
1280 DCHECK(sii);
1281 gpu::SharedImageInterface::SwapChainMailboxes mailboxes =
1282 sii->CreateSwapChain(
1283 ColorParams().TransferableResourceFormat(), gfx::Size(size),
1284 ColorParams().GetStorageGfxColorSpace(), kTopLeft_GrSurfaceOrigin,
1285 kPremul_SkAlphaType, usage);
1286 back_buffer_mailbox_ = mailboxes.back_buffer;
1287 front_buffer_mailbox_ = mailboxes.front_buffer;
1288 sync_token_ = sii->GenVerifiedSyncToken();
1289
1290 // Wait for the mailboxes to be ready to be used.
1291 auto* raster_interface =
1292 context_provider_wrapper_->ContextProvider()->RasterInterface();
1293 DCHECK(raster_interface);
1294 raster_interface->WaitSyncTokenCHROMIUM(sync_token_.GetData());
1295
1296 back_buffer_texture_id_ =
1297 raster_interface->CreateAndConsumeForGpuRaster(back_buffer_mailbox_);
1298 raster_interface->BeginSharedImageAccessDirectCHROMIUM(
1299 back_buffer_texture_id_, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
1300 }
1301
1302 } // namespace blink
1303