blob: 55ba75488539e8e8bcf3d19cef760ee66118e71b [file] [log] [blame]
// 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 "gpu/command_buffer/service/shared_image/shared_image_representation.h"
#include "base/debug/dump_without_crashing.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkPromiseImageTexture.h"
#include "third_party/skia/include/gpu/GrBackendSurfaceMutableState.h"
#include "third_party/skia/include/gpu/GrDirectContext.h"
#include "ui/gl/gl_fence.h"
namespace gpu {
SharedImageRepresentation::SharedImageRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* owning_tracker)
: manager_(manager), backing_(backing), tracker_(owning_tracker) {
DCHECK(tracker_);
// TODO(hitawala): Rewrite the reference counting so that
// SharedImageRepresentation does not need manager and manager attaches to
// backing in Register().
// If mailbox is zero this is owned by a compound backing and not reference
// counted.
if (manager_ && !backing_->mailbox().IsZero()) {
backing_->AddRef(this);
}
}
SharedImageRepresentation::~SharedImageRepresentation() {
// CHECK here as we'll crash later anyway, and this makes it clearer what the
// error is.
CHECK(!has_scoped_access_) << "Destroying a SharedImageRepresentation with "
"outstanding Scoped*Access objects.";
// If mailbox is zero this is owned by a compound backing and not reference
// counted.
if (manager_ && !backing_->mailbox().IsZero()) {
manager_->OnRepresentationDestroyed(backing_->mailbox(), this);
}
}
std::unique_ptr<GLTextureImageRepresentation::ScopedAccess>
GLTextureImageRepresentationBase::BeginScopedAccess(
GLenum mode,
AllowUnclearedAccess allow_uncleared) {
if (allow_uncleared != AllowUnclearedAccess::kYes && !IsCleared()) {
LOG(ERROR) << "Attempt to access an uninitialized SharedImage";
return nullptr;
}
if (!BeginAccess(mode))
return nullptr;
UpdateClearedStateOnBeginAccess();
if (mode == kReadAccessMode)
backing()->OnReadSucceeded();
else
backing()->OnWriteSucceeded();
return std::make_unique<ScopedAccess>(
base::PassKey<GLTextureImageRepresentationBase>(), this);
}
bool GLTextureImageRepresentationBase::BeginAccess(GLenum mode) {
return true;
}
bool GLTextureImageRepresentationBase::SupportsMultipleConcurrentReadAccess() {
return false;
}
gpu::TextureBase* GLTextureImageRepresentation::GetTextureBase() {
return GetTexture();
}
void GLTextureImageRepresentation::UpdateClearedStateOnEndAccess() {
auto* texture = GetTexture();
// Operations on the gles2::Texture may have cleared or uncleared it. Make
// sure this state is reflected back in the SharedImage.
gfx::Rect cleared_rect = texture->GetLevelClearedRect(texture->target(), 0);
if (cleared_rect != ClearedRect())
SetClearedRect(cleared_rect);
}
void GLTextureImageRepresentation::UpdateClearedStateOnBeginAccess() {
auto* texture = GetTexture();
// Operations outside of the gles2::Texture may have cleared or uncleared it.
// Make sure this state is reflected back in gles2::Texture.
gfx::Rect cleared_rect = ClearedRect();
if (cleared_rect != texture->GetLevelClearedRect(texture->target(), 0))
texture->SetLevelClearedRect(texture->target(), 0, cleared_rect);
}
gpu::TextureBase* GLTexturePassthroughImageRepresentation::GetTextureBase() {
return GetTexturePassthrough().get();
}
bool SkiaImageRepresentation::SupportsMultipleConcurrentReadAccess() {
return false;
}
SkiaImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
base::PassKey<SkiaImageRepresentation> /* pass_key */,
SkiaImageRepresentation* representation,
sk_sp<SkSurface> surface,
std::unique_ptr<GrBackendSurfaceMutableState> end_state)
: ScopedAccessBase(representation),
surface_(std::move(surface)),
end_state_(std::move(end_state)) {}
SkiaImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
base::PassKey<SkiaImageRepresentation> /* pass_key */,
SkiaImageRepresentation* representation,
sk_sp<SkPromiseImageTexture> promise_image_texture,
std::unique_ptr<GrBackendSurfaceMutableState> end_state)
: ScopedAccessBase(representation),
promise_image_texture_(std::move(promise_image_texture)),
end_state_(std::move(end_state)) {}
SkiaImageRepresentation::ScopedWriteAccess::~ScopedWriteAccess() {
if (end_state_) {
NOTREACHED() << "Before ending write access TakeEndState() must be called "
"and the result passed to skia to make sure all layout and "
"ownership transitions are done.";
static std::atomic_int count = 0;
if (count++ < 3)
base::debug::DumpWithoutCrashing();
}
representation()->EndWriteAccess(std::move(surface_));
}
std::unique_ptr<GrBackendSurfaceMutableState>
SkiaImageRepresentation::ScopedWriteAccess::TakeEndState() {
return std::move(end_state_);
}
std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess>
SkiaImageRepresentation::BeginScopedWriteAccess(
int final_msaa_count,
const SkSurfaceProps& surface_props,
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores,
AllowUnclearedAccess allow_uncleared,
bool use_sk_surface) {
if (allow_uncleared != AllowUnclearedAccess::kYes && !IsCleared()) {
LOG(ERROR) << "Attempt to write to an uninitialized SharedImage";
return nullptr;
}
std::unique_ptr<GrBackendSurfaceMutableState> end_state;
if (use_sk_surface) {
sk_sp<SkSurface> surface =
BeginWriteAccess(final_msaa_count, surface_props, begin_semaphores,
end_semaphores, &end_state);
if (!surface) {
LOG(ERROR) << "Unable to initialize SkSurface";
return nullptr;
}
backing()->OnWriteSucceeded();
return std::make_unique<ScopedWriteAccess>(
base::PassKey<SkiaImageRepresentation>(), this, std::move(surface),
std::move(end_state));
}
sk_sp<SkPromiseImageTexture> promise_image_texture =
BeginWriteAccess(begin_semaphores, end_semaphores, &end_state);
if (!promise_image_texture) {
LOG(ERROR) << "Unable to initialize SkPromiseImageTexture";
return nullptr;
}
backing()->OnWriteSucceeded();
return std::make_unique<ScopedWriteAccess>(
base::PassKey<SkiaImageRepresentation>(), this,
std::move(promise_image_texture), std::move(end_state));
}
std::unique_ptr<SkiaImageRepresentation::ScopedWriteAccess>
SkiaImageRepresentation::BeginScopedWriteAccess(
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores,
AllowUnclearedAccess allow_uncleared,
bool use_sk_surface) {
return BeginScopedWriteAccess(
/*final_msaa_count=*/1,
SkSurfaceProps(0 /* flags */, kUnknown_SkPixelGeometry), begin_semaphores,
end_semaphores, allow_uncleared, use_sk_surface);
}
SkiaImageRepresentation::ScopedReadAccess::ScopedReadAccess(
base::PassKey<SkiaImageRepresentation> /* pass_key */,
SkiaImageRepresentation* representation,
sk_sp<SkPromiseImageTexture> promise_image_texture,
std::unique_ptr<GrBackendSurfaceMutableState> end_state)
: ScopedAccessBase(representation),
promise_image_texture_(std::move(promise_image_texture)),
end_state_(std::move(end_state)) {}
SkiaImageRepresentation::ScopedReadAccess::~ScopedReadAccess() {
if (end_state_) {
NOTREACHED() << "Before ending read access TakeEndState() must be called "
"and the result passed to skia to make sure all layout and "
"ownership transitions are done.";
static std::atomic_int count = 0;
if (count++ < 3)
base::debug::DumpWithoutCrashing();
}
representation()->EndReadAccess();
}
sk_sp<SkImage> SkiaImageRepresentation::ScopedReadAccess::CreateSkImage(
GrDirectContext* context) const {
auto surface_origin = representation()->surface_origin();
auto color_type =
viz::ResourceFormatToClosestSkColorType(true, representation()->format());
auto alpha_type = representation()->alpha_type();
auto sk_color_space =
representation()->color_space().GetAsFullRangeRGB().ToSkColorSpace();
return SkImage::MakeFromTexture(
context, promise_image_texture_->backendTexture(), surface_origin,
color_type, alpha_type, sk_color_space);
}
std::unique_ptr<GrBackendSurfaceMutableState>
SkiaImageRepresentation::ScopedReadAccess::TakeEndState() {
return std::move(end_state_);
}
std::unique_ptr<SkiaImageRepresentation::ScopedReadAccess>
SkiaImageRepresentation::BeginScopedReadAccess(
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores) {
if (!IsCleared()) {
auto cr = ClearedRect();
LOG(ERROR) << base::StringPrintf(
"Attempt to read from an uninitialized SharedImage. "
"Initialized region: (%d, %d, %d, %d) Size: (%d, %d)",
cr.x(), cr.y(), cr.width(), cr.height(), size().width(),
size().height());
return nullptr;
}
std::unique_ptr<GrBackendSurfaceMutableState> end_state;
sk_sp<SkPromiseImageTexture> promise_image_texture =
BeginReadAccess(begin_semaphores, end_semaphores, &end_state);
if (!promise_image_texture)
return nullptr;
backing()->OnReadSucceeded();
return std::make_unique<ScopedReadAccess>(
base::PassKey<SkiaImageRepresentation>(), this,
std::move(promise_image_texture), std::move(end_state));
}
sk_sp<SkSurface> SkiaImageRepresentation::BeginWriteAccess(
int final_msaa_count,
const SkSurfaceProps& surface_props,
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores,
std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
return BeginWriteAccess(final_msaa_count, surface_props, begin_semaphores,
end_semaphores);
}
sk_sp<SkSurface> SkiaImageRepresentation::BeginWriteAccess(
int final_msaa_count,
const SkSurfaceProps& surface_props,
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores) {
return nullptr;
}
sk_sp<SkPromiseImageTexture> SkiaImageRepresentation::BeginReadAccess(
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores,
std::unique_ptr<GrBackendSurfaceMutableState>* end_state) {
return BeginReadAccess(begin_semaphores, end_semaphores);
}
sk_sp<SkPromiseImageTexture> SkiaImageRepresentation::BeginReadAccess(
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores) {
return nullptr;
}
#if BUILDFLAG(IS_ANDROID)
AHardwareBuffer* OverlayImageRepresentation::GetAHardwareBuffer() {
NOTREACHED();
return nullptr;
}
#elif defined(USE_OZONE)
scoped_refptr<gfx::NativePixmap> OverlayImageRepresentation::GetNativePixmap() {
return backing()->GetNativePixmap();
}
#endif
OverlayImageRepresentation::ScopedReadAccess::ScopedReadAccess(
base::PassKey<OverlayImageRepresentation> pass_key,
OverlayImageRepresentation* representation,
gl::GLImage* gl_image,
gfx::GpuFenceHandle acquire_fence)
: ScopedAccessBase(representation),
gl_image_(gl_image),
acquire_fence_(std::move(acquire_fence)) {}
OverlayImageRepresentation::ScopedReadAccess::~ScopedReadAccess() {
representation()->EndReadAccess(std::move(release_fence_));
}
std::unique_ptr<OverlayImageRepresentation::ScopedReadAccess>
OverlayImageRepresentation::BeginScopedReadAccess(bool needs_gl_image) {
if (!IsCleared()) {
LOG(ERROR) << "Attempt to read from an uninitialized SharedImage";
return nullptr;
}
gfx::GpuFenceHandle acquire_fence;
if (!BeginReadAccess(acquire_fence))
return nullptr;
backing()->OnReadSucceeded();
return std::make_unique<ScopedReadAccess>(
base::PassKey<OverlayImageRepresentation>(), this,
needs_gl_image ? GetGLImage() : nullptr, std::move(acquire_fence));
}
DawnImageRepresentation::ScopedAccess::ScopedAccess(
base::PassKey<DawnImageRepresentation> /* pass_key */,
DawnImageRepresentation* representation,
WGPUTexture texture)
: ScopedAccessBase(representation), texture_(texture) {}
DawnImageRepresentation::ScopedAccess::~ScopedAccess() {
representation()->EndAccess();
}
std::unique_ptr<DawnImageRepresentation::ScopedAccess>
DawnImageRepresentation::BeginScopedAccess(
WGPUTextureUsage usage,
AllowUnclearedAccess allow_uncleared) {
if (allow_uncleared != AllowUnclearedAccess::kYes && !IsCleared()) {
LOG(ERROR) << "Attempt to access an uninitialized SharedImage";
return nullptr;
}
WGPUTexture texture = BeginAccess(usage);
if (!texture)
return nullptr;
if (usage & kWriteUsage) {
backing()->OnWriteSucceeded();
} else {
backing()->OnReadSucceeded();
}
return std::make_unique<ScopedAccess>(
base::PassKey<DawnImageRepresentation>(), this, texture);
}
SharedImageRepresentationFactoryRef::~SharedImageRepresentationFactoryRef() {
backing()->UnregisterImageFactory();
backing()->MarkForDestruction();
}
VaapiImageRepresentation::VaapiImageRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
VaapiDependencies* vaapi_deps)
: SharedImageRepresentation(manager, backing, tracker),
vaapi_deps_(vaapi_deps) {}
VaapiImageRepresentation::~VaapiImageRepresentation() = default;
VaapiImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
base::PassKey<VaapiImageRepresentation> /* pass_key */,
VaapiImageRepresentation* representation)
: ScopedAccessBase(representation) {}
VaapiImageRepresentation::ScopedWriteAccess::~ScopedWriteAccess() {
representation()->EndAccess();
}
const media::VASurface*
VaapiImageRepresentation::ScopedWriteAccess::va_surface() {
return representation()->vaapi_deps_->GetVaSurface();
}
std::unique_ptr<VaapiImageRepresentation::ScopedWriteAccess>
VaapiImageRepresentation::BeginScopedWriteAccess() {
return std::make_unique<ScopedWriteAccess>(
base::PassKey<VaapiImageRepresentation>(), this);
}
MemoryImageRepresentation::ScopedReadAccess::ScopedReadAccess(
base::PassKey<MemoryImageRepresentation> pass_key,
MemoryImageRepresentation* representation,
SkPixmap pixmap)
: ScopedAccessBase(representation), pixmap_(pixmap) {}
MemoryImageRepresentation::ScopedReadAccess::~ScopedReadAccess() = default;
std::unique_ptr<MemoryImageRepresentation::ScopedReadAccess>
MemoryImageRepresentation::BeginScopedReadAccess() {
return std::make_unique<ScopedReadAccess>(
base::PassKey<MemoryImageRepresentation>(), this, BeginReadAccess());
}
RasterImageRepresentation::ScopedReadAccess::ScopedReadAccess(
base::PassKey<RasterImageRepresentation> pass_key,
RasterImageRepresentation* representation,
const cc::PaintOpBuffer* paint_op_buffer,
const absl::optional<SkColor4f>& clear_color)
: ScopedAccessBase(representation),
paint_op_buffer_(paint_op_buffer),
clear_color_(clear_color) {}
RasterImageRepresentation::ScopedReadAccess::~ScopedReadAccess() {
representation()->EndReadAccess();
}
RasterImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
base::PassKey<RasterImageRepresentation> pass_key,
RasterImageRepresentation* representation,
cc::PaintOpBuffer* paint_op_buffer)
: ScopedAccessBase(representation), paint_op_buffer_(paint_op_buffer) {}
RasterImageRepresentation::ScopedWriteAccess::~ScopedWriteAccess() {
representation()->EndWriteAccess(std::move(callback_));
}
std::unique_ptr<RasterImageRepresentation::ScopedReadAccess>
RasterImageRepresentation::BeginScopedReadAccess() {
absl::optional<SkColor4f> clear_color;
auto* paint_op_buffer = BeginReadAccess(clear_color);
if (!paint_op_buffer)
return nullptr;
return std::make_unique<ScopedReadAccess>(
base::PassKey<RasterImageRepresentation>(), this, paint_op_buffer,
clear_color);
}
std::unique_ptr<RasterImageRepresentation::ScopedWriteAccess>
RasterImageRepresentation::BeginScopedWriteAccess(
scoped_refptr<SharedContextState> context_state,
int final_msaa_count,
const SkSurfaceProps& surface_props,
const absl::optional<SkColor4f>& clear_color,
bool visible) {
return std::make_unique<ScopedWriteAccess>(
base::PassKey<RasterImageRepresentation>(), this,
BeginWriteAccess(std::move(context_state), final_msaa_count,
surface_props, clear_color, visible));
}
} // namespace gpu