blob: bd37120369d2c495fc12994748427e6f80882cd6 [file]
// 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.
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
#include <GLES3/gl3.h>
#include <vector>
#include "base/logging.h"
#include "gpu/command_buffer/tests/gl_manager.h"
#include "gpu/command_buffer/tests/gl_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gpu {
class GLDrawBuffersTest : public testing::Test {
protected:
void SetUp() override {
GLManager::Options options;
options.context_type = CONTEXT_TYPE_OPENGLES3;
gl_.Initialize(options);
}
void TearDown() override { gl_.Destroy(); }
bool IsApplicable() const { return gl_.IsInitialized(); }
GLManager gl_;
};
// Test that lazy clearing of integer renderbuffers works even if DRAW_BUFFER0
// is GL_NONE.
TEST_F(GLDrawBuffersTest, ClearUnclearedIntegerAttachmentWithDrawBufferNone) {
if (!IsApplicable()) {
return;
}
const GLsizei kWidth = 4;
const GLsizei kHeight = 4;
const size_t kNumElements = kWidth * kHeight * 4;
// Create renderbuffer
GLuint rb = 0;
glGenRenderbuffers(1, &rb);
glBindRenderbuffer(GL_RENDERBUFFER, rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, kWidth, kHeight);
// Create framebuffer
GLuint fb = 0;
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, rb);
ASSERT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Fill the storage with a known marker.
GLenum draw_buffers[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffersEXT(1, draw_buffers);
GLuint marker[] = {0xDEu, 0xADu, 0xBEu, 0xEFu};
glClearBufferuiv(GL_COLOR, 0, marker);
// Verify it was written
{
std::vector<GLuint> pixels(kNumElements, 0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
pixels.data());
ASSERT_GE(pixels.size(), 4u);
EXPECT_EQ(0xDEu, pixels[0]);
EXPECT_EQ(0xADu, pixels[1]);
EXPECT_EQ(0xBEu, pixels[2]);
EXPECT_EQ(0xEFu, pixels[3]);
}
// Re-spec the same renderbuffer to make it uncleared.
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, kWidth, kHeight);
// Set DRAW_BUFFER0 to NONE.
GLenum draw_buffers_none[] = {GL_NONE};
glDrawBuffersEXT(1, draw_buffers_none);
// Read pixels to trigger lazy clear.
glReadBuffer(GL_COLOR_ATTACHMENT0);
std::vector<GLuint> pixels(kNumElements, 0);
glReadPixels(0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
pixels.data());
// Verify it was cleared to 0, not containing the marker.
for (GLuint val : pixels) {
EXPECT_EQ(0u, val);
}
glDeleteFramebuffers(1, &fb);
glDeleteRenderbuffers(1, &rb);
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
}
// Test that lazy clearing of integer renderbuffers works for attachment 1
// even if DRAW_BUFFER1 is GL_NONE (which is the default).
TEST_F(GLDrawBuffersTest,
ClearUnclearedIntegerAttachmentAtSlot1WithDefaultDrawBuffers) {
if (!IsApplicable()) {
return;
}
GLint max_draw_buffers = 0;
glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
if (max_draw_buffers < 2) {
LOG(INFO) << "Skipping test because MAX_DRAW_BUFFERS is "
<< max_draw_buffers;
return;
}
const GLsizei kWidth = 4;
const GLsizei kHeight = 4;
const size_t kNumElements = kWidth * kHeight * 4;
GLuint rb = 0;
glGenRenderbuffers(1, &rb);
glBindRenderbuffer(GL_RENDERBUFFER, rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, kWidth, kHeight);
GLuint fb = 0;
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_RENDERBUFFER, rb);
// We need to enable it to clear it first.
GLenum draw_buffers[] = {GL_NONE, GL_COLOR_ATTACHMENT1};
glDrawBuffersEXT(2, draw_buffers);
ASSERT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
glCheckFramebufferStatus(GL_FRAMEBUFFER));
GLuint marker[] = {0xDEu, 0xADu, 0xBEu, 0xEFu};
glClearBufferuiv(GL_COLOR, 1, marker);
// Verify
{
std::vector<GLuint> pixels(kNumElements, 0);
glReadBuffer(GL_COLOR_ATTACHMENT1);
glReadPixels(0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
pixels.data());
ASSERT_GE(pixels.size(), 4u);
EXPECT_EQ(0xDEu, pixels[0]);
}
// Re-spec
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8UI, kWidth, kHeight);
// Reset DRAW_BUFFERS to default: [COLOR_ATTACHMENT0].
// This means DRAW_BUFFER1 is GL_NONE.
GLenum default_draw_buffers[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffersEXT(1, default_draw_buffers);
// Read pixels from ATTACHMENT1 to trigger lazy clear.
glReadBuffer(GL_COLOR_ATTACHMENT1);
std::vector<GLuint> pixels(kNumElements, 0);
glReadPixels(0, 0, kWidth, kHeight, GL_RGBA_INTEGER, GL_UNSIGNED_INT,
pixels.data());
for (GLuint val : pixels) {
EXPECT_EQ(0u, val);
}
glDeleteFramebuffers(1, &fb);
glDeleteRenderbuffers(1, &rb);
EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
}
} // namespace gpu