Metal: Implement EGL_ANGLE_iosurface_client_buffer.

GL_R16UI format is not supported yet. It will be implemented once
integer textures are implemented in metal back-end.

Bug: angleproject:4847
Bug: angleproject:2634
Change-Id: I60a52c0ce327a524c74e80b18bb15978ac52065b
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2329091
Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Le Hoang Quyen
2020-07-31 02:08:09 +08:00
committed by Commit Bot
parent a5a08b5e4e
commit 69ca10255c
13 changed files with 498 additions and 258 deletions

View File

@@ -2,9 +2,9 @@
"src/libANGLE/renderer/angle_format.py":
"32ba71942c0fd00e6807104f1bb80a3c",
"src/libANGLE/renderer/metal/gen_mtl_format_table.py":
"b6468446dd1da3e44ac9dd11690b5bf1",
"780f56abea19db610d2b829ba817fdc6",
"src/libANGLE/renderer/metal/mtl_format_map.json":
"223e0b729f5df7d91af382fa3af32254",
"7aad5b3ed806e0d932cbbfe6d3b8a834",
"src/libANGLE/renderer/metal/mtl_format_table_autogen.mm":
"d924184394625032e8a3e97c8b936a5f"
"efd031ead828c19f5476413b2b743087"
}

View File

@@ -93,6 +93,11 @@ class DisplayMtl : public DisplayImpl
bool isValidNativeWindow(EGLNativeWindowType window) const override;
egl::Error validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const override;
egl::ConfigSet generateConfigs() override;
std::string getRendererDescription() const;

View File

@@ -166,8 +166,7 @@ SurfaceImpl *DisplayMtl::createWindowSurface(const egl::SurfaceState &state,
SurfaceImpl *DisplayMtl::createPbufferSurface(const egl::SurfaceState &state,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return static_cast<SurfaceImpl *>(0);
return new PBufferSurfaceMtl(this, state, attribs);
}
SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &state,
@@ -175,8 +174,15 @@ SurfaceImpl *DisplayMtl::createPbufferFromClientBuffer(const egl::SurfaceState &
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs)
{
UNIMPLEMENTED();
return static_cast<SurfaceImpl *>(0);
switch (buftype)
{
case EGL_IOSURFACE_ANGLE:
return new IOSurfaceSurfaceMtl(this, state, clientBuffer, attribs);
break;
default:
UNREACHABLE();
}
return nullptr;
}
SurfaceImpl *DisplayMtl::createPixmapSurface(const egl::SurfaceState &state,
@@ -249,6 +255,7 @@ egl::Error DisplayMtl::makeCurrent(egl::Surface *drawSurface,
void DisplayMtl::generateExtensions(egl::DisplayExtensions *outExtensions) const
{
outExtensions->flexibleSurfaceCompatibility = true;
outExtensions->iosurfaceClientBuffer = true;
}
void DisplayMtl::generateCaps(egl::Caps *outCaps) const {}
@@ -278,9 +285,10 @@ egl::ConfigSet DisplayMtl::generateConfigs()
config.transparentType = EGL_NONE;
// Pbuffer
config.maxPBufferWidth = 4096;
config.maxPBufferHeight = 4096;
config.maxPBufferPixels = 4096 * 4096;
config.bindToTextureTarget = EGL_TEXTURE_2D;
config.maxPBufferWidth = 4096;
config.maxPBufferHeight = 4096;
config.maxPBufferPixels = 4096 * 4096;
// Caveat
config.configCaveat = EGL_NONE;
@@ -290,9 +298,9 @@ egl::ConfigSet DisplayMtl::generateConfigs()
config.samples = 0;
config.level = 0;
config.bindToTextureRGB = EGL_FALSE;
config.bindToTextureRGBA = EGL_FALSE;
config.bindToTextureRGBA = EGL_TRUE;
config.surfaceType = EGL_WINDOW_BIT;
config.surfaceType = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
config.minSwapInterval = 0;
@@ -360,6 +368,26 @@ bool DisplayMtl::isValidNativeWindow(EGLNativeWindowType window) const
}
}
egl::Error DisplayMtl::validateClientBuffer(const egl::Config *configuration,
EGLenum buftype,
EGLClientBuffer clientBuffer,
const egl::AttributeMap &attribs) const
{
switch (buftype)
{
case EGL_IOSURFACE_ANGLE:
if (!IOSurfaceSurfaceMtl::ValidateAttributes(clientBuffer, attribs))
{
return egl::EglBadAttribute();
}
break;
default:
UNREACHABLE();
return egl::EglBadAttribute();
}
return egl::NoError();
}
std::string DisplayMtl::getRendererDescription() const
{
ANGLE_MTL_OBJC_SCOPE

View File

@@ -158,6 +158,79 @@ class WindowSurfaceMtl : public SurfaceMtl
CGSize mCurrentKnownDrawableSize;
};
// Offscreen surface, base class of PBuffer, IOSurface.
class OffscreenSurfaceMtl : public SurfaceMtl
{
public:
OffscreenSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
const egl::AttributeMap &attribs);
~OffscreenSurfaceMtl() override;
void destroy(const egl::Display *display) override;
egl::Error swap(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;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
protected:
angle::Result ensureTexturesSizeCorrect(const gl::Context *context);
gl::Extents mSize;
};
// PBuffer surface
class PBufferSurfaceMtl : public OffscreenSurfaceMtl
{
public:
PBufferSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
const egl::AttributeMap &attribs);
void setFixedWidth(EGLint width) override;
void setFixedHeight(EGLint height) override;
};
// Offscreen created from IOSurface
class IOSurfaceSurfaceMtl : public OffscreenSurfaceMtl
{
public:
IOSurfaceSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs);
~IOSurfaceSurfaceMtl() override;
egl::Error bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer) override;
egl::Error releaseTexImage(const gl::Context *context, EGLint buffer) override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
static bool ValidateAttributes(EGLClientBuffer buffer, const egl::AttributeMap &attribs);
private:
angle::Result ensureColorTextureCreated(const gl::Context *context);
IOSurfaceRef mIOSurface;
NSUInteger mIOSurfacePlane;
int mIOSurfaceFormatIdx;
};
} // namespace rx
#endif /* LIBANGLE_RENDERER_METAL_SURFACEMTL_H_ */

