Commit 4f247baf by Le Hoang Quyen Committed by Commit Bot

Metal: Implement EXT_draw_buffers & ANGLE_framebuffer_blit

Bug: angleproject:2634 Change-Id: I769ca7e113e660870e9b31dafb706c313db8ac24 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2332146 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com>
parent 1d331c91
...@@ -30,6 +30,12 @@ struct FeaturesMtl : FeatureSetBase ...@@ -30,6 +30,12 @@ struct FeaturesMtl : FeatureSetBase
Feature hasNonUniformDispatch = { Feature hasNonUniformDispatch = {
"has_non_uniform_dispatch", FeatureCategory::MetalFeatures, "has_non_uniform_dispatch", FeatureCategory::MetalFeatures,
"The renderer supports non uniform compute shader dispatch's group size", &members}; "The renderer supports non uniform compute shader dispatch's group size", &members};
// fragment stencil output support
Feature hasStencilOutput = {"has_shader_stencil_output", FeatureCategory::MetalFeatures,
"The renderer supports stencil output from fragment shader",
&members};
// Texture swizzle support: // Texture swizzle support:
Feature hasTextureSwizzle = {"has_texture_swizzle", FeatureCategory::MetalFeatures, Feature hasTextureSwizzle = {"has_texture_swizzle", FeatureCategory::MetalFeatures,
"The renderer supports texture swizzle", &members}; "The renderer supports texture swizzle", &members};
......
...@@ -134,6 +134,9 @@ uint64_t GetGpuIDFromDisplayID(uint32_t displayID); ...@@ -134,6 +134,9 @@ uint64_t GetGpuIDFromDisplayID(uint32_t displayID);
// Helper to get the active GPU ID from an OpenGL display mask. // Helper to get the active GPU ID from an OpenGL display mask.
uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask); uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask);
// Get VendorID from metal device's registry ID
VendorID GetVendorIDFromMetalDeviceRegistryID(uint64_t registryID);
#endif #endif
} // namespace angle } // namespace angle
......
...@@ -232,6 +232,55 @@ uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask) ...@@ -232,6 +232,55 @@ uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask)
return 0; return 0;
} }
// Get VendorID from metal device's registry ID
VendorID GetVendorIDFromMetalDeviceRegistryID(uint64_t registryID)
{
# if defined(ANGLE_PLATFORM_MACOS)
// On macOS, the following code is only supported since 10.13.
if (@available(macOS 10.13, *))
# endif
{
// Get a matching dictionary for the IOGraphicsAccelerator2
CFMutableDictionaryRef matchingDict = IORegistryEntryIDMatching(registryID);
if (matchingDict == nullptr)
{
return 0;
}
// IOServiceGetMatchingService will consume the reference on the matching dictionary,
// so we don't need to release the dictionary.
io_registry_entry_t acceleratorEntry =
IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict);
if (acceleratorEntry == IO_OBJECT_NULL)
{
return 0;
}
// Get the parent entry that will be the IOPCIDevice
io_registry_entry_t deviceEntry = IO_OBJECT_NULL;
if (IORegistryEntryGetParentEntry(acceleratorEntry, kIOServicePlane, &deviceEntry) !=
kIOReturnSuccess ||
deviceEntry == IO_OBJECT_NULL)
{
IOObjectRelease(acceleratorEntry);
return 0;
}
IOObjectRelease(acceleratorEntry);
uint32_t vendorId;
if (!GetEntryProperty(deviceEntry, CFSTR("vendor-id"), &vendorId))
{
vendorId = 0;
}
IOObjectRelease(deviceEntry);
return vendorId;
}
return 0;
}
bool GetSystemInfo(SystemInfo *info) bool GetSystemInfo(SystemInfo *info)
{ {
{ {
......
...@@ -54,6 +54,12 @@ _metal_backend_sources = [ ...@@ -54,6 +54,12 @@ _metal_backend_sources = [
"mtl_state_cache.mm", "mtl_state_cache.mm",
"mtl_utils.h", "mtl_utils.h",
"mtl_utils.mm", "mtl_utils.mm",
"shaders/compiled/compiled_default_metallib_2_1_debug_ios_autogen.inc",
"shaders/compiled/compiled_default_metallib_2_1_debug_ios_sim_autogen.inc",
"shaders/compiled/compiled_default_metallib_2_1_debug_mac_autogen.inc",
"shaders/compiled/compiled_default_metallib_2_1_ios_autogen.inc",
"shaders/compiled/compiled_default_metallib_2_1_ios_sim_autogen.inc",
"shaders/compiled/compiled_default_metallib_2_1_mac_autogen.inc",
"shaders/compiled/compiled_default_metallib_debug_ios_autogen.inc", "shaders/compiled/compiled_default_metallib_debug_ios_autogen.inc",
"shaders/compiled/compiled_default_metallib_debug_ios_sim_autogen.inc", "shaders/compiled/compiled_default_metallib_debug_ios_sim_autogen.inc",
"shaders/compiled/compiled_default_metallib_debug_mac_autogen.inc", "shaders/compiled/compiled_default_metallib_debug_mac_autogen.inc",
...@@ -86,6 +92,7 @@ angle_source_set("angle_metal_backend") { ...@@ -86,6 +92,7 @@ angle_source_set("angle_metal_backend") {
public_deps = [ public_deps = [
"${angle_root}:angle_glslang_wrapper", "${angle_root}:angle_glslang_wrapper",
"${angle_root}:angle_gpu_info_util",
"${angle_root}:angle_image_util", "${angle_root}:angle_image_util",
"${angle_root}:libANGLE_headers", "${angle_root}:libANGLE_headers",
] ]
......
...@@ -27,6 +27,7 @@ class DisplayMtl; ...@@ -27,6 +27,7 @@ class DisplayMtl;
class FramebufferMtl; class FramebufferMtl;
class VertexArrayMtl; class VertexArrayMtl;
class ProgramMtl; class ProgramMtl;
class RenderTargetMtl;
class WindowSurfaceMtl; class WindowSurfaceMtl;
class ContextMtl : public ContextImpl, public mtl::Context class ContextMtl : public ContextImpl, public mtl::Context
...@@ -266,7 +267,9 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -266,7 +267,9 @@ class ContextMtl : public ContextImpl, public mtl::Context
void invalidateRenderPipeline(); void invalidateRenderPipeline();
// Call this to notify ContextMtl whenever FramebufferMtl's state changed // Call this to notify ContextMtl whenever FramebufferMtl's state changed
void onDrawFrameBufferChange(const gl::Context *context, FramebufferMtl *framebuffer); void onDrawFrameBufferChangedState(const gl::Context *context,
FramebufferMtl *framebuffer,
bool renderPassChanged);
void onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer); void onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer);
const MTLClearColor &getClearColorValue() const; const MTLClearColor &getClearColorValue() const;
...@@ -297,7 +300,8 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -297,7 +300,8 @@ class ContextMtl : public ContextImpl, public mtl::Context
void present(const gl::Context *context, id<CAMetalDrawable> presentationDrawable); void present(const gl::Context *context, id<CAMetalDrawable> presentationDrawable);
angle::Result finishCommandBuffer(); angle::Result finishCommandBuffer();
// Check whether compatible render pass has been started. // Check whether compatible render pass has been started. Compatible render pass is a render
// pass having the same attachments, and possibly having different load/store options.
bool hasStartedRenderPass(const mtl::RenderPassDesc &desc); bool hasStartedRenderPass(const mtl::RenderPassDesc &desc);
// Get current render encoder. May be nullptr if no render pass has been started. // Get current render encoder. May be nullptr if no render pass has been started.
...@@ -305,16 +309,20 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -305,16 +309,20 @@ class ContextMtl : public ContextImpl, public mtl::Context
// Will end current command encoder if it is valid, then start new encoder. // Will end current command encoder if it is valid, then start new encoder.
// Unless hasStartedRenderPass(desc) returns true. // Unless hasStartedRenderPass(desc) returns true.
mtl::RenderCommandEncoder *getRenderCommandEncoder(const mtl::RenderPassDesc &desc); // Note: passing a compatible render pass with different load/store options won't end the
// current render pass. If a new render pass is desired, call endEncoding() prior to this.
mtl::RenderCommandEncoder *getRenderPassCommandEncoder(const mtl::RenderPassDesc &desc);
// Utilities to quickly create render command enconder to a specific texture: // Utilities to quickly create render command encoder to a specific texture:
// The previous content of texture will be loaded
mtl::RenderCommandEncoder *getTextureRenderCommandEncoder(const mtl::TextureRef &textureTarget,
const gl::ImageIndex &index);
// The previous content of texture will be loaded if clearColor is not provided // The previous content of texture will be loaded if clearColor is not provided
mtl::RenderCommandEncoder *getRenderCommandEncoder(const mtl::TextureRef &textureTarget, mtl::RenderCommandEncoder *getRenderTargetCommandEncoderWithClear(
const gl::ImageIndex &index, const RenderTargetMtl &renderTarget,
const Optional<MTLClearColor> &clearColor); const Optional<MTLClearColor> &clearColor);
// The previous content of texture will be loaded // The previous content of texture will be loaded
mtl::RenderCommandEncoder *getRenderCommandEncoder(const mtl::TextureRef &textureTarget, mtl::RenderCommandEncoder *getRenderTargetCommandEncoder(const RenderTargetMtl &renderTarget);
const gl::ImageIndex &index);
// Will end current command encoder and start new blit command encoder. Unless a blit comamnd // Will end current command encoder and start new blit command encoder. Unless a blit comamnd
// encoder is already started. // encoder is already started.
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "libANGLE/renderer/metal/FrameBufferMtl.h" #include "libANGLE/renderer/metal/FrameBufferMtl.h"
#include "libANGLE/renderer/metal/ProgramMtl.h" #include "libANGLE/renderer/metal/ProgramMtl.h"
#include "libANGLE/renderer/metal/RenderBufferMtl.h" #include "libANGLE/renderer/metal/RenderBufferMtl.h"
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
#include "libANGLE/renderer/metal/ShaderMtl.h" #include "libANGLE/renderer/metal/ShaderMtl.h"
#include "libANGLE/renderer/metal/TextureMtl.h" #include "libANGLE/renderer/metal/TextureMtl.h"
#include "libANGLE/renderer/metal/VertexArrayMtl.h" #include "libANGLE/renderer/metal/VertexArrayMtl.h"
...@@ -1212,7 +1213,7 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder() ...@@ -1212,7 +1213,7 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder()
return &mRenderEncoder; return &mRenderEncoder;
} }
mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::RenderPassDesc &desc) mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::RenderPassDesc &desc)
{ {
if (hasStartedRenderPass(desc)) if (hasStartedRenderPass(desc))
{ {
...@@ -1229,12 +1230,11 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::Render ...@@ -1229,12 +1230,11 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::Render
return &mRenderEncoder.restart(desc); return &mRenderEncoder.restart(desc);
} }
// Utilities to quickly create render command enconder to a specific texture: // Utilities to quickly create render command encoder to a specific texture:
// The previous content of texture will be loaded if clearColor is not provided // The previous content of texture will be loaded
mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder( mtl::RenderCommandEncoder *ContextMtl::getTextureRenderCommandEncoder(
const mtl::TextureRef &textureTarget, const mtl::TextureRef &textureTarget,
const gl::ImageIndex &index, const gl::ImageIndex &index)
const Optional<MTLClearColor> &clearColor)
{ {
ASSERT(textureTarget && textureTarget->valid()); ASSERT(textureTarget && textureTarget->valid());
...@@ -1244,21 +1244,39 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder( ...@@ -1244,21 +1244,39 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(
rpDesc.colorAttachments[0].level = index.getLevelIndex(); rpDesc.colorAttachments[0].level = index.getLevelIndex();
rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0; rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0;
rpDesc.numColorAttachments = 1; rpDesc.numColorAttachments = 1;
rpDesc.sampleCount = textureTarget->samples();
return getRenderPassCommandEncoder(rpDesc);
}
// The previous content of texture will be loaded if clearColor is not provided
mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoderWithClear(
const RenderTargetMtl &renderTarget,
const Optional<MTLClearColor> &clearColor)
{
ASSERT(renderTarget.getTexture());
mtl::RenderPassDesc rpDesc;
renderTarget.toRenderPassAttachmentDesc(&rpDesc.colorAttachments[0]);
rpDesc.numColorAttachments = 1;
rpDesc.sampleCount = renderTarget.getRenderSamples();
if (clearColor.valid()) if (clearColor.valid())
{ {
rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear; rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
rpDesc.colorAttachments[0].clearColor = rpDesc.colorAttachments[0].clearColor = mtl::EmulatedAlphaClearColor(
mtl::EmulatedAlphaClearColor(clearColor.value(), textureTarget->getColorWritableMask()); clearColor.value(), renderTarget.getTexture()->getColorWritableMask());
endEncoding(true);
} }
return getRenderCommandEncoder(rpDesc); return getRenderPassCommandEncoder(rpDesc);
} }
// The previous content of texture will be loaded // The previous content of texture will be loaded
mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::TextureRef &textureTarget, mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoder(
const gl::ImageIndex &index) const RenderTargetMtl &renderTarget)
{ {
return getRenderCommandEncoder(textureTarget, index, Optional<MTLClearColor>()); return getRenderTargetCommandEncoderWithClear(renderTarget, Optional<MTLClearColor>());
} }
mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoder() mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoder()
...@@ -1403,25 +1421,33 @@ void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context) ...@@ -1403,25 +1421,33 @@ void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context)
mDrawFramebuffer->onStartedDrawingToFrameBuffer(context); mDrawFramebuffer->onStartedDrawingToFrameBuffer(context);
onDrawFrameBufferChange(context, mDrawFramebuffer); onDrawFrameBufferChangedState(context, mDrawFramebuffer, true);
} }
void ContextMtl::onDrawFrameBufferChange(const gl::Context *context, FramebufferMtl *framebuffer) void ContextMtl::onDrawFrameBufferChangedState(const gl::Context *context,
FramebufferMtl *framebuffer,
bool renderPassChanged)
{ {
const gl::State &glState = getState(); const gl::State &glState = getState();
ASSERT(framebuffer == mtl::GetImpl(glState.getDrawFramebuffer())); ASSERT(framebuffer == mtl::GetImpl(glState.getDrawFramebuffer()));
mDirtyBits.set(DIRTY_BIT_DRAW_FRAMEBUFFER);
updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(), updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane()); glState.getFarPlane());
updateFrontFace(glState); updateFrontFace(glState);
updateScissor(glState); updateScissor(glState);
// End any render encoding using the old render pass. if (renderPassChanged)
endEncoding(false); {
// Need to re-apply state to RenderCommandEncoder // End any render encoding using the old render pass.
invalidateState(context); endEncoding(false);
// Need to re-apply state to RenderCommandEncoder
invalidateState(context);
}
else
{
// Invalidate current pipeline only.
invalidateRenderPipeline();
}
} }
void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer) void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMtl *backbuffer)
...@@ -1798,6 +1824,9 @@ angle::Result ContextMtl::checkIfPipelineChanged( ...@@ -1798,6 +1824,9 @@ angle::Result ContextMtl::checkIfPipelineChanged(
mRenderPipelineDesc.alphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled(); mRenderPipelineDesc.alphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled();
mRenderPipelineDesc.emulateCoverageMask = mState.isSampleCoverageEnabled(); mRenderPipelineDesc.emulateCoverageMask = mState.isSampleCoverageEnabled();
mRenderPipelineDesc.outputDescriptor.updateEnabledDrawBuffers(
mDrawFramebuffer->getState().getEnabledDrawBuffers());
*changedPipelineDesc = mRenderPipelineDesc; *changedPipelineDesc = mRenderPipelineDesc;
} }
......
...@@ -111,6 +111,9 @@ class DisplayMtl : public DisplayImpl ...@@ -111,6 +111,9 @@ class DisplayMtl : public DisplayImpl
bool supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const; bool supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const;
bool supportsIOSGPUFamily(uint8_t iOSFamily) const; bool supportsIOSGPUFamily(uint8_t iOSFamily) const;
bool supportsMacGPUFamily(uint8_t macFamily) const; bool supportsMacGPUFamily(uint8_t macFamily) const;
bool isAMD() const;
bool isIntel() const;
bool isNVIDIA() const;
id<MTLDevice> getMetalDevice() const { return mMetalDevice; } id<MTLDevice> getMetalDevice() const { return mMetalDevice; }
...@@ -160,6 +163,7 @@ class DisplayMtl : public DisplayImpl ...@@ -160,6 +163,7 @@ class DisplayMtl : public DisplayImpl
angle::Result initializeShaderLibrary(); angle::Result initializeShaderLibrary();
mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil; mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil;
uint32_t mMetalDeviceVendorId = 0;
mtl::CommandQueue mCmdQueue; mtl::CommandQueue mCmdQueue;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "libANGLE/renderer/metal/DisplayMtl.h" #include "libANGLE/renderer/metal/DisplayMtl.h"
#include "gpu_info_util/SystemInfo.h"
#include "libANGLE/Context.h" #include "libANGLE/Context.h"
#include "libANGLE/Display.h" #include "libANGLE/Display.h"
#include "libANGLE/Surface.h" #include "libANGLE/Surface.h"
...@@ -70,6 +71,8 @@ angle::Result DisplayMtl::initializeImpl(egl::Display *display) ...@@ -70,6 +71,8 @@ angle::Result DisplayMtl::initializeImpl(egl::Display *display)
return angle::Result::Stop; return angle::Result::Stop;
} }
mMetalDeviceVendorId = mtl::GetDeviceVendorId(mMetalDevice);
mCmdQueue.set([[mMetalDevice.get() newCommandQueue] ANGLE_MTL_AUTORELEASE]); mCmdQueue.set([[mMetalDevice.get() newCommandQueue] ANGLE_MTL_AUTORELEASE]);
mCapsInitialized = false; mCapsInitialized = false;
...@@ -100,6 +103,8 @@ void DisplayMtl::terminate() ...@@ -100,6 +103,8 @@ void DisplayMtl::terminate()
mMetalDevice = nil; mMetalDevice = nil;
mCapsInitialized = false; mCapsInitialized = false;
mMetalDeviceVendorId = 0;
if (mGlslangInitialized) if (mGlslangInitialized)
{ {
GlslangRelease(); GlslangRelease();
...@@ -585,9 +590,9 @@ void DisplayMtl::initializeExtensions() const ...@@ -585,9 +590,9 @@ void DisplayMtl::initializeExtensions() const
mNativeExtensions.mapBufferOES = true; mNativeExtensions.mapBufferOES = true;
mNativeExtensions.mapBufferRange = false; mNativeExtensions.mapBufferRange = false;
mNativeExtensions.textureStorage = true; mNativeExtensions.textureStorage = true;
mNativeExtensions.drawBuffers = false; mNativeExtensions.drawBuffers = true;
mNativeExtensions.fragDepth = true; mNativeExtensions.fragDepth = true;
mNativeExtensions.framebufferBlit = false; mNativeExtensions.framebufferBlit = true;
mNativeExtensions.framebufferMultisample = false; mNativeExtensions.framebufferMultisample = false;
mNativeExtensions.copyTexture = true; mNativeExtensions.copyTexture = true;
mNativeExtensions.copyCompressedTexture = false; mNativeExtensions.copyCompressedTexture = false;
...@@ -662,7 +667,13 @@ void DisplayMtl::initializeTextureCaps() const ...@@ -662,7 +667,13 @@ void DisplayMtl::initializeTextureCaps() const
void DisplayMtl::initializeFeatures() void DisplayMtl::initializeFeatures()
{ {
bool isMetal2_1 = false;
bool isMetal2_2 = false; bool isMetal2_2 = false;
if (ANGLE_APPLE_AVAILABLE_XCI(10.14, 13.0, 12.0))
{
isMetal2_1 = true;
}
if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0)) if (ANGLE_APPLE_AVAILABLE_XCI(10.15, 13.0, 13.0))
{ {
isMetal2_2 = true; isMetal2_2 = true;
...@@ -672,6 +683,7 @@ void DisplayMtl::initializeFeatures() ...@@ -672,6 +683,7 @@ void DisplayMtl::initializeFeatures()
mFeatures.hasBaseVertexInstancedDraw.enabled = true; mFeatures.hasBaseVertexInstancedDraw.enabled = true;
mFeatures.hasDepthTextureFiltering.enabled = false; mFeatures.hasDepthTextureFiltering.enabled = false;
mFeatures.hasNonUniformDispatch.enabled = true; mFeatures.hasNonUniformDispatch.enabled = true;
mFeatures.hasStencilOutput.enabled = false;
mFeatures.hasTextureSwizzle.enabled = false; mFeatures.hasTextureSwizzle.enabled = false;
mFeatures.allowSeparatedDepthStencilBuffers.enabled = false; mFeatures.allowSeparatedDepthStencilBuffers.enabled = false;
...@@ -682,6 +694,11 @@ void DisplayMtl::initializeFeatures() ...@@ -682,6 +694,11 @@ void DisplayMtl::initializeFeatures()
ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve, ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve,
supportsEitherGPUFamily(3, 1)); supportsEitherGPUFamily(3, 1));
// http://anglebug.com/4919
// Stencil blit shader is not compiled on Intel & NVIDIA, need investigation.
ANGLE_FEATURE_CONDITION((&mFeatures), hasStencilOutput,
isMetal2_1 && !isIntel() && !isNVIDIA());
ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle, ANGLE_FEATURE_CONDITION((&mFeatures), hasTextureSwizzle,
isMetal2_2 && supportsEitherGPUFamily(1, 2)); isMetal2_2 && supportsEitherGPUFamily(1, 2));
...@@ -710,11 +727,27 @@ angle::Result DisplayMtl::initializeShaderLibrary() ...@@ -710,11 +727,27 @@ angle::Result DisplayMtl::initializeShaderLibrary()
size_t compiled_shader_binary_len; size_t compiled_shader_binary_len;
#if !defined(NDEBUG) #if !defined(NDEBUG)
compiled_shader_binary = compiled_default_metallib_debug; if (getFeatures().hasStencilOutput.enabled)
compiled_shader_binary_len = compiled_default_metallib_debug_len; {
compiled_shader_binary = compiled_default_metallib_2_1_debug;
compiled_shader_binary_len = compiled_default_metallib_2_1_debug_len;
}
else
{
compiled_shader_binary = compiled_default_metallib_debug;
compiled_shader_binary_len = compiled_default_metallib_debug_len;
}
#else #else
compiled_shader_binary = compiled_default_metallib; if (getFeatures().hasStencilOutput.enabled)
compiled_shader_binary_len = compiled_default_metallib_len; {
compiled_shader_binary = compiled_default_metallib_2_1;
compiled_shader_binary_len = compiled_default_metallib_2_1_len;
}
else
{
compiled_shader_binary = compiled_default_metallib;
compiled_shader_binary_len = compiled_default_metallib_len;
}
#endif #endif
mDefaultShaders = CreateShaderLibraryFromBinary(getMetalDevice(), compiled_shader_binary, mDefaultShaders = CreateShaderLibraryFromBinary(getMetalDevice(), compiled_shader_binary,
...@@ -879,4 +912,19 @@ bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) c ...@@ -879,4 +912,19 @@ bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) c
return supportsIOSGPUFamily(iOSFamily) || supportsMacGPUFamily(macFamily); return supportsIOSGPUFamily(iOSFamily) || supportsMacGPUFamily(macFamily);
} }
bool DisplayMtl::isAMD() const
{
return angle::IsAMD(mMetalDeviceVendorId);
}
bool DisplayMtl::isIntel() const
{
return angle::IsIntel(mMetalDeviceVendorId);
}
bool DisplayMtl::isNVIDIA() const
{
return angle::IsNVIDIA(mMetalDeviceVendorId);
}
} // namespace rx } // namespace rx
...@@ -121,6 +121,13 @@ class FramebufferMtl : public FramebufferImpl ...@@ -121,6 +121,13 @@ class FramebufferMtl : public FramebufferImpl
private: private:
void reset(); void reset();
angle::Result invalidateImpl(ContextMtl *contextMtl, size_t count, const GLenum *attachments); angle::Result invalidateImpl(ContextMtl *contextMtl, size_t count, const GLenum *attachments);
angle::Result blitWithDraw(const gl::Context *context,
FramebufferMtl *srcFrameBuffer,
bool blitColorBuffer,
bool blitDepthBuffer,
bool blitStencilBuffer,
GLenum filter,
const mtl::BlitParams &baseParams);
angle::Result clearImpl(const gl::Context *context, angle::Result clearImpl(const gl::Context *context,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
mtl::ClearRectParams *clearOpts); mtl::ClearRectParams *clearOpts);
...@@ -129,6 +136,15 @@ class FramebufferMtl : public FramebufferImpl ...@@ -129,6 +136,15 @@ class FramebufferMtl : public FramebufferImpl
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
const mtl::ClearRectParams &clearOpts); const mtl::ClearRectParams &clearOpts);
angle::Result clearWithLoadOpRenderPassNotStarted(const gl::Context *context,
gl::DrawBufferMask clearColorBuffers,
const mtl::ClearRectParams &clearOpts);
angle::Result clearWithLoadOpRenderPassStarted(const gl::Context *context,
gl::DrawBufferMask clearColorBuffers,
const mtl::ClearRectParams &clearOpts,
mtl::RenderCommandEncoder *encoder);
angle::Result clearWithDraw(const gl::Context *context, angle::Result clearWithDraw(const gl::Context *context,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
const mtl::ClearRectParams &clearOpts); const mtl::ClearRectParams &clearOpts);
......
...@@ -60,8 +60,8 @@ angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context, ...@@ -60,8 +60,8 @@ angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context,
if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0)) if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0))
{ {
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, static_cast<uint32_t>(width), ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, static_cast<uint32_t>(width),
static_cast<uint32_t>(height), 1, false, false, static_cast<uint32_t>(height), 1, false,
&mTexture)); mFormat.hasDepthAndStencilBits(), &mTexture));
mRenderTarget.set(mTexture, 0, 0, mFormat); mRenderTarget.set(mTexture, 0, 0, mFormat);
......
...@@ -102,6 +102,7 @@ class SurfaceMtl : public SurfaceImpl ...@@ -102,6 +102,7 @@ class SurfaceMtl : public SurfaceImpl
int mSamples = 0; int mSamples = 0;
RenderTargetMtl mColorRenderTarget; RenderTargetMtl mColorRenderTarget;
RenderTargetMtl mColorManualResolveRenderTarget;
RenderTargetMtl mDepthRenderTarget; RenderTargetMtl mDepthRenderTarget;
RenderTargetMtl mStencilRenderTarget; RenderTargetMtl mStencilRenderTarget;
}; };
......
...@@ -89,17 +89,19 @@ angle::Result CreateTexture(const gl::Context *context, ...@@ -89,17 +89,19 @@ angle::Result CreateTexture(const gl::Context *context,
mtl::TextureRef *textureOut) mtl::TextureRef *textureOut)
{ {
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
bool allowFormatView = format.hasDepthAndStencilBits();
if (samples > 1) if (samples > 1)
{ {
ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, format, width, height, samples, ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, format, width, height, samples,
/** renderTargetOnly */ renderTargetOnly, /** renderTargetOnly */ renderTargetOnly,
/** allowFormatView */ false, textureOut)); /** allowFormatView */ allowFormatView,
textureOut));
} }
else else
{ {
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, format, width, height, 1, ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, format, width, height, 1,
/** renderTargetOnly */ renderTargetOnly, /** renderTargetOnly */ renderTargetOnly,
/** allowFormatView */ false, textureOut)); /** allowFormatView */ allowFormatView, textureOut));
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -291,6 +293,7 @@ void SurfaceMtl::destroy(const egl::Display *display) ...@@ -291,6 +293,7 @@ void SurfaceMtl::destroy(const egl::Display *display)
mMSColorTexture = nullptr; mMSColorTexture = nullptr;
mColorRenderTarget.reset(); mColorRenderTarget.reset();
mColorManualResolveRenderTarget.reset();
mDepthRenderTarget.reset(); mDepthRenderTarget.reset();
mStencilRenderTarget.reset(); mStencilRenderTarget.reset();
} }
...@@ -474,7 +477,7 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context * ...@@ -474,7 +477,7 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size)) if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size))
{ {
ANGLE_TRY(CreateTexture(context, mDepthFormat, size.width, size.height, mSamples, ANGLE_TRY(CreateTexture(context, mDepthFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ true, &mDepthTexture)); /** renderTargetOnly */ false, &mDepthTexture));
mDepthRenderTarget.set(mDepthTexture, 0, 0, mDepthFormat); mDepthRenderTarget.set(mDepthTexture, 0, 0, mDepthFormat);
} }
...@@ -488,7 +491,7 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context * ...@@ -488,7 +491,7 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
else else
{ {
ANGLE_TRY(CreateTexture(context, mStencilFormat, size.width, size.height, mSamples, ANGLE_TRY(CreateTexture(context, mStencilFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ true, &mStencilTexture)); /** renderTargetOnly */ false, &mStencilTexture));
} }
mStencilRenderTarget.set(mStencilTexture, 0, 0, mStencilFormat); mStencilRenderTarget.set(mStencilTexture, 0, 0, mStencilFormat);
...@@ -505,11 +508,13 @@ angle::Result SurfaceMtl::resolveColorTextureIfNeeded(const gl::Context *context ...@@ -505,11 +508,13 @@ angle::Result SurfaceMtl::resolveColorTextureIfNeeded(const gl::Context *context
// Manually resolve texture // Manually resolve texture
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
mColorManualResolveRenderTarget.set(mColorTexture, 0, 0, mColorFormat);
mtl::RenderCommandEncoder *encoder = mtl::RenderCommandEncoder *encoder =
contextMtl->getRenderCommandEncoder(mColorTexture, gl::ImageIndex::Make2D(0)); contextMtl->getRenderTargetCommandEncoder(mColorManualResolveRenderTarget);
ANGLE_TRY( ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(context, encoder,
contextMtl->getDisplay()->getUtils().blitWithDraw(context, encoder, mMSColorTexture)); mMSColorTexture));
contextMtl->endEncoding(true); contextMtl->endEncoding(true);
mColorManualResolveRenderTarget.reset();
} }
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -969,8 +974,9 @@ angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context * ...@@ -969,8 +974,9 @@ angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context *
if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB) if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB)
{ {
// This format has emulated alpha channel. Initialize texture's alpha channel to 1.0. // This format has emulated alpha channel. Initialize texture's alpha channel to 1.0.
ANGLE_TRY(mtl::InitializeTextureContentsGPU( ANGLE_TRY(mtl::InitializeTextureContentsGPU(context, mColorTexture, mColorFormat,
context, mColorTexture, gl::ImageIndex::Make2D(0), MTLColorWriteMaskAlpha)); gl::ImageIndex::Make2D(0),
MTLColorWriteMaskAlpha));
// Disable subsequent rendering to alpha channel. // Disable subsequent rendering to alpha channel.
mColorTexture->setColorWritableMask(MTLColorWriteMaskAll & (~MTLColorWriteMaskAlpha)); mColorTexture->setColorWritableMask(MTLColorWriteMaskAll & (~MTLColorWriteMaskAlpha));
......
...@@ -333,9 +333,9 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context) ...@@ -333,9 +333,9 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
{ {
case gl::TextureType::_2D: case gl::TextureType::_2D:
layers = 1; layers = 1;
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, desc.size.width, ANGLE_TRY(mtl::Texture::Make2DTexture(
desc.size.height, mips, false, true, contextMtl, mFormat, desc.size.width, desc.size.height, mips, false,
&mNativeTexture)); mFormat.hasDepthAndStencilBits(), &mNativeTexture));
mLayeredRenderTargets.resize(1); mLayeredRenderTargets.resize(1);
mLayeredRenderTargets[0].set(mNativeTexture, 0, 0, mFormat); mLayeredRenderTargets[0].set(mNativeTexture, 0, 0, mFormat);
mLayeredTextureViews.resize(1); mLayeredTextureViews.resize(1);
...@@ -344,7 +344,8 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context) ...@@ -344,7 +344,8 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
case gl::TextureType::CubeMap: case gl::TextureType::CubeMap:
layers = 6; layers = 6;
ANGLE_TRY(mtl::Texture::MakeCubeTexture(contextMtl, mFormat, desc.size.width, mips, ANGLE_TRY(mtl::Texture::MakeCubeTexture(contextMtl, mFormat, desc.size.width, mips,
false, true, &mNativeTexture)); false, mFormat.hasDepthAndStencilBits(),
&mNativeTexture));
mLayeredRenderTargets.resize(gl::kCubeFaceCount); mLayeredRenderTargets.resize(gl::kCubeFaceCount);
mLayeredTextureViews.resize(gl::kCubeFaceCount); mLayeredTextureViews.resize(gl::kCubeFaceCount);
for (uint32_t f = 0; f < gl::kCubeFaceCount; ++f) for (uint32_t f = 0; f < gl::kCubeFaceCount; ++f)
...@@ -894,7 +895,8 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context, ...@@ -894,7 +895,8 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context,
case gl::TextureType::_2D: case gl::TextureType::_2D:
case gl::TextureType::CubeMap: case gl::TextureType::CubeMap:
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mtlFormat, size.width, ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mtlFormat, size.width,
size.height, 1, false, false, &image)); size.height, 1, false,
mFormat.hasDepthAndStencilBits(), &image));
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -1204,20 +1206,26 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context, ...@@ -1204,20 +1206,26 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context,
mtl::TextureRef &image = mTexImages[GetImageLayerIndex(index)][index.getLevelIndex()]; mtl::TextureRef &image = mTexImages[GetImageLayerIndex(index)][index.getLevelIndex()];
ASSERT(image && image->valid()); ASSERT(image && image->valid());
mtl::RenderCommandEncoder *cmdEncoder = RenderTargetMtl writeRtt;
contextMtl->getRenderCommandEncoder(image, GetImageBaseLevelIndex(image)); writeRtt.set(image, 0, 0, mFormat);
mtl::BlitParams blitParams; mtl::RenderCommandEncoder *cmdEncoder = contextMtl->getRenderTargetCommandEncoder(writeRtt);
mtl::ColorBlitParams blitParams;
blitParams.dstTextureSize = image->size(0);
blitParams.dstRect = gl::Rectangle(modifiedDestOffset.x, modifiedDestOffset.y,
clippedSourceArea.width, clippedSourceArea.height);
blitParams.dstScissorRect = blitParams.dstRect;
blitParams.dstOffset = modifiedDestOffset; blitParams.enabledBuffers.set(0);
blitParams.dstColorMask = image->getColorWritableMask();
blitParams.src = colorReadRT->getTexture(); blitParams.src = colorReadRT->getTexture();
blitParams.srcLevel = static_cast<uint32_t>(colorReadRT->getLevelIndex()); blitParams.srcLevel = colorReadRT->getLevelIndex();
blitParams.srcLayer = colorReadRT->getLayerIndex();
blitParams.srcRect = clippedSourceArea; blitParams.srcRect = clippedSourceArea;
blitParams.srcYFlipped = framebufferMtl->flipY(); blitParams.srcYFlipped = framebufferMtl->flipY();
blitParams.dstLuminance = internalFormat.isLUMA(); blitParams.dstLuminance = internalFormat.isLUMA();
return displayMtl->getUtils().blitWithDraw(context, cmdEncoder, blitParams); return displayMtl->getUtils().blitColorWithDraw(context, cmdEncoder, blitParams);
} }
angle::Result TextureMtl::copySubImageCPU(const gl::Context *context, angle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
...@@ -1336,14 +1344,19 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context, ...@@ -1336,14 +1344,19 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context,
} }
mtl::RenderCommandEncoder *cmdEncoder = mtl::RenderCommandEncoder *cmdEncoder =
contextMtl->getRenderCommandEncoder(image, GetImageBaseLevelIndex(image)); contextMtl->getTextureRenderCommandEncoder(image, GetImageBaseLevelIndex(image));
mtl::BlitParams blitParams; mtl::ColorBlitParams blitParams;
blitParams.dstTextureSize = image->size();
blitParams.dstRect =
gl::Rectangle(destOffset.x, destOffset.y, sourceBox.width, sourceBox.height);
blitParams.dstScissorRect = blitParams.dstRect;
blitParams.dstOffset = destOffset; blitParams.enabledBuffers.set(0);
blitParams.dstColorMask = image->getColorWritableMask();
blitParams.src = sourceTexture; blitParams.src = sourceTexture;
blitParams.srcLevel = sourceNativeLevel; blitParams.srcLevel = sourceNativeLevel;
blitParams.srcLayer = 0;
blitParams.srcRect = gl::Rectangle(sourceBox.x, sourceBox.y, sourceBox.width, sourceBox.height); blitParams.srcRect = gl::Rectangle(sourceBox.x, sourceBox.y, sourceBox.width, sourceBox.height);
blitParams.srcYFlipped = false; blitParams.srcYFlipped = false;
blitParams.dstLuminance = internalFormat.isLUMA(); blitParams.dstLuminance = internalFormat.isLUMA();
...@@ -1351,7 +1364,7 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context, ...@@ -1351,7 +1364,7 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context,
blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha; blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha;
blitParams.unpackUnmultiplyAlpha = unpackUnmultiplyAlpha; blitParams.unpackUnmultiplyAlpha = unpackUnmultiplyAlpha;
return displayMtl->getUtils().blitWithDraw(context, cmdEncoder, blitParams); return displayMtl->getUtils().blitColorWithDraw(context, cmdEncoder, blitParams);
} }
angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context, angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context,
......
...@@ -97,7 +97,7 @@ namespace mtl ...@@ -97,7 +97,7 @@ namespace mtl
// NOTE(hqle): support variable max number of vertex attributes // NOTE(hqle): support variable max number of vertex attributes
constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS; constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS;
// NOTE(hqle): support variable max number of render targets // NOTE(hqle): support variable max number of render targets
constexpr uint32_t kMaxRenderTargets = 1; constexpr uint32_t kMaxRenderTargets = 4;
constexpr size_t kDefaultAttributeSize = 4 * sizeof(float); constexpr size_t kDefaultAttributeSize = 4 * sizeof(float);
......
...@@ -158,6 +158,7 @@ class Texture final : public Resource, ...@@ -158,6 +158,7 @@ class Texture final : public Resource,
uint32_t width(uint32_t level = 0) const; uint32_t width(uint32_t level = 0) const;
uint32_t height(uint32_t level = 0) const; uint32_t height(uint32_t level = 0) const;
uint32_t depth(uint32_t level = 0) const;
gl::Extents size(uint32_t level = 0) const; gl::Extents size(uint32_t level = 0) const;
gl::Extents size(const gl::ImageIndex &index) const; gl::Extents size(const gl::ImageIndex &index) const;
...@@ -171,6 +172,9 @@ class Texture final : public Resource, ...@@ -171,6 +172,9 @@ class Texture final : public Resource,
// Get linear color space view. Only usable for sRGB textures. // Get linear color space view. Only usable for sRGB textures.
TextureRef getLinearColorView(); TextureRef getLinearColorView();
// Get stencil view
TextureRef getStencilView();
// Change the wrapped metal object. Special case for swapchain image // Change the wrapped metal object. Special case for swapchain image
void set(id<MTLTexture> metalTexture); void set(id<MTLTexture> metalTexture);
...@@ -206,6 +210,8 @@ class Texture final : public Resource, ...@@ -206,6 +210,8 @@ class Texture final : public Resource,
// Linear view of sRGB texture // Linear view of sRGB texture
TextureRef mLinearColorView; TextureRef mLinearColorView;
TextureRef mStencilView;
}; };
class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>> class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
......
...@@ -425,13 +425,18 @@ uint32_t Texture::height(uint32_t level) const ...@@ -425,13 +425,18 @@ uint32_t Texture::height(uint32_t level) const
return static_cast<uint32_t>(GetMipSize(get().height, level)); return static_cast<uint32_t>(GetMipSize(get().height, level));
} }
uint32_t Texture::depth(uint32_t level) const
{
return static_cast<uint32_t>(GetMipSize(get().depth, level));
}
gl::Extents Texture::size(uint32_t level) const gl::Extents Texture::size(uint32_t level) const
{ {
gl::Extents re; gl::Extents re;
re.width = width(level); re.width = width(level);
re.height = height(level); re.height = height(level);
re.depth = static_cast<uint32_t>(GetMipSize(get().depth, level)); re.depth = depth(level);
return re; return re;
} }
...@@ -472,10 +477,41 @@ TextureRef Texture::getLinearColorView() ...@@ -472,10 +477,41 @@ TextureRef Texture::getLinearColorView()
return mLinearColorView; return mLinearColorView;
} }
TextureRef Texture::getStencilView()
{
if (mStencilView)
{
return mStencilView;
}
switch (pixelFormat())
{
case MTLPixelFormatStencil8:
case MTLPixelFormatX32_Stencil8:
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case MTLPixelFormatX24_Stencil8:
#endif
return mStencilView = shared_from_this();
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
case MTLPixelFormatDepth24Unorm_Stencil8:
mStencilView = createViewWithDifferentFormat(MTLPixelFormatX24_Stencil8);
break;
#endif
case MTLPixelFormatDepth32Float_Stencil8:
mStencilView = createViewWithDifferentFormat(MTLPixelFormatX32_Stencil8);
break;
default:
UNREACHABLE();
}
return mStencilView;
}
void Texture::set(id<MTLTexture> metalTexture) void Texture::set(id<MTLTexture> metalTexture)
{ {
ParentClass::set(metalTexture); ParentClass::set(metalTexture);
// Reset stencil view
mStencilView = nullptr;
mLinearColorView = nullptr; mLinearColorView = nullptr;
} }
......
...@@ -206,6 +206,8 @@ struct RenderPipelineOutputDesc ...@@ -206,6 +206,8 @@ struct RenderPipelineOutputDesc
{ {
bool operator==(const RenderPipelineOutputDesc &rhs) const; bool operator==(const RenderPipelineOutputDesc &rhs) const;
void updateEnabledDrawBuffers(gl::DrawBufferMask enabledBuffers);
RenderPipelineColorAttachmentDesc colorAttachments[kMaxRenderTargets]; RenderPipelineColorAttachmentDesc colorAttachments[kMaxRenderTargets];
// Use uint16_t instead of MTLPixelFormat to compact space // Use uint16_t instead of MTLPixelFormat to compact space
......
...@@ -618,6 +618,17 @@ bool RenderPipelineOutputDesc::operator==(const RenderPipelineOutputDesc &rhs) c ...@@ -618,6 +618,17 @@ bool RenderPipelineOutputDesc::operator==(const RenderPipelineOutputDesc &rhs) c
ANGLE_PROP_EQ(*this, rhs, stencilAttachmentPixelFormat); ANGLE_PROP_EQ(*this, rhs, stencilAttachmentPixelFormat);
} }
void RenderPipelineOutputDesc::updateEnabledDrawBuffers(gl::DrawBufferMask enabledBuffers)
{
for (uint32_t colorIndex = 0; colorIndex < this->numColorAttachments; ++colorIndex)
{
if (!enabledBuffers.test(colorIndex))
{
this->colorAttachments[colorIndex].writeMask = MTLColorWriteMaskNone;
}
}
}
// RenderPipelineDesc implementation // RenderPipelineDesc implementation
RenderPipelineDesc::RenderPipelineDesc() RenderPipelineDesc::RenderPipelineDesc()
{ {
...@@ -716,11 +727,10 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat ...@@ -716,11 +727,10 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat
auto &renderPassColorAttachment = this->colorAttachments[i]; auto &renderPassColorAttachment = this->colorAttachments[i];
auto texture = renderPassColorAttachment.texture; auto texture = renderPassColorAttachment.texture;
// Copy parameters from blend state
outputDescriptor.colorAttachments[i].update(blendState);
if (texture) if (texture)
{ {
// Copy parameters from blend state
outputDescriptor.colorAttachments[i].update(blendState);
outputDescriptor.colorAttachments[i].pixelFormat = texture->pixelFormat(); outputDescriptor.colorAttachments[i].pixelFormat = texture->pixelFormat();
...@@ -731,7 +741,9 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat ...@@ -731,7 +741,9 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat
} }
else else
{ {
outputDescriptor.colorAttachments[i].pixelFormat = MTLPixelFormatInvalid;
outputDescriptor.colorAttachments[i].blendingEnabled = false;
outputDescriptor.colorAttachments[i].pixelFormat = MTLPixelFormatInvalid;
} }
} }
......
...@@ -37,6 +37,7 @@ angle::Result InitializeTextureContents(const gl::Context *context, ...@@ -37,6 +37,7 @@ angle::Result InitializeTextureContents(const gl::Context *context,
// - channelsToInit parameter controls which channels will get their content initialized. // - channelsToInit parameter controls which channels will get their content initialized.
angle::Result InitializeTextureContentsGPU(const gl::Context *context, angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const TextureRef &texture, const TextureRef &texture,
const Format &textureObjFormat,
const gl::ImageIndex &index, const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit); MTLColorWriteMask channelsToInit);
...@@ -54,6 +55,8 @@ MTLScissorRect GetScissorRect(const gl::Rectangle &rect, ...@@ -54,6 +55,8 @@ MTLScissorRect GetScissorRect(const gl::Rectangle &rect,
NSUInteger screenHeight = 0, NSUInteger screenHeight = 0,
bool flipY = false); bool flipY = false);
uint32_t GetDeviceVendorId(id<MTLDevice> metalDevice);
AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice, AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice,
const std::string &source, const std::string &source,
AutoObjCPtr<NSError *> *error); AutoObjCPtr<NSError *> *error);
......
...@@ -13,8 +13,10 @@ ...@@ -13,8 +13,10 @@
#include <TargetConditionals.h> #include <TargetConditionals.h>
#include "common/MemoryBuffer.h" #include "common/MemoryBuffer.h"
#include "gpu_info_util/SystemInfo.h"
#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/RenderTargetMtl.h"
#include "libANGLE/renderer/metal/mtl_render_utils.h" #include "libANGLE/renderer/metal/mtl_render_utils.h"
namespace rx namespace rx
...@@ -22,6 +24,48 @@ namespace rx ...@@ -22,6 +24,48 @@ namespace rx
namespace mtl namespace mtl
{ {
namespace
{
uint32_t GetDeviceVendorIdFromName(id<MTLDevice> metalDevice)
{
struct Vendor
{
NSString *const trademark;
uint32_t vendorId;
};
constexpr Vendor kVendors[] = {{@"AMD", angle::kVendorID_AMD},
{@"Radeon", angle::kVendorID_AMD},
{@"Intel", angle::kVendorID_Intel},
{@"Geforce", angle::kVendorID_NVIDIA},
{@"Quadro", angle::kVendorID_NVIDIA}};
ANGLE_MTL_OBJC_SCOPE
{
if (metalDevice)
{
for (const Vendor &it : kVendors)
{
if ([metalDevice.name rangeOfString:it.trademark].location != NSNotFound)
{
return it.vendorId;
}
}
}
return 0;
}
}
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
uint32_t GetDeviceVendorIdFromIOKit(id<MTLDevice> device)
{
return angle::GetVendorIDFromMetalDeviceRegistryID(device.registryID);
}
#endif
}
angle::Result InitializeTextureContents(const gl::Context *context, angle::Result InitializeTextureContents(const gl::Context *context,
const TextureRef &texture, const TextureRef &texture,
const Format &textureObjFormat, const Format &textureObjFormat,
...@@ -89,7 +133,8 @@ angle::Result InitializeTextureContents(const gl::Context *context, ...@@ -89,7 +133,8 @@ angle::Result InitializeTextureContents(const gl::Context *context,
} }
else else
{ {
ANGLE_TRY(InitializeTextureContentsGPU(context, texture, index, MTLColorWriteMaskAll)); ANGLE_TRY(InitializeTextureContentsGPU(context, texture, textureObjFormat, index,
MTLColorWriteMaskAll));
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -97,11 +142,17 @@ angle::Result InitializeTextureContents(const gl::Context *context, ...@@ -97,11 +142,17 @@ angle::Result InitializeTextureContents(const gl::Context *context,
angle::Result InitializeTextureContentsGPU(const gl::Context *context, angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const TextureRef &texture, const TextureRef &texture,
const Format &textureObjFormat,
const gl::ImageIndex &index, const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit) MTLColorWriteMask channelsToInit)
{ {
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
// NOTE(hqle): Support layered textures
ASSERT(!index.hasLayer());
// Use clear render command // Use clear render command
RenderTargetMtl tempRtt;
tempRtt.set(texture, index.getLevelIndex(), 0, textureObjFormat);
// temporarily enable color channels requested via channelsToInit. Some emulated format has some // temporarily enable color channels requested via channelsToInit. Some emulated format has some
// channels write mask disabled when the texture is created. // channels write mask disabled when the texture is created.
...@@ -113,16 +164,18 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context, ...@@ -113,16 +164,18 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
{ {
// If all channels will be initialized, use clear loadOp. // If all channels will be initialized, use clear loadOp.
Optional<MTLClearColor> blackColor = MTLClearColorMake(0, 0, 0, 1); Optional<MTLClearColor> blackColor = MTLClearColorMake(0, 0, 0, 1);
encoder = contextMtl->getRenderCommandEncoder(texture, index, blackColor); encoder = contextMtl->getRenderTargetCommandEncoderWithClear(tempRtt, blackColor);
} }
else else
{ {
// If there are some channels don't need to be initialized, we must use clearWithDraw. // If there are some channels don't need to be initialized, we must use clearWithDraw.
encoder = contextMtl->getRenderCommandEncoder(texture, index); encoder = contextMtl->getRenderTargetCommandEncoder(tempRtt);
ClearRectParams clearParams; ClearRectParams clearParams;
clearParams.clearColor = {.alpha = 1}; clearParams.clearColor = {.alpha = 1};
clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height()); clearParams.dstTextureSize = texture->size();
clearParams.enabledBuffers.set(0);
clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height());
ANGLE_TRY( ANGLE_TRY(
contextMtl->getDisplay()->getUtils().clearWithDraw(context, encoder, clearParams)); contextMtl->getDisplay()->getUtils().clearWithDraw(context, encoder, clearParams));
...@@ -193,6 +246,23 @@ MTLScissorRect GetScissorRect(const gl::Rectangle &rect, NSUInteger screenHeight ...@@ -193,6 +246,23 @@ MTLScissorRect GetScissorRect(const gl::Rectangle &rect, NSUInteger screenHeight
return re; return re;
} }
uint32_t GetDeviceVendorId(id<MTLDevice> metalDevice)
{
uint32_t vendorId = 0;
#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
if (ANGLE_APPLE_AVAILABLE_XC(10.13, 13.0))
{
vendorId = GetDeviceVendorIdFromIOKit(metalDevice);
}
#endif
if (!vendorId)
{
vendorId = GetDeviceVendorIdFromName(metalDevice);
}
return vendorId;
}
AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice, AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice,
const std::string &source, const std::string &source,
AutoObjCPtr<NSError *> *error) AutoObjCPtr<NSError *> *error)
......
...@@ -834,6 +834,9 @@ TEST_P(BlitFramebufferANGLETest, BlitStencil) ...@@ -834,6 +834,9 @@ TEST_P(BlitFramebufferANGLETest, BlitStencil)
// http://anglebug.com/2205 // http://anglebug.com/2205
ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9()); ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9());
// http://anglebug.com/4919
ANGLE_SKIP_TEST_IF(IsIntel() && IsMetal());
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO); glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
glClearColor(0.0, 1.0, 0.0, 1.0); glClearColor(0.0, 1.0, 0.0, 1.0);
...@@ -2006,6 +2009,8 @@ ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest, ...@@ -2006,6 +2009,8 @@ ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest,
ES2_OPENGL(), ES2_OPENGL(),
ES3_OPENGL(), ES3_OPENGL(),
ES2_VULKAN(), ES2_VULKAN(),
ES3_VULKAN()); ES3_VULKAN(),
ES2_METAL(),
WithNoShaderStencilOutput(ES2_METAL()));
ANGLE_INSTANTIATE_TEST_ES3(BlitFramebufferTest); ANGLE_INSTANTIATE_TEST_ES3(BlitFramebufferTest);
...@@ -209,6 +209,11 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp) ...@@ -209,6 +209,11 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp)
stream << "_EmulateCopyTexImage2DFromRenderbuffers"; stream << "_EmulateCopyTexImage2DFromRenderbuffers";
} }
if (pp.eglParameters.shaderStencilOutputFeature == EGL_FALSE)
{
stream << "_NoStencilOutput";
}
return stream; return stream;
} }
......
...@@ -227,6 +227,13 @@ inline PlatformParameters WithEmulateCopyTexImage2DFromRenderbuffers( ...@@ -227,6 +227,13 @@ inline PlatformParameters WithEmulateCopyTexImage2DFromRenderbuffers(
return p; return p;
} }
inline PlatformParameters WithNoShaderStencilOutput(const PlatformParameters &params)
{
PlatformParameters re = params;
re.eglParameters.shaderStencilOutputFeature = EGL_FALSE;
return re;
}
inline PlatformParameters WithRobustness(const PlatformParameters &params) inline PlatformParameters WithRobustness(const PlatformParameters &params)
{ {
PlatformParameters withRobustness = params; PlatformParameters withRobustness = params;
......
...@@ -61,7 +61,7 @@ struct EGLPlatformParameters ...@@ -61,7 +61,7 @@ struct EGLPlatformParameters
return std::tie(renderer, majorVersion, minorVersion, deviceType, presentPath, return std::tie(renderer, majorVersion, minorVersion, deviceType, presentPath,
debugLayersEnabled, contextVirtualization, transformFeedbackFeature, debugLayersEnabled, contextVirtualization, transformFeedbackFeature,
allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers, allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers,
platformMethods, robustness); shaderStencilOutputFeature, platformMethods, robustness);
} }
EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE; EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
...@@ -75,6 +75,7 @@ struct EGLPlatformParameters ...@@ -75,6 +75,7 @@ struct EGLPlatformParameters
EGLint transformFeedbackFeature = EGL_DONT_CARE; EGLint transformFeedbackFeature = EGL_DONT_CARE;
EGLint allocateNonZeroMemoryFeature = EGL_DONT_CARE; EGLint allocateNonZeroMemoryFeature = EGL_DONT_CARE;
EGLint emulateCopyTexImage2DFromRenderbuffers = EGL_DONT_CARE; EGLint emulateCopyTexImage2DFromRenderbuffers = EGL_DONT_CARE;
EGLint shaderStencilOutputFeature = EGL_DONT_CARE;
angle::PlatformMethods *platformMethods = nullptr; angle::PlatformMethods *platformMethods = nullptr;
}; };
......
...@@ -196,6 +196,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow, ...@@ -196,6 +196,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow,
enabledFeatureOverrides.push_back("emulate_copyteximage2d_from_renderbuffers"); enabledFeatureOverrides.push_back("emulate_copyteximage2d_from_renderbuffers");
} }
if (params.shaderStencilOutputFeature == EGL_FALSE)
{
disabledFeatureOverrides.push_back("has_shader_stencil_output");
}
if (!disabledFeatureOverrides.empty()) if (!disabledFeatureOverrides.empty())
{ {
if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr) if (strstr(extensionString, "EGL_ANGLE_feature_control") == nullptr)
......
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