12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "gpu/ipc/in_process_command_buffer.h"
- #include <stddef.h>
- #include <stdint.h>
- #include <set>
- #include <utility>
- #include "base/atomic_sequence_num.h"
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/command_line.h"
- #include "base/location.h"
- #include "base/logging.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/weak_ptr.h"
- #include "base/numerics/safe_conversions.h"
- #include "base/sequence_checker.h"
- #include "base/synchronization/waitable_event.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/threading/thread.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "base/trace_event/memory_dump_manager.h"
- #include "base/trace_event/trace_event.h"
- #include "cc/base/completion_event.h"
- #include "components/viz/common/features.h"
- #include "gpu/command_buffer/client/gpu_control_client.h"
- #include "gpu/command_buffer/client/shared_image_interface.h"
- #include "gpu/command_buffer/common/sync_token.h"
- #include "gpu/command_buffer/service/command_buffer_service.h"
- #include "gpu/command_buffer/service/command_buffer_task_executor.h"
- #include "gpu/command_buffer/service/context_group.h"
- #include "gpu/command_buffer/service/gl_context_virtual.h"
- #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
- #include "gpu/command_buffer/service/gpu_command_buffer_memory_tracker.h"
- #include "gpu/command_buffer/service/gpu_fence_manager.h"
- #include "gpu/command_buffer/service/gpu_tracer.h"
- #include "gpu/command_buffer/service/gr_shader_cache.h"
- #include "gpu/command_buffer/service/image_factory.h"
- #include "gpu/command_buffer/service/mailbox_manager_factory.h"
- #include "gpu/command_buffer/service/memory_program_cache.h"
- #include "gpu/command_buffer/service/memory_tracking.h"
- #include "gpu/command_buffer/service/query_manager.h"
- #include "gpu/command_buffer/service/raster_decoder.h"
- #include "gpu/command_buffer/service/scheduler.h"
- #include "gpu/command_buffer/service/service_utils.h"
- #include "gpu/command_buffer/service/shared_context_state.h"
- #include "gpu/command_buffer/service/shared_image_interface_in_process.h"
- #include "gpu/command_buffer/service/single_task_sequence.h"
- #include "gpu/command_buffer/service/sync_point_manager.h"
- #include "gpu/command_buffer/service/webgpu_decoder.h"
- #include "gpu/config/gpu_feature_info.h"
- #include "gpu/config/gpu_preferences.h"
- #include "gpu/config/gpu_switches.h"
- #include "gpu/ipc/common/gpu_client_ids.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/gpu_fence.h"
- #include "ui/gfx/gpu_fence_handle.h"
- #include "ui/gl/gl_bindings.h"
- #include "ui/gl/gl_context.h"
- #include "ui/gl/gl_share_group.h"
- #include "ui/gl/gl_surface_egl.h"
- #include "ui/gl/gl_utils.h"
- #include "ui/gl/gl_version_info.h"
- #include "ui/gl/init/create_gr_gl_interface.h"
- #include "ui/gl/init/gl_factory.h"
- namespace gpu {
- namespace {
- template <typename T>
- base::OnceClosure WrapTaskWithResult(base::OnceCallback<T(void)> task,
- T* result,
- base::WaitableEvent* completion) {
- auto wrapper = [](base::OnceCallback<T(void)> task, T* result,
- base::WaitableEvent* completion) {
- *result = std::move(task).Run();
- completion->Signal();
- };
- return base::BindOnce(wrapper, std::move(task), result, completion);
- }
- class ScopedEvent {
- public:
- explicit ScopedEvent(base::WaitableEvent* event) : event_(event) {}
- ~ScopedEvent() { event_->Signal(); }
- private:
- raw_ptr<base::WaitableEvent> event_;
- };
- } // namespace
- void InProcessCommandBuffer::SetError() {
- // Signal errors by losing the command buffer.
- command_buffer_->SetParseError(error::kLostContext);
- }
- void InProcessCommandBuffer::WrapTaskWithGpuCheck(base::OnceClosure task) {
- RunTaskOnGpuThread(std::move(task));
- }
- InProcessCommandBuffer::InProcessCommandBuffer(
- CommandBufferTaskExecutor* task_executor,
- const GURL& active_url)
- : active_url_(active_url),
- flush_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- task_executor_(task_executor),
- fence_sync_wait_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
- base::WaitableEvent::InitialState::NOT_SIGNALED) {
- // This binds the client sequence checker to the current sequence.
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- // Detach gpu sequence checker because we want to bind it to the gpu sequence,
- // and not the current (client) sequence except for webview (see Initialize).
- DETACH_FROM_SEQUENCE(gpu_sequence_checker_);
- DCHECK(task_executor_);
- }
- InProcessCommandBuffer::~InProcessCommandBuffer() {
- Destroy();
- }
- gpu::ServiceTransferCache* InProcessCommandBuffer::GetTransferCacheForTest()
- const {
- return static_cast<raster::RasterDecoder*>(decoder_.get())
- ->GetTransferCacheForTest();
- }
- int InProcessCommandBuffer::GetRasterDecoderIdForTest() const {
- return static_cast<raster::RasterDecoder*>(decoder_.get())
- ->DecoderIdForTest();
- }
- webgpu::WebGPUDecoder* InProcessCommandBuffer::GetWebGPUDecoderForTest() const {
- return static_cast<webgpu::WebGPUDecoder*>(decoder_.get());
- }
- gpu::SharedImageInterface* InProcessCommandBuffer::GetSharedImageInterface()
- const {
- return shared_image_interface_.get();
- }
- bool InProcessCommandBuffer::MakeCurrent() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- if (!context_) {
- return true;
- }
- if (error::IsError(command_buffer_->GetState().error)) {
- DLOG(ERROR) << "MakeCurrent failed because context lost.";
- return false;
- }
- if (!decoder_->MakeCurrent()) {
- DLOG(ERROR) << "Context lost because MakeCurrent failed.";
- command_buffer_->SetParseError(error::kLostContext);
- return false;
- }
- return true;
- }
- absl::optional<gles2::ProgramCache::ScopedCacheUse>
- InProcessCommandBuffer::CreateCacheUse() {
- absl::optional<gles2::ProgramCache::ScopedCacheUse> cache_use;
- if (context_group_->has_program_cache()) {
- cache_use.emplace(
- context_group_->get_program_cache(),
- base::BindRepeating(&DecoderClient::CacheBlob, base::Unretained(this),
- gpu::GpuDiskCacheType::kGlShaders));
- }
- return cache_use;
- }
- gpu::ContextResult InProcessCommandBuffer::Initialize(
- const ContextCreationAttribs& attribs,
- ImageFactory* image_factory,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner,
- gpu::raster::GrShaderCache* gr_shader_cache,
- GpuProcessActivityFlags* activity_flags) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- TRACE_EVENT0("gpu", "InProcessCommandBuffer::Initialize");
- DCHECK(task_runner);
- origin_task_runner_ = std::move(task_runner);
- client_thread_weak_ptr_ = client_thread_weak_ptr_factory_.GetWeakPtr();
- Capabilities capabilities;
- InitializeOnGpuThreadParams params(attribs, &capabilities, image_factory,
- gr_shader_cache, activity_flags);
- base::OnceCallback<gpu::ContextResult(void)> init_task =
- base::BindOnce(&InProcessCommandBuffer::InitializeOnGpuThread,
- base::Unretained(this), params);
- task_scheduler_holder_ =
- std::make_unique<gpu::GpuTaskSchedulerHelper>(task_executor_);
- task_sequence_ = task_scheduler_holder_->GetTaskSequence();
- // Here we block by using a WaitableEvent to make sure InitializeOnGpuThread
- // is finished as part of Initialize function. This also makes sure we won't
- // try to cache GLSurface before the creation is finished.
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- gpu::ContextResult result = gpu::ContextResult::kSuccess;
- task_sequence_->ScheduleTask(
- WrapTaskWithResult(std::move(init_task), &result, &completion), {});
- completion.Wait();
- if (result == gpu::ContextResult::kSuccess) {
- capabilities_ = capabilities;
- shared_image_interface_ = std::make_unique<SharedImageInterfaceInProcess>(
- task_sequence_, gpu_dependency_.get(), this);
- }
- return result;
- }
- gpu::ContextResult InProcessCommandBuffer::InitializeOnGpuThread(
- const InitializeOnGpuThreadParams& params) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- TRACE_EVENT0("gpu", "InProcessCommandBuffer::InitializeOnGpuThread");
- UpdateActiveUrl();
- gpu_dependency_ =
- std::make_unique<DisplayCompositorMemoryAndTaskControllerOnGpu>(
- task_executor_, params.image_factory);
- GpuDriverBugWorkarounds workarounds(
- task_executor_->gpu_feature_info().enabled_gpu_driver_bug_workarounds);
- std::unique_ptr<MemoryTracker> memory_tracker;
- // Android WebView won't have a memory tracker.
- if (task_executor_->ShouldCreateMemoryTracker()) {
- const uint64_t client_tracing_id =
- base::trace_event::MemoryDumpManager::GetInstance()
- ->GetTracingProcessId();
- memory_tracker = std::make_unique<GpuCommandBufferMemoryTracker>(
- gpu_dependency_->command_buffer_id(), client_tracing_id,
- base::ThreadTaskRunnerHandle::Get(), /* obserer=*/nullptr);
- }
- auto feature_info = base::MakeRefCounted<gles2::FeatureInfo>(
- workarounds, task_executor_->gpu_feature_info());
- context_group_ = base::MakeRefCounted<gles2::ContextGroup>(
- task_executor_->gpu_preferences(),
- gles2::PassthroughCommandDecoderSupported(),
- task_executor_->mailbox_manager(), std::move(memory_tracker),
- task_executor_->shader_translator_cache(),
- task_executor_->framebuffer_completeness_cache(), feature_info,
- params.attribs.bind_generates_resource, params.image_factory,
- nullptr /* progress_reporter */, task_executor_->gpu_feature_info(),
- task_executor_->discardable_manager(),
- task_executor_->passthrough_discardable_manager(),
- task_executor_->shared_image_manager());
- #if BUILDFLAG(IS_MAC)
- // Virtualize GpuPreference:::kLowPower contexts by default on OS X to prevent
- // performance regressions when enabling FCM. https://crbug.com/180463
- use_virtualized_gl_context_ |=
- (params.attribs.gpu_preference == gl::GpuPreference::kLowPower);
- #endif
- use_virtualized_gl_context_ |= task_executor_->ForceVirtualizedGLContexts();
- use_virtualized_gl_context_ |=
- context_group_->feature_info()->workarounds().use_virtualized_gl_contexts;
- if (context_group_->use_passthrough_cmd_decoder()) {
- // Virtualized contexts don't work with passthrough command decoder.
- // See https://crbug.com/914976
- use_virtualized_gl_context_ = false;
- }
- command_buffer_ = std::make_unique<CommandBufferService>(
- this, gpu_dependency_->memory_tracker());
- context_state_ = task_executor_->GetSharedContextState();
- if (context_state_) {
- surface_ = context_state_->surface();
- } else {
- // TODO(crbug.com/1247756): Is creating an offscreen GL surface needed
- // still?
- surface_ = gl::init::CreateOffscreenGLSurface(gl::GetDefaultDisplay(),
- gfx::Size());
- if (!surface_.get()) {
- DestroyOnGpuThread();
- LOG(ERROR) << "ContextResult::kFatalFailure: Failed to create surface.";
- return gpu::ContextResult::kFatalFailure;
- }
- }
- sync_point_client_state_ =
- task_executor_->sync_point_manager()->CreateSyncPointClientState(
- GetNamespaceID(), GetCommandBufferID(),
- task_sequence_->GetSequenceId());
- if (context_group_->use_passthrough_cmd_decoder()) {
- // When using the passthrough command decoder, never share with other
- // contexts.
- gl_share_group_ = base::MakeRefCounted<gl::GLShareGroup>();
- } else {
- // When using the validating command decoder, always use the global share
- // group.
- gl_share_group_ = task_executor_->GetShareGroup();
- }
- if (params.attribs.context_type == CONTEXT_TYPE_WEBGPU) {
- if (!task_executor_->gpu_preferences().enable_webgpu) {
- DLOG(ERROR) << "ContextResult::kFatalFailure: WebGPU not enabled";
- return gpu::ContextResult::kFatalFailure;
- }
- std::unique_ptr<webgpu::WebGPUDecoder> webgpu_decoder(
- webgpu::WebGPUDecoder::Create(
- this, command_buffer_.get(), task_executor_->shared_image_manager(),
- gpu_dependency_->memory_tracker(), task_executor_->outputter(),
- task_executor_->gpu_preferences(), context_state_));
- gpu::ContextResult result =
- webgpu_decoder->Initialize(task_executor_->gpu_feature_info());
- if (result != gpu::ContextResult::kSuccess) {
- DestroyOnGpuThread();
- DLOG(ERROR) << "Failed to initialize WebGPU decoder.";
- return result;
- }
- decoder_ = std::move(webgpu_decoder);
- } else {
- // TODO(khushalsagar): A lot of this initialization code is duplicated in
- // GpuChannelManager. Pull it into a common util method.
- scoped_refptr<gl::GLContext> real_context =
- use_virtualized_gl_context_ ? gl_share_group_->shared_context()
- : nullptr;
- if (real_context &&
- (!real_context->MakeCurrent(surface_.get()) ||
- real_context->CheckStickyGraphicsResetStatus() != GL_NO_ERROR)) {
- real_context = nullptr;
- }
- if (!real_context) {
- real_context = gl::init::CreateGLContext(
- gl_share_group_.get(), surface_.get(),
- GenerateGLContextAttribs(params.attribs, context_group_.get()));
- if (!real_context) {
- // TODO(piman): This might not be fatal, we could recurse into
- // CreateGLContext to get more info, tho it should be exceedingly
- // rare and may not be recoverable anyway.
- DestroyOnGpuThread();
- LOG(ERROR) << "ContextResult::kFatalFailure: "
- "Failed to create shared context for virtualization.";
- return gpu::ContextResult::kFatalFailure;
- }
- // Ensure that context creation did not lose track of the intended share
- // group.
- DCHECK(real_context->share_group() == gl_share_group_.get());
- task_executor_->gpu_feature_info().ApplyToGLContext(real_context.get());
- if (use_virtualized_gl_context_)
- gl_share_group_->SetSharedContext(real_context.get());
- }
- if (!real_context->MakeCurrent(surface_.get())) {
- LOG(ERROR)
- << "ContextResult::kTransientFailure, failed to make context current";
- DestroyOnGpuThread();
- return ContextResult::kTransientFailure;
- }
- if (params.attribs.enable_raster_interface &&
- !params.attribs.enable_gles2_interface) {
- gr_shader_cache_ = params.gr_shader_cache;
- if (!context_state_ ||
- !context_state_->MakeCurrent(nullptr, /*needs_gl=*/true)) {
- DestroyOnGpuThread();
- LOG(ERROR) << "Failed to make context current.";
- return ContextResult::kTransientFailure;
- }
- // TODO(penghuang): Merge all SharedContextState::Initialize*()
- if (!context_state_->IsGLInitialized()) {
- context_state_->InitializeGL(task_executor_->gpu_preferences(),
- context_group_->feature_info());
- }
- context_ = context_state_->context();
- decoder_.reset(raster::RasterDecoder::Create(
- this, command_buffer_.get(), task_executor_->outputter(),
- task_executor_->gpu_feature_info(), task_executor_->gpu_preferences(),
- gpu_dependency_->memory_tracker(),
- task_executor_->shared_image_manager(), params.image_factory,
- context_state_, true /*is_privileged*/));
- } else {
- decoder_.reset(gles2::GLES2Decoder::Create(this, command_buffer_.get(),
- task_executor_->outputter(),
- context_group_.get()));
- if (use_virtualized_gl_context_) {
- context_ = base::MakeRefCounted<GLContextVirtual>(
- gl_share_group_.get(), real_context.get(), decoder_->AsWeakPtr());
- if (!context_->Initialize(surface_.get(),
- GenerateGLContextAttribs(
- params.attribs, context_group_.get()))) {
- // TODO(piman): This might not be fatal, we could recurse into
- // CreateGLContext to get more info, tho it should be exceedingly
- // rare and may not be recoverable anyway.
- DestroyOnGpuThread();
- LOG(ERROR) << "ContextResult::kFatalFailure: "
- "Failed to initialize virtual GL context.";
- return gpu::ContextResult::kFatalFailure;
- }
- if (!context_->MakeCurrent(surface_.get())) {
- DestroyOnGpuThread();
- // The caller should retry making a context, but this one won't work.
- LOG(ERROR) << "ContextResult::kTransientFailure: "
- "Could not make context current.";
- return gpu::ContextResult::kTransientFailure;
- }
- } else {
- context_ = real_context;
- DCHECK(context_->IsCurrent(surface_.get()));
- }
- }
- if (!context_group_->has_program_cache() &&
- !context_group_->feature_info()->workarounds().disable_program_cache) {
- context_group_->set_program_cache(task_executor_->program_cache());
- }
- }
- gles2::DisallowedFeatures disallowed_features;
- auto result = decoder_->Initialize(surface_, context_, /*offscreen=*/true,
- disallowed_features, params.attribs);
- if (result != gpu::ContextResult::kSuccess) {
- DestroyOnGpuThread();
- DLOG(ERROR) << "Failed to initialize decoder.";
- return result;
- }
- if (task_executor_->gpu_preferences().enable_gpu_service_logging)
- decoder_->SetLogCommands(true);
- if (context_ && use_virtualized_gl_context_) {
- // If virtualized GL contexts are in use, then real GL context state
- // is in an indeterminate state, since the GLStateRestorer was not
- // initialized at the time the GLContextVirtual was made current. In
- // the case that this command decoder is the next one to be
- // processed, force a "full virtual" MakeCurrent to be performed.
- context_->ForceReleaseVirtuallyCurrent();
- if (!context_->MakeCurrent(surface_.get())) {
- DestroyOnGpuThread();
- LOG(ERROR) << "ContextResult::kTransientFailure: "
- "Failed to make context current after initialization.";
- return gpu::ContextResult::kTransientFailure;
- }
- }
- *params.capabilities = decoder_->GetCapabilities();
- return gpu::ContextResult::kSuccess;
- }
- void InProcessCommandBuffer::Destroy() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- TRACE_EVENT0("gpu", "InProcessCommandBuffer::Destroy");
- client_thread_weak_ptr_factory_.InvalidateWeakPtrs();
- gpu_control_client_ = nullptr;
- shared_image_interface_ = nullptr;
- // Here we block by using a WaitableEvent to make sure DestroyOnGpuThread is
- // finished as part of Destroy.
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- bool result = false;
- base::OnceCallback<bool(void)> destroy_task = base::BindOnce(
- &InProcessCommandBuffer::DestroyOnGpuThread, base::Unretained(this));
- task_sequence_->ScheduleTask(
- WrapTaskWithResult(std::move(destroy_task), &result, &completion), {});
- completion.Wait();
- task_sequence_ = nullptr;
- }
- bool InProcessCommandBuffer::DestroyOnGpuThread() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- TRACE_EVENT0("gpu", "InProcessCommandBuffer::DestroyOnGpuThread");
- UpdateActiveUrl();
- gpu_thread_weak_ptr_factory_.InvalidateWeakPtrs();
- // Clean up GL resources if possible.
- bool have_context = context_.get() && context_->MakeCurrent(surface_.get());
- absl::optional<gles2::ProgramCache::ScopedCacheUse> cache_use;
- if (have_context)
- cache_use = CreateCacheUse();
- // Prepare to destroy the surface while the context is still current, because
- // some surface destructors make GL calls.
- if (surface_)
- surface_->PrepareToDestroy(have_context);
- if (decoder_) {
- decoder_->Destroy(have_context);
- decoder_.reset();
- }
- command_buffer_.reset();
- surface_ = nullptr;
- context_ = nullptr;
- if (sync_point_client_state_) {
- sync_point_client_state_->Destroy();
- sync_point_client_state_ = nullptr;
- }
- gl_share_group_ = nullptr;
- context_group_ = nullptr;
- if (context_state_)
- context_state_->MakeCurrent(nullptr);
- context_state_ = nullptr;
- gpu_dependency_.reset();
- return true;
- }
- CommandBufferServiceClient::CommandBatchProcessedResult
- InProcessCommandBuffer::OnCommandBatchProcessed() {
- return task_sequence_->ShouldYield() ? kPauseExecution : kContinueExecution;
- }
- void InProcessCommandBuffer::OnParseError() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- // There is a race between service side FlushOnGpuThread() calling
- // UpdateLastStateOnGpuThread() and client side calling GetLastState().
- // Update last_state_ now before notifying client side to save the
- // error and make the race benign.
- UpdateLastStateOnGpuThread();
- PostOrRunClientCallback(base::BindOnce(&InProcessCommandBuffer::OnContextLost,
- client_thread_weak_ptr_));
- }
- void InProcessCommandBuffer::OnContextLost() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- #if DCHECK_IS_ON()
- // This method shouldn't be called more than once.
- DCHECK(!context_lost_);
- context_lost_ = true;
- #endif
- if (gpu_control_client_)
- gpu_control_client_->OnGpuControlLostContext();
- }
- void InProcessCommandBuffer::RunTaskOnGpuThread(base::OnceClosure task) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- UpdateActiveUrl();
- std::move(task).Run();
- }
- void InProcessCommandBuffer::ScheduleGpuTask(
- base::OnceClosure task,
- std::vector<SyncToken> sync_token_fences,
- SingleTaskSequence::ReportingCallback report_callback) {
- base::OnceClosure gpu_task = base::BindOnce(
- &InProcessCommandBuffer::RunTaskOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), std::move(task));
- task_sequence_->ScheduleTask(std::move(gpu_task),
- std::move(sync_token_fences),
- std::move(report_callback));
- }
- void InProcessCommandBuffer::ContinueGpuTask(base::OnceClosure task) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- base::OnceClosure gpu_task = base::BindOnce(
- &InProcessCommandBuffer::RunTaskOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), std::move(task));
- task_sequence_->ContinueTask(std::move(gpu_task));
- }
- CommandBuffer::State InProcessCommandBuffer::GetLastState() {
- base::AutoLock lock(last_state_lock_);
- return last_state_;
- }
- void InProcessCommandBuffer::UpdateLastStateOnGpuThread() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- base::AutoLock lock(last_state_lock_);
- command_buffer_->UpdateState();
- State state = command_buffer_->GetState();
- if (state.generation - last_state_.generation < 0x80000000U)
- last_state_ = state;
- }
- bool InProcessCommandBuffer::HasUnprocessedCommandsOnGpuThread() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- if (command_buffer_) {
- CommandBuffer::State state = command_buffer_->GetState();
- return command_buffer_->put_offset() != state.get_offset &&
- !error::IsError(state.error);
- }
- return false;
- }
- void InProcessCommandBuffer::FlushOnGpuThread(
- int32_t put_offset,
- const std::vector<SyncToken>& sync_token_fences) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- TRACE_EVENT1("gpu", "InProcessCommandBuffer::FlushOnGpuThread", "put_offset",
- put_offset);
- ScopedEvent handle_flush(&flush_event_);
- // Check if sync token waits are invalid or already complete. Do not use
- // SyncPointManager::IsSyncTokenReleased() as it can't say if the wait is
- // invalid.
- for (const auto& sync_token : sync_token_fences)
- DCHECK(!sync_point_client_state_->Wait(sync_token, base::DoNothing()));
- if (!MakeCurrent())
- return;
- auto cache_use = CreateCacheUse();
- {
- absl::optional<raster::GrShaderCache::ScopedCacheUse> gr_cache_use;
- if (gr_shader_cache_)
- gr_cache_use.emplace(gr_shader_cache_, kDisplayCompositorClientId);
- command_buffer_->Flush(put_offset, decoder_.get());
- }
- // Update state before signaling the flush event.
- UpdateLastStateOnGpuThread();
- bool has_unprocessed_commands = HasUnprocessedCommandsOnGpuThread();
- if (!command_buffer_->scheduled() || has_unprocessed_commands) {
- ContinueGpuTask(base::BindOnce(&InProcessCommandBuffer::FlushOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(),
- put_offset, sync_token_fences));
- }
- // If we've processed all pending commands but still have pending queries,
- // pump idle work until the query is passed.
- if (!has_unprocessed_commands &&
- (decoder_->HasMoreIdleWork() || decoder_->HasPendingQueries())) {
- ScheduleDelayedWorkOnGpuThread();
- }
- }
- void InProcessCommandBuffer::PerformDelayedWorkOnGpuThread() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- delayed_work_pending_ = false;
- if (MakeCurrent()) {
- auto cache_use = CreateCacheUse();
- decoder_->PerformIdleWork();
- decoder_->ProcessPendingQueries(false);
- if (decoder_->HasMoreIdleWork() || decoder_->HasPendingQueries()) {
- ScheduleDelayedWorkOnGpuThread();
- }
- }
- }
- void InProcessCommandBuffer::ScheduleDelayedWorkOnGpuThread() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- if (delayed_work_pending_)
- return;
- delayed_work_pending_ = true;
- task_executor_->ScheduleDelayedWork(
- base::BindOnce(&InProcessCommandBuffer::PerformDelayedWorkOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr()));
- }
- void InProcessCommandBuffer::Flush(int32_t put_offset) {
- if (GetLastState().error != error::kNoError)
- return;
- if (last_put_offset_ == put_offset)
- return;
- TRACE_EVENT1("gpu", "InProcessCommandBuffer::Flush", "put_offset",
- put_offset);
- last_put_offset_ = put_offset;
- std::vector<SyncToken> sync_token_fences;
- next_flush_sync_token_fences_.swap(sync_token_fences);
- // Don't use std::move() for |sync_token_fences| because evaluation order for
- // arguments is not defined.
- ScheduleGpuTask(base::BindOnce(&InProcessCommandBuffer::FlushOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(),
- put_offset, sync_token_fences),
- sync_token_fences);
- }
- void InProcessCommandBuffer::OrderingBarrier(int32_t put_offset) {
- Flush(put_offset);
- }
- CommandBuffer::State InProcessCommandBuffer::WaitForTokenInRange(int32_t start,
- int32_t end) {
- TRACE_EVENT2("gpu", "InProcessCommandBuffer::WaitForTokenInRange", "start",
- start, "end", end);
- State last_state = GetLastState();
- while (!InRange(start, end, last_state.token) &&
- last_state.error == error::kNoError) {
- flush_event_.Wait();
- last_state = GetLastState();
- }
- return last_state;
- }
- CommandBuffer::State InProcessCommandBuffer::WaitForGetOffsetInRange(
- uint32_t set_get_buffer_count,
- int32_t start,
- int32_t end) {
- TRACE_EVENT2("gpu", "InProcessCommandBuffer::WaitForGetOffsetInRange",
- "start", start, "end", end);
- State last_state = GetLastState();
- while (((set_get_buffer_count != last_state.set_get_buffer_count) ||
- !InRange(start, end, last_state.get_offset)) &&
- last_state.error == error::kNoError) {
- flush_event_.Wait();
- last_state = GetLastState();
- }
- return last_state;
- }
- void InProcessCommandBuffer::SetGetBuffer(int32_t shm_id) {
- if (GetLastState().error != error::kNoError)
- return;
- base::WaitableEvent completion(
- base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED);
- ScheduleGpuTask(base::BindOnce(
- &InProcessCommandBuffer::SetGetBufferOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), shm_id, &completion));
- completion.Wait();
- last_put_offset_ = 0;
- }
- void InProcessCommandBuffer::SetGetBufferOnGpuThread(
- int32_t shm_id,
- base::WaitableEvent* completion) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- command_buffer_->SetGetBuffer(shm_id);
- UpdateLastStateOnGpuThread();
- completion->Signal();
- }
- scoped_refptr<Buffer> InProcessCommandBuffer::CreateTransferBuffer(
- uint32_t size,
- int32_t* id,
- TransferBufferAllocationOption option) {
- scoped_refptr<Buffer> buffer = MakeMemoryBuffer(size);
- *id = GetNextBufferId();
- ScheduleGpuTask(
- base::BindOnce(&InProcessCommandBuffer::RegisterTransferBufferOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), *id, buffer));
- return buffer;
- }
- void InProcessCommandBuffer::RegisterTransferBufferOnGpuThread(
- int32_t id,
- scoped_refptr<Buffer> buffer) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- command_buffer_->RegisterTransferBuffer(id, std::move(buffer));
- }
- void InProcessCommandBuffer::DestroyTransferBuffer(int32_t id) {
- ScheduleGpuTask(
- base::BindOnce(&InProcessCommandBuffer::DestroyTransferBufferOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), id));
- }
- void InProcessCommandBuffer::ForceLostContext(error::ContextLostReason reason) {
- ScheduleGpuTask(
- base::BindOnce(&InProcessCommandBuffer::ForceLostContextOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), reason));
- }
- void InProcessCommandBuffer::ForceLostContextOnGpuThread(
- error::ContextLostReason reason) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- // Similar implementation to CommandBufferDirect.
- command_buffer_->SetContextLostReason(reason);
- command_buffer_->SetParseError(error::kLostContext);
- }
- void InProcessCommandBuffer::DestroyTransferBufferOnGpuThread(int32_t id) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- command_buffer_->DestroyTransferBuffer(id);
- }
- void InProcessCommandBuffer::SetGpuControlClient(GpuControlClient* client) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- gpu_control_client_ = client;
- }
- const Capabilities& InProcessCommandBuffer::GetCapabilities() const {
- return capabilities_;
- }
- const GpuFeatureInfo& InProcessCommandBuffer::GetGpuFeatureInfo() const {
- return task_executor_->gpu_feature_info();
- }
- void InProcessCommandBuffer::OnConsoleMessage(int32_t id,
- const std::string& message) {
- // TODO(piman): implement this.
- }
- void InProcessCommandBuffer::CacheBlob(gpu::GpuDiskCacheType type,
- const std::string& key,
- const std::string& shader) {}
- void InProcessCommandBuffer::OnFenceSyncRelease(uint64_t release) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- SyncToken sync_token(GetNamespaceID(), GetCommandBufferID(), release);
- command_buffer_->SetReleaseCount(release);
- sync_point_client_state_->ReleaseFenceSync(release);
- }
- void InProcessCommandBuffer::OnDescheduleUntilFinished() {
- NOTREACHED();
- }
- void InProcessCommandBuffer::OnRescheduleAfterFinished() {
- NOTREACHED();
- }
- void InProcessCommandBuffer::OnSwapBuffers(uint64_t swap_id, uint32_t flags) {
- NOTREACHED();
- }
- void InProcessCommandBuffer::ScheduleGrContextCleanup() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- context_state_->ScheduleGrContextCleanup();
- }
- void InProcessCommandBuffer::HandleReturnData(base::span<const uint8_t> data) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- std::vector<uint8_t> vec(data.data(), data.data() + data.size());
- PostOrRunClientCallback(
- base::BindOnce(&InProcessCommandBuffer::HandleReturnDataOnOriginThread,
- client_thread_weak_ptr_, std::move(vec)));
- }
- void InProcessCommandBuffer::PostOrRunClientCallback(
- base::OnceClosure callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- if (!origin_task_runner_) {
- task_executor_->PostNonNestableToClient(std::move(callback));
- return;
- }
- origin_task_runner_->PostTask(FROM_HERE, std::move(callback));
- }
- base::OnceClosure InProcessCommandBuffer::WrapClientCallback(
- base::OnceClosure callback) {
- return base::BindOnce(&InProcessCommandBuffer::PostOrRunClientCallback,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(),
- std::move(callback));
- }
- void InProcessCommandBuffer::SignalSyncToken(const SyncToken& sync_token,
- base::OnceClosure callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- ScheduleGpuTask(
- base::BindOnce(&InProcessCommandBuffer::SignalSyncTokenOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), sync_token,
- std::move(callback)));
- }
- void InProcessCommandBuffer::SignalSyncTokenOnGpuThread(
- const SyncToken& sync_token,
- base::OnceClosure callback) {
- auto callback_pair =
- base::SplitOnceCallback(WrapClientCallback(std::move(callback)));
- if (!sync_point_client_state_->Wait(sync_token,
- std::move(callback_pair.first))) {
- std::move(callback_pair.second).Run();
- }
- }
- void InProcessCommandBuffer::SignalQuery(unsigned query_id,
- base::OnceClosure callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- ScheduleGpuTask(
- base::BindOnce(&InProcessCommandBuffer::SignalQueryOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), query_id,
- std::move(callback)));
- }
- void InProcessCommandBuffer::SignalQueryOnGpuThread(
- unsigned query_id,
- base::OnceClosure callback) {
- decoder_->SetQueryCallback(query_id, WrapClientCallback(std::move(callback)));
- }
- void InProcessCommandBuffer::CreateGpuFence(uint32_t gpu_fence_id,
- ClientGpuFence source) {
- // Pass a cloned handle to the GPU process since the source ClientGpuFence
- // may go out of scope before the queued task runs.
- gfx::GpuFence* gpu_fence = gfx::GpuFence::FromClientGpuFence(source);
- gfx::GpuFenceHandle handle = gpu_fence->GetGpuFenceHandle().Clone();
- ScheduleGpuTask(
- base::BindOnce(&InProcessCommandBuffer::CreateGpuFenceOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), gpu_fence_id,
- std::move(handle)));
- }
- void InProcessCommandBuffer::CreateGpuFenceOnGpuThread(
- uint32_t gpu_fence_id,
- gfx::GpuFenceHandle handle) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- UpdateActiveUrl();
- if (!GetFeatureInfo()->feature_flags().chromium_gpu_fence) {
- DLOG(ERROR) << "CHROMIUM_gpu_fence unavailable";
- command_buffer_->SetParseError(error::kLostContext);
- return;
- }
- gles2::GpuFenceManager* gpu_fence_manager = decoder_->GetGpuFenceManager();
- DCHECK(gpu_fence_manager);
- if (gpu_fence_manager->CreateGpuFenceFromHandle(gpu_fence_id,
- std::move(handle)))
- return;
- // The insertion failed. This shouldn't happen, force context loss to avoid
- // inconsistent state.
- command_buffer_->SetParseError(error::kLostContext);
- }
- void InProcessCommandBuffer::GetGpuFence(
- uint32_t gpu_fence_id,
- base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)> callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- ScheduleGpuTask(
- base::BindOnce(&InProcessCommandBuffer::GetGpuFenceOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(), gpu_fence_id,
- std::move(callback)));
- }
- void InProcessCommandBuffer::GetGpuFenceOnGpuThread(
- uint32_t gpu_fence_id,
- base::OnceCallback<void(std::unique_ptr<gfx::GpuFence>)> callback) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- if (!GetFeatureInfo()->feature_flags().chromium_gpu_fence) {
- DLOG(ERROR) << "CHROMIUM_gpu_fence unavailable";
- command_buffer_->SetParseError(error::kLostContext);
- return;
- }
- gles2::GpuFenceManager* manager = decoder_->GetGpuFenceManager();
- DCHECK(manager);
- std::unique_ptr<gfx::GpuFence> gpu_fence;
- if (manager->IsValidGpuFence(gpu_fence_id)) {
- gpu_fence = manager->GetGpuFence(gpu_fence_id);
- } else {
- // Retrieval failed. This shouldn't happen, force context loss to avoid
- // inconsistent state.
- DLOG(ERROR) << "GpuFence not found";
- command_buffer_->SetParseError(error::kLostContext);
- }
- PostOrRunClientCallback(
- base::BindOnce(std::move(callback), std::move(gpu_fence)));
- }
- void InProcessCommandBuffer::SetLock(base::Lock*) {
- // No support for using on multiple threads.
- NOTREACHED();
- }
- void InProcessCommandBuffer::EnsureWorkVisible() {
- // This is only relevant for out-of-process command buffers.
- }
- CommandBufferNamespace InProcessCommandBuffer::GetNamespaceID() const {
- return CommandBufferNamespace::IN_PROCESS;
- }
- CommandBufferId InProcessCommandBuffer::GetCommandBufferID() const {
- return gpu_dependency_->command_buffer_id();
- }
- void InProcessCommandBuffer::FlushPendingWork() {
- // This is only relevant for out-of-process command buffers.
- }
- uint64_t InProcessCommandBuffer::GenerateFenceSyncRelease() {
- return next_fence_sync_release_++;
- }
- bool InProcessCommandBuffer::IsFenceSyncReleased(uint64_t release) {
- return release <= GetLastState().release_count;
- }
- void InProcessCommandBuffer::WaitSyncToken(const SyncToken& sync_token) {
- next_flush_sync_token_fences_.push_back(sync_token);
- }
- bool InProcessCommandBuffer::CanWaitUnverifiedSyncToken(
- const SyncToken& sync_token) {
- return sync_token.namespace_id() == GetNamespaceID();
- }
- const gles2::FeatureInfo* InProcessCommandBuffer::GetFeatureInfo() const {
- DCHECK_CALLED_ON_VALID_SEQUENCE(gpu_sequence_checker_);
- return context_group_->feature_info();
- }
- void InProcessCommandBuffer::HandleReturnDataOnOriginThread(
- std::vector<uint8_t> data) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(client_sequence_checker_);
- if (gpu_control_client_) {
- gpu_control_client_->OnGpuControlReturnData(data);
- }
- }
- void InProcessCommandBuffer::UpdateActiveUrl() {
- if (!active_url_.is_empty())
- ContextUrl::SetActiveUrl(active_url_);
- }
- } // namespace gpu
|