// // Copyright 2020 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // FramebufferObjectTest.cpp: Tests basic usage of OES_framebuffer_object extension. #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" using namespace angle; class FramebufferObjectTest : public ANGLETest<> { protected: FramebufferObjectTest() { setWindowWidth(32); setWindowHeight(32); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); setConfigDepthBits(24); } void testSetUp() override { mTexture.reset(new GLTexture()); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, mTexture->get()); } void testTearDown() override { mTexture.reset(); } std::unique_ptr mTexture; }; // Checks that framebuffer object can be used without GL errors. TEST_P(FramebufferObjectTest, FramebufferObject) { GLuint fboId; GLint params; glGenFramebuffersOES(1, &fboId); EXPECT_GL_NO_ERROR(); glIsFramebufferOES(fboId); EXPECT_GL_NO_ERROR(); glBindFramebufferOES(GL_FRAMEBUFFER, fboId); EXPECT_GL_NO_ERROR(); glCheckFramebufferStatusOES(GL_FRAMEBUFFER); EXPECT_GL_NO_ERROR(); glGetFramebufferAttachmentParameterivOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, ¶ms); EXPECT_GL_NO_ERROR(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffersOES(1, &fboId); EXPECT_GL_NO_ERROR(); } // Checks that texture object can be bound for framebuffer object. TEST_P(FramebufferObjectTest, TextureObject) { GLuint fboId; glGenFramebuffers(1, &fboId); glBindFramebuffer(GL_FRAMEBUFFER, fboId); glFramebufferTexture2DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mTexture->get(), 0); EXPECT_GL_NO_ERROR(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fboId); } // Checks different formats for a texture object bound to a framebuffer object. TEST_P(FramebufferObjectTest, TextureObjectDifferentFormats) { // http://anglebug.com/42264178 ANGLE_SKIP_TEST_IF(IsMac() && IsOpenGL()); GLuint fboId; glGenFramebuffersOES(1, &fboId); glBindFramebufferOES(GL_FRAMEBUFFER_OES, fboId); using FormatInfo = std::array; constexpr std::array kFormatArrays = { {{GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE}, {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE}, {GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, {GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}}}; for (const FormatInfo &formatInfo : kFormatArrays) { glTexImage2D(GL_TEXTURE_2D, 0, formatInfo[0], 1, 1, 0, formatInfo[1], formatInfo[2], &GLColor::green); glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, mTexture->get(), 0); ASSERT_EQ(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES), (GLenum)GL_FRAMEBUFFER_COMPLETE_OES); } EXPECT_GL_NO_ERROR(); glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glDeleteFramebuffersOES(1, &fboId); } // Checks that renderbuffer object can be used and can be bound for framebuffer object. TEST_P(FramebufferObjectTest, RenderbufferObject) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_framebuffer_object")); GLuint fboId; GLuint rboId; GLint params; glGenFramebuffers(1, &fboId); glBindFramebuffer(GL_FRAMEBUFFER, fboId); glGenRenderbuffersOES(1, &rboId); EXPECT_GL_NO_ERROR(); glIsRenderbufferOES(rboId); EXPECT_GL_NO_ERROR(); glBindRenderbufferOES(GL_RENDERBUFFER, rboId); EXPECT_GL_NO_ERROR(); glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGBA4, 32, 32); EXPECT_GL_NO_ERROR(); glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGB5_A1, 32, 32); EXPECT_GL_NO_ERROR(); glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGB565, 32, 32); EXPECT_GL_NO_ERROR(); glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGBA8, 32, 32); EXPECT_GL_NO_ERROR(); glFramebufferRenderbufferOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rboId); EXPECT_GL_NO_ERROR(); glGetRenderbufferParameterivOES(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, ¶ms); EXPECT_GL_NO_ERROR(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fboId); glDeleteRenderbuffersOES(1, &rboId); EXPECT_GL_NO_ERROR(); } // Checks that an RGBA8 renderbuffer object can be used and can be bound for framebuffer object. TEST_P(FramebufferObjectTest, RGBA8Renderbuffer) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_framebuffer_object")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_ARM_rgba8")); GLuint fbo; GLuint rbo; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glGenRenderbuffersOES(1, &rbo); EXPECT_GL_NO_ERROR(); glIsRenderbufferOES(rbo); EXPECT_GL_NO_ERROR(); glBindRenderbufferOES(GL_RENDERBUFFER, rbo); EXPECT_GL_NO_ERROR(); glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGBA8, 16, 16); EXPECT_GL_NO_ERROR(); glFramebufferRenderbufferOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo); EXPECT_GL_NO_ERROR(); glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::white); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbo); glDeleteRenderbuffersOES(1, &rbo); EXPECT_GL_NO_ERROR(); } // Checks that an RGB8 and an RGBA8 renderbuffer object can be used and can be bound for framebuffer // object one after the other. TEST_P(FramebufferObjectTest, RGB8AndRGBA8Renderbuffers) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_framebuffer_object")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_rgb8_rgba8")); GLuint fbo; GLuint rbo[2]; glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); glGenRenderbuffersOES(2, rbo); EXPECT_GL_NO_ERROR(); glBindRenderbufferOES(GL_RENDERBUFFER, rbo[0]); EXPECT_GL_NO_ERROR(); glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGB8, 16, 16); EXPECT_GL_NO_ERROR(); glBindRenderbufferOES(GL_RENDERBUFFER, rbo[1]); EXPECT_GL_NO_ERROR(); glRenderbufferStorageOES(GL_RENDERBUFFER, GL_RGBA8, 16, 16); EXPECT_GL_NO_ERROR(); glFramebufferRenderbufferOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[0]); EXPECT_GL_NO_ERROR(); glClearColor(0.0, 1.0, 0.0, 0.1); glClear(GL_COLOR_BUFFER_BIT); EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::green); glFramebufferRenderbufferOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[1]); EXPECT_GL_NO_ERROR(); glClearColor(1.0, 0.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); EXPECT_PIXEL_RECT_EQ(0, 0, 16, 16, GLColor::magenta); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &fbo); glDeleteRenderbuffersOES(2, rbo); EXPECT_GL_NO_ERROR(); } // Checks that generateMipmap can be called without GL errors. TEST_P(FramebufferObjectTest, GenerateMipmap) { constexpr uint32_t kSize = 32; std::vector pixelData(kSize * kSize * 4, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data()); glGenerateMipmapOES(GL_TEXTURE_2D); EXPECT_GL_NO_ERROR(); } ANGLE_INSTANTIATE_TEST_ES1(FramebufferObjectTest);