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
VertexArrayMtl *mVertexArray = 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>;
gl::AttributesMask mDirtyDefaultAttribsMask;
......
......@@ -663,7 +663,7 @@ ProgramImpl *ContextMtl::createProgram(const gl::ProgramState &state)
// Framebuffer creation
FramebufferImpl *ContextMtl::createFramebuffer(const gl::FramebufferState &state)
{
return new FramebufferMtl(state, false, false);
return new FramebufferMtl(state, false);
}
// Texture creation
......@@ -937,9 +937,16 @@ void ContextMtl::present(const gl::Context *context, id<CAMetalDrawable> present
{
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);
......@@ -1172,14 +1179,10 @@ void ContextMtl::updateDrawFrameBufferBinding(const gl::Context *context)
{
const gl::State &glState = getState();
auto oldFrameBuffer = mDrawFramebuffer;
mDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
mDrawFramebuffer = mtl::GetImpl(glState.getDrawFramebuffer());
mDrawFramebufferIsDefault = mDrawFramebuffer->getState().isDefault();
if (oldFrameBuffer && hasStartedRenderPass(oldFrameBuffer->getRenderPassDesc(this)))
{
oldFrameBuffer->onFinishedDrawingToFrameBuffer(context, &mRenderEncoder);
}
mDrawFramebuffer->onStartedDrawingToFrameBuffer(context);
onDrawFrameBufferChange(context, mDrawFramebuffer);
}
......
......@@ -24,9 +24,7 @@ class SurfaceMtl;
class FramebufferMtl : public FramebufferImpl
{
public:
explicit FramebufferMtl(const gl::FramebufferState &state,
bool flipY,
bool alwaysDiscardDepthStencil);
explicit FramebufferMtl(const gl::FramebufferState &state, bool flipY);
~FramebufferMtl() override;
void destroy(const gl::Context *context) override;
......@@ -91,9 +89,8 @@ class FramebufferMtl : public FramebufferImpl
const mtl::RenderPassDesc &getRenderPassDesc(ContextMtl *context);
// Call this to notify FramebufferMtl whenever its render pass has ended.
void onFinishedDrawingToFrameBuffer(const gl::Context *context,
mtl::RenderCommandEncoder *encoder);
// Call this to notify FramebufferMtl whenever its render pass has started.
void onStartedDrawingToFrameBuffer(const gl::Context *context);
// The actual area will be adjusted based on framebuffer flipping property.
gl::Rectangle getReadPixelArea(const gl::Rectangle &glArea);
......@@ -140,13 +137,9 @@ class FramebufferMtl : public FramebufferImpl
// depth & stencil attachments as of now. Separate depth & stencil could be useful to
// save spaces on iOS devices. See doc/PackedDepthStencilSupport.md.
std::array<RenderTargetMtl *, mtl::kMaxRenderTargets> mColorRenderTargets;
std::array<bool, mtl::kMaxRenderTargets> mDiscardColors;
RenderTargetMtl *mDepthRenderTarget = nullptr;
bool mDiscardDepth = false;
RenderTargetMtl *mStencilRenderTarget = nullptr;
bool mDiscardStencil = false;
mtl::RenderPassDesc mRenderPassDesc;
const bool mAlwaysDiscardDepthStencil;
const bool mFlipY = false;
};
} // namespace rx
......
......@@ -274,7 +274,7 @@ egl::Error SurfaceMtl::initialize(const egl::Display *display)
FramebufferImpl *SurfaceMtl::createDefaultFramebuffer(const gl::Context *context,
const gl::FramebufferState &state)
{
auto fbo = new FramebufferMtl(state, /* flipY */ true, /* alwaysDiscard */ true);
auto fbo = new FramebufferMtl(state, /* flipY */ true);
return fbo;
}
......
......@@ -236,6 +236,8 @@ class RenderCommandEncoder final : public CommandEncoder
RenderCommandEncoder &setDepthStencilStoreAction(MTLStoreAction depthStoreAction,
MTLStoreAction stencilStoreAction);
RenderCommandEncoder &setDepthStoreAction(MTLStoreAction action);
RenderCommandEncoder &setStencilStoreAction(MTLStoreAction action);
const RenderPassDesc &renderPassDesc() const { return mRenderPassDesc; }
......
......@@ -753,6 +753,22 @@ RenderCommandEncoder &RenderCommandEncoder::setDepthStencilStoreAction(
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(CommandBuffer *cmdBuffer) : CommandEncoder(cmdBuffer, BLIT)
{}
......
......@@ -26,7 +26,10 @@ class DiscardFramebufferEXTTest : public ANGLETest
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
const GLenum discards1[] = {GL_COLOR_EXT};
......@@ -61,7 +64,7 @@ TEST_P(DiscardFramebufferEXTTest, DefaultFramebuffer)
TEST_P(DiscardFramebufferEXTTest, NonDefaultFramebuffer)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("EXT_discard_framebuffer"));
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_discard_framebuffer"));
GLuint tex2D;
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