blob: e27c48ba4fbf4ada585f17da2a88f4576106f152 [file] [log] [blame]
// Copyright 2018 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/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/shared_image/shared_image_format_utils.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 "third_party/skia/include/gpu/GrYUVABackendTextures.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 (manager_ && backing_->is_ref_counted()) {
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 (manager_ && backing_->is_ref_counted()) {
manager_->OnRepresentationDestroyed(backing_.ExtractAsDangling()->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);
}
gpu::TextureBase* GLTextureImageRepresentationBase::GetTextureBase() {
DCHECK(format().is_single_plane());
return GetTextureBase(0);
}
bool GLTextureImageRepresentationBase::BeginAccess(GLenum mode) {
return true;
}
bool GLTextureImageRepresentationBase::SupportsMultipleConcurrentReadAccess() {
return false;
}
gpu::TextureBase* GLTextureImageRepresentation::GetTextureBase(
int plane_index) {
return GetTexture(plane_index);
}
gles2::Texture* GLTextureImageRepresentation::GetTexture() {
DCHECK(format().is_single_plane());
return GetTexture(0);
}
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(
int plane_index) {
return GetTexturePassthrough(plane_index).get();
}
const scoped_refptr<gles2::TexturePassthrough>&
GLTexturePassthroughImageRepresentation::GetTexturePassthrough() {
DCHECK(format().is_single_plane());
return GetTexturePassthrough(0);
}
bool SkiaImageRepresentation::SupportsMultipleConcurrentReadAccess() {
return false;
}
SkiaImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
base::PassKey<SkiaImageRepresentation> /* pass_key */,
SkiaImageRepresentation* representation,
std::vector<sk_sp<SkSurface>> surfaces,
std::unique_ptr<GrBackendSurfaceMutableState> end_state)
: ScopedAccessBase(representation),
surfaces_(std::move(surfaces)),
end_state_(std::move(end_state)) {
DCHECK(!surfaces_.empty());
}
SkiaImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
base::PassKey<SkiaImageRepresentation> /* pass_key */,
SkiaImageRepresentation* representation,
std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures,
std::unique_ptr<GrBackendSurfaceMutableState> end_state)
: ScopedAccessBase(representation),
promise_image_textures_(std::move(promise_image_textures)),
end_state_(std::move(end_state)) {
DCHECK(!promise_image_textures_.empty());
}
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();
}
// Ensure no one uses `surfaces_` by dropping the reference before calling
// EndWriteAccess.
surfaces_.clear();
representation()->EndWriteAccess();
}
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,
const gfx::Rect& update_rect,
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) {
std::vector<sk_sp<SkSurface>> surfaces =
BeginWriteAccess(final_msaa_count, surface_props, update_rect,
begin_semaphores, end_semaphores, &end_state);
if (surfaces.empty()) {
LOG(ERROR) << "Unable to initialize SkSurface";
return nullptr;
}
backing()->OnWriteSucceeded();
return std::make_unique<ScopedWriteAccess>(
base::PassKey<SkiaImageRepresentation>(), this, std::move(surfaces),
std::move(end_state));
}
std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures =
BeginWriteAccess(begin_semaphores, end_semaphores, &end_state);
if (promise_image_textures.empty()) {
LOG(ERROR) << "Unable to initialize SkPromiseImageTexture";
return nullptr;
}
backing()->OnWriteSucceeded();
return std::make_unique<ScopedWriteAccess>(
base::PassKey<SkiaImageRepresentation>(), this,
std::move(promise_image_textures), 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) {
return BeginScopedWriteAccess(
final_msaa_count, surface_props, gfx::Rect(size()), begin_semaphores,
end_semaphores, allow_uncleared, use_sk_surface);
}
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,
std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures,
std::unique_ptr<GrBackendSurfaceMutableState> end_state)
: ScopedAccessBase(representation),
promise_image_textures_(std::move(promise_image_textures)),
end_state_(std::move(end_state)) {
DCHECK(!promise_image_textures_.empty());
}
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,
SkImage::TextureReleaseProc texture_release_proc,
SkImage::ReleaseContext release_context) const {
auto format = representation()->format();
auto surface_origin = representation()->surface_origin();
auto sk_color_space =
representation()->color_space().GetAsFullRangeRGB().ToSkColorSpace();
if (format.is_single_plane() || format.PrefersExternalSampler()) {
DCHECK_EQ(static_cast<int>(promise_image_textures_.size()), 1);
auto alpha_type = representation()->alpha_type();
auto color_type = viz::ToClosestSkColorType(true, format);
return SkImage::MakeFromTexture(
context, promise_image_texture()->backendTexture(), surface_origin,
color_type, alpha_type, sk_color_space, texture_release_proc,
release_context);
} else {
DCHECK_EQ(static_cast<int>(promise_image_textures_.size()),
format.NumberOfPlanes());
std::array<GrBackendTexture, SkYUVAInfo::kMaxPlanes> yuva_textures;
// Get the texture per plane.
for (int plane_index = 0; plane_index < format.NumberOfPlanes();
plane_index++) {
yuva_textures[plane_index] =
promise_image_texture(plane_index)->backendTexture();
}
SkISize sk_size = gfx::SizeToSkISize(representation()->size());
// TODO(crbug.com/828599): This should really default to rec709.
SkYUVColorSpace yuv_color_space = kRec601_SkYUVColorSpace;
representation()->color_space().ToSkYUVColorSpace(
format.MultiplanarBitDepth(), &yuv_color_space);
SkYUVAInfo yuva_info(sk_size, ToSkYUVAPlaneConfig(format),
ToSkYUVASubsampling(format), yuv_color_space);
GrYUVABackendTextures yuva_backend_textures(yuva_info, yuva_textures.data(),
surface_origin);
return SkImage::MakeFromYUVATextures(context, yuva_backend_textures,
sk_color_space, texture_release_proc,
release_context);
}
}
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;
std::vector<sk_sp<SkPromiseImageTexture>> promise_image_textures =
BeginReadAccess(begin_semaphores, end_semaphores, &end_state);
if (promise_image_textures.empty())
return nullptr;
backing()->OnReadSucceeded();
return std::make_unique<ScopedReadAccess>(
base::PassKey<SkiaImageRepresentation>(), this,
std::move(promise_image_textures), std::move(end_state));
}
#if BUILDFLAG(IS_ANDROID)
AHardwareBuffer* OverlayImageRepresentation::GetAHardwareBuffer() {
NOTREACHED();
return nullptr;
}
std::unique_ptr<base::android::ScopedHardwareBufferFenceSync>
OverlayImageRepresentation::GetAHardwareBufferFenceSync() {
NOTREACHED();
return nullptr;
}
#elif BUILDFLAG(IS_OZONE)
scoped_refptr<gfx::NativePixmap> OverlayImageRepresentation::GetNativePixmap() {
return backing()->GetNativePixmap();
}
#elif BUILDFLAG(IS_WIN)
absl::optional<gl::DCLayerOverlayImage>
OverlayImageRepresentation::GetDCLayerOverlayImage() {
NOTREACHED();
return absl::nullopt;
}
#elif BUILDFLAG(IS_MAC)
gfx::ScopedIOSurface OverlayImageRepresentation::GetIOSurface() const {
return gfx::ScopedIOSurface();
}
bool OverlayImageRepresentation::IsInUseByWindowServer() const {
return false;
}
#endif
OverlayImageRepresentation::ScopedReadAccess::ScopedReadAccess(
base::PassKey<OverlayImageRepresentation> pass_key,
OverlayImageRepresentation* representation,
gfx::GpuFenceHandle acquire_fence)
: ScopedAccessBase(representation),
acquire_fence_(std::move(acquire_fence)) {}
OverlayImageRepresentation::ScopedReadAccess::~ScopedReadAccess() {
representation()->EndReadAccess(std::move(release_fence_));
}
std::unique_ptr<OverlayImageRepresentation::ScopedReadAccess>
OverlayImageRepresentation::BeginScopedReadAccess() {
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,
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));
}
VideoDecodeImageRepresentation::VideoDecodeImageRepresentation(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker)
: SharedImageRepresentation(manager, backing, tracker) {}
VideoDecodeImageRepresentation::~VideoDecodeImageRepresentation() = default;
VideoDecodeImageRepresentation::ScopedWriteAccess::ScopedWriteAccess(
base::PassKey<VideoDecodeImageRepresentation> /* pass_key */,
VideoDecodeImageRepresentation* representation)
: ScopedAccessBase(representation) {}
VideoDecodeImageRepresentation::ScopedWriteAccess::~ScopedWriteAccess() {
representation()->EndWriteAccess();
}
std::unique_ptr<VideoDecodeImageRepresentation::ScopedWriteAccess>
VideoDecodeImageRepresentation::BeginScopedWriteAccess() {
if (!BeginWriteAccess())
return nullptr;
return std::make_unique<ScopedWriteAccess>(
base::PassKey<VideoDecodeImageRepresentation>(), this);
}
} // namespace gpu