GL: Add recreateFboUponFlush workaround. For the moment, apply it to all Qualcomm GPUs. The workaround will be restricted further in follow-on commits. Pass gl::Context to GLImplFactory::createSync on all backends in order to provide it to the GL backend for the workaround. Fixed lurking problem with escape sequences in angle_format.py. Incorporated new unit tests, including some which force-enable the workaround; should be a no-op on other platforms. Co-authored with jetski-cli. Bug: chromium:493747593 Change-Id: I027bfb484611a89615620001f160d0c909a7b22f Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/7815775 Reviewed-by: Geoff Lang <geofflang@chromium.org> Commit-Queue: Kenneth Russell <kbr@chromium.org>
diff --git a/include/platform/autogen/FeaturesGL_autogen.h b/include/platform/autogen/FeaturesGL_autogen.h index d5e9061..d30f958 100644 --- a/include/platform/autogen/FeaturesGL_autogen.h +++ b/include/platform/autogen/FeaturesGL_autogen.h
@@ -692,6 +692,12 @@ &members, }; + FeatureInfo recreateFboUponFlush = { + "recreateFboUponFlush", + FeatureCategory::OpenGLWorkarounds, + &members, + }; + }; inline FeaturesGL::FeaturesGL() = default;
diff --git a/include/platform/gl_features.json b/include/platform/gl_features.json index 6c1a696..7232893 100644 --- a/include/platform/gl_features.json +++ b/include/platform/gl_features.json
@@ -901,6 +901,14 @@ "Some drivers have internal failures when attempting to allocate and initialize buffers larger than 1gb." ], "issue": "http://crbug.com/475877320" + }, + { + "name": "recreate_fbo_upon_flush", + "category": "Workarounds", + "description": [ + "Recreate FBO upon flush/finish/fencesync under certain conditions to work around driver bugs." + ], + "issue": "http://crbug.com/493747593" } ] }
diff --git a/scripts/code_generation_hashes/ANGLE_format.json b/scripts/code_generation_hashes/ANGLE_format.json index 5061608..3591ef2 100644 --- a/scripts/code_generation_hashes/ANGLE_format.json +++ b/scripts/code_generation_hashes/ANGLE_format.json
@@ -4,7 +4,7 @@ "src/libANGLE/renderer/Format_table_autogen.cpp": "21e0b0aa9ce772d528e7063ee94cede7", "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/angle_format_data.json": "f82d30f65cebd8c787ac0d29fa4c0221", "src/libANGLE/renderer/angle_format_map.json":
diff --git a/scripts/code_generation_hashes/ANGLE_load_functions_table.json b/scripts/code_generation_hashes/ANGLE_load_functions_table.json index ec85f68..ec8f763 100644 --- a/scripts/code_generation_hashes/ANGLE_load_functions_table.json +++ b/scripts/code_generation_hashes/ANGLE_load_functions_table.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/gen_load_functions_table.py": "73e96775a0bd1a424f3f8585b1c5175f", "src/libANGLE/renderer/load_functions_data.json":
diff --git a/scripts/code_generation_hashes/D3D11_format.json b/scripts/code_generation_hashes/D3D11_format.json index 90fadc6..8cd8a9e 100644 --- a/scripts/code_generation_hashes/D3D11_format.json +++ b/scripts/code_generation_hashes/D3D11_format.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/d3d/d3d11/gen_texture_format_table.py": "70dcd2607cd481f450233c7c2b5c7ac0", "src/libANGLE/renderer/d3d/d3d11/texture_format_data.json":
diff --git a/scripts/code_generation_hashes/DXGI_format.json b/scripts/code_generation_hashes/DXGI_format.json index 648d43d..214b818 100644 --- a/scripts/code_generation_hashes/DXGI_format.json +++ b/scripts/code_generation_hashes/DXGI_format.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/angle_format_map.json": "abad08e462a0839d1600d83f83bcad8b", "src/libANGLE/renderer/dxgi_format_data.json":
diff --git a/scripts/code_generation_hashes/GL_copy_conversion_table.json b/scripts/code_generation_hashes/GL_copy_conversion_table.json index 341b8b8..af3566a 100644 --- a/scripts/code_generation_hashes/GL_copy_conversion_table.json +++ b/scripts/code_generation_hashes/GL_copy_conversion_table.json
@@ -6,5 +6,5 @@ "src/libANGLE/gen_copy_conversion_table.py": "3b1f0182a41af78b44930fb415ff0fb6", "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30" + "49c55a74e763b1cfd0d96c4b49b4e402" }
diff --git a/scripts/code_generation_hashes/GL_format_map.json b/scripts/code_generation_hashes/GL_format_map.json index eda4f5c..73563bb 100644 --- a/scripts/code_generation_hashes/GL_format_map.json +++ b/scripts/code_generation_hashes/GL_format_map.json
@@ -8,5 +8,5 @@ "src/libANGLE/gen_format_map.py": "32b43aedcbad2aa5eaa47052cc8573ac", "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30" + "49c55a74e763b1cfd0d96c4b49b4e402" }
diff --git a/scripts/code_generation_hashes/Metal_default_shaders.json b/scripts/code_generation_hashes/Metal_default_shaders.json index 79e6c2a..68a8512 100644 --- a/scripts/code_generation_hashes/Metal_default_shaders.json +++ b/scripts/code_generation_hashes/Metal_default_shaders.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/angle_format_map.json": "abad08e462a0839d1600d83f83bcad8b", "src/libANGLE/renderer/gen_angle_format_table.py":
diff --git a/scripts/code_generation_hashes/Metal_format_table.json b/scripts/code_generation_hashes/Metal_format_table.json index 1279b30..663e0d2 100644 --- a/scripts/code_generation_hashes/Metal_format_table.json +++ b/scripts/code_generation_hashes/Metal_format_table.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/angle_format_map.json": "abad08e462a0839d1600d83f83bcad8b", "src/libANGLE/renderer/metal/gen_mtl_format_table.py":
diff --git a/scripts/code_generation_hashes/OpenGL_dispatch_table.json b/scripts/code_generation_hashes/OpenGL_dispatch_table.json index 17f66d2..dea39df 100644 --- a/scripts/code_generation_hashes/OpenGL_dispatch_table.json +++ b/scripts/code_generation_hashes/OpenGL_dispatch_table.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/gl/DispatchTableGL_autogen.cpp": "31c088a9f24d58dc3b440412ff1410b1", "src/libANGLE/renderer/gl/DispatchTableGL_autogen.h":
diff --git a/scripts/code_generation_hashes/Vulkan_format.json b/scripts/code_generation_hashes/Vulkan_format.json index b81d75c..ba5152f 100644 --- a/scripts/code_generation_hashes/Vulkan_format.json +++ b/scripts/code_generation_hashes/Vulkan_format.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/angle_format_map.json": "abad08e462a0839d1600d83f83bcad8b", "src/libANGLE/renderer/vulkan/gen_vk_format_table.py":
diff --git a/scripts/code_generation_hashes/Vulkan_mandatory_format_support_table.json b/scripts/code_generation_hashes/Vulkan_mandatory_format_support_table.json index 02679eb..1616f34 100644 --- a/scripts/code_generation_hashes/Vulkan_mandatory_format_support_table.json +++ b/scripts/code_generation_hashes/Vulkan_mandatory_format_support_table.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/vulkan/gen_vk_mandatory_format_support_table.py": "a9fd6f3ff2b584aff382364489146c76", "src/libANGLE/renderer/vulkan/vk_format_map.json":
diff --git a/scripts/code_generation_hashes/WebGPU_format.json b/scripts/code_generation_hashes/WebGPU_format.json index 68bae1f..5380ce4 100644 --- a/scripts/code_generation_hashes/WebGPU_format.json +++ b/scripts/code_generation_hashes/WebGPU_format.json
@@ -1,6 +1,6 @@ { "src/libANGLE/renderer/angle_format.py": - "45ffbde9a8edc7cec1c6c3afc5517b30", + "49c55a74e763b1cfd0d96c4b49b4e402", "src/libANGLE/renderer/angle_format_map.json": "abad08e462a0839d1600d83f83bcad8b", "src/libANGLE/renderer/wgpu/gen_wgpu_format_table.py":
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp index 742a100..57f4a73 100644 --- a/src/libANGLE/Context.cpp +++ b/src/libANGLE/Context.cpp
@@ -8146,7 +8146,7 @@ GLsync Context::fenceSync(GLenum condition, GLbitfield flags) { SyncID syncHandle; - if (!mState.mSyncManager->createSync(mImplementation.get(), &syncHandle)) + if (!mState.mSyncManager->createSync(mImplementation.get(), this, &syncHandle)) { handleExhaustionError(angle::EntryPoint::GLFenceSync); return nullptr;
diff --git a/src/libANGLE/Fence.cpp b/src/libANGLE/Fence.cpp index 07115c9..35c6ae4 100644 --- a/src/libANGLE/Fence.cpp +++ b/src/libANGLE/Fence.cpp
@@ -64,9 +64,9 @@ return angle::Result::Continue; } -Sync::Sync(rx::GLImplFactory *factory, SyncID id) +Sync::Sync(rx::GLImplFactory *factory, SyncID id, const Context *context) : RefCountObject(factory->generateSerial(), id), - mFence(factory->createSync()), + mFence(factory->createSync(context)), mLabel(), mCondition(GL_SYNC_GPU_COMMANDS_COMPLETE), mFlags(0)
diff --git a/src/libANGLE/Fence.h b/src/libANGLE/Fence.h index ed0ae84..f36153e 100644 --- a/src/libANGLE/Fence.h +++ b/src/libANGLE/Fence.h
@@ -53,7 +53,7 @@ class Sync final : public RefCountObject<SyncID>, public LabeledObject { public: - Sync(rx::GLImplFactory *factory, SyncID id); + Sync(rx::GLImplFactory *factory, SyncID id, const Context *context); ~Sync() override; void onDestroy(const Context *context) override;
diff --git a/src/libANGLE/Fence_unittest.cpp b/src/libANGLE/Fence_unittest.cpp index 251d217..85df992 100644 --- a/src/libANGLE/Fence_unittest.cpp +++ b/src/libANGLE/Fence_unittest.cpp
@@ -96,9 +96,9 @@ void SetUp() override { mImpl = new MockSyncImpl; - EXPECT_CALL(factory, createSync()).WillOnce(Return(mImpl)); + EXPECT_CALL(factory, createSync(_)).WillOnce(Return(mImpl)); - mFence = new gl::Sync(&factory, {1}); + mFence = new gl::Sync(&factory, {1}, nullptr); EXPECT_CALL(*mImpl, destroy()); mFence->addRef(); }
diff --git a/src/libANGLE/ResourceManager.cpp b/src/libANGLE/ResourceManager.cpp index 42e5502..d1f5e8f 100644 --- a/src/libANGLE/ResourceManager.cpp +++ b/src/libANGLE/ResourceManager.cpp
@@ -364,13 +364,13 @@ sync->release(context); } -bool SyncManager::createSync(rx::GLImplFactory *factory, SyncID *outSync) +bool SyncManager::createSync(rx::GLImplFactory *factory, const Context *context, SyncID *outSync) { if (!mHandleAllocator.allocate(&outSync->value)) { return false; } - Sync *sync = new Sync(factory, *outSync); + Sync *sync = new Sync(factory, *outSync, context); sync->addRef(); mObjectMap.assign(*outSync, sync); return true;
diff --git a/src/libANGLE/ResourceManager.h b/src/libANGLE/ResourceManager.h index cf23fc4..1959aec 100644 --- a/src/libANGLE/ResourceManager.h +++ b/src/libANGLE/ResourceManager.h
@@ -286,7 +286,7 @@ class SyncManager : public TypedResourceManager<Sync, SyncManager, SyncID> { public: - bool createSync(rx::GLImplFactory *factory, SyncID *outSync); + bool createSync(rx::GLImplFactory *factory, const Context *context, SyncID *outSync); Sync *getSync(SyncID handle) const; static void DeleteObject(const Context *context, Sync *sync);
diff --git a/src/libANGLE/renderer/GLImplFactory.h b/src/libANGLE/renderer/GLImplFactory.h index ba7985f..1eee80c 100644 --- a/src/libANGLE/renderer/GLImplFactory.h +++ b/src/libANGLE/renderer/GLImplFactory.h
@@ -28,6 +28,7 @@ namespace gl { class State; +class Context; } // namespace gl namespace rx @@ -86,7 +87,7 @@ // Query and Fence creation virtual QueryImpl *createQuery(gl::QueryType type) = 0; virtual FenceNVImpl *createFenceNV() = 0; - virtual SyncImpl *createSync() = 0; + virtual SyncImpl *createSync(const gl::Context *context) = 0; // Transform Feedback creation virtual TransformFeedbackImpl *createTransformFeedback(
diff --git a/src/libANGLE/renderer/angle_format.py b/src/libANGLE/renderer/angle_format.py index 8dbf48a..71f1aab 100644 --- a/src/libANGLE/renderer/angle_format.py +++ b/src/libANGLE/renderer/angle_format.py
@@ -102,7 +102,7 @@ def get_channel_tokens(format_id): if 'EXTERNAL' in format_id: return ['R8', 'G8', 'B8', 'A8'] - r = re.compile(r'([' + kChannels + '][\d]+)') + r = re.compile(r'([' + kChannels + r'][\d]+)') return list(filter(r.match, r.split(format_id))) @@ -158,7 +158,7 @@ if internal_format.find('INT_10_10_10_2_OES') == 0: return 'rgba' - channels_pattern = re.compile('GL_(COMPRESSED_)?(SIGNED_)?(ETC\d_)?([A-Z]+)') + channels_pattern = re.compile(r'GL_(COMPRESSED_)?(SIGNED_)?(ETC\d_)?([A-Z]+)') match = re.search(channels_pattern, internal_format) channels_string = match.group(4)
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp index 780737a..7bb463d 100644 --- a/src/libANGLE/renderer/d3d/d3d11/Context11.cpp +++ b/src/libANGLE/renderer/d3d/d3d11/Context11.cpp
@@ -228,7 +228,7 @@ return new FenceNV11(mRenderer); } -SyncImpl *Context11::createSync() +SyncImpl *Context11::createSync(const gl::Context *) { return new Sync11(mRenderer); }
diff --git a/src/libANGLE/renderer/d3d/d3d11/Context11.h b/src/libANGLE/renderer/d3d/d3d11/Context11.h index 93fc111..6859029 100644 --- a/src/libANGLE/renderer/d3d/d3d11/Context11.h +++ b/src/libANGLE/renderer/d3d/d3d11/Context11.h
@@ -55,7 +55,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; - SyncImpl *createSync() override; + SyncImpl *createSync(const gl::Context *context) override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback(
diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp index 99c1e17..6724f11 100644 --- a/src/libANGLE/renderer/d3d/d3d9/Context9.cpp +++ b/src/libANGLE/renderer/d3d/d3d9/Context9.cpp
@@ -121,7 +121,7 @@ return new FenceNV9(mRenderer); } -SyncImpl *Context9::createSync() +SyncImpl *Context9::createSync(const gl::Context *) { // D3D9 doesn't support ES 3.0 and its sync objects. UNREACHABLE();
diff --git a/src/libANGLE/renderer/d3d/d3d9/Context9.h b/src/libANGLE/renderer/d3d/d3d9/Context9.h index 8cf106f..f87bbe9 100644 --- a/src/libANGLE/renderer/d3d/d3d9/Context9.h +++ b/src/libANGLE/renderer/d3d/d3d9/Context9.h
@@ -53,7 +53,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; - SyncImpl *createSync() override; + SyncImpl *createSync(const gl::Context *context) override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback(
diff --git a/src/libANGLE/renderer/gl/ContextGL.cpp b/src/libANGLE/renderer/gl/ContextGL.cpp index fdfa3b1..1eca4c4 100644 --- a/src/libANGLE/renderer/gl/ContextGL.cpp +++ b/src/libANGLE/renderer/gl/ContextGL.cpp
@@ -193,9 +193,14 @@ } } -SyncImpl *ContextGL::createSync() +SyncImpl *ContextGL::createSync(const gl::Context *context) { - return new SyncGL(getFunctions()); + SyncImpl *sync = new SyncGL(getFunctions()); + if (context) + { + static_cast<void>(applyRecreateFboWorkaroundIfNeeded(context)); + } + return sync; } TransformFeedbackImpl *ContextGL::createTransformFeedback(const gl::TransformFeedbackState &state) @@ -239,14 +244,81 @@ return new OverlayImpl(state); } +angle::Result ContextGL::applyRecreateFboWorkaroundIfNeeded(const gl::Context *context) +{ + if (!getFeaturesGL().recreateFboUponFlush.enabled) + { + return angle::Result::Continue; + } + + gl::Framebuffer *drawFbo = context->getState().getDrawFramebuffer(); + if (!drawFbo || drawFbo->isDefault()) + { + return angle::Result::Continue; + } + + FramebufferGL *drawFboGL = GetImplAs<FramebufferGL>(drawFbo); + + bool needWorkaround = false; + + // The workaround is needed when the draw framebuffer has a depth or stencil + // attachment with either of the following criteria: + // + // 1) The attachment is a renderbuffer. + // + // 2) The attachment is an immutable texture, and the attached level of the + // texture was never initialized via glTexSubImage2D. + + const gl::FramebufferAttachment *depthAtt = drawFbo->getDepthAttachment(); + const gl::FramebufferAttachment *stencilAtt = drawFbo->getStencilAttachment(); + + const gl::FramebufferAttachment *attachments[] = {depthAtt, stencilAtt}; + for (const gl::FramebufferAttachment *att : attachments) + { + if (!att) + { + continue; + } + + if (att->type() == GL_RENDERBUFFER) + { + needWorkaround = true; + break; + } + else if (att->type() == GL_TEXTURE) + { + const gl::Texture *texture = att->getTexture(); + if (texture->getImmutableFormat()) + { + const gl::ImageIndex &index = att->getTextureImageIndex(); + const gl::ImageDesc &desc = texture->getState().getImageDesc(index); + if (desc.initState == gl::InitState::MayNeedInit) + { + needWorkaround = true; + break; + } + } + } + } + + if (needWorkaround) + { + ANGLE_TRY(drawFboGL->recreateFbo(context)); + } + + return angle::Result::Continue; +} + angle::Result ContextGL::flush(const gl::Context *context) { - return mRenderer->flush(); + ANGLE_TRY(mRenderer->flush()); + return applyRecreateFboWorkaroundIfNeeded(context); } angle::Result ContextGL::finish(const gl::Context *context) { - return mRenderer->finish(); + ANGLE_TRY(mRenderer->finish()); + return applyRecreateFboWorkaroundIfNeeded(context); } ANGLE_INLINE angle::Result ContextGL::setDrawArraysState(const gl::Context *context,
diff --git a/src/libANGLE/renderer/gl/ContextGL.h b/src/libANGLE/renderer/gl/ContextGL.h index e441800..a5be68e 100644 --- a/src/libANGLE/renderer/gl/ContextGL.h +++ b/src/libANGLE/renderer/gl/ContextGL.h
@@ -74,7 +74,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; - SyncImpl *createSync() override; + SyncImpl *createSync(const gl::Context *context) override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback( @@ -316,6 +316,8 @@ gl::AttributesMask updateAttributesForBaseInstance(GLuint baseInstance); void resetUpdatedAttributes(gl::AttributesMask attribMask); + angle::Result applyRecreateFboWorkaroundIfNeeded(const gl::Context *context); + protected: std::shared_ptr<RendererGL> mRenderer;
diff --git a/src/libANGLE/renderer/gl/FramebufferGL.cpp b/src/libANGLE/renderer/gl/FramebufferGL.cpp index 6889e4c..55d1527 100644 --- a/src/libANGLE/renderer/gl/FramebufferGL.cpp +++ b/src/libANGLE/renderer/gl/FramebufferGL.cpp
@@ -1339,6 +1339,80 @@ return blitter->clearFramebuffer(context, colorAttachments, depth, stencil, this); } +angle::Result FramebufferGL::recreateFbo(const gl::Context *context) +{ + const FunctionsGL *functions = GetFunctionsGL(context); + StateManagerGL *stateManager = GetStateManagerGL(context); + + stateManager->deleteFramebuffer(mFramebufferID); + mFramebufferID = 0; + functions->genFramebuffers(1, &mFramebufferID); + stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID); + + const gl::FramebufferState &state = getState(); + size_t numColorAttachments = state.getColorAttachments().size(); + gl::Framebuffer::DirtyBits dirtyBits; + + // Setting dirty bits that require entry points from later context + // versions will crash, as syncState dereferences null function + // pointers. + for (size_t i = 0; i < numColorAttachments; ++i) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 + i); + } + if (state.getDepthAttachment()) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT); + } + if (state.getStencilAttachment()) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT); + } + const DrawBuffersVector<GLenum> &drawBufferStates = state.getDrawBufferStates(); + if (drawBufferStates[0] != GL_COLOR_ATTACHMENT0 || + std::find_if_not(drawBufferStates.begin() + 1, drawBufferStates.end(), + [](const GLenum ¤t) { return current == GL_NONE; }) != + drawBufferStates.end()) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_DRAW_BUFFERS); + } + if (state.getReadBufferState() != GL_COLOR_ATTACHMENT0) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_READ_BUFFER); + } + if (state.getDefaultWidth() != 0) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_DEFAULT_WIDTH); + } + if (state.getDefaultHeight() != 0) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT); + } + if (state.getDefaultSamples() != 0) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES); + } + if (state.getDefaultFixedSampleLocations() != 0) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS); + } + if (state.getDefaultLayers() != 0) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_DEFAULT_LAYERS); + } + if (state.getWriteControlMode() != SrgbWriteControlMode::Default) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE); + } + if (state.getFlipY() != GL_FALSE) + { + dirtyBits.set(Framebuffer::DIRTY_BIT_FLIP_Y); + } + + // Leave other bits like DIRTY_BIT_FOVEATION alone. + return syncState(context, GL_FRAMEBUFFER, dirtyBits, gl::Command::Other); +} + angle::Result FramebufferGL::syncState(const gl::Context *context, GLenum binding, const gl::Framebuffer::DirtyBits &dirtyBits,
diff --git a/src/libANGLE/renderer/gl/FramebufferGL.h b/src/libANGLE/renderer/gl/FramebufferGL.h index d2f7c17..9163555 100644 --- a/src/libANGLE/renderer/gl/FramebufferGL.h +++ b/src/libANGLE/renderer/gl/FramebufferGL.h
@@ -91,6 +91,8 @@ const gl::Framebuffer::DirtyBits &dirtyBits, gl::Command command) override; + angle::Result recreateFbo(const gl::Context *context); + void updateDefaultFramebufferID(GLuint framebufferID); bool isDefault() const { return mState.isDefault(); }
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp index 4f7239e..5594a61 100644 --- a/src/libANGLE/renderer/gl/renderergl_utils.cpp +++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -2683,6 +2683,10 @@ // exposed. ANGLE_FEATURE_CONDITION(features, bgraTexImageFormatsBroken, !isMesa && isQualcomm); + // Recreate FBO upon flush/finish/fencesync under certain conditions to work around Qualcomm + // driver bugs. + ANGLE_FEATURE_CONDITION(features, recreateFboUponFlush, isQualcomm); + // glGenerateMipmap may silently fail on mesa, leaving mips that are expected to be recreated to // match the base level in their original shape, hidden from ANGLE and its validation. ANGLE_FEATURE_CONDITION(features, recreateMipmapLevelsBeforeGenerate, isMesa);
diff --git a/src/libANGLE/renderer/metal/ContextMtl.h b/src/libANGLE/renderer/metal/ContextMtl.h index 35be494..0fca4f8 100644 --- a/src/libANGLE/renderer/metal/ContextMtl.h +++ b/src/libANGLE/renderer/metal/ContextMtl.h
@@ -243,7 +243,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; - SyncImpl *createSync() override; + SyncImpl *createSync(const gl::Context *context) override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback(
diff --git a/src/libANGLE/renderer/metal/ContextMtl.mm b/src/libANGLE/renderer/metal/ContextMtl.mm index 35bc62f..21f9753 100644 --- a/src/libANGLE/renderer/metal/ContextMtl.mm +++ b/src/libANGLE/renderer/metal/ContextMtl.mm
@@ -1521,7 +1521,7 @@ { return new FenceNVMtl(); } -SyncImpl *ContextMtl::createSync() +SyncImpl *ContextMtl::createSync(const gl::Context *) { return new SyncMtl(); }
diff --git a/src/libANGLE/renderer/null/ContextNULL.cpp b/src/libANGLE/renderer/null/ContextNULL.cpp index c15a1d8..df0ab3e 100644 --- a/src/libANGLE/renderer/null/ContextNULL.cpp +++ b/src/libANGLE/renderer/null/ContextNULL.cpp
@@ -482,7 +482,7 @@ return new FenceNVNULL(); } -SyncImpl *ContextNULL::createSync() +SyncImpl *ContextNULL::createSync(const gl::Context *) { return new SyncNULL(); }
diff --git a/src/libANGLE/renderer/null/ContextNULL.h b/src/libANGLE/renderer/null/ContextNULL.h index bca0122..a2e49d8 100644 --- a/src/libANGLE/renderer/null/ContextNULL.h +++ b/src/libANGLE/renderer/null/ContextNULL.h
@@ -231,7 +231,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; - SyncImpl *createSync() override; + SyncImpl *createSync(const gl::Context *context) override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback(
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp index d2a2177..78fd17a 100644 --- a/src/libANGLE/renderer/vulkan/ContextVk.cpp +++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -6287,7 +6287,7 @@ return new FenceNVVk(); } -SyncImpl *ContextVk::createSync() +SyncImpl *ContextVk::createSync(const gl::Context *) { return new SyncVk(); }
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h index 163cd93..a344834 100644 --- a/src/libANGLE/renderer/vulkan/ContextVk.h +++ b/src/libANGLE/renderer/vulkan/ContextVk.h
@@ -360,7 +360,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; - SyncImpl *createSync() override; + SyncImpl *createSync(const gl::Context *context) override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback(
diff --git a/src/libANGLE/renderer/wgpu/ContextWgpu.cpp b/src/libANGLE/renderer/wgpu/ContextWgpu.cpp index c894e88..1bbfdda 100644 --- a/src/libANGLE/renderer/wgpu/ContextWgpu.cpp +++ b/src/libANGLE/renderer/wgpu/ContextWgpu.cpp
@@ -1112,7 +1112,7 @@ return new FenceNVWgpu(); } -SyncImpl *ContextWgpu::createSync() +SyncImpl *ContextWgpu::createSync(const gl::Context *) { return new SyncWgpu(); }
diff --git a/src/libANGLE/renderer/wgpu/ContextWgpu.h b/src/libANGLE/renderer/wgpu/ContextWgpu.h index 3fb933f..ef996ce 100644 --- a/src/libANGLE/renderer/wgpu/ContextWgpu.h +++ b/src/libANGLE/renderer/wgpu/ContextWgpu.h
@@ -260,7 +260,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override; FenceNVImpl *createFenceNV() override; - SyncImpl *createSync() override; + SyncImpl *createSync(const gl::Context *context) override; // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback(
diff --git a/src/tests/angle_unittests_utils.h b/src/tests/angle_unittests_utils.h index 8400776..529677b 100644 --- a/src/tests/angle_unittests_utils.h +++ b/src/tests/angle_unittests_utils.h
@@ -60,7 +60,7 @@ // Query and Fence creation QueryImpl *createQuery(gl::QueryType type) override { return nullptr; } FenceNVImpl *createFenceNV() override { return nullptr; } - SyncImpl *createSync() override { return nullptr; } + SyncImpl *createSync(const gl::Context *context) override { return nullptr; } // Transform Feedback creation TransformFeedbackImpl *createTransformFeedback(const gl::TransformFeedbackState &state) override @@ -101,7 +101,7 @@ VertexArrayImpl *(const gl::VertexArrayState &, const gl::VertexArrayBuffers &)); MOCK_METHOD1(createQuery, QueryImpl *(gl::QueryType type)); MOCK_METHOD0(createFenceNV, FenceNVImpl *()); - MOCK_METHOD0(createSync, SyncImpl *()); + MOCK_METHOD1(createSync, SyncImpl *(const gl::Context *)); MOCK_METHOD1(createTransformFeedback, TransformFeedbackImpl *(const gl::TransformFeedbackState &)); MOCK_METHOD1(createSampler, SamplerImpl *(const gl::SamplerState &));
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp index a029996..1f01ecb 100644 --- a/src/tests/gl_tests/FramebufferTest.cpp +++ b/src/tests/gl_tests/FramebufferTest.cpp
@@ -9421,3 +9421,293 @@ ES3_VULKAN().disable(Feature::PreferDynamicRendering)); ANGLE_INSTANTIATE_TEST_ES3_AND(DefaultFramebufferTest, ES3_VULKAN().disable(Feature::PreferDynamicRendering)); + +class FramebufferTest_ES3FBOWorkaround : public ANGLETest<> +{ + protected: + FramebufferTest_ES3FBOWorkaround() + { + setWindowWidth(128); + setWindowHeight(128); + setConfigRedBits(8); + setConfigGreenBits(8); + setConfigBlueBits(8); + setConfigAlphaBits(8); + setConfigDepthBits(24); + setConfigStencilBits(8); + } + + void testSetUp() override + { + mColorProgram = + CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); + ASSERT_NE(0u, mColorProgram); + mColorUniformLocation = glGetUniformLocation(mColorProgram, essl1_shaders::ColorUniform()); + ASSERT_NE(-1, mColorUniformLocation); + } + + void testTearDown() override + { + if (mColorProgram != 0) + { + glDeleteProgram(mColorProgram); + } + } + + void drawRedQuad() + { + glUseProgram(mColorProgram); + glUniform4f(mColorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); + drawQuad(mColorProgram, essl1_shaders::PositionAttrib(), 0.5f); + } + + void drawGreenQuad() + { + glUseProgram(mColorProgram); + glUniform4f(mColorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); + drawQuad(mColorProgram, essl1_shaders::PositionAttrib(), 0.5f); + } + + GLuint mColorProgram = 0; + GLint mColorUniformLocation = -1; +}; + +// Sub-Test 1: Renderbuffer depth/stencil attachment Case +TEST_P(FramebufferTest_ES3FBOWorkaround, RenderbufferWorkaround) +{ + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + GLRenderbuffer rbo; + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 128, 128); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); + + GLTexture texture; + glBindTexture(GL_TEXTURE_2D, texture); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 128, 128); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); + + ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); + ASSERT_GL_NO_ERROR(); + + // Draw a red quad to color buffer + drawRedQuad(); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); + + // Trigger flush -> FBO recreation! + glFlush(); + ASSERT_GL_NO_ERROR(); + + // Draw a green quad to color buffer + drawGreenQuad(); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + ASSERT_GL_NO_ERROR(); +} + +// Sub-Test 2: Uninitialized Texture Case +TEST_P(FramebufferTest_ES3FBOWorkaround, UninitializedTextureWorkaround) +{ + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + GLTexture depthTex; + glBindTexture(GL_TEXTURE_2D, depthTex); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 128, 128); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex, 0); + + GLTexture colorTex; + glBindTexture(GL_TEXTURE_2D, colorTex); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 128, 128); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); + + ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); + ASSERT_GL_NO_ERROR(); + + // Draw red + drawRedQuad(); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); + + // Trigger flush -> FBO recreation! + glFlush(); + ASSERT_GL_NO_ERROR(); + + // Draw green + drawGreenQuad(); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + ASSERT_GL_NO_ERROR(); +} + +// Sub-Test 3: Initialized Texture Case (Workaround does NOT trigger) +TEST_P(FramebufferTest_ES3FBOWorkaround, InitializedTextureNoWorkaround) +{ + GLFramebuffer fbo; + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + GLTexture depthTex; + glBindTexture(GL_TEXTURE_2D, depthTex); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, 128, 128); + + // Initialize/clear the depth texture level using glTexSubImage2D + std::vector<GLushort> depthData(128 * 128, 0); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 128, 128, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, + depthData.data()); + ASSERT_GL_NO_ERROR(); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTex, 0); + + GLTexture colorTex; + glBindTexture(GL_TEXTURE_2D, colorTex); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 128, 128); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); + + ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); + ASSERT_GL_NO_ERROR(); + + // Draw red + drawRedQuad(); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); + + // Trigger flush -> Workaround should NOT trigger, but we test that everything still works + glFlush(); + ASSERT_GL_NO_ERROR(); + + // Draw green + drawGreenQuad(); + EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); + ASSERT_GL_NO_ERROR(); +} + +// Sub-Test 4: FBO combined with FenceSync +TEST_P(FramebufferTest_ES3FBOWorkaround, FBOAndFenceSync) +{ + GLuint i; + GLuint num_buffers; + GLuint buffer1; + GLuint buffer2; + GLuint framebuffer; + GLuint textures[2]; + GLuint renderbuffers[2]; + GLuint framebuffers[2]; + GLuint textures2[2]; + GLuint *buffers; + void *pixels; + char *g_prepared_buffer; + char data[16]; + + g_prepared_buffer = (char *)calloc(1, 0x400); + *(int *)(g_prepared_buffer + 0x00) = 0x40082000; + *(int *)(g_prepared_buffer + 0x04) = 0x40282000; + *(int *)(g_prepared_buffer + 0x08) = 0x40282000; + *(int *)(g_prepared_buffer + 0x0c) = 0x40282000; + *(int *)(g_prepared_buffer + 0x28) = 0x33800000; + *(int *)(g_prepared_buffer + 0x110) = 0x40282000; + *(int *)(g_prepared_buffer + 0x114) = 0x40282000; + *(int *)(g_prepared_buffer + 0x118) = 0x40282000; + *(int *)(g_prepared_buffer + 0x11c) = 0x40282000; + + pixels = calloc(1, 0x4000); + num_buffers = 10; + buffers = (GLuint *)calloc(1, 4 * num_buffers); + + glGenFramebuffers(2, framebuffers); + glGenRenderbuffers(2, renderbuffers); + glGenTextures(2, textures); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 40, 40); + glBindTexture(GL_TEXTURE_2D, textures[1]); + glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 43, 43); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, framebuffers); + glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[0]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 40, 40); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[1]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[0], 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + renderbuffers[0]); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glGenFramebuffers(1, framebuffers); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[0]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + renderbuffers[0]); + glClear(GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffers[1]); + glReadPixels(0, 0, 40, 40, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffers[1]); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[1], 0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &framebuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 40, 40); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffers[1]); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, + renderbuffers[0]); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glPixelStorei(GL_PACK_ROW_LENGTH, 43); + glGenBuffers(1, &buffer1); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer1); + glBufferData(GL_PIXEL_UNPACK_BUFFER, 0x400, g_prepared_buffer, GL_DYNAMIC_DRAW); + glGenTextures(2, textures2); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures2[0]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 0x25, 1, 0, GL_RGBA, GL_FLOAT, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textures2[1]); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 0x27, 1, 0, GL_RGBA, GL_FLOAT, 0); + glPixelStorei(GL_PACK_ROW_LENGTH, 0); + glPixelStorei(GL_PACK_ROW_LENGTH, 43); + glGenBuffers(num_buffers, buffers); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glGenBuffers(1, &buffer2); + glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer2); + glBufferData(GL_PIXEL_PACK_BUFFER, 0x4000, pixels, GL_STATIC_COPY); + glFinish(); + glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + for (i = 0; i < num_buffers; i++) + { + glBindBuffer(GL_ARRAY_BUFFER, buffers[i]); + glBufferData(GL_ARRAY_BUFFER, 16, &data, GL_DYNAMIC_DRAW); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + for (i = 0; i < num_buffers; i++) + { + glDeleteBuffers(1, &buffers[i]); + glActiveTexture(GL_TEXTURE0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 0x25, 1, 0, GL_RGBA, GL_FLOAT, 0); + glActiveTexture(GL_TEXTURE1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 0x27, 1, 0, GL_RGBA, GL_FLOAT, 0); + } + glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); /* crash / recreateFbo workaround point! */ + ASSERT_GL_NO_ERROR(); + + // Cleanup + glDeleteFramebuffers(1, framebuffers); + glDeleteFramebuffers(1, &framebuffers[1]); + glDeleteRenderbuffers(2, renderbuffers); + glDeleteTextures(2, textures); + glDeleteTextures(2, textures2); + glDeleteBuffers(1, &buffer1); + glDeleteBuffers(1, &buffer2); + free(g_prepared_buffer); + free(pixels); + free(buffers); +} + +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(FramebufferTest_ES3FBOWorkaround); +ANGLE_INSTANTIATE_TEST_ES3_AND(FramebufferTest_ES3FBOWorkaround, + ES3_OPENGL().enable(Feature::RecreateFboUponFlush), + ES3_OPENGLES().enable(Feature::RecreateFboUponFlush));
diff --git a/util/autogen/angle_features_autogen.cpp b/util/autogen/angle_features_autogen.cpp index 55389d0..59306b6 100644 --- a/util/autogen/angle_features_autogen.cpp +++ b/util/autogen/angle_features_autogen.cpp
@@ -287,6 +287,7 @@ {Feature::QueryCounterBitsGeneratesErrors, "queryCounterBitsGeneratesErrors"}, {Feature::ReadPixelsUsingImplementationColorReadFormatForNorm16, "readPixelsUsingImplementationColorReadFormatForNorm16"}, {Feature::ReapplyUBOBindingsAfterUsingBinaryProgram, "reapplyUBOBindingsAfterUsingBinaryProgram"}, + {Feature::RecreateFboUponFlush, "recreateFboUponFlush"}, {Feature::RecreateMipmapLevelsBeforeGenerate, "recreateMipmapLevelsBeforeGenerate"}, {Feature::RecycleVkEvent, "recycleVkEvent"}, {Feature::RegenerateStructNames, "regenerateStructNames"},
diff --git a/util/autogen/angle_features_autogen.h b/util/autogen/angle_features_autogen.h index d5016ce..4c46125 100644 --- a/util/autogen/angle_features_autogen.h +++ b/util/autogen/angle_features_autogen.h
@@ -287,6 +287,7 @@ QueryCounterBitsGeneratesErrors, ReadPixelsUsingImplementationColorReadFormatForNorm16, ReapplyUBOBindingsAfterUsingBinaryProgram, + RecreateFboUponFlush, RecreateMipmapLevelsBeforeGenerate, RecycleVkEvent, RegenerateStructNames,