View File

@@ -46,6 +46,40 @@ constexpr angle::FormatID kDefaultFrameBufferStencilFormatId = angle::FormatID::
constexpr angle::FormatID kDefaultFrameBufferDepthStencilFormatId =
angle::FormatID::D24_UNORM_S8_UINT;
struct IOSurfaceFormatInfo
{
GLenum internalFormat;
GLenum type;
size_t componentBytes;
angle::FormatID nativeAngleFormatId;
};
// clang-format off
// NOTE(hqle): Support R16_UINT once GLES3 is complete.
constexpr std::array<IOSurfaceFormatInfo, 6> kIOSurfaceFormats = {{
{GL_RED, GL_UNSIGNED_BYTE, 1, angle::FormatID::R8_UNORM},
{GL_RG, GL_UNSIGNED_BYTE, 2, angle::FormatID::R8G8_UNORM},
{GL_RGB, GL_UNSIGNED_BYTE, 4, angle::FormatID::B8G8R8A8_UNORM},
{GL_BGRA_EXT, GL_UNSIGNED_BYTE, 4, angle::FormatID::B8G8R8A8_UNORM},
{GL_RGBA, GL_HALF_FLOAT, 8, angle::FormatID::R16G16B16A16_FLOAT},
{GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV, 4, angle::FormatID::B10G10R10A2_UNORM},
}};
// 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;
}
angle::Result CreateTexture(const gl::Context *context,
const mtl::Format &format,
uint32_t width,
@@ -209,14 +243,7 @@ SurfaceMtl::SurfaceMtl(DisplayMtl *display,
const egl::AttributeMap &attribs)
: SurfaceImpl(state)
{
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf says that BGRA8Unorm is
// only supported if depth24Stencil8PixelFormatSupported capabilitiy is YES. Yet
// CAMetalLayer can be created with pixelFormat MTLPixelFormatBGRA8Unorm. So the mtl::Format
// used for SurfaceMtl is initialized a bit differently from normal TextureMtl's mtl::Format.
// It won't use format table, instead we initialize its values here to use BGRA8Unorm directly:
mColorFormat.intendedFormatId = mColorFormat.actualFormatId = angle::FormatID::B8G8R8A8_UNORM;
mColorFormat.metalFormat = MTLPixelFormatBGRA8Unorm;
mColorFormat = display->getPixelFormat(angle::FormatID::B8G8R8A8_UNORM);
mSamples = state.config->samples;
@@ -747,4 +774,248 @@ angle::Result WindowSurfaceMtl::swapImpl(const gl::Context *context)
return angle::Result::Continue;
}
// OffscreenSurfaceMtl implementation
OffscreenSurfaceMtl::OffscreenSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
const egl::AttributeMap &attribs)
: SurfaceMtl(display, state, attribs)
{
mSize = gl::Extents(attribs.getAsInt(EGL_WIDTH, 1), attribs.getAsInt(EGL_HEIGHT, 1), 1);
}
OffscreenSurfaceMtl::~OffscreenSurfaceMtl() {}
void OffscreenSurfaceMtl::destroy(const egl::Display *display)
{
SurfaceMtl::destroy(display);
}
egl::Error OffscreenSurfaceMtl::swap(const gl::Context *context)
{
// Check for surface resize.
ANGLE_TO_EGL_TRY(ensureTexturesSizeCorrect(context));
return egl::NoError();
}
egl::Error OffscreenSurfaceMtl::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
contextMtl->flushCommandBufer();
// Initialize offscreen textures if needed:
ANGLE_TO_EGL_TRY(ensureTexturesSizeCorrect(context));
return egl::NoError();
}
egl::Error OffscreenSurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
if (mMSColorTexture)
{
ANGLE_TO_EGL_TRY(resolveColorTextureIfNeeded(context));
}
// NOTE(hqle): Should we finishCommandBuffer or flush is enough?
contextMtl->flushCommandBufer();
return egl::NoError();
}
angle::Result OffscreenSurfaceMtl::getAttachmentRenderTarget(
const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut)
{
// Initialize offscreen textures if needed:
ANGLE_TRY(ensureTexturesSizeCorrect(context));
return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
}
angle::Result OffscreenSurfaceMtl::ensureTexturesSizeCorrect(const gl::Context *context)
{
if (!mColorTexture || mColorTexture->size() != mSize)
{
ANGLE_TRY(CreateTexture(context, mColorFormat, mSize.width, mSize.height, 1,
/** renderTargetOnly */ false, &mColorTexture));
mColorRenderTarget.set(mColorTexture, 0, 0, mColorFormat);
}
return ensureCompanionTexturesSizeCorrect(context, mSize);
}
// PBufferSurfaceMtl implementation
PBufferSurfaceMtl::PBufferSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
const egl::AttributeMap &attribs)
: OffscreenSurfaceMtl(display, state, attribs)
{}
void PBufferSurfaceMtl::setFixedWidth(EGLint width)
{
mSize.width = width;
}
void PBufferSurfaceMtl::setFixedHeight(EGLint height)
{
mSize.height = height;
}
// IOSurfaceSurfaceMtl implementation.
IOSurfaceSurfaceMtl::IOSurfaceSurfaceMtl(DisplayMtl *display,
const egl::SurfaceState &state,
EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
: OffscreenSurfaceMtl(display, state, attribs), mIOSurface((__bridge IOSurfaceRef)(buffer))
{
CFRetain(mIOSurface);
mIOSurfacePlane = 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);
mIOSurfaceFormatIdx =
FindIOSurfaceFormatIndex(static_cast<GLenum>(internalFormat), static_cast<GLenum>(type));
ASSERT(mIOSurfaceFormatIdx >= 0);
mColorFormat =
display->getPixelFormat(kIOSurfaceFormats[mIOSurfaceFormatIdx].nativeAngleFormatId);
}
IOSurfaceSurfaceMtl::~IOSurfaceSurfaceMtl()
{
if (mIOSurface != nullptr)
{
CFRelease(mIOSurface);
mIOSurface = nullptr;
}
}
egl::Error IOSurfaceSurfaceMtl::bindTexImage(const gl::Context *context,
gl::Texture *texture,
EGLint buffer)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
StartFrameCapture(contextMtl);
// Initialize offscreen texture if needed:
ANGLE_TO_EGL_TRY(ensureColorTextureCreated(context));
return OffscreenSurfaceMtl::bindTexImage(context, texture, buffer);
}
egl::Error IOSurfaceSurfaceMtl::releaseTexImage(const gl::Context *context, EGLint buffer)
{
egl::Error re = OffscreenSurfaceMtl::releaseTexImage(context, buffer);
StopFrameCapture();
return re;
}
angle::Result IOSurfaceSurfaceMtl::getAttachmentRenderTarget(
const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut)
{
// Initialize offscreen texture if needed:
ANGLE_TRY(ensureColorTextureCreated(context));
return OffscreenSurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples,
rtOut);
}
angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context *context)
{
if (mColorTexture)
{
return angle::Result::Continue;
}
ContextMtl *contextMtl = mtl::GetImpl(context);
ANGLE_MTL_OBJC_SCOPE
{
auto texDesc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:mColorFormat.metalFormat
width:mSize.width
height:mSize.height
mipmapped:NO];
texDesc.usage = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
id<MTLTexture> texture =
[contextMtl->getMetalDevice() newTextureWithDescriptor:texDesc
iosurface:mIOSurface
plane:mIOSurfacePlane];
mColorTexture = mtl::Texture::MakeFromMetal([texture ANGLE_MTL_AUTORELEASE]);
}
mColorRenderTarget.set(mColorTexture, 0, 0, mColorFormat);
if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB)
{
// This format has emulated alpha channel. Initialize texture's alpha channel to 1.0.
ANGLE_TRY(mtl::InitializeTextureContentsGPU(
context, mColorTexture, gl::ImageIndex::Make2D(0), MTLColorWriteMaskAlpha));
// Disable subsequent rendering to alpha channel.
mColorTexture->setColorWritableMask(MTLColorWriteMaskAll & (~MTLColorWriteMaskAlpha));
}
return angle::Result::Continue;
}
// static
bool IOSurfaceSurfaceMtl::ValidateAttributes(EGLClientBuffer buffer,
const egl::AttributeMap &attribs)
{
IOSurfaceRef ioSurface = (__bridge 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;
}
return true;
}
}

