Commit 560a8d88 by Jamie Madill

Refactor CopyTexImage validation.

Move the common validation code to a shared base function. BUG=angle:571 Change-Id: Id70b413b408a21f0a8933cfd4a09e261e637bae1 Reviewed-on: https://chromium-review.googlesource.com/200559Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarShannon Woods <shannonwoods@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 74be6a84
......@@ -698,11 +698,6 @@ void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei
void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
{
if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset != 0)
{
return gl::error(GL_INVALID_VALUE);
}
// can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
......@@ -1562,13 +1557,6 @@ void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLi
{
int faceIndex = targetToIndex(target);
GLsizei size = mImageArray[faceIndex][level]->getWidth();
if (xoffset + width > size || yoffset + height > size || zoffset != 0)
{
return gl::error(GL_INVALID_VALUE);
}
// We can only make our texture storage to a render target if the level we're copying *to* is complete
// and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
// rely on the "getBaseLevel*" methods reliably otherwise.
......@@ -1676,11 +1664,7 @@ rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
Renderbuffer *TextureCubeMap::getRenderbuffer(GLenum target, GLint level)
{
if (!IsCubemapTextureTarget(target))
{
return gl::error(GL_INVALID_OPERATION, (Renderbuffer *)NULL);
}
ASSERT(!IsCubemapTextureTarget(target));
int faceIndex = targetToIndex(target);
Renderbuffer *renderBuffer = mRenderbufferProxies.get(level, faceIndex);
......@@ -1935,11 +1919,6 @@ rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
{
if (xoffset + width > mImageArray[level]->getWidth() || yoffset + height > mImageArray[level]->getHeight() || zoffset >= mImageArray[level]->getDepth())
{
return gl::error(GL_INVALID_VALUE);
}
// can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
......@@ -2494,11 +2473,6 @@ rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
{
if (xoffset + width > getWidth(level) || yoffset + height > getHeight(level) || zoffset >= getLayers(level) || getLayers(level) == 0)
{
return gl::error(GL_INVALID_VALUE);
}
// can only make our texture storage to a render target if level 0 is defined (with a width & height) and
// the current level we're copying to is defined (with appropriate format, width & height)
bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
......
......@@ -6124,12 +6124,6 @@ void __stdcall glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GL
return;
}
// Zero sized copies are valid but no-ops
if (width == 0 || height == 0)
{
return;
}
gl::Framebuffer *framebuffer = context->getReadFramebuffer();
gl::Texture *texture = NULL;
switch (target)
......
......@@ -67,6 +67,7 @@ bool ValidTextureTarget(const Context *context, GLenum target)
// This function differs from ValidTextureTarget in that the target must be
// usable as the destination of a 2D operation-- so a cube face is valid, but
// GL_TEXTURE_CUBE_MAP is not.
// Note: duplicate of IsInternalTextureTarget
bool ValidTexture2DDestinationTarget(const Context *context, GLenum target)
{
switch (target)
......@@ -1098,4 +1099,172 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
return true;
}
bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
GLint border, GLenum *textureFormatOut)
{
if (!ValidTexture2DDestinationTarget(context, target))
{
return gl::error(GL_INVALID_ENUM, false);
}
if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (border != 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (!ValidMipLevel(context, target, level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::Framebuffer *framebuffer = context->getReadFramebuffer();
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
}
if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
{
return gl::error(GL_INVALID_OPERATION, false);
}
gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
GLenum colorbufferInternalFormat = source->getInternalFormat();
gl::Texture *texture = NULL;
GLenum textureInternalFormat = GL_NONE;
bool textureCompressed = false;
bool textureIsDepth = false;
GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0;
switch (target)
{
case GL_TEXTURE_2D:
{
gl::Texture2D *texture2d = context->getTexture2D();
if (texture2d)
{
textureInternalFormat = texture2d->getInternalFormat(level);
textureCompressed = texture2d->isCompressed(level);
textureIsDepth = texture2d->isDepth(level);
textureLevelWidth = texture2d->getWidth(level);
textureLevelHeight = texture2d->getHeight(level);
textureLevelDepth = 1;
texture = texture2d;
}
}
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
{
gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
if (textureCube)
{
textureInternalFormat = textureCube->getInternalFormat(target, level);
textureCompressed = textureCube->isCompressed(target, level);
textureIsDepth = false;
textureLevelWidth = textureCube->getWidth(target, level);
textureLevelHeight = textureCube->getHeight(target, level);
textureLevelDepth = 1;
texture = textureCube;
}
}
break;
case GL_TEXTURE_2D_ARRAY:
{
gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
if (texture2dArray)
{
textureInternalFormat = texture2dArray->getInternalFormat(level);
textureCompressed = texture2dArray->isCompressed(level);
textureIsDepth = texture2dArray->isDepth(level);
textureLevelWidth = texture2dArray->getWidth(level);
textureLevelHeight = texture2dArray->getHeight(level);
textureLevelDepth = texture2dArray->getLayers(level);
texture = texture2dArray;
}
}
break;
case GL_TEXTURE_3D:
{
gl::Texture3D *texture3d = context->getTexture3D();
if (texture3d)
{
textureInternalFormat = texture3d->getInternalFormat(level);
textureCompressed = texture3d->isCompressed(level);
textureIsDepth = texture3d->isDepth(level);
textureLevelWidth = texture3d->getWidth(level);
textureLevelHeight = texture3d->getHeight(level);
textureLevelDepth = texture3d->getDepth(level);
texture = texture3d;
}
}
break;
default:
return gl::error(GL_INVALID_ENUM, false);
}
if (!texture)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (texture->isImmutable() && !isSubImage)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (textureIsDepth)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (textureCompressed)
{
int clientVersion = context->getClientVersion();
GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat, clientVersion);
GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat, clientVersion);
if (((width % blockWidth) != 0 && width != textureLevelWidth) ||
((height % blockHeight) != 0 && height != textureLevelHeight))
{
return gl::error(GL_INVALID_OPERATION, false);
}
}
if (isSubImage)
{
if (xoffset + width > textureLevelWidth ||
yoffset + height > textureLevelHeight ||
zoffset >= textureLevelDepth)
{
return gl::error(GL_INVALID_VALUE, false);
}
}
*textureFormatOut = textureInternalFormat;
return true;
}
}
......@@ -54,6 +54,10 @@ bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint locati
bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType, unsigned int *numParams);
bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height,
GLint border, GLenum *textureInternalFormatOut);
}
#endif // LIBGLESV2_VALIDATION_ES_H
......@@ -457,122 +457,17 @@ bool ValidateES2CopyTexImageParameters(gl::Context* context, GLenum target, GLin
GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
GLint border)
{
if (!ValidTexture2DDestinationTarget(context, target))
{
return gl::error(GL_INVALID_ENUM, false);
}
if (!gl::IsInternalTextureTarget(target, context->getClientVersion()))
{
return gl::error(GL_INVALID_ENUM, false);
}
if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
{
return gl::error(GL_INVALID_VALUE, false);
}
// Verify zero border
if (border != 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
GLenum textureInternalFormat = GL_NONE;
// Validate dimensions based on Context limits and validate the texture
if (!ValidMipLevel(context, target, level))
if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat))
{
return gl::error(GL_INVALID_VALUE, false);
return false;
}
gl::Framebuffer *framebuffer = context->getReadFramebuffer();
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
}
if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
{
return gl::error(GL_INVALID_OPERATION, false);
}
GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
gl::Texture *texture = NULL;
GLenum textureFormat = GL_RGBA;
switch (target)
{
case GL_TEXTURE_2D:
{
if (width > (context->getMaximum2DTextureDimension() >> level) ||
height > (context->getMaximum2DTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::Texture2D *tex2d = context->getTexture2D();
if (tex2d)
{
if (isSubImage && !validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d))
{
return false; // error already registered by validateSubImageParams
}
texture = tex2d;
textureFormat = gl::GetFormat(tex2d->getInternalFormat(level), context->getClientVersion());
}
}
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
{
if (!isSubImage && width != height)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (width > (context->getMaximumCubeTextureDimension() >> level) ||
height > (context->getMaximumCubeTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::TextureCubeMap *texcube = context->getTextureCubeMap();
if (texcube)
{
if (isSubImage && !validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube))
{
return false; // error already registered by validateSubImageParams
}
texture = texcube;
textureFormat = gl::GetFormat(texcube->getInternalFormat(target, level), context->getClientVersion());
}
}
break;
default:
return gl::error(GL_INVALID_ENUM, false);
}
if (!texture)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (texture->isImmutable() && !isSubImage)
{
return gl::error(GL_INVALID_OPERATION, false);
}
GLenum textureFormat = gl::GetFormat(textureInternalFormat, context->getClientVersion());
// [OpenGL ES 2.0.24] table 3.9
if (isSubImage)
......
......@@ -286,160 +286,19 @@ bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y,
GLsizei width, GLsizei height, GLint border)
{
if (!ValidTexture2DDestinationTarget(context, target))
GLenum textureInternalFormat;
if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
xoffset, yoffset, zoffset, x, y, width, height, border, &textureInternalFormat))
{
return gl::error(GL_INVALID_ENUM, false);
}
if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (border != 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (!ValidMipLevel(context, target, level))
{
return gl::error(GL_INVALID_VALUE, false);
return false;
}
gl::Framebuffer *framebuffer = context->getReadFramebuffer();
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
}
if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
{
return gl::error(GL_INVALID_OPERATION, false);
}
gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
GLenum colorbufferInternalFormat = source->getInternalFormat();
gl::Texture *texture = NULL;
GLenum textureInternalFormat = GL_NONE;
bool textureCompressed = false;
bool textureIsDepth = false;
GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0;
switch (target)
{
case GL_TEXTURE_2D:
{
gl::Texture2D *texture2d = context->getTexture2D();
if (texture2d)
{
textureInternalFormat = texture2d->getInternalFormat(level);
textureCompressed = texture2d->isCompressed(level);
textureIsDepth = texture2d->isDepth(level);
textureLevelWidth = texture2d->getWidth(level);
textureLevelHeight = texture2d->getHeight(level);
textureLevelDepth = 1;
texture = texture2d;
}
}
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
{
gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
if (textureCube)
{
textureInternalFormat = textureCube->getInternalFormat(target, level);
textureCompressed = textureCube->isCompressed(target, level);
textureIsDepth = false;
textureLevelWidth = textureCube->getWidth(target, level);
textureLevelHeight = textureCube->getHeight(target, level);
textureLevelDepth = 1;
texture = textureCube;
}
}
break;
case GL_TEXTURE_2D_ARRAY:
{
gl::Texture2DArray *texture2dArray = context->getTexture2DArray();
if (texture2dArray)
{
textureInternalFormat = texture2dArray->getInternalFormat(level);
textureCompressed = texture2dArray->isCompressed(level);
textureIsDepth = texture2dArray->isDepth(level);
textureLevelWidth = texture2dArray->getWidth(level);
textureLevelHeight = texture2dArray->getHeight(level);
textureLevelDepth = texture2dArray->getLayers(level);
texture = texture2dArray;
}
}
break;
case GL_TEXTURE_3D:
{
gl::Texture3D *texture3d = context->getTexture3D();
if (texture3d)
{
textureInternalFormat = texture3d->getInternalFormat(level);
textureCompressed = texture3d->isCompressed(level);
textureIsDepth = texture3d->isDepth(level);
textureLevelWidth = texture3d->getWidth(level);
textureLevelHeight = texture3d->getHeight(level);
textureLevelDepth = texture3d->getDepth(level);
texture = texture3d;
}
}
break;
default:
return gl::error(GL_INVALID_ENUM, false);
}
if (!texture)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (texture->isImmutable() && !isSubImage)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (textureIsDepth)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (textureCompressed)
{
if ((width % 4 != 0 && width != textureLevelWidth) ||
(height % 4 != 0 && height != textureLevelHeight))
{
return gl::error(GL_INVALID_OPERATION, false);
}
}
if (isSubImage)
{
if (xoffset + width > textureLevelWidth ||
yoffset + height > textureLevelHeight ||
zoffset >= textureLevelDepth)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (!gl::IsValidCopyTexImageCombination(textureInternalFormat, colorbufferInternalFormat, context->getReadFramebufferHandle(),
context->getClientVersion()))
{
......@@ -455,8 +314,6 @@ bool ValidateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
}
}
// If width or height is zero, it is a no-op. Return false without setting an error.
return (width > 0 && height > 0);
}
......
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