blob: 5c32bbe41014d34120dccc2b305978a56363dd69 [file] [log] [blame]
//
// 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<GLColor> 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