blob: b460c93474ed5c4331fba1db392531397a48e0ae [file] [log] [blame]
// Copyright 2019 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_backing_factory_iosurface.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "components/viz/common/gpu/metal_context_provider.h"
#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/common/resources/resource_sizes.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/shared_image_backing.h"
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/command_buffer/service/skia_utils.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "third_party/skia/include/core/SkPromiseImageTexture.h"
#include "ui/gfx/mac/io_surface.h"
#include "ui/gl/buildflags.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_image_io_surface.h"
#import <Metal/Metal.h>
// Usage of BUILDFLAG(USE_DAWN) needs to be after the include for
// ui/gl/buildflags.h
#if BUILDFLAG(USE_DAWN)
#include <dawn_native/MetalBackend.h>
#endif // BUILDFLAG(USE_DAWN)
namespace gpu {
namespace {
struct GLFormatInfo {
bool supported = false;
// GL internal_format/format/type triplet.
GLuint internal_format = 0;
GLenum format = 0;
GLenum type = 0;
};
// Get GL format triplets and modify them to match the logic in
// gl_image_iosurface.mm
GLFormatInfo GetGLFormatInfo(viz::ResourceFormat format) {
GLFormatInfo info = {
true,
viz::GLInternalFormat(format),
viz::GLDataFormat(format),
viz::GLDataType(format),
};
if (info.internal_format == GL_ZERO || info.format == GL_ZERO ||
info.type == GL_ZERO) {
return {false, GL_ZERO, GL_ZERO, GL_ZERO};
}
switch (format) {
case viz::BGRA_8888:
info.format = GL_RGBA;
info.internal_format = GL_RGBA;
break;
// Technically we should use GL_RGB but CGLTexImageIOSurface2D() (and
// OpenGL ES 3.0, for the case) support only GL_RGBA (the hardware ignores
// the alpha channel anyway), see https://crbug.com/797347.
case viz::BGRX_1010102:
info.format = GL_RGBA;
info.internal_format = GL_RGBA;
break;
default:
break;
}
return info;
}
void FlushIOSurfaceGLOperations() {
// The CGLTexImageIOSurface2D documentation says that we need to call
// glFlush, otherwise there is the risk of a race between different
// graphics contexts.
gl::GLApi* api = gl::g_current_gl_context;
api->glFlushFn();
}
base::Optional<WGPUTextureFormat> GetWGPUFormat(gfx::BufferFormat format) {
switch (format) {
case gfx::BufferFormat::R_8:
return WGPUTextureFormat_R8Unorm;
case gfx::BufferFormat::RG_88:
return WGPUTextureFormat_RG8Unorm;
case gfx::BufferFormat::RGBX_8888:
case gfx::BufferFormat::RGBA_8888:
case gfx::BufferFormat::BGRX_8888:
return WGPUTextureFormat_BGRA8Unorm;
default:
return {};
}
}
base::scoped_nsprotocol<id<MTLTexture>> API_AVAILABLE(macos(10.11))
CreateMetalTexture(id<MTLDevice> mtl_device,
IOSurfaceRef io_surface,
const gfx::Size& size,
viz::ResourceFormat format) {
TRACE_EVENT0("gpu", "SharedImageBackingFactoryIOSurface::CreateMetalTexture");
base::scoped_nsprotocol<id<MTLTexture>> mtl_texture;
MTLPixelFormat mtl_pixel_format;
switch (format) {
case viz::RED_8:
case viz::ALPHA_8:
case viz::LUMINANCE_8:
mtl_pixel_format = MTLPixelFormatR8Unorm;
break;
case viz::RG_88:
mtl_pixel_format = MTLPixelFormatRG8Unorm;
break;
case viz::RGBA_8888:
mtl_pixel_format = MTLPixelFormatRGBA8Unorm;
break;
case viz::BGRA_8888:
mtl_pixel_format = MTLPixelFormatBGRA8Unorm;
break;
default:
// TODO(https://crbug.com/952063): Add support for all formats supported
// by GLImageIOSurface.
DLOG(ERROR) << "Resource format not yet supported in Metal.";
return mtl_texture;
}
base::scoped_nsobject<MTLTextureDescriptor> mtl_tex_desc(
[MTLTextureDescriptor new]);
[mtl_tex_desc setTextureType:MTLTextureType2D];
[mtl_tex_desc
setUsage:MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget];
[mtl_tex_desc setPixelFormat:mtl_pixel_format];
[mtl_tex_desc setWidth:size.width()];
[mtl_tex_desc setHeight:size.height()];
[mtl_tex_desc setDepth:1];
[mtl_tex_desc setMipmapLevelCount:1];
[mtl_tex_desc setArrayLength:1];
[mtl_tex_desc setSampleCount:1];
// TODO(https://crbug.com/952063): For zero-copy resources that are populated
// on the CPU (e.g, video frames), it may be that MTLStorageModeManaged will
// be more appropriate.
[mtl_tex_desc setStorageMode:MTLStorageModePrivate];
mtl_texture.reset([mtl_device newTextureWithDescriptor:mtl_tex_desc
iosurface:io_surface
plane:0]);
DCHECK(mtl_texture);
return mtl_texture;
}
} // anonymous namespace
// Representation of a SharedImageBackingIOSurface as a GL Texture.
class SharedImageRepresentationGLTextureIOSurface
: public SharedImageRepresentationGLTexture {
public:
SharedImageRepresentationGLTextureIOSurface(SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
gles2::Texture* texture)
: SharedImageRepresentationGLTexture(manager, backing, tracker),
texture_(texture) {
DCHECK(texture_);
}
~SharedImageRepresentationGLTextureIOSurface() override {
texture_->RemoveLightweightRef(has_context());
}
gles2::Texture* GetTexture() override { return texture_; }
bool BeginAccess(GLenum mode) override { return true; }
void EndAccess() override { FlushIOSurfaceGLOperations(); }
private:
gles2::Texture* texture_;
DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureIOSurface);
};
// Representation of a SharedImageBackingIOSurface as a Skia Texture.
class SharedImageRepresentationSkiaIOSurface
: public SharedImageRepresentationSkia {
public:
SharedImageRepresentationSkiaIOSurface(
SharedImageManager* manager,
SharedImageBacking* backing,
scoped_refptr<SharedContextState> context_state,
sk_sp<SkPromiseImageTexture> promise_texture,
MemoryTypeTracker* tracker,
gles2::Texture* gles2_texture)
: SharedImageRepresentationSkia(manager, backing, tracker),
context_state_(std::move(context_state)),
promise_texture_(std::move(promise_texture)),
gles2_texture_(gles2_texture) {
DCHECK(promise_texture_);
}
~SharedImageRepresentationSkiaIOSurface() override {
if (gles2_texture_)
gles2_texture_->RemoveLightweightRef(has_context());
}
sk_sp<SkSurface> BeginWriteAccess(
int final_msaa_count,
const SkSurfaceProps& surface_props,
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores) override {
SkColorType sk_color_type = viz::ResourceFormatToClosestSkColorType(
/*gpu_compositing=*/true, format());
return SkSurface::MakeFromBackendTextureAsRenderTarget(
context_state_->gr_context(), promise_texture_->backendTexture(),
kTopLeft_GrSurfaceOrigin, final_msaa_count, sk_color_type,
backing()->color_space().ToSkColorSpace(), &surface_props);
}
void EndWriteAccess(sk_sp<SkSurface> surface) override {
if (context_state_->GrContextIsGL())
FlushIOSurfaceGLOperations();
if (gles2_texture_ &&
gles2_texture_->IsLevelCleared(gles2_texture_->target(), 0)) {
backing()->SetCleared();
}
}
sk_sp<SkPromiseImageTexture> BeginReadAccess(
std::vector<GrBackendSemaphore>* begin_semaphores,
std::vector<GrBackendSemaphore>* end_semaphores) override {
return promise_texture_;
}
void EndReadAccess() override {
if (context_state_->GrContextIsGL())
FlushIOSurfaceGLOperations();
}
private:
scoped_refptr<SharedContextState> context_state_;
sk_sp<SkPromiseImageTexture> promise_texture_;
gles2::Texture* const gles2_texture_;
};
// Representation of a SharedImageBackingIOSurface as a Dawn Texture.
#if BUILDFLAG(USE_DAWN)
class SharedImageRepresentationDawnIOSurface
: public SharedImageRepresentationDawn {
public:
SharedImageRepresentationDawnIOSurface(
SharedImageManager* manager,
SharedImageBacking* backing,
MemoryTypeTracker* tracker,
WGPUDevice device,
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
WGPUTextureFormat wgpu_format)
: SharedImageRepresentationDawn(manager, backing, tracker),
io_surface_(std::move(io_surface)),
device_(device),
wgpu_format_(wgpu_format),
dawn_procs_(dawn_native::GetProcs()) {
DCHECK(device_);
DCHECK(io_surface_);
// Keep a reference to the device so that it stays valid (it might become
// lost in which case operations will be noops).
dawn_procs_.deviceReference(device_);
}
~SharedImageRepresentationDawnIOSurface() override {
EndAccess();
dawn_procs_.deviceRelease(device_);
}
WGPUTexture BeginAccess(WGPUTextureUsage usage) final {
WGPUTextureDescriptor desc;
desc.nextInChain = nullptr;
desc.format = wgpu_format_;
desc.usage = usage;
desc.dimension = WGPUTextureDimension_2D;
desc.size = {size().width(), size().height(), 1};
desc.arrayLayerCount = 1;
desc.mipLevelCount = 1;
desc.sampleCount = 1;
texture_ =
dawn_native::metal::WrapIOSurface(device_, &desc, io_surface_.get(), 0);
if (texture_) {
// Keep a reference to the texture so that it stays valid (its content
// might be destroyed).
dawn_procs_.textureReference(texture_);
// Assume that the user of this representation will write to the texture
// so set the cleared flag so that other representations don't overwrite
// the result.
// TODO(cwallez@chromium.org): This is incorrect and allows reading
// uninitialized data. When !IsCleared we should tell dawn_native to
// consider the texture lazy-cleared. crbug.com/1036080
SetCleared();
}
return texture_;
}
void EndAccess() final {
if (!texture_) {
return;
}
// TODO(cwallez@chromium.org): query dawn_native to know if the texture was
// cleared and set IsCleared appropriately.
// All further operations on the textures are errors (they would be racy
// with other backings).
dawn_procs_.textureDestroy(texture_);
// macOS has a global GPU command queue so synchronization between APIs and
// devices is automatic. However on Metal, wgpuQueueSubmit "commits" the
// Metal command buffers but they aren't "scheduled" in the global queue
// immediately. (that work seems offloaded to a different thread?)
// Wait for all the previous submitted commands to be scheduled to have
// scheduling races between commands using the IOSurface on different APIs.
// This is a blocking call but should be almost instant.
TRACE_EVENT0("gpu", "SharedImageRepresentationDawnIOSurface::EndAccess");
dawn_native::metal::WaitForCommandsToBeScheduled(device_);
dawn_procs_.textureRelease(texture_);
texture_ = nullptr;
}
private:
base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
WGPUDevice device_;
WGPUTexture texture_ = nullptr;
WGPUTextureFormat wgpu_format_;
// TODO(cwallez@chromium.org): Load procs only once when the factory is
// created and pass a pointer to them around?
DawnProcTable dawn_procs_;
};
#endif // BUILDFLAG(USE_DAWN)
// Implementation of SharedImageBacking by wrapping IOSurfaces. Disable
// unguarded availability warnings because they are incompatible with using a
// scoped_nsprotocol for the id<MTLTexture> and because all access to Metal is
// guarded on the context provider already successfully using Metal.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunguarded-availability"
class SharedImageBackingIOSurface : public ClearTrackingSharedImageBacking {
public:
SharedImageBackingIOSurface(const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage,
base::ScopedCFTypeRef<IOSurfaceRef> io_surface,
base::Optional<WGPUTextureFormat> dawn_format,
size_t estimated_size)
: ClearTrackingSharedImageBacking(mailbox,
format,
size,
color_space,
usage,
estimated_size,
false /* is_thread_safe */),
io_surface_(std::move(io_surface)),
dawn_format_(dawn_format) {
DCHECK(io_surface_);
}
~SharedImageBackingIOSurface() final {
TRACE_EVENT0("gpu", "SharedImageBackingFactoryIOSurface::Destroy");
DCHECK(io_surface_);
if (legacy_texture_) {
legacy_texture_->RemoveLightweightRef(have_context());
legacy_texture_ = nullptr;
}
mtl_texture_.reset();
io_surface_.reset();
}
gfx::Rect ClearedRect() const final {
// If a |legacy_texture_| exists, defer to that. Once created,
// |legacy_texture_| is never destroyed, so no need to synchronize with
// ClearedRect.
if (legacy_texture_) {
return legacy_texture_->GetLevelClearedRect(legacy_texture_->target(), 0);
} else {
return ClearTrackingSharedImageBacking::ClearedRect();
}
}
void SetClearedRect(const gfx::Rect& cleared_rect) final {
// If a |legacy_texture_| exists, defer to that. Once created,
// |legacy_texture_| is never destroyed, so no need to synchronize with
// SetClearedRect.
if (legacy_texture_) {
legacy_texture_->SetLevelClearedRect(legacy_texture_->target(), 0,
cleared_rect);
} else {
ClearTrackingSharedImageBacking::SetClearedRect(cleared_rect);
}
}
void Update(std::unique_ptr<gfx::GpuFence> in_fence) final {}
bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) final {
DCHECK(io_surface_);
legacy_texture_ = GenGLTexture();
if (!legacy_texture_) {
return false;
}
// Make sure our |legacy_texture_| has the right initial cleared rect.
legacy_texture_->SetLevelClearedRect(
legacy_texture_->target(), 0,
ClearTrackingSharedImageBacking::ClearedRect());
mailbox_manager->ProduceTexture(mailbox(), legacy_texture_);
return true;
}
protected:
std::unique_ptr<SharedImageRepresentationGLTexture> ProduceGLTexture(
SharedImageManager* manager,
MemoryTypeTracker* tracker) final {
gles2::Texture* texture = GenGLTexture();
if (!texture) {
return nullptr;
}
return std::make_unique<SharedImageRepresentationGLTextureIOSurface>(
manager, this, tracker, texture);
}
std::unique_ptr<SharedImageRepresentationSkia> ProduceSkia(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
scoped_refptr<SharedContextState> context_state) override {
gles2::Texture* gles2_texture = nullptr;
GrBackendTexture gr_backend_texture;
if (context_state->GrContextIsGL()) {
gles2_texture = GenGLTexture();
if (!gles2_texture)
return nullptr;
GetGrBackendTexture(
context_state->feature_info(), gles2_texture->target(), size(),
gles2_texture->service_id(), format(), &gr_backend_texture);
}
if (context_state->GrContextIsMetal()) {
if (!mtl_texture_) {
id<MTLDevice> mtl_device =
context_state->metal_context_provider()->GetMTLDevice();
mtl_texture_ =
CreateMetalTexture(mtl_device, io_surface_, size(), format());
DCHECK(mtl_texture_);
}
GrMtlTextureInfo info;
info.fTexture.retain(mtl_texture_.get());
gr_backend_texture = GrBackendTexture(size().width(), size().height(),
GrMipMapped::kNo, info);
}
sk_sp<SkPromiseImageTexture> promise_texture =
SkPromiseImageTexture::Make(gr_backend_texture);
return std::make_unique<SharedImageRepresentationSkiaIOSurface>(
manager, this, std::move(context_state), promise_texture, tracker,
gles2_texture);
}
std::unique_ptr<SharedImageRepresentationDawn> ProduceDawn(
SharedImageManager* manager,
MemoryTypeTracker* tracker,
WGPUDevice device) override {
#if BUILDFLAG(USE_DAWN)
if (!dawn_format_) {
LOG(ERROR) << "Format not supported for Dawn";
return nullptr;
}
return std::make_unique<SharedImageRepresentationDawnIOSurface>(
manager, this, tracker, device, io_surface_, dawn_format_.value());
#else // BUILDFLAG(USE_DAWN)
return nullptr;
#endif // BUILDFLAG(USE_DAWN)
}
private:
gles2::Texture* GenGLTexture() {
TRACE_EVENT0("gpu", "SharedImageBackingFactoryIOSurface::GenGLTexture");
GLFormatInfo gl_info = GetGLFormatInfo(format());
DCHECK(gl_info.supported);
// Wrap the IOSurface in a GLImageIOSurface
scoped_refptr<gl::GLImageIOSurface> image(
gl::GLImageIOSurface::Create(size(), gl_info.internal_format));
if (!image->Initialize(io_surface_, gfx::GenericSharedMemoryId(),
viz::BufferFormat(format()))) {
LOG(ERROR) << "Failed to create GLImageIOSurface";
return nullptr;
}
gl::GLApi* api = gl::g_current_gl_context;
// Save the currently bound rectangle texture to reset it once we are done.
GLint old_texture_binding = 0;
api->glGetIntegervFn(GL_TEXTURE_BINDING_RECTANGLE, &old_texture_binding);
// Create a gles2 rectangle texture to bind to the IOSurface.
GLuint service_id = 0;
api->glGenTexturesFn(1, &service_id);
api->glBindTextureFn(GL_TEXTURE_RECTANGLE, service_id);
api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER,
GL_LINEAR);
api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
api->glTexParameteriFn(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
// Bind the GLImageIOSurface to our texture
if (!image->BindTexImage(GL_TEXTURE_RECTANGLE)) {
LOG(ERROR) << "Failed to bind GLImageIOSurface";
api->glBindTextureFn(GL_TEXTURE_RECTANGLE, old_texture_binding);
api->glDeleteTexturesFn(1, &service_id);
return nullptr;
}
// If the backing is already cleared, no need to clear it again.
gfx::Rect cleared_rect = ClearedRect();
// Manually create a gles2::Texture wrapping our driver texture.
gles2::Texture* texture = new gles2::Texture(service_id);
texture->SetLightweightRef();
texture->SetTarget(GL_TEXTURE_RECTANGLE, 1);
texture->sampler_state_.min_filter = GL_LINEAR;
texture->sampler_state_.mag_filter = GL_LINEAR;
texture->sampler_state_.wrap_t = GL_CLAMP_TO_EDGE;
texture->sampler_state_.wrap_s = GL_CLAMP_TO_EDGE;
texture->SetLevelInfo(GL_TEXTURE_RECTANGLE, 0, gl_info.internal_format,
size().width(), size().height(), 1, 0, gl_info.format,
gl_info.type, cleared_rect);
texture->SetLevelImage(GL_TEXTURE_RECTANGLE, 0, image.get(),
gles2::Texture::BOUND);
texture->SetImmutable(true, false);
DCHECK_EQ(image->GetInternalFormat(), gl_info.internal_format);
api->glBindTextureFn(GL_TEXTURE_RECTANGLE, old_texture_binding);
return texture;
}
base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
base::Optional<WGPUTextureFormat> dawn_format_;
base::scoped_nsprotocol<id<MTLTexture>> mtl_texture_;
// A texture for the associated legacy mailbox.
gles2::Texture* legacy_texture_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(SharedImageBackingIOSurface);
};
#pragma clang diagnostic pop
// Implementation of SharedImageBackingFactoryIOSurface that creates
// SharedImageBackings wrapping IOSurfaces.
SharedImageBackingFactoryIOSurface::SharedImageBackingFactoryIOSurface(
const GpuDriverBugWorkarounds& workarounds,
const GpuFeatureInfo& gpu_feature_info,
bool use_gl)
: use_gl_(use_gl) {
if (use_gl_) {
CollectGLFormatInfo(workarounds, gpu_feature_info);
}
}
void SharedImageBackingFactoryIOSurface::CollectGLFormatInfo(
const GpuDriverBugWorkarounds& workarounds,
const GpuFeatureInfo& gpu_feature_info) {
scoped_refptr<gles2::FeatureInfo> feature_info =
new gles2::FeatureInfo(workarounds, gpu_feature_info);
feature_info->Initialize(ContextType::CONTEXT_TYPE_OPENGLES2, false,
gles2::DisallowedFeatures());
const gles2::Validators* validators = feature_info->validators();
// Precompute for each format if we can use it with GL.
for (int i = 0; i <= viz::RESOURCE_FORMAT_MAX; ++i) {
viz::ResourceFormat format = static_cast<viz::ResourceFormat>(i);
GLFormatInfo gl_info = GetGLFormatInfo(format);
format_supported_by_gl_[i] =
gl_info.supported &&
validators->texture_internal_format.IsValid(gl_info.internal_format) &&
validators->texture_format.IsValid(gl_info.format) &&
validators->pixel_type.IsValid(gl_info.type);
}
}
SharedImageBackingFactoryIOSurface::~SharedImageBackingFactoryIOSurface() =
default;
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryIOSurface::CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage,
bool is_thread_safe) {
TRACE_EVENT0("gpu", "SharedImageBackingFactoryIOSurface::CreateSharedImage");
DCHECK(!is_thread_safe);
// Check the format is supported and for simplicity always require it to be
// supported for GL.
if (use_gl_ && !format_supported_by_gl_[format]) {
LOG(ERROR) << "viz::ResourceFormat " << format
<< " not supported by IOSurfaces";
return nullptr;
}
// Calculate SharedImage size in bytes.
size_t estimated_size;
if (!viz::ResourceSizes::MaybeSizeInBytes(size, format, &estimated_size)) {
LOG(ERROR) << "Failed to calculate SharedImage size";
return nullptr;
}
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
gfx::CreateIOSurface(size, viz::BufferFormat(format), false));
if (!io_surface) {
LOG(ERROR) << "Failed to allocate IOSurface.";
return nullptr;
}
gfx::IOSurfaceSetColorSpace(io_surface, color_space);
// OpenGL textures bound to IOSurfaces won't work on macOS unless the internal
// format is BGRA, so force a BGRA internal format for viz::RGBA_8888.
base::Optional<WGPUTextureFormat> wgpu_format =
format == viz::RGBA_8888 ? WGPUTextureFormat_BGRA8Unorm
: viz::ToWGPUFormat(format);
if (wgpu_format.value() == WGPUTextureFormat_Undefined) {
wgpu_format = base::nullopt;
}
return std::make_unique<SharedImageBackingIOSurface>(
mailbox, format, size, color_space, usage, std::move(io_surface),
wgpu_format, estimated_size);
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryIOSurface::CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage,
base::span<const uint8_t> pixel_data) {
NOTIMPLEMENTED();
return nullptr;
}
std::unique_ptr<SharedImageBacking>
SharedImageBackingFactoryIOSurface::CreateSharedImage(
const Mailbox& mailbox,
int client_id,
gfx::GpuMemoryBufferHandle handle,
gfx::BufferFormat format,
SurfaceHandle surface_handle,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage) {
if (handle.type != gfx::GpuMemoryBufferType::IO_SURFACE_BUFFER) {
NOTIMPLEMENTED();
return nullptr;
}
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
IOSurfaceLookupFromMachPort(handle.mach_port.get()));
if (!io_surface) {
DLOG(ERROR) << "IOSurfaceLookupFromMachPort failed.";
return nullptr;
}
viz::ResourceFormat resource_format = viz::GetResourceFormat(format);
size_t estimated_size = 0;
if (!viz::ResourceSizes::MaybeSizeInBytes(size, resource_format,
&estimated_size)) {
DLOG(ERROR) << "Failed to calculate SharedImage size";
return nullptr;
}
return std::make_unique<SharedImageBackingIOSurface>(
mailbox, resource_format, size, color_space, usage, std::move(io_surface),
GetWGPUFormat(format), estimated_size);
}
bool SharedImageBackingFactoryIOSurface::CanImportGpuMemoryBuffer(
gfx::GpuMemoryBufferType memory_buffer_type) {
return false;
}
} // namespace gpu