| // Copyright 2013 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "cc/raster/zero_copy_raster_buffer_provider.h" | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include <algorithm> | 
 | #include <utility> | 
 |  | 
 | #include "base/feature_list.h" | 
 | #include "base/memory/raw_ptr.h" | 
 | #include "base/trace_event/process_memory_dump.h" | 
 | #include "base/trace_event/trace_event.h" | 
 | #include "base/trace_event/traced_value.h" | 
 | #include "cc/base/features.h" | 
 | #include "cc/resources/resource_pool.h" | 
 | #include "cc/trees/layer_tree_frame_sink.h" | 
 | #include "components/viz/client/client_resource_provider.h" | 
 | #include "components/viz/common/resources/platform_color.h" | 
 | #include "components/viz/common/resources/shared_image_format_utils.h" | 
 | #include "gpu/command_buffer/client/client_shared_image.h" | 
 | #include "gpu/command_buffer/client/shared_image_interface.h" | 
 | #include "gpu/command_buffer/common/shared_image_trace_utils.h" | 
 | #include "gpu/command_buffer/common/shared_image_usage.h" | 
 | #include "ui/gfx/buffer_format_util.h" | 
 | #include "url/gurl.h" | 
 |  | 
 | namespace cc { | 
 | namespace { | 
 |  | 
 | constexpr static auto kBufferUsage = gfx::BufferUsage::GPU_READ_CPU_READ_WRITE; | 
 |  | 
 | } | 
 |  | 
 | ZeroCopyRasterBufferImpl::ZeroCopyRasterBufferImpl( | 
 |     const ResourcePool::InUsePoolResource& in_use_resource, | 
 |     scoped_refptr<gpu::SharedImageInterface> sii, | 
 |     bool resource_has_previous_content, | 
 |     bool is_software) | 
 |     : sii_(sii), | 
 |       resource_has_previous_content_(resource_has_previous_content), | 
 |       is_software_(is_software) { | 
 |   if (!in_use_resource.backing()) { | 
 |     if (is_software) { | 
 |       in_use_resource.InstallSoftwareBacking( | 
 |           sii, "ZeroCopyRasterBufferProviderSoftware"); | 
 |       in_use_resource.backing()->mailbox_sync_token = | 
 |           sii->GenVerifiedSyncToken(); | 
 |     } else { | 
 |       auto backing = std::make_unique<ResourcePool::Backing>( | 
 |           in_use_resource.size(), in_use_resource.format(), | 
 |           in_use_resource.color_space()); | 
 |       // This RasterBufferProvider will modify the resource outside of the | 
 |       // GL command stream. So resources should not become available for reuse | 
 |       // until they are not in use by the gpu anymore, which a fence is used | 
 |       // to determine. | 
 |       backing->wait_on_fence_required = true; | 
 |       in_use_resource.set_backing(std::move(backing)); | 
 |     } | 
 |   } | 
 |   backing_ = in_use_resource.backing(); | 
 |   if (!backing_->shared_image()) { | 
 |     // The backing's SharedImage will be created on a worker thread during the | 
 |     // execution of this raster; to avoid data races during taking of memory | 
 |     // dumps on the compositor thread, mark the backing's SharedImage as | 
 |     // unavailable for access on the compositor thread for the duration of the | 
 |     // raster. | 
 |     backing_->can_access_shared_image_on_compositor_thread = false; | 
 |   } | 
 | } | 
 |  | 
 | ZeroCopyRasterBufferImpl::~ZeroCopyRasterBufferImpl() { | 
 |   // This raster task is complete, so if the backing's SharedImage was created | 
 |   // on a worker thread during the raster work that has now happened. | 
 |   backing_->can_access_shared_image_on_compositor_thread = true; | 
 |  | 
 |   // Drop the SharedImage if it was not possible to map it. | 
 |   if (failed_to_map_shared_image_) { | 
 |     backing_->shared_image()->UpdateDestructionSyncToken(gpu::SyncToken()); | 
 |     backing_->clear_shared_image(); | 
 |   } | 
 |  | 
 |   if (is_software_) { | 
 |     // The below work is specific to GPU compositing. | 
 |     return; | 
 |   } | 
 |  | 
 |   // If it was not possible to allocate the SharedImage | 
 |   // (https://crbug.com/554541) or it was not possible to map it, then we | 
 |   // don't have anything to give to the display compositor, so we report a | 
 |   // zero mailbox that will result in checkerboarding. | 
 |   if (!backing_->shared_image()) { | 
 |     return; | 
 |   } | 
 |  | 
 |   // This is destroyed on the compositor thread when raster is complete, but | 
 |   // before the backing is prepared for export to the display compositor. So | 
 |   // we can set up the texture and SyncToken here. | 
 |   // TODO(danakj): This could be done with the worker context in Playback. Do | 
 |   // we need to do things in IsResourceReadyToDraw() and OrderingBarrier then? | 
 |   sii_->UpdateSharedImage(backing_->returned_sync_token, | 
 |                           backing_->shared_image()->mailbox()); | 
 |  | 
 |   backing_->mailbox_sync_token = sii_->GenUnverifiedSyncToken(); | 
 | } | 
 |  | 
 | void ZeroCopyRasterBufferImpl::Playback( | 
 |     const RasterSource* raster_source, | 
 |     const gfx::Rect& raster_full_rect, | 
 |     const gfx::Rect& raster_dirty_rect, | 
 |     uint64_t new_content_id, | 
 |     const gfx::AxisTransform2d& transform, | 
 |     const RasterSource::PlaybackSettings& playback_settings, | 
 |     const GURL& url) { | 
 |   TRACE_EVENT0("cc", "ZeroCopyRasterBuffer::Playback"); | 
 |  | 
 |   gfx::Rect playback_rect = raster_full_rect; | 
 |   if (resource_has_previous_content_) { | 
 |     playback_rect.Intersect(raster_dirty_rect); | 
 |   } | 
 |   DCHECK(!playback_rect.IsEmpty()) | 
 |       << "Why are we rastering a tile that's not dirty?"; | 
 |  | 
 |   // Create a MappableSI if necessary. | 
 |   if (is_software_) { | 
 |     // WHen used with the software compositor, the SharedImage is created in the | 
 |     // constructor. | 
 |     CHECK(backing_->shared_image()); | 
 |   } else if (!backing_->shared_image()) { | 
 |     gpu::SharedImageUsageSet usage = | 
 |         gpu::SHARED_IMAGE_USAGE_DISPLAY_READ | gpu::SHARED_IMAGE_USAGE_SCANOUT; | 
 |     if (!backing_->CreateSharedImage(sii_.get(), usage, "ZeroCopyRasterTile", | 
 |                                      kBufferUsage)) { | 
 |       LOG(ERROR) << "Creation of MappableSharedImage failed."; | 
 |       return; | 
 |     } | 
 |   } | 
 |  | 
 |   std::unique_ptr<gpu::ClientSharedImage::ScopedMapping> mapping = | 
 |       backing_->shared_image()->Map(); | 
 |   if (!mapping) { | 
 |     LOG(ERROR) << "MapSharedImage Failed."; | 
 |  | 
 |     // NOTE: It is not safe to clear the SharedImage here as it might be being | 
 |     // read on the compositor thread as part of memory dump generation. | 
 |     // Instead, save the fact that mapping failed so that the SharedImage can | 
 |     // be cleared in the destructor of this object. | 
 |     failed_to_map_shared_image_ = true; | 
 |     return; | 
 |   } | 
 |  | 
 |   // TODO(danakj): Implement partial raster with raster_dirty_rect for GPU | 
 |   // compositing. | 
 |   RasterBufferProvider::PlaybackToMemory( | 
 |       mapping->GetMemoryForPlane(0).data(), backing_->format(), | 
 |       backing_->size(), mapping->Stride(0), raster_source, raster_full_rect, | 
 |       playback_rect, transform, backing_->color_space(), playback_settings); | 
 | } | 
 |  | 
 | bool ZeroCopyRasterBufferImpl::SupportsBackgroundThreadPriority() const { | 
 |   return true; | 
 | } | 
 |  | 
 | ZeroCopyRasterBufferProvider::ZeroCopyRasterBufferProvider( | 
 |     const scoped_refptr<gpu::SharedImageInterface>& shared_image_interface, | 
 |     bool is_software) | 
 |     : is_software_(is_software), | 
 |       shared_image_interface_(shared_image_interface) { | 
 |   CHECK(shared_image_interface_) | 
 |       << "SharedImageInterface is null in ZeroCopyRasterBufferProvider ctor!"; | 
 | } | 
 |  | 
 | ZeroCopyRasterBufferProvider::~ZeroCopyRasterBufferProvider() = default; | 
 |  | 
 | std::unique_ptr<RasterBuffer> | 
 | ZeroCopyRasterBufferProvider::AcquireBufferForRaster( | 
 |     const ResourcePool::InUsePoolResource& resource, | 
 |     uint64_t resource_content_id, | 
 |     uint64_t previous_content_id, | 
 |     bool depends_on_at_raster_decodes, | 
 |     bool depends_on_hardware_accelerated_jpeg_candidates, | 
 |     bool depends_on_hardware_accelerated_webp_candidates) { | 
 |   bool resource_has_previous_content = | 
 |       resource_content_id && resource_content_id == previous_content_id; | 
 |  | 
 |   return std::make_unique<ZeroCopyRasterBufferImpl>( | 
 |       resource, shared_image_interface_, resource_has_previous_content, | 
 |       is_software_); | 
 | } | 
 |  | 
 | void ZeroCopyRasterBufferProvider::Flush() {} | 
 |  | 
 | bool ZeroCopyRasterBufferProvider::CanPartialRasterIntoProvidedResource() | 
 |     const { | 
 |   return true; | 
 | } | 
 |  | 
 | bool ZeroCopyRasterBufferProvider::IsResourceReadyToDraw( | 
 |     const ResourcePool::InUsePoolResource& resource) { | 
 |   // Zero-copy resources are immediately ready to draw. | 
 |   return true; | 
 | } | 
 |  | 
 | uint64_t ZeroCopyRasterBufferProvider::SetReadyToDrawCallback( | 
 |     const std::vector<const ResourcePool::InUsePoolResource*>& resources, | 
 |     base::OnceClosure callback, | 
 |     uint64_t pending_callback_id) { | 
 |   // Zero-copy resources are immediately ready to draw. | 
 |   return 0; | 
 | } | 
 |  | 
 | void ZeroCopyRasterBufferProvider::Shutdown() {} | 
 |  | 
 | }  // namespace cc |