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)
if (forceSaveRenderPassContent)
{
// Save the work in progress.
mRenderEncoder.setColorStoreAction(MTLStoreActionStore);
mRenderEncoder.setDepthStencilStoreAction(MTLStoreActionStore, MTLStoreActionStore);
mRenderEncoder.setStoreAction(MTLStoreActionStore);
}
mRenderEncoder.endEncoding();
......@@ -1459,9 +1458,7 @@ void ContextMtl::onBackbufferResized(const gl::Context *context, WindowSurfaceMt
return;
}
updateViewport(framebuffer, glState.getViewport(), glState.getNearPlane(),
glState.getFarPlane());
updateScissor(glState);
onDrawFrameBufferChangedState(context, framebuffer, true);
}
void ContextMtl::updateProgramExecutable(const gl::Context *context)
......
......@@ -451,6 +451,9 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context,
{
ContextMtl *contextMtl = mtl::GetImpl(context);
bool mustNotifyContext = false;
// Cache old mRenderPassDesc before update*RenderTarget() invalidate it.
mtl::RenderPassDesc oldRenderPassDesc = mRenderPassDesc;
for (size_t dirtyBit : dirtyBits)
{
switch (dirtyBit)
......@@ -494,8 +497,6 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context,
}
}
auto oldRenderPassDesc = mRenderPassDesc;
ANGLE_TRY(prepareRenderPass(context, &mRenderPassDesc));
bool renderPassChanged = !oldRenderPassDesc.equalIgnoreLoadStoreOptions(mRenderPassDesc);
......@@ -529,10 +530,16 @@ RenderTargetMtl *FramebufferMtl::getColorReadRenderTarget(const gl::Context *con
if (mBackbuffer)
{
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context)))
bool isNewDrawable = false;
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context, &isNewDrawable)))
{
return nullptr;
}
if (isNewDrawable && mBackbuffer->hasRobustResourceInit())
{
(void)mBackbuffer->initializeContents(context, gl::ImageIndex::Make2D(0));
}
}
return mColorRenderTargets[mState.getReadIndex()];
......@@ -563,24 +570,26 @@ mtl::RenderCommandEncoder *FramebufferMtl::ensureRenderPassStarted(const gl::Con
{
ContextMtl *contextMtl = mtl::GetImpl(context);
if (renderPassHasStarted(contextMtl))
{
return contextMtl->getRenderCommandEncoder();
}
if (mBackbuffer)
{
// Backbuffer might obtain new drawable, which means it might change the
// the native texture used as the target of the render pass.
// We need to call this before creating render encoder.
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context)))
bool isNewDrawable;
if (IsError(mBackbuffer->ensureCurrentDrawableObtained(context, &isNewDrawable)))
{
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,
// level, slice must be the same.
// Only support ensureRenderPassStarted() with different load & store options only. The
// texture, level, slice must be the same.
ASSERT(desc.equalIgnoreLoadStoreOptions(mRenderPassDesc));
mtl::RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(desc);
......@@ -929,8 +938,8 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
return angle::Result::Continue;
}
MTLColorWriteMask colorMask = contextMtl->getColorMask();
uint32_t stencilMask = contextMtl->getStencilMask();
clearOpts.clearColorMask = contextMtl->getColorMask();
uint32_t stencilMask = contextMtl->getStencilMask();
if (!contextMtl->getDepthMask())
{
// Disable depth clearing, since depth write is disable
......@@ -941,7 +950,7 @@ angle::Result FramebufferMtl::clearImpl(const gl::Context *context,
clearOpts.enabledBuffers = clearColorBuffers;
if (clearOpts.clearArea == renderArea &&
(!clearOpts.clearColor.valid() || colorMask == MTLColorWriteMaskAll) &&
(!clearOpts.clearColor.valid() || clearOpts.clearColorMask == MTLColorWriteMaskAll) &&
(!clearOpts.clearStencil.valid() ||
(stencilMask & mtl::kStencilMaskAll) == mtl::kStencilMaskAll))
{
......
......@@ -71,6 +71,8 @@ class SurfaceMtl : public SurfaceImpl
const mtl::Format &getColorFormat() const { return mColorFormat; }
int getSamples() const { return mSamples; }
bool hasRobustResourceInit() const { return mRobustResourceInit; }
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
......@@ -95,6 +97,8 @@ class SurfaceMtl : public SurfaceImpl
// Auto resolve MS texture at the end of render pass or requires a separate blitting pass?
bool mAutoResolveMSColorTexture = false;
bool mRobustResourceInit = false;
mtl::Format mColorFormat;
mtl::Format mDepthFormat;
mtl::Format mStencilFormat;
......@@ -127,6 +131,9 @@ class WindowSurfaceMtl : public SurfaceMtl
void setSwapInterval(EGLint interval) 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
EGLint getWidth() const override;
EGLint getHeight() const override;
......@@ -137,7 +144,8 @@ class WindowSurfaceMtl : public SurfaceMtl
GLsizei samples,
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
// implicitly calls ensureCurrentDrawableObtained().
......
......@@ -82,17 +82,21 @@ int FindIOSurfaceFormatIndex(GLenum internalFormat, GLenum type)
return -1;
}
angle::Result CreateTexture(const gl::Context *context,
const mtl::Format &format,
uint32_t width,
uint32_t height,
uint32_t samples,
bool renderTargetOnly,
mtl::TextureRef *textureOut)
angle::Result CreateOrResizeTexture(const gl::Context *context,
const mtl::Format &format,
uint32_t width,
uint32_t height,
uint32_t samples,
bool renderTargetOnly,
mtl::TextureRef *textureOut)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
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,
/** renderTargetOnly */ renderTargetOnly,
......@@ -247,6 +251,8 @@ SurfaceMtl::SurfaceMtl(DisplayMtl *display,
const egl::AttributeMap &attribs)
: SurfaceImpl(state)
{
mRobustResourceInit =
attribs.get(EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE, EGL_FALSE) == EGL_TRUE;
mColorFormat = display->getPixelFormat(angle::FormatID::B8G8R8A8_UNORM);
mSamples = state.config->samples;
......@@ -418,7 +424,32 @@ EGLint SurfaceMtl::getSwapBehavior() const
angle::Result SurfaceMtl::initializeContents(const gl::Context *context,
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;
}
......@@ -461,9 +492,9 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
{
mAutoResolveMSColorTexture =
contextMtl->getDisplay()->getFeatures().allowMultisampleStoreAndResolve.enabled;
ANGLE_TRY(CreateTexture(context, mColorFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ mAutoResolveMSColorTexture,
&mMSColorTexture));
ANGLE_TRY(CreateOrResizeTexture(context, mColorFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ mAutoResolveMSColorTexture,
&mMSColorTexture));
if (mAutoResolveMSColorTexture)
{
......@@ -478,8 +509,8 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
if (mDepthFormat.valid() && (!mDepthTexture || mDepthTexture->size() != size))
{
ANGLE_TRY(CreateTexture(context, mDepthFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ false, &mDepthTexture));
ANGLE_TRY(CreateOrResizeTexture(context, mDepthFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ false, &mDepthTexture));
mDepthRenderTarget.set(mDepthTexture, 0, 0, mDepthFormat);
}
......@@ -492,8 +523,9 @@ angle::Result SurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Context *
}
else
{
ANGLE_TRY(CreateTexture(context, mStencilFormat, size.width, size.height, mSamples,
/** renderTargetOnly */ false, &mStencilTexture));
ANGLE_TRY(CreateOrResizeTexture(context, mStencilFormat, size.width, size.height,
mSamples,
/** renderTargetOnly */ false, &mStencilTexture));
}
mStencilRenderTarget.set(mStencilTexture, 0, 0, mStencilFormat);
......@@ -634,20 +666,40 @@ EGLint WindowSurfaceMtl::getSwapBehavior() const
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,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut)
{
ANGLE_TRY(ensureCurrentDrawableObtained(context));
ANGLE_TRY(ensureCurrentDrawableObtained(context, nullptr));
ANGLE_TRY(ensureCompanionTexturesSizeCorrect(context));
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)
{
ANGLE_TRY(obtainNextDrawable(context));
......@@ -670,7 +722,7 @@ angle::Result WindowSurfaceMtl::ensureCompanionTexturesSizeCorrect(const gl::Con
angle::Result WindowSurfaceMtl::ensureColorTextureReadyForReadPixels(const gl::Context *context)
{
ANGLE_TRY(ensureCurrentDrawableObtained(context));
ANGLE_TRY(ensureCurrentDrawableObtained(context, nullptr));
if (mMSColorTexture)
{
......@@ -857,8 +909,8 @@ angle::Result OffscreenSurfaceMtl::ensureTexturesSizeCorrect(const gl::Context *
{
if (!mColorTexture || mColorTexture->size() != mSize)
{
ANGLE_TRY(CreateTexture(context, mColorFormat, mSize.width, mSize.height, 1,
/** renderTargetOnly */ false, &mColorTexture));
ANGLE_TRY(CreateOrResizeTexture(context, mColorFormat, mSize.width, mSize.height, 1,
/** renderTargetOnly */ false, &mColorTexture));
mColorRenderTarget.set(mColorTexture, 0, 0, mColorFormat);
}
......@@ -976,7 +1028,9 @@ angle::Result IOSurfaceSurfaceMtl::ensureColorTextureCreated(const gl::Context *
if (kIOSurfaceFormats[mIOSurfaceFormatIdx].internalFormat == GL_RGB)
{
// This format has emulated alpha channel. Initialize texture's alpha channel to 1.0.
ANGLE_TRY(mtl::InitializeTextureContentsGPU(context, mColorTexture, mColorFormat,
const mtl::Format &rgbClearFormat =
contextMtl->getPixelFormat(angle::FormatID::R8G8B8_UNORM);
ANGLE_TRY(mtl::InitializeTextureContentsGPU(context, mColorTexture, rgbClearFormat,
gl::ImageIndex::Make2D(0),
MTLColorWriteMaskAlpha));
......
......@@ -820,7 +820,9 @@ angle::Result TextureMtl::copyImage(const gl::Context *context,
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));
}
......@@ -1258,11 +1260,6 @@ angle::Result TextureMtl::setImageImpl(const gl::Context *context,
return angle::Result::Continue;
}
if (context->isWebGL() && !pixels)
{
ANGLE_TRY(initializeContents(context, index));
}
// Format of the supplied pixels.
const gl::InternalFormat *srcFormatInfo;
if (srcFormat != dstFormatInfo.format || srcType != dstFormatInfo.type)
......@@ -1478,7 +1475,7 @@ angle::Result TextureMtl::checkForEmulatedChannels(const gl::Context *context,
{
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,
angle::Result TextureMtl::initializeContents(const gl::Context *context,
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));
mtl::TextureRef &image = getImage(index);
return mtl::InitializeTextureContents(context, image, mFormat, GetZeroLevelIndex(image));
ContextMtl *contextMtl = mtl::GetImpl(context);
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,
......
......@@ -420,6 +420,9 @@ class RenderCommandEncoder final : public CommandEncoder
RenderCommandEncoder &setDepthStoreAction(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
// is no draw call recorded yet.
RenderCommandEncoder &setColorLoadAction(MTLLoadAction action,
......
......@@ -1430,6 +1430,13 @@ RenderCommandEncoder &RenderCommandEncoder::setStencilStoreAction(MTLStoreAction
return *this;
}
RenderCommandEncoder &RenderCommandEncoder::setStoreAction(MTLStoreAction action)
{
setColorStoreAction(action);
setDepthStencilStoreAction(action, action);
return *this;
}
RenderCommandEncoder &RenderCommandEncoder::setColorLoadAction(MTLLoadAction action,
const MTLClearColor &clearValue,
uint32_t colorAttachmentIndex)
......
......@@ -30,6 +30,8 @@ namespace mtl
{
struct ClearRectParams : public ClearOptions
{
MTLColorWriteMask clearColorMask = MTLColorWriteMaskAll;
gl::Extents dstTextureSize;
// Only clear enabled buffers
......
......@@ -673,7 +673,7 @@ id<MTLRenderPipelineState> ClearUtils::getClearRenderPipelineState(const gl::Con
{
ContextMtl *contextMtl = GetImpl(context);
// The color mask to be applied to every color attachment:
MTLColorWriteMask globalColorMask = contextMtl->getColorMask();
MTLColorWriteMask globalColorMask = params.clearColorMask;
if (!params.clearColor.valid())
{
globalColorMask = MTLColorWriteMaskNone;
......
......@@ -188,6 +188,8 @@ class Texture final : public Resource,
uint32_t samples() const;
angle::Result resize(ContextMtl *context, uint32_t width, uint32_t height);
// For render target
MTLColorWriteMask getColorWritableMask() const { return *mColorWritableMask; }
void setColorWritableMask(MTLColorWriteMask mask) { *mColorWritableMask = mask; }
......@@ -228,6 +230,8 @@ class Texture final : public Resource,
void syncContent(ContextMtl *context);
AutoObjCObj<MTLTextureDescriptor> mCreationDesc;
// This property is shared between this object and its views:
std::shared_ptr<MTLColorWriteMask> mColorWritableMask;
......
......@@ -262,6 +262,8 @@ Texture::Texture(ContextMtl *context,
}
set([[metalDevice newTextureWithDescriptor:desc] ANGLE_MTL_AUTORELEASE]);
mCreationDesc.retainAssign(desc);
}
}
......@@ -542,6 +544,32 @@ uint32_t Texture::samples() const
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()
{
if (mLinearColorView)
......
......@@ -28,7 +28,7 @@ namespace mtl
NS_ASSUME_NONNULL_BEGIN
// Initialize texture content to (0, 0, 0, 1)
// Initialize texture content to black.
angle::Result InitializeTextureContents(const gl::Context *context,
const TextureRef &texture,
const Format &textureObjFormat,
......@@ -41,6 +41,12 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const gl::ImageIndex &index,
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
angle::Result ReadTexturePerSliceBytes(const gl::Context *context,
const TextureRef &texture,
......
......@@ -84,7 +84,6 @@ void GetSliceAndDepth(const gl::ImageIndex &index, GLint *layer, GLint *startDep
*startDepth = index.getLayerIndex();
break;
default:
UNREACHABLE();
break;
}
}
......@@ -104,14 +103,15 @@ angle::Result InitializeTextureContents(const gl::Context *context,
const gl::ImageIndex &index)
{
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);
const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat();
// 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:
if (!textureObjFormat.valid() || intendedInternalFormat.compressed ||
intendedInternalFormat.depthBits > 0 || intendedInternalFormat.stencilBits > 0)
if (!textureObjFormat.valid() || intendedInternalFormat.compressed)
{
return angle::Result::Continue;
}
......@@ -181,6 +181,27 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const gl::ImageIndex &index,
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);
GLint sliceOrDepth = GetSliceOrDepth(index);
......@@ -188,37 +209,81 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
RenderTargetMtl tempRtt;
tempRtt.set(texture, index.getLevelIndex(), sliceOrDepth, textureObjFormat);
// 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);
MTLClearColor blackColor = {};
if (!textureObjFormat.intendedAngleFormat().alphaBits)
{
// if intended format doesn't have alpha, set it to 1.0.
blackColor.alpha = kEmulatedAlphaValue;
}
RenderCommandEncoder *encoder;
if (channelsToInit == MTLColorWriteMaskAll)
{
// If all channels will be initialized, use clear loadOp.
Optional<MTLClearColor> blackColor = MTLClearColorMake(0, 0, 0, 1);
encoder = contextMtl->getRenderTargetCommandEncoderWithClear(tempRtt, blackColor);
}
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.
encoder = contextMtl->getRenderTargetCommandEncoder(tempRtt);
ClearRectParams clearParams;
clearParams.clearColor = {.alpha = 1};
clearParams.clearColor = blackColor;
clearParams.dstTextureSize = texture->size();
clearParams.enabledBuffers.set(0);
clearParams.clearArea = gl::Rectangle(0, 0, texture->width(), texture->height());
ANGLE_TRY(
contextMtl->getDisplay()->getUtils().clearWithDraw(context, encoder, clearParams));
// 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);
// Restore texture's intended write mask
texture->setColorWritableMask(oldMask);
RenderCommandEncoder *encoder = contextMtl->getRenderPassCommandEncoder(rpDesc);
encoder->setStoreAction(MTLStoreActionStore);
return angle::Result::Continue;
}
......
......@@ -211,23 +211,11 @@ class RobustResourceInitTest : public ANGLETest
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");
}
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(),
"EGL_ANGLE_robust_resource_initialization");
}
......@@ -324,8 +312,8 @@ class RobustResourceInitTestES31 : public RobustResourceInitTest
// it only works on the implemented renderers
TEST_P(RobustResourceInitTest, ExpectedRendererSupport)
{
bool shouldHaveSupport =
IsD3D11() || IsD3D11_FL93() || IsD3D9() || IsOpenGL() || IsOpenGLES() || IsVulkan();
bool shouldHaveSupport = IsD3D11() || IsD3D11_FL93() || IsD3D9() || IsOpenGL() ||
IsOpenGLES() || IsVulkan() || IsMetal();
EXPECT_EQ(shouldHaveSupport, hasGLExtension());
EXPECT_EQ(shouldHaveSupport, hasEGLExtension());
EXPECT_EQ(shouldHaveSupport, hasRobustSurfaceInit());
......@@ -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_P(RobustResourceInitTest, CopyTexSubImage2DCustomFBOZeroOffsets)
{
// TODO(anglebug.com/4507): pass this test on the Metal backend.
ANGLE_SKIP_TEST_IF(IsMetal());
ANGLE_SKIP_TEST_IF(!hasGLExtension());
copyTexSubImage2DCustomFBOTest(0, 0);
}
// Test CopyTexSubImage2D clipped to size of custom FBO, negative x/y source offset.
TEST_P(RobustResourceInitTest, CopyTexSubImage2DCustomFBONegativeOffsets)
{
// TODO(anglebug.com/4507): pass this test on the Metal backend.
ANGLE_SKIP_TEST_IF(IsMetal());
ANGLE_SKIP_TEST_IF(!hasGLExtension());
copyTexSubImage2DCustomFBOTest(-8, -8);
}
......@@ -1920,22 +1906,34 @@ TEST_P(RobustResourceInitTest, SurfaceInitializedAfterSwap)
GLColor::red,
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++)
{
if (swapBehaviour == EGL_BUFFER_PRESERVED && i > 0)
{
EXPECT_PIXEL_COLOR_EQ(0, 0, clearColors[i - 1]);
}
else
{
checkFramebufferNonZeroPixels(0, 0, 0, 0, GLColor::black);
}
angle::Vector4 clearColor = clearColors[i].toNormalizedVector();
glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
glClear(GL_COLOR_BUFFER_BIT);
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();
}
}
......@@ -2106,8 +2104,7 @@ TEST_P(RobustResourceInitTestES3, InitializeMultisampledDepthRenderbufferAfterCo
// Corner case for robust resource init: CopyTexImage to a cube map.
TEST_P(RobustResourceInitTest, CopyTexImageToOffsetCubeMap)
{
// http://anglebug.com/4549
ANGLE_SKIP_TEST_IF(IsMetal());
ANGLE_SKIP_TEST_IF(!hasGLExtension());
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