Fix Texture2DTest.TextureSize.

This CL fixes a number of issues: fixes the calls to texture
size query, fixes an uninitialized memory read, fixes some
incomplete texture cases, and fixes an out-of-bounds with the
color array. It also cleans up the test logic, and splits the
test into four sub-tests so it runs more smoothly in CI.

Noticed while working on the capture/replay harness with ASAN.

Bug: angleproject:5982
Change-Id: I15459381b92332db5adad2bd91c0b9eb0f8b5961
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3104005
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Jamie Madill 2021-08-18 12:22:58 -04:00 коммит произвёл Angle LUCI CQ
Родитель b2238a3c14
Коммит 02005fdc89
1 изменённых файлов: 133 добавлений и 146 удалений

Просмотреть файл

@ -373,6 +373,8 @@ void main()
ASSERT_GL_NO_ERROR();
}
void testTextureSize(int testCaseIndex);
GLuint mTexture2D;
GLint mTexture2DUniformLocation;
};
@ -3239,81 +3241,45 @@ void FillLevel(GLint level,
GLuint width,
GLuint height,
const GLColor &color,
bool opt_cubemap,
bool opt_subTex)
bool cubemap,
bool subTex)
{
GLsizei numPixels = width * height;
std::unique_ptr<uint8_t[]> pixels;
GLsizei largeDim = std::max(width, height);
GLsizei smallDim = std::min(width, height);
std::unique_ptr<uint8_t[]> pixelRow = std::make_unique<uint8_t[]>(largeDim * 4);
for (GLint jj = 0; jj < largeDim; ++jj)
std::vector<GLColor> pixels(width * height, color);
std::vector<GLenum> targets;
if (cubemap)
{
GLsizei off = jj * 4;
pixelRow[off + 0] = color[0];
pixelRow[off + 1] = color[1];
pixelRow[off + 2] = color[2];
pixelRow[off + 3] = color[3];
}
if (largeDim == numPixels)
{
pixels = std::move(pixelRow);
targets = {GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
}
else
{
pixels = std::make_unique<uint8_t[]>(numPixels * 4);
for (GLint jj = 0; jj < smallDim; ++jj)
{
GLsizei off = jj * largeDim * 4;
memcpy(pixels.get() + off, pixelRow.get(), largeDim * 4);
}
targets = {GL_TEXTURE_2D};
}
if (opt_cubemap)
for (GLenum target : targets)
{
std::array<GLenum, 6> targets = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z};
for (GLenum target : targets)
if (subTex)
{
if (opt_subTex)
{
glTexSubImage2D(target, level, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
pixels.get());
}
else
{
glTexImage2D(target, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixels.get());
}
}
}
else
{
if (opt_subTex)
{
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
pixels.get());
glTexSubImage2D(target, level, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
pixels.data());
}
else
{
glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixels.get());
glTexImage2D(target, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
pixels.data());
}
}
}
// This is part of tests that webgl_conformance_vulkan_passthrough_tests
// conformance/textures/misc/texture-size.html does
TEST_P(Texture2DTest, TextureSize)
void Texture2DTest::testTextureSize(int testCaseIndex)
{
// http://anglebug.com/5982
ANGLE_SKIP_TEST_IF(IsLinux() && IsTSan() && (IsOpenGL() || IsVulkan()));
// http://anglebug.com/6296
ANGLE_SKIP_TEST_IF(IsMetal());
const GLColor kNewMipColors[] = {
std::array<GLColor, 6> kNewMipColors = {
GLColor::green, GLColor::red, GLColor::blue,
GLColor::yellow, GLColor::magenta, GLColor::cyan,
};
@ -3339,108 +3305,129 @@ void main()
{
gl_FragColor = textureCube(tex, texcoord);
})";
GLuint programCubeMap = CompileProgram(kVS, kFS);
ASSERT_NE(0u, programCubeMap);
ANGLE_GL_PROGRAM(programCubeMap, kVS, kFS);
GLint textureCubeUniformLocation = glGetUniformLocation(programCubeMap, "tex");
ASSERT_NE(-1, textureCubeUniformLocation);
ASSERT_GL_NO_ERROR();
GLint max2DSize, maxCubeMapSize;
glGetTexParameteriv(GL_TEXTURE_2D, GL_MAX_TEXTURE_SIZE, &max2DSize);
glGetTexParameteriv(GL_TEXTURE_CUBE_MAP, GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeMapSize);
// Assuming 2048x2048xRGBA (22meg with mips) will run on all WebGL platforms
GLint max2DSize = 0;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DSize);
GLint maxCubeMapSize = 0;
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeMapSize);
// Assuming 2048x2048xRGBA (22 mb with mips) will run on all WebGL platforms
GLint max2DSquareSize = std::min(max2DSize, 2048);
// I'd prefer this to be 2048 but that's 16meg x 6 faces or 128meg (with mips)
// 1024 is 33.5 meg (with mips)
// I'd prefer this to be 2048 but that's 16 mb x 6 faces or 128 mb (with mips)
// 1024 is 33.5 mb (with mips)
maxCubeMapSize = std::min(maxCubeMapSize, 1024);
ASSERT_GL_NO_ERROR();
GLint power = 0;
GLint size = std::pow(2, power);
GLint texWidth, texHeight;
while (size <= max2DSize)
for (GLint size = 1; size <= max2DSize; size *= 2)
{
for (int i = 0; i < 4; i++)
bool cubeMap = testCaseIndex == 3;
GLenum texTarget = cubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
GLuint program = cubeMap ? programCubeMap : mProgram;
GLint texWidth = 0, texHeight = 0;
switch (testCaseIndex)
{
bool cubeMap = i == 3 ? true : false;
GLenum texTarget = cubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
switch (i)
{
case 0:
texWidth = size;
texHeight = 1;
break;
case 1:
texWidth = 1;
texHeight = size;
break;
case 2:
case 3:
texWidth = size;
texHeight = size;
break;
}
if (texWidth == texHeight && size > max2DSquareSize)
{
continue;
}
if (cubeMap && size > maxCubeMapSize)
{
continue;
}
GLuint texture;
glGenTextures(1, &texture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(texTarget, texture);
glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
FillLevel(0, texWidth, texHeight, kNewMipColors[colorCount], cubeMap, false);
if (cubeMap)
{
glUseProgram(programCubeMap);
}
else
{
glUseProgram(mProgram);
}
glUniform1i(mTexture2DUniformLocation, 0);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 1.0f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[colorCount]);
colorCount = (colorCount + 1) % sizeof(kNewMipColors);
FillLevel(0, texWidth, texHeight, kNewMipColors[colorCount], cubeMap, false);
glGenerateMipmap(texTarget);
EXPECT_GL_NO_ERROR();
glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 1.0f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[colorCount]);
colorCount = (colorCount + 1) % sizeof(kNewMipColors);
FillLevel(0, texWidth, texHeight, kNewMipColors[colorCount], cubeMap, true);
glGenerateMipmap(texTarget);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(mProgram, "position", 1.0f);
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[colorCount]);
EXPECT_GL_NO_ERROR();
glDeleteTextures(1, &texture);
case 0:
texWidth = size;
texHeight = 1;
break;
case 1:
texWidth = 1;
texHeight = size;
break;
case 2:
case 3:
texWidth = size;
texHeight = size;
break;
}
++power;
size = std::pow(2, power);
if (texWidth == texHeight && size > max2DSquareSize)
{
return;
}
if (cubeMap && size > maxCubeMapSize)
{
return;
}
GLTexture texture;
glActiveTexture(GL_TEXTURE0);
glBindTexture(texTarget, texture);
FillLevel(0, texWidth, texHeight, kNewMipColors[colorCount], cubeMap, false);
glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(texTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(texTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
ASSERT_GL_NO_ERROR();
glClear(GL_COLOR_BUFFER_BIT);
ASSERT_GL_NO_ERROR();
glUseProgram(program);
if (cubeMap)
{
glUniform1i(textureCubeUniformLocation, 0);
}
else
{
glUniform1i(mTexture2DUniformLocation, 0);
}
drawQuad(program, "position", 1.0f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[colorCount]);
colorCount = (colorCount + 1) % kNewMipColors.size();
FillLevel(0, texWidth, texHeight, kNewMipColors[colorCount], cubeMap, false);
glGenerateMipmap(texTarget);
ASSERT_GL_NO_ERROR();
glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(program, "position", 1.0f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[colorCount]);
colorCount = (colorCount + 1) % kNewMipColors.size();
FillLevel(0, texWidth, texHeight, kNewMipColors[colorCount], cubeMap, true);
glGenerateMipmap(texTarget);
glClear(GL_COLOR_BUFFER_BIT);
drawQuad(program, "position", 1.0f);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, kNewMipColors[colorCount]);
}
}
// Permutation 0 of testTextureSize.
TEST_P(Texture2DTest, TextureSizeCase0)
{
testTextureSize(0);
}
// Permutation 1 of testTextureSize.
TEST_P(Texture2DTest, TextureSizeCase1)
{
testTextureSize(1);
}
// Permutation 2 of testTextureSize.
TEST_P(Texture2DTest, TextureSizeCase2)
{
testTextureSize(2);
}
// Permutation 3 of testTextureSize.
TEST_P(Texture2DTest, TextureSizeCase3)
{
testTextureSize(3);
}
// Test that drawing works correctly RGBA 3D texture
TEST_P(Texture3DTestES2, RGBA)
{
@ -8184,7 +8171,7 @@ class Texture2DDepthTest : public Texture2DTest
}
};
// Test depth texture compatibility with OES_depth_texture. Uses unsized internformat.
// Test depth texture compatibility with OES_depth_texture. Uses unsized internal format.
TEST_P(Texture2DDepthTest, DepthTextureES2Compatibility)
{
ANGLE_SKIP_TEST_IF(IsD3D11());