Commit 05af7590 by Le Hoang Quyen Committed by Commit Bot

Metal: Fix FramebufferMtl's read-after-delete

Due to late verification, ContextMtl might call onFinishedDrawingToFrameBuffer() on a deleted framebuffer object inside syncState() Fix: - Switch to call onStartedDrawingToFrameBuffer() on new FBO instead of calling onFinishedDrawingToFrameBuffer() on old (and possibly deleted) FBO. - Also discard framebuffer only takes effect per render pass. The discard flag will be reset when render pass starts. Bug: angleproject:4144 Change-Id: I7c6c96862892f1c241ce4af3b61862fa4b710a94 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1924101 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarJonah Ryan-Davis <jonahr@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 7c95d081
...@@ -363,6 +363,12 @@ class ContextMtl : public ContextImpl, public mtl::Context ...@@ -363,6 +363,12 @@ class ContextMtl : public ContextImpl, public mtl::Context
VertexArrayMtl *mVertexArray = nullptr; VertexArrayMtl *mVertexArray = nullptr;
ProgramMtl *mProgram = nullptr; ProgramMtl *mProgram = nullptr;
// Special flag to indicate current draw framebuffer is default framebuffer.
// We need this instead of calling mDrawFramebuffer->getState().isDefault() because
// mDrawFramebuffer might point to a deleted object, ContextMtl only knows about this very late,
// only during syncState() function call.
bool mDrawFramebufferIsDefault = true;
using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>; using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>;
gl::AttributesMask mDirtyDefaultAttribsMask; gl::AttributesMask mDirtyDefaultAttribsMask;
......
...@@ -663,7 +663,7 @@ ProgramImpl *ContextMtl::createProgram(const gl::ProgramState &state) ...@@ -663,7 +663,7 @@ ProgramImpl *ContextMtl::createProgram(const gl::ProgramState &state)
// Framebuffer creation // Framebuffer creation
FramebufferImpl *ContextMtl::createFramebuffer(const gl::FramebufferState &state) FramebufferImpl *ContextMtl::createFramebuffer(const gl::FramebufferState &state)
{ {
return new FramebufferMtl(state, false, false); return new FramebufferMtl(state, false);
} }
// Texture creation // Texture creation
...@@ -937,9 +937,16 @@ void ContextMtl::present(const gl::Context *context, id<CAMetalDrawable> present ...@@ -937,9 +937,16 @@ void ContextMtl::present(const gl::Context *context, id<CAMetalDrawable> present
{ {
ensureCommandBufferValid(); ensureCommandBufferValid();
if (hasStartedRenderPass(mDrawFramebuffer)) // Always discard default FBO's depth stencil buffers at the end of the frame:
if (mDrawFramebufferIsDefault && hasStartedRenderPass(mDrawFramebuffer))
{ {
mDrawFramebuffer->onFinishedDrawingToFrameBuffer(context, &mRenderEncoder); constexpr GLenum dsAttachments[] = {GL_DEPTH, GL_STENCIL};
(void)mDrawFramebuffer->invalidate(context, 2, dsAttachments);
endEncoding(false);
// Reset discard flag by notify framebuffer that a new render pass has started.
mDrawFramebuffer->onStartedDrawingToFrameBuffer(context);
} }
endEncoding(false); endEncoding(false);
...@@ -1172,14 +1179,10 @@ void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context) ...@@ -1172,14 +1179,10 @@ void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context)
{ {
const gl::State &glState = getState(); const gl::State &glState = getState();
auto oldFrameBuffer = mDrawFramebuffer; mDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
mDrawFramebufferIsDefault = mDrawFramebuffer->getState().isDefault();
mDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
if (oldFrameBuffer && hasStartedRenderPass(oldFrameBuffer->getRenderPassDesc(this))) mDrawFramebuffer->onStartedDrawingToFrameBuffer(context);
{
oldFrameBuffer->onFinishedDrawingToFrameBuffer(context, &mRenderEncoder);
}
onDrawFrameBufferChange(context, mDrawFramebuffer); onDrawFrameBufferChange(context, mDrawFramebuffer);
} }
......
...@@ -24,9 +24,7 @@ class SurfaceMtl; ...@@ -24,9 +24,7 @@ class SurfaceMtl;
class FramebufferMtl : public FramebufferImpl class FramebufferMtl : public FramebufferImpl
{ {
public: public:
explicit FramebufferMtl(const gl::FramebufferState &state, explicit FramebufferMtl(const gl::FramebufferState &state, bool flipY);
bool flipY,
bool alwaysDiscardDepthStencil);
~FramebufferMtl() override; ~FramebufferMtl() override;
void destroy(const gl::Context *context) override; void destroy(const gl::Context *context) override;
...@@ -91,9 +89,8 @@ class FramebufferMtl : public FramebufferImpl ...@@ -91,9 +89,8 @@ class FramebufferMtl : public FramebufferImpl
const mtl::RenderPassDesc &getRenderPassDesc(ContextMtl *context); const mtl::RenderPassDesc &getRenderPassDesc(ContextMtl *context);
// Call this to notify FramebufferMtl whenever its render pass has ended. // Call this to notify FramebufferMtl whenever its render pass has started.
void onFinishedDrawingToFrameBuffer(const gl::Context *context, void onStartedDrawingToFrameBuffer(const gl::Context *context);
mtl::RenderCommandEncoder *encoder);
// The actual area will be adjusted based on framebuffer flipping property. // The actual area will be adjusted based on framebuffer flipping property.
gl::Rectangle getReadPixelArea(const gl::Rectangle &glArea); gl::Rectangle getReadPixelArea(const gl::Rectangle &glArea);
...@@ -140,13 +137,9 @@ class FramebufferMtl : public FramebufferImpl ...@@ -140,13 +137,9 @@ class FramebufferMtl : public FramebufferImpl
// depth & stencil attachments as of now. Separate depth & stencil could be useful to // depth & stencil attachments as of now. Separate depth & stencil could be useful to
// save spaces on iOS devices. See doc/PackedDepthStencilSupport.md. // save spaces on iOS devices. See doc/PackedDepthStencilSupport.md.
std::array<RenderTargetMtl *, mtl::kMaxRenderTargets> mColorRenderTargets; std::array<RenderTargetMtl *, mtl::kMaxRenderTargets> mColorRenderTargets;
std::array<bool, mtl::kMaxRenderTargets> mDiscardColors;
RenderTargetMtl *mDepthRenderTarget = nullptr; RenderTargetMtl *mDepthRenderTarget = nullptr;
bool mDiscardDepth = false;
RenderTargetMtl *mStencilRenderTarget = nullptr; RenderTargetMtl *mStencilRenderTarget = nullptr;
bool mDiscardStencil = false;
mtl::RenderPassDesc mRenderPassDesc; mtl::RenderPassDesc mRenderPassDesc;
const bool mAlwaysDiscardDepthStencil;
const bool mFlipY = false; const bool mFlipY = false;
}; };
} // namespace rx } // namespace rx
......
...@@ -45,8 +45,8 @@ const gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context, ...@@ -45,8 +45,8 @@ const gl::InternalFormat &GetReadAttachmentInfo(const gl::Context *context,
} }
// FramebufferMtl implementation // FramebufferMtl implementation
FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state, bool flipY, bool alwaysDiscard) FramebufferMtl::FramebufferMtl(const gl::FramebufferState &state, bool flipY)
: FramebufferImpl(state), mAlwaysDiscardDepthStencil(alwaysDiscard), mFlipY(flipY) : FramebufferImpl(state), mFlipY(flipY)
{ {
reset(); reset();
} }
...@@ -59,12 +59,7 @@ void FramebufferMtl::reset() ...@@ -59,12 +59,7 @@ void FramebufferMtl::reset()
{ {
rt = nullptr; rt = nullptr;
} }
for (auto &discardColor : mDiscardColors)
{
discardColor = false;
}
mDepthRenderTarget = mStencilRenderTarget = nullptr; mDepthRenderTarget = mStencilRenderTarget = nullptr;
mDiscardDepth = mDiscardStencil = false;
} }
void FramebufferMtl::destroy(const gl::Context *context) void FramebufferMtl::destroy(const gl::Context *context)
...@@ -289,7 +284,7 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context, ...@@ -289,7 +284,7 @@ angle::Result FramebufferMtl::syncState(const gl::Context *context,
{ {
ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 && ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX); dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
// NOTE(hqle): What are we supposed to do? // NOTE: might need to notify context.
} }
break; break;
} }
...@@ -340,48 +335,66 @@ const mtl::RenderPassDesc &FramebufferMtl::getRenderPassDesc(ContextMtl *context ...@@ -340,48 +335,66 @@ const mtl::RenderPassDesc &FramebufferMtl::getRenderPassDesc(ContextMtl *context
return mRenderPassDesc; return mRenderPassDesc;
} }
void FramebufferMtl::onFinishedDrawingToFrameBuffer(const gl::Context *context, void FramebufferMtl::onStartedDrawingToFrameBuffer(const gl::Context *context)
mtl::RenderCommandEncoder *encoder)
{ {
if (!encoder->valid()) // Compute loadOp based on previous storeOp and reset storeOp flags:
for (mtl::RenderPassColorAttachmentDesc &colorAttachment : mRenderPassDesc.colorAttachments)
{ {
return; if (colorAttachment.storeAction == MTLStoreActionDontCare)
} {
// If we previously discarded attachment's content, then don't need to load it.
ContextMtl *contextMtl = mtl::GetImpl(context); colorAttachment.loadAction = MTLLoadActionDontCare;
}
ASSERT(encoder->renderPassDesc().equalIgnoreLoadStoreOptions(mRenderPassDesc)); else
for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
{
if (mDiscardColors[i])
{ {
encoder->setColorStoreAction(MTLStoreActionDontCare, i); colorAttachment.loadAction = MTLLoadActionLoad;
} }
colorAttachment.storeAction = MTLStoreActionStore; // Default action is store
} }
encoder->setDepthStencilStoreAction( // Depth load/store
(mDiscardDepth || mAlwaysDiscardDepthStencil) ? MTLStoreActionDontCare if (mRenderPassDesc.depthAttachment.storeAction == MTLStoreActionDontCare)
: MTLStoreActionStore, {
(mDiscardStencil || mAlwaysDiscardDepthStencil) ? MTLStoreActionDontCare mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionDontCare;
: MTLStoreActionStore); }
else
{
mRenderPassDesc.depthAttachment.loadAction = MTLLoadActionLoad;
}
mRenderPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
contextMtl->endEncoding(encoder); // Stencil load/store
if (mRenderPassDesc.stencilAttachment.storeAction == MTLStoreActionDontCare)
{
mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionDontCare;
}
else
{
mRenderPassDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
}
mRenderPassDesc.stencilAttachment.storeAction = MTLStoreActionStore;
} }
angle::Result FramebufferMtl::updateColorRenderTarget(const gl::Context *context, angle::Result FramebufferMtl::updateColorRenderTarget(const gl::Context *context,
size_t colorIndexGL) size_t colorIndexGL)
{ {
ASSERT(colorIndexGL < mtl::kMaxRenderTargets);
// Reset load store action
mRenderPassDesc.colorAttachments[colorIndexGL].reset();
return updateCachedRenderTarget(context, mState.getColorAttachment(colorIndexGL), return updateCachedRenderTarget(context, mState.getColorAttachment(colorIndexGL),
&mColorRenderTargets[colorIndexGL]); &mColorRenderTargets[colorIndexGL]);
} }
angle::Result FramebufferMtl::updateDepthRenderTarget(const gl::Context *context) angle::Result FramebufferMtl::updateDepthRenderTarget(const gl::Context *context)
{ {
// Reset load store action
mRenderPassDesc.depthAttachment.reset();
return updateCachedRenderTarget(context, mState.getDepthAttachment(), &mDepthRenderTarget); return updateCachedRenderTarget(context, mState.getDepthAttachment(), &mDepthRenderTarget);
} }
angle::Result FramebufferMtl::updateStencilRenderTarget(const gl::Context *context) angle::Result FramebufferMtl::updateStencilRenderTarget(const gl::Context *context)
{ {
// Reset load store action
mRenderPassDesc.stencilAttachment.reset();
return updateCachedRenderTarget(context, mState.getStencilAttachment(), &mStencilRenderTarget); return updateCachedRenderTarget(context, mState.getStencilAttachment(), &mStencilRenderTarget);
} }
...@@ -420,19 +433,16 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context, ...@@ -420,19 +433,16 @@ angle::Result FramebufferMtl::prepareRenderPass(const gl::Context *context,
mtl::RenderPassColorAttachmentDesc &colorAttachment = mtl::RenderPassColorAttachmentDesc &colorAttachment =
desc.colorAttachments[attachmentIdx++]; desc.colorAttachments[attachmentIdx++];
colorAttachment.reset();
colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment); colorRenderTarget->toRenderPassAttachmentDesc(&colorAttachment);
} }
if (mDepthRenderTarget) if (mDepthRenderTarget)
{ {
desc.depthAttachment.reset();
mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment); mDepthRenderTarget->toRenderPassAttachmentDesc(&desc.depthAttachment);
} }
if (mStencilRenderTarget) if (mStencilRenderTarget)
{ {
desc.stencilAttachment.reset();
mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment); mStencilRenderTarget->toRenderPassAttachmentDesc(&desc.stencilAttachment);
} }
...@@ -475,30 +485,34 @@ angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context, ...@@ -475,30 +485,34 @@ angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context,
{ {
if (startedRenderPass) if (startedRenderPass)
{ {
// Render pass already started, and we want to clear this buffer,
// then discard its content before clearing.
encoder->setColorStoreAction(MTLStoreActionDontCare, attachmentIdx); encoder->setColorStoreAction(MTLStoreActionDontCare, attachmentIdx);
} }
colorAttachment.loadAction = MTLLoadActionClear; colorAttachment.loadAction = MTLLoadActionClear;
overrideClearColor(texture, clearOpts.clearColor.value(), &colorAttachment.clearColor); overrideClearColor(texture, clearOpts.clearColor.value(), &colorAttachment.clearColor);
} }
else else if (startedRenderPass)
{ {
if (startedRenderPass) // If render pass already started and we don't want to clear this buffer,
{ // then store it with current render encoder and load it before clearing step
encoder->setColorStoreAction(MTLStoreActionStore, attachmentIdx); encoder->setColorStoreAction(MTLStoreActionStore, attachmentIdx);
}
colorAttachment.loadAction = MTLLoadActionLoad; colorAttachment.loadAction = MTLLoadActionLoad;
} }
} }
MTLStoreAction preClearDethpStoreAction, preClearStencilStoreAction; MTLStoreAction preClearDethpStoreAction = MTLStoreActionStore,
preClearStencilStoreAction = MTLStoreActionStore;
if (clearOpts.clearDepth.valid()) if (clearOpts.clearDepth.valid())
{ {
preClearDethpStoreAction = MTLStoreActionDontCare; preClearDethpStoreAction = MTLStoreActionDontCare;
tempDesc.depthAttachment.loadAction = MTLLoadActionClear; tempDesc.depthAttachment.loadAction = MTLLoadActionClear;
tempDesc.depthAttachment.clearDepth = clearOpts.clearDepth.value(); tempDesc.depthAttachment.clearDepth = clearOpts.clearDepth.value();
} }
else else if (startedRenderPass)
{ {
// If render pass already started and we don't want to clear this buffer,
// then store it with current render encoder and load it before clearing step
preClearDethpStoreAction = MTLStoreActionStore; preClearDethpStoreAction = MTLStoreActionStore;
tempDesc.depthAttachment.loadAction = MTLLoadActionLoad; tempDesc.depthAttachment.loadAction = MTLLoadActionLoad;
} }
...@@ -509,13 +523,15 @@ angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context, ...@@ -509,13 +523,15 @@ angle::Result FramebufferMtl::clearWithLoadOp(const gl::Context *context,
tempDesc.stencilAttachment.loadAction = MTLLoadActionClear; tempDesc.stencilAttachment.loadAction = MTLLoadActionClear;
tempDesc.stencilAttachment.clearStencil = clearOpts.clearStencil.value(); tempDesc.stencilAttachment.clearStencil = clearOpts.clearStencil.value();
} }
else else if (startedRenderPass)
{ {
// If render pass already started and we don't want to clear this buffer,
// then store it with current render encoder and load it before clearing step
preClearStencilStoreAction = MTLStoreActionStore; preClearStencilStoreAction = MTLStoreActionStore;
tempDesc.stencilAttachment.loadAction = MTLLoadActionLoad; tempDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
} }
// End current render pass. // End current render encoder.
if (startedRenderPass) if (startedRenderPass)
{ {
encoder->setDepthStencilStoreAction(preClearDethpStoreAction, preClearStencilStoreAction); encoder->setDepthStencilStoreAction(preClearDethpStoreAction, preClearStencilStoreAction);
...@@ -534,30 +550,9 @@ angle::Result FramebufferMtl::clearWithDraw(const gl::Context *context, ...@@ -534,30 +550,9 @@ 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();
mtl::RenderPassDesc rpDesc;
ANGLE_TRY(prepareRenderPass(context, mState.getEnabledDrawBuffers(), &rpDesc));
for (uint32_t i = 0, attachmentIdx = 0; i < rpDesc.numColorAttachments; ++i, ++attachmentIdx)
{
mtl::RenderPassColorAttachmentDesc &colorAttachment =
rpDesc.colorAttachments[attachmentIdx];
// Need to preserve previous content, since we only clear a portion of the framebuffer
colorAttachment.loadAction = MTLLoadActionLoad;
}
if (rpDesc.depthAttachment.texture)
{
rpDesc.depthAttachment.loadAction = MTLLoadActionLoad;
}
if (rpDesc.stencilAttachment.texture) // Start new render encoder if not already.
{ mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder(mRenderPassDesc);
rpDesc.stencilAttachment.loadAction = MTLLoadActionLoad;
}
// Start new render encoder with loadOp=Load
mtl::RenderCommandEncoder *encoder = contextMtl->getRenderCommandEncoder(rpDesc);
display->getUtils().clearWithDraw(context, encoder, clearOpts); display->getUtils().clearWithDraw(context, encoder, clearOpts);
...@@ -646,24 +641,41 @@ angle::Result FramebufferMtl::invalidateImpl(ContextMtl *contextMtl, ...@@ -646,24 +641,41 @@ angle::Result FramebufferMtl::invalidateImpl(ContextMtl *contextMtl,
} }
// Set the appropriate storeOp for attachments. // Set the appropriate storeOp for attachments.
size_t attachmentIdx = 0; // If we already start the render pass, then need to set the store action now.
for (size_t colorIndexGL : mState.getEnabledDrawBuffers()) bool renderPassStarted = contextMtl->hasStartedRenderPass(mRenderPassDesc);
mtl::RenderCommandEncoder *encoder =
renderPassStarted ? contextMtl->getRenderCommandEncoder() : nullptr;
for (uint32_t i = 0; i < mRenderPassDesc.numColorAttachments; ++i)
{ {
if (mColorRenderTargets[colorIndexGL] && invalidateColorBuffers.test(colorIndexGL)) if (invalidateColorBuffers.test(i))
{ {
mDiscardColors[attachmentIdx] = true; mtl::RenderPassColorAttachmentDesc &colorAttachment =
mRenderPassDesc.colorAttachments[i];
colorAttachment.storeAction = MTLStoreActionDontCare;
if (renderPassStarted)
{
encoder->setColorStoreAction(MTLStoreActionDontCare, i);
}
} }
++attachmentIdx;
} }
if (invalidateDepthBuffer && mDepthRenderTarget) if (invalidateDepthBuffer && mDepthRenderTarget)
{ {
mDiscardDepth = true; mRenderPassDesc.depthAttachment.storeAction = MTLStoreActionDontCare;
if (renderPassStarted)
{
encoder->setDepthStoreAction(MTLStoreActionDontCare);
}
} }
if (invalidateStencilBuffer && mStencilRenderTarget) if (invalidateStencilBuffer && mStencilRenderTarget)
{ {
mDiscardStencil = true; mRenderPassDesc.stencilAttachment.storeAction = MTLStoreActionDontCare;
if (renderPassStarted)
{
encoder->setStencilStoreAction(MTLStoreActionDontCare);
}
} }
return angle::Result::Continue; return angle::Result::Continue;
......
...@@ -274,7 +274,7 @@ egl::Error SurfaceMtl::initialize(const egl::Display *display) ...@@ -274,7 +274,7 @@ egl::Error SurfaceMtl::initialize(const egl::Display *display)
FramebufferImpl *SurfaceMtl::createDefaultFramebuffer(const gl::Context *context, FramebufferImpl *SurfaceMtl::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state) const gl::FramebufferState &state)
{ {
auto fbo = new FramebufferMtl(state, /* flipY */ true, /* alwaysDiscard */ true); auto fbo = new FramebufferMtl(state, /* flipY */ true);
return fbo; return fbo;
} }
......
...@@ -236,6 +236,8 @@ class RenderCommandEncoder final : public CommandEncoder ...@@ -236,6 +236,8 @@ class RenderCommandEncoder final : public CommandEncoder
RenderCommandEncoder &setDepthStencilStoreAction(MTLStoreAction depthStoreAction, RenderCommandEncoder &setDepthStencilStoreAction(MTLStoreAction depthStoreAction,
MTLStoreAction stencilStoreAction); MTLStoreAction stencilStoreAction);
RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action);
RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action);
const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; } const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; }
......
...@@ -753,6 +753,22 @@ RenderCommandEncoder &RenderCommandEncoder::setDepthStencilStoreAction( ...@@ -753,6 +753,22 @@ RenderCommandEncoder &RenderCommandEncoder::setDepthStencilStoreAction(
return *this; return *this;
} }
RenderCommandEncoder &RenderCommandEncoder::setDepthStoreAction(MTLStoreAction action)
{
// We only store the options, will defer the actual setting until the encoder finishes
mRenderPassDesc.depthAttachment.storeAction = action;
return *this;
}
RenderCommandEncoder &RenderCommandEncoder::setStencilStoreAction(MTLStoreAction action)
{
// We only store the options, will defer the actual setting until the encoder finishes
mRenderPassDesc.stencilAttachment.storeAction = action;
return *this;
}
// BlitCommandEncoder // BlitCommandEncoder
BlitCommandEncoder::BlitCommandEncoder(CommandBuffer *cmdBuffer) : CommandEncoder(cmdBuffer, BLIT) BlitCommandEncoder::BlitCommandEncoder(CommandBuffer *cmdBuffer) : CommandEncoder(cmdBuffer, BLIT)
{} {}
......
...@@ -26,7 +26,10 @@ class DiscardFramebufferEXTTest : public ANGLETest ...@@ -26,7 +26,10 @@ class DiscardFramebufferEXTTest : public ANGLETest
TEST_P(DiscardFramebufferEXTTest, DefaultFramebuffer) TEST_P(DiscardFramebufferEXTTest, DefaultFramebuffer)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("EXT_discard_framebuffer")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_discard_framebuffer"));
// TODO: fix crash issue. http://anglebug.com/4141
ANGLE_SKIP_TEST_IF(IsD3D11());
// These should succeed on the default framebuffer // These should succeed on the default framebuffer
const GLenum discards1[] = {GL_COLOR_EXT}; const GLenum discards1[] = {GL_COLOR_EXT};
...@@ -61,7 +64,7 @@ TEST_P(DiscardFramebufferEXTTest, DefaultFramebuffer) ...@@ -61,7 +64,7 @@ TEST_P(DiscardFramebufferEXTTest, DefaultFramebuffer)
TEST_P(DiscardFramebufferEXTTest, NonDefaultFramebuffer) TEST_P(DiscardFramebufferEXTTest, NonDefaultFramebuffer)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("EXT_discard_framebuffer")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_discard_framebuffer"));
GLuint tex2D; GLuint tex2D;
GLuint framebuffer; GLuint framebuffer;
......
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