blob: 79fe58cb83c5c06a5a73b68792fdaf21b3a637b7 [file] [log] [blame]
// Copyright 2025 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/slim/texture_layer.h"
#include <utility>
#include "base/functional/bind.h"
#include "base/memory/scoped_refptr.h"
#include "cc/layers/texture_layer_client.h"
#include "cc/slim/layer_tree_impl.h"
#include "components/viz/client/client_resource_provider.h"
#include "components/viz/common/quads/compositor_render_pass.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/release_callback.h"
#include "components/viz/common/resources/resource_id.h"
#include "components/viz/common/resources/transferable_resource.h"
namespace cc::slim {
class TextureLayer::TransferableResourceHolder
: public base::RefCountedThreadSafe<TransferableResourceHolder> {
public:
static scoped_refptr<TransferableResourceHolder> Create(
const viz::TransferableResource& resource,
viz::ReleaseCallback release_callback) {
return new TransferableResourceHolder(resource,
std::move(release_callback));
}
TransferableResourceHolder(const TransferableResourceHolder&) = delete;
TransferableResourceHolder& operator=(const TransferableResourceHolder&) =
delete;
// Returns a callback that stores the parameters in order to run the actual
// callback on destruction.
viz::ReleaseCallback CreateCallback() {
return base::BindOnce(&TransferableResourceHolder::DoReleaseCallback,
base::WrapRefCounted(this));
}
const viz::TransferableResource& resource() const { return resource_; }
protected:
virtual ~TransferableResourceHolder() {
if (release_callback_) {
std::move(release_callback_).Run(destruction_sync_token_, is_lost_);
}
}
private:
friend class base::RefCountedThreadSafe<TransferableResourceHolder>;
explicit TransferableResourceHolder(const viz::TransferableResource& resource,
viz::ReleaseCallback release_callback)
: resource_(resource),
release_callback_(std::move(release_callback)),
destruction_sync_token_(resource.sync_token()) {}
void DoReleaseCallback(const gpu::SyncToken& sync_token, bool is_lost) {
destruction_sync_token_ = sync_token;
is_lost_ = is_lost;
}
const viz::TransferableResource resource_;
viz::ReleaseCallback release_callback_;
gpu::SyncToken destruction_sync_token_;
bool is_lost_ = false;
};
// static
scoped_refptr<TextureLayer> TextureLayer::Create(TextureLayerClient* client) {
return base::AdoptRef(new TextureLayer(client));
}
TextureLayer::TextureLayer(TextureLayerClient* client) : client_(client) {
CHECK(client_);
}
TextureLayer::~TextureLayer() {
OnResourceEvicted();
}
void TextureLayer::NotifyUpdatedResource() {
// Guarantees that AppendQuads is called for the next frame.
NotifyPropertyChanged();
}
void TextureLayer::ClearTexture() {
OnResourceEvicted();
resource_holder_.reset();
}
void TextureLayer::SetLayerTree(LayerTree* layer_tree) {
if (this->layer_tree() == layer_tree) {
return;
}
OnResourceEvicted();
Layer::SetLayerTree(layer_tree);
}
void TextureLayer::OnResourceEvicted() {
if (resource_id_) {
DCHECK(layer_tree());
auto* resource_provider =
static_cast<LayerTreeImpl*>(layer_tree())->GetClientResourceProvider();
// TODO(crbug.com/447533816): Remove this conditional. Right now, during a
// GPU context loss, the layers aren't informed about lost resources.
if (resource_provider) {
resource_provider->RemoveImportedResource(resource_id_);
}
resource_id_ = viz::kInvalidResourceId;
}
}
void TextureLayer::AppendQuads(viz::CompositorRenderPass& render_pass,
FrameData& data,
const gfx::Transform& transform_to_root,
const gfx::Transform& transform_to_target,
const gfx::Rect* clip_in_target,
const gfx::Rect& visible_rect,
float opacity) {
viz::TransferableResource resource;
viz::ReleaseCallback release_callback;
if (client_->PrepareTransferableResource(&resource, &release_callback)) {
OnResourceEvicted();
resource_holder_ = TransferableResourceHolder::Create(
resource, std::move(release_callback));
}
if (!resource_holder_) {
return;
}
if (!resource_id_) {
auto* resource_provider =
static_cast<LayerTreeImpl*>(layer_tree())->GetClientResourceProvider();
// base::Unretained is safe because ~TextureLayer will clear the callback
// (through ClientResourceProvider::RemoveImportedResources).
auto evicted_callback = base::BindOnce(&TextureLayer::OnResourceEvicted,
base::Unretained(this));
resource_id_ = resource_provider->ImportResource(
resource_holder_->resource(), viz::ReleaseCallback(),
resource_holder_->CreateCallback(), std::move(evicted_callback));
}
viz::SharedQuadState* quad_state =
CreateAndAppendSharedQuadState(render_pass, data, transform_to_target,
clip_in_target, visible_rect, opacity);
viz::TextureDrawQuad* quad =
render_pass.CreateAndAppendDrawQuad<viz::TextureDrawQuad>();
constexpr bool kNearest = false;
constexpr bool kSecureOutputOnly = false;
constexpr auto kVideoType = gfx::ProtectedVideoType::kClear;
const bool needs_blending =
!contents_opaque() && !background_color().isOpaque();
quad->SetNew(quad_state, quad_state->quad_layer_rect,
quad_state->visible_quad_layer_rect, needs_blending,
resource_id_, gfx::PointF(), gfx::PointF(1.0f, 1.0f),
background_color(), kNearest, kSecureOutputOnly, kVideoType);
}
} // namespace cc::slim