Commit f2aa9d5d by Le Hoang Quyen Committed by Commit Bot

Reland: Metal: Support importing external metal textures

This relands I4d4a88cfbb77d8b7508b787c7fec44073d3b11b0. Fixes: - uninstantiated ImageTestMetal error - failed ImageTest.ANGLEExtensionAvailability on ARM mac. Bug: angleproject:5763 Bug: angleproject:5814 Change-Id: I906fe52baefd6be3c6e00f594795bd527df01616 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2820178Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Le Hoang Quyen <le.hoang.q@gmail.com>
parent eac31b7d
Name
ANGLE_metal_texture_client_buffer
Name Strings
EGL_ANGLE_metal_texture_client_buffer
Contributors
Le Hoang Quyen
Contacts
Jamie Madill, Google (jmadill 'at' google 'dot' com)
Le Hoang Quyen (lehoangq 'at' gmail.com)
Status
Draft
Version
Version 1, Jul 19, 2020
Number
EGL Extension #??
Dependencies
This extension is written against the wording of the EGL 1.4
Specification.
Overview
This extension allows creating EGL images from external metal texture objects.
New Types
None
New Procedures and Functions
None
New Tokens
Accepted in the <target> parameter of eglCreateImageKHR:
EGL_METAL_TEXTURE_ANGLE 0x34A7
Additions to Chapter 2 of the EGL 1.2 Specification (EGL Operation)
Add to section 2.5.1 "EGLImage Specification" (as defined by the
EGL_KHR_image_base specification), in the description of
eglCreateImageKHR:
"Values accepted for <target> are listed in Table aaa, below.
+----------------------------+-----------------------------------------+
| <target> | Notes |
+----------------------------+-----------------------------------------+
| EGL_METAL_TEXTURE_ANGLE | Used for Metal texture objects |
+----------------------------+-----------------------------------------+
Table aaa. Legal values for eglCreateImageKHR <target> parameter
...
If <target> is EGL_METAL_TEXTURE_ANGLE, <dpy> must be a valid display, <ctx>
must be EGL_NO_CONTEXT, <buffer> must be a pointer to a valid MTLTexture
object (cast into the type EGLClientBuffer), and attributes are ignored.
The width and height of the pbuffer are determined by the width and height
of <buffer>."
If the EGL_ANGLE_device_metal extension is present, the provided Metal texture
object must have been created by the same Metal device queried from the
display. If these requirements are not met, an EGL_BAD_PARAMETER error is
generated."
Revision History
Version 1, 2020/19/07 - First draft
...@@ -228,6 +228,11 @@ EGLAPI EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limi ...@@ -228,6 +228,11 @@ EGLAPI EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limi
#define EGL_BIND_TO_TEXTURE_TARGET_ANGLE 0x348D #define EGL_BIND_TO_TEXTURE_TARGET_ANGLE 0x348D
#endif /* EGL_ANGLE_iosurface_client_buffer */ #endif /* EGL_ANGLE_iosurface_client_buffer */
#ifndef ANGLE_metal_texture_client_buffer
#define ANGLE_metal_texture_client_buffer 1
#define EGL_METAL_TEXTURE_ANGLE 0x34A7
#endif /* ANGLE_metal_texture_client_buffer */
#ifndef EGL_ANGLE_create_context_extensions_enabled #ifndef EGL_ANGLE_create_context_extensions_enabled
#define EGL_ANGLE_create_context_extensions_enabled 1 #define EGL_ANGLE_create_context_extensions_enabled 1
#define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F #define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
"src/libANGLE/renderer/angle_format_map.json": "src/libANGLE/renderer/angle_format_map.json":
"46b589fc0fc306b2f7c97ee7bb08baee", "46b589fc0fc306b2f7c97ee7bb08baee",
"src/libANGLE/renderer/metal/gen_mtl_format_table.py": "src/libANGLE/renderer/metal/gen_mtl_format_table.py":
"50165403832b36233870f612e60530da", "aabe2ff87c8d03cae69125535089e392",
"src/libANGLE/renderer/metal/mtl_format_map.json": "src/libANGLE/renderer/metal/mtl_format_map.json":
"848c1e2f6d76115e3d0499346b5684d5", "848c1e2f6d76115e3d0499346b5684d5",
"src/libANGLE/renderer/metal/mtl_format_table_autogen.mm": "src/libANGLE/renderer/metal/mtl_format_table_autogen.mm":
"1972cdd31eff1fddaa965e2027710fa0" "6d9b7743cbca2a3b2485c748c289e58c"
} }
\ No newline at end of file
...@@ -1255,6 +1255,7 @@ bool IsExternalImageTarget(EGLenum target) ...@@ -1255,6 +1255,7 @@ bool IsExternalImageTarget(EGLenum target)
case EGL_NATIVE_BUFFER_ANDROID: case EGL_NATIVE_BUFFER_ANDROID:
case EGL_D3D11_TEXTURE_ANGLE: case EGL_D3D11_TEXTURE_ANGLE:
case EGL_LINUX_DMA_BUF_EXT: case EGL_LINUX_DMA_BUF_EXT:
case EGL_METAL_TEXTURE_ANGLE:
return true; return true;
default: default:
......
...@@ -1466,6 +1466,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const ...@@ -1466,6 +1466,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_ANGLE_program_cache_control", programCacheControl, &extensionStrings); InsertExtensionString("EGL_ANGLE_program_cache_control", programCacheControl, &extensionStrings);
InsertExtensionString("EGL_ANGLE_robust_resource_initialization", robustResourceInitialization, &extensionStrings); InsertExtensionString("EGL_ANGLE_robust_resource_initialization", robustResourceInitialization, &extensionStrings);
InsertExtensionString("EGL_ANGLE_iosurface_client_buffer", iosurfaceClientBuffer, &extensionStrings); InsertExtensionString("EGL_ANGLE_iosurface_client_buffer", iosurfaceClientBuffer, &extensionStrings);
InsertExtensionString("EGL_ANGLE_metal_texture_client_buffer", mtlTextureClientBuffer, &extensionStrings);
InsertExtensionString("EGL_ANGLE_create_context_extensions_enabled", createContextExtensionsEnabled, &extensionStrings); InsertExtensionString("EGL_ANGLE_create_context_extensions_enabled", createContextExtensionsEnabled, &extensionStrings);
InsertExtensionString("EGL_ANDROID_presentation_time", presentationTime, &extensionStrings); InsertExtensionString("EGL_ANDROID_presentation_time", presentationTime, &extensionStrings);
InsertExtensionString("EGL_ANDROID_blob_cache", blobCache, &extensionStrings); InsertExtensionString("EGL_ANDROID_blob_cache", blobCache, &extensionStrings);
......
...@@ -1139,6 +1139,9 @@ struct DisplayExtensions ...@@ -1139,6 +1139,9 @@ struct DisplayExtensions
// EGL_ANGLE_iosurface_client_buffer // EGL_ANGLE_iosurface_client_buffer
bool iosurfaceClientBuffer = false; bool iosurfaceClientBuffer = false;
// EGL_ANGLE_metal_texture_client_buffer
bool mtlTextureClientBuffer = false;
// EGL_ANGLE_create_context_extensions_enabled // EGL_ANGLE_create_context_extensions_enabled
bool createContextExtensionsEnabled = false; bool createContextExtensionsEnabled = false;
......
...@@ -23,6 +23,8 @@ _metal_backend_sources = [ ...@@ -23,6 +23,8 @@ _metal_backend_sources = [
"DisplayMtl_api.h", "DisplayMtl_api.h",
"FrameBufferMtl.h", "FrameBufferMtl.h",
"FrameBufferMtl.mm", "FrameBufferMtl.mm",
"ImageMtl.h",
"ImageMtl.mm",
"ProgramMtl.h", "ProgramMtl.h",
"ProgramMtl.mm", "ProgramMtl.mm",
"QueryMtl.h", "QueryMtl.h",
......
...@@ -84,6 +84,10 @@ class DisplayMtl : public DisplayImpl ...@@ -84,6 +84,10 @@ class DisplayMtl : public DisplayImpl
ShareGroupImpl *createShareGroup() override; ShareGroupImpl *createShareGroup() override;
ExternalImageSiblingImpl *createExternalImageSibling(const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs) override;
gl::Version getMaxSupportedESVersion() const override; gl::Version getMaxSupportedESVersion() const override;
gl::Version getMaxConformantESVersion() const override; gl::Version getMaxConformantESVersion() const override;
...@@ -103,6 +107,11 @@ class DisplayMtl : public DisplayImpl ...@@ -103,6 +107,11 @@ class DisplayMtl : public DisplayImpl
EGLClientBuffer clientBuffer, EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override; const egl::AttributeMap &attribs) const override;
egl::Error validateImageClientBuffer(const gl::Context *context,
EGLenum target,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override;
egl::ConfigSet generateConfigs() override; egl::ConfigSet generateConfigs() override;
gl::Caps getNativeCaps() const; gl::Caps getNativeCaps() const;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "libANGLE/renderer/glslang_wrapper_utils.h" #include "libANGLE/renderer/glslang_wrapper_utils.h"
#include "libANGLE/renderer/metal/ContextMtl.h" #include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/DeviceMtl.h" #include "libANGLE/renderer/metal/DeviceMtl.h"
#include "libANGLE/renderer/metal/ImageMtl.h"
#include "libANGLE/renderer/metal/SurfaceMtl.h" #include "libANGLE/renderer/metal/SurfaceMtl.h"
#include "libANGLE/renderer/metal/SyncMtl.h" #include "libANGLE/renderer/metal/SyncMtl.h"
#include "libANGLE/renderer/metal/mtl_common.h" #include "libANGLE/renderer/metal/mtl_common.h"
...@@ -229,8 +230,7 @@ ImageImpl *DisplayMtl::createImage(const egl::ImageState &state, ...@@ -229,8 +230,7 @@ ImageImpl *DisplayMtl::createImage(const egl::ImageState &state,
EGLenum target, EGLenum target,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
UNIMPLEMENTED(); return new ImageMtl(state, context);
return nullptr;
} }
rx::ContextImpl *DisplayMtl::createContext(const gl::State &state, rx::ContextImpl *DisplayMtl::createContext(const gl::State &state,
...@@ -255,6 +255,22 @@ ShareGroupImpl *DisplayMtl::createShareGroup() ...@@ -255,6 +255,22 @@ ShareGroupImpl *DisplayMtl::createShareGroup()
return new ShareGroupMtl(); return new ShareGroupMtl();
} }
ExternalImageSiblingImpl *DisplayMtl::createExternalImageSibling(const gl::Context *context,
EGLenum target,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
switch (target)
{
case EGL_METAL_TEXTURE_ANGLE:
return new TextureImageSiblingMtl(buffer);
default:
UNREACHABLE();
return nullptr;
}
}
gl::Version DisplayMtl::getMaxSupportedESVersion() const gl::Version DisplayMtl::getMaxSupportedESVersion() const
{ {
// NOTE(hqle): Supports GLES 3.0 on iOS GPU family 4+ for now. // NOTE(hqle): Supports GLES 3.0 on iOS GPU family 4+ for now.
...@@ -295,6 +311,7 @@ void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -295,6 +311,7 @@ void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->surfacelessContext = true; outExtensions->surfacelessContext = true;
outExtensions->displayTextureShareGroup = true; outExtensions->displayTextureShareGroup = true;
outExtensions->displaySemaphoreShareGroup = true; outExtensions->displaySemaphoreShareGroup = true;
outExtensions->mtlTextureClientBuffer = true;
if (mFeatures.hasEvents.enabled) if (mFeatures.hasEvents.enabled)
{ {
...@@ -307,6 +324,10 @@ void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -307,6 +324,10 @@ void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const
// this extension so that ANGLE can be initialized in Chrome. WebGL will fail to use // this extension so that ANGLE can be initialized in Chrome. WebGL will fail to use
// this extension (anglebug.com/4929) // this extension (anglebug.com/4929)
outExtensions->robustResourceInitialization = true; outExtensions->robustResourceInitialization = true;
// EGL_KHR_image
outExtensions->image = true;
outExtensions->imageBase = true;
} }
void DisplayMtl::generateCaps(egl::Caps *outCaps) const {} void DisplayMtl::generateCaps(egl::Caps *outCaps) const {}
...@@ -439,6 +460,26 @@ egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration, ...@@ -439,6 +460,26 @@ egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration,
return egl::NoError(); return egl::NoError();
} }
egl::Error DisplayMtl::validateImageClientBuffer(const gl::Context *context,
EGLenum target,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
switch (target)
{
case EGL_METAL_TEXTURE_ANGLE:
if (!TextureImageSiblingMtl::ValidateClientBuffer(this, clientBuffer))
{
return egl::EglBadAttribute();
}
break;
default:
UNREACHABLE();
return egl::EglBadAttribute();
}
return egl::NoError();
}
gl::Caps DisplayMtl::getNativeCaps() const gl::Caps DisplayMtl::getNativeCaps() const
{ {
ensureCapsInitialized(); ensureCapsInitialized();
...@@ -649,7 +690,7 @@ void DisplayMtl::initializeExtensions() const ...@@ -649,7 +690,7 @@ void DisplayMtl::initializeExtensions() const
// Enable EXT_blend_minmax // Enable EXT_blend_minmax
mNativeExtensions.blendMinMax = true; mNativeExtensions.blendMinMax = true;
mNativeExtensions.eglImageOES = false; mNativeExtensions.eglImageOES = true;
mNativeExtensions.eglImageExternalOES = false; mNativeExtensions.eglImageExternalOES = false;
// NOTE(hqle): Support GL_OES_EGL_image_external_essl3. // NOTE(hqle): Support GL_OES_EGL_image_external_essl3.
mNativeExtensions.eglImageExternalEssl3OES = false; mNativeExtensions.eglImageExternalEssl3OES = false;
......
//
// Copyright 2021 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.
//
// ImageMtl.h:
// Defines the class interface for ImageMtl, implementing ImageImpl.
//
#ifndef LIBANGLE_RENDERER_METAL_IMAGEMTL_H
#define LIBANGLE_RENDERER_METAL_IMAGEMTL_H
#include "libANGLE/renderer/ImageImpl.h"
#include "libANGLE/renderer/metal/mtl_resources.h"
namespace rx
{
class DisplayMtl;
class TextureImageSiblingMtl : public ExternalImageSiblingImpl
{
public:
TextureImageSiblingMtl(EGLClientBuffer buffer);
~TextureImageSiblingMtl() override;
static bool ValidateClientBuffer(const DisplayMtl *display, EGLClientBuffer buffer);
egl::Error initialize(const egl::Display *display) override;
void onDestroy(const egl::Display *display) override;
// ExternalImageSiblingImpl interface
gl::Format getFormat() const override;
bool isRenderable(const gl::Context *context) const override;
bool isTexturable(const gl::Context *context) const override;
gl::Extents getSize() const override;
size_t getSamples() const override;
bool isYUV() const override;
const mtl::TextureRef &getTexture() const { return mNativeTexture; }
const mtl::Format &getFormatMtl() const { return mFormat; }
private:
angle::Result initImpl(DisplayMtl *display);
EGLClientBuffer mBuffer;
gl::Format mGLFormat;
mtl::Format mFormat;
bool mRenderable = false;
bool mTextureable = false;
mtl::TextureRef mNativeTexture;
};
class ImageMtl : public ImageImpl
{
public:
ImageMtl(const egl::ImageState &state, const gl::Context *context);
~ImageMtl() override;
void onDestroy(const egl::Display *display) override;
egl::Error initialize(const egl::Display *display) override;
angle::Result orphan(const gl::Context *context, egl::ImageSibling *sibling) override;
const mtl::TextureRef &getTexture() const { return mNativeTexture; }
gl::TextureType getImageTextureType() const { return mImageTextureType; }
uint32_t getImageLevel() const { return mImageLevel; }
uint32_t getImageLayer() const { return mImageLayer; }
private:
gl::TextureType mImageTextureType;
uint32_t mImageLevel = 0;
uint32_t mImageLayer = 0;
mtl::TextureRef mNativeTexture;
};
} // namespace rx
#endif /* LIBANGLE_RENDERER_METAL_IMAGEMTL_H */
//
// Copyright 2021 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.
//
// ImageMtl.cpp:
// Implements the class methods for ImageMtl.
//
#include "libANGLE/renderer/metal/ImageMtl.h"
#include "common/debug.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/RenderBufferMtl.h"
#include "libANGLE/renderer/metal/TextureMtl.h"
namespace rx
{
// TextureImageSiblingMtl implementation
TextureImageSiblingMtl::TextureImageSiblingMtl(EGLClientBuffer buffer)
: mBuffer(buffer), mGLFormat(GL_NONE)
{}
TextureImageSiblingMtl::~TextureImageSiblingMtl() {}
// Static
bool TextureImageSiblingMtl::ValidateClientBuffer(const DisplayMtl *display, EGLClientBuffer buffer)
{
id<MTLTexture> texture = (__bridge id<MTLTexture>)(buffer);
if (!texture || texture.device != display->getMetalDevice())
{
return false;
}
if (texture.textureType != MTLTextureType2D && texture.textureType != MTLTextureTypeCube)
{
return false;
}
angle::FormatID angleFormatId = mtl::Format::MetalToAngleFormatID(texture.pixelFormat);
const mtl::Format &format = display->getPixelFormat(angleFormatId);
if (!format.valid())
{
ERR() << "Unrecognized format";
// Not supported
return false;
}
return true;
}
egl::Error TextureImageSiblingMtl::initialize(const egl::Display *display)
{
DisplayMtl *displayMtl = mtl::GetImpl(display);
if (initImpl(displayMtl) != angle::Result::Continue)
{
return egl::EglBadParameter();
}
return egl::NoError();
}
angle::Result TextureImageSiblingMtl::initImpl(DisplayMtl *displayMtl)
{
mNativeTexture = mtl::Texture::MakeFromMetal((__bridge id<MTLTexture>)(mBuffer));
angle::FormatID angleFormatId =
mtl::Format::MetalToAngleFormatID(mNativeTexture->pixelFormat());
mFormat = displayMtl->getPixelFormat(angleFormatId);
mGLFormat = gl::Format(mFormat.intendedAngleFormat().glInternalFormat);
mRenderable = mFormat.getCaps().depthRenderable || mFormat.getCaps().colorRenderable;
mTextureable = mFormat.getCaps().filterable || mFormat.hasDepthOrStencilBits();
return angle::Result::Continue;
}
void TextureImageSiblingMtl::onDestroy(const egl::Display *display)
{
mNativeTexture = nullptr;
}
gl::Format TextureImageSiblingMtl::getFormat() const
{
return mGLFormat;
}
bool TextureImageSiblingMtl::isRenderable(const gl::Context *context) const
{
return mRenderable;
}
bool TextureImageSiblingMtl::isTexturable(const gl::Context *context) const
{
return mTextureable;
}
gl::Extents TextureImageSiblingMtl::getSize() const
{
return mNativeTexture ? mNativeTexture->sizeAt0() : gl::Extents(0, 0, 0);
}
size_t TextureImageSiblingMtl::getSamples() const
{
uint32_t samples = mNativeTexture ? mNativeTexture->samples() : 0;
return samples > 1 ? samples : 0;
}
bool TextureImageSiblingMtl::isYUV() const
{
// NOTE(hqle): not supporting YUV image yet.
return false;
}
// ImageMtl implementation
ImageMtl::ImageMtl(const egl::ImageState &state, const gl::Context *context) : ImageImpl(state) {}
ImageMtl::~ImageMtl() {}
void ImageMtl::onDestroy(const egl::Display *display)
{
mNativeTexture = nullptr;
}
egl::Error ImageMtl::initialize(const egl::Display *display)
{
if (mState.target == EGL_METAL_TEXTURE_ANGLE)
{
const TextureImageSiblingMtl *externalImageSibling =
GetImplAs<TextureImageSiblingMtl>(GetAs<egl::ExternalImageSibling>(mState.source));
mNativeTexture = externalImageSibling->getTexture();
switch (mNativeTexture->textureType())
{
case MTLTextureType2D:
mImageTextureType = gl::TextureType::_2D;
break;
case MTLTextureTypeCube:
mImageTextureType = gl::TextureType::CubeMap;
break;
default:
UNREACHABLE();
}
mImageLevel = 0;
mImageLayer = 0;
}
else
{
UNREACHABLE();
return egl::EglBadAccess();
}
return egl::NoError();
}
angle::Result ImageMtl::orphan(const gl::Context *context, egl::ImageSibling *sibling)
{
if (sibling == mState.source)
{
mNativeTexture = nullptr;
}
return angle::Result::Continue;
}
} // namespace rx
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "libANGLE/renderer/metal/RenderBufferMtl.h" #include "libANGLE/renderer/metal/RenderBufferMtl.h"
#include "libANGLE/renderer/metal/ContextMtl.h" #include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/ImageMtl.h"
#include "libANGLE/renderer/metal/mtl_format_utils.h" #include "libANGLE/renderer/metal/mtl_format_utils.h"
#include "libANGLE/renderer/metal/mtl_utils.h" #include "libANGLE/renderer/metal/mtl_utils.h"
...@@ -122,9 +123,20 @@ angle::Result RenderbufferMtl::setStorageMultisample(const gl::Context *context, ...@@ -122,9 +123,20 @@ angle::Result RenderbufferMtl::setStorageMultisample(const gl::Context *context,
angle::Result RenderbufferMtl::setStorageEGLImageTarget(const gl::Context *context, angle::Result RenderbufferMtl::setStorageEGLImageTarget(const gl::Context *context,
egl::Image *image) egl::Image *image)
{ {
// NOTE(hqle): Support EGLimage releaseTexture();
UNIMPLEMENTED();
return angle::Result::Stop; ContextMtl *contextMtl = mtl::GetImpl(context);
ImageMtl *imageMtl = mtl::GetImpl(image);
mTexture = imageMtl->getTexture();
const angle::FormatID angleFormatId =
angle::Format::InternalFormatToID(image->getFormat().info->sizedInternalFormat);
mFormat = contextMtl->getPixelFormat(angleFormatId);
mRenderTarget.set(mTexture, mtl::kZeroNativeMipLevel, 0, mFormat);
return angle::Result::Continue;
} }
angle::Result RenderbufferMtl::getAttachmentRenderTarget(const gl::Context *context, angle::Result RenderbufferMtl::getAttachmentRenderTarget(const gl::Context *context,
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "libANGLE/renderer/metal/ContextMtl.h" #include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/DisplayMtl.h" #include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/FrameBufferMtl.h" #include "libANGLE/renderer/metal/FrameBufferMtl.h"
#include "libANGLE/renderer/metal/ImageMtl.h"
#include "libANGLE/renderer/metal/SamplerMtl.h" #include "libANGLE/renderer/metal/SamplerMtl.h"
#include "libANGLE/renderer/metal/SurfaceMtl.h" #include "libANGLE/renderer/metal/SurfaceMtl.h"
#include "libANGLE/renderer/metal/mtl_common.h" #include "libANGLE/renderer/metal/mtl_common.h"
...@@ -1081,9 +1082,32 @@ angle::Result TextureMtl::setEGLImageTarget(const gl::Context *context, ...@@ -1081,9 +1082,32 @@ angle::Result TextureMtl::setEGLImageTarget(const gl::Context *context,
gl::TextureType type, gl::TextureType type,
egl::Image *image) egl::Image *image)
{ {
UNIMPLEMENTED(); releaseTexture(true);
return angle::Result::Stop; ContextMtl *contextMtl = mtl::GetImpl(context);
ImageMtl *imageMtl = mtl::GetImpl(image);
if (type != imageMtl->getImageTextureType())
{
return angle::Result::Stop;
}
mNativeTexture = imageMtl->getTexture();
const angle::FormatID angleFormatId =
angle::Format::InternalFormatToID(image->getFormat().info->sizedInternalFormat);
mFormat = contextMtl->getPixelFormat(angleFormatId);
mSlices = mNativeTexture->cubeFacesOrArrayLength();
gl::Extents size = mNativeTexture->sizeAt0();
mIsPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
ANGLE_TRY(ensureSamplerStateCreated(context));
// Tell context to rebind textures
contextMtl->invalidateCurrentTextures();
return angle::Result::Continue;
} }
angle::Result TextureMtl::setImageExternal(const gl::Context *context, angle::Result TextureMtl::setImageExternal(const gl::Context *context,
......
...@@ -44,6 +44,15 @@ namespace rx ...@@ -44,6 +44,15 @@ namespace rx
namespace mtl namespace mtl
{{ {{
angle::FormatID Format::MetalToAngleFormatID(MTLPixelFormat formatMtl)
{{
// Actual conversion
switch (formatMtl)
{{
{mtl_pixel_format_switch}
}}
}}
void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_) void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
{{ {{
this->intendedFormatId = intendedFormatId_; this->intendedFormatId = intendedFormatId_;
...@@ -133,6 +142,10 @@ case_image_format_template2 = """ case angle::FormatID::{angle_format}: ...@@ -133,6 +142,10 @@ case_image_format_template2 = """ case angle::FormatID::{angle_format}:
""" """
case_image_mtl_to_angle_template = """ case {mtl_format}:
return angle::FormatID::{angle_format};
"""
case_vertex_format_template1 = """ case angle::FormatID::{angle_format}: case_vertex_format_template1 = """ case angle::FormatID::{angle_format}:
this->metalFormat = {mtl_format}; this->metalFormat = {mtl_format};
this->actualFormatId = angle::FormatID::{actual_angle_format}; this->actualFormatId = angle::FormatID::{actual_angle_format};
...@@ -278,6 +291,8 @@ def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_ ...@@ -278,6 +291,8 @@ def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_
# This format requires fallback when depth24Stencil8PixelFormatSupported flag is false. # This format requires fallback when depth24Stencil8PixelFormatSupported flag is false.
# Fallback format: # Fallback format:
actual_angle_format_fallback = mac_fallbacks[actual_angle_format] actual_angle_format_fallback = mac_fallbacks[actual_angle_format]
fallback_condition = "metalDevice.depth24Stencil8PixelFormatSupported && \
!display->getFeatures().forceD24S8AsUnsupported.enabled"
# return if else block: # return if else block:
return image_format_assign_template2.format( return image_format_assign_template2.format(
actual_angle_format=actual_angle_format, actual_angle_format=actual_angle_format,
...@@ -288,8 +303,7 @@ def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_ ...@@ -288,8 +303,7 @@ def gen_image_map_switch_mac_case(angle_format, actual_angle_format_info, angle_
mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback], mtl_format_fallback=angle_to_mtl_map[actual_angle_format_fallback],
init_function_fallback=angle_format_utils.get_internal_format_initializer( init_function_fallback=angle_format_utils.get_internal_format_initializer(
gl_format, actual_angle_format_fallback), gl_format, actual_angle_format_fallback),
fallback_condition=("metalDevice.depth24Stencil8PixelFormatSupported && " + fallback_condition=fallback_condition)
"!display->getFeatures().forceD24S8AsUnsupported.enabled"))
else: else:
# return ordinary block: # return ordinary block:
return image_format_assign_template1.format( return image_format_assign_template1.format(
...@@ -400,6 +414,40 @@ def gen_image_map_switch_string(image_table, angle_to_gl): ...@@ -400,6 +414,40 @@ def gen_image_map_switch_string(image_table, angle_to_gl):
return switch_data return switch_data
def gen_image_mtl_to_angle_switch_string(image_table):
angle_to_mtl = image_table["map"]
mac_specific_map = image_table["map_mac"]
ios_specific_map = image_table["map_ios"]
switch_data = ''
# Common case
for angle_format in sorted(angle_to_mtl.keys()):
switch_data += case_image_mtl_to_angle_template.format(
mtl_format=angle_to_mtl[angle_format], angle_format=angle_format)
# Mac specific
switch_data += "#if TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
for angle_format in sorted(mac_specific_map.keys()):
switch_data += case_image_mtl_to_angle_template.format(
mtl_format=mac_specific_map[angle_format], angle_format=angle_format)
switch_data += "#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST\n"
# iOS + macOS 11.0+ specific
switch_data += "#if TARGET_OS_IOS || TARGET_OS_TV || (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 101600))\n"
for angle_format in sorted(ios_specific_map.keys()):
# ETC1_R8G8B8_UNORM_BLOCK is a duplicated of ETC2_R8G8B8_UNORM_BLOCK
if angle_format == 'ETC1_R8G8B8_UNORM_BLOCK':
continue
switch_data += case_image_mtl_to_angle_template.format(
mtl_format=ios_specific_map[angle_format], angle_format=angle_format)
switch_data += "#endif // TARGET_OS_IOS || TARGET_OS_TV || mac 11.0+\n"
switch_data += " default:\n"
switch_data += " return angle::FormatID::NONE;\n"
return switch_data
def gen_vertex_map_switch_case(angle_fmt, actual_angle_fmt, angle_to_mtl_map, override_packed_map): def gen_vertex_map_switch_case(angle_fmt, actual_angle_fmt, angle_to_mtl_map, override_packed_map):
mtl_format = angle_to_mtl_map[actual_angle_fmt] mtl_format = angle_to_mtl_map[actual_angle_fmt]
copy_function, default_alpha, same_gl_type = get_vertex_copy_function_and_default_alpha( copy_function, default_alpha, same_gl_type = get_vertex_copy_function_and_default_alpha(
...@@ -525,6 +573,7 @@ def main(): ...@@ -525,6 +573,7 @@ def main():
map_vertex = map_json["vertex"] map_vertex = map_json["vertex"]
image_switch_data = gen_image_map_switch_string(map_image, angle_to_gl) image_switch_data = gen_image_map_switch_string(map_image, angle_to_gl)
image_mtl_to_angle_switch_data = gen_image_mtl_to_angle_switch_string(map_image)
vertex_switch_data = gen_vertex_map_switch_string(map_vertex) vertex_switch_data = gen_vertex_map_switch_string(map_vertex)
...@@ -534,6 +583,7 @@ def main(): ...@@ -534,6 +583,7 @@ def main():
script_name=sys.argv[0], script_name=sys.argv[0],
data_source_name=data_source_name, data_source_name=data_source_name,
angle_image_format_switch=image_switch_data, angle_image_format_switch=image_switch_data,
mtl_pixel_format_switch=image_mtl_to_angle_switch_data,
angle_vertex_format_switch=vertex_switch_data, angle_vertex_format_switch=vertex_switch_data,
metal_format_caps=caps_init_str) metal_format_caps=caps_init_str)
with open('mtl_format_table_autogen.mm', 'wt') as out_file: with open('mtl_format_table_autogen.mm', 'wt') as out_file:
......
...@@ -97,6 +97,7 @@ class DisplayMtl; ...@@ -97,6 +97,7 @@ class DisplayMtl;
class ContextMtl; class ContextMtl;
class FramebufferMtl; class FramebufferMtl;
class BufferMtl; class BufferMtl;
class ImageMtl;
class VertexArrayMtl; class VertexArrayMtl;
class TextureMtl; class TextureMtl;
class ProgramMtl; class ProgramMtl;
...@@ -220,6 +221,12 @@ struct ImplTypeHelper<egl::Display> ...@@ -220,6 +221,12 @@ struct ImplTypeHelper<egl::Display>
using ImplType = DisplayMtl; using ImplType = DisplayMtl;
}; };
template <>
struct ImplTypeHelper<egl::Image>
{
using ImplType = ImageMtl;
};
template <typename T> template <typename T>
using GetImplType = typename ImplTypeHelper<T>::ImplType; using GetImplType = typename ImplTypeHelper<T>::ImplType;
......
...@@ -62,6 +62,8 @@ struct Format : public FormatBase ...@@ -62,6 +62,8 @@ struct Format : public FormatBase
{ {
Format() = default; Format() = default;
static angle::FormatID MetalToAngleFormatID(MTLPixelFormat formatMtl);
const gl::InternalFormat &intendedInternalFormat() const; const gl::InternalFormat &intendedInternalFormat() const;
const gl::InternalFormat &actualInternalFormat() const; const gl::InternalFormat &actualInternalFormat() const;
......
...@@ -3399,6 +3399,26 @@ bool ValidateCreateImage(const ValidationContext *val, ...@@ -3399,6 +3399,26 @@ bool ValidateCreateImage(const ValidationContext *val,
} }
break; break;
case EGL_METAL_TEXTURE_ANGLE:
if (!displayExtensions.mtlTextureClientBuffer)
{
val->setError(EGL_BAD_PARAMETER,
"EGL_ANGLE_metal_texture_client_buffer not supported.");
return false;
}
if (context != nullptr)
{
val->setError(EGL_BAD_CONTEXT, "ctx must be EGL_NO_CONTEXT.");
return false;
}
ANGLE_EGL_TRY_RETURN(
val->eglThread,
display->validateImageClientBuffer(context, target, buffer, attributes),
val->entryPoint, val->labeledObject, false);
break;
default: default:
val->setError(EGL_BAD_PARAMETER, "invalid target: 0x%X", target); val->setError(EGL_BAD_PARAMETER, "invalid target: 0x%X", target);
return false; return false;
......
...@@ -202,6 +202,14 @@ if (is_win || is_linux || is_chromeos || is_android || is_fuchsia || is_apple) { ...@@ -202,6 +202,14 @@ if (is_win || is_linux || is_chromeos || is_android || is_fuchsia || is_apple) {
"CoreFoundation.framework", "CoreFoundation.framework",
"IOSurface.framework", "IOSurface.framework",
] ]
ldflags = [
"-weak_framework",
"Metal",
]
cflags_objcc = [
"-Wno-nullability-completeness",
"-Wno-unguarded-availability",
]
} }
if (is_win) { if (is_win) {
sources += angle_end2end_tests_win_sources sources += angle_end2end_tests_win_sources
......
...@@ -187,6 +187,7 @@ angle_end2end_tests_mac_sources = [ ...@@ -187,6 +187,7 @@ angle_end2end_tests_mac_sources = [
"egl_tests/EGLDeviceCGLTest.cpp", "egl_tests/EGLDeviceCGLTest.cpp",
"egl_tests/EGLIOSurfaceClientBufferTest.cpp", "egl_tests/EGLIOSurfaceClientBufferTest.cpp",
"egl_tests/EGLSurfaceTestMac.mm", "egl_tests/EGLSurfaceTestMac.mm",
"gl_tests/ImageTestMetal.mm",
] ]
angle_end2end_tests_win_sources = [ angle_end2end_tests_win_sources = [
"egl_tests/EGLDeviceTest.cpp", "egl_tests/EGLDeviceTest.cpp",
......
...@@ -1003,6 +1003,22 @@ TEST_P(ImageTest, ANGLEExtensionAvailability) ...@@ -1003,6 +1003,22 @@ TEST_P(ImageTest, ANGLEExtensionAvailability)
EXPECT_FALSE(hasExternalESSL3Ext()); EXPECT_FALSE(hasExternalESSL3Ext());
} }
} }
else if (IsMetal())
{
// http://anglebug.com/5814
// http://anglebug.com/5841 (wrong detection of IsMetal() on macOS 11)
ANGLE_SKIP_TEST_IF(IsARM64());
// NOTE(hqle): Metal currently doesn't implement any image extensions besides
// EGL_ANGLE_metal_texture_client_buffer
EXPECT_TRUE(hasOESExt());
EXPECT_TRUE(hasBaseExt());
EXPECT_FALSE(hasExternalExt());
EXPECT_FALSE(hasExternalESSL3Ext());
EXPECT_FALSE(has2DTextureExt());
EXPECT_FALSE(has3DTextureExt());
EXPECT_FALSE(hasRenderbufferExt());
}
else else
{ {
EXPECT_FALSE(hasOESExt()); EXPECT_FALSE(hasOESExt());
......
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