From 69ca10255c64bef82912c5d6118534c87ff245b6 Mon Sep 17 00:00:00 2001 From: Le Hoang Quyen Date: Fri, 31 Jul 2020 02:08:09 +0800 Subject: [PATCH] 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 Reviewed-by: Jonah Ryan-Davis Reviewed-by: Jamie Madill --- .../Metal_format_table.json | 6 +- src/libANGLE/renderer/metal/DisplayMtl.h | 5 + src/libANGLE/renderer/metal/DisplayMtl.mm | 46 ++- src/libANGLE/renderer/metal/SurfaceMtl.h | 73 +++++ src/libANGLE/renderer/metal/SurfaceMtl.mm | 287 +++++++++++++++++- src/libANGLE/renderer/metal/TextureMtl.mm | 28 +- .../renderer/metal/gen_mtl_format_table.py | 2 +- .../renderer/metal/mtl_format_map.json | 13 +- .../metal/mtl_format_table_autogen.mm | 225 +------------- .../renderer/metal/mtl_format_utils.mm | 2 + src/libANGLE/renderer/metal/mtl_utils.h | 7 + src/libANGLE/renderer/metal/mtl_utils.mm | 43 +++ .../EGLIOSurfaceClientBufferTest.cpp | 19 +- 13 files changed, 498 insertions(+), 258 deletions(-) diff --git a/scripts/code_generation_hashes/Metal_format_table.json b/scripts/code_generation_hashes/Metal_format_table.json index 9f151dc59..3dd6132a1 100644 --- a/scripts/code_generation_hashes/Metal_format_table.json +++ b/scripts/code_generation_hashes/Metal_format_table.json @@ -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" } \ No newline at end of file diff --git a/src/libANGLE/renderer/metal/DisplayMtl.h b/src/libANGLE/renderer/metal/DisplayMtl.h index 9bc28f024..72a34c915 100644 --- a/src/libANGLE/renderer/metal/DisplayMtl.h +++ b/src/libANGLE/renderer/metal/DisplayMtl.h @@ -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; diff --git a/src/libANGLE/renderer/metal/DisplayMtl.mm b/src/libANGLE/renderer/metal/DisplayMtl.mm index ebebb2c20..3a4ca0430 100644 --- a/src/libANGLE/renderer/metal/DisplayMtl.mm +++ b/src/libANGLE/renderer/metal/DisplayMtl.mm @@ -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(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(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 diff --git a/src/libANGLE/renderer/metal/SurfaceMtl.h b/src/libANGLE/renderer/metal/SurfaceMtl.h index af295b7be..6bf23bd0e 100644 --- a/src/libANGLE/renderer/metal/SurfaceMtl.h +++ b/src/libANGLE/renderer/metal/SurfaceMtl.h @@ -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_ */ diff --git a/src/libANGLE/renderer/metal/SurfaceMtl.mm b/src/libANGLE/renderer/metal/SurfaceMtl.mm index 51238f509..68cf27d5f 100644 --- a/src/libANGLE/renderer/metal/SurfaceMtl.mm +++ b/src/libANGLE/renderer/metal/SurfaceMtl.mm @@ -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 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(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(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(internalFormat), static_cast(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 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(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(width) > IOSurfaceGetWidthOfPlane(ioSurface, plane) || + height <= 0 || static_cast(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(internalFormat), static_cast(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; +} + } diff --git a/src/libANGLE/renderer/metal/TextureMtl.mm b/src/libANGLE/renderer/metal/TextureMtl.mm index a54e657e5..7bf3ce731 100644 --- a/src/libANGLE/renderer/metal/TextureMtl.mm +++ b/src/libANGLE/renderer/metal/TextureMtl.mm @@ -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(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, diff --git a/src/libANGLE/renderer/metal/gen_mtl_format_table.py b/src/libANGLE/renderer/metal/gen_mtl_format_table.py index a1f1e92b0..763af2814 100644 --- a/src/libANGLE/renderer/metal/gen_mtl_format_table.py +++ b/src/libANGLE/renderer/metal/gen_mtl_format_table.py @@ -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"] diff --git a/src/libANGLE/renderer/metal/mtl_format_map.json b/src/libANGLE/renderer/metal/mtl_format_map.json index bd58f1226..79caa7ca6 100644 --- a/src/libANGLE/renderer/metal/mtl_format_map.json +++ b/src/libANGLE/renderer/metal/mtl_format_map.json @@ -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": { diff --git a/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm b/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm index ed7cb4ab8..7f93e8627 100644 --- a/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm +++ b/src/libANGLE/renderer/metal/mtl_format_table_autogen.mm @@ -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; diff --git a/src/libANGLE/renderer/metal/mtl_format_utils.mm b/src/libANGLE/renderer/metal/mtl_format_utils.mm index c7f96b398..9724143ef 100644 --- a/src/libANGLE/renderer/metal/mtl_format_utils.mm +++ b/src/libANGLE/renderer/metal/mtl_format_utils.mm @@ -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: diff --git a/src/libANGLE/renderer/metal/mtl_utils.h b/src/libANGLE/renderer/metal/mtl_utils.h index 37251e3a2..41f98dcb2 100644 --- a/src/libANGLE/renderer/metal/mtl_utils.h +++ b/src/libANGLE/renderer/metal/mtl_utils.h @@ -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, diff --git a/src/libANGLE/renderer/metal/mtl_utils.mm b/src/libANGLE/renderer/metal/mtl_utils.mm index 3da89334f..b08eaaaea 100644 --- a/src/libANGLE/renderer/metal/mtl_utils.mm +++ b/src/libANGLE/renderer/metal/mtl_utils.mm @@ -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 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; diff --git a/src/tests/egl_tests/EGLIOSurfaceClientBufferTest.cpp b/src/tests/egl_tests/EGLIOSurfaceClientBufferTest.cpp index 0d36946ef..6ee9dc21e 100644 --- a/src/tests/egl_tests/EGLIOSurfaceClientBufferTest.cpp +++ b/src/tests/egl_tests/EGLIOSurfaceClientBufferTest.cpp @@ -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 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());