Commit 3a6d6ae5 authored by Corentin Wallez's avatar Corentin Wallez Committed by Commit Bot

Add an IOSurface SharedImageBackingFactory

Texture sharing between OpenGL and Metal on Mac has to be done through
IOSurfaces so we add a SharedImageBackingFactory for this OS-specific
mechanism.

SharedImageBackingFactory starts with supports for producing GLTexture
SharedImage representations as well as legacy mailboxes. Support for
other representations will be added in later commits.

BUG=chromium:938895

Change-Id: I4aa5faf026c273b3a02820ed08c3a502e6769678
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1505511
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: default avatarAntoine Labour <piman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638720}
parent 9ea56fae
...@@ -292,6 +292,7 @@ test("gl_tests") { ...@@ -292,6 +292,7 @@ test("gl_tests") {
sources += [ "command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc" ] sources += [ "command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc" ]
} else if (is_mac) { } else if (is_mac) {
libs += [ "IOSurface.framework" ] libs += [ "IOSurface.framework" ]
sources += [ "command_buffer/service/shared_image_backing_factory_iosurface_unittest.cc" ]
} else if (is_win) { } else if (is_win) {
deps += [ deps += [
"//ui/platform_window", "//ui/platform_window",
......
...@@ -332,8 +332,14 @@ target(link_target_type, "gles2_sources") { ...@@ -332,8 +332,14 @@ target(link_target_type, "gles2_sources") {
} }
if (is_mac) { if (is_mac) {
sources += [
"shared_image_backing_factory_iosurface.h",
"shared_image_backing_factory_iosurface.mm",
]
# Required by gles2_cmd_decoder.cc on Mac. # Required by gles2_cmd_decoder.cc on Mac.
libs = [ libs = [
"Cocoa.framework",
"IOSurface.framework", "IOSurface.framework",
"OpenGL.framework", "OpenGL.framework",
] ]
......
// 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.
#ifndef GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_IOSURFACE_H_
#define GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_IOSURFACE_H_
#include <memory>
#include "base/macros.h"
#include "components/viz/common/resources/resource_format.h"
#include "gpu/command_buffer/service/shared_image_backing_factory.h"
#include "gpu/gpu_gles2_export.h"
#include "ui/gl/gl_bindings.h"
namespace gfx {
class Size;
class ColorSpace;
} // namespace gfx
namespace gpu {
class GpuDriverBugWorkarounds;
struct GpuFeatureInfo;
struct Mailbox;
class SharedImageBacking;
// Implementation of SharedImageBackingFactory that produce IOSurface backed
// SharedImages. This is meant to be used on macOS only.
class GPU_GLES2_EXPORT SharedImageBackingFactoryIOSurface
: public SharedImageBackingFactory {
public:
SharedImageBackingFactoryIOSurface(const GpuDriverBugWorkarounds& workarounds,
const GpuFeatureInfo& gpu_feature_info);
~SharedImageBackingFactoryIOSurface() override;
// SharedImageBackingFactory implementation.
std::unique_ptr<SharedImageBacking> CreateSharedImage(
const Mailbox& mailbox,
viz::ResourceFormat format,
const gfx::Size& size,
const gfx::ColorSpace& color_space,
uint32_t usage) override;
std::unique_ptr<SharedImageBacking> 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) override;
std::unique_ptr<SharedImageBacking> 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) override;
private:
bool format_supported_by_gl_[viz::RESOURCE_FORMAT_MAX + 1];
DISALLOW_COPY_AND_ASSIGN(SharedImageBackingFactoryIOSurface);
};
} // namespace gpu
#endif // GPU_COMMAND_BUFFER_SERVICE_SHARED_IMAGE_BACKING_FACTORY_IOSURFACE_H_
// 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 "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_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/gl_context.h"
#include "ui/gl/gl_image_io_surface.h"
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();
}
} // 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,
sk_sp<SkPromiseImageTexture> promise_texture,
MemoryTypeTracker* tracker,
gles2::Texture* texture)
: SharedImageRepresentationSkia(manager, backing, tracker),
promise_texture_(std::move(promise_texture)),
texture_(texture) {
DCHECK(texture_);
DCHECK(promise_texture_);
}
~SharedImageRepresentationSkiaIOSurface() override {
texture_->RemoveLightweightRef(has_context());
}
sk_sp<SkSurface> BeginWriteAccess(
GrContext* gr_context,
int final_msaa_count,
const SkSurfaceProps& surface_props) override {
SkColorType sk_color_type = viz::ResourceFormatToClosestSkColorType(
/*gpu_compositing=*/true, format());
return SkSurface::MakeFromBackendTextureAsRenderTarget(
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 {
FlushIOSurfaceGLOperations();
if (texture_->IsLevelCleared(texture_->target(), 0)) {
backing()->SetCleared();
}
}
sk_sp<SkPromiseImageTexture> BeginReadAccess(SkSurface* sk_surface) override {
return promise_texture_;
}
void EndReadAccess() override { FlushIOSurfaceGLOperations(); }
private:
sk_sp<SkPromiseImageTexture> promise_texture_;
gles2::Texture* texture_;
};
// Implementation of SharedImageBacking by wrapping IOSurfaces
class SharedImageBackingIOSurface : public SharedImageBacking {
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,
size_t estimated_size)
: SharedImageBacking(mailbox,
format,
size,
color_space,
usage,
estimated_size),
io_surface_(std::move(io_surface)) {
DCHECK(io_surface_);
}
~SharedImageBackingIOSurface() final { DCHECK(!io_surface_); }
bool IsCleared() const final { return is_cleared_; }
void SetCleared() final {
if (legacy_texture_) {
legacy_texture_->SetLevelCleared(legacy_texture_->target(), 0, true);
}
is_cleared_ = true;
}
void Update() final {}
bool ProduceLegacyMailbox(MailboxManager* mailbox_manager) final {
DCHECK(io_surface_);
legacy_texture_ = GenGLTexture();
if (!legacy_texture_) {
return false;
}
mailbox_manager->ProduceTexture(mailbox(), legacy_texture_);
return true;
}
void Destroy() final {
DCHECK(io_surface_);
if (legacy_texture_) {
legacy_texture_->RemoveLightweightRef(have_context());
legacy_texture_ = nullptr;
}
io_surface_.reset();
}
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) override {
gles2::Texture* texture = GenGLTexture();
if (!texture) {
return nullptr;
}
GrBackendTexture backend_texture;
GetGrBackendTexture(gl::GLContext::GetCurrent()->GetVersionInfo(),
texture->target(), size(), texture->service_id(),
format(), &backend_texture);
sk_sp<SkPromiseImageTexture> promise_texture =
SkPromiseImageTexture::Make(backend_texture);
return std::make_unique<SharedImageRepresentationSkiaIOSurface>(
manager, this, promise_texture, tracker, texture);
}
private:
gles2::Texture* 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;
if (is_cleared_) {
cleared_rect = gfx::Rect(size());
}
// 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);
DCHECK_EQ(image->GetInternalFormat(), gl_info.format);
api->glBindTextureFn(GL_TEXTURE_RECTANGLE, old_texture_binding);
return texture;
}
base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
bool is_cleared_ = false;
// A texture for the associated legacy mailbox.
gles2::Texture* legacy_texture_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(SharedImageBackingIOSurface);
};
// Implementation of SharedImageBackingFactoryIOSurface that creates
// SharedImageBackings wrapping IOSurfaces.
SharedImageBackingFactoryIOSurface::SharedImageBackingFactoryIOSurface(
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) {
// Check the format is supported and for simplicity always require it to be
// supported for GL.
if (!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);
return std::make_unique<SharedImageBackingIOSurface>(
mailbox, format, size, color_space, usage, std::move(io_surface),
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) {
NOTIMPLEMENTED();
return nullptr;
}
} // namespace gpu
// 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 <memory>
#include <utility>
#include "base/bind_helpers.h"
#include "gpu/command_buffer/common/shared_image_usage.h"
#include "gpu/command_buffer/service/mailbox_manager_impl.h"
#include "gpu/command_buffer/service/shared_context_state.h"
#include "gpu/command_buffer/service/shared_image_factory.h"
#include "gpu/command_buffer/service/shared_image_manager.h"
#include "gpu/command_buffer/service/shared_image_representation.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_feature_info.h"
#include "gpu/config/gpu_preferences.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkPromiseImageTexture.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/init/gl_factory.h"
namespace gpu {
namespace {
class SharedImageBackingFactoryIOSurfaceTest : public testing::Test {
public:
void SetUp() override {
surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
ASSERT_TRUE(surface_);
context_ = gl::init::CreateGLContext(nullptr, surface_.get(),
gl::GLContextAttribs());
ASSERT_TRUE(context_);
bool result = context_->MakeCurrent(surface_.get());
ASSERT_TRUE(result);
GpuDriverBugWorkarounds workarounds;
scoped_refptr<gl::GLShareGroup> share_group = new gl::GLShareGroup();
context_state_ = base::MakeRefCounted<SharedContextState>(
std::move(share_group), surface_, context_,
false /* use_virtualized_gl_contexts */, base::DoNothing());
context_state_->InitializeGrContext(workarounds, nullptr);
auto feature_info =
base::MakeRefCounted<gles2::FeatureInfo>(workarounds, GpuFeatureInfo());
context_state_->InitializeGL(GpuPreferences(), std::move(feature_info));
backing_factory_ = std::make_unique<SharedImageBackingFactoryIOSurface>(
workarounds, GpuFeatureInfo());
memory_type_tracker_ = std::make_unique<MemoryTypeTracker>(nullptr);
shared_image_representation_factory_ =
std::make_unique<SharedImageRepresentationFactory>(
&shared_image_manager_, nullptr);
}
GrContext* gr_context() { return context_state_->gr_context(); }
protected:
scoped_refptr<gl::GLSurface> surface_;
scoped_refptr<gl::GLContext> context_;
scoped_refptr<SharedContextState> context_state_;
std::unique_ptr<SharedImageBackingFactoryIOSurface> backing_factory_;
gles2::MailboxManagerImpl mailbox_manager_;
SharedImageManager shared_image_manager_;
std::unique_ptr<MemoryTypeTracker> memory_type_tracker_;
std::unique_ptr<SharedImageRepresentationFactory>
shared_image_representation_factory_;
};
// Basic test to check creation and deletion of IOSurface backed shared image.
TEST_F(SharedImageBackingFactoryIOSurfaceTest, Basic) {
Mailbox mailbox = Mailbox::GenerateForSharedImage();
viz::ResourceFormat format = viz::ResourceFormat::RGBA_8888;
gfx::Size size(256, 256);
gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY;
auto backing = backing_factory_->CreateSharedImage(mailbox, format, size,
color_space, usage);
EXPECT_TRUE(backing);
// Check clearing.
if (!backing->IsCleared()) {
backing->SetCleared();
EXPECT_TRUE(backing->IsCleared());
}
// First, validate via a legacy mailbox.
GLenum expected_target = GL_TEXTURE_RECTANGLE;
EXPECT_TRUE(backing->ProduceLegacyMailbox(&mailbox_manager_));
TextureBase* texture_base = mailbox_manager_.ConsumeTexture(mailbox);
// Currently there is no support for passthrough texture on Mac and hence
// in IOSurface backing. So the TextureBase* should be pointing to a Texture
// object.
auto* texture = gles2::Texture::CheckedCast(texture_base);
ASSERT_TRUE(texture);
EXPECT_EQ(texture->target(), expected_target);
EXPECT_TRUE(texture->IsImmutable());
int width, height, depth;
bool has_level =
texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height, &depth);
EXPECT_TRUE(has_level);
EXPECT_EQ(width, size.width());
EXPECT_EQ(height, size.height());
// Next validate via a SharedImageRepresentationGLTexture.
std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref =
shared_image_manager_.Register(std::move(backing),
memory_type_tracker_.get());
auto gl_representation =
shared_image_representation_factory_->ProduceGLTexture(mailbox);
EXPECT_TRUE(gl_representation);
EXPECT_TRUE(gl_representation->GetTexture()->service_id());
EXPECT_EQ(expected_target, gl_representation->GetTexture()->target());
EXPECT_EQ(size, gl_representation->size());
EXPECT_EQ(format, gl_representation->format());
EXPECT_EQ(color_space, gl_representation->color_space());
EXPECT_EQ(usage, gl_representation->usage());
gl_representation.reset();
// Finally, validate a SharedImageRepresentationSkia.
auto skia_representation =
shared_image_representation_factory_->ProduceSkia(mailbox);
EXPECT_TRUE(skia_representation);
auto surface = skia_representation->BeginWriteAccess(
gr_context(), 0, SkSurfaceProps(0, kUnknown_SkPixelGeometry));
EXPECT_TRUE(surface);
EXPECT_EQ(size.width(), surface->width());
EXPECT_EQ(size.height(), surface->height());
skia_representation->EndWriteAccess(std::move(surface));
auto promise_texture = skia_representation->BeginReadAccess(nullptr);
EXPECT_TRUE(promise_texture);
if (promise_texture) {
GrBackendTexture backend_texture = promise_texture->backendTexture();
EXPECT_TRUE(backend_texture.isValid());
EXPECT_EQ(size.width(), backend_texture.width());
EXPECT_EQ(size.height(), backend_texture.height());
}
skia_representation->EndReadAccess();
skia_representation.reset();
factory_ref.reset();
EXPECT_FALSE(mailbox_manager_.ConsumeTexture(mailbox));
}
// Test to check interaction between Gl and skia GL representations.
// We write to a GL texture using gl representation and then read from skia
// representation.
TEST_F(SharedImageBackingFactoryIOSurfaceTest, GLSkiaGL) {
// Create a backing using mailbox.
auto mailbox = Mailbox::GenerateForSharedImage();
auto format = viz::ResourceFormat::RGBA_8888;
gfx::Size size(1, 1);
auto color_space = gfx::ColorSpace::CreateSRGB();
uint32_t usage = SHARED_IMAGE_USAGE_GLES2 | SHARED_IMAGE_USAGE_DISPLAY;
auto backing = backing_factory_->CreateSharedImage(mailbox, format, size,
color_space, usage);
EXPECT_TRUE(backing);
GLenum expected_target = GL_TEXTURE_RECTANGLE;
std::unique_ptr<SharedImageRepresentationFactoryRef> factory_ref =
shared_image_manager_.Register(std::move(backing),
memory_type_tracker_.get());
// Create a SharedImageRepresentationGLTexture.
auto gl_representation =
shared_image_representation_factory_->ProduceGLTexture(mailbox);
EXPECT_TRUE(gl_representation);
EXPECT_EQ(expected_target, gl_representation->GetTexture()->target());
// Create an FBO.
GLuint fbo = 0;
gl::GLApi* api = gl::g_current_gl_context;
api->glGenFramebuffersEXTFn(1, &fbo);
api->glBindFramebufferEXTFn(GL_FRAMEBUFFER, fbo);
// Attach the texture to FBO.
api->glFramebufferTexture2DEXTFn(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
gl_representation->GetTexture()->target(),
gl_representation->GetTexture()->service_id(), 0);
// Set the clear color to green.
api->glClearColorFn(0.0f, 1.0f, 0.0f, 1.0f);
api->glClearFn(GL_COLOR_BUFFER_BIT);
gl_representation.reset();
// Next create a SharedImageRepresentationSkia to read back the texture data.
auto skia_representation =
shared_image_representation_factory_->ProduceSkia(mailbox);
EXPECT_TRUE(skia_representation);
auto promise_texture = skia_representation->BeginReadAccess(nullptr);
EXPECT_TRUE(promise_texture);
if (promise_texture) {
GrBackendTexture backend_texture = promise_texture->backendTexture();
EXPECT_TRUE(backend_texture.isValid());
EXPECT_EQ(size.width(), backend_texture.width());
EXPECT_EQ(size.height(), backend_texture.height());
}
// Create an Sk Image from GrBackendTexture.
auto sk_image = SkImage::MakeFromTexture(
gr_context(), promise_texture->backendTexture(), kTopLeft_GrSurfaceOrigin,
kRGBA_8888_SkColorType, kOpaque_SkAlphaType, nullptr);
SkImageInfo dst_info =
SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType,
kOpaque_SkAlphaType, nullptr);
const int num_pixels = size.width() * size.height();
std::unique_ptr<uint8_t[]> dst_pixels(new uint8_t[num_pixels * 4]());
// Read back pixels from Sk Image.
EXPECT_TRUE(sk_image->readPixels(dst_info, dst_pixels.get(),
dst_info.minRowBytes(), 0, 0));
skia_representation->EndReadAccess();
// Compare the pixel values.
EXPECT_EQ(dst_pixels[0], 0);
EXPECT_EQ(dst_pixels[1], 255);
EXPECT_EQ(dst_pixels[2], 0);
EXPECT_EQ(dst_pixels[3], 255);
skia_representation.reset();
factory_ref.reset();
EXPECT_FALSE(mailbox_manager_.ConsumeTexture(mailbox));
}
} // anonymous namespace
} // namespace gpu
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include "gpu/command_buffer/service/external_vk_image_factory.h" #include "gpu/command_buffer/service/external_vk_image_factory.h"
#elif defined(OS_ANDROID) && BUILDFLAG(ENABLE_VULKAN) #elif defined(OS_ANDROID) && BUILDFLAG(ENABLE_VULKAN)
#include "gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h" #include "gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.h"
#elif defined(OS_MACOSX)
#include "gpu/command_buffer/service/shared_image_backing_factory_iosurface.h"
#endif #endif
namespace gpu { namespace gpu {
...@@ -77,6 +79,11 @@ SharedImageFactory::SharedImageFactory( ...@@ -77,6 +79,11 @@ SharedImageFactory::SharedImageFactory(
std::make_unique<SharedImageBackingFactoryAHB>(workarounds, std::make_unique<SharedImageBackingFactoryAHB>(workarounds,
gpu_feature_info, gpu_feature_info,
context_state)), context_state)),
#elif defined(OS_MACOSX)
interop_backing_factory_(
std::make_unique<SharedImageBackingFactoryIOSurface>(
workarounds,
gpu_feature_info)),
#endif #endif
wrapped_sk_image_factory_( wrapped_sk_image_factory_(
gpu_preferences.enable_raster_to_sk_image gpu_preferences.enable_raster_to_sk_image
......
...@@ -43,6 +43,9 @@ class SharedImageBackingAHB; ...@@ -43,6 +43,9 @@ class SharedImageBackingAHB;
class SharedImageRepresentationGLTexture; class SharedImageRepresentationGLTexture;
class SharedImageRepresentationGLTextureAHB; class SharedImageRepresentationGLTextureAHB;
class SharedImageRepresentationSkiaGLAHB; class SharedImageRepresentationSkiaGLAHB;
class SharedImageBackingIOSurface;
class SharedImageRepresentationGLTextureIOSurface;
class SharedImageRepresentationSkiaIOSurface;
namespace gles2 { namespace gles2 {
class GLStreamTextureImage; class GLStreamTextureImage;
...@@ -375,6 +378,9 @@ class GPU_GLES2_EXPORT Texture final : public TextureBase { ...@@ -375,6 +378,9 @@ class GPU_GLES2_EXPORT Texture final : public TextureBase {
friend class gpu::SharedImageBackingAHB; friend class gpu::SharedImageBackingAHB;
friend class gpu::SharedImageRepresentationGLTextureAHB; friend class gpu::SharedImageRepresentationGLTextureAHB;
friend class gpu::SharedImageRepresentationSkiaGLAHB; friend class gpu::SharedImageRepresentationSkiaGLAHB;
friend class gpu::SharedImageBackingIOSurface;
friend class gpu::SharedImageRepresentationGLTextureIOSurface;
friend class gpu::SharedImageRepresentationSkiaIOSurface;
friend class TextureDefinition; friend class TextureDefinition;
friend class TextureManager; friend class TextureManager;
friend class TextureRef; friend class TextureRef;
......
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