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 "base/logging.h" 6 #include "base/memory/shared_memory_mapping.h" 7 #include "base/memory/weak_ptr.h" 8 #include "components/viz/common/resources/shared_bitmap.h" 9 #include "gpu/command_buffer/client/gles2_interface.h" 10 #include "gpu/command_buffer/common/mailbox.h" 11 #include "gpu/command_buffer/common/sync_token.h" 12 #include "gpu/ipc/common/mailbox.mojom-blink.h" 13 #include "third_party/blink/renderer/platform/geometry/int_size.h" 14 #include "third_party/blink/renderer/platform/graphics/canvas_color_params.h" 15 #include "third_party/blink/renderer/platform/graphics/web_graphics_context_3d_provider_wrapper.h" 16 #include "third_party/blink/renderer/platform/scheduler/public/thread.h" 17 #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" 18 19 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_H_ 20 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_H_ 21 22 namespace gfx { 23 24 class GpuMemoryBuffer; 25 26 } // namespace gfx 27 28 namespace gpu { 29 namespace raster { 30 31 class RasterInterface; 32 33 } // namespace raster 34 } // namespace gpu 35 36 namespace viz { 37 38 class SingleReleaseCallback; 39 struct TransferableResource; 40 41 } // namespace viz 42 43 namespace blink { 44 45 class CanvasResourceProvider; 46 class StaticBitmapImage; 47 48 // TODO(danakj): One day the gpu::mojom::Mailbox type should be shared with 49 // blink directly and we won't need to use gpu::mojom::blink::Mailbox, nor the 50 // conversion through WTF::Vector. 51 gpu::mojom::blink::MailboxPtr SharedBitmapIdToGpuMailboxPtr( 52 const viz::SharedBitmapId& id); 53 54 // Generic resource interface, used for locking (RAII) and recycling pixel 55 // buffers of any type. 56 // Note that this object may be accessed across multiple threads but not 57 // concurrently. The caller is responsible to call Transfer on the object before 58 // using it on a different thread. 59 class PLATFORM_EXPORT CanvasResource 60 : public WTF::ThreadSafeRefCounted<CanvasResource> { 61 public: 62 virtual ~CanvasResource(); 63 64 // We perform a lazy copy on write if the canvas content needs to be updated 65 // while its current resource is in use. In order to avoid re-allocating 66 // resources, its preferable to reuse a resource if its no longer in use. 67 // This API indicates whether a resource can be recycled. 68 virtual bool IsRecycleable() const = 0; 69 70 // Returns true if rendering to the resource is accelerated. 71 virtual bool IsAccelerated() const = 0; 72 73 // Returns true if the resource can be used with accelerated compositing. This 74 // is different from IsAccelerated since a resource may be rendered to on the 75 // CPU but can be used with GPU compositing (using GMBs). 76 virtual bool SupportsAcceleratedCompositing() const = 0; 77 78 // Returns true if the resource is still usable. It maybe not be valid in the 79 // case of a context loss or if we fail to initialize the memory backing for 80 // the resource. 81 virtual bool IsValid() const = 0; 82 83 // When a resource is returned by the display compositor, a sync token is 84 // provided to indicate when the compositor's commands using the resource are 85 // executed on the GPU thread. 86 // However in some cases we need to ensure that the commands using the 87 // resource have finished executing on the GPU itself. This API indicates 88 // whether this is required. The primary use-case for this is GMBs rendered to 89 // on the CPU but composited on the GPU. Its important for the GPU reads to be 90 // finished before updating the resource on the CPU. NeedsReadLockFences()91 virtual bool NeedsReadLockFences() const { return false; } 92 93 // The bounds for this resource. 94 virtual IntSize Size() const = 0; 95 96 // The mailbox which can be used to reference this resource in GPU commands. 97 // The sync mode indicates how the sync token for the resource should be 98 // prepared. 99 virtual const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) = 0; 100 101 // A CanvasResource is not thread-safe and does not allow concurrent usage 102 // from multiple threads. But it maybe used from any thread. It remains bound 103 // to the current thread until Transfer is called. Note that while the 104 // resource maybe used for reads on any thread, it can be written to only on 105 // the thread where it was created. Transfer()106 virtual void Transfer() {} 107 108 // Returns the sync token to indicate when all writes to the current resource 109 // are finished on the GPU thread. GetSyncToken()110 virtual const gpu::SyncToken GetSyncToken() { 111 NOTREACHED(); 112 return gpu::SyncToken(); 113 } 114 115 // Provides a TransferableResource representation of this resource to share it 116 // with the compositor. 117 bool PrepareTransferableResource(viz::TransferableResource*, 118 std::unique_ptr<viz::SingleReleaseCallback>*, 119 MailboxSyncMode); 120 121 // Issues a wait for this sync token on the context used by this resource for 122 // rendering. 123 void WaitSyncToken(const gpu::SyncToken&); 124 125 virtual bool OriginClean() const = 0; 126 virtual void SetOriginClean(bool) = 0; 127 128 // Provides a StaticBitmapImage wrapping this resource. Commonly used for 129 // snapshots not used in compositing (for instance to draw to another canvas). 130 virtual scoped_refptr<StaticBitmapImage> Bitmap() = 0; 131 132 // Copies the contents of |image| to the resource's backing memory. Only 133 // CanvasResourceProvider and derivatives should call this. 134 virtual void TakeSkImage(sk_sp<SkImage> image) = 0; 135 136 // Called when the resource is marked lost. Losing a resource does not mean 137 // that the backing memory has been destroyed, since the resource itself keeps 138 // a ref on that memory. 139 // It means that the consumer (commonly the compositor) can not provide a sync 140 // token for the resource to be safely recycled and its the GL state may be 141 // inconsistent with when the resource was given to the compositor. So it 142 // should not be recycled for writing again but can be safely read from. 143 virtual void NotifyResourceLost() = 0; 144 SetFilterQuality(SkFilterQuality filter)145 void SetFilterQuality(SkFilterQuality filter) { filter_quality_ = filter; } 146 // The filter quality to use when the resource is drawn by the compositor. FilterQuality()147 SkFilterQuality FilterQuality() const { return filter_quality_; } 148 149 SkImageInfo CreateSkImageInfo() const; 150 is_cross_thread()151 bool is_cross_thread() const { 152 return base::PlatformThread::CurrentRef() != owning_thread_ref_; 153 } 154 155 protected: 156 CanvasResource(base::WeakPtr<CanvasResourceProvider>, 157 SkFilterQuality, 158 const CanvasColorParams&); 159 160 // Called during resource destruction if the resource is destroyed on a thread 161 // other than where it was created. This implies that no context associated 162 // cleanup can be done and any resources tied to the context may be leaked. As 163 // such, a resource must be deleted on the owning thread and this should only 164 // be called when the owning thread and its associated context was torn down 165 // before this resource could be deleted. Abandon()166 virtual void Abandon() { TearDown(); } 167 168 // Returns true if the resource is backed by memory such that it can be used 169 // for direct scanout by the display. IsOverlayCandidate()170 virtual bool IsOverlayCandidate() const { return false; } 171 172 // Returns true if the resource is backed by memory that can be referenced 173 // using a mailbox. 174 virtual bool HasGpuMailbox() const = 0; 175 176 // Destroys the backing memory and any other references to it kept alive by 177 // this object. This must be called from the same thread where the resource 178 // was created. 179 virtual void TearDown() = 0; 180 181 gpu::InterfaceBase* InterfaceBase() const; 182 gpu::gles2::GLES2Interface* ContextGL() const; 183 gpu::raster::RasterInterface* RasterInterface() const; 184 GLenum GLFilter() const; 185 GrContext* GetGrContext() const; 186 virtual base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper()187 ContextProviderWrapper() const { 188 NOTREACHED(); 189 return nullptr; 190 } 191 bool PrepareAcceleratedTransferableResource( 192 viz::TransferableResource* out_resource, 193 MailboxSyncMode); 194 bool PrepareUnacceleratedTransferableResource( 195 viz::TransferableResource* out_resource); ColorParams()196 const CanvasColorParams& ColorParams() const { return color_params_; } 197 void OnDestroy(); Provider()198 CanvasResourceProvider* Provider() { return provider_.get(); } WeakProvider()199 base::WeakPtr<CanvasResourceProvider> WeakProvider() { return provider_; } 200 201 const base::PlatformThreadRef owning_thread_ref_; 202 const scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner_; 203 204 protected: 205 // Returns the texture target for the resource. TextureTarget()206 virtual GLenum TextureTarget() const { 207 NOTREACHED(); 208 return 0; 209 } 210 211 private: 212 // Sync token that was provided when resource was released 213 gpu::SyncToken sync_token_for_release_; 214 base::WeakPtr<CanvasResourceProvider> provider_; 215 SkFilterQuality filter_quality_; 216 CanvasColorParams color_params_; 217 #if DCHECK_IS_ON() 218 bool did_call_on_destroy_ = false; 219 #endif 220 }; 221 222 // Resource type for SharedBitmaps 223 class PLATFORM_EXPORT CanvasResourceSharedBitmap final : public CanvasResource { 224 public: 225 static scoped_refptr<CanvasResourceSharedBitmap> Create( 226 const IntSize&, 227 const CanvasColorParams&, 228 base::WeakPtr<CanvasResourceProvider>, 229 SkFilterQuality); 230 ~CanvasResourceSharedBitmap() override; IsRecycleable()231 bool IsRecycleable() const final { return IsValid(); } IsAccelerated()232 bool IsAccelerated() const final { return false; } 233 bool IsValid() const final; SupportsAcceleratedCompositing()234 bool SupportsAcceleratedCompositing() const final { return false; } NeedsReadLockFences()235 bool NeedsReadLockFences() const final { return false; } 236 void Abandon() final; 237 IntSize Size() const final; 238 void TakeSkImage(sk_sp<SkImage> image) final; 239 scoped_refptr<StaticBitmapImage> Bitmap() final; OriginClean()240 bool OriginClean() const final { return is_origin_clean_; } SetOriginClean(bool flag)241 void SetOriginClean(bool flag) final { is_origin_clean_ = flag; } 242 const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) override; 243 void NotifyResourceLost() override; 244 245 private: 246 void TearDown() override; 247 bool HasGpuMailbox() const override; 248 249 CanvasResourceSharedBitmap(const IntSize&, 250 const CanvasColorParams&, 251 base::WeakPtr<CanvasResourceProvider>, 252 SkFilterQuality); 253 254 viz::SharedBitmapId shared_bitmap_id_; 255 base::WritableSharedMemoryMapping shared_mapping_; 256 IntSize size_; 257 bool is_origin_clean_ = true; 258 }; 259 260 // Resource type for SharedImage 261 class PLATFORM_EXPORT CanvasResourceSharedImage final : public CanvasResource { 262 public: 263 static scoped_refptr<CanvasResourceSharedImage> Create( 264 const IntSize&, 265 base::WeakPtr<WebGraphicsContext3DProviderWrapper>, 266 base::WeakPtr<CanvasResourceProvider>, 267 SkFilterQuality, 268 const CanvasColorParams&, 269 bool is_origin_top_left, 270 bool is_accelerated, 271 uint32_t shared_image_usage_flags); 272 ~CanvasResourceSharedImage() override; 273 IsRecycleable()274 bool IsRecycleable() const final { return true; } IsAccelerated()275 bool IsAccelerated() const final { return is_accelerated_; } SupportsAcceleratedCompositing()276 bool SupportsAcceleratedCompositing() const override { return true; } 277 bool IsValid() const final; Size()278 IntSize Size() const final { return size_; } 279 scoped_refptr<StaticBitmapImage> Bitmap() final; 280 void Transfer() final; 281 OriginClean()282 bool OriginClean() const final { return is_origin_clean_; } SetOriginClean(bool value)283 void SetOriginClean(bool value) final { is_origin_clean_ = value; } TakeSkImage(sk_sp<SkImage> image)284 void TakeSkImage(sk_sp<SkImage> image) final { NOTREACHED(); } 285 void NotifyResourceLost() final; NeedsReadLockFences()286 bool NeedsReadLockFences() const final { 287 // If the resource is not accelerated, it will be written to on the CPU. We 288 // need read lock fences to ensure that all reads on the GPU are done when 289 // the resource is returned by the display compositor. 290 return !is_accelerated_; 291 } 292 GetTextureIdForReadAccess()293 GLuint GetTextureIdForReadAccess() const { 294 return owning_thread_data().texture_id_for_read_access; 295 } GetTextureIdForWriteAccess()296 GLuint GetTextureIdForWriteAccess() const { 297 return owning_thread_data().texture_id_for_write_access; 298 } TextureTarget()299 GLenum TextureTarget() const override { return texture_target_; } 300 301 void WillDraw(); has_read_access()302 bool has_read_access() const { 303 return owning_thread_data().bitmap_image_read_refs > 0u; 304 } is_lost()305 bool is_lost() const { return owning_thread_data().is_lost; } 306 void CopyRenderingResultsToGpuMemoryBuffer(const sk_sp<SkImage>& image); 307 const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) override; 308 309 private: 310 // These members are either only accessed on the owning thread, or are only 311 // updated on the owning thread and then are read on a different thread. 312 // We ensure to correctly update their state in Transfer, which is called 313 // before a resource is used on a different thread. 314 struct OwningThreadData { 315 bool mailbox_needs_new_sync_token = true; 316 gpu::Mailbox shared_image_mailbox; 317 gpu::SyncToken sync_token; 318 size_t bitmap_image_read_refs = 0u; 319 MailboxSyncMode mailbox_sync_mode = kVerifiedSyncToken; 320 bool is_lost = false; 321 322 // We need to create 2 representations if canvas is operating in single 323 // buffered mode to allow concurrent scopes for read and write access, 324 // because the Begin/EndSharedImageAccessDirectCHROMIUM APIs allow only one 325 // active access mode for a representation. 326 // In non single buffered mode, the 2 texture ids are the same. 327 GLuint texture_id_for_read_access = 0u; 328 GLuint texture_id_for_write_access = 0u; 329 }; 330 331 static void OnBitmapImageDestroyed( 332 scoped_refptr<CanvasResourceSharedImage> resource, 333 bool has_read_ref_on_texture, 334 const gpu::SyncToken& sync_token, 335 bool is_lost); 336 337 void TearDown() override; 338 void Abandon() override; 339 base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper() 340 const override; 341 bool HasGpuMailbox() const override; 342 const gpu::SyncToken GetSyncToken() override; IsOverlayCandidate()343 bool IsOverlayCandidate() const final { return is_overlay_candidate_; } 344 345 CanvasResourceSharedImage(const IntSize&, 346 base::WeakPtr<WebGraphicsContext3DProviderWrapper>, 347 base::WeakPtr<CanvasResourceProvider>, 348 SkFilterQuality, 349 const CanvasColorParams&, 350 bool is_origin_top_left, 351 bool is_accelerated, 352 uint32_t shared_image_usage_flags); 353 owning_thread_data()354 OwningThreadData& owning_thread_data() { 355 DCHECK(!is_cross_thread()); 356 return owning_thread_data_; 357 } owning_thread_data()358 const OwningThreadData& owning_thread_data() const { 359 DCHECK(!is_cross_thread()); 360 return owning_thread_data_; 361 } 362 363 // Can be read on any thread but updated only on the owning thread. mailbox()364 const gpu::Mailbox& mailbox() const { 365 return owning_thread_data_.shared_image_mailbox; 366 } mailbox_needs_new_sync_token()367 bool mailbox_needs_new_sync_token() const { 368 return owning_thread_data_.mailbox_needs_new_sync_token; 369 } sync_token()370 const gpu::SyncToken& sync_token() const { 371 return owning_thread_data_.sync_token; 372 } 373 374 // This should only be de-referenced on the owning thread but may be copied 375 // on a different thread. 376 base::WeakPtr<WebGraphicsContext3DProviderWrapper> context_provider_wrapper_; 377 378 // This can be accessed on any thread, irrespective of whether there are 379 // active readers or not. 380 bool is_origin_clean_ = true; 381 382 // GMB based software raster path. The resource is written to on the CPU but 383 // passed using the mailbox to the display compositor for use as an overlay. 384 std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer_; 385 386 // Accessed on any thread. 387 const IntSize size_; 388 const bool is_origin_top_left_; 389 const bool is_accelerated_; 390 const bool is_overlay_candidate_; 391 const GLenum texture_target_; 392 const bool use_oop_rasterization_; 393 394 OwningThreadData owning_thread_data_; 395 }; 396 397 // Resource type for a given opaque external resource described on construction 398 // via a Mailbox; this CanvasResource IsAccelerated() by definition. 399 class PLATFORM_EXPORT ExternalCanvasResource final : public CanvasResource { 400 public: 401 static scoped_refptr<ExternalCanvasResource> Create( 402 const gpu::Mailbox&, 403 const IntSize&, 404 GLenum texture_target, 405 const CanvasColorParams&, 406 base::WeakPtr<WebGraphicsContext3DProviderWrapper>, 407 base::WeakPtr<CanvasResourceProvider>, 408 SkFilterQuality, 409 bool is_origin_top_left); 410 ~ExternalCanvasResource() override; IsRecycleable()411 bool IsRecycleable() const final { return IsValid(); } IsAccelerated()412 bool IsAccelerated() const final { return true; } 413 bool IsValid() const override; SupportsAcceleratedCompositing()414 bool SupportsAcceleratedCompositing() const override { return true; } NeedsReadLockFences()415 bool NeedsReadLockFences() const final { return false; } OriginClean()416 bool OriginClean() const final { return is_origin_clean_; } SetOriginClean(bool value)417 void SetOriginClean(bool value) final { is_origin_clean_ = value; } 418 void Abandon() final; Size()419 IntSize Size() const final { return size_; } 420 void TakeSkImage(sk_sp<SkImage> image) final; NotifyResourceLost()421 void NotifyResourceLost() override { 422 // Used for single buffering mode which doesn't need to care about sync 423 // token synchronization. 424 } 425 426 scoped_refptr<StaticBitmapImage> Bitmap() override; 427 const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) override; 428 429 private: 430 void TearDown() override; TextureTarget()431 GLenum TextureTarget() const final { return texture_target_; } IsOverlayCandidate()432 bool IsOverlayCandidate() const final { return true; } 433 bool HasGpuMailbox() const override; 434 const gpu::SyncToken GetSyncToken() override; 435 base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper() 436 const override; 437 438 ExternalCanvasResource(const gpu::Mailbox&, 439 const IntSize&, 440 GLenum texture_target, 441 const CanvasColorParams&, 442 base::WeakPtr<WebGraphicsContext3DProviderWrapper>, 443 base::WeakPtr<CanvasResourceProvider>, 444 SkFilterQuality, 445 bool is_origin_top_left); 446 447 const base::WeakPtr<WebGraphicsContext3DProviderWrapper> 448 context_provider_wrapper_; 449 const IntSize size_; 450 const gpu::Mailbox mailbox_; 451 const GLenum texture_target_; 452 const bool is_origin_top_left_; 453 454 gpu::SyncToken sync_token_; 455 456 bool is_origin_clean_ = true; 457 }; 458 459 class PLATFORM_EXPORT CanvasResourceSwapChain final : public CanvasResource { 460 public: 461 static scoped_refptr<CanvasResourceSwapChain> Create( 462 const IntSize&, 463 const CanvasColorParams&, 464 base::WeakPtr<WebGraphicsContext3DProviderWrapper>, 465 base::WeakPtr<CanvasResourceProvider>, 466 SkFilterQuality); 467 ~CanvasResourceSwapChain() override; IsRecycleable()468 bool IsRecycleable() const final { return IsValid(); } IsAccelerated()469 bool IsAccelerated() const final { return true; } 470 bool IsValid() const override; SupportsAcceleratedCompositing()471 bool SupportsAcceleratedCompositing() const override { return true; } NeedsReadLockFences()472 bool NeedsReadLockFences() const final { return false; } OriginClean()473 bool OriginClean() const final { return is_origin_clean_; } SetOriginClean(bool value)474 void SetOriginClean(bool value) final { is_origin_clean_ = value; } 475 void Abandon() final; Size()476 IntSize Size() const final { return size_; } 477 void TakeSkImage(sk_sp<SkImage> image) final; NotifyResourceLost()478 void NotifyResourceLost() override { 479 // Used for single buffering mode which doesn't need to care about sync 480 // token synchronization. 481 } 482 483 scoped_refptr<StaticBitmapImage> Bitmap() override; 484 TextureTarget()485 GLenum TextureTarget() const final { return GL_TEXTURE_2D; } GetBackingTextureHandleForOverwrite()486 GLuint GetBackingTextureHandleForOverwrite() { 487 return back_buffer_texture_id_; 488 } 489 490 void PresentSwapChain(); 491 const gpu::Mailbox& GetOrCreateGpuMailbox(MailboxSyncMode) override; 492 493 private: 494 void TearDown() override; IsOverlayCandidate()495 bool IsOverlayCandidate() const final { return true; } 496 bool HasGpuMailbox() const override; 497 const gpu::SyncToken GetSyncToken() override; 498 base::WeakPtr<WebGraphicsContext3DProviderWrapper> ContextProviderWrapper() 499 const override; 500 501 CanvasResourceSwapChain(const IntSize&, 502 const CanvasColorParams&, 503 base::WeakPtr<WebGraphicsContext3DProviderWrapper>, 504 base::WeakPtr<CanvasResourceProvider>, 505 SkFilterQuality); 506 507 const base::WeakPtr<WebGraphicsContext3DProviderWrapper> 508 context_provider_wrapper_; 509 const IntSize size_; 510 gpu::Mailbox front_buffer_mailbox_; 511 gpu::Mailbox back_buffer_mailbox_; 512 GLuint front_buffer_texture_id_ = 0u; 513 GLuint back_buffer_texture_id_ = 0u; 514 gpu::SyncToken sync_token_; 515 516 bool is_origin_clean_ = true; 517 }; 518 519 } // namespace blink 520 521 #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_CANVAS_RESOURCE_H_ 522