Commit 806ba566 by Jonah Ryan-Davis Committed by Commit Bot

Extend ANGLE_iosurface_client_buffer to Vulkan backend for Swangle

Implement an IOSurface-backed pBuffer surface for the Vulkan backend on Mac, through SwANGLE. ANGLE will pass a raw pointer to Swiftshader and handle locking/unlocking the IOSurface. Bug: chromium:1015454 Change-Id: Ia3ead55334736003d405b54ba8dcc7701706fbb2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1965434 Commit-Queue: Jonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 5641d193
......@@ -55,6 +55,11 @@ New Tokens
EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
EGL_IOSURFACE_USAGE_HINT_ANGLE 0x348A
Accepted in the <attribute> parameter of
eglGetConfigAttrib:
EGL_BIND_TO_TEXTURE_TARGET_ANGLE 0x348D
Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
Replace the last sentence of paragraph 1 of Section 3.5.3 with the
......@@ -81,8 +86,8 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
- EGL_TEXTURE_FORMAT with a value of EGL_TEXTURE_RGBA
- EGL_WIDTH with a value between 1 and the width of <buffer>.
- EGL_HEIGHT with a value between 1 and the height of <buffer>.
- EGL_TEXTURE_TARGET with a value of EGL_TEXTURE_RECTANGLE_ANGLE (macOS)
or EGL_TEXTURE_2D (iOS)
- EGL_TEXTURE_TARGET with a value that matches the attribute
EGL_BIND_TO_TEXTURE_TARGET_ANGLE as queried from eglGetConfigAttrib.
- EGL_IOSURFACE_PLANE_ANGLE with a value between 0 and the number of
planes of <buffer> (exclusive).
......@@ -119,6 +124,15 @@ Additions to Chapter 3 of the EGL 1.4 Specification (EGL Functions and Errors)
of the associcated IOSurface object are undefined while the pbuffer is
bound to a client texture."
Append to the end of Table 3.1.
---------------------------------------------------------------------------
Attribute Type Notes
---------------------------------------------------------------------------
EGL_BIND_TO_TEXTURE_TARGET_ANGLE enum Texture target supported by
IOSurface-backed pbuffers.
---------------------------------------------------------------------------
Issues
1. Can RGB formats be supported?
......
......@@ -197,6 +197,7 @@ EGLAPI EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limi
#define EGL_IOSURFACE_USAGE_HINT_ANGLE 0x348A
#define EGL_IOSURFACE_READ_HINT_ANGLE 0x0001
#define EGL_IOSURFACE_WRITE_HINT_ANGLE 0x0002
#define EGL_BIND_TO_TEXTURE_TARGET_ANGLE 0x348D
#endif /* EGL_ANGLE_iosurface_client_buffer */
#ifndef EGL_ANGLE_create_context_extensions_enabled
......
......@@ -229,6 +229,12 @@ struct FeaturesVk : FeatureSetBase
"Use ANGLE's Vulkan deferred command graph.",
&members,
};
// Whether the VkDevice supports the VK_EXT_external_memory_host extension, on which the
// ANGLE_iosurface_client_buffer extension can be layered.
Feature supportsExternalMemoryHost = {
"supports_external_memory_host", FeatureCategory::VulkanFeatures,
"VkDevice supports the VK_EXT_external_memory_host extension", &members};
};
inline FeaturesVk::FeaturesVk() = default;
......
......@@ -18,6 +18,7 @@ namespace angle
{
std::string GetExecutablePath();
std::string GetExecutableDirectory();
std::string GetHelperExecutableDir();
const char *GetSharedLibraryExtension();
const char *GetExecutableExtension();
char GetPathSeparator();
......
......@@ -55,6 +55,19 @@ const char *GetPathSeparatorForEnvironmentVar()
return ":";
}
std::string GetHelperExecutableDir()
{
std::string directory;
static int dummySymbol = 0;
Dl_info dlInfo;
if (dladdr(&dummySymbol, &dlInfo) != 0)
{
std::string moduleName = dlInfo.dli_fname;
directory = moduleName.substr(0, moduleName.find_last_of('/') + 1);
}
return directory;
}
class PosixLibrary : public Library
{
public:
......@@ -63,13 +76,7 @@ class PosixLibrary : public Library
std::string directory;
if (searchType == SearchType::ApplicationDir)
{
static int dummySymbol = 0;
Dl_info dlInfo;
if (dladdr(&dummySymbol, &dlInfo) != 0)
{
std::string moduleName = dlInfo.dli_fname;
directory = moduleName.substr(0, moduleName.find_last_of('/') + 1);
}
directory = GetHelperExecutableDir();
}
std::string fullPath = directory + libraryName + "." + GetSharedLibraryExtension();
......
......@@ -100,4 +100,9 @@ char GetPathSeparator()
{
return '\\';
}
std::string GetHelperExecutableDir()
{
return "";
}
} // namespace angle
......@@ -34,6 +34,7 @@ Config::Config()
alphaMaskSize(0),
bindToTextureRGB(EGL_FALSE),
bindToTextureRGBA(EGL_FALSE),
bindToTextureTarget(EGL_TEXTURE_2D),
colorBufferType(EGL_RGB_BUFFER),
configCaveat(EGL_NONE),
configID(0),
......@@ -318,6 +319,9 @@ std::vector<const Config *> ConfigSet::filter(const AttributeMap &attributeMap)
case EGL_BIND_TO_TEXTURE_RGBA:
match = config.bindToTextureRGBA == static_cast<EGLBoolean>(attributeValue);
break;
case EGL_BIND_TO_TEXTURE_TARGET_ANGLE:
match = config.bindToTextureTarget == static_cast<EGLenum>(attributeValue);
break;
case EGL_MIN_SWAP_INTERVAL:
match = config.minSwapInterval == attributeValue;
break;
......
......@@ -43,6 +43,7 @@ struct Config
EGLint alphaMaskSize; // Bits of Alpha Mask in the mask buffer
EGLBoolean bindToTextureRGB; // True if bindable to RGB textures.
EGLBoolean bindToTextureRGBA; // True if bindable to RGBA textures.
EGLenum bindToTextureTarget; // Which texture target should be used for pbuffers
EGLenum colorBufferType; // Color buffer type
EGLenum configCaveat; // Any caveats for the configuration
EGLint configID; // Unique EGLConfig identifier
......
......@@ -3654,6 +3654,9 @@ void QueryConfigAttrib(const Config *config, EGLint attribute, EGLint *value)
case EGL_SURFACE_TYPE:
*value = config->surfaceType;
break;
case EGL_BIND_TO_TEXTURE_TARGET_ANGLE:
*value = config->bindToTextureTarget;
break;
case EGL_TRANSPARENT_TYPE:
*value = config->transparentType;
break;
......
......@@ -259,6 +259,8 @@ egl::ConfigSet DisplayCGL::generateConfigs()
config.bindToTextureRGB = EGL_FALSE;
config.bindToTextureRGBA = EGL_FALSE;
config.bindToTextureTarget = EGL_TEXTURE_RECTANGLE_ANGLE;
config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
config.minSwapInterval = 1;
......
......@@ -204,6 +204,12 @@ egl::ConfigSet DisplayEAGL::generateConfigs()
config.bindToTextureRGB = EGL_FALSE;
config.bindToTextureRGBA = EGL_FALSE;
# if !ANGLE_PLATFORM_MACCATALYST
config.bindToTextureTarget = EGL_TEXTURE_2D;
# else
config.bindToTextureTarget = EGL_TEXTURE_RECTANGLE_ANGLE;
# endif
config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
config.minSwapInterval = 1;
......
......@@ -45,18 +45,18 @@ _vulkan_backend_sources = [
"OverlayVk.h",
"PersistentCommandPool.cpp",
"PersistentCommandPool.h",
"ProgramVk.cpp",
"ProgramVk.h",
"ProgramPipelineVk.cpp",
"ProgramPipelineVk.h",
"ProgramVk.cpp",
"ProgramVk.h",
"QueryVk.cpp",
"QueryVk.h",
"RenderTargetVk.cpp",
"RenderTargetVk.h",
"RenderbufferVk.cpp",
"RenderbufferVk.h",
"RendererVk.cpp",
"RendererVk.h",
"RenderTargetVk.cpp",
"RenderTargetVk.h",
"SamplerVk.cpp",
"SamplerVk.h",
"SecondaryCommandBuffer.cpp",
......@@ -83,12 +83,12 @@ _vulkan_backend_sources = [
"vk_caps_utils.h",
"vk_ext_provoking_vertex.h",
"vk_format_table_autogen.cpp",
"vk_format_utils.h",
"vk_format_utils.cpp",
"vk_format_utils.h",
"vk_helpers.cpp",
"vk_helpers.h",
"vk_internal_shaders_autogen.h",
"vk_internal_shaders_autogen.cpp",
"vk_internal_shaders_autogen.h",
"vk_mandatory_format_support_table_autogen.cpp",
"vk_utils.cpp",
"vk_utils.h",
......@@ -144,10 +144,12 @@ if (is_ggp) {
if (is_mac) {
_vulkan_backend_sources += [
"mac/DisplayVkMac.mm",
"mac/DisplayVkMac.h",
"mac/WindowSurfaceVkMac.mm",
"mac/DisplayVkMac.mm",
"mac/IOSurfaceSurfaceVkMac.h",
"mac/IOSurfaceSurfaceVkMac.mm",
"mac/WindowSurfaceVkMac.h",
"mac/WindowSurfaceVkMac.mm",
]
}
......@@ -170,9 +172,7 @@ group("angle_vulkan_entry_points") {
"//third_party/fuchsia-sdk/sdk:vulkan",
]
} else if (!is_android && !is_ggp) {
data_deps = [
"$angle_root/third_party/vulkan-loader/src:libvulkan",
]
data_deps = [ "$angle_root/third_party/vulkan-loader/src:libvulkan" ]
}
}
......
......@@ -95,10 +95,12 @@ class DisplayVk : public DisplayImpl, public vk::Context
void populateFeatureList(angle::FeatureList *features) override;
protected:
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
private:
virtual SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state,
EGLNativeWindowType window) = 0;
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
void generateCaps(egl::Caps *outCaps) const override;
mutable angle::ScratchBuffer mScratchBuffer;
......
......@@ -231,6 +231,21 @@ const char *GetVkObjectTypeName(VkObjectType type)
}
}
// This function is unused on Android/Fuschia/GGP
#if !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) && \
!defined(ANGLE_PLATFORM_GGP)
const std::string WrapICDEnvironment(const char *icdEnvironment)
{
# if defined(ANGLE_PLATFORM_APPLE)
// On MacOS the libraries are bundled into the application directory
std::string ret = angle::GetHelperExecutableDir() + icdEnvironment;
return ret;
# endif // defined(ANGLE_PLATFORM_APPLE)
return icdEnvironment;
}
#endif // !defined(ANGLE_PLATFORM_ANDROID) && !defined(ANGLE_PLATFORM_FUCHSIA) &&
// !defined(ANGLE_PLATFORM_GGP)
VKAPI_ATTR VkBool32 VKAPI_CALL
DebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
......@@ -370,7 +385,7 @@ class ScopedVkLoaderEnvironment : angle::NonCopyable
!defined(ANGLE_PLATFORM_GGP)
if (icd == vk::ICD::Mock)
{
if (!setICDEnvironment(ANGLE_VK_MOCK_ICD_JSON))
if (!setICDEnvironment(WrapICDEnvironment(ANGLE_VK_MOCK_ICD_JSON).c_str()))
{
ERR() << "Error setting environment for Mock/Null Driver.";
}
......@@ -378,7 +393,7 @@ class ScopedVkLoaderEnvironment : angle::NonCopyable
# if defined(ANGLE_VK_SWIFTSHADER_ICD_JSON)
else if (icd == vk::ICD::SwiftShader)
{
if (!setICDEnvironment(ANGLE_VK_SWIFTSHADER_ICD_JSON))
if (!setICDEnvironment(WrapICDEnvironment(ANGLE_VK_SWIFTSHADER_ICD_JSON).c_str()))
{
ERR() << "Error setting environment for SwiftShader.";
}
......@@ -552,6 +567,7 @@ RendererVk::RendererVk()
mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
mMaxVertexAttribDivisor(1),
mMaxVertexAttribStride(0),
mMinImportedHostPointerAlignment(1),
mDevice(VK_NULL_HANDLE),
mLastCompletedQueueSerial(mQueueSerialFactory.generate()),
mCurrentQueueSerial(mQueueSerialFactory.generate()),
......@@ -922,6 +938,10 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
mPhysicalDeviceSubgroupProperties = {};
mPhysicalDeviceSubgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
mPhysicalDeviceExternalMemoryHostProperties = {};
mPhysicalDeviceExternalMemoryHostProperties.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
if (!vkGetPhysicalDeviceProperties2KHR || !vkGetPhysicalDeviceFeatures2KHR)
{
return;
......@@ -959,6 +979,12 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
vk::AddToPNextChain(&deviceFeatures, &mTransformFeedbackFeatures);
}
// Query external memory host properties
if (ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames))
{
vk::AddToPNextChain(&deviceProperties, &mPhysicalDeviceExternalMemoryHostProperties);
}
// Query subgroup properties
vk::AddToPNextChain(&deviceProperties, &mPhysicalDeviceSubgroupProperties);
......@@ -966,12 +992,13 @@ void RendererVk::queryDeviceExtensionFeatures(const ExtensionNameList &deviceExt
vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties);
// Clean up pNext chains
mLineRasterizationFeatures.pNext = nullptr;
mProvokingVertexFeatures.pNext = nullptr;
mVertexAttributeDivisorFeatures.pNext = nullptr;
mVertexAttributeDivisorProperties.pNext = nullptr;
mTransformFeedbackFeatures.pNext = nullptr;
mPhysicalDeviceSubgroupProperties.pNext = nullptr;
mLineRasterizationFeatures.pNext = nullptr;
mProvokingVertexFeatures.pNext = nullptr;
mVertexAttributeDivisorFeatures.pNext = nullptr;
mVertexAttributeDivisorProperties.pNext = nullptr;
mTransformFeedbackFeatures.pNext = nullptr;
mPhysicalDeviceSubgroupProperties.pNext = nullptr;
mPhysicalDeviceExternalMemoryHostProperties.pNext = nullptr;
}
angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex)
......@@ -1193,6 +1220,13 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
vk::AddToPNextChain(&createInfo, &mTransformFeedbackFeatures);
}
if (getFeatures().supportsExternalMemoryHost.enabled)
{
enabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME);
mMinImportedHostPointerAlignment =
mPhysicalDeviceExternalMemoryHostProperties.minImportedHostPointerAlignment;
}
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.flags = 0;
createInfo.queueCreateInfoCount = 1;
......@@ -1563,6 +1597,10 @@ void RendererVk::initFeatures(DisplayVk *displayVk, const ExtensionNameList &dev
ANGLE_FEATURE_CONDITION((&mFeatures), commandGraph, true);
ANGLE_FEATURE_CONDITION(
(&mFeatures), supportsExternalMemoryHost,
ExtensionFound(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, deviceExtensionNames));
angle::PlatformMethods *platform = ANGLEPlatformCurrent();
platform->overrideFeaturesVk(platform, &mFeatures);
......
......@@ -145,6 +145,11 @@ class RendererVk : angle::NonCopyable
uint32_t getMaxVertexAttribDivisor() const { return mMaxVertexAttribDivisor; }
VkDeviceSize getMaxVertexAttribStride() const { return mMaxVertexAttribStride; }
VkDeviceSize getMinImportedHostPointerAlignment() const
{
return mMinImportedHostPointerAlignment;
}
bool isMockICDEnabled() const { return mEnabledICD == vk::ICD::Mock; }
// Query the format properties for select bits (linearTilingFeatures, optimalTilingFeatures and
......@@ -264,6 +269,7 @@ class RendererVk : angle::NonCopyable
VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT mVertexAttributeDivisorProperties;
VkPhysicalDeviceTransformFeedbackFeaturesEXT mTransformFeedbackFeatures;
VkPhysicalDeviceSubgroupProperties mPhysicalDeviceSubgroupProperties;
VkPhysicalDeviceExternalMemoryHostPropertiesEXT mPhysicalDeviceExternalMemoryHostProperties;
std::vector<VkQueueFamilyProperties> mQueueFamilyProperties;
std::mutex mQueueMutex;
angle::PackedEnumMap<egl::ContextPriority, VkQueue> mQueues;
......@@ -271,6 +277,7 @@ class RendererVk : angle::NonCopyable
uint32_t mCurrentQueueFamilyIndex;
uint32_t mMaxVertexAttribDivisor;
VkDeviceSize mMaxVertexAttribStride;
VkDeviceSize mMinImportedHostPointerAlignment;
VkDevice mDevice;
AtomicSerialFactory mQueueSerialFactory;
AtomicSerialFactory mShaderSerialFactory;
......
......@@ -155,6 +155,49 @@ angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *display
return angle::Result::Continue;
}
angle::Result OffscreenSurfaceVk::AttachmentImage::initializeWithExternalMemory(
DisplayVk *displayVk,
EGLint width,
EGLint height,
const vk::Format &vkFormat,
GLint samples,
void *buffer)
{
RendererVk *renderer = displayVk->getRenderer();
ASSERT(renderer->getFeatures().supportsExternalMemoryHost.enabled);
const angle::Format &textureFormat = vkFormat.actualImageFormat();
bool isDepthOrStencilFormat = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVKDepthStencilImageUsageFlags
: kSurfaceVKColorImageUsageFlags;
VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
std::max(static_cast<uint32_t>(height), 1u), 1u};
ANGLE_TRY(
image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, samples, usage, 0, 0, 1, 1));
VkImportMemoryHostPointerInfoEXT importMemoryHostPointerInfo = {};
importMemoryHostPointerInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT;
importMemoryHostPointerInfo.pNext = nullptr;
importMemoryHostPointerInfo.handleType =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT;
importMemoryHostPointerInfo.pHostPointer = buffer;
VkMemoryRequirements externalMemoryRequirements;
image.getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
VkMemoryPropertyFlags flags = 0;
ANGLE_TRY(image.initExternalMemory(displayVk, renderer->getMemoryProperties(),
externalMemoryRequirements, &importMemoryHostPointerInfo,
VK_QUEUE_FAMILY_EXTERNAL, flags));
// Clear the image if it has emulated channels.
image.stageClearIfEmulatedFormat(gl::ImageIndex::Make2D(0), vkFormat);
return angle::Result::Continue;
}
void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display)
{
DisplayVk *displayVk = vk::GetImpl(display);
......
......@@ -75,7 +75,7 @@ class OffscreenSurfaceVk : public SurfaceVk
vk::ImageHelper *getColorAttachmentImage();
private:
protected:
struct AttachmentImage final : angle::NonCopyable
{
AttachmentImage();
......@@ -86,13 +86,21 @@ class OffscreenSurfaceVk : public SurfaceVk
EGLint height,
const vk::Format &vkFormat,
GLint samples);
angle::Result initializeWithExternalMemory(DisplayVk *displayVk,
EGLint width,
EGLint height,
const vk::Format &vkFormat,
GLint samples,
void *buffer);
void destroy(const egl::Display *display);
vk::ImageHelper image;
vk::ImageViewHelper imageViews;
};
angle::Result initializeImpl(DisplayVk *displayVk);
virtual angle::Result initializeImpl(DisplayVk *displayVk);
EGLint mWidth;
EGLint mHeight;
......
......@@ -25,9 +25,21 @@ class DisplayVkMac : public DisplayVk
SurfaceImpl *createWindowSurfaceVk(const egl::SurfaceState &state,
EGLNativeWindowType window) override;
SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) override;
egl::ConfigSet generateConfigs() override;
bool checkConfigSupport(egl::Config *config) override;
void generateExtensions(egl::DisplayExtensions *outExtensions) const override;
egl::Error validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override;
const char *getWSIExtension() const override;
};
......
......@@ -11,6 +11,8 @@
#include <vulkan/vulkan.h>
#include "libANGLE/renderer/vulkan/RendererVk.h"
#include "libANGLE/renderer/vulkan/mac/IOSurfaceSurfaceVkMac.h"
#include "libANGLE/renderer/vulkan/mac/WindowSurfaceVkMac.h"
#include "libANGLE/renderer/vulkan/vk_caps_utils.h"
......@@ -34,6 +36,16 @@ SurfaceImpl *DisplayVkMac::createWindowSurfaceVk(const egl::SurfaceState &state,
return new WindowSurfaceVkMac(state, window);
}
SurfaceImpl *DisplayVkMac::createPbufferFromClientBuffer(const egl::SurfaceState &state,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs)
{
ASSERT(buftype == EGL_IOSURFACE_ANGLE);
return new IOSurfaceSurfaceVkMac(state, clientBuffer, attribs);
}
egl::ConfigSet DisplayVkMac::generateConfigs()
{
constexpr GLenum kColorFormats[] = {GL_BGRA8_EXT, GL_BGRX8_ANGLEX};
......@@ -62,4 +74,26 @@ DisplayImpl *CreateVulkanMacDisplay(const egl::DisplayState &state)
return new DisplayVkMac(state);
}
void DisplayVkMac::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->iosurfaceClientBuffer =
getRenderer()->getFeatures().supportsExternalMemoryHost.enabled;
DisplayVk::generateExtensions(outExtensions);
}
egl::Error DisplayVkMac::validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
ASSERT(buftype == EGL_IOSURFACE_ANGLE);
if (!IOSurfaceSurfaceVkMac::ValidateAttributes(this, clientBuffer, attribs))
{
return egl::EglBadAttribute();
}
return egl::NoError();
}
} // namespace rx
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// IOSurfaceSurfaceVkMac.h:
// Subclasses SurfaceVk for the Mac platform to implement PBuffers using an IOSurface
//
#ifndef LIBANGLE_RENDERER_VULKAN_MAC_IOSURFACESURFACEVKMAC_H_
#define LIBANGLE_RENDERER_VULKAN_MAC_IOSURFACESURFACEVKMAC_H_
#include "libANGLE/renderer/vulkan/SurfaceVk.h"
struct __IOSurface;
typedef __IOSurface *IOSurfaceRef;
namespace egl
{
class AttributeMap;
} // namespace egl
namespace rx
{
class IOSurfaceSurfaceVkMac : public OffscreenSurfaceVk
{
public:
IOSurfaceSurfaceVkMac(const egl::SurfaceState &state,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs);
~IOSurfaceSurfaceVkMac() override;
egl::Error initialize(const egl::Display *display) override;
egl::Error unMakeCurrent(const gl::Context *context) override;
egl::Error bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer) override;
egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
static bool ValidateAttributes(const DisplayVk *displayVk,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs);
protected:
angle::Result initializeImpl(DisplayVk *displayVk) override;
private:
IOSurfaceRef mIOSurface;
int mPlane;
int mFormatIndex;
};
} // namespace rx
#endif // LIBANGLE_RENDERER_VULKAN_MAC_IOSURFACESURFACEVKMAC_H_
//
// Copyright 2020 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// IOSurfaceSurfaceVkMac.mm:
// Implements methods from IOSurfaceSurfaceVkMac.
//
#include "libANGLE/renderer/vulkan/mac/IOSurfaceSurfaceVkMac.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/vulkan/ContextVk.h"
#include "libANGLE/renderer/vulkan/DisplayVk.h"
#include "libANGLE/renderer/vulkan/FramebufferVk.h"
#include "libANGLE/renderer/vulkan/TextureVk.h"
#include <IOSurface/IOSurface.h>
namespace rx
{
namespace
{
struct IOSurfaceFormatInfo
{
GLenum internalFormat;
GLenum type;
size_t componentBytes;
GLenum nativeSizedInternalFormat;
};
// clang-format off
constexpr std::array<IOSurfaceFormatInfo, 6> kIOSurfaceFormats = {{
{GL_RED, GL_UNSIGNED_BYTE, 1, GL_R8 },
{GL_R16UI, GL_UNSIGNED_SHORT, 2, GL_R16UI },
{GL_RG, GL_UNSIGNED_BYTE, 2, GL_RG8 },
{GL_RGB, GL_UNSIGNED_BYTE, 4, GL_BGRA8_EXT},
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, GL_BGRA8_EXT },
{GL_RGBA, GL_HALF_FLOAT, 8, GL_RGBA16F },
}};
// clang-format on
int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
{
for (int i = 0; i < static_cast<int>(kIOSurfaceFormats.size()); ++i)
{
const auto &formatInfo = kIOSurfaceFormats[i];
if (formatInfo.internalFormat == internalFormat && formatInfo.type == type)
{
return i;
}
}
return -1;
}
} // anonymous namespace
IOSurfaceSurfaceVkMac::IOSurfaceSurfaceVkMac(const egl::SurfaceState &state,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
: OffscreenSurfaceVk(state), mIOSurface(nullptr), mPlane(0), mFormatIndex(-1)
{
// Keep reference to the IOSurface so it doesn't get deleted while the pbuffer exists.
mIOSurface = reinterpret_cast<IOSurfaceRef>(buffer);
CFRetain(mIOSurface);
// Extract attribs useful for the call to CGLTexImageIOSurface2D
mWidth = static_cast<int>(attribs.get(EGL_WIDTH));
mHeight = static_cast<int>(attribs.get(EGL_HEIGHT));
mPlane = static_cast<int>(attribs.get(EGL_IOSURFACE_PLANE_ANGLE));
EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
EGLAttrib type = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
mFormatIndex =
FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
ASSERT(mFormatIndex >= 0);
}
IOSurfaceSurfaceVkMac::~IOSurfaceSurfaceVkMac()
{
if (mIOSurface != nullptr)
{
CFRelease(mIOSurface);
mIOSurface = nullptr;
}
}
egl::Error IOSurfaceSurfaceVkMac::initialize(const egl::Display *display)
{
DisplayVk *displayVk = vk::GetImpl(display);
angle::Result result = initializeImpl(displayVk);
return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
}
angle::Result IOSurfaceSurfaceVkMac::initializeImpl(DisplayVk *displayVk)
{
RendererVk *renderer = displayVk->getRenderer();
const egl::Config *config = mState.config;
GLint samples = 1;
if (config->sampleBuffers && config->samples > 1)
{
samples = config->samples;
}
ANGLE_VK_CHECK(displayVk, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
// Swiftshader will use the raw pointer to the buffer referenced by the IOSurfaceRef
ANGLE_TRY(mColorAttachment.initializeWithExternalMemory(
displayVk, mWidth, mHeight,
renderer->getFormat(kIOSurfaceFormats[mFormatIndex].nativeSizedInternalFormat), samples,
IOSurfaceGetBaseAddressOfPlane(mIOSurface, mPlane)));
mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, 0, 0);
return angle::Result::Continue;
}
egl::Error IOSurfaceSurfaceVkMac::unMakeCurrent(const gl::Context *context)
{
ASSERT(context != nullptr);
ContextVk *contextVk = vk::GetImpl(context);
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
angle::Result result = contextVk->flushImpl(nullptr);
return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
}
egl::Error IOSurfaceSurfaceVkMac::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer)
{
IOSurfaceLock(mIOSurface, 0, nullptr);
return egl::NoError();
}
egl::Error IOSurfaceSurfaceVkMac::releaseTexImage(const gl::Context *context, EGLint buffer)
{
ASSERT(context != nullptr);
ContextVk *contextVk = vk::GetImpl(context);
DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
angle::Result result = contextVk->finishImpl();
IOSurfaceUnlock(mIOSurface, 0, nullptr);
return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
}
// static
bool IOSurfaceSurfaceVkMac::ValidateAttributes(const DisplayVk *displayVk,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
ASSERT(displayVk != nullptr);
RendererVk *renderer = displayVk->getRenderer();
IOSurfaceRef ioSurface = reinterpret_cast<IOSurfaceRef>(buffer);
// The plane must exist for this IOSurface. IOSurfaceGetPlaneCount can return 0 for non-planar
// ioSurfaces but we will treat non-planar like it is a single plane.
size_t surfacePlaneCount = std::max(size_t(1), IOSurfaceGetPlaneCount(ioSurface));
EGLAttrib plane = attribs.get(EGL_IOSURFACE_PLANE_ANGLE);
if (plane < 0 || static_cast<size_t>(plane) >= surfacePlaneCount)
{
return false;
}
// The width height specified must be at least (1, 1) and at most the plane size
EGLAttrib width = attribs.get(EGL_WIDTH);
EGLAttrib height = attribs.get(EGL_HEIGHT);
if (width <= 0 || static_cast<size_t>(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) ||
height <= 0 || static_cast<size_t>(height) > IOSurfaceGetHeightOfPlane(ioSurface, plane))
{
return false;
}
// Find this IOSurface format
EGLAttrib internalFormat = attribs.get(EGL_TEXTURE_INTERNAL_FORMAT_ANGLE);
EGLAttrib type = attribs.get(EGL_TEXTURE_TYPE_ANGLE);
int formatIndex =
FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
if (formatIndex < 0)
{
return false;
}
// Check that the format matches this IOSurface plane
if (IOSurfaceGetBytesPerElementOfPlane(ioSurface, plane) !=
kIOSurfaceFormats[formatIndex].componentBytes)
{
return false;
}
void *pointer = IOSurfaceGetBaseAddressOfPlane(ioSurface, plane);
VkMemoryHostPointerPropertiesEXT memoryHostPointerProperties = {};
memoryHostPointerProperties.sType = VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT;
vkGetMemoryHostPointerPropertiesEXT(
renderer->getDevice(), VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT,
pointer, &memoryHostPointerProperties);
bool hostVisible =
memoryHostPointerProperties.memoryTypeBits & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
if (!hostVisible)
{
return false;
}
VkDeviceSize alignment = renderer->getMinImportedHostPointerAlignment();
if (reinterpret_cast<size_t>(pointer) % alignment != 0)
{
return false;
}
return true;
}
} // namespace rx
......@@ -178,6 +178,7 @@ Error ValidateConfigAttribute(const Display *display, EGLAttrib attribute)
case EGL_SAMPLES:
case EGL_SAMPLE_BUFFERS:
case EGL_SURFACE_TYPE:
case EGL_BIND_TO_TEXTURE_TARGET_ANGLE:
case EGL_TRANSPARENT_TYPE:
case EGL_TRANSPARENT_BLUE_VALUE:
case EGL_TRANSPARENT_GREEN_VALUE:
......@@ -1874,19 +1875,11 @@ Error ValidateCreatePbufferFromClientBuffer(Display *display,
if (buftype == EGL_IOSURFACE_ANGLE)
{
#if ANGLE_PLATFORM_MACOS || ANGLE_PLATFORM_MACCATALYST
if (textureTarget != EGL_TEXTURE_RECTANGLE_ANGLE)
if (static_cast<EGLenum>(textureTarget) != config->bindToTextureTarget)
{
return EglBadAttribute()
<< "EGL_IOSURFACE requires the EGL_TEXTURE_RECTANGLE target on desktop macOS";
<< "EGL_IOSURFACE requires the texture target to match the config";
}
#else // ANGLE_PLATFORM_MACOS || ANGLE_PLATFORM_MACCATALYST
if (textureTarget != EGL_TEXTURE_2D)
{
return EglBadAttribute() << "EGL_IOSURFACE requires the EGL_TEXTURE_2D target on iOS";
}
#endif // ANGLE_PLATFORM_MACOS || ANGLE_PLATFORM_MACCATALYST
if (textureFormat != EGL_TEXTURE_RGBA)
{
return EglBadAttribute() << "EGL_IOSURFACE requires the EGL_TEXTURE_RGBA format";
......
......@@ -372,6 +372,12 @@ ANGLETestBase::ANGLETestBase(const PlatformParameters &params)
PlatformParameters withMethods = params;
withMethods.eglParameters.platformMethods = &gDefaultPlatformMethods;
// We don't build vulkan debug layers on Mac (http://anglebug.com/4376)
if (IsOSX() && withMethods.getRenderer() == EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE)
{
withMethods.eglParameters.debugLayersEnabled = false;
}
auto iter = gFixtures.find(withMethods);
if (iter != gFixtures.end())
{
......
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