Commit dac687f4 authored by Sunny Sachanandani's avatar Sunny Sachanandani Committed by Chromium LUCI CQ

gpu: Swap GL shared image backing and factory source files

https://crrev.com/c/2313044 split the GL shared image backing and
factory into separate source files, but the contents of the .cc files
got mixed up - the factory contained the backing sources and vice-versa.
This didn't cause any issues during build because the backing and
factory are always in the same translation unit.

This CL only swaps the contents of the two files and git detects it as a
file rename change so it should have no effect, modulo spelling mistakes
caught by Tricium.

Bug: 1092155
Change-Id: I792b9a7500efc0138354c8cee903cd908e15d523
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2641058
Auto-Submit: Sunny Sachanandani <sunnyps@chromium.org>
Reviewed-by: default avatarccameron <ccameron@chromium.org>
Reviewed-by: default avatarvikas soni <vikassoni@chromium.org>
Commit-Queue: Sunny Sachanandani <sunnyps@chromium.org>
Commit-Queue: vikas soni <vikassoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#845504}
parent 5a773275
......@@ -44,6 +44,7 @@
#include "ui/gl/gl_image_shared_memory.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/progress_reporter.h"
#include "ui/gl/scoped_binders.h"
#include "ui/gl/shared_gl_fence_egl.h"
#include "ui/gl/trace_util.h"
......@@ -53,19 +54,14 @@
#include "gpu/command_buffer/service/shared_image_batch_access_manager.h"
#endif
#if defined(OS_MAC)
#include "gpu/command_buffer/service/shared_image_backing_factory_iosurface.h"
#endif
namespace gpu {
namespace {
size_t EstimatedSize(viz::ResourceFormat format, const gfx::Size& size) {
size_t estimated_size = 0;
viz::ResourceSizes::MaybeSizeInBytes(size, format, &estimated_size);
return estimated_size;
}
using ScopedResetAndRestoreUnpackState =
SharedImageBackingGLCommon::ScopedResetAndRestoreUnpackState;
using ScopedRestoreTexture = SharedImageBackingGLCommon::ScopedRestoreTexture;
using InitializeGLTextureParams =
SharedImageBackingGLCommon::InitializeGLTextureParams;
......@@ -73,163 +69,551 @@ using InitializeGLTextureParams =
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////
// SharedImageBackingGLTexture
// SharedImageBackingFactoryGLTexture
SharedImageBackingFactoryGLTexture::SharedImageBackingFactoryGLTexture(
const GpuPreferences& gpu_preferences,
const GpuDriverBugWorkarounds& workarounds,
const GpuFeatureInfo& gpu_feature_info,
ImageFactory* image_factory,
SharedImageBatchAccessManager* batch_access_manager,
gl::ProgressReporter* progress_reporter)
: use_passthrough_(gpu_preferences.use_passthrough_cmd_decoder &&
gles2::PassthroughCommandDecoderSupported()),
image_factory_(image_factory),
workarounds_(workarounds),
progress_reporter_(progress_reporter) {
#if defined(OS_ANDROID)
batch_access_manager_ = batch_access_manager;
#endif
gl::GLApi* api = gl::g_current_gl_context;
api->glGetIntegervFn(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
// When the passthrough command decoder is used, the max_texture_size
// workaround is implemented by ANGLE. Trying to adjust the max size here
// would cause discrepancy between what we think the max size is and what
// ANGLE tells the clients.
if (!use_passthrough_ && workarounds.max_texture_size) {
max_texture_size_ =
std::min(max_texture_size_, workarounds.max_texture_size);
}
// Ensure max_texture_size_ is less than INT_MAX so that gfx::Rect and friends
// can be used to accurately represent all valid sub-rects, with overflow
// cases, clamped to INT_MAX, always invalid.
max_texture_size_ = std::min(max_texture_size_, INT_MAX - 1);
SharedImageBackingGLTexture::SharedImageBackingGLTexture(
// TODO(piman): Can we extract the logic out of FeatureInfo?
scoped_refptr<gles2::FeatureInfo> feature_info =
new gles2::FeatureInfo(workarounds, gpu_feature_info);
feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2,
use_passthrough_, gles2::DisallowedFeatures());
gpu_memory_buffer_formats_ =
feature_info->feature_flags().gpu_memory_buffer_formats;
texture_usage_angle_ = feature_info->feature_flags().angle_texture_usage;
attribs.es3_capable = feature_info->IsES3Capable();
attribs.desktop_gl = !feature_info->gl_version_info().is_es;
// Can't use the value from feature_info, as we unconditionally enable this
// extension, and assume it can't be used if PBOs are not used (which isn't
// true for Skia used directly against GL).
attribs.supports_unpack_subimage =
gl::g_current_gl_driver->ext.b_GL_EXT_unpack_subimage;
bool enable_texture_storage =
feature_info->feature_flags().ext_texture_storage;
bool enable_scanout_images =
(image_factory_ && image_factory_->SupportsCreateAnonymousImage());
const gles2::Validators* validators = feature_info->validators();
for (int i = 0; i <= viz::RESOURCE_FORMAT_MAX; ++i) {
auto format = static_cast<viz::ResourceFormat>(i);
FormatInfo& info = format_info_[i];
if (!viz::GLSupportsFormat(format))
continue;
const GLuint image_internal_format = viz::GLInternalFormat(format);
const GLenum gl_format = viz::GLDataFormat(format);
const GLenum gl_type = viz::GLDataType(format);
const bool uncompressed_format_valid =
validators->texture_internal_format.IsValid(image_internal_format) &&
validators->texture_format.IsValid(gl_format);
const bool compressed_format_valid =
validators->compressed_texture_format.IsValid(image_internal_format);
if ((uncompressed_format_valid || compressed_format_valid) &&
validators->pixel_type.IsValid(gl_type)) {
info.enabled = true;
info.is_compressed = compressed_format_valid;
info.gl_format = gl_format;
info.gl_type = gl_type;
info.swizzle = gles2::TextureManager::GetCompatibilitySwizzle(
feature_info.get(), gl_format);
info.image_internal_format =
gles2::TextureManager::AdjustTexInternalFormat(
feature_info.get(), image_internal_format, gl_type);
info.adjusted_format =
gles2::TextureManager::AdjustTexFormat(feature_info.get(), gl_format);
}
if (!info.enabled)
continue;
if (enable_texture_storage && !info.is_compressed) {
GLuint storage_internal_format = viz::TextureStorageFormat(format);
if (validators->texture_internal_format_storage.IsValid(
storage_internal_format)) {
info.supports_storage = true;
info.storage_internal_format =
gles2::TextureManager::AdjustTexStorageFormat(
feature_info.get(), storage_internal_format);
}
}
if (!info.enabled || !enable_scanout_images ||
!IsGpuMemoryBufferFormatSupported(format)) {
continue;
}
const gfx::BufferFormat buffer_format = viz::BufferFormat(format);
switch (buffer_format) {
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::BGRA_8888:
case gfx::BufferFormat::RGBA_F16:
case gfx::BufferFormat::R_8:
case gfx::BufferFormat::BGRA_1010102:
case gfx::BufferFormat::RGBA_1010102:
break;
default:
continue;
}
if (!gpu_memory_buffer_formats_.Has(buffer_format))
continue;
info.allow_scanout = true;
info.buffer_format = buffer_format;
DCHECK_EQ(info.image_internal_format,
gl::BufferFormatToGLInternalFormat(buffer_format));
if (base::Contains(gpu_preferences.texture_target_exception_list,
gfx::BufferUsageAndFormat(gfx::BufferUsage::SCANOUT,
buffer_format))) {
info.target_for_scanout = gpu::GetPlatformSpecificTextureTarget();
}
}
}
SharedImageBackingFactoryGLTexture::~SharedImageBackingFactoryGLTexture() =
default;
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
bool is_passthrough)
: SharedImageBacking(mailbox,
format,
size,
color_space,
surface_origin,
alpha_type,
usage,
EstimatedSize(format, size),
false /* is_thread_safe */),
is_passthrough_(is_passthrough) {}
SharedImageBackingGLTexture::~SharedImageBackingGLTexture() {
if (IsPassthrough()) {
if (passthrough_texture_) {
if (!have_context())
passthrough_texture_->MarkContextLost();
passthrough_texture_.reset();
}
bool is_thread_safe) {
if (is_thread_safe) {
return MakeEglImageBacking(mailbox, format, size, color_space,
surface_origin, alpha_type, usage);
} else {
if (texture_) {
texture_->RemoveLightweightRef(have_context());
texture_ = nullptr;
}
return CreateSharedImageInternal(mailbox, format, surface_handle, size,
color_space, surface_origin, alpha_type,
usage, base::span<const uint8_t>());
}
}
GLenum SharedImageBackingGLTexture::GetGLTarget() const {
return texture_ ? texture_->target() : passthrough_texture_->target();
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
base::span<const uint8_t> pixel_data) {
return CreateSharedImageInternal(mailbox, format, kNullSurfaceHandle, size,
color_space, surface_origin, alpha_type,
usage, pixel_data);
}
GLuint SharedImageBackingGLTexture::GetGLServiceId() const {
return texture_ ? texture_->service_id() : passthrough_texture_->service_id();
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImage(
const Mailbox& mailbox,
int client_id,
gfx::GpuMemoryBufferHandle handle,
gfx::BufferFormat buffer_format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage) {
if (!gpu_memory_buffer_formats_.Has(buffer_format)) {
LOG(ERROR) << "CreateSharedImage: unsupported buffer format "
<< gfx::BufferFormatToString(buffer_format);
return nullptr;
}
void SharedImageBackingGLTexture::OnMemoryDump(
const std::string& dump_name,
base::trace_event::MemoryAllocatorDump* dump,
base::trace_event::ProcessMemoryDump* pmd,
uint64_t client_tracing_id) {
const auto client_guid = GetSharedImageGUIDForTracing(mailbox());
if (!IsPassthrough()) {
const auto service_guid =
gl::GetGLTextureServiceGUIDForTracing(texture_->service_id());
pmd->CreateSharedGlobalAllocatorDump(service_guid);
pmd->AddOwnershipEdge(client_guid, service_guid, /* importance */ 2);
texture_->DumpLevelMemory(pmd, client_tracing_id, dump_name);
if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, buffer_format)) {
LOG(ERROR) << "Invalid image size " << size.ToString() << " for "
<< gfx::BufferFormatToString(buffer_format);
return nullptr;
}
}
gfx::Rect SharedImageBackingGLTexture::ClearedRect() const {
if (IsPassthrough()) {
// This backing is used exclusively with ANGLE which handles clear tracking
// internally. Act as though the texture is always cleared.
return gfx::Rect(size());
} else {
return texture_->GetLevelClearedRect(texture_->target(), 0);
const gfx::GpuMemoryBufferType handle_type = handle.type;
GLenum target =
(handle_type == gfx::SHARED_MEMORY_BUFFER ||
!NativeBufferNeedsPlatformSpecificTextureTarget(buffer_format))
? GL_TEXTURE_2D
: gpu::GetPlatformSpecificTextureTarget();
scoped_refptr<gl::GLImage> image = MakeGLImage(
client_id, std::move(handle), buffer_format, surface_handle, size);
if (!image) {
LOG(ERROR) << "Failed to create image.";
return nullptr;
}
}
// If we decide to use GL_TEXTURE_2D at the target for a native buffer, we
// would like to verify that it will actually work. If the image expects to be
// copied, there is no way to do this verification here, because copying is
// done lazily after the SharedImage is created, so require that the image is
// bindable. Currently NativeBufferNeedsPlatformSpecificTextureTarget can
// only return false on Chrome OS where GLImageNativePixmap is used which is
// always bindable.
#if DCHECK_IS_ON()
bool texture_2d_support = false;
#if defined(OS_MAC)
// If the PlatformSpecificTextureTarget on Mac is GL_TEXTURE_2D, this is
// supported.
texture_2d_support =
(gpu::GetPlatformSpecificTextureTarget() == GL_TEXTURE_2D);
#endif // defined(OS_MAC)
DCHECK(handle_type == gfx::SHARED_MEMORY_BUFFER || target != GL_TEXTURE_2D ||
texture_2d_support || image->ShouldBindOrCopy() == gl::GLImage::BIND);
#endif // DCHECK_IS_ON()
if (color_space.IsValid())
image->SetColorSpace(color_space);
if (usage & SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX)
image->DisableInUseByWindowServer();
viz::ResourceFormat format = viz::GetResourceFormat(buffer_format);
const bool for_framebuffer_attachment =
(usage & (SHARED_IMAGE_USAGE_RASTER |
SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT)) != 0;
const bool is_rgb_emulation = (usage & SHARED_IMAGE_USAGE_RGB_EMULATION) != 0;
void SharedImageBackingGLTexture::SetClearedRect(
const gfx::Rect& cleared_rect) {
if (!IsPassthrough())
texture_->SetLevelClearedRect(texture_->target(), 0, cleared_rect);
InitializeGLTextureParams params;
params.target = target;
params.internal_format =
is_rgb_emulation ? GL_RGB : image->GetInternalFormat();
params.format = is_rgb_emulation ? GL_RGB : image->GetDataFormat();
params.type = image->GetDataType();
params.is_cleared = true;
params.is_rgb_emulation = is_rgb_emulation;
params.framebuffer_attachment_angle =
for_framebuffer_attachment && texture_usage_angle_;
return std::make_unique<SharedImageBackingGLImage>(
image, mailbox, format, size, color_space, surface_origin, alpha_type,
usage, params, attribs, use_passthrough_);
}
bool SharedImageBackingGLTexture::ProduceLegacyMailbox(
MailboxManager* mailbox_manager) {
if (IsPassthrough())
mailbox_manager->ProduceTexture(mailbox(), passthrough_texture_.get());
else
mailbox_manager->ProduceTexture(mailbox(), texture_);
return true;
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImageForTest(
const Mailbox& mailbox,
GLenum target,
GLuint service_id,
bool is_cleared,
viz::ResourceFormat format,
const gfx::Size& size,
uint32_t usage) {
auto result = std::make_unique<SharedImageBackingGLTexture>(
mailbox, format, size, gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, usage, false /* is_passthrough */);
InitializeGLTextureParams params;
params.target = target;
params.internal_format = viz::GLInternalFormat(format);
params.format = viz::GLDataFormat(format);
params.type = viz::GLDataType(format);
params.is_cleared = is_cleared;
result->InitializeGLTexture(service_id, params);
return std::move(result);
}
std::unique_ptr<SharedImageRepresentationGLTexture>
SharedImageBackingGLTexture::ProduceGLTexture(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
DCHECK(texture_);
return std::make_unique<SharedImageRepresentationGLTextureImpl>(
manager, this, nullptr, tracker, texture_);
scoped_refptr<gl::GLImage> SharedImageBackingFactoryGLTexture::MakeGLImage(
int client_id,
gfx::GpuMemoryBufferHandle handle,
gfx::BufferFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size) {
if (handle.type == gfx::SHARED_MEMORY_BUFFER) {
if (!base::IsValueInRangeForNumericType<size_t>(handle.stride))
return nullptr;
auto image = base::MakeRefCounted<gl::GLImageSharedMemory>(size);
if (!image->Initialize(handle.region, handle.id, format, handle.offset,
handle.stride)) {
return nullptr;
}
return image;
}
if (!image_factory_)
return nullptr;
return image_factory_->CreateImageForGpuMemoryBuffer(
std::move(handle), size, format, client_id, surface_handle);
}
std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
SharedImageBackingGLTexture::ProduceGLTexturePassthrough(
SharedImageManager* manager,
MemoryTypeTracker* tracker) {
DCHECK(passthrough_texture_);
return std::make_unique<SharedImageRepresentationGLTexturePassthroughImpl>(
manager, this, nullptr, tracker, passthrough_texture_);
bool SharedImageBackingFactoryGLTexture::CanImportGpuMemoryBuffer(
gfx::GpuMemoryBufferType memory_buffer_type) {
// SharedImageFactory may call CanImportGpuMemoryBuffer() in all other
// SharedImageBackingFactory implementations except this one.
NOTREACHED();
return true;
}
std::unique_ptr<SharedImageRepresentationDawn>
SharedImageBackingGLTexture::ProduceDawn(SharedImageManager* manager,
MemoryTypeTracker* tracker,
WGPUDevice device) {
if (!factory()) {
DLOG(ERROR) << "No SharedImageFactory to create a dawn representation.";
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::MakeEglImageBacking(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage) {
#if defined(OS_ANDROID)
const FormatInfo& format_info = format_info_[format];
if (!format_info.enabled) {
DLOG(ERROR) << "MakeEglImageBacking: invalid format";
return nullptr;
}
return SharedImageBackingGLCommon::ProduceDawnCommon(
factory(), manager, tracker, device, this, IsPassthrough());
}
DCHECK(!(usage & SHARED_IMAGE_USAGE_SCANOUT));
std::unique_ptr<SharedImageRepresentationSkia>
SharedImageBackingGLTexture::ProduceSkia(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
scoped_refptr<SharedContextState> context_state) {
if (!cached_promise_texture_) {
GrBackendTexture backend_texture;
GetGrBackendTexture(context_state->feature_info(), GetGLTarget(), size(),
GetGLServiceId(), format(), &backend_texture);
cached_promise_texture_ = SkPromiseImageTexture::Make(backend_texture);
}
return std::make_unique<SharedImageRepresentationSkiaImpl>(
manager, this, nullptr, std::move(context_state), cached_promise_texture_,
tracker);
if (size.width() < 1 || size.height() < 1 ||
size.width() > max_texture_size_ || size.height() > max_texture_size_) {
DLOG(ERROR) << "MakeEglImageBacking: Invalid size";
return nullptr;
}
// Calculate SharedImage size in bytes.
size_t estimated_size;
if (!viz::ResourceSizes::MaybeSizeInBytes(size, format, &estimated_size)) {
DLOG(ERROR) << "MakeEglImageBacking: Failed to calculate SharedImage size";
return nullptr;
}
return std::make_unique<SharedImageBackingEglImage>(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
estimated_size, format_info.gl_format, format_info.gl_type,
batch_access_manager_, workarounds_, use_passthrough_);
#else
return nullptr;
#endif
}
void SharedImageBackingGLTexture::Update(
std::unique_ptr<gfx::GpuFence> in_fence) {}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImageInternal(
const Mailbox& mailbox,
viz::ResourceFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
base::span<const uint8_t> pixel_data) {
const FormatInfo& format_info = format_info_[format];
if (!format_info.enabled) {
LOG(ERROR) << "CreateSharedImage: invalid format";
return nullptr;
}
void SharedImageBackingGLTexture::InitializeGLTexture(
GLuint service_id,
const InitializeGLTextureParams& params) {
SharedImageBackingGLCommon::MakeTextureAndSetParameters(
params.target, service_id, params.framebuffer_attachment_angle,
IsPassthrough() ? &passthrough_texture_ : nullptr,
IsPassthrough() ? nullptr : &texture_);
if (IsPassthrough()) {
passthrough_texture_->SetEstimatedSize(EstimatedSize(format(), size()));
#if defined(OS_MAC)
const bool use_buffer =
usage & (SHARED_IMAGE_USAGE_SCANOUT | SHARED_IMAGE_USAGE_WEBGPU);
#else
const bool use_buffer = usage & SHARED_IMAGE_USAGE_SCANOUT;
#endif
if (use_buffer && !format_info.allow_scanout) {
LOG(ERROR) << "CreateSharedImage: SCANOUT shared images unavailable. "
"Buffer format= "
<< gfx::BufferFormatToString(format_info.buffer_format);
return nullptr;
}
if (size.width() < 1 || size.height() < 1 ||
size.width() > max_texture_size_ || size.height() > max_texture_size_) {
LOG(ERROR) << "CreateSharedImage: invalid size";
return nullptr;
}
GLenum target = use_buffer ? format_info.target_for_scanout : GL_TEXTURE_2D;
// If we have initial data to upload, ensure it is sized appropriately.
if (!pixel_data.empty()) {
if (format_info.is_compressed) {
const char* error_message = "unspecified";
if (!gles2::ValidateCompressedTexDimensions(
target, 0 /* level */, size.width(), size.height(), 1 /* depth */,
format_info.image_internal_format, &error_message)) {
LOG(ERROR) << "CreateSharedImage: "
"ValidateCompressedTexDimensionsFailed with error: "
<< error_message;
return nullptr;
}
GLsizei bytes_required = 0;
if (!gles2::GetCompressedTexSizeInBytes(
nullptr /* function_name */, size.width(), size.height(),
1 /* depth */, format_info.image_internal_format, &bytes_required,
nullptr /* error_state */)) {
LOG(ERROR) << "CreateSharedImage: Unable to compute required size for "
"initial texture upload.";
return nullptr;
}
if (bytes_required < 0 ||
pixel_data.size() != static_cast<size_t>(bytes_required)) {
LOG(ERROR) << "CreateSharedImage: Initial data does not have expected "
"size.";
return nullptr;
}
} else {
texture_->SetLevelInfo(params.target, 0, params.internal_format,
size().width(), size().height(), 1, 0, params.format,
params.type,
params.is_cleared ? gfx::Rect(size()) : gfx::Rect());
texture_->SetImmutable(true, params.has_immutable_storage);
uint32_t bytes_required;
uint32_t unpadded_row_size = 0u;
uint32_t padded_row_size = 0u;
if (!gles2::GLES2Util::ComputeImageDataSizes(
size.width(), size.height(), 1 /* depth */, format_info.gl_format,
format_info.gl_type, 4 /* alignment */, &bytes_required,
&unpadded_row_size, &padded_row_size)) {
LOG(ERROR) << "CreateSharedImage: Unable to compute required size for "
"initial texture upload.";
return nullptr;
}
// The GL spec, used in the computation for required bytes in the function
// above, assumes no padding is required for the last row in the image.
// But the client data does include this padding, so we add it for the
// data validation check here.
uint32_t padding = padded_row_size - unpadded_row_size;
bytes_required += padding;
if (pixel_data.size() != bytes_required) {
LOG(ERROR) << "CreateSharedImage: Initial data does not have expected "
"size.";
return nullptr;
}
}
}
const bool for_framebuffer_attachment =
(usage & (SHARED_IMAGE_USAGE_RASTER |
SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT)) != 0;
scoped_refptr<gl::GLImage> image;
// TODO(piman): We pretend the texture was created in an ES2 context, so that
// it can be used in other ES2 contexts, and so we have to pass gl_format as
// the internal format in the LevelInfo. https://crbug.com/628064
GLuint level_info_internal_format = format_info.gl_format;
bool is_cleared = false;
// |scoped_progress_reporter| will notify |progress_reporter_| upon
// construction and destruction. We limit the scope so that progress is
// reported immediately after allocation/upload and before other GL
// operations.
if (use_buffer) {
{
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
image = image_factory_->CreateAnonymousImage(
size, format_info.buffer_format, gfx::BufferUsage::SCANOUT,
surface_handle, &is_cleared);
}
// Scanout images have different constraints than GL images and might fail
// to allocate even if GL images can be created.
if (!image) {
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
// TODO(dcastagna): Use BufferUsage::GPU_READ_WRITE instead
// BufferUsage::GPU_READ once we add it.
image = image_factory_->CreateAnonymousImage(
size, format_info.buffer_format, gfx::BufferUsage::GPU_READ,
surface_handle, &is_cleared);
}
// The allocated image should not require copy.
if (!image || image->ShouldBindOrCopy() != gl::GLImage::BIND) {
LOG(ERROR) << "CreateSharedImage: Failed to create bindable image";
return nullptr;
}
level_info_internal_format = image->GetInternalFormat();
if (color_space.IsValid())
image->SetColorSpace(color_space);
if (usage & SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX)
image->DisableInUseByWindowServer();
}
InitializeGLTextureParams params;
params.target = target;
params.internal_format = level_info_internal_format;
params.format = format_info.gl_format;
params.type = format_info.gl_type;
params.is_cleared = pixel_data.empty() ? is_cleared : true;
params.has_immutable_storage = !image && format_info.supports_storage;
params.framebuffer_attachment_angle =
for_framebuffer_attachment && texture_usage_angle_;
if (image) {
DCHECK(!format_info.swizzle);
auto result = std::make_unique<SharedImageBackingGLImage>(
image, mailbox, format, size, color_space, surface_origin, alpha_type,
usage, params, attribs, use_passthrough_);
if (!pixel_data.empty()) {
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
result->InitializePixels(format_info.adjusted_format, format_info.gl_type,
pixel_data.data());
}
return std::move(result);
} else {
auto result = std::make_unique<SharedImageBackingGLTexture>(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
use_passthrough_);
result->InitializeGLTexture(0, params);
gl::GLApi* api = gl::g_current_gl_context;
ScopedRestoreTexture scoped_restore(api, target);
api->glBindTextureFn(target, result->GetGLServiceId());
if (format_info.supports_storage) {
{
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glTexStorage2DEXTFn(target, 1, format_info.storage_internal_format,
size.width(), size.height());
}
}
void SharedImageBackingGLTexture::SetCompatibilitySwizzle(
const gles2::Texture::CompatibilitySwizzle* swizzle) {
if (!IsPassthrough())
texture_->SetCompatibilitySwizzle(swizzle);
if (!pixel_data.empty()) {
ScopedResetAndRestoreUnpackState scoped_unpack_state(
api, attribs, true /* uploading_data */);
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glTexSubImage2DFn(target, 0, 0, 0, size.width(), size.height(),
format_info.adjusted_format, format_info.gl_type,
pixel_data.data());
}
} else if (format_info.is_compressed) {
ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs,
!pixel_data.empty());
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glCompressedTexImage2DFn(
target, 0, format_info.image_internal_format, size.width(),
size.height(), 0, pixel_data.size(), pixel_data.data());
} else {
ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs,
!pixel_data.empty());
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glTexImage2DFn(target, 0, format_info.image_internal_format,
size.width(), size.height(), 0,
format_info.adjusted_format, format_info.gl_type,
pixel_data.data());
}
result->SetCompatibilitySwizzle(format_info.swizzle);
return std::move(result);
}
}
///////////////////////////////////////////////////////////////////////////////
// SharedImageBackingFactoryGLTexture::FormatInfo
SharedImageBackingFactoryGLTexture::FormatInfo::FormatInfo() = default;
SharedImageBackingFactoryGLTexture::FormatInfo::~FormatInfo() = default;
} // namespace gpu
......@@ -44,7 +44,6 @@
#include "ui/gl/gl_image_shared_memory.h"
#include "ui/gl/gl_implementation.h"
#include "ui/gl/gl_version_info.h"
#include "ui/gl/progress_reporter.h"
#include "ui/gl/scoped_binders.h"
#include "ui/gl/shared_gl_fence_egl.h"
#include "ui/gl/trace_util.h"
......@@ -54,14 +53,19 @@
#include "gpu/command_buffer/service/shared_image_batch_access_manager.h"
#endif
#if defined(OS_MAC)
#include "gpu/command_buffer/service/shared_image_backing_factory_iosurface.h"
#endif
namespace gpu {
namespace {
using ScopedResetAndRestoreUnpackState =
SharedImageBackingGLCommon::ScopedResetAndRestoreUnpackState;
using ScopedRestoreTexture = SharedImageBackingGLCommon::ScopedRestoreTexture;
size_t EstimatedSize(viz::ResourceFormat format, const gfx::Size& size) {
size_t estimated_size = 0;
viz::ResourceSizes::MaybeSizeInBytes(size, format, &estimated_size);
return estimated_size;
}
using InitializeGLTextureParams =
SharedImageBackingGLCommon::InitializeGLTextureParams;
......@@ -69,551 +73,163 @@ using InitializeGLTextureParams =
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////
// SharedImageBackingFactoryGLTexture
SharedImageBackingFactoryGLTexture::SharedImageBackingFactoryGLTexture(
const GpuPreferences& gpu_preferences,
const GpuDriverBugWorkarounds& workarounds,
const GpuFeatureInfo& gpu_feature_info,
ImageFactory* image_factory,
SharedImageBatchAccessManager* batch_access_manager,
gl::ProgressReporter* progress_reporter)
: use_passthrough_(gpu_preferences.use_passthrough_cmd_decoder &&
gles2::PassthroughCommandDecoderSupported()),
image_factory_(image_factory),
workarounds_(workarounds),
progress_reporter_(progress_reporter) {
#if defined(OS_ANDROID)
batch_access_manager_ = batch_access_manager;
#endif
gl::GLApi* api = gl::g_current_gl_context;
api->glGetIntegervFn(GL_MAX_TEXTURE_SIZE, &max_texture_size_);
// When the passthrough command decoder is used, the max_texture_size
// workaround is implemented by ANGLE. Trying to adjust the max size here
// would cause discrepency between what we think the max size is and what
// ANGLE tells the clients.
if (!use_passthrough_ && workarounds.max_texture_size) {
max_texture_size_ =
std::min(max_texture_size_, workarounds.max_texture_size);
}
// Ensure max_texture_size_ is less than INT_MAX so that gfx::Rect and friends
// can be used to accurately represent all valid sub-rects, with overflow
// cases, clamped to INT_MAX, always invalid.
max_texture_size_ = std::min(max_texture_size_, INT_MAX - 1);
// SharedImageBackingGLTexture
// TODO(piman): Can we extract the logic out of FeatureInfo?
scoped_refptr<gles2::FeatureInfo> feature_info =
new gles2::FeatureInfo(workarounds, gpu_feature_info);
feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2,
use_passthrough_, gles2::DisallowedFeatures());
gpu_memory_buffer_formats_ =
feature_info->feature_flags().gpu_memory_buffer_formats;
texture_usage_angle_ = feature_info->feature_flags().angle_texture_usage;
attribs.es3_capable = feature_info->IsES3Capable();
attribs.desktop_gl = !feature_info->gl_version_info().is_es;
// Can't use the value from feature_info, as we unconditionally enable this
// extension, and assume it can't be used if PBOs are not used (which isn't
// true for Skia used direclty against GL).
attribs.supports_unpack_subimage =
gl::g_current_gl_driver->ext.b_GL_EXT_unpack_subimage;
bool enable_texture_storage =
feature_info->feature_flags().ext_texture_storage;
bool enable_scanout_images =
(image_factory_ && image_factory_->SupportsCreateAnonymousImage());
const gles2::Validators* validators = feature_info->validators();
for (int i = 0; i <= viz::RESOURCE_FORMAT_MAX; ++i) {
auto format = static_cast<viz::ResourceFormat>(i);
FormatInfo& info = format_info_[i];
if (!viz::GLSupportsFormat(format))
continue;
const GLuint image_internal_format = viz::GLInternalFormat(format);
const GLenum gl_format = viz::GLDataFormat(format);
const GLenum gl_type = viz::GLDataType(format);
const bool uncompressed_format_valid =
validators->texture_internal_format.IsValid(image_internal_format) &&
validators->texture_format.IsValid(gl_format);
const bool compressed_format_valid =
validators->compressed_texture_format.IsValid(image_internal_format);
if ((uncompressed_format_valid || compressed_format_valid) &&
validators->pixel_type.IsValid(gl_type)) {
info.enabled = true;
info.is_compressed = compressed_format_valid;
info.gl_format = gl_format;
info.gl_type = gl_type;
info.swizzle = gles2::TextureManager::GetCompatibilitySwizzle(
feature_info.get(), gl_format);
info.image_internal_format =
gles2::TextureManager::AdjustTexInternalFormat(
feature_info.get(), image_internal_format, gl_type);
info.adjusted_format =
gles2::TextureManager::AdjustTexFormat(feature_info.get(), gl_format);
}
if (!info.enabled)
continue;
if (enable_texture_storage && !info.is_compressed) {
GLuint storage_internal_format = viz::TextureStorageFormat(format);
if (validators->texture_internal_format_storage.IsValid(
storage_internal_format)) {
info.supports_storage = true;
info.storage_internal_format =
gles2::TextureManager::AdjustTexStorageFormat(
feature_info.get(), storage_internal_format);
}
}
if (!info.enabled || !enable_scanout_images ||
!IsGpuMemoryBufferFormatSupported(format)) {
continue;
}
const gfx::BufferFormat buffer_format = viz::BufferFormat(format);
switch (buffer_format) {
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::BGRA_8888:
case gfx::BufferFormat::RGBA_F16:
case gfx::BufferFormat::R_8:
case gfx::BufferFormat::BGRA_1010102:
case gfx::BufferFormat::RGBA_1010102:
break;
default:
continue;
}
if (!gpu_memory_buffer_formats_.Has(buffer_format))
continue;
info.allow_scanout = true;
info.buffer_format = buffer_format;
DCHECK_EQ(info.image_internal_format,
gl::BufferFormatToGLInternalFormat(buffer_format));
if (base::Contains(gpu_preferences.texture_target_exception_list,
gfx::BufferUsageAndFormat(gfx::BufferUsage::SCANOUT,
buffer_format))) {
info.target_for_scanout = gpu::GetPlatformSpecificTextureTarget();
}
}
}
SharedImageBackingFactoryGLTexture::~SharedImageBackingFactoryGLTexture() =
default;
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImage(
SharedImageBackingGLTexture::SharedImageBackingGLTexture(
const Mailbox& mailbox,
viz::ResourceFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
bool is_thread_safe) {
if (is_thread_safe) {
return MakeEglImageBacking(mailbox, format, size, color_space,
surface_origin, alpha_type, usage);
} else {
return CreateSharedImageInternal(mailbox, format, surface_handle, size,
color_space, surface_origin, alpha_type,
usage, base::span<const uint8_t>());
bool is_passthrough)
: SharedImageBacking(mailbox,
format,
size,
color_space,
surface_origin,
alpha_type,
usage,
EstimatedSize(format, size),
false /* is_thread_safe */),
is_passthrough_(is_passthrough) {}
SharedImageBackingGLTexture::~SharedImageBackingGLTexture() {
if (IsPassthrough()) {
if (passthrough_texture_) {
if (!have_context())
passthrough_texture_->MarkContextLost();
passthrough_texture_.reset();
}
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
base::span<const uint8_t> pixel_data) {
return CreateSharedImageInternal(mailbox, format, kNullSurfaceHandle, size,
color_space, surface_origin, alpha_type,
usage, pixel_data);
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImage(
const Mailbox& mailbox,
int client_id,
gfx::GpuMemoryBufferHandle handle,
gfx::BufferFormat buffer_format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage) {
if (!gpu_memory_buffer_formats_.Has(buffer_format)) {
LOG(ERROR) << "CreateSharedImage: unsupported buffer format "
<< gfx::BufferFormatToString(buffer_format);
return nullptr;
}
if (!gpu::IsImageSizeValidForGpuMemoryBufferFormat(size, buffer_format)) {
LOG(ERROR) << "Invalid image size " << size.ToString() << " for "
<< gfx::BufferFormatToString(buffer_format);
return nullptr;
} else {
if (texture_) {
texture_->RemoveLightweightRef(have_context());
texture_ = nullptr;
}
const gfx::GpuMemoryBufferType handle_type = handle.type;
GLenum target =
(handle_type == gfx::SHARED_MEMORY_BUFFER ||
!NativeBufferNeedsPlatformSpecificTextureTarget(buffer_format))
? GL_TEXTURE_2D
: gpu::GetPlatformSpecificTextureTarget();
scoped_refptr<gl::GLImage> image = MakeGLImage(
client_id, std::move(handle), buffer_format, surface_handle, size);
if (!image) {
LOG(ERROR) << "Failed to create image.";
return nullptr;
}
// If we decide to use GL_TEXTURE_2D at the target for a native buffer, we
// would like to verify that it will actually work. If the image expects to be
// copied, there is no way to do this verification here, because copying is
// done lazily after the SharedImage is created, so require that the image is
// bindable. Currently NativeBufferNeedsPlatformSpecificTextureTarget can
// only return false on Chrome OS where GLImageNativePixmap is used which is
// always bindable.
#if DCHECK_IS_ON()
bool texture_2d_support = false;
#if defined(OS_MAC)
// If the PlatformSpecificTextureTarget on Mac is GL_TEXTURE_2D, this is
// supported.
texture_2d_support =
(gpu::GetPlatformSpecificTextureTarget() == GL_TEXTURE_2D);
#endif // defined(OS_MAC)
DCHECK(handle_type == gfx::SHARED_MEMORY_BUFFER || target != GL_TEXTURE_2D ||
texture_2d_support || image->ShouldBindOrCopy() == gl::GLImage::BIND);
#endif // DCHECK_IS_ON()
if (color_space.IsValid())
image->SetColorSpace(color_space);
if (usage & SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX)
image->DisableInUseByWindowServer();
viz::ResourceFormat format = viz::GetResourceFormat(buffer_format);
const bool for_framebuffer_attachment =
(usage & (SHARED_IMAGE_USAGE_RASTER |
SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT)) != 0;
const bool is_rgb_emulation = (usage & SHARED_IMAGE_USAGE_RGB_EMULATION) != 0;
}
InitializeGLTextureParams params;
params.target = target;
params.internal_format =
is_rgb_emulation ? GL_RGB : image->GetInternalFormat();
params.format = is_rgb_emulation ? GL_RGB : image->GetDataFormat();
params.type = image->GetDataType();
params.is_cleared = true;
params.is_rgb_emulation = is_rgb_emulation;
params.framebuffer_attachment_angle =
for_framebuffer_attachment && texture_usage_angle_;
return std::make_unique<SharedImageBackingGLImage>(
image, mailbox, format, size, color_space, surface_origin, alpha_type,
usage, params, attribs, use_passthrough_);
GLenum SharedImageBackingGLTexture::GetGLTarget() const {
return texture_ ? texture_->target() : passthrough_texture_->target();
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImageForTest(
const Mailbox& mailbox,
GLenum target,
GLuint service_id,
bool is_cleared,
viz::ResourceFormat format,
const gfx::Size& size,
uint32_t usage) {
auto result = std::make_unique<SharedImageBackingGLTexture>(
mailbox, format, size, gfx::ColorSpace(), kTopLeft_GrSurfaceOrigin,
kPremul_SkAlphaType, usage, false /* is_passthrough */);
InitializeGLTextureParams params;
params.target = target;
params.internal_format = viz::GLInternalFormat(format);
params.format = viz::GLDataFormat(format);
params.type = viz::GLDataType(format);
params.is_cleared = is_cleared;
result->InitializeGLTexture(service_id, params);
return std::move(result);
GLuint SharedImageBackingGLTexture::GetGLServiceId() const {
return texture_ ? texture_->service_id() : passthrough_texture_->service_id();
}
scoped_refptr<gl::GLImage> SharedImageBackingFactoryGLTexture::MakeGLImage(
int client_id,
gfx::GpuMemoryBufferHandle handle,
gfx::BufferFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size) {
if (handle.type == gfx::SHARED_MEMORY_BUFFER) {
if (!base::IsValueInRangeForNumericType<size_t>(handle.stride))
return nullptr;
auto image = base::MakeRefCounted<gl::GLImageSharedMemory>(size);
if (!image->Initialize(handle.region, handle.id, format, handle.offset,
handle.stride)) {
return nullptr;
void SharedImageBackingGLTexture::OnMemoryDump(
const std::string& dump_name,
base::trace_event::MemoryAllocatorDump* dump,
base::trace_event::ProcessMemoryDump* pmd,
uint64_t client_tracing_id) {
const auto client_guid = GetSharedImageGUIDForTracing(mailbox());
if (!IsPassthrough()) {
const auto service_guid =
gl::GetGLTextureServiceGUIDForTracing(texture_->service_id());
pmd->CreateSharedGlobalAllocatorDump(service_guid);
pmd->AddOwnershipEdge(client_guid, service_guid, /* importance */ 2);
texture_->DumpLevelMemory(pmd, client_tracing_id, dump_name);
}
}
return image;
gfx::Rect SharedImageBackingGLTexture::ClearedRect() const {
if (IsPassthrough()) {
// This backing is used exclusively with ANGLE which handles clear tracking
// internally. Act as though the texture is always cleared.
return gfx::Rect(size());
} else {
return texture_->GetLevelClearedRect(texture_->target(), 0);
}
}
if (!image_factory_)
return nullptr;
return image_factory_->CreateImageForGpuMemoryBuffer(
std::move(handle), size, format, client_id, surface_handle);
void SharedImageBackingGLTexture::SetClearedRect(
const gfx::Rect& cleared_rect) {
if (!IsPassthrough())
texture_->SetLevelClearedRect(texture_->target(), 0, cleared_rect);
}
bool SharedImageBackingFactoryGLTexture::CanImportGpuMemoryBuffer(
gfx::GpuMemoryBufferType memory_buffer_type) {
// SharedImageFactory may call CanImportGpuMemoryBuffer() in all other
// SharedImageBackingFactory implementations except this one.
NOTREACHED();
bool SharedImageBackingGLTexture::ProduceLegacyMailbox(
MailboxManager* mailbox_manager) {
if (IsPassthrough())
mailbox_manager->ProduceTexture(mailbox(), passthrough_texture_.get());
else
mailbox_manager->ProduceTexture(mailbox(), texture_);
return true;
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::MakeEglImageBacking(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage) {
#if defined(OS_ANDROID)
const FormatInfo& format_info = format_info_[format];
if (!format_info.enabled) {
DLOG(ERROR) << "MakeEglImageBacking: invalid format";
return nullptr;
}
DCHECK(!(usage & SHARED_IMAGE_USAGE_SCANOUT));
if (size.width() < 1 || size.height() < 1 ||
size.width() > max_texture_size_ || size.height() > max_texture_size_) {
DLOG(ERROR) << "MakeEglImageBacking: Invalid size";
return nullptr;
}
// Calculate SharedImage size in bytes.
size_t estimated_size;
if (!viz::ResourceSizes::MaybeSizeInBytes(size, format, &estimated_size)) {
DLOG(ERROR) << "MakeEglImageBacking: Failed to calculate SharedImage size";
return nullptr;
}
return std::make_unique<SharedImageBackingEglImage>(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
estimated_size, format_info.gl_format, format_info.gl_type,
batch_access_manager_, workarounds_, use_passthrough_);
#else
return nullptr;
#endif
std::unique_ptr<SharedImageRepresentationGLTexture>
SharedImageBackingGLTexture::ProduceGLTexture(SharedImageManager* manager,
MemoryTypeTracker* tracker) {
DCHECK(texture_);
return std::make_unique<SharedImageRepresentationGLTextureImpl>(
manager, this, nullptr, tracker, texture_);
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryGLTexture::CreateSharedImageInternal(
const Mailbox& mailbox,
viz::ResourceFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
GrSurfaceOrigin surface_origin,
SkAlphaType alpha_type,
uint32_t usage,
base::span<const uint8_t> pixel_data) {
const FormatInfo& format_info = format_info_[format];
if (!format_info.enabled) {
LOG(ERROR) << "CreateSharedImage: invalid format";
return nullptr;
}
#if defined(OS_MAC)
const bool use_buffer =
usage & (SHARED_IMAGE_USAGE_SCANOUT | SHARED_IMAGE_USAGE_WEBGPU);
#else
const bool use_buffer = usage & SHARED_IMAGE_USAGE_SCANOUT;
#endif
if (use_buffer && !format_info.allow_scanout) {
LOG(ERROR) << "CreateSharedImage: SCANOUT shared images unavailable. "
"Buffer format= "
<< gfx::BufferFormatToString(format_info.buffer_format);
return nullptr;
}
if (size.width() < 1 || size.height() < 1 ||
size.width() > max_texture_size_ || size.height() > max_texture_size_) {
LOG(ERROR) << "CreateSharedImage: invalid size";
return nullptr;
}
GLenum target = use_buffer ? format_info.target_for_scanout : GL_TEXTURE_2D;
// If we have initial data to upload, ensure it is sized appropriately.
if (!pixel_data.empty()) {
if (format_info.is_compressed) {
const char* error_message = "unspecified";
if (!gles2::ValidateCompressedTexDimensions(
target, 0 /* level */, size.width(), size.height(), 1 /* depth */,
format_info.image_internal_format, &error_message)) {
LOG(ERROR) << "CreateSharedImage: "
"ValidateCompressedTexDimensionsFailed with error: "
<< error_message;
return nullptr;
}
GLsizei bytes_required = 0;
if (!gles2::GetCompressedTexSizeInBytes(
nullptr /* function_name */, size.width(), size.height(),
1 /* depth */, format_info.image_internal_format, &bytes_required,
nullptr /* error_state */)) {
LOG(ERROR) << "CreateSharedImage: Unable to compute required size for "
"initial texture upload.";
return nullptr;
}
if (bytes_required < 0 ||
pixel_data.size() != static_cast<size_t>(bytes_required)) {
LOG(ERROR) << "CreateSharedImage: Initial data does not have expected "
"size.";
return nullptr;
}
} else {
uint32_t bytes_required;
uint32_t unpadded_row_size = 0u;
uint32_t padded_row_size = 0u;
if (!gles2::GLES2Util::ComputeImageDataSizes(
size.width(), size.height(), 1 /* depth */, format_info.gl_format,
format_info.gl_type, 4 /* alignment */, &bytes_required,
&unpadded_row_size, &padded_row_size)) {
LOG(ERROR) << "CreateSharedImage: Unable to compute required size for "
"initial texture upload.";
return nullptr;
}
// The GL spec, used in the computation for required bytes in the function
// above, assumes no padding is required for the last row in the image.
// But the client data does include this padding, so we add it for the
// data validation check here.
uint32_t padding = padded_row_size - unpadded_row_size;
bytes_required += padding;
if (pixel_data.size() != bytes_required) {
LOG(ERROR) << "CreateSharedImage: Initial data does not have expected "
"size.";
return nullptr;
}
}
}
const bool for_framebuffer_attachment =
(usage & (SHARED_IMAGE_USAGE_RASTER |
SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT)) != 0;
scoped_refptr<gl::GLImage> image;
// TODO(piman): We pretend the texture was created in an ES2 context, so that
// it can be used in other ES2 contexts, and so we have to pass gl_format as
// the internal format in the LevelInfo. https://crbug.com/628064
GLuint level_info_internal_format = format_info.gl_format;
bool is_cleared = false;
std::unique_ptr<SharedImageRepresentationGLTexturePassthrough>
SharedImageBackingGLTexture::ProduceGLTexturePassthrough(
SharedImageManager* manager,
MemoryTypeTracker* tracker) {
DCHECK(passthrough_texture_);
return std::make_unique<SharedImageRepresentationGLTexturePassthroughImpl>(
manager, this, nullptr, tracker, passthrough_texture_);
}
// |scoped_progress_reporter| will notify |progress_reporter_| upon
// construction and destruction. We limit the scope so that progress is
// reported immediately after allocation/upload and before other GL
// operations.
if (use_buffer) {
{
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
image = image_factory_->CreateAnonymousImage(
size, format_info.buffer_format, gfx::BufferUsage::SCANOUT,
surface_handle, &is_cleared);
}
// Scanout images have different constraints than GL images and might fail
// to allocate even if GL images can be created.
if (!image) {
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
// TODO(dcastagna): Use BufferUsage::GPU_READ_WRITE instead
// BufferUsage::GPU_READ once we add it.
image = image_factory_->CreateAnonymousImage(
size, format_info.buffer_format, gfx::BufferUsage::GPU_READ,
surface_handle, &is_cleared);
}
// The allocated image should not require copy.
if (!image || image->ShouldBindOrCopy() != gl::GLImage::BIND) {
LOG(ERROR) << "CreateSharedImage: Failed to create bindable image";
std::unique_ptr<SharedImageRepresentationDawn>
SharedImageBackingGLTexture::ProduceDawn(SharedImageManager* manager,
MemoryTypeTracker* tracker,
WGPUDevice device) {
if (!factory()) {
DLOG(ERROR) << "No SharedImageFactory to create a dawn representation.";
return nullptr;
}
level_info_internal_format = image->GetInternalFormat();
if (color_space.IsValid())
image->SetColorSpace(color_space);
if (usage & SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX)
image->DisableInUseByWindowServer();
}
InitializeGLTextureParams params;
params.target = target;
params.internal_format = level_info_internal_format;
params.format = format_info.gl_format;
params.type = format_info.gl_type;
params.is_cleared = pixel_data.empty() ? is_cleared : true;
params.has_immutable_storage = !image && format_info.supports_storage;
params.framebuffer_attachment_angle =
for_framebuffer_attachment && texture_usage_angle_;
if (image) {
DCHECK(!format_info.swizzle);
auto result = std::make_unique<SharedImageBackingGLImage>(
image, mailbox, format, size, color_space, surface_origin, alpha_type,
usage, params, attribs, use_passthrough_);
if (!pixel_data.empty()) {
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
result->InitializePixels(format_info.adjusted_format, format_info.gl_type,
pixel_data.data());
}
return std::move(result);
} else {
auto result = std::make_unique<SharedImageBackingGLTexture>(
mailbox, format, size, color_space, surface_origin, alpha_type, usage,
use_passthrough_);
result->InitializeGLTexture(0, params);
return SharedImageBackingGLCommon::ProduceDawnCommon(
factory(), manager, tracker, device, this, IsPassthrough());
}
gl::GLApi* api = gl::g_current_gl_context;
ScopedRestoreTexture scoped_restore(api, target);
api->glBindTextureFn(target, result->GetGLServiceId());
std::unique_ptr<SharedImageRepresentationSkia>
SharedImageBackingGLTexture::ProduceSkia(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
scoped_refptr<SharedContextState> context_state) {
if (!cached_promise_texture_) {
GrBackendTexture backend_texture;
GetGrBackendTexture(context_state->feature_info(), GetGLTarget(), size(),
GetGLServiceId(), format(), &backend_texture);
cached_promise_texture_ = SkPromiseImageTexture::Make(backend_texture);
}
return std::make_unique<SharedImageRepresentationSkiaImpl>(
manager, this, nullptr, std::move(context_state), cached_promise_texture_,
tracker);
}
if (format_info.supports_storage) {
{
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glTexStorage2DEXTFn(target, 1, format_info.storage_internal_format,
size.width(), size.height());
}
void SharedImageBackingGLTexture::Update(
std::unique_ptr<gfx::GpuFence> in_fence) {}
if (!pixel_data.empty()) {
ScopedResetAndRestoreUnpackState scoped_unpack_state(
api, attribs, true /* uploading_data */);
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glTexSubImage2DFn(target, 0, 0, 0, size.width(), size.height(),
format_info.adjusted_format, format_info.gl_type,
pixel_data.data());
}
} else if (format_info.is_compressed) {
ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs,
!pixel_data.empty());
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glCompressedTexImage2DFn(
target, 0, format_info.image_internal_format, size.width(),
size.height(), 0, pixel_data.size(), pixel_data.data());
void SharedImageBackingGLTexture::InitializeGLTexture(
GLuint service_id,
const InitializeGLTextureParams& params) {
SharedImageBackingGLCommon::MakeTextureAndSetParameters(
params.target, service_id, params.framebuffer_attachment_angle,
IsPassthrough() ? &passthrough_texture_ : nullptr,
IsPassthrough() ? nullptr : &texture_);
if (IsPassthrough()) {
passthrough_texture_->SetEstimatedSize(EstimatedSize(format(), size()));
} else {
ScopedResetAndRestoreUnpackState scoped_unpack_state(api, attribs,
!pixel_data.empty());
gl::ScopedProgressReporter scoped_progress_reporter(progress_reporter_);
api->glTexImage2DFn(target, 0, format_info.image_internal_format,
size.width(), size.height(), 0,
format_info.adjusted_format, format_info.gl_type,
pixel_data.data());
}
result->SetCompatibilitySwizzle(format_info.swizzle);
return std::move(result);
texture_->SetLevelInfo(params.target, 0, params.internal_format,
size().width(), size().height(), 1, 0, params.format,
params.type,
params.is_cleared ? gfx::Rect(size()) : gfx::Rect());
texture_->SetImmutable(true, params.has_immutable_storage);
}
}
///////////////////////////////////////////////////////////////////////////////
// SharedImageBackingFactoryGLTexture::FormatInfo
SharedImageBackingFactoryGLTexture::FormatInfo::FormatInfo() = default;
SharedImageBackingFactoryGLTexture::FormatInfo::~FormatInfo() = default;
void SharedImageBackingGLTexture::SetCompatibilitySwizzle(
const gles2::Texture::CompatibilitySwizzle* swizzle) {
if (!IsPassthrough())
texture_->SetCompatibilitySwizzle(swizzle);
}
} // namespace gpu
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment