| // Copyright 2026 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef GL_GLEXT_PROTOTYPES | |
| #define GL_GLEXT_PROTOTYPES | |
| #endif | |
| #include <GLES2/gl2.h> | |
| #include <GLES2/gl2ext.h> | |
| #include <GLES3/gl3.h> | |
| #include <stdint.h> | |
| #include "gpu/command_buffer/tests/gl_manager.h" | |
| #include "gpu/command_buffer/tests/gl_test_utils.h" | |
| #include "testing/gtest/include/gtest/gtest.h" | |
| namespace gpu { | |
| class GLInvalidateFramebufferTest : public testing::Test { | |
| protected: | |
| GLManager::Options GetGlManagerOptions() { | |
| GLManager::Options options; | |
| options.context_type = CONTEXT_TYPE_OPENGLES3; | |
| return options; | |
| } | |
| void SetUp() override { gl_.Initialize(GetGlManagerOptions()); } | |
| void TearDown() override { gl_.Destroy(); } | |
| GLManager gl_; | |
| }; | |
| // Port of the POC for b/507508103. | |
| // Creates an incomplete framebuffer and calls glInvalidateFramebuffer. | |
| // Should not crash. | |
| TEST_F(GLInvalidateFramebufferTest, IncompleteFBOInvalidate) { | |
| // If ES3 is not supported, skip the test. | |
| if (!gl_.decoder() || !gl_.decoder()->GetContextGroup()) { | |
| GTEST_SKIP() << "ES3 not supported"; | |
| } | |
| GLuint tex, fbo; | |
| glGenTextures(1, &tex); | |
| glBindTexture(GL_TEXTURE_2D_ARRAY, tex); | |
| // 2 levels, GL_RGBA8 (not depth/stencil renderable), 4x4, 1 layer | |
| glTexStorage3D(GL_TEXTURE_2D_ARRAY, 2, GL_RGBA8, 4, 4, 1); | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| // Try to attach level 2 (out of range, levels are 0 and 1) to | |
| // GL_DEPTH_STENCIL_ATTACHMENT. This should fail validation and generate | |
| // GL_INVALID_VALUE in validating decoder. | |
| glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, tex, 2, | |
| 0); | |
| GLenum att[] = {GL_DEPTH_STENCIL_ATTACHMENT}; | |
| // This call triggered the crash on vulnerable Qualcomm drivers. | |
| // With the workaround, it should be skipped or handled safely without | |
| // crashing. | |
| glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, att); | |
| // We call glFinish to ensure the GPU has processed the commands and we don't | |
| // crash asynchronously. | |
| glFinish(); | |
| // Clean up | |
| glDeleteFramebuffers(1, &fbo); | |
| glDeleteTextures(1, &tex); | |
| // Consume expected errors (GL_INVALID_VALUE from glFramebufferTextureLayer, | |
| // and potentially GL_INVALID_OPERATION from glInvalidateFramebuffer if not | |
| // skipped by ANGLE) to avoid failing CheckGLError. | |
| while (glGetError() != GL_NO_ERROR) { | |
| } | |
| GLTestHelper::CheckGLError("no errors at the end of test", __LINE__); | |
| } | |
| } // namespace gpu |