Fix validation for compressed texture functions.
* No validation that the format matched the texture level's format for
SubImage calls.
* WebGL does not allow the base level to be smaller than the block size.
* ANGLE used to allow mips of size 3 when this is disallowed.
* Don't early-exit validation when dimensions are 0, imageSize validation
happens later.
TEST=conformance/extensions/webgl-compressed-texture-s3tc
BUG=angleproject:1998
Change-Id: I05f5a0b5180344d67b036fdecc17edd2256e85ab
Reviewed-on: https://chromium-review.googlesource.com/480442
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index a4efd03..e2c7af7 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -2136,10 +2136,15 @@
}
}
+bool ValidCompressedDimension(GLsizei size, GLuint blockSize, bool smallerThanBlockSizeAllowed)
+{
+ return (smallerThanBlockSizeAllowed && (size > 0) && (blockSize % size == 0)) ||
+ (size % blockSize == 0);
+}
+
bool ValidCompressedImageSize(const ValidationContext *context,
GLenum internalFormat,
- GLint xoffset,
- GLint yoffset,
+ GLint level,
GLsizei width,
GLsizei height)
{
@@ -2149,6 +2154,45 @@
return false;
}
+ if (width < 0 || height < 0)
+ {
+ return false;
+ }
+
+ if (CompressedTextureFormatRequiresExactSize(internalFormat))
+ {
+ // The ANGLE extensions allow specifying compressed textures with sizes smaller than the
+ // block size for level 0 but WebGL disallows this.
+ bool smallerThanBlockSizeAllowed =
+ level > 0 || !context->getExtensions().webglCompatibility;
+
+ if (!ValidCompressedDimension(width, formatInfo.compressedBlockWidth,
+ smallerThanBlockSizeAllowed) ||
+ !ValidCompressedDimension(height, formatInfo.compressedBlockHeight,
+ smallerThanBlockSizeAllowed))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ValidCompressedSubImageSize(const ValidationContext *context,
+ GLenum internalFormat,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ size_t textureWidth,
+ size_t textureHeight)
+{
+ const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
+ if (!formatInfo.compressed)
+ {
+ return false;
+ }
+
if (xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
{
return false;
@@ -2157,11 +2201,19 @@
if (CompressedTextureFormatRequiresExactSize(internalFormat))
{
if (xoffset % formatInfo.compressedBlockWidth != 0 ||
- yoffset % formatInfo.compressedBlockHeight != 0 ||
- (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth &&
- width % formatInfo.compressedBlockWidth != 0) ||
- (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight &&
- height % formatInfo.compressedBlockHeight != 0))
+ yoffset % formatInfo.compressedBlockHeight != 0)
+ {
+ return false;
+ }
+
+ // Allowed to either have data that is a multiple of block size or is smaller than the block
+ // size but fills the entire mip
+ bool fillsEntireMip = xoffset == 0 && yoffset == 0 &&
+ static_cast<size_t>(width) == textureWidth &&
+ static_cast<size_t>(height) == textureHeight;
+ bool sizeMultipleOfBlockSize = (width % formatInfo.compressedBlockWidth) == 0 &&
+ (height % formatInfo.compressedBlockHeight) == 0;
+ if (!sizeMultipleOfBlockSize && !fillsEntireMip)
{
return false;
}
@@ -3598,14 +3650,7 @@
const gl::InternalFormat &formatInfo =
gl::GetInternalFormatInfo(internalformat, GL_UNSIGNED_BYTE);
- if (formatInfo.depthBits > 0)
- {
- context->handleError(Error(GL_INVALID_OPERATION));
- return false;
- }
-
- if (formatInfo.compressed &&
- !ValidCompressedImageSize(context, internalformat, xoffset, yoffset, width, height))
+ if (formatInfo.depthBits > 0 || formatInfo.compressed)
{
context->handleError(Error(GL_INVALID_OPERATION));
return false;