Skip to content

Commit

Permalink
Add shadow sampler LOD tests for cubemap arrays
Browse files Browse the repository at this point in the history
Added tests for GLSL 3.10 shadow samplers in
fragment shaders with TEXTURE_CUBE_MAP_ARRAY
target (with an extension).

Bug: angleproject:365066518
Change-Id: I0d47b0af24383177d428ebace045e77f5563593c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/5866449
Reviewed-by: Shahbaz Youssefi <[email protected]>
Commit-Queue: Shahbaz Youssefi <[email protected]>
  • Loading branch information
lexaknyazev authored and Angle LUCI CQ committed Sep 16, 2024
1 parent 3cabe8c commit 6d58359
Showing 1 changed file with 189 additions and 0 deletions.
189 changes: 189 additions & 0 deletions src/tests/gl_tests/ShadowSamplerFunctionsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,18 @@ constexpr bool RequiresExtensionForCube(FunctionType function)
}
}

constexpr bool RequiresExtensionForCubeArray(FunctionType function)
{
switch (function)
{
case FunctionType::TextureBias:
case FunctionType::TextureLod:
return true;
default:
return false;
}
}

bool Compare(float reference, float sampled, GLenum op)
{
switch (op)
Expand Down Expand Up @@ -452,6 +464,7 @@ class ShadowSamplerFunctionTextureCubeTest : public ShadowSamplerFunctionTestBas
void setupProgramCube(FunctionType function, bool useShadowSampler)
{
ASSERT_FALSE(IsProj(function));
ASSERT_FALSE(HasOffset(function));
std::stringstream fragmentSource;
fragmentSource << "#version 300 es\n"
<< "#extension GL_EXT_texture_shadow_lod : enable\n"
Expand Down Expand Up @@ -506,6 +519,61 @@ class ShadowSamplerFunctionTextureCubeTest : public ShadowSamplerFunctionTestBas
}
};

class ShadowSamplerFunctionTextureCubeArrayTest : public ShadowSamplerFunctionTestBase
{
protected:
void setupProgramCubeArray(FunctionType function, bool useShadowSampler)
{
ASSERT_FALSE(IsProj(function));
ASSERT_FALSE(HasOffset(function));
ASSERT_FALSE(HasGrad(function));
std::stringstream fragmentSource;
fragmentSource << "#version 310 es\n"
<< "#extension GL_EXT_texture_cube_map_array : require\n"
<< "#extension GL_EXT_texture_shadow_lod : enable\n"
<< "precision mediump float;\n"
<< "precision mediump samplerCubeArray;\n"
<< "precision mediump samplerCubeArrayShadow;\n"
<< "uniform float dRef;\n"
<< "uniform samplerCubeArray" << (useShadowSampler ? "Shadow" : "")
<< " tex;\n"
<< "in vec4 v_position;\n"
<< "out vec4 my_FragColor;\n"
<< "void main()\n"
<< "{\n"
<< " vec4 texcoord = vec4(1.0, v_position.xy, 1.0);\n"
<< " float r = " << FunctionName(function) << "(tex, texcoord";
if (useShadowSampler)
{
fragmentSource << ", dRef";
}

if (HasLOD(function))
{
fragmentSource << ", 2.0";
}
else if (HasBias(function))
{
fragmentSource << ", 3.0";
}

fragmentSource << ")" << (useShadowSampler ? "" : ".r") << ";\n";
if (useShadowSampler)
{
fragmentSource << " my_FragColor = vec4(0.0, r, 1.0 - r, 1.0);\n";
}
else
{
fragmentSource << " my_FragColor = vec4(r, 0.0, 0.0, 1.0);\n";
}
fragmentSource << "}";

ANGLE_GL_PROGRAM(program, essl31_shaders::vs::Passthrough(), fragmentSource.str().c_str());
glUseProgram(program);
mPrg = program;
}
};

constexpr GLenum kCompareFuncs[] = {
GL_LEQUAL, GL_GEQUAL, GL_LESS, GL_GREATER, GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER,
};
Expand Down Expand Up @@ -831,6 +899,114 @@ TEST_P(ShadowSamplerFunctionTextureCubeTest, Test)
}
}

// Test TEXTURE_CUBE_MAP_ARRAY with shadow samplers
TEST_P(ShadowSamplerFunctionTextureCubeArrayTest, Test)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_cube_map_array"));

FunctionType function;
bool mipmapped;
ParseShadowSamplerFunctionVariationsTestParams(GetParam(), &function, &mipmapped);

if (RequiresExtensionForCubeArray(function))
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_shadow_lod"));
}

GLTexture tex;
const std::vector<GLfloat> unused(64, 0.875);
const std::vector<GLfloat> level0(64, 0.125f);
const std::vector<GLfloat> level1(16, 0.5f);
const std::vector<GLfloat> level2(4, 0.25f);
const std::vector<GLfloat> level3(1, 0.75f);

glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, tex);
glTexStorage3D(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, 4, GL_DEPTH_COMPONENT32F, 8, 8, 12);
for (size_t k = 0; k < 6 * 2; ++k)
{
glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, 0, 0, 0, k, 8, 8, 1, GL_DEPTH_COMPONENT,
GL_FLOAT, k > 5 ? level0.data() : unused.data());
glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, 1, 0, 0, k, 4, 4, 1, GL_DEPTH_COMPONENT,
GL_FLOAT, k > 5 ? level1.data() : unused.data());
glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, 2, 0, 0, k, 2, 2, 1, GL_DEPTH_COMPONENT,
GL_FLOAT, k > 5 ? level2.data() : unused.data());
glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, 3, 0, 0, k, 1, 1, 1, GL_DEPTH_COMPONENT,
GL_FLOAT, k > 5 ? level3.data() : unused.data());
}

glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, GL_TEXTURE_MIN_FILTER,
mipmapped ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST);
ASSERT_GL_NO_ERROR();

float expectedSample;
if (mipmapped)
{
if (HasBias(function))
{
// Base level 8x8, viewport 8x8, bias 3.0
expectedSample = level3[0];
}
else if (HasLOD(function))
{
// Explicitly requested level 2
expectedSample = level2[0];
}
else // implicit LOD
{
// Base level 8x8, viewport 8x8, no bias
expectedSample = level0[0];
}
}
else
{
// LOD options must have no effect when the texture is not mipmapped.
expectedSample = level0[0];
}

glViewport(0, 0, 8, 8);
glClearColor(1.0, 0.0, 1.0, 1.0);

// First sample the texture directly for easier debugging
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, GL_TEXTURE_COMPARE_MODE, GL_NONE);
setupProgramCubeArray(function, false);
ASSERT_GL_NO_ERROR();

glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mPrg, essl31_shaders::PositionAttrib(), 0.0f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(expectedSample * 255.0, 0, 0, 255), 1);

// Try shadow samplers
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, GL_TEXTURE_COMPARE_MODE,
GL_COMPARE_REF_TO_TEXTURE);
setupProgramCubeArray(function, true);
const GLint loc = glGetUniformLocation(mPrg, "dRef");
for (const float refValue : kRefValues)
{
glUniform1f(loc, refValue);
for (const GLenum compareFunc : kCompareFuncs)
{
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY_EXT, GL_TEXTURE_COMPARE_FUNC, compareFunc);
ASSERT_GL_NO_ERROR();

glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mPrg, essl31_shaders::PositionAttrib(), 0.0f);
if (Compare(refValue, expectedSample, compareFunc))
{
EXPECT_PIXEL_COLOR_EQ(4, 4, GLColor::green)
<< gl::GLenumToString(gl::GLESEnum::DepthFunction, compareFunc)
<< ", reference " << refValue << ", expected sample " << expectedSample;
}
else
{
EXPECT_PIXEL_COLOR_EQ(4, 4, GLColor::blue)
<< gl::GLenumToString(gl::GLESEnum::DepthFunction, compareFunc)
<< ", reference " << refValue << ", expected sample " << expectedSample;
}
}
}
}

constexpr FunctionType kTexture2DFunctionTypes[] = {
FunctionType::Texture, FunctionType::TextureBias,
FunctionType::TextureOffset, FunctionType::TextureOffsetBias,
Expand All @@ -856,6 +1032,12 @@ constexpr FunctionType kTextureCubeFunctionTypes[] = {
FunctionType::TextureGrad,
};

constexpr FunctionType kTextureCubeArrayFunctionTypes[] = {
FunctionType::Texture,
FunctionType::TextureBias,
FunctionType::TextureLod,
};

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ShadowSamplerFunctionTexture2DTest);
ANGLE_INSTANTIATE_TEST_COMBINE_2(ShadowSamplerFunctionTexture2DTest,
ShadowSamplerFunctionVariationsTestPrint,
Expand All @@ -877,4 +1059,11 @@ ANGLE_INSTANTIATE_TEST_COMBINE_2(ShadowSamplerFunctionTextureCubeTest,
testing::Bool(),
ANGLE_ALL_TEST_PLATFORMS_ES3);

GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ShadowSamplerFunctionTextureCubeArrayTest);
ANGLE_INSTANTIATE_TEST_COMBINE_2(ShadowSamplerFunctionTextureCubeArrayTest,
ShadowSamplerFunctionVariationsTestPrint,
testing::ValuesIn(kTextureCubeArrayFunctionTypes),
testing::Bool(),
ANGLE_ALL_TEST_PLATFORMS_ES31);

} // anonymous namespace

0 comments on commit 6d58359

Please sign in to comment.