| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "gpu/command_buffer/service/shared_image_interface_in_process.h" |
| |
| #include <optional> |
| |
| #include "base/functional/bind.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "build/build_config.h" |
| #include "components/viz/common/resources/shared_image_format_utils.h" |
| #include "gpu/command_buffer/client/client_shared_image.h" |
| #include "gpu/command_buffer/common/shared_image_usage.h" |
| #include "gpu/command_buffer/common/sync_token.h" |
| #include "gpu/command_buffer/service/command_buffer_task_executor.h" |
| #include "gpu/command_buffer/service/display_compositor_memory_and_task_controller_on_gpu.h" |
| #include "gpu/command_buffer/service/gr_shader_cache.h" |
| #include "gpu/command_buffer/service/shared_image/shared_image_factory.h" |
| #include "gpu/command_buffer/service/shared_image_interface_in_process_base.h" |
| #include "gpu/command_buffer/service/single_task_sequence.h" |
| #include "gpu/config/gpu_driver_bug_workarounds.h" |
| #include "gpu/config/gpu_feature_info.h" |
| #include "gpu/config/gpu_preferences.h" |
| #include "gpu/ipc/common/gpu_client_ids.h" |
| #include "third_party/abseil-cpp/absl/cleanup/cleanup.h" |
| #include "ui/gfx/gpu_fence.h" |
| #include "ui/gl/gl_context.h" |
| #include "ui/gl/gl_implementation.h" |
| |
| namespace gpu { |
| |
| struct SharedImageInterfaceInProcess::SetUpOnGpuParams { |
| const GpuPreferences gpu_preferences; |
| const GpuDriverBugWorkarounds gpu_workarounds; |
| const GpuFeatureInfo gpu_feature_info; |
| const raw_ptr<gpu::SharedContextState> context_state; |
| const raw_ptr<SharedImageManager> shared_image_manager; |
| const bool is_for_display_compositor; |
| |
| SetUpOnGpuParams(const GpuPreferences& gpu_preferences, |
| const GpuDriverBugWorkarounds& gpu_workarounds, |
| const GpuFeatureInfo& gpu_feature_info, |
| gpu::SharedContextState* context_state, |
| SharedImageManager* shared_image_manager, |
| bool is_for_display_compositor) |
| : gpu_preferences(gpu_preferences), |
| gpu_workarounds(gpu_workarounds), |
| gpu_feature_info(gpu_feature_info), |
| context_state(context_state), |
| shared_image_manager(shared_image_manager), |
| is_for_display_compositor(is_for_display_compositor) {} |
| |
| ~SetUpOnGpuParams() = default; |
| |
| SetUpOnGpuParams(const SetUpOnGpuParams& other) = delete; |
| SetUpOnGpuParams& operator=(const SetUpOnGpuParams& other) = delete; |
| }; |
| |
| scoped_refptr<SharedImageInterfaceInProcess> |
| SharedImageInterfaceInProcess::Create( |
| SingleTaskSequence* task_sequence, |
| const GpuPreferences& gpu_preferences, |
| const GpuDriverBugWorkarounds& gpu_workarounds, |
| const GpuFeatureInfo& gpu_feature_info, |
| gpu::SharedContextState* context_state, |
| SharedImageManager* shared_image_manager, |
| bool is_for_display_compositor, |
| scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner) { |
| // ensure Initialize() is called before pointer returned to caller |
| auto sii = base::WrapRefCounted(new SharedImageInterfaceInProcess{ |
| task_sequence, shared_image_manager, std::move(gpu_task_runner)}); |
| sii->Initialize(std::make_unique<SetUpOnGpuParams>( |
| gpu_preferences, gpu_workarounds, gpu_feature_info, context_state, |
| shared_image_manager, is_for_display_compositor)); |
| return sii; |
| } |
| |
| SharedImageInterfaceInProcess::SharedImageInterfaceInProcess( |
| SingleTaskSequence* task_sequence, |
| SharedImageManager* shared_image_manager, |
| scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner) |
| : SharedImageInterfaceInProcessBase( |
| CommandBufferNamespace::IN_PROCESS, |
| DisplayCompositorMemoryAndTaskControllerOnGpu::NextCommandBufferId(), |
| /*verify_creation_sync_token=*/false), |
| task_sequence_(task_sequence), |
| gpu_task_runner_(std::move(gpu_task_runner)), |
| shared_image_manager_(shared_image_manager) {} |
| |
| void SharedImageInterfaceInProcess::Initialize( |
| std::unique_ptr<SetUpOnGpuParams> params) { |
| if (gpu_task_runner_->BelongsToCurrentThread()) { |
| SetUpOnGpu(std::move(params)); |
| } else { |
| // Can't safely be called in constructor, because receiver must be |
| // retained, but constructor has zero ref-count |
| task_sequence_->ScheduleTask( |
| base::BindOnce(&SharedImageInterfaceInProcess::SetUpOnGpu, this, |
| std::move(params)), |
| /*sync_token_fences=*/{}, SyncToken()); |
| } |
| } |
| |
| SharedImageInterfaceInProcess::~SharedImageInterfaceInProcess() { |
| base::WaitableEvent completion( |
| base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| |
| if (gpu_task_runner_->BelongsToCurrentThread()) { |
| DestroyOnGpu(&completion); |
| } else { |
| // Unretained because called in destructor, where ref-count is always zero; |
| // safe because destructor is blocked on `completion` until async task runs |
| task_sequence_->ScheduleTask( |
| base::BindOnce(&SharedImageInterfaceInProcess::DestroyOnGpu, |
| base::Unretained(this), &completion), |
| /*sync_token_fences=*/{}, SyncToken()); |
| } |
| |
| completion.Wait(); |
| } |
| |
| const SharedImageCapabilities& |
| SharedImageInterfaceInProcess::GetCapabilities() { |
| base::WaitableEvent completion( |
| base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| |
| if (!shared_image_capabilities_) { |
| shared_image_capabilities_ = std::make_unique<SharedImageCapabilities>(); |
| task_sequence_->ScheduleTask( |
| base::BindOnce(&SharedImageInterfaceInProcess::GetCapabilitiesOnGpu, |
| this, &completion, shared_image_capabilities_.get()), |
| /*sync_token_fences=*/{}, SyncToken()); |
| completion.Wait(); |
| } |
| return *shared_image_capabilities_; |
| } |
| |
| void SharedImageInterfaceInProcess::GetCapabilitiesOnGpu( |
| base::WaitableEvent* completion, |
| SharedImageCapabilities* out_capabilities) { |
| if (!GetSharedImageFactory()) { |
| return; |
| } |
| |
| DCHECK(shared_image_factory_); |
| *out_capabilities = shared_image_factory_->MakeCapabilities(); |
| completion->Signal(); |
| } |
| |
| void SharedImageInterfaceInProcess::SetUpOnGpu( |
| std::unique_ptr<SetUpOnGpuParams> params) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_); |
| context_state_ = params->context_state.get(); |
| |
| create_factory_ = base::BindOnce( |
| [](std::unique_ptr<SetUpOnGpuParams> params) { |
| auto* memory_tracker = params->context_state |
| ? params->context_state->memory_tracker() |
| : nullptr; |
| auto shared_image_factory = std::make_unique<SharedImageFactory>( |
| params->gpu_preferences, params->gpu_workarounds, |
| params->gpu_feature_info, params->context_state, |
| params->shared_image_manager, memory_tracker, |
| params->is_for_display_compositor); |
| return shared_image_factory; |
| }, |
| std::move(params)); |
| |
| // Make the SharedImageInterface use the same sequence as the command buffer, |
| // it's necessary for WebView because of the blocking behavior. |
| // TODO(piman): see if it's worth using a different sequence for non-WebView. |
| sync_point_client_state_ = task_sequence_->CreateSyncPointClientState( |
| CommandBufferNamespace::IN_PROCESS, command_buffer_id()); |
| } |
| |
| void SharedImageInterfaceInProcess::DestroyOnGpu( |
| base::WaitableEvent* completion) { |
| bool have_context = MakeContextCurrent(); |
| if (shared_image_factory_) { |
| shared_image_factory_->DestroyAllSharedImages(have_context); |
| shared_image_factory_ = nullptr; |
| } |
| |
| sync_point_client_state_.Reset(); |
| |
| context_state_ = nullptr; |
| completion->Signal(); |
| } |
| |
| SharedImageFactory* SharedImageInterfaceInProcess::GetSharedImageFactory() { |
| if (shared_image_factory_) { |
| return shared_image_factory_.get(); |
| } |
| |
| // Some shared image backing factories will use GL in ctor, so we need GL even |
| // if chrome is using non-GL backing. |
| if (!MakeContextCurrent(/*needs_gl=*/true)) { |
| return nullptr; |
| } |
| |
| shared_image_factory_ = std::move(create_factory_).Run(); |
| return shared_image_factory_.get(); |
| } |
| |
| bool SharedImageInterfaceInProcess::MakeContextCurrent(bool needs_gl) { |
| if (gl::GetGLImplementation() == gl::kGLImplementationDisabled) { |
| return true; |
| } |
| |
| if (!context_state_) |
| return false; |
| |
| if (context_state_->context_lost()) |
| return false; |
| |
| // |shared_image_factory_| never writes to the surface, so skip unnecessary |
| // MakeCurrent to improve performance. https://crbug.com/457431 |
| auto* context = context_state_->real_context(); |
| if (context->IsCurrent(nullptr)) |
| return !context_state_->CheckResetStatus(needs_gl); |
| return context_state_->MakeCurrent(/*surface=*/nullptr, needs_gl); |
| } |
| |
| void SharedImageInterfaceInProcess::MarkContextLost() { |
| context_state_->MarkContextLost(); |
| } |
| |
| void SharedImageInterfaceInProcess::ScheduleGpuTask( |
| base::OnceClosure task, |
| std::vector<SyncToken> sync_token_fences, |
| const SyncToken& release) { |
| task_sequence_->ScheduleTask(std::move(task), std::move(sync_token_fences), |
| release); |
| } |
| |
| } // namespace gpu |