| // 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 "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 |