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
Feature hasNonUniformDispatch = {
"has_non_uniform_dispatch", FeatureCategory::MetalFeatures,
"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:
Feature hasTextureSwizzle = {"has_texture_swizzle", FeatureCategory::MetalFeatures,
"The renderer supports texture swizzle", &members};
......
......@@ -134,6 +134,9 @@ uint64_t GetGpuIDFromDisplayID(uint32_t displayID);
// Helper to get the active GPU ID from an OpenGL display mask.
uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask);
// Get VendorID from metal device's registry ID
VendorID GetVendorIDFromMetalDeviceRegistryID(uint64_t registryID);
#endif
} // namespace angle
......
......@@ -232,6 +232,55 @@ uint64_t GetGpuIDFromOpenGLDisplayMask(uint32_t displayMask)
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)
{
{
......
......@@ -54,6 +54,12 @@ _metal_backend_sources = [
"mtl_state_cache.mm",
"mtl_utils.h",
"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_sim_autogen.inc",
"shaders/compiled/compiled_default_metallib_debug_mac_autogen.inc",
......@@ -86,6 +92,7 @@ angle_source_set("angle_metal_backend") {
public_deps = [
"${angle_root}:angle_glslang_wrapper",
"${angle_root}:angle_gpu_info_util",
"${angle_root}:angle_image_util",
"${angle_root}:libANGLE_headers",
]
......
......@@ -27,6 +27,7 @@ class DisplayMtl;
class FramebufferMtl;
class VertexArrayMtl;
class ProgramMtl;
class RenderTargetMtl;
class WindowSurfaceMtl;
class ContextMtl : public ContextImpl, public mtl::Context
......@@ -266,7 +267,9 @@ class ContextMtl : public ContextImpl, public mtl::Context
void invalidateRenderPipeline();
// 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);
const MTLClearColor &getClearColorValue() const;
......@@ -297,7 +300,8 @@ class ContextMtl : public ContextImpl, public mtl::Context
void present(const gl::Context *context, id<CAMetalDrawable> presentationDrawable);
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);
// 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
// Will end current command encoder if it is valid, then start new encoder.
// 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
mtl::RenderCommandEncoder *getRenderCommandEncoder(const mtl::TextureRef &textureTarget,
const gl::ImageIndex &index,
const Optional<MTLClearColor> &clearColor);
mtl::RenderCommandEncoder *getRenderTargetCommandEncoderWithClear(
const RenderTargetMtl &renderTarget,
const Optional<MTLClearColor> &clearColor);
// The previous content of texture will be loaded
mtl::RenderCommandEncoder *getRenderCommandEncoder(const mtl::TextureRef &textureTarget,
const gl::ImageIndex &index);
mtl::RenderCommandEncoder *getRenderTargetCommandEncoder(const RenderTargetMtl &renderTarget);
// Will end current command encoder and start new blit command encoder. Unless a blit comamnd
// encoder is already started.
......
......@@ -18,6 +18,7 @@
#include "libANGLE/renderer/metal/FrameBufferMtl.h"
#include "libANGLE/renderer/metal/ProgramMtl.h"
#include "libANGLE/renderer/metal/RenderBufferMtl.h"
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
#include "libANGLE/renderer/metal/ShaderMtl.h"
#include "libANGLE/renderer/metal/TextureMtl.h"
#include "libANGLE/renderer/metal/VertexArrayMtl.h"
......@@ -1212,7 +1213,7 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder()
return &mRenderEncoder;
}
mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::RenderPassDesc &desc)
mtl::RenderCommandEncoder *ContextMtl::getRenderPassCommandEncoder(const mtl::RenderPassDesc &desc)
{
if (hasStartedRenderPass(desc))
{
......@@ -1229,12 +1230,11 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::Render
return &mRenderEncoder.restart(desc);
}
// Utilities to quickly create render command enconder to a specific texture:
// The previous content of texture will be loaded if clearColor is not provided
mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(
// Utilities to quickly create render command encoder to a specific texture:
// The previous content of texture will be loaded
mtl::RenderCommandEncoder *ContextMtl::getTextureRenderCommandEncoder(
const mtl::TextureRef &textureTarget,
const gl::ImageIndex &index,
const Optional<MTLClearColor> &clearColor)
const gl::ImageIndex &index)
{
ASSERT(textureTarget && textureTarget->valid());
......@@ -1244,21 +1244,39 @@ mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(
rpDesc.colorAttachments[0].level = index.getLevelIndex();
rpDesc.colorAttachments[0].sliceOrDepth = index.hasLayer() ? index.getLayerIndex() : 0;
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())
{
rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
rpDesc.colorAttachments[0].clearColor =
mtl::EmulatedAlphaClearColor(clearColor.value(), textureTarget->getColorWritableMask());
rpDesc.colorAttachments[0].clearColor = mtl::EmulatedAlphaClearColor(
clearColor.value(), renderTarget.getTexture()->getColorWritableMask());
endEncoding(true);
}
return getRenderCommandEncoder(rpDesc);
return getRenderPassCommandEncoder(rpDesc);
}
// The previous content of texture will be loaded
mtl::RenderCommandEncoder *ContextMtl::getRenderCommandEncoder(const mtl::TextureRef &textureTarget,
const gl::ImageIndex &index)
mtl::RenderCommandEncoder *ContextMtl::getRenderTargetCommandEncoder(
const RenderTargetMtl &renderTarget)
{
return getRenderCommandEncoder(textureTarget, index, Optional<MTLClearColor>());
return getRenderTargetCommandEncoderWithClear(renderTarget, Optional<MTLClearColor>());
}
mtl::BlitCommandEncoder *ContextMtl::getBlitCommandEncoder()
......@@ -1403,25 +1421,33 @@ void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *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();
ASSERT(framebuffer == mtl::GetImpl(glState.getDrawFramebuffer()));
mDirtyBits.set(DIRTY_BIT_DRAW_FRAMEBUFFER);
updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane());
updateFrontFace(glState);
updateScissor(glState);
// End any render encoding using the old render pass.
endEncoding(false);
// Need to re-apply state to RenderCommandEncoder
invalidateState(context);
if (renderPassChanged)
{
// End any render encoding using the old render pass.
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)
......@@ -1798,6 +1824,9 @@ angle::Result ContextMtl::checkIfPipelineChanged(
mRenderPipelineDesc.alphaToCoverageEnabled = mState.isSampleAlphaToCoverageEnabled();
mRenderPipelineDesc.emulateCoverageMask = mState.isSampleCoverageEnabled();
mRenderPipelineDesc.outputDescriptor.updateEnabledDrawBuffers(
mDrawFramebuffer->getState().getEnabledDrawBuffers());
*changedPipelineDesc = mRenderPipelineDesc;
}
......
......@@ -111,6 +111,9 @@ class DisplayMtl : public DisplayImpl
bool supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) const;
bool supportsIOSGPUFamily(uint8_t iOSFamily) const;
bool supportsMacGPUFamily(uint8_t macFamily) const;
bool isAMD() const;
bool isIntel() const;
bool isNVIDIA() const;
id<MTLDevice> getMetalDevice() const { return mMetalDevice; }
......@@ -160,6 +163,7 @@ class DisplayMtl : public DisplayImpl
angle::Result initializeShaderLibrary();
mtl::AutoObjCPtr<id<MTLDevice>> mMetalDevice = nil;
uint32_t mMetalDeviceVendorId = 0;
mtl::CommandQueue mCmdQueue;
......
......@@ -8,6 +8,7 @@
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "gpu_info_util/SystemInfo.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/Surface.h"
......@@ -70,6 +71,8 @@ angle::Result DisplayMtl::initializeImpl(egl::Display *display)
return angle::Result::Stop;
}
mMetalDeviceVendorId = mtl::GetDeviceVendorId(mMetalDevice);
mCmdQueue.set([[mMetalDevice.get() newCommandQueue] ANGLE_MTL_AUTORELEASE]);
mCapsInitialized = false;
......@@ -100,6 +103,8 @@ void DisplayMtl::terminate()
mMetalDevice = nil;
mCapsInitialized = false;
mMetalDeviceVendorId = 0;
if (mGlslangInitialized)
{
GlslangRelease();
......@@ -585,9 +590,9 @@ void DisplayMtl::initializeExtensions() const
mNativeExtensions.mapBufferOES = true;
mNativeExtensions.mapBufferRange = false;
mNativeExtensions.textureStorage = true;
mNativeExtensions.drawBuffers = false;
mNativeExtensions.drawBuffers = true;
mNativeExtensions.fragDepth = true;
mNativeExtensions.framebufferBlit = false;
mNativeExtensions.framebufferBlit = true;
mNativeExtensions.framebufferMultisample = false;
mNativeExtensions.copyTexture = true;
mNativeExtensions.copyCompressedTexture = false;
......@@ -662,7 +667,13 @@ void DisplayMtl::initializeTextureCaps() const
void DisplayMtl::initializeFeatures()
{
bool isMetal2_1 = 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))
{
isMetal2_2 = true;
......@@ -672,6 +683,7 @@ void DisplayMtl::initializeFeatures()
mFeatures.hasBaseVertexInstancedDraw.enabled = true;
mFeatures.hasDepthTextureFiltering.enabled = false;
mFeatures.hasNonUniformDispatch.enabled = true;
mFeatures.hasStencilOutput.enabled = false;
mFeatures.hasTextureSwizzle.enabled = false;
mFeatures.allowSeparatedDepthStencilBuffers.enabled = false;
......@@ -682,6 +694,11 @@ void DisplayMtl::initializeFeatures()
ANGLE_FEATURE_CONDITION((&mFeatures), allowMultisampleStoreAndResolve,
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,
isMetal2_2 && supportsEitherGPUFamily(1, 2));
......@@ -710,11 +727,27 @@ angle::Result DisplayMtl::initializeShaderLibrary()
size_t compiled_shader_binary_len;
#if !defined(NDEBUG)
compiled_shader_binary = compiled_default_metallib_debug;
compiled_shader_binary_len = compiled_default_metallib_debug_len;
if (getFeatures().hasStencilOutput.enabled)
{
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
compiled_shader_binary = compiled_default_metallib;
compiled_shader_binary_len = compiled_default_metallib_len;
if (getFeatures().hasStencilOutput.enabled)
{
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
mDefaultShaders = CreateShaderLibraryFromBinary(getMetalDevice(), compiled_shader_binary,
......@@ -879,4 +912,19 @@ bool DisplayMtl::supportsEitherGPUFamily(uint8_t iOSFamily, uint8_t macFamily) c
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
......@@ -121,6 +121,13 @@ class FramebufferMtl : public FramebufferImpl
private:
void reset();
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,
gl::DrawBufferMask clearColorBuffers,
mtl::ClearRectParams *clearOpts);
......@@ -129,6 +136,15 @@ class FramebufferMtl : public FramebufferImpl
gl::DrawBufferMask clearColorBuffers,
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,
gl::DrawBufferMask clearColorBuffers,
const mtl::ClearRectParams &clearOpts);
......
......@@ -60,8 +60,8 @@ angle::Result RenderbufferMtl::setStorageImpl(const gl::Context *context,
if ((mTexture == nullptr || !mTexture->valid()) && (width != 0 && height != 0))
{
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, static_cast<uint32_t>(width),
static_cast<uint32_t>(height), 1, false, false,
&mTexture));
static_cast<uint32_t>(height), 1, false,
mFormat.hasDepthAndStencilBits(), &mTexture));
mRenderTarget.set(mTexture, 0, 0, mFormat);
......
......@@ -102,6 +102,7 @@ class SurfaceMtl : public SurfaceImpl
int mSamples = 0;
RenderTargetMtl mColorRenderTarget;
RenderTargetMtl mColorManualResolveRenderTarget;
RenderTargetMtl mDepthRenderTarget;
RenderTargetMtl mStencilRenderTarget;
};
......
......@@ -89,17 +89,19 @@ angle::Result CreateTexture(const gl::Context *context,
mtl::TextureRef *textureOut)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
bool allowFormatView = format.hasDepthAndStencilBits();
if (samples > 1)
{
ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, format, width, height, samples,
/** renderTargetOnly */ renderTargetOnly,
/** allowFormatView */ false, textureOut));
/** allowFormatView */ allowFormatView,
textureOut));
}
else
{
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, format, width, height, 1,
/** renderTargetOnly */ renderTargetOnly,
/** allowFormatView */ false, textureOut));
/** allowFormatView */ allowFormatView, textureOut));
}
return angle::Result::Continue;
}
......@@ -291,6 +293,7 @@ void SurfaceMtl::destroy(const egl::Display *display)
mMSColorTexture = nullptr;
mColorRenderTarget.reset();
mColorManualResolveRenderTarget.reset();
mDepthRenderTarget.reset();
mStencilRenderTarget.reset();
}
......@@ -474,7 +477,7 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size))
{
ANGLE_TRY(CreateTexture(context, mDepthFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ true, &mDepthTexture));
/** renderTargetOnly */ false, &mDepthTexture));
mDepthRenderTarget.set(mDepthTexture, 0, 0, mDepthFormat);
}
......@@ -488,7 +491,7 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
else
{
ANGLE_TRY(CreateTexture(context, mStencilFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ true, &mStencilTexture));
/** renderTargetOnly */ false, &mStencilTexture));
}
mStencilRenderTarget.set(mStencilTexture, 0, 0, mStencilFormat);
......@@ -505,11 +508,13 @@ angle::Result SurfaceMtl::resolveColorTextureIfNeeded(const gl::Context *context
// Manually resolve texture
ContextMtl *contextMtl = mtl::GetImpl(context);
mColorManualResolveRenderTarget.set(mColorTexture, 0, 0, mColorFormat);
mtl::RenderCommandEncoder *encoder =
contextMtl->getRenderCommandEncoder(mColorTexture, gl::ImageIndex::Make2D(0));
ANGLE_TRY(
contextMtl->getDisplay()->getUtils().blitWithDraw(context, encoder, mMSColorTexture));
contextMtl->getRenderTargetCommandEncoder(mColorManualResolveRenderTarget);
ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(context, encoder,
mMSColorTexture));
contextMtl->endEncoding(true);
mColorManualResolveRenderTarget.reset();
}
return angle::Result::Continue;
}
......@@ -969,8 +974,9 @@ angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context *
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));
ANGLE_TRY(mtl::InitializeTextureContentsGPU(context, mColorTexture, mColorFormat,
gl::ImageIndex::Make2D(0),
MTLColorWriteMaskAlpha));
// Disable subsequent rendering to alpha channel.
mColorTexture->setColorWritableMask(MTLColorWriteMaskAll & (~MTLColorWriteMaskAlpha));
......
......@@ -333,9 +333,9 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
{
case gl::TextureType::_2D:
layers = 1;
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mFormat, desc.size.width,
desc.size.height, mips, false, true,
&mNativeTexture));
ANGLE_TRY(mtl::Texture::Make2DTexture(
contextMtl, mFormat, desc.size.width, desc.size.height, mips, false,
mFormat.hasDepthAndStencilBits(), &mNativeTexture));
mLayeredRenderTargets.resize(1);
mLayeredRenderTargets[0].set(mNativeTexture, 0, 0, mFormat);
mLayeredTextureViews.resize(1);
......@@ -344,7 +344,8 @@ angle::Result TextureMtl::ensureTextureCreated(const gl::Context *context)
case gl::TextureType::CubeMap:
layers = 6;
ANGLE_TRY(mtl::Texture::MakeCubeTexture(contextMtl, mFormat, desc.size.width, mips,
false, true, &mNativeTexture));
false, mFormat.hasDepthAndStencilBits(),
&mNativeTexture));
mLayeredRenderTargets.resize(gl::kCubeFaceCount);
mLayeredTextureViews.resize(gl::kCubeFaceCount);
for (uint32_t f = 0; f < gl::kCubeFaceCount; ++f)
......@@ -894,7 +895,8 @@ angle::Result TextureMtl::redefineImage(const gl::Context *context,
case gl::TextureType::_2D:
case gl::TextureType::CubeMap:
ANGLE_TRY(mtl::Texture::Make2DTexture(contextMtl, mtlFormat, size.width,
size.height, 1, false, false, &image));
size.height, 1, false,
mFormat.hasDepthAndStencilBits(), &image));
break;
default:
UNREACHABLE();
......@@ -1204,20 +1206,26 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context,
mtl::TextureRef &image = mTexImages[GetImageLayerIndex(index)][index.getLevelIndex()];
ASSERT(image && image->valid());
mtl::RenderCommandEncoder *cmdEncoder =
contextMtl->getRenderCommandEncoder(image, GetImageBaseLevelIndex(image));
mtl::BlitParams blitParams;
RenderTargetMtl writeRtt;
writeRtt.set(image, 0, 0, mFormat);
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.dstColorMask = image->getColorWritableMask();
blitParams.enabledBuffers.set(0);
blitParams.src = colorReadRT->getTexture();
blitParams.srcLevel = static_cast<uint32_t>(colorReadRT->getLevelIndex());
blitParams.srcLevel = colorReadRT->getLevelIndex();
blitParams.srcLayer = colorReadRT->getLayerIndex();
blitParams.srcRect = clippedSourceArea;
blitParams.srcYFlipped = framebufferMtl->flipY();
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,
......@@ -1336,14 +1344,19 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context,
}
mtl::RenderCommandEncoder *cmdEncoder =
contextMtl->getRenderCommandEncoder(image, GetImageBaseLevelIndex(image));
mtl::BlitParams blitParams;
contextMtl->getTextureRenderCommandEncoder(image, GetImageBaseLevelIndex(image));
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.dstColorMask = image->getColorWritableMask();
blitParams.enabledBuffers.set(0);
blitParams.src = sourceTexture;
blitParams.srcLevel = sourceNativeLevel;
blitParams.srcLayer = 0;
blitParams.srcRect = gl::Rectangle(sourceBox.x, sourceBox.y, sourceBox.width, sourceBox.height);
blitParams.srcYFlipped = false;
blitParams.dstLuminance = internalFormat.isLUMA();
......@@ -1351,7 +1364,7 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context,
blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha;
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,
......
......@@ -97,7 +97,7 @@ namespace mtl
// NOTE(hqle): support variable max number of vertex attributes
constexpr uint32_t kMaxVertexAttribs = gl::MAX_VERTEX_ATTRIBS;
// 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);
......
......@@ -158,6 +158,7 @@ class Texture final : public Resource,
uint32_t width(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(const gl::ImageIndex &index) const;
......@@ -171,6 +172,9 @@ class Texture final : public Resource,
// Get linear color space view. Only usable for sRGB textures.
TextureRef getLinearColorView();
// Get stencil view
TextureRef getStencilView();
// Change the wrapped metal object. Special case for swapchain image
void set(id<MTLTexture> metalTexture);
......@@ -206,6 +210,8 @@ class Texture final : public Resource,
// Linear view of sRGB texture
TextureRef mLinearColorView;
TextureRef mStencilView;
};
class Buffer final : public Resource, public WrappedObject<id<MTLBuffer>>
......
......@@ -425,13 +425,18 @@ uint32_t Texture::height(uint32_t level) const
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 re;
re.width = width(level);
re.height = height(level);
re.depth = static_cast<uint32_t>(GetMipSize(get().depth, level));
re.depth = depth(level);
return re;
}
......@@ -472,10 +477,41 @@ TextureRef Texture::getLinearColorView()
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)
{
ParentClass::set(metalTexture);
// Reset stencil view
mStencilView = nullptr;
mLinearColorView = nullptr;
}
......
......@@ -206,6 +206,8 @@ struct RenderPipelineOutputDesc
{
bool operator==(const RenderPipelineOutputDesc &rhs) const;
void updateEnabledDrawBuffers(gl::DrawBufferMask enabledBuffers);
RenderPipelineColorAttachmentDesc colorAttachments[kMaxRenderTargets];
// Use uint16_t instead of MTLPixelFormat to compact space
......
......@@ -618,6 +618,17 @@ bool RenderPipelineOutputDesc::operator==(const RenderPipelineOutputDesc &rhs) c
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::RenderPipelineDesc()
{
......@@ -716,11 +727,10 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat
auto &renderPassColorAttachment = this->colorAttachments[i];
auto texture = renderPassColorAttachment.texture;
// Copy parameters from blend state
outputDescriptor.colorAttachments[i].update(blendState);
if (texture)
{
// Copy parameters from blend state
outputDescriptor.colorAttachments[i].update(blendState);
outputDescriptor.colorAttachments[i].pixelFormat = texture->pixelFormat();
......@@ -731,7 +741,9 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat
}
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,
// - channelsToInit parameter controls which channels will get their content initialized.
angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const TextureRef &texture,
const Format &textureObjFormat,
const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit);
......@@ -54,6 +55,8 @@ MTLScissorRect GetScissorRect(const gl::Rectangle &rect,
NSUInteger screenHeight = 0,
bool flipY = false);
uint32_t GetDeviceVendorId(id<MTLDevice> metalDevice);
AutoObjCPtr<id<MTLLibrary>> CreateShaderLibrary(id<MTLDevice> metalDevice,
const std::string &source,
AutoObjCPtr<NSError *> *error);
......
......@@ -13,8 +13,10 @@
#include <TargetConditionals.h>
#include "common/MemoryBuffer.h"
#include "gpu_info_util/SystemInfo.h"
#include "libANGLE/renderer/metal/ContextMtl.h"
#include "libANGLE/renderer/metal/DisplayMtl.h"
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
#include "libANGLE/renderer/metal/mtl_render_utils.h"
namespace rx
......@@ -22,6 +24,48 @@ namespace rx
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,
const TextureRef &texture,
const Format &textureObjFormat,
......@@ -89,7 +133,8 @@ angle::Result InitializeTextureContents(const gl::Context *context,
}
else
{
ANGLE_TRY(InitializeTextureContentsGPU(context, texture, index, MTLColorWriteMaskAll));
ANGLE_TRY(InitializeTextureContentsGPU(context, texture, textureObjFormat, index,
MTLColorWriteMaskAll));
}
return angle::Result::Continue;
......@@ -97,11 +142,17 @@ angle::Result InitializeTextureContents(const gl::Context *context,
angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const TextureRef &texture,
const Format &textureObjFormat,
const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
// NOTE(hqle): Support layered textures
ASSERT(!index.hasLayer());
// 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
// channels write mask disabled when the texture is created.
......@@ -113,16 +164,18 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
{
// If all channels will be initialized, use clear loadOp.
Optional<MTLClearColor> blackColor = MTLClearColorMake(0, 0, 0, 1);
encoder = contextMtl->getRenderCommandEncoder(texture, index, blackColor);
encoder = contextMtl->getRenderTargetCommandEncoderWithClear(tempRtt, blackColor);
}
else
{
// 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;
clearParams.clearColor = {.alpha = 1};
clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height());
clearParams.clearColor = {.alpha = 1};
clearParams.dstTextureSize = texture->size();
clearParams.enabledBuffers.set(0);
clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height());
ANGLE_TRY(
contextMtl->getDisplay()->getUtils().clearWithDraw(context, encoder, clearParams));
......@@ -193,6 +246,23 @@ MTLScissorRect GetScissorRect(const gl::Rectangle &rect, NSUInteger screenHeight
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,
const std::string &source,
AutoObjCPtr<NSError *> *error)
......
......@@ -834,6 +834,9 @@ TEST_P(BlitFramebufferANGLETest, BlitStencil)
// http://anglebug.com/2205
ANGLE_SKIP_TEST_IF(IsIntel() && IsD3D9());
// http://anglebug.com/4919
ANGLE_SKIP_TEST_IF(IsIntel() && IsMetal());
glBindFramebuffer(GL_FRAMEBUFFER, mUserFBO);
glClearColor(0.0, 1.0, 0.0, 1.0);
......@@ -2006,6 +2009,8 @@ ANGLE_INSTANTIATE_TEST(BlitFramebufferANGLETest,
ES2_OPENGL(),
ES3_OPENGL(),
ES2_VULKAN(),
ES3_VULKAN());
ES3_VULKAN(),
ES2_METAL(),
WithNoShaderStencilOutput(ES2_METAL()));
ANGLE_INSTANTIATE_TEST_ES3(BlitFramebufferTest);
......@@ -209,6 +209,11 @@ std::ostream &operator<<(std::ostream &stream, const PlatformParameters &pp)
stream << "_EmulateCopyTexImage2DFromRenderbuffers";
}
if (pp.eglParameters.shaderStencilOutputFeature == EGL_FALSE)
{
stream << "_NoStencilOutput";
}
return stream;
}
......
......@@ -227,6 +227,13 @@ inline PlatformParameters WithEmulateCopyTexImage2DFromRenderbuffers(
return p;
}
inline PlatformParameters WithNoShaderStencilOutput(const PlatformParameters &params)
{
PlatformParameters re = params;
re.eglParameters.shaderStencilOutputFeature = EGL_FALSE;
return re;
}
inline PlatformParameters WithRobustness(const PlatformParameters &params)
{
PlatformParameters withRobustness = params;
......
......@@ -61,7 +61,7 @@ struct EGLPlatformParameters
return std::tie(renderer, majorVersion, minorVersion, deviceType, presentPath,
debugLayersEnabled, contextVirtualization, transformFeedbackFeature,
allocateNonZeroMemoryFeature, emulateCopyTexImage2DFromRenderbuffers,
platformMethods, robustness);
shaderStencilOutputFeature, platformMethods, robustness);
}
EGLint renderer = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
......@@ -75,6 +75,7 @@ struct EGLPlatformParameters
EGLint transformFeedbackFeature = EGL_DONT_CARE;
EGLint allocateNonZeroMemoryFeature = EGL_DONT_CARE;
EGLint emulateCopyTexImage2DFromRenderbuffers = EGL_DONT_CARE;
EGLint shaderStencilOutputFeature = EGL_DONT_CARE;
angle::PlatformMethods *platformMethods = nullptr;
};
......
......@@ -196,6 +196,11 @@ bool EGLWindow::initializeDisplay(OSWindow *osWindow,
enabledFeatureOverrides.push_back("emulate_copyteximage2d_from_renderbuffers");
}
if (params.shaderStencilOutputFeature == EGL_FALSE)
{
disabledFeatureOverrides.push_back("has_shader_stencil_output");
}
if (!disabledFeatureOverrides.empty())
{
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