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