blob: d5108cd9d4d656c6c23464e5049c23171a2856c2 [file] [log] [blame]
// 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/test_image_backing.h"
#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h"
#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/ganesh/GrBackendSurface.h"
#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h"
#include "third_party/skia/include/gpu/ganesh/gl/GrGLTypes.h"
#include "third_party/skia/include/gpu/ganesh/mock/GrMockTypes.h"
#include "third_party/skia/include/private/chromium/GrPromiseImageTexture.h"
namespace gpu {
namespace {
class TestGLTextureImageRepresentation : public GLTextureImageRepresentation {
public:
TestGLTextureImageRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
const std::vector<raw_ptr<gles2::Texture>>& textures)
: GLTextureImageRepresentation(manager, backing, tracker),
textures_(std::move(textures)) {}
gles2::Texture* GetTexture(int plane_index) override {
DCHECK(backing()->format().IsValidPlaneIndex(plane_index));
return textures_[plane_index];
}
bool BeginAccess(GLenum mode) override {
return static_cast<TestImageBacking*>(backing())->can_access();
}
void EndAccess() override {}
private:
std::vector<raw_ptr<gles2::Texture>> textures_;
};
class TestGLTexturePassthroughImageRepresentation
: public GLTexturePassthroughImageRepresentation {
public:
TestGLTexturePassthroughImageRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
const std::vector<scoped_refptr<gles2::TexturePassthrough>>& textures)
: GLTexturePassthroughImageRepresentation(manager, backing, tracker),
textures_(std::move(textures)) {}
const scoped_refptr<gles2::TexturePassthrough>& GetTexturePassthrough(
int plane_index) override {
DCHECK(backing()->format().IsValidPlaneIndex(plane_index));
return textures_[plane_index];
}
bool BeginAccess(GLenum mode) override {
return static_cast<TestImageBacking*>(backing())->can_access();
}
void EndAccess() override {}
private:
std::vector<scoped_refptr<gles2::TexturePassthrough>> textures_;
};
class TestSkiaImageRepresentation : public SkiaGaneshImageRepresentation {
public:
TestSkiaImageRepresentation(
GrDirectContext* gr_context,
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
std::vector<sk_sp<GrPromiseImageTexture>> promise_textures)
: SkiaGaneshImageRepresentation(gr_context, manager, backing, tracker),
promise_textures_(std::move(promise_textures)) {}
protected:
std::vector<sk_sp<SkSurface>> BeginWriteAccess(
int final_msaa_count,
const SkSurfaceProps& surface_props,
const gfx::Rect& update_rect,
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores,
std::unique_ptr<skgpu::MutableTextureState>* end_state) override {
if (!static_cast<TestImageBacking*>(backing())->can_access()) {
return {};
}
SkSurfaceProps props = skia::LegacyDisplayGlobals::GetSkSurfaceProps();
auto surface = SkSurfaces::Raster(
SkImageInfo::MakeN32Premul(size().width(), size().height()), &props);
if (!surface)
return {};
return {surface};
}
std::vector<sk_sp<GrPromiseImageTexture>> BeginWriteAccess(
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores,
std::unique_ptr<skgpu::MutableTextureState>* end_state) override {
if (!static_cast<TestImageBacking*>(backing())->can_access()) {
return {};
}
return promise_textures_;
}
void EndWriteAccess() override {}
std::vector<sk_sp<GrPromiseImageTexture>> BeginReadAccess(
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores,
std::unique_ptr<skgpu::MutableTextureState>* end_state) override {
if (!static_cast<TestImageBacking*>(backing())->can_access()) {
return {};
}
return promise_textures_;
}
void EndReadAccess() override {}
private:
std::vector<sk_sp<GrPromiseImageTexture>> promise_textures_;
};
class TestDawnImageRepresentation : public DawnImageRepresentation {
public:
TestDawnImageRepresentation(SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker)
: DawnImageRepresentation(manager, backing, tracker) {}
wgpu::Texture BeginAccess(wgpu::TextureUsage usage,
wgpu::TextureUsage internal_usage) override {
if (!static_cast<TestImageBacking*>(backing())->can_access()) {
return nullptr;
}
return wgpu::Texture(reinterpret_cast<WGPUTexture>(203));
}
void EndAccess() override {}
};
class TestMetalSkiaGraphiteImageRepresentation
: public SkiaGraphiteImageRepresentation {
public:
TestMetalSkiaGraphiteImageRepresentation(SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker)
: SkiaGraphiteImageRepresentation(manager, backing, tracker) {}
std::vector<scoped_refptr<GraphiteTextureHolder>> BeginReadAccess() override {
return {};
}
void EndReadAccess() override {}
std::vector<sk_sp<SkSurface>> BeginWriteAccess(
const SkSurfaceProps& surface_props,
const gfx::Rect& update_rect) override {
std::vector<sk_sp<SkSurface>> surfaces;
for (int plane = 0; plane < format().NumberOfPlanes(); plane++) {
auto plane_size = format().GetPlaneSize(plane, size());
surfaces.push_back(
SkSurfaces::Null(plane_size.width(), plane_size.height()));
}
return surfaces;
}
std::vector<scoped_refptr<GraphiteTextureHolder>> BeginWriteAccess()
override {
return {};
}
void EndWriteAccess() override {}
};
} // namespace
TestImageBacking::TestImageBacking(const Mailbox& mailbox,
viz::SharedImageFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
SharedImageUsageSet usage,
size_t estimated_size,
GLuint texture_id)
: SharedImageBacking(mailbox,
format,
size,
color_space,
surface_origin,
alpha_type,
usage,
"TestBacking",
estimated_size,
/*is_thread_safe=*/false) {
const int num_textures =
format.PrefersExternalSampler() ? 1 : format.NumberOfPlanes();
textures_.reserve(num_textures);
passthrough_textures_.reserve(num_textures);
const int num_planes = format.NumberOfPlanes();
for (int plane = 0; plane < num_planes; ++plane) {
auto* texture = new gles2::Texture(texture_id + plane);
texture->SetLightweightRef();
texture->SetTarget(GL_TEXTURE_2D, 1);
texture->set_min_filter(GL_LINEAR);
texture->set_mag_filter(GL_LINEAR);
texture->set_wrap_t(GL_CLAMP_TO_EDGE);
texture->set_wrap_s(GL_CLAMP_TO_EDGE);
GLFormatDesc format_desc =
GLFormatCaps().ToGLFormatDesc(format, /*plane_index=*/plane);
gfx::Size plane_size = format.GetPlaneSize(plane, size);
texture->SetLevelInfo(GL_TEXTURE_2D, 0, format_desc.image_internal_format,
plane_size.width(), plane_size.height(), 1, 0,
format_desc.data_format, format_desc.data_type,
gfx::Rect());
texture->SetImmutable(true, true);
auto passthrough_texture = base::MakeRefCounted<gles2::TexturePassthrough>(
texture_id + plane, GL_TEXTURE_2D);
textures_.push_back(texture);
passthrough_textures_.push_back(std::move(passthrough_texture));
}
}
TestImageBacking::TestImageBacking(const Mailbox& mailbox,
viz::SharedImageFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
SharedImageUsageSet usage,
size_t estimated_size)
: TestImageBacking(mailbox,
format,
size,
color_space,
surface_origin,
alpha_type,
usage,
estimated_size,
/*texture_id=*/203) {
// Using a dummy |texture_id|, so lose our context so we don't do anything
// real with it.
OnContextLost();
}
TestImageBacking::~TestImageBacking() {
// Pretend our context is lost to avoid actual cleanup in |textures_| or
// |passthrough_textures_|.
GLuint texture_id = service_id();
for (auto& texture : textures_) {
texture.ExtractAsDangling()->RemoveLightweightRef(/*have_context=*/false);
}
for (auto& passthrough_texture : passthrough_textures_) {
passthrough_texture->MarkContextLost();
passthrough_texture.reset();
}
if (have_context())
glDeleteTextures(1, &texture_id);
}
bool TestImageBacking::GetUploadFromMemoryCalledAndReset() {
return std::exchange(upload_from_memory_called_, false);
}
bool TestImageBacking::GetReadbackToMemoryCalledAndReset() {
return std::exchange(readback_to_memory_called_, false);
}
SharedImageBackingType TestImageBacking::GetType() const {
return SharedImageBackingType::kTest;
}
gfx::Rect TestImageBacking::ClearedRect() const {
return textures_[0]->GetLevelClearedRect(textures_[0]->target(), 0);
}
void TestImageBacking::SetClearedRect(const gfx::Rect& cleared_rect) {
textures_[0]->SetLevelClearedRect(textures_[0]->target(), 0, cleared_rect);
}
void TestImageBacking::SetPurgeable(bool purgeable) {
if (purgeable) {
if (set_purgeable_callback_)
set_purgeable_callback_.Run(mailbox());
} else {
if (set_not_purgeable_callback_)
set_not_purgeable_callback_.Run(mailbox());
}
}
bool TestImageBacking::UploadFromMemory(const std::vector<SkPixmap>& pixmap) {
DCHECK_EQ(format().NumberOfPlanes(), static_cast<int>(pixmap.size()));
upload_from_memory_called_ = true;
return true;
}
bool TestImageBacking::ReadbackToMemory(const std::vector<SkPixmap>& pixmaps) {
DCHECK_EQ(format().NumberOfPlanes(), static_cast<int>(pixmaps.size()));
readback_to_memory_called_ = true;
return true;
}
std::unique_ptr<GLTextureImageRepresentation>
TestImageBacking::ProduceGLTexture(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
return std::make_unique<TestGLTextureImageRepresentation>(manager, this,
tracker, textures_);
}
std::unique_ptr<GLTexturePassthroughImageRepresentation>
TestImageBacking::ProduceGLTexturePassthrough(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
return std::make_unique<TestGLTexturePassthroughImageRepresentation>(
manager, this, tracker, passthrough_textures_);
}
std::unique_ptr<SkiaGaneshImageRepresentation>
TestImageBacking::ProduceSkiaGanesh(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
scoped_refptr<SharedContextState> context_state) {
DCHECK(!textures_.empty());
std::vector<sk_sp<GrPromiseImageTexture>> promise_textures;
const GLFormatCaps caps =
context_state ? context_state->GetGLFormatCaps() : GLFormatCaps();
if (format().is_single_plane() || format().PrefersExternalSampler()) {
GLFormatDesc format_desc =
format().PrefersExternalSampler()
? caps.ToGLFormatDescExternalSampler(format())
: caps.ToGLFormatDesc(format(), /*plane_index=*/0);
// TODO(b/346406519): Investigate if possible to change target to
// GL_TEXTURE_2D.
auto backend_texture = GrBackendTextures::MakeGL(
size().width(), size().height(), skgpu::Mipmapped::kNo,
GrGLTextureInfo{
GL_TEXTURE_EXTERNAL_OES, textures_[0]->service_id(),
static_cast<GrGLenum>(format_desc.storage_internal_format)});
if (!backend_texture.isValid()) {
return nullptr;
}
auto promise_texture = GrPromiseImageTexture::Make(backend_texture);
if (!promise_texture) {
return nullptr;
}
promise_textures.push_back(std::move(promise_texture));
} else {
DCHECK_EQ(format().NumberOfPlanes(), static_cast<int>(textures_.size()));
for (int plane_index = 0; plane_index < format().NumberOfPlanes();
plane_index++) {
// Use the format and size per plane for multiplanar formats.
gfx::Size plane_size = format().GetPlaneSize(plane_index, size());
GLFormatDesc format_desc = caps.ToGLFormatDesc(format(), plane_index);
// TODO(b/346406519): Investigate if possible to change target to
// GL_TEXTURE_2D.
auto backend_texture = GrBackendTextures::MakeGL(
plane_size.width(), plane_size.height(), skgpu::Mipmapped::kNo,
GrGLTextureInfo{
GL_TEXTURE_EXTERNAL_OES, textures_[plane_index]->service_id(),
static_cast<GrGLenum>(format_desc.storage_internal_format)});
if (!backend_texture.isValid()) {
return nullptr;
}
auto promise_texture = GrPromiseImageTexture::Make(backend_texture);
if (!promise_texture) {
return nullptr;
}
promise_textures.push_back(std::move(promise_texture));
}
}
return std::make_unique<TestSkiaImageRepresentation>(
context_state ? context_state->gr_context() : nullptr, manager, this,
tracker, std::move(promise_textures));
}
std::unique_ptr<DawnImageRepresentation> TestImageBacking::ProduceDawn(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
const wgpu::Device& device,
wgpu::BackendType backend_type,
std::vector<wgpu::TextureFormat> view_formats,
scoped_refptr<SharedContextState> context_state) {
return std::make_unique<TestDawnImageRepresentation>(manager, this, tracker);
}
std::unique_ptr<SkiaGraphiteImageRepresentation>
TestImageBacking::ProduceSkiaGraphite(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
scoped_refptr<SharedContextState> context_state) {
#if BUILDFLAG(SKIA_USE_METAL)
return std::make_unique<TestMetalSkiaGraphiteImageRepresentation>(
manager, this, tracker);
#else
return nullptr;
#endif // BUILDFLAG(SKIA_USE_METAL)
}
std::unique_ptr<OverlayImageRepresentation> TestImageBacking::ProduceOverlay(
SharedImageManager* manager,
MemoryTypeTracker* tracker) {
return std::make_unique<TestOverlayImageRepresentation>(manager, this,
tracker);
}
bool TestOverlayImageRepresentation::BeginReadAccess(
gfx::GpuFenceHandle& acquire_fence) {
return true;
}
void TestOverlayImageRepresentation::EndReadAccess(
gfx::GpuFenceHandle release_fence) {}
#if BUILDFLAG(IS_ANDROID)
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
TestOverlayImageRepresentation::GetAHardwareBufferFenceSync() {
return nullptr;
}
#endif
#if BUILDFLAG(IS_APPLE)
bool TestOverlayImageRepresentation::IsInUseByWindowServer() const {
return static_cast<TestImageBacking*>(backing())->in_use_by_window_server();
}
#endif // BUILDFLAG(IS_APPLE)
} // namespace gpu