123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- // Copyright 2018 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 "media/gpu/command_buffer_helper.h"
- #include <utility>
- #include <vector>
- #include "base/logging.h"
- #include "base/memory/raw_ptr.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/threading/thread_checker.h"
- #include "build/build_config.h"
- #include "gpu/command_buffer/common/scheduling_priority.h"
- #include "gpu/command_buffer/service/decoder_context.h"
- #include "gpu/command_buffer/service/scheduler.h"
- #include "gpu/command_buffer/service/shared_image/shared_image_backing.h"
- #include "gpu/command_buffer/service/shared_image/shared_image_representation.h"
- #include "gpu/command_buffer/service/sync_point_manager.h"
- #include "gpu/ipc/service/command_buffer_stub.h"
- #include "gpu/ipc/service/gpu_channel.h"
- #include "gpu/ipc/service/gpu_channel_manager.h"
- #include "media/gpu/gles2_decoder_helper.h"
- #include "ui/gl/gl_context.h"
- #if BUILDFLAG(IS_WIN)
- #include "gpu/command_buffer/service/dxgi_shared_handle_manager.h"
- #endif
- namespace media {
- namespace {
- class CommandBufferHelperImpl
- : public CommandBufferHelper,
- public gpu::CommandBufferStub::DestructionObserver {
- public:
- explicit CommandBufferHelperImpl(gpu::CommandBufferStub* stub)
- : CommandBufferHelper(stub->channel()->task_runner()),
- stub_(stub),
- memory_tracker_(this),
- memory_type_tracker_(&memory_tracker_) {
- DVLOG(1) << __func__;
- DCHECK(stub_->channel()->task_runner()->BelongsToCurrentThread());
- stub_->AddDestructionObserver(this);
- wait_sequence_id_ = stub_->channel()->scheduler()->CreateSequence(
- #if BUILDFLAG(IS_MAC)
- // Workaround for crbug.com/1035750.
- // TODO(sandersd): Investigate whether there is a deeper scheduling
- // problem that can be resolved.
- gpu::SchedulingPriority::kHigh
- #else
- gpu::SchedulingPriority::kNormal
- #endif // BUILDFLAG(IS_MAC)
- ,
- stub_->channel()->task_runner());
- decoder_helper_ = GLES2DecoderHelper::Create(stub_->decoder_context());
- }
- CommandBufferHelperImpl(const CommandBufferHelperImpl&) = delete;
- CommandBufferHelperImpl& operator=(const CommandBufferHelperImpl&) = delete;
- gl::GLContext* GetGLContext() override {
- DVLOG(2) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!decoder_helper_)
- return nullptr;
- return decoder_helper_->GetGLContext();
- }
- gpu::SharedImageStub* GetSharedImageStub() override {
- return shared_image_stub();
- }
- // Const variant of above method for internal callers.
- gpu::SharedImageStub* shared_image_stub() const {
- if (!stub_)
- return nullptr;
- return stub_->channel()->shared_image_stub();
- }
- #if BUILDFLAG(IS_WIN)
- gpu::DXGISharedHandleManager* GetDXGISharedHandleManager() override {
- if (!stub_)
- return nullptr;
- return stub_->channel()
- ->gpu_channel_manager()
- ->shared_image_manager()
- ->dxgi_shared_handle_manager()
- .get();
- }
- #endif
- bool HasStub() override {
- DVLOG(4) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return stub_;
- }
- bool MakeContextCurrent() override {
- DVLOG(2) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return decoder_helper_ && decoder_helper_->MakeContextCurrent();
- }
- std::unique_ptr<gpu::SharedImageRepresentationFactoryRef> Register(
- std::unique_ptr<gpu::SharedImageBacking> backing) override {
- DVLOG(2) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- return stub_->channel()
- ->gpu_channel_manager()
- ->shared_image_manager()
- ->Register(std::move(backing), &memory_type_tracker_);
- }
- gpu::TextureBase* GetTexture(GLuint service_id) const override {
- DVLOG(2) << __func__ << "(" << service_id << ")";
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(stub_->decoder_context()->GetGLContext()->IsCurrent(nullptr));
- DCHECK(textures_.count(service_id));
- return textures_.at(service_id)->GetTextureBase();
- }
- GLuint CreateTexture(GLenum target,
- GLenum internal_format,
- GLsizei width,
- GLsizei height,
- GLenum format,
- GLenum type) override {
- DVLOG(2) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(stub_->decoder_context()->GetGLContext()->IsCurrent(nullptr));
- std::unique_ptr<gpu::gles2::AbstractTexture> texture =
- decoder_helper_->CreateTexture(target, internal_format, width, height,
- format, type);
- GLuint service_id = texture->service_id();
- textures_[service_id] = std::move(texture);
- return service_id;
- }
- void DestroyTexture(GLuint service_id) override {
- DVLOG(2) << __func__ << "(" << service_id << ")";
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(stub_->decoder_context()->GetGLContext()->IsCurrent(nullptr));
- DCHECK(textures_.count(service_id));
- textures_.erase(service_id);
- }
- void SetCleared(GLuint service_id) override {
- DVLOG(2) << __func__ << "(" << service_id << ")";
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(textures_.count(service_id));
- textures_[service_id]->SetCleared();
- }
- bool BindImage(GLuint service_id,
- gl::GLImage* image,
- bool client_managed) override {
- DVLOG(2) << __func__ << "(" << service_id << ")";
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(textures_.count(service_id));
- textures_[service_id]->BindImage(image, client_managed);
- return true;
- }
- gpu::Mailbox CreateMailbox(GLuint service_id) override {
- DVLOG(2) << __func__ << "(" << service_id << ")";
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!decoder_helper_)
- return gpu::Mailbox();
- DCHECK(textures_.count(service_id));
- return decoder_helper_->CreateMailbox(textures_[service_id].get());
- }
- void ProduceTexture(const gpu::Mailbox& mailbox, GLuint service_id) override {
- DVLOG(2) << __func__ << "(" << mailbox.ToDebugString() << ", " << service_id
- << ")";
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!decoder_helper_)
- return;
- DCHECK(textures_.count(service_id));
- return decoder_helper_->ProduceTexture(mailbox,
- textures_[service_id].get());
- }
- void WaitForSyncToken(gpu::SyncToken sync_token,
- base::OnceClosure done_cb) override {
- DVLOG(2) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (!stub_)
- return;
- // TODO(sandersd): Do we need to keep a ref to |this| while there are
- // pending waits? If we destruct while they are pending, they will never
- // run.
- stub_->channel()->scheduler()->ScheduleTask(
- gpu::Scheduler::Task(wait_sequence_id_, std::move(done_cb),
- std::vector<gpu::SyncToken>({sync_token})));
- }
- void SetWillDestroyStubCB(WillDestroyStubCB will_destroy_stub_cb) override {
- DCHECK(!will_destroy_stub_cb_);
- will_destroy_stub_cb_ = std::move(will_destroy_stub_cb);
- }
- bool IsPassthrough() const override {
- if (!stub_)
- return false;
- return stub_->decoder_context()
- ->GetFeatureInfo()
- ->is_passthrough_cmd_decoder();
- }
- bool SupportsTextureRectangle() const override {
- if (!stub_)
- return false;
- return stub_->decoder_context()
- ->GetFeatureInfo()
- ->feature_flags()
- .arb_texture_rectangle;
- }
- private:
- // Helper class to forward memory tracking calls to shared image stub.
- // Necessary because the underlying stub and channel can get destroyed before
- // the CommandBufferHelper and its clients.
- class MemoryTrackerImpl : public gpu::MemoryTracker {
- public:
- explicit MemoryTrackerImpl(CommandBufferHelperImpl* helper)
- : helper_(helper) {
- if (auto* stub = helper_->shared_image_stub()) {
- // We assume these don't change after initialization.
- client_id_ = stub->ClientId();
- client_tracing_id_ = stub->ClientTracingId();
- context_group_tracing_id_ = stub->ContextGroupTracingId();
- }
- }
- ~MemoryTrackerImpl() override = default;
- MemoryTrackerImpl(const MemoryTrackerImpl&) = delete;
- MemoryTrackerImpl& operator=(const MemoryTrackerImpl&) = delete;
- void TrackMemoryAllocatedChange(int64_t delta) override {
- if (auto* stub = helper_->shared_image_stub())
- stub->TrackMemoryAllocatedChange(delta);
- }
- uint64_t GetSize() const override {
- if (auto* stub = helper_->shared_image_stub())
- return stub->GetSize();
- return 0;
- }
- int ClientId() const override { return client_id_; }
- uint64_t ClientTracingId() const override { return client_tracing_id_; }
- uint64_t ContextGroupTracingId() const override {
- return context_group_tracing_id_;
- }
- private:
- const raw_ptr<CommandBufferHelperImpl> helper_;
- int client_id_ = 0;
- uint64_t client_tracing_id_ = 0;
- uint64_t context_group_tracing_id_ = 0;
- };
- ~CommandBufferHelperImpl() override {
- DVLOG(1) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (stub_)
- DestroyStub();
- }
- void OnWillDestroyStub(bool have_context) override {
- DVLOG(1) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- // In case |will_destroy_stub_cb_| drops the last reference to |this|, make
- // sure that we're around a bit longer.
- scoped_refptr<CommandBufferHelper> thiz(this);
- if (will_destroy_stub_cb_)
- std::move(will_destroy_stub_cb_).Run(have_context);
- DestroyStub();
- }
- void DestroyStub() {
- DVLOG(3) << __func__;
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- decoder_helper_ = nullptr;
- // If the last reference to |this| is in a |done_cb|, destroying the wait
- // sequence can delete |this|. Clearing |stub_| first prevents DestroyStub()
- // being called twice.
- gpu::CommandBufferStub* stub = stub_;
- stub_ = nullptr;
- stub->RemoveDestructionObserver(this);
- stub->channel()->scheduler()->DestroySequence(wait_sequence_id_);
- }
- raw_ptr<gpu::CommandBufferStub> stub_;
- // Wait tasks are scheduled on our own sequence so that we can't inadvertently
- // block the command buffer.
- gpu::SequenceId wait_sequence_id_;
- // TODO(sandersd): Merge GLES2DecoderHelper implementation into this class.
- std::unique_ptr<GLES2DecoderHelper> decoder_helper_;
- std::map<GLuint, std::unique_ptr<gpu::gles2::AbstractTexture>> textures_;
- WillDestroyStubCB will_destroy_stub_cb_;
- MemoryTrackerImpl memory_tracker_;
- gpu::MemoryTypeTracker memory_type_tracker_;
- THREAD_CHECKER(thread_checker_);
- };
- } // namespace
- CommandBufferHelper::CommandBufferHelper(
- scoped_refptr<base::SequencedTaskRunner> task_runner)
- : base::RefCountedDeleteOnSequence<CommandBufferHelper>(
- std::move(task_runner)) {}
- // static
- scoped_refptr<CommandBufferHelper> CommandBufferHelper::Create(
- gpu::CommandBufferStub* stub) {
- return base::MakeRefCounted<CommandBufferHelperImpl>(stub);
- }
- } // namespace media
|