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 "components/viz/common/resources/bitmap_allocation.h"
11 #include "components/viz/common/resources/resource_format_utils.h"
12 #include "components/viz/common/resources/single_release_callback.h"
13 #include "components/viz/common/resources/transferable_resource.h"
14 #include "gpu/GLES2/gl2extchromium.h"
15 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
16 #include "gpu/command_buffer/client/raster_interface.h"
17 #include "gpu/command_buffer/client/shared_image_interface.h"
18 #include "gpu/command_buffer/common/capabilities.h"
19 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
20 #include "gpu/command_buffer/common/shared_image_usage.h"
21 #include "gpu/command_buffer/common/sync_token.h"
22 #include "third_party/blink/public/platform/platform.h"
23 #include "third_party/blink/renderer/platform/graphics/accelerated_static_bitmap_image.h"
24 #include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
25 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
26 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
27 #include "third_party/blink/renderer/platform/graphics/static_bitmap_image.h"
28 #include "third_party/blink/renderer/platform/graphics/unaccelerated_static_bitmap_image.h"
29 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
30 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
31 #include "third_party/blink/renderer/platform/wtf/functional.h"
32 #include "third_party/skia/include/gpu/GrContext.h"
33 #include "ui/gfx/buffer_format_util.h"
34 #include "ui/gfx/color_space.h"
35 
36 namespace blink {
37 
38 // TODO(danakj): One day the gpu::mojom::Mailbox type should be shared with
39 // blink directly and we won't need to use gpu::mojom::blink::Mailbox, nor the
40 // conversion through WTF::Vector.
SharedBitmapIdToGpuMailboxPtr(const viz::SharedBitmapId & id)41 gpu::mojom::blink::MailboxPtr SharedBitmapIdToGpuMailboxPtr(
42     const viz::SharedBitmapId& id) {
43   WTF::Vector<int8_t> name(GL_MAILBOX_SIZE_CHROMIUM);
44   for (int i = 0; i < GL_MAILBOX_SIZE_CHROMIUM; ++i)
45     name[i] = id.name[i];
46   return {base::in_place, name};
47 }
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 
WaitSyncToken(const gpu::SyncToken & sync_token)98 void CanvasResource::WaitSyncToken(const gpu::SyncToken& sync_token) {
99   if (sync_token.HasData()) {
100     if (auto* interface_base = InterfaceBase())
101       interface_base->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
102   }
103 }
104 
ReleaseFrameResources(base::WeakPtr<CanvasResourceProvider> resource_provider,scoped_refptr<CanvasResource> resource,const gpu::SyncToken & sync_token,bool lost_resource)105 static void ReleaseFrameResources(
106     base::WeakPtr<CanvasResourceProvider> resource_provider,
107     scoped_refptr<CanvasResource> resource,
108     const gpu::SyncToken& sync_token,
109     bool lost_resource) {
110   resource->WaitSyncToken(sync_token);
111 
112   if (resource_provider)
113     resource_provider->NotifyTexParamsModified(resource.get());
114 
115   // TODO(khushalsagar): If multiple readers had access to this resource, losing
116   // it once should make sure subsequent releases don't try to recycle this
117   // resource.
118   if (lost_resource)
119     resource->NotifyResourceLost();
120   if (resource_provider && !lost_resource && resource->IsRecycleable())
121     resource_provider->RecycleResource(std::move(resource));
122 }
123 
PrepareTransferableResource(viz::TransferableResource * out_resource,std::unique_ptr<viz::SingleReleaseCallback> * out_callback,MailboxSyncMode sync_mode)124 bool CanvasResource::PrepareTransferableResource(
125     viz::TransferableResource* out_resource,
126     std::unique_ptr<viz::SingleReleaseCallback>* out_callback,
127     MailboxSyncMode sync_mode) {
128   DCHECK(IsValid());
129 
130   DCHECK(out_callback);
131   auto func = WTF::Bind(&ReleaseFrameResources, provider_,
132                         WTF::Passed(base::WrapRefCounted(this)));
133   *out_callback = viz::SingleReleaseCallback::Create(std::move(func));
134 
135   if (!out_resource)
136     return true;
137   if (SupportsAcceleratedCompositing())
138     return PrepareAcceleratedTransferableResource(out_resource, sync_mode);
139   return PrepareUnacceleratedTransferableResource(out_resource);
140 }
141 
PrepareAcceleratedTransferableResource(viz::TransferableResource * out_resource,MailboxSyncMode sync_mode)142 bool CanvasResource::PrepareAcceleratedTransferableResource(
143     viz::TransferableResource* out_resource,
144     MailboxSyncMode sync_mode) {
145   TRACE_EVENT0("blink",
146                "CanvasResource::PrepareAcceleratedTransferableResource");
147   // Gpu compositing is a prerequisite for compositing an accelerated resource
148   DCHECK(SharedGpuContext::IsGpuCompositingEnabled());
149   if (!ContextProviderWrapper())
150     return false;
151   const gpu::Mailbox& mailbox = GetOrCreateGpuMailbox(sync_mode);
152   if (mailbox.IsZero())
153     return false;
154 
155   *out_resource = viz::TransferableResource::MakeGL(
156       mailbox, GLFilter(), TextureTarget(), GetSyncToken(), gfx::Size(Size()),
157       IsOverlayCandidate());
158 
159   out_resource->color_space = color_params_.GetSamplerGfxColorSpace();
160   out_resource->format = color_params_.TransferableResourceFormat();
161   out_resource->read_lock_fences_enabled = NeedsReadLockFences();
162 
163   return true;
164 }
165 
PrepareUnacceleratedTransferableResource(viz::TransferableResource * out_resource)166 bool CanvasResource::PrepareUnacceleratedTransferableResource(
167     viz::TransferableResource* out_resource) {
168   TRACE_EVENT0("blink",
169                "CanvasResource::PrepareUnacceleratedTransferableResource");
170   const gpu::Mailbox& mailbox = GetOrCreateGpuMailbox(kVerifiedSyncToken);
171   if (mailbox.IsZero())
172     return false;
173 
174   // For software compositing, the display compositor assumes an N32 format for
175   // the resource type and completely ignores the format set on the
176   // TransferableResource. Clients are expected to render in N32 format but use
177   // RGBA as the tagged format on resources.
178   *out_resource = viz::TransferableResource::MakeSoftware(
179       mailbox, gfx::Size(Size()), viz::RGBA_8888);
180 
181   out_resource->color_space = color_params_.GetSamplerGfxColorSpace();
182 
183   return true;
184 }
185 
GetGrContext() const186 GrContext* CanvasResource::GetGrContext() const {
187   if (!ContextProviderWrapper())
188     return nullptr;
189   return ContextProviderWrapper()->ContextProvider()->GetGrContext();
190 }
191 
CreateSkImageInfo() const192 SkImageInfo CanvasResource::CreateSkImageInfo() const {
193   return SkImageInfo::Make(
194       Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
195       ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
196 }
197 
GLFilter() const198 GLenum CanvasResource::GLFilter() const {
199   return filter_quality_ == kNone_SkFilterQuality ? GL_NEAREST : GL_LINEAR;
200 }
201 
202 // CanvasResourceSharedBitmap
203 //==============================================================================
204 
CanvasResourceSharedBitmap(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)205 CanvasResourceSharedBitmap::CanvasResourceSharedBitmap(
206     const IntSize& size,
207     const CanvasColorParams& color_params,
208     base::WeakPtr<CanvasResourceProvider> provider,
209     SkFilterQuality filter_quality)
210     : CanvasResource(std::move(provider), filter_quality, color_params),
211       size_(size) {
212   // Software compositing lazily uses RGBA_8888 as the resource format
213   // everywhere but the content is expected to be rendered in N32 format.
214   base::MappedReadOnlyRegion shm = viz::bitmap_allocation::AllocateSharedBitmap(
215       gfx::Size(Size()), viz::RGBA_8888);
216 
217   if (!shm.IsValid())
218     return;
219 
220   shared_mapping_ = std::move(shm.mapping);
221   shared_bitmap_id_ = viz::SharedBitmap::GenerateId();
222 
223   CanvasResourceDispatcher* resource_dispatcher =
224       Provider() ? Provider()->ResourceDispatcher() : nullptr;
225   if (resource_dispatcher) {
226     resource_dispatcher->DidAllocateSharedBitmap(
227         std::move(shm.region),
228         SharedBitmapIdToGpuMailboxPtr(shared_bitmap_id_));
229   }
230 }
231 
~CanvasResourceSharedBitmap()232 CanvasResourceSharedBitmap::~CanvasResourceSharedBitmap() {
233   OnDestroy();
234 }
235 
IsValid() const236 bool CanvasResourceSharedBitmap::IsValid() const {
237   return shared_mapping_.IsValid();
238 }
239 
Size() const240 IntSize CanvasResourceSharedBitmap::Size() const {
241   return size_;
242 }
243 
Bitmap()244 scoped_refptr<StaticBitmapImage> CanvasResourceSharedBitmap::Bitmap() {
245   if (!IsValid())
246     return nullptr;
247   // Construct an SkImage that references the shared memory buffer.
248   // The release callback holds a reference to |this| to ensure that the
249   // canvas resource that owns the shared memory stays alive at least until
250   // the SkImage is destroyed.
251   SkImageInfo image_info = SkImageInfo::Make(
252       Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
253       ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
254   SkPixmap pixmap(image_info, shared_mapping_.memory(),
255                   image_info.minRowBytes());
256   this->AddRef();
257   sk_sp<SkImage> sk_image = SkImage::MakeFromRaster(
258       pixmap,
259       [](const void*, SkImage::ReleaseContext resource_to_unref) {
260         static_cast<CanvasResourceSharedBitmap*>(resource_to_unref)->Release();
261       },
262       this);
263   auto image = UnacceleratedStaticBitmapImage::Create(sk_image);
264   image->SetOriginClean(is_origin_clean_);
265   return image;
266 }
267 
Create(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)268 scoped_refptr<CanvasResourceSharedBitmap> CanvasResourceSharedBitmap::Create(
269     const IntSize& size,
270     const CanvasColorParams& color_params,
271     base::WeakPtr<CanvasResourceProvider> provider,
272     SkFilterQuality filter_quality) {
273   auto resource = AdoptRef(new CanvasResourceSharedBitmap(
274       size, color_params, std::move(provider), filter_quality));
275   return resource->IsValid() ? resource : nullptr;
276 }
277 
TearDown()278 void CanvasResourceSharedBitmap::TearDown() {
279   CanvasResourceDispatcher* resource_dispatcher =
280       Provider() ? Provider()->ResourceDispatcher() : nullptr;
281   if (resource_dispatcher && !shared_bitmap_id_.IsZero()) {
282     resource_dispatcher->DidDeleteSharedBitmap(
283         SharedBitmapIdToGpuMailboxPtr(shared_bitmap_id_));
284   }
285   shared_mapping_ = {};
286 }
287 
Abandon()288 void CanvasResourceSharedBitmap::Abandon() {
289   shared_mapping_ = {};
290 }
291 
NotifyResourceLost()292 void CanvasResourceSharedBitmap::NotifyResourceLost() {
293   // Release our reference to the shared memory mapping since the resource can
294   // no longer be safely recycled and this memory is needed for copy-on-write.
295   shared_mapping_ = {};
296 }
297 
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)298 const gpu::Mailbox& CanvasResourceSharedBitmap::GetOrCreateGpuMailbox(
299     MailboxSyncMode sync_mode) {
300   return shared_bitmap_id_;
301 }
302 
HasGpuMailbox() const303 bool CanvasResourceSharedBitmap::HasGpuMailbox() const {
304   return !shared_bitmap_id_.IsZero();
305 }
306 
TakeSkImage(sk_sp<SkImage> image)307 void CanvasResourceSharedBitmap::TakeSkImage(sk_sp<SkImage> image) {
308   SkImageInfo image_info = SkImageInfo::Make(
309       Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
310       ColorParams().GetSkAlphaType(),
311       ColorParams().GetSkColorSpaceForSkSurfaces());
312 
313   bool read_pixels_successful = image->readPixels(
314       image_info, shared_mapping_.memory(), image_info.minRowBytes(), 0, 0);
315   DCHECK(read_pixels_successful);
316 }
317 
318 // CanvasResourceSharedImage
319 //==============================================================================
320 
CanvasResourceSharedImage(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)321 CanvasResourceSharedImage::CanvasResourceSharedImage(
322     const IntSize& size,
323     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
324     base::WeakPtr<CanvasResourceProvider> provider,
325     SkFilterQuality filter_quality,
326     const CanvasColorParams& color_params,
327     bool is_origin_top_left,
328     bool is_accelerated,
329     uint32_t shared_image_usage_flags)
330     : CanvasResource(std::move(provider), filter_quality, color_params),
331       context_provider_wrapper_(std::move(context_provider_wrapper)),
332       size_(size),
333       is_origin_top_left_(is_origin_top_left),
334       is_accelerated_(is_accelerated),
335       is_overlay_candidate_(shared_image_usage_flags &
336                             gpu::SHARED_IMAGE_USAGE_SCANOUT),
337       texture_target_(
338           is_overlay_candidate_
339               ? gpu::GetBufferTextureTarget(
340                     gfx::BufferUsage::SCANOUT,
341                     BufferFormat(ColorParams().TransferableResourceFormat()),
342                     context_provider_wrapper_->ContextProvider()
343                         ->GetCapabilities())
344               : GL_TEXTURE_2D),
345       use_oop_rasterization_(context_provider_wrapper_->ContextProvider()
346                                  ->GetCapabilities()
347                                  .supports_oop_raster) {
348   auto* gpu_memory_buffer_manager =
349       Platform::Current()->GetGpuMemoryBufferManager();
350   if (!is_accelerated_) {
351     DCHECK(gpu_memory_buffer_manager);
352     DCHECK(shared_image_usage_flags & gpu::SHARED_IMAGE_USAGE_DISPLAY);
353 
354     gpu_memory_buffer_ = gpu_memory_buffer_manager->CreateGpuMemoryBuffer(
355         gfx::Size(size), ColorParams().GetBufferFormat(),
356         gfx::BufferUsage::SCANOUT_CPU_READ_WRITE, gpu::kNullSurfaceHandle);
357     if (!gpu_memory_buffer_)
358       return;
359 
360     gpu_memory_buffer_->SetColorSpace(color_params.GetStorageGfxColorSpace());
361   }
362 
363   auto* shared_image_interface =
364       context_provider_wrapper_->ContextProvider()->SharedImageInterface();
365   DCHECK(shared_image_interface);
366 
367   // The GLES2 flag is needed for rendering via GL using a GrContext.
368   if (use_oop_rasterization_) {
369     shared_image_usage_flags = shared_image_usage_flags |
370                                gpu::SHARED_IMAGE_USAGE_RASTER |
371                                gpu::SHARED_IMAGE_USAGE_OOP_RASTERIZATION;
372   } else {
373     shared_image_usage_flags = shared_image_usage_flags |
374                                gpu::SHARED_IMAGE_USAGE_GLES2 |
375                                gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
376   }
377 
378   gpu::Mailbox shared_image_mailbox;
379   if (gpu_memory_buffer_) {
380     shared_image_mailbox = shared_image_interface->CreateSharedImage(
381         gpu_memory_buffer_.get(), gpu_memory_buffer_manager,
382         ColorParams().GetStorageGfxColorSpace(), shared_image_usage_flags);
383   } else {
384     shared_image_mailbox = shared_image_interface->CreateSharedImage(
385         ColorParams().TransferableResourceFormat(), gfx::Size(size),
386         ColorParams().GetStorageGfxColorSpace(), shared_image_usage_flags);
387   }
388 
389   // Wait for the mailbox to be ready to be used.
390   WaitSyncToken(shared_image_interface->GenUnverifiedSyncToken());
391 
392   auto* raster_interface = RasterInterface();
393   DCHECK(raster_interface);
394   owning_thread_data().shared_image_mailbox = shared_image_mailbox;
395 
396   if (use_oop_rasterization_)
397     return;
398 
399   owning_thread_data().texture_id_for_read_access =
400       raster_interface->CreateAndConsumeForGpuRaster(shared_image_mailbox);
401 
402   // For the non-accelerated case, writes are done on the CPU. So we don't need
403   // a texture for writes.
404   if (!is_accelerated_)
405     return;
406   if (shared_image_usage_flags &
407       gpu::SHARED_IMAGE_USAGE_CONCURRENT_READ_WRITE) {
408     owning_thread_data().texture_id_for_write_access =
409         raster_interface->CreateAndConsumeForGpuRaster(shared_image_mailbox);
410   } else {
411     owning_thread_data().texture_id_for_write_access =
412         owning_thread_data().texture_id_for_read_access;
413   }
414 }
415 
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)416 scoped_refptr<CanvasResourceSharedImage> CanvasResourceSharedImage::Create(
417     const IntSize& size,
418     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
419     base::WeakPtr<CanvasResourceProvider> provider,
420     SkFilterQuality filter_quality,
421     const CanvasColorParams& color_params,
422     bool is_origin_top_left,
423     bool is_accelerated,
424     uint32_t shared_image_usage_flags) {
425   TRACE_EVENT0("blink", "CanvasResourceSharedImage::Create");
426   auto resource = base::AdoptRef(new CanvasResourceSharedImage(
427       size, std::move(context_provider_wrapper), std::move(provider),
428       filter_quality, color_params, is_origin_top_left, is_accelerated,
429       shared_image_usage_flags));
430   return resource->IsValid() ? resource : nullptr;
431 }
432 
IsValid() const433 bool CanvasResourceSharedImage::IsValid() const {
434   return !mailbox().IsZero();
435 }
436 
~CanvasResourceSharedImage()437 CanvasResourceSharedImage::~CanvasResourceSharedImage() {
438   OnDestroy();
439 }
440 
TearDown()441 void CanvasResourceSharedImage::TearDown() {
442   DCHECK(!is_cross_thread());
443 
444   // The context deletes all shared images on destruction which means no
445   // cleanup is needed if the context was lost.
446   if (ContextProviderWrapper()) {
447     auto* raster_interface = RasterInterface();
448     auto* shared_image_interface =
449         ContextProviderWrapper()->ContextProvider()->SharedImageInterface();
450     if (raster_interface && shared_image_interface) {
451       gpu::SyncToken shared_image_sync_token;
452       raster_interface->GenUnverifiedSyncTokenCHROMIUM(
453           shared_image_sync_token.GetData());
454       shared_image_interface->DestroySharedImage(shared_image_sync_token,
455                                                  mailbox());
456     }
457     if (raster_interface) {
458       if (owning_thread_data().texture_id_for_read_access) {
459         raster_interface->DeleteGpuRasterTexture(
460             owning_thread_data().texture_id_for_read_access);
461       }
462       if (owning_thread_data().texture_id_for_write_access &&
463           owning_thread_data().texture_id_for_write_access !=
464               owning_thread_data().texture_id_for_read_access) {
465         raster_interface->DeleteGpuRasterTexture(
466             owning_thread_data().texture_id_for_write_access);
467       }
468     }
469   }
470 
471   owning_thread_data().texture_id_for_read_access = 0u;
472   owning_thread_data().texture_id_for_write_access = 0u;
473 }
474 
Abandon()475 void CanvasResourceSharedImage::Abandon() {
476   // Called when the owning thread has been torn down which will destroy the
477   // context on which the shared image was created so no cleanup is necessary.
478 }
479 
WillDraw()480 void CanvasResourceSharedImage::WillDraw() {
481   DCHECK(!is_cross_thread())
482       << "Write access is only allowed on the owning thread";
483 
484   // Sync token for software mode is generated from SharedImageInterface each
485   // time the GMB is updated.
486   if (!is_accelerated_)
487     return;
488 
489   owning_thread_data().mailbox_needs_new_sync_token = true;
490 }
491 
492 // static
OnBitmapImageDestroyed(scoped_refptr<CanvasResourceSharedImage> resource,bool has_read_ref_on_texture,const gpu::SyncToken & sync_token,bool is_lost)493 void CanvasResourceSharedImage::OnBitmapImageDestroyed(
494     scoped_refptr<CanvasResourceSharedImage> resource,
495     bool has_read_ref_on_texture,
496     const gpu::SyncToken& sync_token,
497     bool is_lost) {
498   DCHECK(!resource->is_cross_thread());
499 
500   if (has_read_ref_on_texture) {
501     DCHECK(!resource->use_oop_rasterization_);
502     DCHECK_GT(resource->owning_thread_data().bitmap_image_read_refs, 0u);
503 
504     resource->owning_thread_data().bitmap_image_read_refs--;
505     if (resource->owning_thread_data().bitmap_image_read_refs == 0u &&
506         resource->RasterInterface()) {
507       resource->RasterInterface()->EndSharedImageAccessDirectCHROMIUM(
508           resource->owning_thread_data().texture_id_for_read_access);
509     }
510   }
511 
512   auto weak_provider = resource->WeakProvider();
513   ReleaseFrameResources(std::move(weak_provider), std::move(resource),
514                         sync_token, is_lost);
515 }
516 
Transfer()517 void CanvasResourceSharedImage::Transfer() {
518   if (is_cross_thread() || !ContextProviderWrapper())
519     return;
520 
521   // TODO(khushalsagar): This is for consistency with MailboxTextureHolder
522   // transfer path. Its unclear why the verification can not be deferred until
523   // the resource needs to be transferred cross-process.
524   owning_thread_data().mailbox_sync_mode = kVerifiedSyncToken;
525   GetSyncToken();
526 }
527 
Bitmap()528 scoped_refptr<StaticBitmapImage> CanvasResourceSharedImage::Bitmap() {
529   TRACE_EVENT0("blink", "CanvasResourceSharedImage::Bitmap");
530 
531   SkImageInfo image_info = CreateSkImageInfo();
532   if (!is_accelerated_) {
533     if (!gpu_memory_buffer_->Map())
534       return nullptr;
535 
536     SkPixmap pixmap(CreateSkImageInfo(), gpu_memory_buffer_->memory(0),
537                     gpu_memory_buffer_->stride(0));
538     auto sk_image = SkImage::MakeRasterCopy(pixmap);
539     gpu_memory_buffer_->Unmap();
540     return sk_image ? UnacceleratedStaticBitmapImage::Create(sk_image)
541                     : nullptr;
542   }
543 
544   // In order to avoid creating multiple representations for this shared image
545   // on the same context, the AcceleratedStaticBitmapImage uses the texture id
546   // of the resource here. We keep a count of pending shared image releases to
547   // correctly scope the read lock for this texture.
548   // If this resource is accessed across threads, or the
549   // AcceleratedStaticBitmapImage is accessed on a different thread after being
550   // created here, the image will create a new representation from the mailbox
551   // rather than referring to the shared image's texture ID if it was provided
552   // below.
553   const bool has_read_ref_on_texture =
554       !is_cross_thread() && !use_oop_rasterization_;
555   GLuint texture_id_for_image = 0u;
556   if (has_read_ref_on_texture) {
557     texture_id_for_image = owning_thread_data().texture_id_for_read_access;
558     owning_thread_data().bitmap_image_read_refs++;
559     if (owning_thread_data().bitmap_image_read_refs == 1u &&
560         RasterInterface()) {
561       RasterInterface()->BeginSharedImageAccessDirectCHROMIUM(
562           texture_id_for_image, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
563     }
564   }
565 
566   // The |release_callback| keeps a ref on this resource to ensure the backing
567   // shared image is kept alive until the lifetime of the image.
568   // Note that the code in CanvasResourceProvider::RecycleResource also uses the
569   // ref-count on the resource as a proxy for a read lock to allow recycling the
570   // resource once all refs have been released.
571   auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
572       &OnBitmapImageDestroyed, scoped_refptr<CanvasResourceSharedImage>(this),
573       has_read_ref_on_texture));
574 
575   scoped_refptr<StaticBitmapImage> image;
576 
577   // If its cross thread, then the sync token was already verified. If not, then
578   // we don't need one. The image lazily generates a token if needed.
579   gpu::SyncToken token = is_cross_thread() ? sync_token() : gpu::SyncToken();
580   image = AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
581       mailbox(), token, texture_id_for_image, image_info, texture_target_,
582       is_origin_top_left_, context_provider_wrapper_, owning_thread_ref_,
583       owning_thread_task_runner_, std::move(release_callback));
584 
585   DCHECK(image);
586   return image;
587 }
588 
CopyRenderingResultsToGpuMemoryBuffer(const sk_sp<SkImage> & image)589 void CanvasResourceSharedImage::CopyRenderingResultsToGpuMemoryBuffer(
590     const sk_sp<SkImage>& image) {
591   DCHECK(!is_cross_thread());
592 
593   if (!ContextProviderWrapper() || !gpu_memory_buffer_->Map())
594     return;
595 
596   auto surface = SkSurface::MakeRasterDirect(CreateSkImageInfo(),
597                                              gpu_memory_buffer_->memory(0),
598                                              gpu_memory_buffer_->stride(0));
599   surface->getCanvas()->drawImage(image, 0, 0);
600   auto* sii =
601       ContextProviderWrapper()->ContextProvider()->SharedImageInterface();
602   gpu_memory_buffer_->Unmap();
603   sii->UpdateSharedImage(gpu::SyncToken(), mailbox());
604   owning_thread_data().sync_token = sii->GenUnverifiedSyncToken();
605 }
606 
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)607 const gpu::Mailbox& CanvasResourceSharedImage::GetOrCreateGpuMailbox(
608     MailboxSyncMode sync_mode) {
609   if (!is_cross_thread()) {
610     owning_thread_data().mailbox_sync_mode = sync_mode;
611   }
612   return mailbox();
613 }
614 
HasGpuMailbox() const615 bool CanvasResourceSharedImage::HasGpuMailbox() const {
616   return !mailbox().IsZero();
617 }
618 
GetSyncToken()619 const gpu::SyncToken CanvasResourceSharedImage::GetSyncToken() {
620   if (is_cross_thread()) {
621     // Sync token should be generated at Transfer time, which must always be
622     // called before cross-thread usage. And since we don't allow writes on
623     // another thread, the sync token generated at Transfer time shouldn't
624     // have been invalidated.
625     DCHECK(!mailbox_needs_new_sync_token());
626     DCHECK(sync_token().verified_flush());
627 
628     return sync_token();
629   }
630 
631   if (mailbox_needs_new_sync_token()) {
632     auto* raster_interface = RasterInterface();
633     DCHECK(raster_interface);  // caller should already have early exited if
634                                // !raster_interface.
635     raster_interface->GenUnverifiedSyncTokenCHROMIUM(
636         owning_thread_data().sync_token.GetData());
637     owning_thread_data().mailbox_needs_new_sync_token = false;
638   }
639 
640   if (owning_thread_data().mailbox_sync_mode == kVerifiedSyncToken &&
641       !owning_thread_data().sync_token.verified_flush()) {
642     int8_t* token_data = owning_thread_data().sync_token.GetData();
643     auto* raster_interface = RasterInterface();
644     raster_interface->ShallowFlushCHROMIUM();
645     raster_interface->VerifySyncTokensCHROMIUM(&token_data, 1);
646     owning_thread_data().sync_token.SetVerifyFlush();
647   }
648 
649   return sync_token();
650 }
651 
NotifyResourceLost()652 void CanvasResourceSharedImage::NotifyResourceLost() {
653   owning_thread_data().is_lost = true;
654 
655   if (WeakProvider())
656     Provider()->NotifyTexParamsModified(this);
657 }
658 
659 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const660 CanvasResourceSharedImage::ContextProviderWrapper() const {
661   DCHECK(!is_cross_thread());
662   return context_provider_wrapper_;
663 }
664 
665 // ExternalCanvasResource
666 //==============================================================================
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)667 scoped_refptr<ExternalCanvasResource> ExternalCanvasResource::Create(
668     const gpu::Mailbox& mailbox,
669     const IntSize& size,
670     GLenum texture_target,
671     const CanvasColorParams& color_params,
672     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
673     base::WeakPtr<CanvasResourceProvider> provider,
674     SkFilterQuality filter_quality,
675     bool is_origin_top_left) {
676   TRACE_EVENT0("blink", "ExternalCanvasResource::Create");
677   auto resource = AdoptRef(new ExternalCanvasResource(
678       mailbox, size, texture_target, color_params,
679       std::move(context_provider_wrapper), std::move(provider), filter_quality,
680       is_origin_top_left));
681   return resource->IsValid() ? resource : nullptr;
682 }
683 
~ExternalCanvasResource()684 ExternalCanvasResource::~ExternalCanvasResource() {
685   OnDestroy();
686 }
687 
IsValid() const688 bool ExternalCanvasResource::IsValid() const {
689   return context_provider_wrapper_ && !mailbox_.IsZero();
690 }
691 
Abandon()692 void ExternalCanvasResource::Abandon() {
693   // We don't need to destroy the shared image mailbox since we don't own it.
694 }
695 
TakeSkImage(sk_sp<SkImage> image)696 void ExternalCanvasResource::TakeSkImage(sk_sp<SkImage> image) {
697   NOTREACHED();
698 }
699 
Bitmap()700 scoped_refptr<StaticBitmapImage> ExternalCanvasResource::Bitmap() {
701   TRACE_EVENT0("blink", "ExternalCanvasResource::Bitmap");
702   if (!IsValid())
703     return nullptr;
704 
705   // The |release_callback| keeps a ref on this resource to ensure the backing
706   // shared image is kept alive until the lifetime of the image.
707   auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
708       [](scoped_refptr<ExternalCanvasResource> resource,
709          const gpu::SyncToken& sync_token, bool is_lost) {
710         // Do nothing but hold onto the refptr.
711       },
712       base::RetainedRef(this)));
713 
714   return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
715       mailbox_, GetSyncToken(), /*shared_image_texture_id=*/0u,
716       CreateSkImageInfo(), texture_target_, is_origin_top_left_,
717       context_provider_wrapper_, owning_thread_ref_, owning_thread_task_runner_,
718       std::move(release_callback));
719 }
720 
TearDown()721 void ExternalCanvasResource::TearDown() {
722   Abandon();
723 }
724 
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)725 const gpu::Mailbox& ExternalCanvasResource::GetOrCreateGpuMailbox(
726     MailboxSyncMode sync_mode) {
727   TRACE_EVENT0("blink", "ExternalCanvasResource::GetOrCreateGpuMailbox");
728   DCHECK_EQ(sync_mode, kVerifiedSyncToken);
729   return mailbox_;
730 }
731 
HasGpuMailbox() const732 bool ExternalCanvasResource::HasGpuMailbox() const {
733   return !mailbox_.IsZero();
734 }
735 
GetSyncToken()736 const gpu::SyncToken ExternalCanvasResource::GetSyncToken() {
737   TRACE_EVENT0("blink", "ExternalCanvasResource::GetSyncToken");
738   if (!sync_token_.HasData()) {
739     auto* gl = ContextGL();
740     if (gl)
741       gl->GenSyncTokenCHROMIUM(sync_token_.GetData());
742   }
743   return sync_token_;
744 }
745 
746 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const747 ExternalCanvasResource::ContextProviderWrapper() const {
748   return context_provider_wrapper_;
749 }
750 
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)751 ExternalCanvasResource::ExternalCanvasResource(
752     const gpu::Mailbox& mailbox,
753     const IntSize& size,
754     GLenum texture_target,
755     const CanvasColorParams& color_params,
756     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
757     base::WeakPtr<CanvasResourceProvider> provider,
758     SkFilterQuality filter_quality,
759     bool is_origin_top_left)
760     : CanvasResource(std::move(provider), filter_quality, color_params),
761       context_provider_wrapper_(std::move(context_provider_wrapper)),
762       size_(size),
763       mailbox_(mailbox),
764       texture_target_(texture_target),
765       is_origin_top_left_(is_origin_top_left) {}
766 
767 // CanvasResourceSwapChain
768 //==============================================================================
Create(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)769 scoped_refptr<CanvasResourceSwapChain> CanvasResourceSwapChain::Create(
770     const IntSize& size,
771     const CanvasColorParams& color_params,
772     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
773     base::WeakPtr<CanvasResourceProvider> provider,
774     SkFilterQuality filter_quality) {
775   TRACE_EVENT0("blink", "CanvasResourceSwapChain::Create");
776   auto resource = AdoptRef(new CanvasResourceSwapChain(
777       size, color_params, std::move(context_provider_wrapper),
778       std::move(provider), filter_quality));
779   return resource->IsValid() ? resource : nullptr;
780 }
781 
~CanvasResourceSwapChain()782 CanvasResourceSwapChain::~CanvasResourceSwapChain() {
783   OnDestroy();
784 }
785 
IsValid() const786 bool CanvasResourceSwapChain::IsValid() const {
787   return context_provider_wrapper_ && HasGpuMailbox();
788 }
789 
TakeSkImage(sk_sp<SkImage> image)790 void CanvasResourceSwapChain::TakeSkImage(sk_sp<SkImage> image) {
791   NOTREACHED();
792 }
793 
Bitmap()794 scoped_refptr<StaticBitmapImage> CanvasResourceSwapChain::Bitmap() {
795   SkImageInfo image_info = SkImageInfo::Make(
796       Size().Width(), Size().Height(), ColorParams().GetSkColorType(),
797       ColorParams().GetSkAlphaType(), ColorParams().GetSkColorSpace());
798 
799   // It's safe to share the front buffer texture id if we're on the same thread
800   // since the |release_callback| ensures this resource will be alive.
801   GLuint shared_texture_id = 0u;
802   if (!is_cross_thread())
803     shared_texture_id = front_buffer_texture_id_;
804 
805   // The |release_callback| keeps a ref on this resource to ensure the backing
806   // shared image is kept alive until the lifetime of the image.
807   auto release_callback = viz::SingleReleaseCallback::Create(base::BindOnce(
808       [](scoped_refptr<CanvasResourceSwapChain>, const gpu::SyncToken&, bool) {
809         // Do nothing but hold onto the refptr.
810       },
811       base::RetainedRef(this)));
812 
813   return AcceleratedStaticBitmapImage::CreateFromCanvasMailbox(
814       front_buffer_mailbox_, sync_token_, shared_texture_id, image_info,
815       GL_TEXTURE_2D, true /*is_origin_top_left*/, context_provider_wrapper_,
816       owning_thread_ref_, owning_thread_task_runner_,
817       std::move(release_callback));
818 }
819 
Abandon()820 void CanvasResourceSwapChain::Abandon() {
821   // Called when the owning thread has been torn down which will destroy the
822   // context on which the shared image was created so no cleanup is necessary.
823 }
824 
TearDown()825 void CanvasResourceSwapChain::TearDown() {
826   // The context deletes all shared images on destruction which means no
827   // cleanup is needed if the context was lost.
828   if (!context_provider_wrapper_)
829     return;
830 
831   auto* raster_interface =
832       context_provider_wrapper_->ContextProvider()->RasterInterface();
833   DCHECK(raster_interface);
834   raster_interface->EndSharedImageAccessDirectCHROMIUM(
835       front_buffer_texture_id_);
836   raster_interface->DeleteGpuRasterTexture(front_buffer_texture_id_);
837   raster_interface->EndSharedImageAccessDirectCHROMIUM(back_buffer_texture_id_);
838   raster_interface->DeleteGpuRasterTexture(back_buffer_texture_id_);
839   // No synchronization is needed here because the GL SharedImageRepresentation
840   // will keep the backing alive on the service until the textures are deleted.
841   auto* sii =
842       context_provider_wrapper_->ContextProvider()->SharedImageInterface();
843   DCHECK(sii);
844   sii->DestroySharedImage(gpu::SyncToken(), front_buffer_mailbox_);
845   sii->DestroySharedImage(gpu::SyncToken(), back_buffer_mailbox_);
846 }
847 
GetOrCreateGpuMailbox(MailboxSyncMode sync_mode)848 const gpu::Mailbox& CanvasResourceSwapChain::GetOrCreateGpuMailbox(
849     MailboxSyncMode sync_mode) {
850   DCHECK_EQ(sync_mode, kVerifiedSyncToken);
851   return front_buffer_mailbox_;
852 }
853 
HasGpuMailbox() const854 bool CanvasResourceSwapChain::HasGpuMailbox() const {
855   return !front_buffer_mailbox_.IsZero();
856 }
857 
GetSyncToken()858 const gpu::SyncToken CanvasResourceSwapChain::GetSyncToken() {
859   DCHECK(sync_token_.verified_flush());
860   return sync_token_;
861 }
862 
PresentSwapChain()863 void CanvasResourceSwapChain::PresentSwapChain() {
864   DCHECK(!is_cross_thread());
865   DCHECK(context_provider_wrapper_);
866   TRACE_EVENT0("blink", "CanvasResourceSwapChain::PresentSwapChain");
867 
868   auto* raster_interface =
869       context_provider_wrapper_->ContextProvider()->RasterInterface();
870   DCHECK(raster_interface);
871 
872   auto* sii =
873       context_provider_wrapper_->ContextProvider()->SharedImageInterface();
874   DCHECK(sii);
875 
876   // Synchronize presentation and rendering.
877   raster_interface->GenUnverifiedSyncTokenCHROMIUM(sync_token_.GetData());
878   sii->PresentSwapChain(sync_token_, back_buffer_mailbox_);
879   // This only gets called via the CanvasResourceDispatcher export path so a
880   // verified sync token will be needed ultimately.
881   sync_token_ = sii->GenVerifiedSyncToken();
882   raster_interface->WaitSyncTokenCHROMIUM(sync_token_.GetData());
883 
884   // PresentSwapChain() flips the front and back buffers, but the mailboxes
885   // still refer to the current front and back buffer after present.  So the
886   // front buffer contains the content we just rendered, and it needs to be
887   // copied into the back buffer to support a retained mode like canvas expects.
888   // The wait sync token ensure that the present executes before we do the copy.
889   raster_interface->CopySubTexture(front_buffer_mailbox_, back_buffer_mailbox_,
890                                    GL_TEXTURE_2D, 0, 0, 0, 0, size_.Width(),
891                                    size_.Height(), false /* unpack_flip_y */,
892                                    false /* unpack_premultiply_alpha */);
893 }
894 
895 base::WeakPtr<WebGraphicsContext3DProviderWrapper>
ContextProviderWrapper() const896 CanvasResourceSwapChain::ContextProviderWrapper() const {
897   return context_provider_wrapper_;
898 }
899 
CanvasResourceSwapChain(const IntSize & size,const CanvasColorParams & color_params,base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,base::WeakPtr<CanvasResourceProvider> provider,SkFilterQuality filter_quality)900 CanvasResourceSwapChain::CanvasResourceSwapChain(
901     const IntSize& size,
902     const CanvasColorParams& color_params,
903     base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper,
904     base::WeakPtr<CanvasResourceProvider> provider,
905     SkFilterQuality filter_quality)
906     : CanvasResource(std::move(provider), filter_quality, color_params),
907       context_provider_wrapper_(std::move(context_provider_wrapper)),
908       size_(size) {
909   if (!context_provider_wrapper_)
910     return;
911 
912   uint32_t usage = gpu::SHARED_IMAGE_USAGE_DISPLAY |
913                    gpu::SHARED_IMAGE_USAGE_GLES2 |
914                    gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT |
915                    gpu::SHARED_IMAGE_USAGE_SCANOUT;
916 
917   auto* sii =
918       context_provider_wrapper_->ContextProvider()->SharedImageInterface();
919   DCHECK(sii);
920   gpu::SharedImageInterface::SwapChainMailboxes mailboxes =
921       sii->CreateSwapChain(ColorParams().TransferableResourceFormat(),
922                            gfx::Size(size),
923                            ColorParams().GetStorageGfxColorSpace(), usage);
924   back_buffer_mailbox_ = mailboxes.back_buffer;
925   front_buffer_mailbox_ = mailboxes.front_buffer;
926   sync_token_ = sii->GenVerifiedSyncToken();
927 
928   // Wait for the mailboxes to be ready to be used.
929   auto* raster_interface =
930       context_provider_wrapper_->ContextProvider()->RasterInterface();
931   DCHECK(raster_interface);
932   raster_interface->WaitSyncTokenCHROMIUM(sync_token_.GetData());
933 
934   front_buffer_texture_id_ =
935       raster_interface->CreateAndConsumeForGpuRaster(front_buffer_mailbox_);
936   raster_interface->BeginSharedImageAccessDirectCHROMIUM(
937       front_buffer_texture_id_, GL_SHARED_IMAGE_ACCESS_MODE_READ_CHROMIUM);
938 
939   back_buffer_texture_id_ =
940       raster_interface->CreateAndConsumeForGpuRaster(back_buffer_mailbox_);
941   raster_interface->BeginSharedImageAccessDirectCHROMIUM(
942       back_buffer_texture_id_, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM);
943 }
944 
945 }  // namespace blink
946