Commit 6c394220 by Brandon Schade Committed by Commit Bot

Vulkan: Fix bug in compressed texel block computation

When performing a staged update to compressed images, ensure that the bufferRowLength and bufferImageHeight is a multiple of the compressed texel block Bug: angleproject:5017 Test: angle_end2end_test --gtest_filter=*ETC1CompressedImageNPOT* Change-Id: I54327ec610d1050465d112c7eff385d19dc0c390 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2393754Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarShahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Mohan Maiya <m.maiya@samsung.com>
parent 2383e36d
......@@ -1274,6 +1274,36 @@ GLuint InternalFormat::computePixelBytes(GLenum formatType) const
return components * typeInfo.bytes;
}
bool InternalFormat::computeBufferRowLength(uint32_t width, uint32_t *resultOut) const
{
CheckedNumeric<GLuint> checkedWidth(width);
if (compressed)
{
angle::CheckedNumeric<uint32_t> checkedRowLength =
rx::CheckedRoundUp<uint32_t>(width, compressedBlockWidth);
return CheckedMathResult(checkedRowLength, resultOut);
}
return CheckedMathResult(checkedWidth, resultOut);
}
bool InternalFormat::computeBufferImageHeight(uint32_t height, uint32_t *resultOut) const
{
CheckedNumeric<GLuint> checkedHeight(height);
if (compressed)
{
angle::CheckedNumeric<uint32_t> checkedImageHeight =
rx::CheckedRoundUp<uint32_t>(height, compressedBlockHeight);
return CheckedMathResult(checkedImageHeight, resultOut);
}
return CheckedMathResult(checkedHeight, resultOut);
}
bool InternalFormat::computeRowPitch(GLenum formatType,
GLsizei width,
GLint alignment,
......
......@@ -138,6 +138,9 @@ struct InternalFormat
GLuint computePixelBytes(GLenum formatType) const;
ANGLE_NO_DISCARD bool computeBufferRowLength(uint32_t width, uint32_t *resultOut) const;
ANGLE_NO_DISCARD bool computeBufferImageHeight(uint32_t height, uint32_t *resultOut) const;
ANGLE_NO_DISCARD bool computeRowPitch(GLenum formatType,
GLsizei width,
GLint alignment,
......
......@@ -1692,18 +1692,15 @@ angle::Result TextureVk::copyAndStageImageSubresource(ContextVk *contextVk,
// Stage an update to the new image
ASSERT(stagingBuffer);
uint32_t bufferRowLength = updatedExtents.width;
uint32_t bufferImageHeight = updatedExtents.height;
const gl::InternalFormat &formatInfo =
gl::GetSizedInternalFormatInfo(mImage->getFormat().internalFormat);
if (formatInfo.compressed)
{
// In the case of a compressed texture, bufferRowLength can never be smaller than the
// compressed format's compressed block width, and bufferImageHeight can never be smaller
// than the compressed block height.
bufferRowLength = std::max(bufferRowLength, formatInfo.compressedBlockWidth);
bufferImageHeight = std::max(bufferImageHeight, formatInfo.compressedBlockHeight);
}
uint32_t bufferRowLength;
uint32_t bufferImageHeight;
ANGLE_VK_CHECK_MATH(contextVk,
formatInfo.computeBufferRowLength(updatedExtents.width, &bufferRowLength));
ANGLE_VK_CHECK_MATH(
contextVk, formatInfo.computeBufferImageHeight(updatedExtents.height, &bufferImageHeight));
ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer(
contextVk, bufferSize, dstLevelGL, currentLayer, layerCount, bufferRowLength,
bufferImageHeight, updatedExtents, offset, stagingBuffer, stagingBufferOffsets));
......
......@@ -3931,18 +3931,12 @@ angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
outputRowPitch = rowPitch;
outputDepthPitch = depthPitch;
allocationSize = totalSize;
angle::CheckedNumeric<uint32_t> checkedRowLength =
rx::CheckedRoundUp<uint32_t>(glExtents.width, storageFormatInfo.compressedBlockWidth);
angle::CheckedNumeric<uint32_t> checkedImageHeight =
rx::CheckedRoundUp<uint32_t>(glExtents.height, storageFormatInfo.compressedBlockHeight);
ANGLE_VK_CHECK_MATH(contextVk, checkedRowLength.IsValid());
ANGLE_VK_CHECK_MATH(contextVk, checkedImageHeight.IsValid());
bufferRowLength = checkedRowLength.ValueOrDie();
bufferImageHeight = checkedImageHeight.ValueOrDie();
allocationSize = totalSize;
ANGLE_VK_CHECK_MATH(
contextVk, storageFormatInfo.computeBufferRowLength(glExtents.width, &bufferRowLength));
ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeBufferImageHeight(
glExtents.height, &bufferImageHeight));
}
else
{
......
......@@ -7806,6 +7806,56 @@ TEST_P(ETC1CompressedTextureTest, ETC1CompressedSubImage)
ASSERT_GL_NO_ERROR();
}
// Fully-define a NPOT compressed texture and draw; set MAX_LEVEL and draw; then increase
// MAX_LEVEL and draw. This used to cause Vulkan validation errors.
TEST_P(ETC1CompressedTextureTest, ETC1CompressedImageNPOT)
{
// ETC texture formats are not supported on Mac OpenGL. http://anglebug.com/3853
ANGLE_SKIP_TEST_IF(IsOSX() && IsDesktopOpenGL());
ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_compressed_ETC1_RGB8_sub_texture"));
const GLuint width = 5u;
const GLuint height = 5u;
// round up to the nearest block size
const GLsizei imageSize = 8 * 8 / 2;
// smallest block size
const GLsizei minImageSize = 4 * 4 / 2;
uint8_t data[imageSize] = {0};
setWindowWidth(width);
setWindowHeight(height);
// Setup primary Texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_ETC1_RGB8_OES, width, height, 0, imageSize, data);
ASSERT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 1, GL_ETC1_RGB8_OES, width / 2, height / 2, 0,
minImageSize, data);
ASSERT_GL_NO_ERROR();
glCompressedTexImage2D(GL_TEXTURE_2D, 2, GL_ETC1_RGB8_OES, width / 4, height / 4, 0,
minImageSize, data);
ASSERT_GL_NO_ERROR();
glUseProgram(mProgram);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
drawQuad(mProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
drawQuad(mProgram, "position", 0.5f);
ASSERT_GL_NO_ERROR();
}
// Fully-define a compressed texture and draw; then decrease MAX_LEVEL and draw; then increase
// MAX_LEVEL and draw. This used to cause Vulkan validation errors.
TEST_P(ETC1CompressedTextureTest, ETC1ShrinkThenGrowMaxLevels)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment