123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729 |
- // Copyright 2015 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 "components/exo/buffer.h"
- #include <stdint.h>
- #include <algorithm>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/logging.h"
- #include "base/memory/weak_ptr.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "base/trace_event/trace_event.h"
- #include "base/trace_event/traced_value.h"
- #include "build/build_config.h"
- #include "components/exo/frame_sink_resource_manager.h"
- #include "components/viz/common/gpu/context_lost_observer.h"
- #include "components/viz/common/gpu/context_provider.h"
- #include "components/viz/common/resources/resource_format.h"
- #include "components/viz/common/resources/resource_format_utils.h"
- #include "components/viz/common/resources/resource_id.h"
- #include "components/viz/common/resources/returned_resource.h"
- #include "gpu/GLES2/gl2extchromium.h"
- #include "gpu/command_buffer/client/context_support.h"
- #include "gpu/command_buffer/client/raster_interface.h"
- #include "gpu/command_buffer/client/shared_image_interface.h"
- #include "gpu/command_buffer/common/mailbox.h"
- #include "gpu/command_buffer/common/shared_image_usage.h"
- #include "gpu/command_buffer/common/sync_token.h"
- #include "ui/aura/env.h"
- #include "ui/compositor/compositor.h"
- #include "ui/gfx/gpu_fence_handle.h"
- #include "ui/gfx/gpu_memory_buffer.h"
- #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- #include "base/files/scoped_file.h"
- #include "base/posix/eintr_wrapper.h"
- #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- namespace exo {
- namespace {
- // The amount of time before we wait for release queries using
- // GetQueryObjectuivEXT(GL_QUERY_RESULT_EXT).
- const int kWaitForReleaseDelayMs = 500;
- constexpr char kBufferInUse[] = "BufferInUse";
- } // namespace
- ////////////////////////////////////////////////////////////////////////////////
- // Buffer::Texture
- // Encapsulates the state and logic needed to bind a buffer to a SharedImage.
- class Buffer::Texture : public viz::ContextLostObserver {
- public:
- Texture(scoped_refptr<viz::RasterContextProvider> context_provider,
- const gfx::Size& size);
- Texture(scoped_refptr<viz::RasterContextProvider> context_provider,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gfx::GpuMemoryBuffer* gpu_memory_buffer,
- unsigned texture_target,
- unsigned query_type,
- base::TimeDelta wait_for_release_time,
- bool is_overlay_candidate);
- Texture(const Texture&) = delete;
- Texture& operator=(const Texture&) = delete;
- ~Texture() override;
- // Overridden from viz::ContextLostObserver:
- void OnContextLost() override;
- // Returns true if the RasterInterface context has been lost.
- bool IsLost();
- // Allow texture to be reused after |sync_token| has passed and runs
- // |callback|.
- void Release(base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
- viz::ReturnedResource resource);
- // Updates the contents referenced by |gpu_memory_buffer_| returned by
- // mailbox().
- // Returns a sync token that can be used when accessing the SharedImage from a
- // different context.
- gpu::SyncToken UpdateSharedImage(
- std::unique_ptr<gfx::GpuFence> acquire_fence);
- // Releases the contents referenced by |mailbox_| after |sync_token| has
- // passed and runs |callback| when completed.
- void ReleaseSharedImage(
- base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
- viz::ReturnedResource resource);
- // Copy the contents of texture to |destination| and runs |callback| when
- // completed. Returns a sync token that can be used when accessing texture
- // from a different context.
- gpu::SyncToken CopyTexImage(std::unique_ptr<gfx::GpuFence> acquire_fence,
- Texture* destination,
- base::OnceClosure callback);
- // Returns the mailbox for this texture.
- gpu::Mailbox mailbox() const { return mailbox_; }
- private:
- void DestroyResources();
- void ReleaseWhenQueryResultIsAvailable(base::OnceClosure callback);
- void Released();
- void ScheduleWaitForRelease(base::TimeDelta delay);
- void WaitForRelease();
- gfx::GpuMemoryBuffer* const gpu_memory_buffer_;
- const gfx::Size size_;
- scoped_refptr<viz::RasterContextProvider> context_provider_;
- const unsigned texture_target_;
- const unsigned query_type_;
- unsigned query_id_ = 0;
- gpu::Mailbox mailbox_;
- base::OnceClosure release_callback_;
- const base::TimeDelta wait_for_release_delay_;
- base::TimeTicks wait_for_release_time_;
- bool wait_for_release_pending_ = false;
- base::WeakPtrFactory<Texture> weak_ptr_factory_{this};
- };
- Buffer::Texture::Texture(
- scoped_refptr<viz::RasterContextProvider> context_provider,
- const gfx::Size& size)
- : gpu_memory_buffer_(nullptr),
- size_(size),
- context_provider_(std::move(context_provider)),
- texture_target_(GL_TEXTURE_2D),
- query_type_(GL_COMMANDS_COMPLETED_CHROMIUM) {
- gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
- // Add GLES2 usage as it is used by RasterImplementationGLES.
- const uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER |
- gpu::SHARED_IMAGE_USAGE_DISPLAY |
- gpu::SHARED_IMAGE_USAGE_GLES2;
- mailbox_ = sii->CreateSharedImage(
- viz::ResourceFormat::RGBA_8888, size, gfx::ColorSpace::CreateSRGB(),
- kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, usage,
- gpu::kNullSurfaceHandle);
- DCHECK(!mailbox_.IsZero());
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
- // Provides a notification when |context_provider_| is lost.
- context_provider_->AddObserver(this);
- }
- Buffer::Texture::Texture(
- scoped_refptr<viz::RasterContextProvider> context_provider,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- gfx::GpuMemoryBuffer* gpu_memory_buffer,
- unsigned texture_target,
- unsigned query_type,
- base::TimeDelta wait_for_release_delay,
- bool is_overlay_candidate)
- : gpu_memory_buffer_(gpu_memory_buffer),
- size_(gpu_memory_buffer->GetSize()),
- context_provider_(std::move(context_provider)),
- texture_target_(texture_target),
- query_type_(query_type),
- wait_for_release_delay_(wait_for_release_delay) {
- gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
- // Add GLES2 usage as it is used by RasterImplementationGLES.
- uint32_t usage = gpu::SHARED_IMAGE_USAGE_RASTER |
- gpu::SHARED_IMAGE_USAGE_DISPLAY |
- gpu::SHARED_IMAGE_USAGE_GLES2;
- if (is_overlay_candidate) {
- usage |= gpu::SHARED_IMAGE_USAGE_SCANOUT;
- }
- mailbox_ = sii->CreateSharedImage(
- gpu_memory_buffer_, gpu_memory_buffer_manager,
- gfx::ColorSpace::CreateSRGB(), kTopLeft_GrSurfaceOrigin,
- kPremul_SkAlphaType, usage);
- DCHECK(!mailbox_.IsZero());
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- ri->WaitSyncTokenCHROMIUM(sii->GenUnverifiedSyncToken().GetConstData());
- ri->GenQueriesEXT(1, &query_id_);
- // Provides a notification when |context_provider_| is lost.
- context_provider_->AddObserver(this);
- }
- Buffer::Texture::~Texture() {
- DestroyResources();
- if (context_provider_)
- context_provider_->RemoveObserver(this);
- }
- void Buffer::Texture::OnContextLost() {
- DestroyResources();
- context_provider_->RemoveObserver(this);
- context_provider_.reset();
- }
- bool Buffer::Texture::IsLost() {
- if (context_provider_) {
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- return ri->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
- }
- return true;
- }
- void Buffer::Texture::Release(
- base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
- viz::ReturnedResource resource) {
- if (context_provider_) {
- // Only need to wait on the sync token if we don't have a release fence.
- if (resource.sync_token.HasData() && resource.release_fence.is_null()) {
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- ri->WaitSyncTokenCHROMIUM(resource.sync_token.GetConstData());
- }
- }
- // Run callback as texture can be reused immediately after waiting for sync
- // token.
- std::move(callback).Run(std::move(resource.release_fence));
- }
- gpu::SyncToken Buffer::Texture::UpdateSharedImage(
- std::unique_ptr<gfx::GpuFence> acquire_fence) {
- gpu::SyncToken sync_token;
- if (context_provider_) {
- gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
- DCHECK(!mailbox_.IsZero());
- // UpdateSharedImage gets called only after |mailbox_| can be reused.
- // A buffer can be reattached to a surface only after it has been returned
- // to wayland clients. We return buffers to clients only after the query
- // |query_type_| is available.
- sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
- mailbox_);
- sync_token = sii->GenUnverifiedSyncToken();
- TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
- "bound");
- }
- return sync_token;
- }
- void Buffer::Texture::ReleaseSharedImage(
- base::OnceCallback<void(gfx::GpuFenceHandle)> callback,
- viz::ReturnedResource resource) {
- // Only need to wait on the sync token and query if we don't have a release
- // fence.
- if (context_provider_ && resource.release_fence.is_null()) {
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- if (resource.sync_token.HasData())
- ri->WaitSyncTokenCHROMIUM(resource.sync_token.GetConstData());
- ri->BeginQueryEXT(query_type_, query_id_);
- ri->EndQueryEXT(query_type_);
- // Run callback when query result is available (i.e., when all operations on
- // the shared image have completed and it's ready to be reused) if sync
- // token has data and buffer has been used. If buffer was never used then
- // run the callback immediately.
- if (resource.sync_token.HasData()) {
- ReleaseWhenQueryResultIsAvailable(base::BindOnce(
- std::move(callback), /*release_fence=*/gfx::GpuFenceHandle()));
- return;
- }
- }
- std::move(callback).Run(std::move(resource.release_fence));
- }
- gpu::SyncToken Buffer::Texture::CopyTexImage(
- std::unique_ptr<gfx::GpuFence> acquire_fence,
- Texture* destination,
- base::OnceClosure callback) {
- gpu::SyncToken sync_token;
- if (context_provider_) {
- DCHECK(!mailbox_.IsZero());
- gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
- sii->UpdateSharedImage(gpu::SyncToken(), std::move(acquire_fence),
- mailbox_);
- sync_token = sii->GenUnverifiedSyncToken();
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- ri->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
- DCHECK_NE(query_id_, 0u);
- ri->BeginQueryEXT(query_type_, query_id_);
- ri->CopySubTexture(mailbox_, destination->mailbox_,
- destination->texture_target_, 0, 0, 0, 0, size_.width(),
- size_.height(), /*unpack_flip_y=*/false,
- /*unpack_premultiply_alpha=*/false);
- ri->EndQueryEXT(query_type_);
- // Run callback when query result is available.
- ReleaseWhenQueryResultIsAvailable(std::move(callback));
- // Create and return a sync token that can be used to ensure that the
- // CopySubTexture call is processed before issuing any commands
- // that will read from the target texture on a different context.
- ri->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
- }
- return sync_token;
- }
- void Buffer::Texture::DestroyResources() {
- if (context_provider_) {
- if (query_id_) {
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- ri->DeleteQueriesEXT(1, &query_id_);
- query_id_ = 0;
- }
- gpu::SharedImageInterface* sii = context_provider_->SharedImageInterface();
- sii->DestroySharedImage(gpu::SyncToken(), mailbox_);
- }
- }
- void Buffer::Texture::ReleaseWhenQueryResultIsAvailable(
- base::OnceClosure callback) {
- DCHECK(context_provider_);
- DCHECK(release_callback_.is_null());
- release_callback_ = std::move(callback);
- wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay_;
- ScheduleWaitForRelease(wait_for_release_delay_);
- TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_,
- "pending_query");
- context_provider_->ContextSupport()->SignalQuery(
- query_id_, base::BindOnce(&Buffer::Texture::Released,
- weak_ptr_factory_.GetWeakPtr()));
- }
- void Buffer::Texture::Released() {
- if (!release_callback_.is_null())
- std::move(release_callback_).Run();
- }
- void Buffer::Texture::ScheduleWaitForRelease(base::TimeDelta delay) {
- if (wait_for_release_pending_)
- return;
- wait_for_release_pending_ = true;
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&Buffer::Texture::WaitForRelease,
- weak_ptr_factory_.GetWeakPtr()),
- delay);
- }
- void Buffer::Texture::WaitForRelease() {
- DCHECK(wait_for_release_pending_);
- wait_for_release_pending_ = false;
- if (release_callback_.is_null())
- return;
- base::TimeTicks current_time = base::TimeTicks::Now();
- if (current_time < wait_for_release_time_) {
- ScheduleWaitForRelease(wait_for_release_time_ - current_time);
- return;
- }
- base::OnceClosure callback = std::move(release_callback_);
- if (context_provider_) {
- TRACE_EVENT0("exo", "Buffer::Texture::WaitForQueryResult");
- // We need to wait for the result to be available. Getting the result of
- // the query implies waiting for it to become available. The actual result
- // is unimportant and also not well defined.
- unsigned result = 0;
- gpu::raster::RasterInterface* ri = context_provider_->RasterInterface();
- ri->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
- }
- std::move(callback).Run();
- }
- Buffer::BufferRelease::BufferRelease(
- gfx::GpuFenceHandle release_fence,
- std::unique_ptr<base::FileDescriptorWatcher::Controller> controller,
- base::OnceClosure buffer_release_callback)
- : release_fence(std::move(release_fence)),
- controller(std::move(controller)),
- buffer_release_callback(std::move(buffer_release_callback)) {}
- Buffer::BufferRelease::~BufferRelease() = default;
- Buffer::BufferRelease::BufferRelease(BufferRelease&&) = default;
- Buffer::BufferRelease& Buffer::BufferRelease::operator=(BufferRelease&&) =
- default;
- ////////////////////////////////////////////////////////////////////////////////
- // Buffer, public:
- Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer)
- : Buffer(std::move(gpu_memory_buffer),
- GL_TEXTURE_2D /* texture_target */,
- GL_COMMANDS_COMPLETED_CHROMIUM /* query_type */,
- true /* use_zero_copy */,
- false /* is_overlay_candidate */,
- false /* y_invert */) {}
- Buffer::Buffer(std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
- unsigned texture_target,
- unsigned query_type,
- bool use_zero_copy,
- bool is_overlay_candidate,
- bool y_invert)
- : gpu_memory_buffer_(std::move(gpu_memory_buffer)),
- texture_target_(texture_target),
- query_type_(query_type),
- use_zero_copy_(use_zero_copy),
- is_overlay_candidate_(is_overlay_candidate),
- y_invert_(y_invert),
- wait_for_release_delay_(base::Milliseconds(kWaitForReleaseDelayMs)) {}
- Buffer::~Buffer() {}
- bool Buffer::ProduceTransferableResource(
- FrameSinkResourceManager* resource_manager,
- std::unique_ptr<gfx::GpuFence> acquire_fence,
- bool secure_output_only,
- viz::TransferableResource* resource,
- ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
- PerCommitExplicitReleaseCallback per_commit_explicit_release_callback) {
- TRACE_EVENT1("exo", "Buffer::ProduceTransferableResource", "buffer_id",
- static_cast<const void*>(gfx_buffer()));
- DCHECK(attach_count_);
- next_commit_id_++;
- // If textures are lost, destroy them to ensure that we create new ones below.
- if (contents_texture_ && contents_texture_->IsLost())
- contents_texture_.reset();
- if (texture_ && texture_->IsLost())
- texture_.reset();
- ui::ContextFactory* context_factory =
- aura::Env::GetInstance()->context_factory();
- // Note: This can fail if GPU acceleration has been disabled.
- scoped_refptr<viz::RasterContextProvider> context_provider =
- context_factory->SharedMainThreadRasterContextProvider();
- if (!context_provider) {
- DLOG(WARNING) << "Failed to acquire a context provider";
- resource->id = viz::kInvalidResourceId;
- resource->size = gfx::Size();
- if (per_commit_explicit_release_callback)
- std::move(per_commit_explicit_release_callback)
- .Run(/*release_fence=*/gfx::GpuFenceHandle());
- return false;
- }
- const bool request_release_fence =
- !per_commit_explicit_release_callback.is_null();
- if (per_commit_explicit_release_callback)
- pending_explicit_releases_.emplace(
- next_commit_id_, std::move(per_commit_explicit_release_callback));
- resource->id = resource_manager->AllocateResourceId();
- resource->format = viz::RGBA_8888;
- resource->filter = GL_LINEAR;
- resource->size = gpu_memory_buffer_->GetSize();
- // Create a new image texture for |gpu_memory_buffer_| with |texture_target_|
- // if one doesn't already exist. The contents of this buffer are copied to
- // |texture| using a call to CopyTexImage.
- if (!contents_texture_) {
- contents_texture_ = std::make_unique<Texture>(
- context_provider, context_factory->GetGpuMemoryBufferManager(),
- gpu_memory_buffer_.get(), texture_target_, query_type_,
- wait_for_release_delay_, is_overlay_candidate_);
- }
- Texture* contents_texture = contents_texture_.get();
- if (release_contents_callback_.IsCancelled())
- TRACE_EVENT_ASYNC_BEGIN1("exo", kBufferInUse, gpu_memory_buffer_.get(),
- "buffer_id",
- static_cast<const void*>(gfx_buffer()));
- // Cancel pending contents release callback.
- release_contents_callback_.Reset(
- base::BindOnce(&Buffer::ReleaseContents, base::Unretained(this)));
- #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- // Check if this buffer needs HW protection. This can only happen if we
- // require a secure output.
- if (secure_output_only &&
- protected_buffer_state_ == ProtectedBufferState::UNKNOWN &&
- gpu_memory_buffer_ && protected_native_pixmap_query) {
- gfx::GpuMemoryBufferHandle gmb_handle = gpu_memory_buffer_->CloneHandle();
- if (!gmb_handle.native_pixmap_handle.planes.empty()) {
- base::ScopedFD pixmap_handle(HANDLE_EINTR(
- dup(gmb_handle.native_pixmap_handle.planes[0].fd.get())));
- if (pixmap_handle.is_valid()) {
- protected_buffer_state_ = ProtectedBufferState::QUERYING;
- protected_native_pixmap_query->IsProtectedNativePixmapHandle(
- std::move(pixmap_handle),
- base::BindOnce(&Buffer::OnIsProtectedNativePixmapHandle,
- AsWeakPtr()));
- }
- }
- }
- #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- // Zero-copy means using the contents texture directly.
- if (use_zero_copy_) {
- // This binds the latest contents of this buffer to |contents_texture|.
- gpu::SyncToken sync_token =
- contents_texture->UpdateSharedImage(std::move(acquire_fence));
- resource->mailbox_holder = gpu::MailboxHolder(contents_texture->mailbox(),
- sync_token, texture_target_);
- resource->is_overlay_candidate = is_overlay_candidate_;
- resource->format = viz::GetResourceFormat(gpu_memory_buffer_->GetFormat());
- if (context_provider->ContextCapabilities().chromium_gpu_fence &&
- request_release_fence) {
- resource->synchronization_type =
- viz::TransferableResource::SynchronizationType::kReleaseFence;
- }
- // The contents texture will be released when no longer used by the
- // compositor.
- resource_manager->SetResourceReleaseCallback(
- resource->id,
- base::BindOnce(&Buffer::Texture::ReleaseSharedImage,
- base::Unretained(contents_texture),
- base::BindOnce(&Buffer::ReleaseContentsTexture,
- AsWeakPtr(), std::move(contents_texture_),
- release_contents_callback_.callback(),
- next_commit_id_)));
- return true;
- }
- // Create a mailbox texture that we copy the buffer contents to.
- if (!texture_) {
- texture_ = std::make_unique<Texture>(context_provider,
- gpu_memory_buffer_->GetSize());
- }
- Texture* texture = texture_.get();
- // Copy the contents of |contents_texture| to |texture| and produce a
- // texture mailbox from the result in |texture|. The contents texture will
- // be released when copy has completed.
- gpu::SyncToken sync_token = contents_texture->CopyTexImage(
- std::move(acquire_fence), texture,
- base::BindOnce(&Buffer::ReleaseContentsTexture, AsWeakPtr(),
- std::move(contents_texture_),
- release_contents_callback_.callback(), next_commit_id_,
- /*release_fence=*/gfx::GpuFenceHandle()));
- resource->mailbox_holder =
- gpu::MailboxHolder(texture->mailbox(), sync_token, GL_TEXTURE_2D);
- resource->is_overlay_candidate = false;
- // The mailbox texture will be released when no longer used by the
- // compositor.
- resource_manager->SetResourceReleaseCallback(
- resource->id,
- base::BindOnce(&Buffer::Texture::Release, base::Unretained(texture),
- base::BindOnce(&Buffer::ReleaseTexture, AsWeakPtr(),
- std::move(texture_))));
- return true;
- }
- void Buffer::OnAttach() {
- DLOG_IF(WARNING, attach_count_)
- << "Reattaching a buffer that is already attached to another surface.";
- TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id",
- static_cast<const void*>(gfx_buffer()), "count", attach_count_);
- ++attach_count_;
- }
- void Buffer::OnDetach() {
- DCHECK_GT(attach_count_, 0u);
- TRACE_EVENT2("exo", "Buffer::OnAttach", "buffer_id",
- static_cast<const void*>(gfx_buffer()), "count", attach_count_);
- --attach_count_;
- // Release buffer if no longer attached to a surface and content has been
- // released.
- if (!attach_count_ && release_contents_callback_.IsCancelled())
- Release();
- }
- gfx::Size Buffer::GetSize() const {
- return gpu_memory_buffer_->GetSize();
- }
- gfx::BufferFormat Buffer::GetFormat() const {
- return gpu_memory_buffer_->GetFormat();
- }
- SkColor4f Buffer::GetColor() const {
- return SkColors::kBlack;
- }
- #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- bool Buffer::NeedsHardwareProtection() {
- // We don't indicate protection is needed in the UNKNOWN state because we have
- // not seen a pixmap yet that could be protected.
- return protected_buffer_state_ == ProtectedBufferState::PROTECTED ||
- protected_buffer_state_ == ProtectedBufferState::QUERYING;
- }
- #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- ////////////////////////////////////////////////////////////////////////////////
- // Buffer, private:
- void Buffer::Release() {
- TRACE_EVENT_ASYNC_END0("exo", kBufferInUse, gpu_memory_buffer_.get());
- // Run release callback to notify the client that buffer has been released.
- if (!release_callback_.is_null())
- release_callback_.Run();
- }
- void Buffer::ReleaseTexture(std::unique_ptr<Texture> texture,
- gfx::GpuFenceHandle release_fence) {
- // Buffer was composited - we should not receive a release fence.
- DCHECK(release_fence.is_null());
- texture_ = std::move(texture);
- }
- void Buffer::ReleaseContentsTexture(std::unique_ptr<Texture> texture,
- base::OnceClosure callback,
- uint64_t commit_id,
- gfx::GpuFenceHandle release_fence) {
- contents_texture_ = std::move(texture);
- MaybeRunPerCommitRelease(commit_id, std::move(release_fence),
- std::move(callback));
- }
- void Buffer::ReleaseContents() {
- TRACE_EVENT1("exo", "Buffer::ReleaseContents", "buffer_id",
- static_cast<const void*>(gfx_buffer()));
- // Cancel callback to indicate that buffer has been released.
- release_contents_callback_.Cancel();
- if (attach_count_) {
- TRACE_EVENT_ASYNC_STEP_INTO0("exo", kBufferInUse, gpu_memory_buffer_.get(),
- "attached");
- } else {
- // Release buffer if not attached to surface.
- Release();
- }
- }
- void Buffer::MaybeRunPerCommitRelease(
- uint64_t commit_id,
- gfx::GpuFenceHandle release_fence,
- base::OnceClosure buffer_release_callback) {
- auto iter = pending_explicit_releases_.find(commit_id);
- if (iter != pending_explicit_releases_.end()) {
- std::move(iter->second).Run(release_fence.Clone());
- pending_explicit_releases_.erase(iter);
- }
- // We are still required to send these wl_buffer.release events even if
- // the client supports explicit synchronization.
- if (release_fence.is_null()) {
- std::move(buffer_release_callback).Run();
- } else {
- #if BUILDFLAG(IS_POSIX)
- // Watching the release fence's fd results in a context switch to the I/O
- // thread. That may steal thread time from other applications, which can
- // do something useful during that time. Moreover, most of the time the
- // fence can have already been signalled. Thus, only watch the fence is
- // readable iff it hasn't been signalled yet.
- base::TimeTicks ticks;
- auto status = gfx::GpuFence::GetStatusChangeTime(
- release_fence.owned_fd.get(), &ticks);
- if (status == gfx::GpuFence::kSignaled) {
- std::move(buffer_release_callback).Run();
- return;
- }
- auto controller = base::FileDescriptorWatcher::WatchReadable(
- release_fence.owned_fd.get(),
- base::BindRepeating(&Buffer::FenceSignalled, AsWeakPtr(), commit_id));
- buffer_releases_.emplace(
- commit_id,
- BufferRelease(std::move(release_fence), std::move(controller),
- std::move(buffer_release_callback)));
- #else
- NOTREACHED();
- #endif
- }
- }
- void Buffer::FenceSignalled(uint64_t commit_id) {
- auto iter = buffer_releases_.find(commit_id);
- DCHECK(iter != buffer_releases_.end());
- std::move(iter->second.buffer_release_callback).Run();
- buffer_releases_.erase(iter);
- }
- #if BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- void Buffer::OnIsProtectedNativePixmapHandle(bool is_protected) {
- protected_buffer_state_ = is_protected ? ProtectedBufferState::PROTECTED
- : ProtectedBufferState::UNPROTECTED;
- }
- #endif // BUILDFLAG(USE_ARC_PROTECTED_MEDIA)
- SolidColorBuffer::SolidColorBuffer(const SkColor4f& color,
- const gfx::Size& size)
- : Buffer(nullptr), color_(color), size_(size) {}
- SolidColorBuffer::~SolidColorBuffer() = default;
- bool SolidColorBuffer::ProduceTransferableResource(
- FrameSinkResourceManager* resource_manager,
- std::unique_ptr<gfx::GpuFence> acquire_fence,
- bool secure_output_only,
- viz::TransferableResource* resource,
- ProtectedNativePixmapQueryDelegate* protected_native_pixmap_query,
- PerCommitExplicitReleaseCallback per_commit_explicit_release_callback) {
- if (per_commit_explicit_release_callback)
- std::move(per_commit_explicit_release_callback)
- .Run(/*release_fence=*/gfx::GpuFenceHandle());
- return false;
- }
- SkColor4f SolidColorBuffer::GetColor() const {
- return color_;
- }
- gfx::Size SolidColorBuffer::GetSize() const {
- return size_;
- }
- } // namespace exo
|