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 <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