// // Copyright 2018 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. // // DepthStencilTest: // Tests covering depth- or stencil-only rendering to make sure the other non-existing aspect is // not affecting the results (since the format may be emulated with one that has both aspects). // #include "test_utils/ANGLETest.h" #include "test_utils/gl_raii.h" using namespace angle; namespace { class DepthStencilTest : public ANGLETest<> { protected: DepthStencilTest() { setWindowWidth(128); setWindowHeight(128); setConfigRedBits(8); setConfigGreenBits(8); setConfigBlueBits(8); setConfigAlphaBits(8); setConfigDepthBits(24); setConfigStencilBits(8); } void testSetUp() override { glBindTexture(GL_TEXTURE_2D, mColorTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); // Setup Color/Stencil FBO with a stencil format that's emulated with packed depth/stencil. glBindFramebuffer(GL_FRAMEBUFFER, mColorStencilFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mColorTexture, 0); glBindRenderbuffer(GL_RENDERBUFFER, mStencilTexture); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, mStencilTexture); ASSERT_GL_NO_ERROR(); // Note: GL_DEPTH_COMPONENT24 is allowed in GLES2 with GL_OES_depth24 extension. if (getClientMajorVersion() >= 3 || IsGLExtensionEnabled("GL_OES_depth24")) { // Setup Color/Depth FBO with a depth format that's emulated with packed depth/stencil. glBindFramebuffer(GL_FRAMEBUFFER, mColorDepthFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, mColorTexture, 0); glBindRenderbuffer(GL_RENDERBUFFER, mDepthTexture); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepthTexture); } ASSERT_GL_NO_ERROR(); } void bindColorStencilFBO() { glBindFramebuffer(GL_FRAMEBUFFER, mColorStencilFBO); mHasDepth = false; } void bindColorDepthFBO() { glBindFramebuffer(GL_FRAMEBUFFER, mColorDepthFBO); mHasStencil = false; } void prepareSingleEmulatedWithPacked(); void ensureColor(GLColor color); void ensureDepthUnaffected(); void ensureStencilUnaffected(); private: GLFramebuffer mColorStencilFBO; GLFramebuffer mColorDepthFBO; GLTexture mColorTexture; GLRenderbuffer mDepthTexture; GLRenderbuffer mStencilTexture; bool mHasDepth = true; bool mHasStencil = true; }; class DepthStencilTestES3 : public DepthStencilTest { protected: void compareDepth(uint32_t expected); void clearAndCompareDepth(GLfloat depth, uint32_t expected); void drawAndCompareDepth(GLProgram &program, GLfloat depth, uint32_t expected); }; void DepthStencilTest::ensureColor(GLColor color) { const int width = getWindowWidth(); const int height = getWindowHeight(); std::vector pixelData(width * height); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixelData.data()); for (int i = 0; i < width * height; i += 16) { GLColor actualColor = pixelData[i]; EXPECT_NEAR(color.R, actualColor.R, 1); EXPECT_NEAR(color.G, actualColor.G, 1); EXPECT_NEAR(color.B, actualColor.B, 1); EXPECT_NEAR(color.A, actualColor.A, 1); if (i % width == 0) i += 16 * width; } } void DepthStencilTest::ensureDepthUnaffected() { ANGLE_GL_PROGRAM(depthTestProgram, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Blue()); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_EQUAL); drawQuad(depthTestProgram, essl1_shaders::PositionAttrib(), 0.123f); glDisable(GL_DEPTH_TEST); ASSERT_GL_NO_ERROR(); // Since depth shouldn't exist, the drawQuad above should succeed in turning the whole image // blue. ensureColor(GLColor::blue); } void DepthStencilTest::ensureStencilUnaffected() { ANGLE_GL_PROGRAM(stencilTestProgram, essl1_shaders::vs::Passthrough(), essl1_shaders::fs::Green()); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 0x1B, 0xFF); drawQuad(stencilTestProgram, essl1_shaders::PositionAttrib(), 0.0f); glDisable(GL_STENCIL_TEST); ASSERT_GL_NO_ERROR(); // Since stencil shouldn't exist, the drawQuad above should succeed in turning the whole image // green. ensureColor(GLColor::green); } void DepthStencilTest::prepareSingleEmulatedWithPacked() { const int w = getWindowWidth(); const int h = getWindowHeight(); const int whalf = w >> 1; const int hhalf = h >> 1; // Clear to a random color, 0.75 depth and 0x36 stencil Vector4 color1(0.1f, 0.2f, 0.3f, 0.4f); GLColor color1RGB(color1); glClearColor(color1[0], color1[1], color1[2], color1[3]); glClearDepthf(0.75f); glClearStencil(0x36); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); ASSERT_GL_NO_ERROR(); // Verify color was cleared correctly. EXPECT_PIXEL_COLOR_NEAR(0, 0, color1RGB, 1); // Use masked color to clear two channels of the image to a second color, 0.25 depth and 0x59 // stencil. Vector4 color2(0.2f, 0.4f, 0.6f, 0.8f); glClearColor(color2[0], color2[1], color2[2], color2[3]); glClearDepthf(0.25f); glClearStencil(0x59); glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_FALSE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); ASSERT_GL_NO_ERROR(); GLColor color2RGB(Vector4(color2[0], color1[1], color2[2], color1[3])); EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, color2RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, 0, color2RGB, 1); EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color2RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color2RGB, 1); EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color2RGB, 1); // Use scissor to clear the center to a third color, 0.5 depth and 0xA9 stencil. glEnable(GL_SCISSOR_TEST); glScissor(whalf / 2, hhalf / 2, whalf, hhalf); Vector4 color3(0.3f, 0.5f, 0.7f, 0.9f); GLColor color3RGB(color3); glClearColor(color3[0], color3[1], color3[2], color3[3]); glClearDepthf(0.5f); glClearStencil(0xA9); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_COLOR_NEAR(whalf, hhalf, color3RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, 0, color2RGB, 1); EXPECT_PIXEL_COLOR_NEAR(w - 1, 0, color2RGB, 1); EXPECT_PIXEL_COLOR_NEAR(0, h - 1, color2RGB, 1); EXPECT_PIXEL_COLOR_NEAR(w - 1, h - 1, color2RGB, 1); // Use scissor to draw to the right half of the image with a fourth color, 0.6 depth and 0x84 // stencil. glEnable(GL_SCISSOR_TEST); glScissor(whalf, 0, whalf, h); ANGLE_GL_PROGRAM(redProgram, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0x84, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilMask(0xFF); drawQuad(redProgram, essl1_shaders::PositionAttrib(), 0.2f); glDisable(GL_STENCIL_TEST); glDisable(GL_SCISSOR_TEST); } // Tests that clearing or rendering into a depth-only format doesn't affect stencil. TEST_P(DepthStencilTest, DepthOnlyEmulatedWithPacked) { ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3 && !IsGLExtensionEnabled("GL_OES_depth24")); bindColorDepthFBO(); prepareSingleEmulatedWithPacked(); ensureStencilUnaffected(); } // Tests that clearing or rendering into a stencil-only format doesn't affect depth. TEST_P(DepthStencilTest, StencilOnlyEmulatedWithPacked) { // http://anglebug.com/40096654 ANGLE_SKIP_TEST_IF(IsWindows() && IsD3D9()); bindColorStencilFBO(); prepareSingleEmulatedWithPacked(); ensureDepthUnaffected(); } // Tests that drawing into stencil buffer along multiple render passes works. TEST_P(DepthStencilTest, StencilOnlyDrawThenCopyThenDraw) { ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); glUseProgram(drawColor); GLint colorUniformLocation = glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); ASSERT_NE(colorUniformLocation, -1); bindColorStencilFBO(); // Draw red once glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0x55, 0xFF); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilMask(0xFF); glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1.0f); ASSERT_GL_NO_ERROR(); // Create a texture and copy color into it, this breaks the render pass. GLTexture texture; glBindTexture(GL_TEXTURE_2D, texture); glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, getWindowWidth(), getWindowHeight(), 0); // Draw green, expecting correct stencil. glStencilFunc(GL_EQUAL, 0x55, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1.0f); ASSERT_GL_NO_ERROR(); // Verify that the texture is now green EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); // For completeness, also verify that the copy texture is red GLFramebuffer fbo; glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); ASSERT_GL_NO_ERROR(); } // Tests that clearing depth/stencil followed by draw works when the depth/stencil attachment is a // texture. TEST_P(DepthStencilTestES3, ClearThenDraw) { GLFramebuffer FBO; glBindFramebuffer(GL_FRAMEBUFFER, FBO); constexpr GLsizei kSize = 6; // Create framebuffer to draw into, with both color and depth attachments. GLTexture color; glBindTexture(GL_TEXTURE_2D, color); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); GLTexture depth; glBindTexture(GL_TEXTURE_2D, depth); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, kSize, kSize, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8_OES, nullptr); GLFramebuffer fbo; glBindFramebuffer(GL_FRAMEBUFFER, fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depth, 0); ASSERT_GL_NO_ERROR(); // Set viewport and clear depth/stencil glViewport(0, 0, kSize, kSize); glClearDepthf(1); glClearStencil(0x55); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // If depth is not cleared to 1, rendering would fail. glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); // If stencil is not clear to 0x55, rendering would fail. glEnable(GL_STENCIL_TEST); glStencilFunc(GL_EQUAL, 0x55, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glStencilMask(0xFF); // Set up program ANGLE_GL_PROGRAM(drawRed, essl1_shaders::vs::Simple(), essl1_shaders::fs::Red()); // Draw red drawQuad(drawRed, essl1_shaders::PositionAttrib(), 0.0f); ASSERT_GL_NO_ERROR(); // Verify. EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(kSize - 1, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(0, kSize - 1, GLColor::red); EXPECT_PIXEL_COLOR_EQ(kSize - 1, kSize - 1, GLColor::red); } // Test that VK_EXT_load_op_none is working properly when // one of the depth / stencil load op is none. // This reproduces a deqp failure on ARM: angleproject:7370 TEST_P(DepthStencilTestES3, LoadStoreOpNoneExtension) { GLFramebuffer fbo; glBindFramebuffer(GL_FRAMEBUFFER, fbo); GLRenderbuffer colorRbo; glBindRenderbuffer(GL_RENDERBUFFER, colorRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); GLRenderbuffer depthStencilBuffer; glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthStencilBuffer); ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); ASSERT_GL_NO_ERROR(); glClearDepthf(1.0f); glClear(GL_DEPTH_BUFFER_BIT); glClearStencil(0.0f); glClear(GL_STENCIL_BUFFER_BIT); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black); // Draw a red quad, stencil enabled, depth disabled // Depth Load Op: None. Depth Store Op: None. // Stencil Load Op: Load. Stencil Store Op: Store. ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); GLint colorLocation = glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); ASSERT_NE(-1, colorLocation); glDisable(GL_BLEND); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_LEQUAL, 0, ~0u); glStencilOp(GL_KEEP, GL_INCR, GL_INCR); glDisable(GL_DITHER); glDisable(GL_DEPTH_TEST); glUseProgram(program); glUniform4f(colorLocation, 1.0f, 0.0f, 0.0f, 1.0f); drawQuad(program, "a_position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); // Draw a green quad, stencil enabled, depth enabled. // Depth Load Op: Load. Depth Store Op: Store. // Stencil Load Op: Load. Stencil Store Op: Store. glUniform4f(colorLocation, 0.0f, 1.0f, 0.0f, 1.0f); glEnable(GL_DEPTH_TEST); drawQuad(program, "a_position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); } void DepthStencilTestES3::compareDepth(uint32_t expected) { uint32_t pixel; glReadPixels(0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &pixel); ASSERT_GL_NO_ERROR(); // Right shift by 8 bits to only compare 24 depth bits // and ignore 8 undefined bits. pixel = pixel >> 8; EXPECT_NEAR(pixel, expected, 1); } void DepthStencilTestES3::clearAndCompareDepth(GLfloat depth, uint32_t expected) { glClearDepthf(depth); glClear(GL_DEPTH_BUFFER_BIT); compareDepth(expected); } void DepthStencilTestES3::drawAndCompareDepth(GLProgram &program, GLfloat positionZ, uint32_t expected) { glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); drawQuad(program, essl3_shaders::PositionAttrib(), positionZ, 1.0f); glDisable(GL_DEPTH_TEST); compareDepth(expected); } TEST_P(DepthStencilTestES3, ReadPixelsDepth24) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_depth24") || !IsGLExtensionEnabled("GL_NV_read_depth")); // The test fails on native GLES on Android in glReadPixels // with GL_INVALID_OPERATION due to the format/type combination // not being supported. ANGLE_SKIP_TEST_IF(IsAndroid() && IsOpenGLES()); // Create GL_DEPTH_COMPONENT24 texture GLTexture depthTexture; glBindTexture(GL_TEXTURE_2D, depthTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, getWindowWidth(), getWindowHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); // Set up framebuffer GLFramebuffer depthFBO; GLRenderbuffer depthRenderbuffer; glBindFramebuffer(GL_FRAMEBUFFER, depthFBO); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0); glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer); ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); ASSERT_GL_NO_ERROR(); // Test clear clearAndCompareDepth(0.0f, 0x0); clearAndCompareDepth(0.125f, 0x200000); clearAndCompareDepth(0.5f, 0x800000); clearAndCompareDepth(1.0f, 0xffffff); // Test draw ANGLE_GL_PROGRAM(depthTestProgram, essl3_shaders::vs::Simple(), essl3_shaders::fs::Green()); drawAndCompareDepth(depthTestProgram, 0.0f, 0x800000); drawAndCompareDepth(depthTestProgram, 0.125f, 0x8fffff); drawAndCompareDepth(depthTestProgram, 0.5f, 0xbfffff); drawAndCompareDepth(depthTestProgram, 1.0f, 0xffffff); ASSERT_GL_NO_ERROR(); } // Tests that the stencil test is correctly handled when a framebuffer is cleared before that // framebuffer's stencil attachment has been configured. TEST_P(DepthStencilTestES3, FramebufferClearThenStencilAttachedThenStencilTestState) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_read_stencil")); GLFramebuffer fbo; glBindFramebuffer(GL_FRAMEBUFFER, fbo); GLRenderbuffer colorRbo; glBindRenderbuffer(GL_RENDERBUFFER, colorRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo); glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); GLRenderbuffer stencilRbo; glBindRenderbuffer(GL_RENDERBUFFER, stencilRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilRbo); glClearStencil(2); glClear(GL_STENCIL_BUFFER_BIT); ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); EXPECT_PIXEL_STENCIL_EQ(0, 0, 2); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); GLint colorLocation = glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); ASSERT_NE(-1, colorLocation); glUseProgram(program); glUniform4f(colorLocation, 1.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0xFF); glStencilOp(GL_KEEP, GL_INCR, GL_INCR); drawQuad(program, "a_position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_STENCIL_EQ(0, 0, 3); } // Tests that the stencil test is correctly handled when both the stencil test state is configured // and a framebuffer is cleared before that framebuffer's stencil attachment has been configured. TEST_P(DepthStencilTestES3, StencilTestStateThenFramebufferClearThenStencilAttached) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_read_stencil")); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0xFF); glStencilOp(GL_KEEP, GL_INCR, GL_INCR); GLFramebuffer fbo; glBindFramebuffer(GL_FRAMEBUFFER, fbo); GLRenderbuffer colorRbo; glBindRenderbuffer(GL_RENDERBUFFER, colorRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo); glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); GLRenderbuffer stencilRbo; glBindRenderbuffer(GL_RENDERBUFFER, stencilRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilRbo); glClearStencil(2); glClear(GL_STENCIL_BUFFER_BIT); ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); EXPECT_PIXEL_STENCIL_EQ(0, 0, 2); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); GLint colorLocation = glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); ASSERT_NE(-1, colorLocation); glUseProgram(program); glUniform4f(colorLocation, 1.0f, 0.0f, 0.0f, 1.0f); drawQuad(program, "a_position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_STENCIL_EQ(0, 0, 3); } // Tests that the stencil test is correctly handled when a framebuffer is cleared before that // framebuffer's stencil attachment has been configured and the stencil test state is configured // during framebuffer setup. TEST_P(DepthStencilTestES3, FramebufferClearThenStencilTestStateThenStencilAttached) { ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_NV_read_stencil")); GLFramebuffer fbo; glBindFramebuffer(GL_FRAMEBUFFER, fbo); GLRenderbuffer colorRbo; glBindRenderbuffer(GL_RENDERBUFFER, colorRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRbo); glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0xFF); glStencilOp(GL_KEEP, GL_INCR, GL_INCR); GLRenderbuffer stencilRbo; glBindRenderbuffer(GL_RENDERBUFFER, stencilRbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, getWindowWidth(), getWindowHeight()); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilRbo); glClearStencil(2); glClear(GL_STENCIL_BUFFER_BIT); ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); ASSERT_GL_NO_ERROR(); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::transparentBlack); EXPECT_PIXEL_STENCIL_EQ(0, 0, 2); ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); GLint colorLocation = glGetUniformLocation(program, angle::essl1_shaders::ColorUniform()); ASSERT_NE(-1, colorLocation); glUseProgram(program); glUniform4f(colorLocation, 1.0f, 0.0f, 0.0f, 1.0f); drawQuad(program, "a_position", 0.5f); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_STENCIL_EQ(0, 0, 3); } // Tests that drawing with read-only depth/stencil followed by depth/stencil output (in two render // passes) works. Regression test for a synchronization bug in the Vulkan backend, caught by // syncval VVL. TEST_P(DepthStencilTestES3, ReadOnlyDepthStencilThenOutputDepthStencil) { constexpr GLsizei kSize = 64; // Create FBO with color, depth and stencil GLTexture texture; glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); GLRenderbuffer renderbuffer; glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, kSize, kSize); GLFramebuffer framebuffer; glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer); ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER); ASSERT_GL_NO_ERROR(); // Initialize depth/stencil glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0xAA, 0xFF); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); glStencilMask(0xFF); ANGLE_GL_PROGRAM(drawColor, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor()); glUseProgram(drawColor); GLint colorUniformLocation = glGetUniformLocation(drawColor, angle::essl1_shaders::ColorUniform()); ASSERT_NE(colorUniformLocation, -1); // Draw red with depth = 1 and stencil = 0xAA glUniform4f(colorUniformLocation, 1.0f, 0.0f, 0.0f, 1.0f); drawQuad(drawColor, essl1_shaders::PositionAttrib(), 1); ASSERT_GL_NO_ERROR(); // Break the render pass by making a copy of the color texture. GLTexture copyTex; glBindTexture(GL_TEXTURE_2D, copyTex); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kSize, kSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, kSize / 2, kSize / 2); ASSERT_GL_NO_ERROR(); // Disable depth/stencil output and issue a draw call that's expected to pass depth/stencil. glDepthFunc(GL_LESS); glDepthMask(GL_FALSE); glStencilFunc(GL_EQUAL, 0xAA, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Draw green glUniform4f(colorUniformLocation, 0.0f, 1.0f, 0.0f, 1.0f); drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95); ASSERT_GL_NO_ERROR(); // Break the render pass glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, 0, 0, 0, kSize / 2, kSize / 2); ASSERT_GL_NO_ERROR(); // Draw again to start another render pass still with depth/stencil read-only glUniform4f(colorUniformLocation, 0.0f, 0.0f, 1.0f, 1.0f); drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95); ASSERT_GL_NO_ERROR(); // Break the render pass glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, kSize / 2, 0, 0, kSize / 2, kSize / 2); ASSERT_GL_NO_ERROR(); // Re-enable depth/stencil output and issue a draw call that's expected to pass depth/stencil. glDepthMask(GL_TRUE); glStencilFunc(GL_EQUAL, 0xAB, 0xF0); glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); // Draw yellow glUniform4f(colorUniformLocation, 1.0f, 1.0f, 0.0f, 1.0f); drawQuad(drawColor, essl1_shaders::PositionAttrib(), 0.95); ASSERT_GL_NO_ERROR(); // Break the render pass glCopyTexSubImage2D(GL_TEXTURE_2D, 0, kSize / 2, kSize / 2, 0, 0, kSize / 2, kSize / 2); ASSERT_GL_NO_ERROR(); GLFramebuffer readFramebuffer; glBindFramebuffer(GL_READ_FRAMEBUFFER, readFramebuffer); glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, copyTex, 0); EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); EXPECT_PIXEL_COLOR_EQ(kSize / 2, 0, GLColor::green); EXPECT_PIXEL_COLOR_EQ(0, kSize / 2, GLColor::blue); EXPECT_PIXEL_COLOR_EQ(kSize / 2, kSize / 2, GLColor::yellow); } ANGLE_INSTANTIATE_TEST_ES2_AND_ES3_AND( DepthStencilTest, ES2_VULKAN().enable(Feature::ForceFallbackFormat), ES2_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat), ES3_VULKAN().enable(Feature::ForceFallbackFormat), ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat)); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DepthStencilTestES3); ANGLE_INSTANTIATE_TEST_ES3_AND( DepthStencilTestES3, ES3_VULKAN().enable(Feature::ForceFallbackFormat), ES3_VULKAN().enable(Feature::DisallowMixedDepthStencilLoadOpNoneAndLoad), ES3_VULKAN_SWIFTSHADER().enable(Feature::ForceFallbackFormat)); } // anonymous namespace