Commit 9bc86c50 by Alexey Knyazev Committed by Commit Bot

Metal: Implement OES_draw_buffers_indexed

Bug: angleproject:2634 Bug: angleproject:4394 Change-Id: Id6e6c6bdea2b1ff3d974e92e067ed63e1b4e4582 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2465919 Commit-Queue: Alexey Knyazev <lexa.knyazev@gmail.com> Reviewed-by: 's avatarLe Hoang Quyen <le.hoang.q@gmail.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 8b1d1fb6
......@@ -294,7 +294,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value);
const mtl::ClearColorValue &getClearColorValue() const;
MTLColorWriteMask getColorMask() const;
const mtl::WriteMaskArray &getWriteMaskArray() const;
float getClearDepthValue() const;
uint32_t getClearStencilValue() const;
// Return front facing stencil write mask
......@@ -420,6 +420,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
float nearPlane,
float farPlane);
void updateDepthRange(float nearPlane, float farPlane);
void updateBlendDescArray(const gl::BlendStateExt &blendStateExt);
void updateScissor(const gl::State &glState);
void updateCullMode(const gl::State &glState);
void updateFrontFace(const gl::State &glState);
......@@ -522,7 +523,8 @@ class ContextMtl : public ContextImpl, public mtl::Context
// State
mtl::RenderPipelineDesc mRenderPipelineDesc;
mtl::DepthStencilDesc mDepthStencilDesc;
mtl::BlendDesc mBlendDesc;
mtl::BlendDescArray mBlendDescArray;
mtl::WriteMaskArray mWriteMaskArray;
mtl::ClearColorValue mClearColor;
uint32_t mClearStencil = 0;
uint32_t mStencilRefFront = 0;
......
......@@ -198,7 +198,13 @@ ContextMtl::~ContextMtl() {}
angle::Result ContextMtl::initialize()
{
mBlendDesc.reset();
for (mtl::BlendDesc &blendDesc : mBlendDescArray)
{
blendDesc.reset();
}
mWriteMaskArray.fill(MTLColorWriteMaskAll);
mDepthStencilDesc.reset();
mTriFanIndexBuffer.initialize(this, 0, mtl::kIndexBufferOffsetAlignment,
......@@ -832,7 +838,20 @@ angle::Result ContextMtl::syncState(const gl::Context *context,
// Initialize incomplete texture set.
ANGLE_TRY(ensureIncompleteTexturesCreated(context));
for (size_t dirtyBit : dirtyBits)
// Metal's blend state is set at once, while ANGLE tracks separate dirty
// bits: ENABLED, FUNCS, and EQUATIONS. Merge all three of them to the first one.
constexpr gl::State::DirtyBits checkBlendBitsMask(
angle::Bit<gl::State::DirtyBits::value_type>(gl::State::DIRTY_BIT_BLEND_ENABLED) |
angle::Bit<gl::State::DirtyBits::value_type>(gl::State::DIRTY_BIT_BLEND_FUNCS) |
angle::Bit<gl::State::DirtyBits::value_type>(gl::State::DIRTY_BIT_BLEND_EQUATIONS));
constexpr gl::State::DirtyBits resetBlendBitsMask(
angle::Bit<gl::State::DirtyBits::value_type>(gl::State::DIRTY_BIT_BLEND_FUNCS) |
angle::Bit<gl::State::DirtyBits::value_type>(gl::State::DIRTY_BIT_BLEND_EQUATIONS));
gl::State::DirtyBits mergedDirtyBits = gl::State::DirtyBits(dirtyBits) & ~resetBlendBitsMask;
mergedDirtyBits.set(gl::State::DIRTY_BIT_BLEND_ENABLED, (dirtyBits & checkBlendBitsMask).any());
for (size_t dirtyBit : mergedDirtyBits)
{
switch (dirtyBit)
{
......@@ -856,21 +875,19 @@ angle::Result ContextMtl::syncState(const gl::Context *context,
mDirtyBits.set(DIRTY_BIT_BLEND_COLOR);
break;
case gl::State::DIRTY_BIT_BLEND_ENABLED:
mBlendDesc.updateBlendEnabled(glState.getBlendState());
invalidateRenderPipeline();
break;
case gl::State::DIRTY_BIT_BLEND_FUNCS:
mBlendDesc.updateBlendFactors(glState.getBlendState());
invalidateRenderPipeline();
break;
case gl::State::DIRTY_BIT_BLEND_EQUATIONS:
mBlendDesc.updateBlendOps(glState.getBlendState());
invalidateRenderPipeline();
updateBlendDescArray(glState.getBlendStateExt());
break;
case gl::State::DIRTY_BIT_COLOR_MASK:
mBlendDesc.updateWriteMask(glState.getBlendState());
{
const gl::BlendStateExt &blendStateExt = glState.getBlendStateExt();
for (size_t i = 0; i < mBlendDescArray.size(); i++)
{
mBlendDescArray[i].updateWriteMask(blendStateExt.getColorMaskIndexed(i));
mWriteMaskArray[i] = mBlendDescArray[i].writeMask;
}
invalidateRenderPipeline();
break;
}
case gl::State::DIRTY_BIT_SAMPLE_ALPHA_TO_COVERAGE_ENABLED:
invalidateRenderPipeline();
break;
......@@ -1299,9 +1316,9 @@ const mtl::ClearColorValue &ContextMtl::getClearColorValue() const
{
return mClearColor;
}
MTLColorWriteMask ContextMtl::getColorMask() const
const mtl::WriteMaskArray &ContextMtl::getWriteMaskArray() const
{
return mBlendDesc.writeMask;
return mWriteMaskArray;
}
float ContextMtl::getClearDepthValue() const
{
......@@ -1567,6 +1584,37 @@ void ContextMtl::updateDepthRange(float nearPlane, float farPlane)
invalidateDriverUniforms();
}
void ContextMtl::updateBlendDescArray(const gl::BlendStateExt &blendStateExt)
{
for (size_t i = 0; i < mBlendDescArray.size(); i++)
{
mtl::BlendDesc &blendDesc = mBlendDescArray[i];
if (blendStateExt.mEnabledMask.test(i))
{
blendDesc.blendingEnabled = true;
blendDesc.sourceRGBBlendFactor =
mtl::GetBlendFactor(blendStateExt.getSrcColorIndexed(i));
blendDesc.sourceAlphaBlendFactor =
mtl::GetBlendFactor(blendStateExt.getSrcAlphaIndexed(i));
blendDesc.destinationRGBBlendFactor =
mtl::GetBlendFactor(blendStateExt.getDstColorIndexed(i));
blendDesc.destinationAlphaBlendFactor =
mtl::GetBlendFactor(blendStateExt.getDstAlphaIndexed(i));
blendDesc.rgbBlendOperation = mtl::GetBlendOp(blendStateExt.getEquationColorIndexed(i));
blendDesc.alphaBlendOperation =
mtl::GetBlendOp(blendStateExt.getEquationAlphaIndexed(i));
}
else
{
// Enforce default state when blending is disabled,
blendDesc.reset(blendDesc.writeMask);
}
}
invalidateRenderPipeline();
}
void ContextMtl::updateScissor(const gl::State &glState)
{
FramebufferMtl *framebufferMtl = mtl::GetImpl(glState.getDrawFramebuffer());
......@@ -2209,7 +2257,7 @@ angle::Result ContextMtl::checkIfPipelineChanged(const gl::Context *context,
{
const mtl::RenderPassDesc &renderPassDesc = mRenderEncoder.renderPassDesc();
// Obtain RenderPipelineDesc's output descriptor.
renderPassDesc.populateRenderPipelineOutputDesc(mBlendDesc,
renderPassDesc.populateRenderPipelineOutputDesc(mBlendDescArray,
&mRenderPipelineDesc.outputDescriptor);
if (xfbPass)
......
......@@ -626,6 +626,8 @@ void DisplayMtl::initializeExtensions() const
mNativeExtensions.mapBufferRange = true;
mNativeExtensions.textureStorage = true;
mNativeExtensions.drawBuffers = true;
mNativeExtensions.drawBuffersIndexedEXT = true;
mNativeExtensions.drawBuffersIndexedOES = true;
mNativeExtensions.fragDepth = true;
mNativeExtensions.framebufferBlitANGLE = true;
mNativeExtensions.framebufferMultisample = true;
......
......@@ -456,10 +456,10 @@ angle::Result FramebufferMtl::blitWithDraw(const gl::Context *context,
colorBlitParams.srcLevel = srcColorRt->getLevelIndex();
colorBlitParams.srcLayer = srcColorRt->getLayerIndex();
colorBlitParams.blitColorMask = contextMtl->getColorMask();
colorBlitParams.enabledBuffers = getState().getEnabledDrawBuffers();
colorBlitParams.filter = filter;
colorBlitParams.dstLuminance = srcColorRt->getFormat()->actualAngleFormat().isLUMA();
colorBlitParams.blitWriteMaskArray = contextMtl->getWriteMaskArray();
colorBlitParams.enabledBuffers = getState().getEnabledDrawBuffers();
colorBlitParams.filter = filter;
colorBlitParams.dstLuminance = srcColorRt->getFormat()->actualAngleFormat().isLUMA();
ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(
context, renderEncoder, srcColorRt->getFormat()->actualAngleFormat(), colorBlitParams));
......@@ -1042,6 +1042,8 @@ angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context,
continue;
}
overrideClearOps.clearWriteMaskArray[0] = overrideClearOps.clearWriteMaskArray[drawbuffer];
mtl::RenderCommandEncoder *encoder =
contextMtl->getRenderTargetCommandEncoder(*renderTarget);
ANGLE_TRY(display->getUtils().clearWithDraw(context, encoder, overrideClearOps));
......@@ -1078,8 +1080,8 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
return angle::Result::Continue;
}
clearOpts.clearColorMask = contextMtl->getColorMask();
uint32_t stencilMask = contextMtl->getStencilMask();
clearOpts.clearWriteMaskArray = contextMtl->getWriteMaskArray();
uint32_t stencilMask = contextMtl->getStencilMask();
if (!contextMtl->getDepthMask())
{
// Disable depth clearing, since depth write is disable
......@@ -1089,8 +1091,18 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
// Only clear enabled buffers
clearOpts.enabledBuffers = clearColorBuffers;
bool allBuffersUnmasked = true;
for (size_t enabledBuffer : clearColorBuffers)
{
if (clearOpts.clearWriteMaskArray[enabledBuffer] != MTLColorWriteMaskAll)
{
allBuffersUnmasked = false;
break;
}
}
if (clearOpts.clearArea == renderArea &&
(!clearOpts.clearColor.valid() || clearOpts.clearColorMask == MTLColorWriteMaskAll) &&
(!clearOpts.clearColor.valid() || allBuffersUnmasked) &&
(!clearOpts.clearStencil.valid() ||
(stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll))
{
......
......@@ -32,11 +32,13 @@ namespace mtl
struct ClearRectParams
{
ClearRectParams() { clearWriteMaskArray.fill(MTLColorWriteMaskAll); }
Optional<ClearColorValue> clearColor;
Optional<float> clearDepth;
Optional<uint32_t> clearStencil;
MTLColorWriteMask clearColorMask = MTLColorWriteMaskAll;
WriteMaskArray clearWriteMaskArray;
const mtl::Format *colorFormat = nullptr;
gl::Extents dstTextureSize;
......@@ -78,7 +80,9 @@ struct BlitParams
struct ColorBlitParams : public BlitParams
{
MTLColorWriteMask blitColorMask = MTLColorWriteMaskAll;
ColorBlitParams() { blitWriteMaskArray.fill(MTLColorWriteMaskAll); }
WriteMaskArray blitWriteMaskArray;
gl::DrawBufferMask enabledBuffers;
GLenum filter = GL_NEAREST;
bool unpackPremultiplyAlpha = false;
......
......@@ -1211,16 +1211,16 @@ id<MTLRenderPipelineState> ClearUtils::getClearRenderPipelineState(const gl::Con
{
ContextMtl *contextMtl = GetImpl(context);
// The color mask to be applied to every color attachment:
MTLColorWriteMask globalColorMask = params.clearColorMask;
WriteMaskArray clearWriteMaskArray = params.clearWriteMaskArray;
if (!params.clearColor.valid())
{
globalColorMask = MTLColorWriteMaskNone;
clearWriteMaskArray.fill(MTLColorWriteMaskNone);
}
RenderPipelineDesc pipelineDesc;
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
renderPassDesc.populateRenderPipelineOutputDesc(globalColorMask,
renderPassDesc.populateRenderPipelineOutputDesc(clearWriteMaskArray,
&pipelineDesc.outputDescriptor);
// Disable clear for some outputs that are not enabled
......@@ -1404,7 +1404,7 @@ id<MTLRenderPipelineState> ColorBlitUtils::getColorBlitRenderPipelineState(
RenderPipelineDesc pipelineDesc;
const RenderPassDesc &renderPassDesc = cmdEncoder->renderPassDesc();
renderPassDesc.populateRenderPipelineOutputDesc(params.blitColorMask,
renderPassDesc.populateRenderPipelineOutputDesc(params.blitWriteMaskArray,
&pipelineDesc.outputDescriptor);
// Disable blit for some outputs that are not enabled
......
......@@ -163,10 +163,7 @@ struct BlendDesc
void reset();
void reset(MTLColorWriteMask writeMask);
void updateWriteMask(const gl::BlendState &blendState);
void updateBlendFactors(const gl::BlendState &blendState);
void updateBlendOps(const gl::BlendState &blendState);
void updateBlendEnabled(const gl::BlendState &blendState);
void updateWriteMask(const uint8_t angleMask);
// Use uint8_t instead of MTLColorWriteMask to compact space
uint8_t writeMask : 4;
......@@ -185,6 +182,9 @@ struct BlendDesc
bool blendingEnabled : 1;
};
using BlendDescArray = std::array<BlendDesc, kMaxRenderTargets>;
using WriteMaskArray = std::array<uint8_t, kMaxRenderTargets>;
struct alignas(2) RenderPipelineColorAttachmentDesc : public BlendDesc
{
bool operator==(const RenderPipelineColorAttachmentDesc &rhs) const;
......@@ -197,9 +197,9 @@ struct alignas(2) RenderPipelineColorAttachmentDesc : public BlendDesc
void reset();
void reset(MTLPixelFormat format);
void reset(MTLPixelFormat format, MTLColorWriteMask writeMask);
void reset(MTLPixelFormat format, const BlendDesc &blendState);
void reset(MTLPixelFormat format, const BlendDesc &blendDesc);
void update(const BlendDesc &blendState);
void update(const BlendDesc &blendDesc);
// Use uint16_t instead of MTLPixelFormat to compact space
uint16_t pixelFormat : 16;
......@@ -367,10 +367,10 @@ struct RenderPassDesc
void populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const;
// This will populate the RenderPipelineOutputDesc with default blend state and the specified
// MTLColorWriteMask
void populateRenderPipelineOutputDesc(MTLColorWriteMask colorWriteMask,
void populateRenderPipelineOutputDesc(const WriteMaskArray &writeMaskArray,
RenderPipelineOutputDesc *outDesc) const;
// This will populate the RenderPipelineOutputDesc with the specified blend state
void populateRenderPipelineOutputDesc(const BlendDesc &blendState,
void populateRenderPipelineOutputDesc(const BlendDescArray &blendDescArray,
RenderPipelineOutputDesc *outDesc) const;
bool equalIgnoreLoadStoreOptions(const RenderPassDesc &other) const;
......
......@@ -535,44 +535,33 @@ void BlendDesc::reset(MTLColorWriteMask _writeMask)
sourceAlphaBlendFactor = sourceRGBBlendFactor = MTLBlendFactorOne;
}
void BlendDesc::updateWriteMask(const gl::BlendState &blendState)
{
writeMask = MTLColorWriteMaskNone;
if (blendState.colorMaskRed)
{
writeMask |= MTLColorWriteMaskRed;
}
if (blendState.colorMaskGreen)
{
writeMask |= MTLColorWriteMaskGreen;
}
if (blendState.colorMaskBlue)
{
writeMask |= MTLColorWriteMaskBlue;
}
if (blendState.colorMaskAlpha)
{
writeMask |= MTLColorWriteMaskAlpha;
}
}
void BlendDesc::updateBlendFactors(const gl::BlendState &blendState)
{
sourceRGBBlendFactor = GetBlendFactor(blendState.sourceBlendRGB);
sourceAlphaBlendFactor = GetBlendFactor(blendState.sourceBlendAlpha);
destinationRGBBlendFactor = GetBlendFactor(blendState.destBlendRGB);
destinationAlphaBlendFactor = GetBlendFactor(blendState.destBlendAlpha);
}
void BlendDesc::updateBlendOps(const gl::BlendState &blendState)
{
rgbBlendOperation = GetBlendOp(blendState.blendEquationRGB);
alphaBlendOperation = GetBlendOp(blendState.blendEquationAlpha);
}
void BlendDesc::updateBlendEnabled(const gl::BlendState &blendState)
{
blendingEnabled = blendState.blend;
void BlendDesc::updateWriteMask(const uint8_t angleMask)
{
ASSERT(angleMask == (angleMask & 0xF));
// ANGLE's packed color mask is abgr (matches Vulkan & D3D11), while Metal expects rgba.
#if defined(__aarch64__)
// ARM64 can reverse bits in a single instruction
writeMask = __builtin_bitreverse8(angleMask) >> 4;
#else
/* On other architectures, Clang generates a polyfill that uses more
instructions than the following expression optimized for a 4-bit value.
(abgr * 0x41) & 0x14A:
.......abgr +
.abgr...... &
00101001010 =
..b.r..a.g.
(b.r..a.g.) * 0x111:
b.r..a.g. +
b.r..a.g..... +
b.r..a.g......... =
b.r.bargbarg.a.g.
^^^^
*/
writeMask = ((((angleMask * 0x41) & 0x14A) * 0x111) >> 7) & 0xF;
#endif
}
// RenderPipelineColorAttachmentDesc implementation
......@@ -603,16 +592,16 @@ void RenderPipelineColorAttachmentDesc::reset(MTLPixelFormat format, MTLColorWri
BlendDesc::reset(_writeMask);
}
void RenderPipelineColorAttachmentDesc::reset(MTLPixelFormat format, const BlendDesc &blendState)
void RenderPipelineColorAttachmentDesc::reset(MTLPixelFormat format, const BlendDesc &blendDesc)
{
this->pixelFormat = format;
BlendDesc::operator=(blendState);
BlendDesc::operator=(blendDesc);
}
void RenderPipelineColorAttachmentDesc::update(const BlendDesc &blendState)
void RenderPipelineColorAttachmentDesc::update(const BlendDesc &blendDesc)
{
BlendDesc::operator=(blendState);
BlendDesc::operator=(blendDesc);
}
// RenderPipelineOutputDesc implementation
......@@ -726,20 +715,24 @@ bool RenderPassAttachmentDesc::operator==(const RenderPassAttachmentDesc &other)
void RenderPassDesc::populateRenderPipelineOutputDesc(RenderPipelineOutputDesc *outDesc) const
{
populateRenderPipelineOutputDesc(MTLColorWriteMaskAll, outDesc);
WriteMaskArray writeMaskArray;
writeMaskArray.fill(MTLColorWriteMaskAll);
populateRenderPipelineOutputDesc(writeMaskArray, outDesc);
}
void RenderPassDesc::populateRenderPipelineOutputDesc(MTLColorWriteMask colorWriteMask,
void RenderPassDesc::populateRenderPipelineOutputDesc(const WriteMaskArray &writeMaskArray,
RenderPipelineOutputDesc *outDesc) const
{
// Default blend state.
BlendDesc blendState;
blendState.reset(colorWriteMask);
populateRenderPipelineOutputDesc(blendState, outDesc);
// Default blend state with replaced color write masks.
BlendDescArray blendDescArray;
for (size_t i = 0; i < blendDescArray.size(); i++)
{
blendDescArray[i].reset(writeMaskArray[i]);
}
populateRenderPipelineOutputDesc(blendDescArray, outDesc);
}
void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendState,
void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDescArray &blendDescArray,
RenderPipelineOutputDesc *outDesc) const
{
RenderPipelineOutputDesc &outputDescriptor = *outDesc;
......@@ -752,16 +745,20 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat
if (texture)
{
// Copy parameters from blend state
outputDescriptor.colorAttachments[i].update(blendState);
if (!renderPassColorAttachment.blendable)
if (renderPassColorAttachment.blendable)
{
// Copy parameters from blend state
outputDescriptor.colorAttachments[i].reset(texture->pixelFormat(),
blendDescArray[i]);
}
else
{
// Disable blending if the attachment's render target doesn't support blending.
outputDescriptor.colorAttachments[i].blendingEnabled = false;
// Force default blending state to reduce the number of unique states.
outputDescriptor.colorAttachments[i].reset(texture->pixelFormat(),
blendDescArray[i].writeMask);
}
outputDescriptor.colorAttachments[i].pixelFormat = texture->pixelFormat();
// Combine the masks. This is useful when the texture is not supposed to have alpha
// channel such as GL_RGB8, however, Metal doesn't natively support 24 bit RGB, so
// we need to use RGBA texture, and then disable alpha write to this texture
......
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