зеркало из https://github.com/AvaloniaUI/angle.git
Sync framebuffer bindings in glInvalidateFramebuffer
If a framebuffer binding change is followed by glInvalidateFramebuffer, ANGLE was not syncing the framebuffer binding. - This means that invalidation was being done on the previous framebuffer. - Paired with deferred clears, this was causing ContextVk to start a render pass on the previous, potentially deleted, framebuffer. Bug: chromium:1267027 Change-Id: I092a0c8dd764db9e49258b694c970babb19cf24b Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3266175 Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Родитель
a9f24fa529
Коммит
0e20c68092
|
@ -645,6 +645,9 @@ void Context::initializeDefaultResources()
|
|||
mCopyImageDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
|
||||
mCopyImageDirtyObjects.set(State::DIRTY_OBJECT_READ_FRAMEBUFFER);
|
||||
|
||||
mInvalidateDirtyBits.set(State::DIRTY_BIT_READ_FRAMEBUFFER_BINDING);
|
||||
mInvalidateDirtyBits.set(State::DIRTY_BIT_DRAW_FRAMEBUFFER_BINDING);
|
||||
|
||||
// Initialize overlay after implementation is initialized.
|
||||
ANGLE_CONTEXT_TRY(mOverlay.init(this));
|
||||
}
|
||||
|
@ -4139,6 +4142,13 @@ ANGLE_INLINE angle::Result Context::prepareForDispatch()
|
|||
return syncDirtyBits(mComputeDirtyBits, Command::Dispatch);
|
||||
}
|
||||
|
||||
angle::Result Context::prepareForInvalidate(GLenum target)
|
||||
{
|
||||
// Only sync the FBO that's being invalidated
|
||||
ANGLE_TRY(mState.syncDirtyObject(this, target));
|
||||
return syncDirtyBits(mInvalidateDirtyBits, Command::Invalidate);
|
||||
}
|
||||
|
||||
angle::Result Context::syncState(const State::DirtyBits &bitMask,
|
||||
const State::DirtyObjects &objectMask,
|
||||
Command command)
|
||||
|
@ -4780,14 +4790,12 @@ void Context::readBuffer(GLenum mode)
|
|||
|
||||
void Context::discardFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
|
||||
{
|
||||
// Only sync the FBO
|
||||
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, target));
|
||||
|
||||
Framebuffer *framebuffer = mState.getTargetFramebuffer(target);
|
||||
ASSERT(framebuffer);
|
||||
|
||||
// The specification isn't clear what should be done when the framebuffer isn't complete.
|
||||
// We leave it up to the framebuffer implementation to decide what to do.
|
||||
ANGLE_CONTEXT_TRY(prepareForInvalidate(target));
|
||||
ANGLE_CONTEXT_TRY(framebuffer->discard(this, numAttachments, attachments));
|
||||
}
|
||||
|
||||
|
@ -4804,8 +4812,7 @@ void Context::invalidateFramebuffer(GLenum target,
|
|||
return;
|
||||
}
|
||||
|
||||
// Only sync the FBO
|
||||
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, target));
|
||||
ANGLE_CONTEXT_TRY(prepareForInvalidate(target));
|
||||
ANGLE_CONTEXT_TRY(framebuffer->invalidate(this, numAttachments, attachments));
|
||||
}
|
||||
|
||||
|
@ -4826,8 +4833,7 @@ void Context::invalidateSubFramebuffer(GLenum target,
|
|||
}
|
||||
|
||||
Rectangle area(x, y, width, height);
|
||||
// Only sync the FBO
|
||||
ANGLE_CONTEXT_TRY(mState.syncDirtyObject(this, target));
|
||||
ANGLE_CONTEXT_TRY(prepareForInvalidate(target));
|
||||
ANGLE_CONTEXT_TRY(framebuffer->invalidateSub(this, numAttachments, attachments, area));
|
||||
}
|
||||
|
||||
|
|
|
@ -490,6 +490,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
|
|||
|
||||
angle::Result prepareForCopyImage();
|
||||
angle::Result prepareForDispatch();
|
||||
angle::Result prepareForInvalidate(GLenum target);
|
||||
|
||||
MemoryProgramCache *getMemoryProgramCache() const { return mMemoryProgramCache; }
|
||||
std::mutex &getProgramCacheMutex() const;
|
||||
|
@ -770,6 +771,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
|
|||
State::DirtyObjects mComputeDirtyObjects;
|
||||
State::DirtyBits mCopyImageDirtyBits;
|
||||
State::DirtyObjects mCopyImageDirtyObjects;
|
||||
State::DirtyBits mInvalidateDirtyBits;
|
||||
|
||||
// Binding to container objects that use dependent state updates.
|
||||
angle::ObserverBinding mVertexArrayObserverBinding;
|
||||
|
|
|
@ -38,6 +38,7 @@ enum class Command
|
|||
Dispatch,
|
||||
Draw,
|
||||
GenerateMipmap,
|
||||
Invalidate,
|
||||
ReadPixels,
|
||||
TexImage,
|
||||
Other
|
||||
|
|
|
@ -5600,6 +5600,8 @@ angle::Result ContextVk::startRenderPass(gl::Rectangle renderArea,
|
|||
vk::CommandBuffer **commandBufferOut,
|
||||
bool *renderPassDescChangedOut)
|
||||
{
|
||||
ASSERT(mDrawFramebuffer == vk::GetImpl(mState.getDrawFramebuffer()));
|
||||
|
||||
ANGLE_TRY(mDrawFramebuffer->startNewRenderPass(this, renderArea, &mRenderPassCommandBuffer,
|
||||
renderPassDescChangedOut));
|
||||
|
||||
|
|
|
@ -210,6 +210,8 @@
|
|||
|
||||
5233 MAC METAL : WebGL2ValidationStateChangeTest.MultiAttachmentDrawFramebufferNegativeAPI/* = SKIP
|
||||
|
||||
6669 MAC METAL : CopyTextureTestES3.InvalidateCopyThenBlend/* = SKIP
|
||||
|
||||
// D3D
|
||||
6432 WIN D3D9 : GLSLTest.HandleExcessiveLoopBug/* = SKIP
|
||||
6091 WIN D3D11 : GLSLTest_ES3.InitGlobalComplexConstant/* = SKIP
|
||||
|
|
|
@ -7108,6 +7108,35 @@ void main()
|
|||
glDrawArrays(GL_POINTS, 0, 1);
|
||||
EXPECT_GL_ERROR(GL_INVALID_OPERATION);
|
||||
}
|
||||
|
||||
// Regression test for a bug where the framebuffer binding was not synced during invalidate when a
|
||||
// clear operation was deferred.
|
||||
TEST_P(SimpleStateChangeTestES3, ChangeFramebufferThenInvalidateWithClear)
|
||||
{
|
||||
// Clear the default framebuffer.
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Start rendering to another framebuffer
|
||||
GLFramebuffer fbo;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
|
||||
|
||||
GLRenderbuffer rbo;
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 16, 16);
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
|
||||
|
||||
ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Red());
|
||||
glUseProgram(program);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
// Switch back to the default framebuffer
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
// Invalidate it. Don't invalidate color, as that's the one being cleared.
|
||||
constexpr GLenum kAttachment = GL_DEPTH;
|
||||
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &kAttachment);
|
||||
EXPECT_GL_NO_ERROR();
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
ANGLE_INSTANTIATE_TEST_ES2(StateChangeTest);
|
||||
|
|
Загрузка…
Ссылка в новой задаче