Commit 80d4901a by Le Hoang Quyen Committed by Commit Bot

Metal: Support integer textures.

Bug: angleproject:2634 Bug: angleproject:5154 Change-Id: Iffea26fe2c683557b4fa7c13fddf3523294b47d4 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2433329 Commit-Queue: Le Hoang Quyen <le.hoang.q@gmail.com> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 96714af8
...@@ -297,7 +297,7 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -297,7 +297,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
void queueEventSignal(const mtl::SharedEventRef &event, uint64_t value); void queueEventSignal(const mtl::SharedEventRef &event, uint64_t value);
void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value); void serverWaitEvent(const mtl::SharedEventRef &event, uint64_t value);
const MTLClearColor &getClearColorValue() const; const mtl::ClearColorValue &getClearColorValue() const;
MTLColorWriteMask getColorMask() const; MTLColorWriteMask getColorMask() const;
float getClearDepthValue() const; float getClearDepthValue() const;
uint32_t getClearStencilValue() const; uint32_t getClearStencilValue() const;
...@@ -529,7 +529,7 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -529,7 +529,7 @@ class ContextMtl : public ContextImpl, public mtl::Context
mtl::RenderPipelineDesc mRenderPipelineDesc; mtl::RenderPipelineDesc mRenderPipelineDesc;
mtl::DepthStencilDesc mDepthStencilDesc; mtl::DepthStencilDesc mDepthStencilDesc;
mtl::BlendDesc mBlendDesc; mtl::BlendDesc mBlendDesc;
MTLClearColor mClearColor; mtl::ClearColorValue mClearColor;
uint32_t mClearStencil = 0; uint32_t mClearStencil = 0;
uint32_t mStencilRefFront = 0; uint32_t mStencilRefFront = 0;
uint32_t mStencilRefBack = 0; uint32_t mStencilRefBack = 0;
......
...@@ -780,10 +780,9 @@ angle::Result ContextMtl::syncState(const gl::Context *context, ...@@ -780,10 +780,9 @@ angle::Result ContextMtl::syncState(const gl::Context *context,
// NOTE(hqle): ES 3.0 feature. // NOTE(hqle): ES 3.0 feature.
break; break;
case gl::State::DIRTY_BIT_CLEAR_COLOR: case gl::State::DIRTY_BIT_CLEAR_COLOR:
mClearColor.red = glState.getColorClearValue().red; mClearColor = mtl::ClearColorValue(
mClearColor.green = glState.getColorClearValue().green; glState.getColorClearValue().red, glState.getColorClearValue().green,
mClearColor.blue = glState.getColorClearValue().blue; glState.getColorClearValue().blue, glState.getColorClearValue().alpha);
mClearColor.alpha = glState.getColorClearValue().alpha;
break; break;
case gl::State::DIRTY_BIT_CLEAR_DEPTH: case gl::State::DIRTY_BIT_CLEAR_DEPTH:
break; break;
...@@ -1123,7 +1122,7 @@ void ContextMtl::invalidateRenderPipeline() ...@@ -1123,7 +1122,7 @@ void ContextMtl::invalidateRenderPipeline()
mDirtyBits.set(DIRTY_BIT_RENDER_PIPELINE); mDirtyBits.set(DIRTY_BIT_RENDER_PIPELINE);
} }
const MTLClearColor &ContextMtl::getClearColorValue() const const mtl::ClearColorValue &ContextMtl::getClearColorValue() const
{ {
return mClearColor; return mClearColor;
} }
......
...@@ -120,6 +120,7 @@ class FramebufferMtl : public FramebufferImpl ...@@ -120,6 +120,7 @@ class FramebufferMtl : public FramebufferImpl
private: private:
void reset(); void reset();
bool checkPackedDepthStencilAttachment() const;
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, angle::Result blitWithDraw(const gl::Context *context,
FramebufferMtl *srcFrameBuffer, FramebufferMtl *srcFrameBuffer,
...@@ -161,10 +162,6 @@ class FramebufferMtl : public FramebufferImpl ...@@ -161,10 +162,6 @@ class FramebufferMtl : public FramebufferImpl
mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context, mtl::RenderCommandEncoder *ensureRenderPassStarted(const gl::Context *context,
const mtl::RenderPassDesc &desc); const mtl::RenderPassDesc &desc);
void overrideClearColor(const mtl::TextureRef &texture,
MTLClearColor clearColor,
MTLClearColor *colorOut);
angle::Result updateColorRenderTarget(const gl::Context *context, size_t colorIndexGL); angle::Result updateColorRenderTarget(const gl::Context *context, size_t colorIndexGL);
angle::Result updateDepthRenderTarget(const gl::Context *context); angle::Result updateDepthRenderTarget(const gl::Context *context);
angle::Result updateStencilRenderTarget(const gl::Context *context); angle::Result updateStencilRenderTarget(const gl::Context *context);
...@@ -185,6 +182,9 @@ class FramebufferMtl : public FramebufferImpl ...@@ -185,6 +182,9 @@ class FramebufferMtl : public FramebufferImpl
RenderTargetMtl *mStencilRenderTarget = nullptr; RenderTargetMtl *mStencilRenderTarget = nullptr;
mtl::RenderPassDesc mRenderPassDesc; mtl::RenderPassDesc mRenderPassDesc;
const mtl::Format *mRenderPassFirstColorAttachmentFormat = nullptr;
bool mRenderPassAttachmentsSameColorType = false;
// Flag indicating the render pass start is a clean start or a resume from interruption such // Flag indicating the render pass start is a clean start or a resume from interruption such
// as by a compute pass. // as by a compute pass.
bool mRenderPassCleanStart = false; bool mRenderPassCleanStart = false;
......
...@@ -23,6 +23,18 @@ ...@@ -23,6 +23,18 @@
namespace rx namespace rx
{ {
namespace
{
// Override clear color based on texture's write mask
void OverrideMTLClearColor(const mtl::TextureRef &texture,
const mtl::ClearColorValue &clearColor,
MTLClearColor *colorOut)
{
*colorOut =
mtl::EmulatedAlphaClearColor(clearColor.toMTLClearColor(), texture->getColorWritableMask());
}
}
// FramebufferMtl implementation // FramebufferMtl implementation
FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state, FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state,
bool flipY, bool flipY,
...@@ -41,6 +53,8 @@ void FramebufferMtl::reset() ...@@ -41,6 +53,8 @@ void FramebufferMtl::reset()
rt = nullptr; rt = nullptr;
} }
mDepthRenderTarget = mStencilRenderTarget = nullptr; mDepthRenderTarget = mStencilRenderTarget = nullptr;
mRenderPassFirstColorAttachmentFormat = nullptr;
} }
void FramebufferMtl::destroy(const gl::Context *context) void FramebufferMtl::destroy(const gl::Context *context)
...@@ -67,9 +81,11 @@ angle::Result FramebufferMtl::invalidateSub(const gl::Context *context, ...@@ -67,9 +81,11 @@ angle::Result FramebufferMtl::invalidateSub(const gl::Context *context,
const GLenum *attachments, const GLenum *attachments,
const gl::Rectangle &area) const gl::Rectangle &area)
{ {
// NOTE(hqle): ES 3.0 feature. if (area.encloses(getCompleteRenderArea()))
UNIMPLEMENTED(); {
return angle::Result::Stop; return invalidateImpl(mtl::GetImpl(context), count, attachments);
}
return angle::Result::Continue;
} }
angle::Result FramebufferMtl::clear(const gl::Context *context, GLbitfield mask) angle::Result FramebufferMtl::clear(const gl::Context *context, GLbitfield mask)
...@@ -105,27 +121,53 @@ angle::Result FramebufferMtl::clearBufferfv(const gl::Context *context, ...@@ -105,27 +121,53 @@ angle::Result FramebufferMtl::clearBufferfv(const gl::Context *context,
GLint drawbuffer, GLint drawbuffer,
const GLfloat *values) const GLfloat *values)
{ {
// NOTE(hqle): ES 3.0 feature. mtl::ClearRectParams clearOpts;
UNIMPLEMENTED();
return angle::Result::Stop; gl::DrawBufferMask clearColorBuffers;
if (buffer == GL_DEPTH)
{
clearOpts.clearDepth = values[0];
}
else
{
clearColorBuffers.set(drawbuffer);
clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
}
return clearImpl(context, clearColorBuffers, &clearOpts);
} }
angle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context, angle::Result FramebufferMtl::clearBufferuiv(const gl::Context *context,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLuint *values) const GLuint *values)
{ {
// NOTE(hqle): ES 3.0 feature. gl::DrawBufferMask clearColorBuffers;
UNIMPLEMENTED(); clearColorBuffers.set(drawbuffer);
return angle::Result::Stop;
mtl::ClearRectParams clearOpts;
clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
return clearImpl(context, clearColorBuffers, &clearOpts);
} }
angle::Result FramebufferMtl::clearBufferiv(const gl::Context *context, angle::Result FramebufferMtl::clearBufferiv(const gl::Context *context,
GLenum buffer, GLenum buffer,
GLint drawbuffer, GLint drawbuffer,
const GLint *values) const GLint *values)
{ {
// NOTE(hqle): ES 3.0 feature. mtl::ClearRectParams clearOpts;
UNIMPLEMENTED();
return angle::Result::Stop; gl::DrawBufferMask clearColorBuffers;
if (buffer == GL_STENCIL)
{
clearOpts.clearStencil = values[0] & mtl::kStencilMaskAll;
}
else
{
clearColorBuffers.set(drawbuffer);
clearOpts.clearColor = mtl::ClearColorValue(values[0], values[1], values[2], values[3]);
}
return clearImpl(context, clearColorBuffers, &clearOpts);
} }
angle::Result FramebufferMtl::clearBufferfi(const gl::Context *context, angle::Result FramebufferMtl::clearBufferfi(const gl::Context *context,
GLenum buffer, GLenum buffer,
...@@ -133,9 +175,11 @@ angle::Result FramebufferMtl::clearBufferfi(const gl::Context *context, ...@@ -133,9 +175,11 @@ angle::Result FramebufferMtl::clearBufferfi(const gl::Context *context,
GLfloat depth, GLfloat depth,
GLint stencil) GLint stencil)
{ {
// NOTE(hqle): ES 3.0 feature. mtl::ClearRectParams clearOpts;
UNIMPLEMENTED(); clearOpts.clearDepth = depth;
return angle::Result::Stop; clearOpts.clearStencil = stencil & mtl::kStencilMaskAll;
return clearImpl(context, gl::DrawBufferMask(), &clearOpts);
} }
const gl::InternalFormat &FramebufferMtl::getImplementationColorReadFormat( const gl::InternalFormat &FramebufferMtl::getImplementationColorReadFormat(
...@@ -188,6 +232,13 @@ angle::Result FramebufferMtl::readPixels(const gl::Context *context, ...@@ -188,6 +232,13 @@ angle::Result FramebufferMtl::readPixels(const gl::Context *context,
PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOrder, packBuffer, PackPixelsParams params(flippedArea, angleFormat, outputPitch, pack.reverseRowOrder, packBuffer,
0); 0);
if (params.packBuffer)
{
// If PBO is active, pixels is treated as offset.
params.offset = reinterpret_cast<ptrdiff_t>(pixels);
}
if (mFlipY) if (mFlipY)
{ {
params.reverseRowOrder = !params.reverseRowOrder; params.reverseRowOrder = !params.reverseRowOrder;
...@@ -410,8 +461,8 @@ angle::Result FramebufferMtl::blitWithDraw(const gl::Context *context, ...@@ -410,8 +461,8 @@ angle::Result FramebufferMtl::blitWithDraw(const gl::Context *context,
colorBlitParams.filter = filter; colorBlitParams.filter = filter;
colorBlitParams.dstLuminance = srcColorRt->getFormat()->actualAngleFormat().isLUMA(); colorBlitParams.dstLuminance = srcColorRt->getFormat()->actualAngleFormat().isLUMA();
ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(context, renderEncoder, ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(
colorBlitParams)); context, renderEncoder, srcColorRt->getFormat()->actualAngleFormat(), colorBlitParams));
} }
return angle::Result::Continue; return angle::Result::Continue;
...@@ -431,19 +482,50 @@ bool FramebufferMtl::checkStatus(const gl::Context *context) const ...@@ -431,19 +482,50 @@ bool FramebufferMtl::checkStatus(const gl::Context *context) const
return false; return false;
} }
if (mState.getDepthAttachment() && mState.getDepthAttachment()->getFormat().info->depthBits &&
mState.getDepthAttachment()->getFormat().info->stencilBits)
{
return checkPackedDepthStencilAttachment();
}
if (mState.getStencilAttachment() && if (mState.getStencilAttachment() &&
mState.getStencilAttachment()->getFormat().info->depthBits && mState.getStencilAttachment()->getFormat().info->depthBits &&
mState.getStencilAttachment()->getFormat().info->stencilBits && mState.getStencilAttachment()->getFormat().info->stencilBits)
mState.hasSeparateDepthAndStencilAttachments())
{ {
// If stencil attachment has depth & stencil bits, it must refer to the same texture return checkPackedDepthStencilAttachment();
// as depth attachment.
return false;
} }
return true; return true;
} }
bool FramebufferMtl::checkPackedDepthStencilAttachment() const
{
if (ANGLE_APPLE_AVAILABLE_XCI(10.14, 13.0, 12.0))
{
// If depth/stencil attachment has depth & stencil bits, then depth & stencil must not have
// separate attachment. i.e. They must be the same texture or one of them has no
// attachment.
if (mState.hasSeparateDepthAndStencilAttachments())
{
WARN() << "Packed depth stencil texture/buffer must not be mixed with other "
"texture/buffer.";
return false;
}
}
else
{
// Metal 2.0 and below doesn't allow packed depth stencil texture to be attached only as
// depth or stencil buffer. i.e. None of the depth & stencil attachment can be null.
if (!mState.getDepthStencilAttachment())
{
WARN() << "Packed depth stencil texture/buffer must be bound to both depth & stencil "
"attachment point.";
return false;
}
}
return true;
}
angle::Result FramebufferMtl::syncState(const gl::Context *context, angle::Result FramebufferMtl::syncState(const gl::Context *context,
GLenum binding, GLenum binding,
const gl::Framebuffer::DirtyBits &dirtyBits, const gl::Framebuffer::DirtyBits &dirtyBits,
...@@ -735,6 +817,8 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, ...@@ -735,6 +817,8 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
{ {
mtl::RenderPassDesc &desc = *pDescOut; mtl::RenderPassDesc &desc = *pDescOut;
mRenderPassFirstColorAttachmentFormat = nullptr;
mRenderPassAttachmentsSameColorType = true;
uint32_t maxColorAttachments = static_cast<uint32_t>(mState.getColorAttachments().size()); uint32_t maxColorAttachments = static_cast<uint32_t>(mState.getColorAttachments().size());
desc.numColorAttachments = 0; desc.numColorAttachments = 0;
desc.sampleCount = 1; desc.sampleCount = 1;
...@@ -751,6 +835,21 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, ...@@ -751,6 +835,21 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1); desc.numColorAttachments = std::max(desc.numColorAttachments, colorIndexGL + 1);
desc.sampleCount = std::max(desc.sampleCount, colorRenderTarget->getRenderSamples()); desc.sampleCount = std::max(desc.sampleCount, colorRenderTarget->getRenderSamples());
if (!mRenderPassFirstColorAttachmentFormat)
{
mRenderPassFirstColorAttachmentFormat = colorRenderTarget->getFormat();
}
else if (colorRenderTarget->getFormat())
{
if (mRenderPassFirstColorAttachmentFormat->actualAngleFormat().isSint() !=
colorRenderTarget->getFormat()->actualAngleFormat().isSint() ||
mRenderPassFirstColorAttachmentFormat->actualAngleFormat().isUint() !=
colorRenderTarget->getFormat()->actualAngleFormat().isUint())
{
mRenderPassAttachmentsSameColorType = false;
}
}
} }
else else
{ {
...@@ -781,14 +880,6 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, ...@@ -781,14 +880,6 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
// Override clear color based on texture's write mask
void FramebufferMtl::overrideClearColor(const mtl::TextureRef &texture,
MTLClearColor clearColor,
MTLClearColor *colorOut)
{
*colorOut = mtl::EmulatedAlphaClearColor(clearColor, texture->getColorWritableMask());
}
angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context, angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context,
gl::DrawBufferMask clearColorBuffers, gl::DrawBufferMask clearColorBuffers,
const mtl::ClearRectParams &clearOpts) const mtl::ClearRectParams &clearOpts)
...@@ -837,7 +928,8 @@ angle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted( ...@@ -837,7 +928,8 @@ angle::Result FramebufferMtl::clearWithLoadOpRenderPassNotStarted(
if (clearColorBuffers.test(colorIndexGL)) if (clearColorBuffers.test(colorIndexGL))
{ {
colorAttachment.loadAction = MTLLoadActionClear; colorAttachment.loadAction = MTLLoadActionClear;
overrideClearColor(texture, clearOpts.clearColor.value(), &colorAttachment.clearColor); OverrideMTLClearColor(texture, clearOpts.clearColor.value(),
&colorAttachment.clearColor);
} }
} }
...@@ -879,7 +971,7 @@ angle::Result FramebufferMtl::clearWithLoadOpRenderPassStarted( ...@@ -879,7 +971,7 @@ angle::Result FramebufferMtl::clearWithLoadOpRenderPassStarted(
if (clearColorBuffers.test(colorIndexGL)) if (clearColorBuffers.test(colorIndexGL))
{ {
MTLClearColor clearVal; MTLClearColor clearVal;
overrideClearColor(texture, clearOpts.clearColor.value(), &clearVal); OverrideMTLClearColor(texture, clearOpts.clearColor.value(), &clearVal);
encoder->setColorLoadAction(MTLLoadActionClear, clearVal, colorIndexGL); encoder->setColorLoadAction(MTLLoadActionClear, clearVal, colorIndexGL);
} }
...@@ -905,10 +997,56 @@ angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context, ...@@ -905,10 +997,56 @@ angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context,
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
DisplayMtl *display = contextMtl->getDisplay(); DisplayMtl *display = contextMtl->getDisplay();
if (mRenderPassAttachmentsSameColorType)
{
// Start new render encoder if not already. // Start new render encoder if not already.
mtl::RenderCommandEncoder *encoder = ensureRenderPassStarted(context, mRenderPassDesc); mtl::RenderCommandEncoder *encoder = ensureRenderPassStarted(context, mRenderPassDesc);
return display->getUtils().clearWithDraw(context, encoder, clearOpts); return display->getUtils().clearWithDraw(context, encoder, clearOpts);
}
// Not all attachments have the same color type.
mtl::ClearRectParams overrideClearOps = clearOpts;
overrideClearOps.enabledBuffers.reset();
// First clear depth/stencil without color attachment
if (clearOpts.clearDepth.valid() || clearOpts.clearStencil.valid())
{
mtl::RenderPassDesc dsOnlyDesc = mRenderPassDesc;
dsOnlyDesc.numColorAttachments = 0;
mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(dsOnlyDesc);
ANGLE_TRY(display->getUtils().clearWithDraw(context, encoder, overrideClearOps));
}
// Clear the color attachment one by one.
overrideClearOps.enabledBuffers.set(0);
for (size_t drawbuffer : clearColorBuffers)
{
if (drawbuffer >= mRenderPassDesc.numColorAttachments)
{
continue;
}
RenderTargetMtl *renderTarget = mColorRenderTargets[drawbuffer];
if (!renderTarget || !renderTarget->getTexture())
{
continue;
}
const mtl::Format &format = *renderTarget->getFormat();
mtl::PixelType clearColorType = overrideClearOps.clearColor.value().getType();
if ((clearColorType == mtl::PixelType::Int && !format.actualAngleFormat().isSint()) ||
(clearColorType == mtl::PixelType::UInt && !format.actualAngleFormat().isUint()) ||
(clearColorType == mtl::PixelType::Float && format.actualAngleFormat().isInt()))
{
continue;
}
mtl::RenderCommandEncoder *encoder =
contextMtl->getRenderTargetCommandEncoder(*renderTarget);
ANGLE_TRY(display->getUtils().clearWithDraw(context, encoder, overrideClearOps));
}
return angle::Result::Continue;
} }
angle::Result FramebufferMtl::clearImpl(const gl::Context *context, angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
...@@ -928,6 +1066,7 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context, ...@@ -928,6 +1066,7 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
const gl::Rectangle renderArea(0, 0, mState.getDimensions().width, const gl::Rectangle renderArea(0, 0, mState.getDimensions().width,
mState.getDimensions().height); mState.getDimensions().height);
clearOpts.colorFormat = mRenderPassFirstColorAttachmentFormat;
clearOpts.dstTextureSize = mState.getExtents(); clearOpts.dstTextureSize = mState.getExtents();
clearOpts.clearArea = ClipRectToScissor(contextMtl->getState(), renderArea, false); clearOpts.clearArea = ClipRectToScissor(contextMtl->getState(), renderArea, false);
clearOpts.flipY = mFlipY; clearOpts.flipY = mFlipY;
......
...@@ -77,5 +77,6 @@ void RenderTargetMtl::toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc * ...@@ -77,5 +77,6 @@ void RenderTargetMtl::toRenderPassAttachmentDesc(mtl::RenderPassAttachmentDesc *
rpaDescOut->implicitMSTexture = mImplicitMSTexture.lock(); rpaDescOut->implicitMSTexture = mImplicitMSTexture.lock();
rpaDescOut->level = mLevelIndex; rpaDescOut->level = mLevelIndex;
rpaDescOut->sliceOrDepth = mLayerIndex; rpaDescOut->sliceOrDepth = mLayerIndex;
rpaDescOut->blendable = mFormat ? mFormat->getCaps().blendable : false;
} }
} }
...@@ -546,8 +546,8 @@ angle::Result SurfaceMtl::resolveColorTextureIfNeeded(const gl::Context *context ...@@ -546,8 +546,8 @@ angle::Result SurfaceMtl::resolveColorTextureIfNeeded(const gl::Context *context
mColorFormat); mColorFormat);
mtl::RenderCommandEncoder *encoder = mtl::RenderCommandEncoder *encoder =
contextMtl->getRenderTargetCommandEncoder(mColorManualResolveRenderTarget); contextMtl->getRenderTargetCommandEncoder(mColorManualResolveRenderTarget);
ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(context, encoder, ANGLE_TRY(contextMtl->getDisplay()->getUtils().blitColorWithDraw(
mMSColorTexture)); context, encoder, mColorFormat.actualAngleFormat(), mMSColorTexture));
contextMtl->endEncoding(true); contextMtl->endEncoding(true);
mColorManualResolveRenderTarget.reset(); mColorManualResolveRenderTarget.reset();
} }
......
...@@ -1780,7 +1780,8 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context, ...@@ -1780,7 +1780,8 @@ angle::Result TextureMtl::copySubImageWithDraw(const gl::Context *context,
blitParams.srcYFlipped = framebufferMtl->flipY(); blitParams.srcYFlipped = framebufferMtl->flipY();
blitParams.dstLuminance = internalFormat.isLUMA(); blitParams.dstLuminance = internalFormat.isLUMA();
return displayMtl->getUtils().blitColorWithDraw(context, cmdEncoder, blitParams); return displayMtl->getUtils().blitColorWithDraw(
context, cmdEncoder, colorReadRT->getFormat()->actualAngleFormat(), blitParams);
} }
angle::Result TextureMtl::copySubImageCPU(const gl::Context *context, angle::Result TextureMtl::copySubImageCPU(const gl::Context *context,
...@@ -1937,7 +1938,8 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context, ...@@ -1937,7 +1938,8 @@ angle::Result TextureMtl::copySubTextureWithDraw(const gl::Context *context,
blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha; blitParams.unpackPremultiplyAlpha = unpackPremultiplyAlpha;
blitParams.unpackUnmultiplyAlpha = unpackUnmultiplyAlpha; blitParams.unpackUnmultiplyAlpha = unpackUnmultiplyAlpha;
return displayMtl->getUtils().blitColorWithDraw(context, cmdEncoder, blitParams); return displayMtl->getUtils().copyTextureWithDraw(context, cmdEncoder, sourceAngleFormat,
mFormat.actualAngleFormat(), blitParams);
} }
angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context, angle::Result TextureMtl::copySubTextureCPU(const gl::Context *context,
......
...@@ -156,7 +156,7 @@ constexpr uint32_t kStencilMaskAll = 0xff; // Only 8 bits stencil is supported ...@@ -156,7 +156,7 @@ constexpr uint32_t kStencilMaskAll = 0xff; // Only 8 bits stencil is supported
constexpr MTLVertexStepFunction kVertexStepFunctionInvalid = constexpr MTLVertexStepFunction kVertexStepFunctionInvalid =
static_cast<MTLVertexStepFunction>(0xff); static_cast<MTLVertexStepFunction>(0xff);
constexpr float kEmulatedAlphaValue = 1.0f; constexpr int kEmulatedAlphaValue = 1;
constexpr size_t kOcclusionQueryResultSize = sizeof(uint64_t); constexpr size_t kOcclusionQueryResultSize = sizeof(uint64_t);
...@@ -404,11 +404,59 @@ class ImageNativeIndexIterator final ...@@ -404,11 +404,59 @@ class ImageNativeIndexIterator final
gl::ImageIndexIterator mNativeIndexIte; gl::ImageIndexIterator mNativeIndexIte;
}; };
struct ClearOptions using ClearColorValueBytes = std::array<uint8_t, 4 * sizeof(float)>;
class ClearColorValue
{ {
Optional<MTLClearColor> clearColor; public:
Optional<float> clearDepth; constexpr ClearColorValue()
Optional<uint32_t> clearStencil; : mType(PixelType::Float), mRedF(0), mGreenF(0), mBlueF(0), mAlphaF(0)
{}
constexpr ClearColorValue(float r, float g, float b, float a)
: mType(PixelType::Float), mRedF(r), mGreenF(g), mBlueF(b), mAlphaF(a)
{}
constexpr ClearColorValue(int32_t r, int32_t g, int32_t b, int32_t a)
: mType(PixelType::Int), mRedI(r), mGreenI(g), mBlueI(b), mAlphaI(a)
{}
constexpr ClearColorValue(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
: mType(PixelType::UInt), mRedU(r), mGreenU(g), mBlueU(b), mAlphaU(a)
{}
constexpr ClearColorValue(const ClearColorValue &src)
: mType(src.mType), mValueBytes(src.mValueBytes)
{}
MTLClearColor toMTLClearColor() const;
PixelType getType() const { return mType; }
const ClearColorValueBytes &getValueBytes() const { return mValueBytes; }
ClearColorValue &operator=(const ClearColorValue &src);
void setAsFloat(float r, float g, float b, float a);
void setAsInt(int32_t r, int32_t g, int32_t b, int32_t a);
void setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a);
private:
PixelType mType;
union
{
struct
{
float mRedF, mGreenF, mBlueF, mAlphaF;
};
struct
{
int32_t mRedI, mGreenI, mBlueI, mAlphaI;
};
struct
{
uint32_t mRedU, mGreenU, mBlueU, mAlphaU;
};
ClearColorValueBytes mValueBytes;
};
}; };
class CommandQueue; class CommandQueue;
......
...@@ -21,6 +21,58 @@ namespace rx ...@@ -21,6 +21,58 @@ namespace rx
namespace mtl namespace mtl
{ {
// ClearColorValue implementation
ClearColorValue &ClearColorValue::operator=(const ClearColorValue &src)
{
mType = src.mType;
mValueBytes = src.mValueBytes;
return *this;
}
void ClearColorValue::setAsFloat(float r, float g, float b, float a)
{
mType = PixelType::Float;
mRedF = r;
mGreenF = g;
mBlueF = b;
mAlphaF = a;
}
void ClearColorValue::setAsInt(int32_t r, int32_t g, int32_t b, int32_t a)
{
mType = PixelType::Int;
mRedI = r;
mGreenI = g;
mBlueI = b;
mAlphaI = a;
}
void ClearColorValue::setAsUInt(uint32_t r, uint32_t g, uint32_t b, uint32_t a)
{
mType = PixelType::UInt;
mRedU = r;
mGreenU = g;
mBlueU = b;
mAlphaU = a;
}
MTLClearColor ClearColorValue::toMTLClearColor() const
{
switch (mType)
{
case PixelType::Int:
return MTLClearColorMake(mRedI, mGreenI, mBlueI, mAlphaI);
case PixelType::UInt:
return MTLClearColorMake(mRedU, mGreenU, mBlueU, mAlphaU);
case PixelType::Float:
return MTLClearColorMake(mRedF, mGreenF, mBlueF, mAlphaF);
default:
UNREACHABLE();
return MTLClearColorMake(0, 0, 0, 0);
}
}
// ImageNativeIndex implementation // ImageNativeIndex implementation
ImageNativeIndexIterator ImageNativeIndex::getLayerIterator(GLint layerCount) const ImageNativeIndexIterator ImageNativeIndex::getLayerIterator(GLint layerCount) const
{ {
......
...@@ -29,10 +29,16 @@ class VisibilityBufferOffsetsMtl; ...@@ -29,10 +29,16 @@ class VisibilityBufferOffsetsMtl;
namespace mtl namespace mtl
{ {
struct ClearRectParams : public ClearOptions
struct ClearRectParams
{ {
Optional<ClearColorValue> clearColor;
Optional<float> clearDepth;
Optional<uint32_t> clearStencil;
MTLColorWriteMask clearColorMask = MTLColorWriteMaskAll; MTLColorWriteMask clearColorMask = MTLColorWriteMaskAll;
const mtl::Format *colorFormat = nullptr;
gl::Extents dstTextureSize; gl::Extents dstTextureSize;
// Only clear enabled buffers // Only clear enabled buffers
...@@ -159,7 +165,9 @@ struct CopyPixelsToBufferParams : CopyPixelsCommonParams ...@@ -159,7 +165,9 @@ struct CopyPixelsToBufferParams : CopyPixelsCommonParams
class ClearUtils final : angle::NonCopyable class ClearUtils final : angle::NonCopyable
{ {
public: public:
ClearUtils(); ClearUtils() = delete;
ClearUtils(const std::string &fragmentShaderName);
ClearUtils(const ClearUtils &src);
void onDestroy(); void onDestroy();
...@@ -180,6 +188,8 @@ class ClearUtils final : angle::NonCopyable ...@@ -180,6 +188,8 @@ class ClearUtils final : angle::NonCopyable
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params); const ClearRectParams &params);
const std::string mFragmentShaderName;
// Render pipeline cache for clear with draw: // Render pipeline cache for clear with draw:
std::array<RenderPipelineCache, kMaxRenderTargets + 1> mClearRenderPipelineCache; std::array<RenderPipelineCache, kMaxRenderTargets + 1> mClearRenderPipelineCache;
}; };
...@@ -187,7 +197,9 @@ class ClearUtils final : angle::NonCopyable ...@@ -187,7 +197,9 @@ class ClearUtils final : angle::NonCopyable
class ColorBlitUtils final : angle::NonCopyable class ColorBlitUtils final : angle::NonCopyable
{ {
public: public:
ColorBlitUtils(); ColorBlitUtils() = delete;
ColorBlitUtils(const std::string &fragmentShaderName);
ColorBlitUtils(const ColorBlitUtils &src);
void onDestroy(); void onDestroy();
...@@ -211,6 +223,8 @@ class ColorBlitUtils final : angle::NonCopyable ...@@ -211,6 +223,8 @@ class ColorBlitUtils final : angle::NonCopyable
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const ColorBlitParams &params); const ColorBlitParams &params);
const std::string mFragmentShaderName;
// Blit with draw pipeline caches: // Blit with draw pipeline caches:
// First array dimension: number of outputs. // First array dimension: number of outputs.
// Second array dimension: source texture type (2d, ms, array, 3d, etc) // Second array dimension: source texture type (2d, ms, array, 3d, etc)
...@@ -230,6 +244,7 @@ class DepthStencilBlitUtils final : angle::NonCopyable ...@@ -230,6 +244,7 @@ class DepthStencilBlitUtils final : angle::NonCopyable
angle::Result blitDepthStencilWithDraw(const gl::Context *context, angle::Result blitDepthStencilWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const DepthStencilBlitParams &params); const DepthStencilBlitParams &params);
// Blit stencil data using intermediate buffer. This function is used on devices with no // Blit stencil data using intermediate buffer. This function is used on devices with no
// support for direct stencil write in shader. Thus an intermediate buffer storing copied // support for direct stencil write in shader. Thus an intermediate buffer storing copied
// stencil data is needed. // stencil data is needed.
...@@ -431,12 +446,19 @@ class RenderUtils : public Context, angle::NonCopyable ...@@ -431,12 +446,19 @@ class RenderUtils : public Context, angle::NonCopyable
// Blit texture data to current framebuffer // Blit texture data to current framebuffer
angle::Result blitColorWithDraw(const gl::Context *context, angle::Result blitColorWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const angle::Format &srcAngleFormat,
const ColorBlitParams &params); const ColorBlitParams &params);
// Same as above but blit the whole texture to the whole of current framebuffer. // Same as above but blit the whole texture to the whole of current framebuffer.
// This function assumes the framebuffer and the source texture have same size. // This function assumes the framebuffer and the source texture have same size.
angle::Result blitColorWithDraw(const gl::Context *context, angle::Result blitColorWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const angle::Format &srcAngleFormat,
const TextureRef &srcTexture); const TextureRef &srcTexture);
angle::Result copyTextureWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const angle::Format &srcAngleFormat,
const angle::Format &dstAngleFormat,
const ColorBlitParams &params);
angle::Result blitDepthStencilWithDraw(const gl::Context *context, angle::Result blitDepthStencilWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
...@@ -490,8 +512,11 @@ class RenderUtils : public Context, angle::NonCopyable ...@@ -490,8 +512,11 @@ class RenderUtils : public Context, angle::NonCopyable
const char *function, const char *function,
unsigned int line) override; unsigned int line) override;
ClearUtils mClearUtils; std::array<ClearUtils, angle::EnumSize<PixelType>()> mClearUtils;
ColorBlitUtils mColorBlitUtils;
std::array<ColorBlitUtils, angle::EnumSize<PixelType>()> mColorBlitUtils;
ColorBlitUtils mCopyTextureFloatToUIntUtils;
DepthStencilBlitUtils mDepthStencilBlitUtils; DepthStencilBlitUtils mDepthStencilBlitUtils;
IndexGeneratorUtils mIndexUtils; IndexGeneratorUtils mIndexUtils;
VisibilityResultUtils mVisibilityResultUtils; VisibilityResultUtils mVisibilityResultUtils;
......
...@@ -535,6 +535,11 @@ StencilBlitViaBufferParams::StencilBlitViaBufferParams(const DepthStencilBlitPar ...@@ -535,6 +535,11 @@ StencilBlitViaBufferParams::StencilBlitViaBufferParams(const DepthStencilBlitPar
// RenderUtils implementation // RenderUtils implementation
RenderUtils::RenderUtils(DisplayMtl *display) RenderUtils::RenderUtils(DisplayMtl *display)
: Context(display), : Context(display),
mClearUtils(
{ClearUtils("clearIntFS"), ClearUtils("clearUIntFS"), ClearUtils("clearFloatFS")}),
mColorBlitUtils({ColorBlitUtils("blitIntFS"), ColorBlitUtils("blitUIntFS"),
ColorBlitUtils("blitFloatFS")}),
mCopyTextureFloatToUIntUtils("copyTextureFloatToUIntFS"),
mCopyPixelsUtils( mCopyPixelsUtils(
{CopyPixelsUtils("readFromBufferToIntTexture", "writeFromIntTextureToBuffer"), {CopyPixelsUtils("readFromBufferToIntTexture", "writeFromIntTextureToBuffer"),
CopyPixelsUtils("readFromBufferToUIntTexture", "writeFromUIntTextureToBuffer"), CopyPixelsUtils("readFromBufferToUIntTexture", "writeFromUIntTextureToBuffer"),
...@@ -550,11 +555,20 @@ angle::Result RenderUtils::initialize() ...@@ -550,11 +555,20 @@ angle::Result RenderUtils::initialize()
void RenderUtils::onDestroy() void RenderUtils::onDestroy()
{ {
mIndexUtils.onDestroy();
mClearUtils.onDestroy();
mColorBlitUtils.onDestroy();
mDepthStencilBlitUtils.onDestroy(); mDepthStencilBlitUtils.onDestroy();
mIndexUtils.onDestroy();
mVisibilityResultUtils.onDestroy();
mMipmapUtils.onDestroy();
mCopyTextureFloatToUIntUtils.onDestroy();
for (ClearUtils &util : mClearUtils)
{
util.onDestroy();
}
for (ColorBlitUtils &util : mColorBlitUtils)
{
util.onDestroy();
}
for (CopyPixelsUtils &util : mCopyPixelsUtils) for (CopyPixelsUtils &util : mCopyPixelsUtils)
{ {
util.onDestroy(); util.onDestroy();
...@@ -590,19 +604,31 @@ angle::Result RenderUtils::clearWithDraw(const gl::Context *context, ...@@ -590,19 +604,31 @@ angle::Result RenderUtils::clearWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const ClearRectParams &params) const ClearRectParams &params)
{ {
return mClearUtils.clearWithDraw(context, cmdEncoder, params); int index = 0;
if (params.clearColor.valid())
{
index = static_cast<int>(params.clearColor.value().getType());
}
else if (params.colorFormat)
{
index = GetPixelTypeIndex(params.colorFormat->actualAngleFormat());
}
return mClearUtils[index].clearWithDraw(context, cmdEncoder, params);
} }
// Blit texture data to current framebuffer // Blit texture data to current framebuffer
angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context, angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const angle::Format &srcAngleFormat,
const ColorBlitParams &params) const ColorBlitParams &params)
{ {
return mColorBlitUtils.blitColorWithDraw(context, cmdEncoder, params); int index = GetPixelTypeIndex(srcAngleFormat);
return mColorBlitUtils[index].blitColorWithDraw(context, cmdEncoder, params);
} }
angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context, angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder, RenderCommandEncoder *cmdEncoder,
const angle::Format &srcAngleFormat,
const TextureRef &srcTexture) const TextureRef &srcTexture)
{ {
if (!srcTexture) if (!srcTexture)
...@@ -618,7 +644,22 @@ angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context, ...@@ -618,7 +644,22 @@ angle::Result RenderUtils::blitColorWithDraw(const gl::Context *context,
params.dstRect = params.dstScissorRect = params.srcRect = params.dstRect = params.dstScissorRect = params.srcRect =
gl::Rectangle(0, 0, params.dstTextureSize.width, params.dstTextureSize.height); gl::Rectangle(0, 0, params.dstTextureSize.width, params.dstTextureSize.height);
return blitColorWithDraw(context, cmdEncoder, params); return blitColorWithDraw(context, cmdEncoder, srcAngleFormat, params);
}
angle::Result RenderUtils::copyTextureWithDraw(const gl::Context *context,
RenderCommandEncoder *cmdEncoder,
const angle::Format &srcAngleFormat,
const angle::Format &dstAngleFormat,
const ColorBlitParams &params)
{
if (!srcAngleFormat.isInt() && dstAngleFormat.isUint())
{
return mCopyTextureFloatToUIntUtils.blitColorWithDraw(context, cmdEncoder, params);
}
ASSERT(srcAngleFormat.isSint() == dstAngleFormat.isSint() &&
srcAngleFormat.isUint() == dstAngleFormat.isUint());
return blitColorWithDraw(context, cmdEncoder, srcAngleFormat, params);
} }
angle::Result RenderUtils::blitDepthStencilWithDraw(const gl::Context *context, angle::Result RenderUtils::blitDepthStencilWithDraw(const gl::Context *context,
...@@ -705,7 +746,11 @@ angle::Result RenderUtils::packPixelsFromTextureToBuffer(ContextMtl *contextMtl, ...@@ -705,7 +746,11 @@ angle::Result RenderUtils::packPixelsFromTextureToBuffer(ContextMtl *contextMtl,
} }
// ClearUtils implementation // ClearUtils implementation
ClearUtils::ClearUtils() = default; ClearUtils::ClearUtils(const std::string &fragmentShaderName)
: mFragmentShaderName(fragmentShaderName)
{}
ClearUtils::ClearUtils(const ClearUtils &src) : ClearUtils(src.mFragmentShaderName) {}
void ClearUtils::onDestroy() void ClearUtils::onDestroy()
{ {
...@@ -736,8 +781,9 @@ void ClearUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx, uint ...@@ -736,8 +781,9 @@ void ClearUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx, uint
type:MTLDataTypeUInt type:MTLDataTypeUInt
withName:NUM_COLOR_OUTPUTS_CONSTANT_NAME]; withName:NUM_COLOR_OUTPUTS_CONSTANT_NAME];
id<MTLFunction> fragmentShader = id<MTLFunction> fragmentShader = [[shaderLib
[[shaderLib newFunctionWithName:@"clearFloatFS" constantValues:funcConstants newFunctionWithName:[NSString stringWithUTF8String:mFragmentShaderName.c_str()]
constantValues:funcConstants
error:&err] ANGLE_MTL_AUTORELEASE]; error:&err] ANGLE_MTL_AUTORELEASE];
ASSERT(fragmentShader); ASSERT(fragmentShader);
...@@ -840,10 +886,14 @@ void ClearUtils::setupClearWithDraw(const gl::Context *context, ...@@ -840,10 +886,14 @@ void ClearUtils::setupClearWithDraw(const gl::Context *context,
// uniform // uniform
ClearParamsUniform uniformParams; ClearParamsUniform uniformParams;
uniformParams.clearColor[0] = static_cast<float>(params.clearColor.value().red); const ClearColorValue &clearValue = params.clearColor.value();
uniformParams.clearColor[1] = static_cast<float>(params.clearColor.value().green); // ClearColorValue is an int, uint, float union so it's safe to use only floats.
uniformParams.clearColor[2] = static_cast<float>(params.clearColor.value().blue); // The Shader will do the bit cast based on appropriate format type.
uniformParams.clearColor[3] = static_cast<float>(params.clearColor.value().alpha); // See shaders/clear.metal (3 variants ClearFloatFS, ClearIntFS and ClearUIntFS each does the
// appropriate bit cast)
ASSERT(sizeof(uniformParams.clearColor) == clearValue.getValueBytes().size());
std::memcpy(uniformParams.clearColor, clearValue.getValueBytes().data(),
clearValue.getValueBytes().size());
uniformParams.clearDepth = params.clearDepth.value(); uniformParams.clearDepth = params.clearDepth.value();
cmdEncoder->setVertexData(uniformParams, 0); cmdEncoder->setVertexData(uniformParams, 0);
...@@ -893,7 +943,12 @@ angle::Result ClearUtils::clearWithDraw(const gl::Context *context, ...@@ -893,7 +943,12 @@ angle::Result ClearUtils::clearWithDraw(const gl::Context *context,
} }
// ColorBlitUtils implementation // ColorBlitUtils implementation
ColorBlitUtils::ColorBlitUtils() = default; ColorBlitUtils::ColorBlitUtils(const std::string &fragmentShaderName)
: mFragmentShaderName(fragmentShaderName)
{}
ColorBlitUtils::ColorBlitUtils(const ColorBlitUtils &src) : ColorBlitUtils(src.mFragmentShaderName)
{}
void ColorBlitUtils::onDestroy() void ColorBlitUtils::onDestroy()
{ {
...@@ -952,8 +1007,9 @@ void ColorBlitUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx, ...@@ -952,8 +1007,9 @@ void ColorBlitUtils::ensureRenderPipelineStateCacheInitialized(ContextMtl *ctx,
type:MTLDataTypeInt type:MTLDataTypeInt
withName:SOURCE_TEXTURE_TYPE_CONSTANT_NAME]; withName:SOURCE_TEXTURE_TYPE_CONSTANT_NAME];
id<MTLFunction> fragmentShader = id<MTLFunction> fragmentShader = [[shaderLib
[[shaderLib newFunctionWithName:@"blitFloatFS" constantValues:funcConstants newFunctionWithName:[NSString stringWithUTF8String:mFragmentShaderName.c_str()]
constantValues:funcConstants
error:&err] ANGLE_MTL_AUTORELEASE]; error:&err] ANGLE_MTL_AUTORELEASE];
ASSERT(vertexShader); ASSERT(vertexShader);
......
...@@ -303,6 +303,9 @@ struct RenderPassAttachmentDesc ...@@ -303,6 +303,9 @@ struct RenderPassAttachmentDesc
MipmapNativeLevel level; MipmapNativeLevel level;
uint32_t sliceOrDepth; uint32_t sliceOrDepth;
// This attachment is blendable or not.
bool blendable;
MTLLoadAction loadAction; MTLLoadAction loadAction;
MTLStoreAction storeAction; MTLStoreAction storeAction;
MTLStoreActionOptions storeActionOptions; MTLStoreActionOptions storeActionOptions;
......
...@@ -693,6 +693,7 @@ void RenderPassAttachmentDesc::reset() ...@@ -693,6 +693,7 @@ void RenderPassAttachmentDesc::reset()
implicitMSTexture.reset(); implicitMSTexture.reset();
level = mtl::kZeroNativeMipLevel; level = mtl::kZeroNativeMipLevel;
sliceOrDepth = 0; sliceOrDepth = 0;
blendable = false;
loadAction = MTLLoadActionLoad; loadAction = MTLLoadActionLoad;
storeAction = MTLStoreActionStore; storeAction = MTLStoreActionStore;
storeActionOptions = MTLStoreActionOptionNone; storeActionOptions = MTLStoreActionOptionNone;
...@@ -746,6 +747,11 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat ...@@ -746,6 +747,11 @@ void RenderPassDesc::populateRenderPipelineOutputDesc(const BlendDesc &blendStat
{ {
// Copy parameters from blend state // Copy parameters from blend state
outputDescriptor.colorAttachments[i].update(blendState); outputDescriptor.colorAttachments[i].update(blendState);
if (!renderPassColorAttachment.blendable)
{
// Disable blending if the attachment's render target doesn't support blending.
outputDescriptor.colorAttachments[i].blendingEnabled = false;
}
outputDescriptor.colorAttachments[i].pixelFormat = texture->pixelFormat(); outputDescriptor.colorAttachments[i].pixelFormat = texture->pixelFormat();
......
...@@ -210,17 +210,18 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context, ...@@ -210,17 +210,18 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
RenderTargetMtl tempRtt; RenderTargetMtl tempRtt;
tempRtt.set(texture, index.getNativeLevel(), sliceOrDepth, textureObjFormat); tempRtt.set(texture, index.getNativeLevel(), sliceOrDepth, textureObjFormat);
MTLClearColor blackColor = {}; int clearAlpha = 0;
if (!textureObjFormat.intendedAngleFormat().alphaBits) if (!textureObjFormat.intendedAngleFormat().alphaBits)
{ {
// if intended format doesn't have alpha, set it to 1.0. // if intended format doesn't have alpha, set it to 1.0.
blackColor.alpha = kEmulatedAlphaValue; clearAlpha = kEmulatedAlphaValue;
} }
RenderCommandEncoder *encoder; RenderCommandEncoder *encoder;
if (channelsToInit == MTLColorWriteMaskAll) if (channelsToInit == MTLColorWriteMaskAll)
{ {
// 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, clearAlpha);
encoder = contextMtl->getRenderTargetCommandEncoderWithClear(tempRtt, blackColor); encoder = contextMtl->getRenderTargetCommandEncoderWithClear(tempRtt, blackColor);
} }
else else
...@@ -233,8 +234,23 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context, ...@@ -233,8 +234,23 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
// 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->getRenderTargetCommandEncoder(tempRtt); encoder = contextMtl->getRenderTargetCommandEncoder(tempRtt);
const angle::Format &angleFormat = textureObjFormat.actualAngleFormat();
ClearRectParams clearParams; ClearRectParams clearParams;
clearParams.clearColor = blackColor; ClearColorValue clearColor;
if (angleFormat.isSint())
{
clearColor.setAsInt(0, 0, 0, clearAlpha);
}
else if (angleFormat.isUint())
{
clearColor.setAsUInt(0, 0, 0, clearAlpha);
}
else
{
clearColor.setAsFloat(0, 0, 0, clearAlpha);
}
clearParams.clearColor = clearColor;
clearParams.dstTextureSize = texture->sizeAt0(); clearParams.dstTextureSize = texture->sizeAt0();
clearParams.enabledBuffers.set(0); clearParams.enabledBuffers.set(0);
clearParams.clearArea = gl::Rectangle(0, 0, texture->widthAt0(), texture->heightAt0()); clearParams.clearArea = gl::Rectangle(0, 0, texture->widthAt0(), texture->heightAt0());
......
...@@ -1100,6 +1100,142 @@ TEST_P(ClearTestES3, MaskedClearHeterogeneousAttachments) ...@@ -1100,6 +1100,142 @@ TEST_P(ClearTestES3, MaskedClearHeterogeneousAttachments)
verifyStencil(kStencilClearValue, kSize); verifyStencil(kStencilClearValue, kSize);
} }
// Test that clearing multiple attachments of different nature (float, int and uint) in the
// presence of a scissor test works correctly. In the Vulkan backend, this exercises clearWithDraw
// and the relevant internal shaders.
TEST_P(ClearTestES3, ScissoredClearHeterogeneousAttachments)
{
// http://anglebug.com/4855
ANGLE_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
// http://anglebug.com/5116
ANGLE_SKIP_TEST_IF(IsWindows() && (IsOpenGL() || IsD3D11()) && IsAMD());
constexpr uint32_t kSize = 16;
constexpr uint32_t kHalfSize = kSize / 2;
constexpr uint32_t kAttachmentCount = 3;
constexpr float kDepthClearValue = 0.256f;
constexpr int32_t kStencilClearValue = 0x1D;
constexpr GLenum kAttachmentFormats[kAttachmentCount] = {
GL_RGBA8,
GL_RGBA8I,
GL_RGBA8UI,
};
constexpr GLenum kDataFormats[kAttachmentCount] = {
GL_RGBA,
GL_RGBA_INTEGER,
GL_RGBA_INTEGER,
};
constexpr GLenum kDataTypes[kAttachmentCount] = {
GL_UNSIGNED_BYTE,
GL_BYTE,
GL_UNSIGNED_BYTE,
};
std::vector<unsigned char> pixelData(kSize * kSize * 4, 0);
glBindFramebuffer(GL_FRAMEBUFFER, mFBOs[0]);
GLTexture textures[kAttachmentCount];
GLRenderbuffer depthStencil;
GLenum drawBuffers[kAttachmentCount];
for (uint32_t i = 0; i < kAttachmentCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, textures[i]);
glTexImage2D(GL_TEXTURE_2D, 0, kAttachmentFormats[i], kSize, kSize, 0, kDataFormats[i],
kDataTypes[i], pixelData.data());
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, textures[i],
0);
drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
}
glBindRenderbuffer(GL_RENDERBUFFER, depthStencil);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
depthStencil);
glDrawBuffers(kAttachmentCount, drawBuffers);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_EQ(0, 0, 0, 0, 0, 0);
// Enable scissor test
glScissor(0, 0, kHalfSize, kHalfSize);
glEnable(GL_SCISSOR_TEST);
GLColor clearValuef = {25, 50, 75, 100};
angle::Vector4 clearValuefv = clearValuef.toNormalizedVector();
glClearColor(clearValuefv.x(), clearValuefv.y(), clearValuefv.z(), clearValuefv.w());
glClearDepthf(kDepthClearValue);
// clear stencil.
glClearBufferiv(GL_STENCIL, 0, &kStencilClearValue);
// clear float color attachment & depth together
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// clear integer attachment.
int clearValuei[4] = {10, -20, 30, -40};
glClearBufferiv(GL_COLOR, 1, clearValuei);
// clear unsigned integer attachment
uint32_t clearValueui[4] = {50, 60, 70, 80};
glClearBufferuiv(GL_COLOR, 2, clearValueui);
ASSERT_GL_NO_ERROR();
{
glReadBuffer(GL_COLOR_ATTACHMENT0);
ASSERT_GL_NO_ERROR();
GLColor expect = clearValuef;
EXPECT_PIXEL_COLOR_EQ(0, 0, expect);
EXPECT_PIXEL_COLOR_EQ(0, kHalfSize - 1, expect);
EXPECT_PIXEL_COLOR_EQ(kHalfSize - 1, 0, expect);
EXPECT_PIXEL_COLOR_EQ(kHalfSize - 1, kHalfSize - 1, expect);
EXPECT_PIXEL_EQ(kHalfSize + 1, kHalfSize + 1, 0, 0, 0, 0);
}
{
glReadBuffer(GL_COLOR_ATTACHMENT1);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_8I(0, 0, clearValuei[0], clearValuei[1], clearValuei[2], clearValuei[3]);
EXPECT_PIXEL_8I(0, kHalfSize - 1, clearValuei[0], clearValuei[1], clearValuei[2],
clearValuei[3]);
EXPECT_PIXEL_8I(kHalfSize - 1, 0, clearValuei[0], clearValuei[1], clearValuei[2],
clearValuei[3]);
EXPECT_PIXEL_8I(kHalfSize - 1, kHalfSize - 1, clearValuei[0], clearValuei[1],
clearValuei[2], clearValuei[3]);
EXPECT_PIXEL_8I(kHalfSize + 1, kHalfSize + 1, 0, 0, 0, 0);
}
{
glReadBuffer(GL_COLOR_ATTACHMENT2);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_8UI(0, 0, clearValueui[0], clearValueui[1], clearValueui[2], clearValueui[3]);
EXPECT_PIXEL_8UI(0, kHalfSize - 1, clearValueui[0], clearValueui[1], clearValueui[2],
clearValueui[3]);
EXPECT_PIXEL_8UI(kHalfSize - 1, 0, clearValueui[0], clearValueui[1], clearValueui[2],
clearValueui[3]);
EXPECT_PIXEL_8UI(kHalfSize - 1, kHalfSize - 1, clearValueui[0], clearValueui[1],
clearValueui[2], clearValueui[3]);
EXPECT_PIXEL_8UI(kHalfSize + 1, kHalfSize + 1, 0, 0, 0, 0);
}
glReadBuffer(GL_COLOR_ATTACHMENT0);
for (uint32_t i = 1; i < kAttachmentCount; ++i)
drawBuffers[i] = GL_NONE;
glDrawBuffers(kAttachmentCount, drawBuffers);
verifyDepth(kDepthClearValue, kHalfSize);
verifyStencil(kStencilClearValue, kHalfSize);
}
// This tests a bug where in a masked clear when calling "ClearBuffer", we would // This tests a bug where in a masked clear when calling "ClearBuffer", we would
// mistakenly clear every channel (including the masked-out ones) // mistakenly clear every channel (including the masked-out ones)
TEST_P(ClearTestES3, MaskedClearBufferBug) TEST_P(ClearTestES3, MaskedClearBufferBug)
...@@ -2140,7 +2276,7 @@ TEST_P(ClearTestES3, ClearBufferfiStencilMask) ...@@ -2140,7 +2276,7 @@ TEST_P(ClearTestES3, ClearBufferfiStencilMask)
// Use this to select which configurations (e.g. which renderer, which GLES major version) these // Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against. // tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ClearTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ClearTest);
ANGLE_INSTANTIATE_TEST_ES3(ClearTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(ClearTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_COMBINE_4(MaskedScissoredClearTest, ANGLE_INSTANTIATE_TEST_COMBINE_4(MaskedScissoredClearTest,
MaskedScissoredClearVariationsTestPrint, MaskedScissoredClearVariationsTestPrint,
testing::Range(0, 3), testing::Range(0, 3),
...@@ -2155,7 +2291,9 @@ ANGLE_INSTANTIATE_TEST_COMBINE_4(MaskedScissoredClearTest, ...@@ -2155,7 +2291,9 @@ ANGLE_INSTANTIATE_TEST_COMBINE_4(MaskedScissoredClearTest,
ES2_OPENGLES(), ES2_OPENGLES(),
ES3_OPENGLES(), ES3_OPENGLES(),
ES2_VULKAN(), ES2_VULKAN(),
ES3_VULKAN()); ES3_VULKAN(),
ES2_METAL(),
ES3_METAL());
ANGLE_INSTANTIATE_TEST_COMBINE_4(VulkanClearTest, ANGLE_INSTANTIATE_TEST_COMBINE_4(VulkanClearTest,
MaskedScissoredClearVariationsTestPrint, MaskedScissoredClearVariationsTestPrint,
testing::Range(0, 3), testing::Range(0, 3),
...@@ -2166,6 +2304,12 @@ ANGLE_INSTANTIATE_TEST_COMBINE_4(VulkanClearTest, ...@@ -2166,6 +2304,12 @@ ANGLE_INSTANTIATE_TEST_COMBINE_4(VulkanClearTest,
ES3_VULKAN()); ES3_VULKAN());
// Not all ANGLE backends support RGB backbuffers // Not all ANGLE backends support RGB backbuffers
ANGLE_INSTANTIATE_TEST(ClearTestRGB, ES2_D3D11(), ES3_D3D11(), ES2_VULKAN(), ES3_VULKAN()); ANGLE_INSTANTIATE_TEST(ClearTestRGB,
ES2_D3D11(),
ES3_D3D11(),
ES2_VULKAN(),
ES3_VULKAN(),
ES2_METAL(),
ES3_METAL());
} // anonymous namespace } // anonymous namespace
...@@ -2541,6 +2541,6 @@ ANGLE_INSTANTIATE_TEST(CopyTextureTestDest, ...@@ -2541,6 +2541,6 @@ ANGLE_INSTANTIATE_TEST(CopyTextureTestDest,
ES2_OPENGLES(), ES2_OPENGLES(),
ES2_VULKAN(), ES2_VULKAN(),
ES2_METAL()); ES2_METAL());
ANGLE_INSTANTIATE_TEST_ES3(CopyTextureTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(CopyTextureTestES3, ES3_METAL());
} // namespace angle } // namespace angle
...@@ -301,6 +301,9 @@ TEST_P(DrawBuffersTest, BlendWithGaps) ...@@ -301,6 +301,9 @@ TEST_P(DrawBuffersTest, BlendWithGaps)
// Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616 // Fails on Intel Ubuntu 19.04 Mesa 19.0.2 Vulkan. http://anglebug.com/3616
ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan()); ANGLE_SKIP_TEST_IF(IsLinux() && IsIntel() && IsVulkan());
// http://anglebug.com/5154
ANGLE_SKIP_TEST_IF(IsOSX() && IsIntel() && IsDesktopOpenGL());
glBindTexture(GL_TEXTURE_2D, mTextures[0]); glBindTexture(GL_TEXTURE_2D, mTextures[0]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, mTextures[0], 0);
......
...@@ -8116,12 +8116,12 @@ ANGLE_INSTANTIATE_TEST(Texture2DRGTest, ...@@ -8116,12 +8116,12 @@ ANGLE_INSTANTIATE_TEST(Texture2DRGTest,
ANGLE_INSTANTIATE_TEST_ES3(Texture2DFloatTestES3); ANGLE_INSTANTIATE_TEST_ES3(Texture2DFloatTestES3);
ANGLE_INSTANTIATE_TEST_ES2(Texture2DFloatTestES2); ANGLE_INSTANTIATE_TEST_ES2(Texture2DFloatTestES2);
ANGLE_INSTANTIATE_TEST_ES3(TextureCubeTestES3); ANGLE_INSTANTIATE_TEST_ES3(TextureCubeTestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DIntegerTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DIntegerTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES3(TextureCubeIntegerTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(TextureCubeIntegerTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES3(TextureCubeIntegerEdgeTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(TextureCubeIntegerEdgeTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES3(Texture2DIntegerProjectiveOffsetTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DIntegerProjectiveOffsetTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES3(Texture2DArrayIntegerTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture2DArrayIntegerTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES3(Texture3DIntegerTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND(Texture3DIntegerTestES3, ES3_METAL());
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(Texture2DDepthTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(Texture2DDepthTest);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(PBOCompressedTextureTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(PBOCompressedTextureTest);
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ETC1CompressedTextureTest); ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(ETC1CompressedTextureTest);
......
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