View File

@@ -14,9 +14,11 @@
#include "common/MemoryBuffer.h"
#include "common/debug.h"
#include "common/mathutil.h"
#include "libANGLE/Surface.h"
#include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/FrameBufferMtl.h"
#include "libANGLE/renderer/metal/SurfaceMtl.h"
#include "libANGLE/renderer/metal/mtl_common.h"
#include "libANGLE/renderer/metal/mtl_format_utils.h"
#include "libANGLE/renderer/metal/mtl_utils.h"
@@ -732,16 +734,32 @@ angle::Result TextureMtl::setBaseLevel(const gl::Context *context, GLuint baseLe
angle::Result TextureMtl::bindTexImage(const gl::Context *context, egl::Surface *surface)
{
UNIMPLEMENTED();
releaseTexture(true);
return angle::Result::Stop;
auto pBuffer = GetImplAs<OffscreenSurfaceMtl>(surface);
mNativeTexture = pBuffer->getColorTexture();
mFormat = pBuffer->getColorFormat();
gl::Extents size = mNativeTexture->size();
mIsPow2 = gl::isPow2(size.width) && gl::isPow2(size.height) && gl::isPow2(size.depth);
ANGLE_TRY(ensureSamplerStateCreated(context));
ASSERT(mState.getType() == gl::TextureType::_2D);
mLayeredRenderTargets.resize(1);
mLayeredRenderTargets[0].set(mNativeTexture, 0, 0, mFormat);
mLayeredTextureViews.resize(1);
mLayeredTextureViews[0] = mNativeTexture;
// Tell context to rebind textures
ContextMtl *contextMtl = mtl::GetImpl(context);
contextMtl->invalidateCurrentTextures();
return angle::Result::Continue;
}
angle::Result TextureMtl::releaseTexImage(const gl::Context *context)
{
UNIMPLEMENTED();
return angle::Result::Stop;
releaseTexture(true);
return angle::Result::Continue;
}
angle::Result TextureMtl::getAttachmentRenderTarget(const gl::Context *context,

View File

@@ -160,7 +160,7 @@ def gen_image_map_switch_string(image_table):
angle_override = image_table["override"]
mac_override = image_table["override_mac"]
ios_override = image_table["override_ios"]
mac_fallbacks = image_table["fallbacks_mac"]
mac_fallbacks = image_table["d24s8_fallbacks_mac"]
angle_to_mtl = image_table["map"]
mac_specific_map = image_table["map_mac"]
ios_specific_map = image_table["map_ios"]

View File

@@ -18,7 +18,8 @@
"B8G8R8A8_UNORM_SRGB": "MTLPixelFormatBGRA8Unorm_sRGB",
"D32_FLOAT": "MTLPixelFormatDepth32Float",
"S8_UINT": "MTLPixelFormatStencil8",
"D32_FLOAT_S8X24_UINT": "MTLPixelFormatDepth32Float_Stencil8"
"D32_FLOAT_S8X24_UINT": "MTLPixelFormatDepth32Float_Stencil8",
"B10G10R10A2_UNORM": "MTLPixelFormatBGR10A2Unorm"
},
"map_ios": {
"R5G6B5_UNORM": "MTLPixelFormatB5G6R5Unorm",
@@ -85,14 +86,8 @@
"R5G5B5A1_UNORM": "R8G8B8A8_UNORM",
"R4G4B4A4_UNORM": "R8G8B8A8_UNORM"
},
"fallbacks_mac": {
"B8G8R8A8_UNORM": "R8G8B8A8_UNORM",
"D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT",
"R8_UNORM": "NONE",
"R16_FLOAT": "NONE",
"R32_FLOAT": "NONE",
"R16G16B16A16_FLOAT": "NONE",
"R32G32B32A32_FLOAT": "NONE"
"d24s8_fallbacks_mac": {
"D24_UNORM_S8_UINT": "D32_FLOAT_S8X24_UINT"
}
},
"vertex": {

View File

@@ -34,27 +34,16 @@ void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
this->actualFormatId = angle::FormatID::A8_UNORM;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::B8G8R8A8_UNORM:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatBGRA8Unorm;
this->actualFormatId = angle::FormatID::B8G8R8A8_UNORM;
}
else
{
this->metalFormat = MTLPixelFormatRGBA8Unorm;
this->actualFormatId = angle::FormatID::R8G8B8A8_UNORM;
}
case angle::FormatID::B10G10R10A2_UNORM:
this->metalFormat = MTLPixelFormatBGR10A2Unorm;
this->actualFormatId = angle::FormatID::B10G10R10A2_UNORM;
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::B8G8R8A8_UNORM:
this->metalFormat = MTLPixelFormatBGRA8Unorm;
this->actualFormatId = angle::FormatID::B8G8R8A8_UNORM;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::B8G8R8A8_UNORM_SRGB:
this->metalFormat = MTLPixelFormatBGRA8Unorm_sRGB;
this->actualFormatId = angle::FormatID::B8G8R8A8_UNORM_SRGB;
@@ -75,105 +64,41 @@ void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
this->actualFormatId = angle::FormatID::NONE;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16G16B16A16_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16G16B16A16_FLOAT:
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16G16_FLOAT:
this->metalFormat = MTLPixelFormatRG16Float;
this->actualFormatId = angle::FormatID::R16G16_FLOAT;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatR16Float;
this->actualFormatId = angle::FormatID::R16_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16_FLOAT:
this->metalFormat = MTLPixelFormatR16Float;
this->actualFormatId = angle::FormatID::R16_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16_UNORM:
this->metalFormat = MTLPixelFormatR16Unorm;
this->actualFormatId = angle::FormatID::R16_UNORM;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R32G32B32A32_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R32G32B32A32_FLOAT:
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R32G32_FLOAT:
this->metalFormat = MTLPixelFormatRG32Float;
this->actualFormatId = angle::FormatID::R32G32_FLOAT;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R32_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatR32Float;
this->actualFormatId = angle::FormatID::R32_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R32_FLOAT:
this->metalFormat = MTLPixelFormatR32Float;
this->actualFormatId = angle::FormatID::R32_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R8G8B8A8_UNORM:
this->metalFormat = MTLPixelFormatRGBA8Unorm;
this->actualFormatId = angle::FormatID::R8G8B8A8_UNORM;
@@ -189,74 +114,26 @@ void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
this->actualFormatId = angle::FormatID::R8G8_UNORM;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R8_UNORM:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatR8Unorm;
this->actualFormatId = angle::FormatID::R8_UNORM;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R8_UNORM:
this->metalFormat = MTLPixelFormatR8Unorm;
this->actualFormatId = angle::FormatID::R8_UNORM;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::S8_UINT:
this->metalFormat = MTLPixelFormatStencil8;
this->actualFormatId = angle::FormatID::S8_UINT;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::A16_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::A16_FLOAT:
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::A32_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::A32_FLOAT:
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::D24_UNORM_X8_UINT:
this->metalFormat = MTLPixelFormatDepth32Float;
this->actualFormatId = angle::FormatID::D32_FLOAT;
@@ -267,90 +144,26 @@ void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
this->actualFormatId = angle::FormatID::D32_FLOAT;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L16A16_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L16A16_FLOAT:
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L16_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L16_FLOAT:
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L32A32_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L32A32_FLOAT:
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L32_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L32_FLOAT:
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::L8A8_UNORM:
this->metalFormat = MTLPixelFormatRGBA8Unorm;
this->actualFormatId = angle::FormatID::R8G8B8A8_UNORM;
@@ -361,48 +174,16 @@ void Format::init(const DisplayMtl *display, angle::FormatID intendedFormatId_)
this->actualFormatId = angle::FormatID::R8G8B8A8_UNORM;
break;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16G16B16_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R16G16B16_FLOAT:
this->metalFormat = MTLPixelFormatRGBA16Float;
this->actualFormatId = angle::FormatID::R16G16B16A16_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R32G32B32_FLOAT:
if (metalDevice.depth24Stencil8PixelFormatSupported)
{
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
}
else
{
this->metalFormat = MTLPixelFormatInvalid;
this->actualFormatId = angle::FormatID::NONE;
}
break;
#else // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R32G32B32_FLOAT:
this->metalFormat = MTLPixelFormatRGBA32Float;
this->actualFormatId = angle::FormatID::R32G32B32A32_FLOAT;
break;
#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST
case angle::FormatID::R8G8B8_UNORM:
this->metalFormat = MTLPixelFormatRGBA8Unorm;
this->actualFormatId = angle::FormatID::R8G8B8A8_UNORM;

View File

@@ -34,6 +34,7 @@ bool OverrideTextureCaps(const DisplayMtl *display, angle::FormatID formatId, gl
case angle::FormatID::R8G8B8A8_UNORM_SRGB:
case angle::FormatID::B8G8R8A8_UNORM:
case angle::FormatID::B8G8R8A8_UNORM_SRGB:
case angle::FormatID::B10G10R10A2_UNORM:
// NOTE: even though iOS devices don't support filtering depth textures, we still report as
// supported here in order for the OES_depth_texture extension to be enabled.
// During draw call, the filter modes will be converted to nearest.
@@ -214,6 +215,7 @@ bool Format::FormatRenderable(MTLPixelFormat format)
case MTLPixelFormatDepth32Float:
case MTLPixelFormatStencil8:
case MTLPixelFormatDepth32Float_Stencil8:
case MTLPixelFormatBGR10A2Unorm:
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case MTLPixelFormatDepth16Unorm:
case MTLPixelFormatDepth24Unorm_Stencil8:

View File

@@ -28,10 +28,17 @@ namespace mtl
NS_ASSUME_NONNULL_BEGIN
// Initialize texture content to (0, 0, 0, 1)
angle::Result InitializeTextureContents(const gl::Context *context,
const TextureRef &texture,
const Format &textureObjFormat,
const gl::ImageIndex &index);
// Same as above but using GPU clear operation instead of CPU.
// - channelsToInit parameter controls which channels will get their content initialized.
angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const TextureRef &texture,
const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit);
MTLViewport GetViewport(const gl::Rectangle &rect, double znear = 0, double zfar = 1);
MTLViewport GetViewportFlipY(const gl::Rectangle &rect,

View File

@@ -14,6 +14,8 @@
#include "common/MemoryBuffer.h"
#include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/mtl_render_utils.h"
namespace rx
{
@@ -77,6 +79,47 @@ angle::Result InitializeTextureContents(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const TextureRef &texture,
const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
// Use clear render command
// temporarily enable color channels requested via channelsToInit. Some emulated format has some
// channels write mask disabled when the texture is created.
MTLColorWriteMask oldMask = texture->getColorWritableMask();
texture->setColorWritableMask(channelsToInit);
RenderCommandEncoder *encoder;
if (channelsToInit == MTLColorWriteMaskAll)
{
// If all channels will be initialized, use clear loadOp.
Optional<MTLClearColor> blackColor = MTLClearColorMake(0, 0, 0, 1);
encoder = contextMtl->getRenderCommandEncoder(texture, index, blackColor);
}
else
{
// If there are some channels don't need to be initialized, we must use clearWithDraw.
encoder = contextMtl->getRenderCommandEncoder(texture, index);
ClearRectParams clearParams;
clearParams.clearColor = {.alpha = 1};
clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height());
ANGLE_TRY(
contextMtl->getDisplay()->getUtils().clearWithDraw(context, encoder, clearParams));
}
ANGLE_UNUSED_VARIABLE(encoder);
contextMtl->endEncoding(true);
// Restore texture's intended write mask
texture->setColorWritableMask(oldMask);
return angle::Result::Continue;
}
MTLViewport GetViewport(const gl::Rectangle &rect, double znear, double zfar)
{
MTLViewport re;

View File

@@ -211,6 +211,10 @@ class IOSurfaceClientBufferTest : public ANGLETest
EXPECT_EGL_TRUE(result);
EXPECT_EGL_SUCCESS();
// IOSurface client buffer's rendering doesn't automatically finish after
// eglReleaseTexImage(). Need to explicitly call glFinish().
glFinish();
IOSurfaceLock(ioSurface.get(), kIOSurfaceLockReadOnly, nullptr);
std::array<T, dataSize> iosurfaceData;
memcpy(iosurfaceData.data(), IOSurfaceGetBaseAddress(ioSurface.get()),
@@ -294,6 +298,11 @@ class IOSurfaceClientBufferTest : public ANGLETest
void doBlitTest(bool ioSurfaceIsSource, int width, int height)
{
if (!hasBlitExt())
{
return;
}
// Create IOSurface and bind it to a texture.
ScopedIOSurfaceRef ioSurface = CreateSinglePlaneIOSurface(width, height, 'BGRA', 4);
EGLSurface pbuffer;
@@ -361,6 +370,10 @@ class IOSurfaceClientBufferTest : public ANGLETest
}
bool hasIOSurfaceExt() const { return IsEGLDisplayExtensionEnabled(mDisplay, kIOSurfaceExt); }
bool hasBlitExt() const
{
return IsEGLDisplayExtensionEnabled(mDisplay, "ANGLE_framebuffer_blit");
}
EGLConfig mConfig;
EGLDisplay mDisplay;
@@ -465,6 +478,9 @@ TEST_P(IOSurfaceClientBufferTest, RenderToR16IOSurface)
{
ANGLE_SKIP_TEST_IF(!hasIOSurfaceExt());
// This test only works on ES3 since it requires an integer texture.
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
// TODO(http://anglebug.com/4369)
ANGLE_SKIP_TEST_IF(isSwiftshader());
@@ -990,4 +1006,5 @@ ANGLE_INSTANTIATE_TEST(IOSurfaceClientBufferTest,
ES2_OPENGL(),
ES3_OPENGL(),
ES2_VULKAN_SWIFTSHADER(),
ES3_VULKAN_SWIFTSHADER());
ES3_VULKAN_SWIFTSHADER(),
ES2_METAL());