Fix handling of incomplete CubeMapArray textures

GFXBench Car Chase binds a cube map array as a default texture,
then immediately samples from it without setting it up.  This
ends up treating the cube map array as incomplete.

On the Vulkan backend, this is resulting in multiple validation
errors, followed by a crash in the driver.  There are a number of
errors, but a telling one is this:

  vkCreateImage(): pCreateInfo->flags contains
  VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, but pCreateInfo->arrayLayers (=1)
  is not greater than or equal to 6. The Vulkan spec states: If
  imageType is VK_IMAGE_TYPE_2D and flags contains
  VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, extent.width and extent.height
  must be equal and arrayLayers must be greater than or equal to 6

This corresponds to language in the GLES 3.2 spec:

  8.18. IMMUTABLE-FORMAT TEXTURE IMAGES
  TexStorage3D Errors
  An INVALID_OPERATION error is generated if any of the following
  conditions hold:
  * target is TEXTURE_CUBE_MAP_ARRAY and depth is not a multiple of 6

Since ANGLE treats incomplete textures as immutable, we need to update
the dimensions of the backing image for CUBE_MAP_ARRAY.

Also add a new test that exposes the problem.

Test: IncompleteTextureTestES31.IncompleteTextureCubeMapArray
Bug: b/218314686
Change-Id: Ibef41e15a7cfccb05e6039bfb8504d237bc42cd4
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3546290
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Cody Northrop <cnorthrop@google.com>
This commit is contained in:
Cody Northrop
2022-03-22 16:44:14 -06:00
committed by Angle LUCI CQ
parent 041c4c6d28
commit 32af258def
2 changed files with 83 additions and 2 deletions

View File

@@ -591,13 +591,27 @@ angle::Result IncompleteTextureSet::getIncompleteTexture(
ContextImpl *implFactory = context->getImplementation();
const gl::Extents colorSize(1, 1, 1);
gl::Extents colorSize(1, 1, 1);
gl::PixelUnpackState unpack;
unpack.alignment = 1;
const gl::Box area(0, 0, 0, 1, 1, 1);
gl::Box area(0, 0, 0, 1, 1, 1);
const IncompleteTextureParameters &incompleteTextureParam =
kIncompleteTextureParameters[format];
// Cube map arrays are expected to have layer counts that are multiples of 6
constexpr int kCubeMapArraySize = 6;
if (type == gl::TextureType::CubeMapArray)
{
// From the GLES 3.2 spec:
// 8.18. IMMUTABLE-FORMAT TEXTURE IMAGES
// TexStorage3D Errors
// An INVALID_OPERATION error is generated if any of the following conditions hold:
// * target is TEXTURE_CUBE_MAP_ARRAY and depth is not a multiple of 6
// Since ANGLE treats incomplete textures as immutable, respect that here.
colorSize.depth = kCubeMapArraySize;
area.depth = kCubeMapArraySize;
}
// If a texture is external use a 2D texture for the incomplete texture
gl::TextureType createType = (type == gl::TextureType::External) ? gl::TextureType::_2D : type;
@@ -638,6 +652,23 @@ angle::Result IncompleteTextureSet::getIncompleteTexture(
incompleteTextureParam.clearColor));
}
}
else if (type == gl::TextureType::CubeMapArray)
{
// We need to provide enough pixel data to fill the array of six faces
GLubyte incompleteCubeArrayPixels[kCubeMapArraySize][4];
for (int i = 0; i < kCubeMapArraySize; ++i)
{
incompleteCubeArrayPixels[i][0] = incompleteTextureParam.clearColor[0];
incompleteCubeArrayPixels[i][1] = incompleteTextureParam.clearColor[1];
incompleteCubeArrayPixels[i][2] = incompleteTextureParam.clearColor[2];
incompleteCubeArrayPixels[i][3] = incompleteTextureParam.clearColor[3];
}
ANGLE_TRY(t->setSubImage(mutableContext, unpack, nullptr,
gl::NonCubeTextureTypeToTarget(createType), 0, area,
incompleteTextureParam.format, incompleteTextureParam.type,
*incompleteCubeArrayPixels));
}
else if (type == gl::TextureType::_2DMultisample)
{
// Call a specialized clear function to init a multisample texture.

View File

@@ -242,6 +242,56 @@ void main()
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
// This mirrors a scenario seen in GFXBench Car Chase where a
// default CUBE_MAP_ARRAY texture is used without being setup.
// Its ends up sampling from an incomplete texture.
TEST_P(IncompleteTextureTestES31, IncompleteTextureCubeMapArray)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_cube_map_array"));
constexpr char kVS[] =
R"(#version 310 es
precision mediump float;
in vec3 pos;
void main() {
gl_Position = vec4(pos, 1.0);
})";
constexpr char kFS[] =
R"(#version 310 es
#extension GL_EXT_texture_cube_map_array : enable
precision mediump float;
out vec4 color;
uniform lowp samplerCubeArray uTex;
void main(){
vec4 outColor = vec4(0.0);
// Pull a color from each cube face to ensure they are all initialized
outColor += texture(uTex, vec4(1.0, 0.0, 0.0, 0.0));
outColor += texture(uTex, vec4(-1.0, 0.0, 0.0, 0.0));
outColor += texture(uTex, vec4(0.0, 1.0, 0.0, 0.0));
outColor += texture(uTex, vec4(0.0, -1.0, 0.0, 0.0));
outColor += texture(uTex, vec4(0.0, 0.0, 1.0, 0.0));
outColor += texture(uTex, vec4(0.0, 0.0, -1.0, 0.0));
color = outColor;
})";
ANGLE_GL_PROGRAM(program, kVS, kFS);
glUseProgram(program);
glUniform1i(glGetUniformLocation(program, "uTex"), 0);
glActiveTexture(GL_TEXTURE0);
// Bind the default texture and don't set it up. This ends up being incomplete.
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, 0);
drawQuad(program, "pos", 0.5f, 1.0f, true);
ASSERT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(0, 0, angle::GLColor::black);
}
// Verifies that an incomplete integer texture has a signed integer type default value.
TEST_P(IncompleteTextureTestES3, IntegerType)
{