Commit 91004654 by Le Hoang Quyen Committed by Commit Bot

Metal: Implement ANGLE_robust_resource_initialization.

Bug: angleproject:4929 Bug: angleproject:2634 Change-Id: Ib99b810059420e69d939f1bbb644c2b95de62850 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2374826 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com>
parent 9a19a996
...@@ -1143,8 +1143,7 @@ void ContextMtl::endEncoding(bool forceSaveRenderPassContent) ...@@ -1143,8 +1143,7 @@ void ContextMtl::endEncoding(bool forceSaveRenderPassContent)
if (forceSaveRenderPassContent) if (forceSaveRenderPassContent)
{ {
// Save the work in progress. // Save the work in progress.
mRenderEncoder.setColorStoreAction(MTLStoreActionStore); mRenderEncoder.setStoreAction(MTLStoreActionStore);
mRenderEncoder.setDepthStencilStoreAction(MTLStoreActionStore, MTLStoreActionStore);
} }
mRenderEncoder.endEncoding(); mRenderEncoder.endEncoding();
...@@ -1459,9 +1458,7 @@ void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMt ...@@ -1459,9 +1458,7 @@ void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMt
return; return;
} }
updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(), onDrawFrameBufferChangedState(context, framebuffer, true);
glState.getFarPlane());
updateScissor(glState);
} }
void ContextMtl::updateProgramExecutable(const gl::Context *context) void ContextMtl::updateProgramExecutable(const gl::Context *context)
......
...@@ -451,6 +451,9 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context, ...@@ -451,6 +451,9 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context,
{ {
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
bool mustNotifyContext = false; bool mustNotifyContext = false;
// Cache old mRenderPassDesc before update*RenderTarget() invalidate it.
mtl::RenderPassDesc oldRenderPassDesc = mRenderPassDesc;
for (size_t dirtyBit : dirtyBits) for (size_t dirtyBit : dirtyBits)
{ {
switch (dirtyBit) switch (dirtyBit)
...@@ -494,8 +497,6 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context, ...@@ -494,8 +497,6 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context,
} }
} }
auto oldRenderPassDesc = mRenderPassDesc;
ANGLE_TRY(prepareRenderPass(context, &mRenderPassDesc)); ANGLE_TRY(prepareRenderPass(context, &mRenderPassDesc));
bool renderPassChanged = !oldRenderPassDesc.equalIgnoreLoadStoreOptions(mRenderPassDesc); bool renderPassChanged = !oldRenderPassDesc.equalIgnoreLoadStoreOptions(mRenderPassDesc);
...@@ -529,10 +530,16 @@ RenderTargetMtl *FramebufferMtl::getColorReadRenderTarget(const gl::Context *con ...@@ -529,10 +530,16 @@ RenderTargetMtl *FramebufferMtl::getColorReadRenderTarget(const gl::Context *con
if (mBackbuffer) if (mBackbuffer)
{ {
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context))) bool isNewDrawable = false;
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context, &isNewDrawable)))
{ {
return nullptr; return nullptr;
} }
if (isNewDrawable && mBackbuffer->hasRobustResourceInit())
{
(void)mBackbuffer->initializeContents(context, gl::ImageIndex::Make2D(0));
}
} }
return mColorRenderTargets[mState.getReadIndex()]; return mColorRenderTargets[mState.getReadIndex()];
...@@ -563,24 +570,26 @@ mtl::RenderCommandEncoder *FramebufferMtl::ensureRenderPassStarted(const gl::Con ...@@ -563,24 +570,26 @@ mtl::RenderCommandEncoder *FramebufferMtl::ensureRenderPassStarted(const gl::Con
{ {
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
if (renderPassHasStarted(contextMtl))
{
return contextMtl->getRenderCommandEncoder();
}
if (mBackbuffer) if (mBackbuffer)
{ {
// Backbuffer might obtain new drawable, which means it might change the // Backbuffer might obtain new drawable, which means it might change the
// the native texture used as the target of the render pass. // the native texture used as the target of the render pass.
// We need to call this before creating render encoder. // We need to call this before creating render encoder.
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context))) bool isNewDrawable;
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context, &isNewDrawable)))
{ {
return nullptr; return nullptr;
} }
if (isNewDrawable && mBackbuffer->hasRobustResourceInit())
{
// Apply robust resource initialization on newly obtained drawable.
(void)mBackbuffer->initializeContents(context, gl::ImageIndex::Make2D(0));
}
} }
// Only support ensureRenderPassStarted() with different load & store options only. The texture, // Only support ensureRenderPassStarted() with different load & store options only. The
// level, slice must be the same. // texture, level, slice must be the same.
ASSERT(desc.equalIgnoreLoadStoreOptions(mRenderPassDesc)); ASSERT(desc.equalIgnoreLoadStoreOptions(mRenderPassDesc));
mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(desc); mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(desc);
...@@ -929,8 +938,8 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context, ...@@ -929,8 +938,8 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
MTLColorWriteMask colorMask = contextMtl->getColorMask(); clearOpts.clearColorMask = contextMtl->getColorMask();
uint32_t stencilMask = contextMtl->getStencilMask(); uint32_t stencilMask = contextMtl->getStencilMask();
if (!contextMtl->getDepthMask()) if (!contextMtl->getDepthMask())
{ {
// Disable depth clearing, since depth write is disable // Disable depth clearing, since depth write is disable
...@@ -941,7 +950,7 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context, ...@@ -941,7 +950,7 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
clearOpts.enabledBuffers = clearColorBuffers; clearOpts.enabledBuffers = clearColorBuffers;
if (clearOpts.clearArea == renderArea && if (clearOpts.clearArea == renderArea &&
(!clearOpts.clearColor.valid() || colorMask == MTLColorWriteMaskAll) && (!clearOpts.clearColor.valid() || clearOpts.clearColorMask == MTLColorWriteMaskAll) &&
(!clearOpts.clearStencil.valid() || (!clearOpts.clearStencil.valid() ||
(stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll)) (stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll))
{ {
......
...@@ -71,6 +71,8 @@ class SurfaceMtl : public SurfaceImpl ...@@ -71,6 +71,8 @@ class SurfaceMtl : public SurfaceImpl
const mtl::Format &getColorFormat() const { return mColorFormat; } const mtl::Format &getColorFormat() const { return mColorFormat; }
int getSamples() const { return mSamples; } int getSamples() const { return mSamples; }
bool hasRobustResourceInit() const { return mRobustResourceInit; }
angle::Result getAttachmentRenderTarget(const gl::Context *context, angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding, GLenum binding,
const gl::ImageIndex &imageIndex, const gl::ImageIndex &imageIndex,
...@@ -95,6 +97,8 @@ class SurfaceMtl : public SurfaceImpl ...@@ -95,6 +97,8 @@ class SurfaceMtl : public SurfaceImpl
// Auto resolve MS texture at the end of render pass or requires a separate blitting pass? // Auto resolve MS texture at the end of render pass or requires a separate blitting pass?
bool mAutoResolveMSColorTexture = false; bool mAutoResolveMSColorTexture = false;
bool mRobustResourceInit = false;
mtl::Format mColorFormat; mtl::Format mColorFormat;
mtl::Format mDepthFormat; mtl::Format mDepthFormat;
mtl::Format mStencilFormat; mtl::Format mStencilFormat;
...@@ -127,6 +131,9 @@ class WindowSurfaceMtl : public SurfaceMtl ...@@ -127,6 +131,9 @@ class WindowSurfaceMtl : public SurfaceMtl
void setSwapInterval(EGLint interval) override; void setSwapInterval(EGLint interval) override;
EGLint getSwapBehavior() const override; EGLint getSwapBehavior() const override;
angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override;
// width and height can change with client window resizing // width and height can change with client window resizing
EGLint getWidth() const override; EGLint getWidth() const override;
EGLint getHeight() const override; EGLint getHeight() const override;
...@@ -137,7 +144,8 @@ class WindowSurfaceMtl : public SurfaceMtl ...@@ -137,7 +144,8 @@ class WindowSurfaceMtl : public SurfaceMtl
GLsizei samples, GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override; FramebufferAttachmentRenderTarget **rtOut) override;
angle::Result ensureCurrentDrawableObtained(const gl::Context *context); angle::Result ensureCurrentDrawableObtained(const gl::Context *context,
bool *newDrawableOut /** nullable */);
// Ensure the the texture returned from getColorTexture() is ready for glReadPixels(). This // Ensure the the texture returned from getColorTexture() is ready for glReadPixels(). This
// implicitly calls ensureCurrentDrawableObtained(). // implicitly calls ensureCurrentDrawableObtained().
......
...@@ -82,17 +82,21 @@ int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type) ...@@ -82,17 +82,21 @@ int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
return -1; return -1;
} }
angle::Result CreateTexture(const gl::Context *context, angle::Result CreateOrResizeTexture(const gl::Context *context,
const mtl::Format &format, const mtl::Format &format,
uint32_t width, uint32_t width,
uint32_t height, uint32_t height,
uint32_t samples, uint32_t samples,
bool renderTargetOnly, bool renderTargetOnly,
mtl::TextureRef *textureOut) mtl::TextureRef *textureOut)
{ {
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
bool allowFormatView = format.hasDepthAndStencilBits(); bool allowFormatView = format.hasDepthAndStencilBits();
if (samples > 1) if (*textureOut)
{
ANGLE_TRY((*textureOut)->resize(contextMtl, width, height));
}
else if (samples > 1)
{ {
ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, format, width, height, samples, ANGLE_TRY(mtl::Texture::Make2DMSTexture(contextMtl, format, width, height, samples,
/** renderTargetOnly */ renderTargetOnly, /** renderTargetOnly */ renderTargetOnly,
...@@ -247,6 +251,8 @@ SurfaceMtl::SurfaceMtl(DisplayMtl *display, ...@@ -247,6 +251,8 @@ SurfaceMtl::SurfaceMtl(DisplayMtl *display,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
: SurfaceImpl(state) : SurfaceImpl(state)
{ {
mRobustResourceInit =
attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE;
mColorFormat = display->getPixelFormat(angle::FormatID::B8G8R8A8_UNORM); mColorFormat = display->getPixelFormat(angle::FormatID::B8G8R8A8_UNORM);
mSamples = state.config->samples; mSamples = state.config->samples;
...@@ -418,7 +424,32 @@ EGLint SurfaceMtl::getSwapBehavior() const ...@@ -418,7 +424,32 @@ EGLint SurfaceMtl::getSwapBehavior() const
angle::Result SurfaceMtl::initializeContents(const gl::Context *context, angle::Result SurfaceMtl::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) const gl::ImageIndex &imageIndex)
{ {
UNIMPLEMENTED(); ASSERT(mColorTexture);
ContextMtl *contextMtl = mtl::GetImpl(context);
// Use loadAction=clear
mtl::RenderPassDesc rpDesc;
rpDesc.sampleCount = mColorTexture->samples();
rpDesc.numColorAttachments = 1;
mColorRenderTarget.toRenderPassAttachmentDesc(&rpDesc.colorAttachments[0]);
rpDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
MTLClearColor black = {};
rpDesc.colorAttachments[0].clearColor =
mtl::EmulatedAlphaClearColor(black, mColorTexture->getColorWritableMask());
if (mDepthTexture)
{
mDepthRenderTarget.toRenderPassAttachmentDesc(&rpDesc.depthAttachment);
rpDesc.depthAttachment.loadAction = MTLLoadActionClear;
}
if (mStencilTexture)
{
mStencilRenderTarget.toRenderPassAttachmentDesc(&rpDesc.stencilAttachment);
rpDesc.stencilAttachment.loadAction = MTLLoadActionClear;
}
mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(rpDesc);
encoder->setStoreAction(MTLStoreActionStore);
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -461,9 +492,9 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context * ...@@ -461,9 +492,9 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
{ {
mAutoResolveMSColorTexture = mAutoResolveMSColorTexture =
contextMtl->getDisplay()->getFeatures().allowMultisampleStoreAndResolve.enabled; contextMtl->getDisplay()->getFeatures().allowMultisampleStoreAndResolve.enabled;
ANGLE_TRY(CreateTexture(context, mColorFormat, size.width, size.height, mSamples, ANGLE_TRY(CreateOrResizeTexture(context, mColorFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ mAutoResolveMSColorTexture, /** renderTargetOnly */ mAutoResolveMSColorTexture,
&mMSColorTexture)); &mMSColorTexture));
if (mAutoResolveMSColorTexture) if (mAutoResolveMSColorTexture)
{ {
...@@ -478,8 +509,8 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context * ...@@ -478,8 +509,8 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size)) if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size))
{ {
ANGLE_TRY(CreateTexture(context, mDepthFormat, size.width, size.height, mSamples, ANGLE_TRY(CreateOrResizeTexture(context, mDepthFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ false, &mDepthTexture)); /** renderTargetOnly */ false, &mDepthTexture));
mDepthRenderTarget.set(mDepthTexture, 0, 0, mDepthFormat); mDepthRenderTarget.set(mDepthTexture, 0, 0, mDepthFormat);
} }
...@@ -492,8 +523,9 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context * ...@@ -492,8 +523,9 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
} }
else else
{ {
ANGLE_TRY(CreateTexture(context, mStencilFormat, size.width, size.height, mSamples, ANGLE_TRY(CreateOrResizeTexture(context, mStencilFormat, size.width, size.height,
/** renderTargetOnly */ false, &mStencilTexture)); mSamples,
/** renderTargetOnly */ false, &mStencilTexture));
} }
mStencilRenderTarget.set(mStencilTexture, 0, 0, mStencilFormat); mStencilRenderTarget.set(mStencilTexture, 0, 0, mStencilFormat);
...@@ -634,20 +666,40 @@ EGLint WindowSurfaceMtl::getSwapBehavior() const ...@@ -634,20 +666,40 @@ EGLint WindowSurfaceMtl::getSwapBehavior() const
return EGL_BUFFER_DESTROYED; return EGL_BUFFER_DESTROYED;
} }
angle::Result WindowSurfaceMtl::initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex)
{
bool newDrawable;
ANGLE_TRY(ensureCurrentDrawableObtained(context, &newDrawable));
if (!newDrawable)
{
return angle::Result::Continue;
}
return SurfaceMtl::initializeContents(context, imageIndex);
}
angle::Result WindowSurfaceMtl::getAttachmentRenderTarget(const gl::Context *context, angle::Result WindowSurfaceMtl::getAttachmentRenderTarget(const gl::Context *context,
GLenum binding, GLenum binding,
const gl::ImageIndex &imageIndex, const gl::ImageIndex &imageIndex,
GLsizei samples, GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) FramebufferAttachmentRenderTarget **rtOut)
{ {
ANGLE_TRY(ensureCurrentDrawableObtained(context)); ANGLE_TRY(ensureCurrentDrawableObtained(context, nullptr));
ANGLE_TRY(ensureCompanionTexturesSizeCorrect(context)); ANGLE_TRY(ensureCompanionTexturesSizeCorrect(context));
return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut); return SurfaceMtl::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
} }
angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context) angle::Result WindowSurfaceMtl::ensureCurrentDrawableObtained(const gl::Context *context,
bool *newDrawableOut)
{ {
if (newDrawableOut)
{
*newDrawableOut = !mCurrentDrawable;
}
if (!mCurrentDrawable) if (!mCurrentDrawable)
{ {
ANGLE_TRY(obtainNextDrawable(context)); ANGLE_TRY(obtainNextDrawable(context));
...@@ -670,7 +722,7 @@ angle::Result WindowSurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Con ...@@ -670,7 +722,7 @@ angle::Result WindowSurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Con
angle::Result WindowSurfaceMtl::ensureColorTextureReadyForReadPixels(const gl::Context *context) angle::Result WindowSurfaceMtl::ensureColorTextureReadyForReadPixels(const gl::Context *context)
{ {
ANGLE_TRY(ensureCurrentDrawableObtained(context)); ANGLE_TRY(ensureCurrentDrawableObtained(context, nullptr));
if (mMSColorTexture) if (mMSColorTexture)
{ {
...@@ -857,8 +909,8 @@ angle::Result OffscreenSurfaceMtl::ensureTexturesSizeCorrect(const gl::Context * ...@@ -857,8 +909,8 @@ angle::Result OffscreenSurfaceMtl::ensureTexturesSizeCorrect(const gl::Context *
{ {
if (!mColorTexture || mColorTexture->size() != mSize) if (!mColorTexture || mColorTexture->size() != mSize)
{ {
ANGLE_TRY(CreateTexture(context, mColorFormat, mSize.width, mSize.height, 1, ANGLE_TRY(CreateOrResizeTexture(context, mColorFormat, mSize.width, mSize.height, 1,
/** renderTargetOnly */ false, &mColorTexture)); /** renderTargetOnly */ false, &mColorTexture));
mColorRenderTarget.set(mColorTexture, 0, 0, mColorFormat); mColorRenderTarget.set(mColorTexture, 0, 0, mColorFormat);
} }
...@@ -976,7 +1028,9 @@ angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context * ...@@ -976,7 +1028,9 @@ angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context *
if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB) if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB)
{ {
// This format has emulated alpha channel. Initialize texture's alpha channel to 1.0. // This format has emulated alpha channel. Initialize texture's alpha channel to 1.0.
ANGLE_TRY(mtl::InitializeTextureContentsGPU(context, mColorTexture, mColorFormat, const mtl::Format &rgbClearFormat =
contextMtl->getPixelFormat(angle::FormatID::R8G8B8_UNORM);
ANGLE_TRY(mtl::InitializeTextureContentsGPU(context, mColorTexture, rgbClearFormat,
gl::ImageIndex::Make2D(0), gl::ImageIndex::Make2D(0),
MTLColorWriteMaskAlpha)); MTLColorWriteMaskAlpha));
......
...@@ -820,7 +820,9 @@ angle::Result TextureMtl::copyImage(const gl::Context *context, ...@@ -820,7 +820,9 @@ angle::Result TextureMtl::copyImage(const gl::Context *context,
ANGLE_TRY(redefineImage(context, index, mtlFormat, newImageSize)); ANGLE_TRY(redefineImage(context, index, mtlFormat, newImageSize));
if (context->isWebGL()) gl::Extents fbSize = source->getReadColorAttachment()->getSize();
gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
if (context->isWebGL() && !fbRect.encloses(sourceArea))
{ {
ANGLE_TRY(initializeContents(context, index)); ANGLE_TRY(initializeContents(context, index));
} }
...@@ -1258,11 +1260,6 @@ angle::Result TextureMtl::setImageImpl(const gl::Context *context, ...@@ -1258,11 +1260,6 @@ angle::Result TextureMtl::setImageImpl(const gl::Context *context,
return angle::Result::Continue; return angle::Result::Continue;
} }
if (context->isWebGL() && !pixels)
{
ANGLE_TRY(initializeContents(context, index));
}
// Format of the supplied pixels. // Format of the supplied pixels.
const gl::InternalFormat *srcFormatInfo; const gl::InternalFormat *srcFormatInfo;
if (srcFormat != dstFormatInfo.format || srcType != dstFormatInfo.type) if (srcFormat != dstFormatInfo.format || srcType != dstFormatInfo.type)
...@@ -1478,7 +1475,7 @@ angle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context, ...@@ -1478,7 +1475,7 @@ angle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context,
{ {
gl::ImageIndex index = GetSliceMipIndex(texture, layer, mip); gl::ImageIndex index = GetSliceMipIndex(texture, layer, mip);
ANGLE_TRY(mtl::InitializeTextureContents(context, texture, mFormat, index)); ANGLE_TRY(mtl::InitializeTextureContents(context, texture, mtlFormat, index));
} }
} }
} }
...@@ -1488,9 +1485,47 @@ angle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context, ...@@ -1488,9 +1485,47 @@ angle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context,
angle::Result TextureMtl::initializeContents(const gl::Context *context, angle::Result TextureMtl::initializeContents(const gl::Context *context,
const gl::ImageIndex &index) const gl::ImageIndex &index)
{ {
if (index.isLayered())
{
// InitializeTextureContents is only able to initialize one layer at a time.
const gl::ImageDesc &desc = mState.getImageDesc(index);
uint32_t layerCount;
if (index.isEntireLevelCubeMap())
{
layerCount = 6;
}
else
{
layerCount = desc.size.depth;
}
gl::ImageIndexIterator ite = index.getLayerIterator(layerCount);
while (ite.hasNext())
{
gl::ImageIndex layerIndex = ite.next();
ANGLE_TRY(initializeContents(context, layerIndex));
}
return angle::Result::Continue;
}
else if (index.getLayerCount() > 1)
{
for (int layer = 0; layer < index.getLayerCount(); ++layer)
{
int layerIdx = layer + index.getLayerIndex();
gl::ImageIndex layerIndex =
gl::ImageIndex::MakeFromType(index.getType(), index.getLevelIndex(), layerIdx);
ANGLE_TRY(initializeContents(context, layerIndex));
}
return angle::Result::Continue;
}
ASSERT(index.getLayerCount() == 1 && !index.isLayered());
ANGLE_TRY(ensureImageCreated(context, index)); ANGLE_TRY(ensureImageCreated(context, index));
mtl::TextureRef &image = getImage(index); ContextMtl *contextMtl = mtl::GetImpl(context);
return mtl::InitializeTextureContents(context, image, mFormat, GetZeroLevelIndex(image)); ImageDefinitionMtl &imageDef = getImageDefinition(index);
const mtl::TextureRef &image = imageDef.image;
const mtl::Format &format = contextMtl->getPixelFormat(imageDef.formatID);
return mtl::InitializeTextureContents(context, image, format, GetZeroLevelIndex(image));
} }
angle::Result TextureMtl::copySubImageImpl(const gl::Context *context, angle::Result TextureMtl::copySubImageImpl(const gl::Context *context,
......
...@@ -420,6 +420,9 @@ class RenderCommandEncoder final : public CommandEncoder ...@@ -420,6 +420,9 @@ class RenderCommandEncoder final : public CommandEncoder
RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action); RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action);
RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action); RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action);
// Set storeaction for every color & depth & stencil attachment.
RenderCommandEncoder &setStoreAction(MTLStoreAction action);
// Change the render pass's loadAction. Note that this operation is only allowed when there // Change the render pass's loadAction. Note that this operation is only allowed when there
// is no draw call recorded yet. // is no draw call recorded yet.
RenderCommandEncoder &setColorLoadAction(MTLLoadAction action, RenderCommandEncoder &setColorLoadAction(MTLLoadAction action,
......
...@@ -1430,6 +1430,13 @@ RenderCommandEncoder &RenderCommandEncoder::setStencilStoreAction(MTLStoreAction ...@@ -1430,6 +1430,13 @@ RenderCommandEncoder &RenderCommandEncoder::setStencilStoreAction(MTLStoreAction
return *this; return *this;
} }
RenderCommandEncoder &RenderCommandEncoder::setStoreAction(MTLStoreAction action)
{
setColorStoreAction(action);
setDepthStencilStoreAction(action, action);
return *this;
}
RenderCommandEncoder &RenderCommandEncoder::setColorLoadAction(MTLLoadAction action, RenderCommandEncoder &RenderCommandEncoder::setColorLoadAction(MTLLoadAction action,
const MTLClearColor &clearValue, const MTLClearColor &clearValue,
uint32_t colorAttachmentIndex) uint32_t colorAttachmentIndex)
......
...@@ -30,6 +30,8 @@ namespace mtl ...@@ -30,6 +30,8 @@ namespace mtl
{ {
struct ClearRectParams : public ClearOptions struct ClearRectParams : public ClearOptions
{ {
MTLColorWriteMask clearColorMask = MTLColorWriteMaskAll;
gl::Extents dstTextureSize; gl::Extents dstTextureSize;
// Only clear enabled buffers // Only clear enabled buffers
......
...@@ -673,7 +673,7 @@ id<MTLRenderPipelineState> ClearUtils::getClearRenderPipelineState(const gl::Con ...@@ -673,7 +673,7 @@ id<MTLRenderPipelineState> ClearUtils::getClearRenderPipelineState(const gl::Con
{ {
ContextMtl *contextMtl = GetImpl(context); ContextMtl *contextMtl = GetImpl(context);
// The color mask to be applied to every color attachment: // The color mask to be applied to every color attachment:
MTLColorWriteMask globalColorMask = contextMtl->getColorMask(); MTLColorWriteMask globalColorMask = params.clearColorMask;
if (!params.clearColor.valid()) if (!params.clearColor.valid())
{ {
globalColorMask = MTLColorWriteMaskNone; globalColorMask = MTLColorWriteMaskNone;
......
...@@ -188,6 +188,8 @@ class Texture final : public Resource, ...@@ -188,6 +188,8 @@ class Texture final : public Resource,
uint32_t samples() const; uint32_t samples() const;
angle::Result resize(ContextMtl *context, uint32_t width, uint32_t height);
// For render target // For render target
MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; } MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; } void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
...@@ -228,6 +230,8 @@ class Texture final : public Resource, ...@@ -228,6 +230,8 @@ class Texture final : public Resource,
void syncContent(ContextMtl *context); void syncContent(ContextMtl *context);
AutoObjCObj<MTLTextureDescriptor> mCreationDesc;
// This property is shared between this object and its views: // This property is shared between this object and its views:
std::shared_ptr<MTLColorWriteMask> mColorWritableMask; std::shared_ptr<MTLColorWriteMask> mColorWritableMask;
......
...@@ -262,6 +262,8 @@ Texture::Texture(ContextMtl *context, ...@@ -262,6 +262,8 @@ Texture::Texture(ContextMtl *context,
} }
set([[metalDevice newTextureWithDescriptor:desc] ANGLE_MTL_AUTORELEASE]); set([[metalDevice newTextureWithDescriptor:desc] ANGLE_MTL_AUTORELEASE]);
mCreationDesc.retainAssign(desc);
} }
} }
...@@ -542,6 +544,32 @@ uint32_t Texture::samples() const ...@@ -542,6 +544,32 @@ uint32_t Texture::samples() const
return static_cast<uint32_t>(get().sampleCount); return static_cast<uint32_t>(get().sampleCount);
} }
angle::Result Texture::resize(ContextMtl *context, uint32_t width, uint32_t height)
{
// Resizing texture view is not supported.
ASSERT(mCreationDesc);
ANGLE_MTL_OBJC_SCOPE
{
MTLTextureDescriptor *newDesc = [[mCreationDesc.get() copy] ANGLE_MTL_AUTORELEASE];
newDesc.width = width;
newDesc.height = height;
id<MTLTexture> newTexture =
[[get().device newTextureWithDescriptor:newDesc] ANGLE_MTL_AUTORELEASE];
ANGLE_CHECK_GL_ALLOC(context, newTexture);
mCreationDesc.retainAssign(newDesc);
set(newTexture);
// Reset reference counter
Resource::reset();
}
return angle::Result::Continue;
}
TextureRef Texture::getLinearColorView() TextureRef Texture::getLinearColorView()
{ {
if (mLinearColorView) if (mLinearColorView)
......
...@@ -28,7 +28,7 @@ namespace mtl ...@@ -28,7 +28,7 @@ namespace mtl
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
// Initialize texture content to (0, 0, 0, 1) // Initialize texture content to black.
angle::Result InitializeTextureContents(const gl::Context *context, angle::Result InitializeTextureContents(const gl::Context *context,
const TextureRef &texture, const TextureRef &texture,
const Format &textureObjFormat, const Format &textureObjFormat,
...@@ -41,6 +41,12 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context, ...@@ -41,6 +41,12 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit); MTLColorWriteMask channelsToInit);
// Same as above but for a depth/stencil texture.
angle::Result InitializeDepthStencilTextureContentsGPU(const gl::Context *context,
const TextureRef &texture,
const Format &textureObjFormat,
const gl::ImageIndex &index);
// Unified texture's per slice/depth texel reading function // Unified texture's per slice/depth texel reading function
angle::Result ReadTexturePerSliceBytes(const gl::Context *context, angle::Result ReadTexturePerSliceBytes(const gl::Context *context,
const TextureRef &texture, const TextureRef &texture,
......
...@@ -84,7 +84,6 @@ void GetSliceAndDepth(const gl::ImageIndex &index, GLint *layer, GLint *startDep ...@@ -84,7 +84,6 @@ void GetSliceAndDepth(const gl::ImageIndex &index, GLint *layer, GLint *startDep
*startDepth = index.getLayerIndex(); *startDepth = index.getLayerIndex();
break; break;
default: default:
UNREACHABLE();
break; break;
} }
} }
...@@ -104,14 +103,15 @@ angle::Result InitializeTextureContents(const gl::Context *context, ...@@ -104,14 +103,15 @@ angle::Result InitializeTextureContents(const gl::Context *context,
const gl::ImageIndex &index) const gl::ImageIndex &index)
{ {
ASSERT(texture && texture->valid()); ASSERT(texture && texture->valid());
// Only one slice can be initialized at a time.
ASSERT(!index.isLayered() || index.getType() == gl::TextureType::_3D);
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat(); const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat();
// This function is called in many places to initialize the content of a texture. // This function is called in many places to initialize the content of a texture.
// So it's better we do the sanity check here instead of let the callers do it themselves: // So it's better we do the sanity check here instead of let the callers do it themselves:
if (!textureObjFormat.valid() || intendedInternalFormat.compressed || if (!textureObjFormat.valid() || intendedInternalFormat.compressed)
intendedInternalFormat.depthBits > 0 || intendedInternalFormat.stencilBits > 0)
{ {
return angle::Result::Continue; return angle::Result::Continue;
} }
...@@ -181,6 +181,27 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context, ...@@ -181,6 +181,27 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const gl::ImageIndex &index, const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit) MTLColorWriteMask channelsToInit)
{ {
// Only one slice can be initialized at a time.
ASSERT(!index.isLayered() || index.getType() == gl::TextureType::_3D);
if (index.isLayered() && index.getType() == gl::TextureType::_3D)
{
gl::ImageIndexIterator ite = index.getLayerIterator(texture->depth(index.getLevelIndex()));
while (ite.hasNext())
{
gl::ImageIndex depthLayerIndex = ite.next();
ANGLE_TRY(InitializeTextureContentsGPU(context, texture, textureObjFormat,
depthLayerIndex, MTLColorWriteMaskAll));
}
return angle::Result::Continue;
}
if (textureObjFormat.hasDepthOrStencilBits())
{
// Depth stencil texture needs dedicated function.
return InitializeDepthStencilTextureContentsGPU(context, texture, textureObjFormat, index);
}
ContextMtl *contextMtl = mtl::GetImpl(context); ContextMtl *contextMtl = mtl::GetImpl(context);
GLint sliceOrDepth = GetSliceOrDepth(index); GLint sliceOrDepth = GetSliceOrDepth(index);
...@@ -188,37 +209,81 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context, ...@@ -188,37 +209,81 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
RenderTargetMtl tempRtt; RenderTargetMtl tempRtt;
tempRtt.set(texture, index.getLevelIndex(), sliceOrDepth, textureObjFormat); tempRtt.set(texture, index.getLevelIndex(), sliceOrDepth, textureObjFormat);
// temporarily enable color channels requested via channelsToInit. Some emulated format has some MTLClearColor blackColor = {};
// channels write mask disabled when the texture is created. if (!textureObjFormat.intendedAngleFormat().alphaBits)
MTLColorWriteMask oldMask = texture->getColorWritableMask(); {
texture->setColorWritableMask(channelsToInit); // if intended format doesn't have alpha, set it to 1.0.
blackColor.alpha = 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, 1);
encoder = contextMtl->getRenderTargetCommandEncoderWithClear(tempRtt, blackColor); encoder = contextMtl->getRenderTargetCommandEncoderWithClear(tempRtt, blackColor);
} }
else else
{ {
// temporarily enable color channels requested via channelsToInit. Some emulated format has
// some channels write mask disabled when the texture is created.
MTLColorWriteMask oldMask = texture->getColorWritableMask();
texture->setColorWritableMask(channelsToInit);
// 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);
ClearRectParams clearParams; ClearRectParams clearParams;
clearParams.clearColor = {.alpha = 1}; clearParams.clearColor = blackColor;
clearParams.dstTextureSize = texture->size(); clearParams.dstTextureSize = texture->size();
clearParams.enabledBuffers.set(0); clearParams.enabledBuffers.set(0);
clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height()); clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height());
ANGLE_TRY( ANGLE_TRY(
contextMtl->getDisplay()->getUtils().clearWithDraw(context, encoder, clearParams)); contextMtl->getDisplay()->getUtils().clearWithDraw(context, encoder, clearParams));
// Restore texture's intended write mask
texture->setColorWritableMask(oldMask);
}
encoder->setStoreAction(MTLStoreActionStore);
return angle::Result::Continue;
}
angle::Result InitializeDepthStencilTextureContentsGPU(const gl::Context *context,
const TextureRef &texture,
const Format &textureObjFormat,
const gl::ImageIndex &index)
{
// Use clear operation
ContextMtl *contextMtl = mtl::GetImpl(context);
const angle::Format &angleFormat = textureObjFormat.actualAngleFormat();
mtl::RenderPassDesc rpDesc;
uint32_t layer = index.hasLayer() ? index.getLayerIndex() : 0;
rpDesc.sampleCount = texture->samples();
if (angleFormat.depthBits)
{
rpDesc.depthAttachment.texture = texture;
rpDesc.depthAttachment.level = index.getLevelIndex();
rpDesc.depthAttachment.sliceOrDepth = layer;
rpDesc.depthAttachment.loadAction = MTLLoadActionClear;
rpDesc.depthAttachment.clearDepth = 1.0;
} }
ANGLE_UNUSED_VARIABLE(encoder); if (angleFormat.stencilBits)
{
rpDesc.stencilAttachment.texture = texture;
rpDesc.stencilAttachment.level = index.getLevelIndex();
rpDesc.stencilAttachment.sliceOrDepth = layer;
rpDesc.stencilAttachment.loadAction = MTLLoadActionClear;
}
// End current render pass
contextMtl->endEncoding(true); contextMtl->endEncoding(true);
// Restore texture's intended write mask RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(rpDesc);
texture->setColorWritableMask(oldMask); encoder->setStoreAction(MTLStoreActionStore);
return angle::Result::Continue; return angle::Result::Continue;
} }
......
...@@ -211,23 +211,11 @@ class RobustResourceInitTest : public ANGLETest ...@@ -211,23 +211,11 @@ class RobustResourceInitTest : public ANGLETest
bool hasGLExtension() bool hasGLExtension()
{ {
// The extension is exposed in metal, but not actually implemented yet
// (http://anglebug.com/4929)
if (IsMetal())
{
return false;
}
return IsGLExtensionEnabled("GL_ANGLE_robust_resource_initialization"); return IsGLExtensionEnabled("GL_ANGLE_robust_resource_initialization");
} }
bool hasEGLExtension() bool hasEGLExtension()
{ {
// The extension is exposed in metal, but not actually implemented yet
// (http://anglebug.com/4929)
if (IsMetal())
{
return false;
}
return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
"EGL_ANGLE_robust_resource_initialization"); "EGL_ANGLE_robust_resource_initialization");
} }
...@@ -324,8 +312,8 @@ class RobustResourceInitTestES31 : public RobustResourceInitTest ...@@ -324,8 +312,8 @@ class RobustResourceInitTestES31 : public RobustResourceInitTest
// it only works on the implemented renderers // it only works on the implemented renderers
TEST_P(RobustResourceInitTest, ExpectedRendererSupport) TEST_P(RobustResourceInitTest, ExpectedRendererSupport)
{ {
bool shouldHaveSupport = bool shouldHaveSupport = IsD3D11() || IsD3D11_FL93() || IsD3D9() || IsOpenGL() ||
IsD3D11() || IsD3D11_FL93() || IsD3D9() || IsOpenGL() || IsOpenGLES() || IsVulkan(); IsOpenGLES() || IsVulkan() || IsMetal();
EXPECT_EQ(shouldHaveSupport, hasGLExtension()); EXPECT_EQ(shouldHaveSupport, hasGLExtension());
EXPECT_EQ(shouldHaveSupport, hasEGLExtension()); EXPECT_EQ(shouldHaveSupport, hasEGLExtension());
EXPECT_EQ(shouldHaveSupport, hasRobustSurfaceInit()); EXPECT_EQ(shouldHaveSupport, hasRobustSurfaceInit());
...@@ -1681,16 +1669,14 @@ void RobustResourceInitTest::copyTexSubImage2DCustomFBOTest(int offsetX, int off ...@@ -1681,16 +1669,14 @@ void RobustResourceInitTest::copyTexSubImage2DCustomFBOTest(int offsetX, int off
// Test CopyTexSubImage2D clipped to size of custom FBO, zero x/y source offset. // Test CopyTexSubImage2D clipped to size of custom FBO, zero x/y source offset.
TEST_P(RobustResourceInitTest, CopyTexSubImage2DCustomFBOZeroOffsets) TEST_P(RobustResourceInitTest, CopyTexSubImage2DCustomFBOZeroOffsets)
{ {
// TODO(anglebug.com/4507): pass this test on the Metal backend. ANGLE_SKIP_TEST_IF(!hasGLExtension());
ANGLE_SKIP_TEST_IF(IsMetal());
copyTexSubImage2DCustomFBOTest(0, 0); copyTexSubImage2DCustomFBOTest(0, 0);
} }
// Test CopyTexSubImage2D clipped to size of custom FBO, negative x/y source offset. // Test CopyTexSubImage2D clipped to size of custom FBO, negative x/y source offset.
TEST_P(RobustResourceInitTest, CopyTexSubImage2DCustomFBONegativeOffsets) TEST_P(RobustResourceInitTest, CopyTexSubImage2DCustomFBONegativeOffsets)
{ {
// TODO(anglebug.com/4507): pass this test on the Metal backend. ANGLE_SKIP_TEST_IF(!hasGLExtension());
ANGLE_SKIP_TEST_IF(IsMetal());
copyTexSubImage2DCustomFBOTest(-8, -8); copyTexSubImage2DCustomFBOTest(-8, -8);
} }
...@@ -1920,22 +1906,34 @@ TEST_P(RobustResourceInitTest, SurfaceInitializedAfterSwap) ...@@ -1920,22 +1906,34 @@ TEST_P(RobustResourceInitTest, SurfaceInitializedAfterSwap)
GLColor::red, GLColor::red,
GLColor::yellow, GLColor::yellow,
}}; }};
if (swapBehaviour != EGL_BUFFER_PRESERVED)
{
checkFramebufferNonZeroPixels(0, 0, 0, 0, GLColor::black);
}
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, 1, 1);
for (size_t i = 0; i < clearColors.size(); i++) for (size_t i = 0; i < clearColors.size(); i++)
{ {
if (swapBehaviour == EGL_BUFFER_PRESERVED && i > 0) if (swapBehaviour == EGL_BUFFER_PRESERVED && i > 0)
{ {
EXPECT_PIXEL_COLOR_EQ(0, 0, clearColors[i - 1]); EXPECT_PIXEL_COLOR_EQ(0, 0, clearColors[i - 1]);
} }
else
{
checkFramebufferNonZeroPixels(0, 0, 0, 0, GLColor::black);
}
angle::Vector4 clearColor = clearColors[i].toNormalizedVector(); angle::Vector4 clearColor = clearColors[i].toNormalizedVector();
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
EXPECT_GL_NO_ERROR(); EXPECT_GL_NO_ERROR();
if (swapBehaviour != EGL_BUFFER_PRESERVED)
{
// Only scissored area (0, 0, 1, 1) has clear color.
// The rest should be robust initialized.
checkFramebufferNonZeroPixels(0, 0, 1, 1, clearColors[i]);
}
swapBuffers(); swapBuffers();
} }
} }
...@@ -2106,8 +2104,7 @@ TEST_P(RobustResourceInitTestES3, InitializeMultisampledDepthRenderbufferAfterCo ...@@ -2106,8 +2104,7 @@ TEST_P(RobustResourceInitTestES3, InitializeMultisampledDepthRenderbufferAfterCo
// Corner case for robust resource init: CopyTexImage to a cube map. // Corner case for robust resource init: CopyTexImage to a cube map.
TEST_P(RobustResourceInitTest, CopyTexImageToOffsetCubeMap) TEST_P(RobustResourceInitTest, CopyTexImageToOffsetCubeMap)
{ {
// http://anglebug.com/4549 ANGLE_SKIP_TEST_IF(!hasGLExtension());
ANGLE_SKIP_TEST_IF(IsMetal());
constexpr GLuint kSize = 2; constexpr GLuint kSize = 2;
......
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