summaryrefslogtreecommitdiff
path: root/chromium/third_party/angle/src/libANGLE/validationES2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/angle/src/libANGLE/validationES2.cpp')
-rw-r--r--chromium/third_party/angle/src/libANGLE/validationES2.cpp1092
1 files changed, 1002 insertions, 90 deletions
diff --git a/chromium/third_party/angle/src/libANGLE/validationES2.cpp b/chromium/third_party/angle/src/libANGLE/validationES2.cpp
index 30c6c74173e..c92ddad83e7 100644
--- a/chromium/third_party/angle/src/libANGLE/validationES2.cpp
+++ b/chromium/third_party/angle/src/libANGLE/validationES2.cpp
@@ -21,6 +21,7 @@
#include "libANGLE/Uniform.h"
#include "common/mathutil.h"
+#include "common/string_utils.h"
#include "common/utilities.h"
namespace gl
@@ -60,11 +61,245 @@ bool IsPartialBlit(gl::Context *context,
return false;
}
+template <typename T>
+bool ValidatePathInstances(gl::Context *context,
+ GLsizei numPaths,
+ const void *paths,
+ GLuint pathBase)
+{
+ const auto *array = static_cast<const T *>(paths);
+
+ for (GLsizei i = 0; i < numPaths; ++i)
+ {
+ const GLuint pathName = array[i] + pathBase;
+ if (context->hasPath(pathName) && !context->hasPathData(pathName))
+ {
+ context->handleError(gl::Error(GL_INVALID_OPERATION, "No such path object."));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ValidateInstancedPathParameters(gl::Context *context,
+ GLsizei numPaths,
+ GLenum pathNameType,
+ const void *paths,
+ GLuint pathBase,
+ GLenum transformType,
+ const GLfloat *transformValues)
+{
+ if (!context->getExtensions().pathRendering)
+ {
+ context->handleError(
+ gl::Error(GL_INVALID_OPERATION, "GL_CHROMIUM_path_rendering is not available."));
+ return false;
+ }
+
+ if (paths == nullptr)
+ {
+ context->handleError(gl::Error(GL_INVALID_VALUE, "No path name array."));
+ return false;
+ }
+
+ if (numPaths < 0)
+ {
+ context->handleError(gl::Error(GL_INVALID_VALUE, "Invalid (negative) numPaths."));
+ return false;
+ }
+
+ if (!angle::IsValueInRangeForNumericType<std::uint32_t>(numPaths))
+ {
+ context->handleError(gl::Error(GL_INVALID_OPERATION, "Overflow in numPaths."));
+ return false;
+ }
+
+ std::uint32_t pathNameTypeSize = 0;
+ std::uint32_t componentCount = 0;
+
+ switch (pathNameType)
+ {
+ case GL_UNSIGNED_BYTE:
+ pathNameTypeSize = sizeof(GLubyte);
+ if (!ValidatePathInstances<GLubyte>(context, numPaths, paths, pathBase))
+ return false;
+ break;
+
+ case GL_BYTE:
+ pathNameTypeSize = sizeof(GLbyte);
+ if (!ValidatePathInstances<GLbyte>(context, numPaths, paths, pathBase))
+ return false;
+ break;
+
+ case GL_UNSIGNED_SHORT:
+ pathNameTypeSize = sizeof(GLushort);
+ if (!ValidatePathInstances<GLushort>(context, numPaths, paths, pathBase))
+ return false;
+ break;
+
+ case GL_SHORT:
+ pathNameTypeSize = sizeof(GLshort);
+ if (!ValidatePathInstances<GLshort>(context, numPaths, paths, pathBase))
+ return false;
+ break;
+
+ case GL_UNSIGNED_INT:
+ pathNameTypeSize = sizeof(GLuint);
+ if (!ValidatePathInstances<GLuint>(context, numPaths, paths, pathBase))
+ return false;
+ break;
+
+ case GL_INT:
+ pathNameTypeSize = sizeof(GLint);
+ if (!ValidatePathInstances<GLint>(context, numPaths, paths, pathBase))
+ return false;
+ break;
+
+ default:
+ context->handleError(gl::Error(GL_INVALID_ENUM, "Invalid path name type."));
+ return false;
+ }
+
+ switch (transformType)
+ {
+ case GL_NONE:
+ componentCount = 0;
+ break;
+ case GL_TRANSLATE_X_CHROMIUM:
+ case GL_TRANSLATE_Y_CHROMIUM:
+ componentCount = 1;
+ break;
+ case GL_TRANSLATE_2D_CHROMIUM:
+ componentCount = 2;
+ break;
+ case GL_TRANSLATE_3D_CHROMIUM:
+ componentCount = 3;
+ break;
+ case GL_AFFINE_2D_CHROMIUM:
+ case GL_TRANSPOSE_AFFINE_2D_CHROMIUM:
+ componentCount = 6;
+ break;
+ case GL_AFFINE_3D_CHROMIUM:
+ case GL_TRANSPOSE_AFFINE_3D_CHROMIUM:
+ componentCount = 12;
+ break;
+ default:
+ context->handleError(gl::Error(GL_INVALID_ENUM, "Invalid transformation."));
+ return false;
+ }
+ if (componentCount != 0 && transformValues == nullptr)
+ {
+ context->handleError(gl::Error(GL_INVALID_VALUE, "No transform array given."));
+ return false;
+ }
+
+ angle::CheckedNumeric<std::uint32_t> checkedSize(0);
+ checkedSize += (numPaths * pathNameTypeSize);
+ checkedSize += (numPaths * sizeof(GLfloat) * componentCount);
+ if (!checkedSize.IsValid())
+ {
+ context->handleError(gl::Error(GL_INVALID_OPERATION, "Overflow in num paths."));
+ return false;
+ }
+
+ return true;
+}
+
+bool IsValidCopyTextureFormat(Context *context, GLenum internalFormat)
+{
+ const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat);
+ switch (internalFormatInfo.format)
+ {
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_LUMINANCE_ALPHA:
+ case GL_RGB:
+ case GL_RGBA:
+ return true;
+
+ case GL_RED:
+ return context->getClientMajorVersion() >= 3 || context->getExtensions().textureRG;
+
+ case GL_BGRA_EXT:
+ return context->getExtensions().textureFormatBGRA8888;
+
+ default:
+ return false;
+ }
+}
+
+bool IsValidCopyTextureDestinationFormatType(Context *context, GLint internalFormat, GLenum type)
+{
+ switch (internalFormat)
+ {
+ case GL_RGB:
+ case GL_RGBA:
+ break;
+
+ case GL_BGRA_EXT:
+ return context->getExtensions().textureFormatBGRA8888;
+
+ default:
+ return false;
+ }
+
+ switch (type)
+ {
+ case GL_UNSIGNED_BYTE:
+ break;
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+bool IsValidCopyTextureDestinationTarget(Context *context, GLenum target)
+{
+ switch (target)
+ {
+ case GL_TEXTURE_2D:
+ return true;
+
+ // TODO(geofflang): accept GL_TEXTURE_RECTANGLE_ARB if the texture_rectangle extension is
+ // supported
+
+ default:
+ return false;
+ }
+}
+
+bool IsValidCopyTextureSourceTarget(Context *context, GLenum target)
+{
+ if (IsValidCopyTextureDestinationTarget(context, target))
+ {
+ return true;
+ }
+
+ // TODO(geofflang): accept GL_TEXTURE_EXTERNAL_OES if the texture_external extension is
+ // supported
+
+ return false;
+}
+
} // anonymous namespace
-bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level, GLenum internalformat, bool isCompressed, bool isSubImage,
- GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
- GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+bool ValidateES2TexImageParameters(Context *context,
+ GLenum target,
+ GLint level,
+ GLenum internalformat,
+ bool isCompressed,
+ bool isSubImage,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ GLsizei imageSize,
+ const GLvoid *pixels)
{
if (!ValidTexture2DDestinationTarget(context, target))
{
@@ -135,7 +370,8 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
{
if (format != GL_NONE)
{
- if (gl::GetSizedInternalFormat(format, type) != texture->getInternalFormat(target, level))
+ if (gl::GetSizedInternalFormat(format, type) !=
+ texture->getFormat(target, level).asSized())
{
context->handleError(Error(GL_INVALID_OPERATION));
return false;
@@ -168,7 +404,7 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
if (isCompressed)
{
GLenum actualInternalFormat =
- isSubImage ? texture->getInternalFormat(target, level) : internalformat;
+ isSubImage ? texture->getFormat(target, level).asSized() : internalformat;
switch (actualInternalFormat)
{
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
@@ -468,6 +704,12 @@ bool ValidateES2TexImageParameters(Context *context, GLenum target, GLint level,
}
}
+ if (!ValidImageDataSize(context, target, width, height, 1, internalformat, type, pixels,
+ imageSize))
+ {
+ return false;
+ }
+
return true;
}
@@ -484,29 +726,28 @@ bool ValidateES2CopyTexImageParameters(ValidationContext *context,
GLsizei height,
GLint border)
{
- GLenum textureInternalFormat = GL_NONE;
-
if (!ValidTexture2DDestinationTarget(context, target))
{
context->handleError(Error(GL_INVALID_ENUM, "Invalid texture target"));
return false;
}
+ Format textureFormat = Format::Invalid();
if (!ValidateCopyTexImageParametersBase(context, target, level, internalformat, isSubImage,
- xoffset, yoffset, 0, x, y, width, height, border, &textureInternalFormat))
+ xoffset, yoffset, 0, x, y, width, height, border,
+ &textureFormat))
{
return false;
}
const gl::Framebuffer *framebuffer = context->getGLState().getReadFramebuffer();
- GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getInternalFormat();
- const auto &internalFormatInfo = gl::GetInternalFormatInfo(textureInternalFormat);
- GLenum textureFormat = internalFormatInfo.format;
+ GLenum colorbufferFormat = framebuffer->getReadColorbuffer()->getFormat().asSized();
+ const auto &formatInfo = *textureFormat.info;
// [OpenGL ES 2.0.24] table 3.9
if (isSubImage)
{
- switch (textureFormat)
+ switch (formatInfo.format)
{
case GL_ALPHA:
if (colorbufferFormat != GL_ALPHA8_EXT &&
@@ -604,8 +845,7 @@ bool ValidateES2CopyTexImageParameters(ValidationContext *context,
return false;
}
- if (internalFormatInfo.type == GL_FLOAT &&
- !context->getExtensions().textureFloat)
+ if (formatInfo.type == GL_FLOAT && !context->getExtensions().textureFloat)
{
context->handleError(Error(GL_INVALID_OPERATION));
return false;
@@ -965,52 +1205,6 @@ bool ValidateES2TexStorageParameters(Context *context, GLenum target, GLsizei le
return true;
}
-// check for combinations of format and type that are valid for ReadPixels
-bool ValidES2ReadFormatType(ValidationContext *context, GLenum format, GLenum type)
-{
- switch (format)
- {
- case GL_RGBA:
- switch (type)
- {
- case GL_UNSIGNED_BYTE:
- break;
- default:
- return false;
- }
- break;
- case GL_BGRA_EXT:
- switch (type)
- {
- case GL_UNSIGNED_BYTE:
- case GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT:
- case GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT:
- break;
- default:
- return false;
- }
- break;
- case GL_RG_EXT:
- case GL_RED_EXT:
- if (!context->getExtensions().textureRG)
- {
- return false;
- }
- switch (type)
- {
- case GL_UNSIGNED_BYTE:
- break;
- default:
- return false;
- }
- break;
-
- default:
- return false;
- }
- return true;
-}
-
bool ValidateDiscardFramebufferEXT(Context *context, GLenum target, GLsizei numAttachments,
const GLenum *attachments)
{
@@ -1454,6 +1648,30 @@ static bool ValidateObjectIdentifierAndName(Context *context, GLenum identifier,
context->handleError(Error(GL_INVALID_ENUM, "Invalid identifier."));
return false;
}
+}
+
+static bool ValidateLabelLength(Context *context, GLsizei length, const GLchar *label)
+{
+ size_t labelLength = 0;
+
+ if (length < 0)
+ {
+ if (label != nullptr)
+ {
+ labelLength = strlen(label);
+ }
+ }
+ else
+ {
+ labelLength = static_cast<size_t>(length);
+ }
+
+ if (labelLength > context->getExtensions().maxLabelLength)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH."));
+ return false;
+ }
return true;
}
@@ -1475,11 +1693,8 @@ bool ValidateObjectLabelKHR(Context *context,
return false;
}
- size_t labelLength = (length < 0) ? strlen(label) : length;
- if (labelLength > context->getExtensions().maxLabelLength)
+ if (!ValidateLabelLength(context, length, label))
{
- context->handleError(
- Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH."));
return false;
}
@@ -1510,8 +1725,7 @@ bool ValidateGetObjectLabelKHR(Context *context,
return false;
}
- // Can no-op if bufSize is zero.
- return bufSize > 0;
+ return true;
}
static bool ValidateObjectPtrName(Context *context, const void *ptr)
@@ -1541,11 +1755,8 @@ bool ValidateObjectPtrLabelKHR(Context *context,
return false;
}
- size_t labelLength = (length < 0) ? strlen(label) : length;
- if (labelLength > context->getExtensions().maxLabelLength)
+ if (!ValidateLabelLength(context, length, label))
{
- context->handleError(
- Error(GL_INVALID_VALUE, "Label length is larger than GL_MAX_LABEL_LENGTH."));
return false;
}
@@ -1575,8 +1786,7 @@ bool ValidateGetObjectPtrLabelKHR(Context *context,
return false;
}
- // Can no-op if bufSize is zero.
- return bufSize > 0;
+ return true;
}
bool ValidateGetPointervKHR(Context *context, GLenum pname, void **params)
@@ -1671,7 +1881,8 @@ bool ValidateBlitFramebufferANGLE(Context *context,
}
// Return an error if the destination formats do not match
- if (attachment->getInternalFormat() != readColorAttachment->getInternalFormat())
+ if (!Format::SameSized(attachment->getFormat(),
+ readColorAttachment->getFormat()))
{
context->handleError(Error(GL_INVALID_OPERATION));
return false;
@@ -1766,15 +1977,46 @@ bool ValidateTexImage2D(Context *context,
GLenum type,
const GLvoid *pixels)
{
- if (context->getClientVersion() < 3)
+ if (context->getClientMajorVersion() < 3)
+ {
+ return ValidateES2TexImageParameters(context, target, level, internalformat, false, false,
+ 0, 0, width, height, border, format, type, -1, pixels);
+ }
+
+ ASSERT(context->getClientMajorVersion() >= 3);
+ return ValidateES3TexImage2DParameters(context, target, level, internalformat, false, false, 0,
+ 0, 0, width, height, 1, border, format, type, -1,
+ pixels);
+}
+
+bool ValidateTexImage2DRobust(Context *context,
+ GLenum target,
+ GLint level,
+ GLint internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ GLsizei bufSize,
+ const GLvoid *pixels)
+{
+ if (!ValidateRobustEntryPoint(context, bufSize))
+ {
+ return false;
+ }
+
+ if (context->getClientMajorVersion() < 3)
{
return ValidateES2TexImageParameters(context, target, level, internalformat, false, false,
- 0, 0, width, height, border, format, type, pixels);
+ 0, 0, width, height, border, format, type, bufSize,
+ pixels);
}
- ASSERT(context->getClientVersion() >= 3);
+ ASSERT(context->getClientMajorVersion() >= 3);
return ValidateES3TexImage2DParameters(context, target, level, internalformat, false, false, 0,
- 0, 0, width, height, 1, border, format, type, pixels);
+ 0, 0, width, height, 1, border, format, type, bufSize,
+ pixels);
}
bool ValidateTexSubImage2D(Context *context,
@@ -1789,15 +2031,16 @@ bool ValidateTexSubImage2D(Context *context,
const GLvoid *pixels)
{
- if (context->getClientVersion() < 3)
+ if (context->getClientMajorVersion() < 3)
{
return ValidateES2TexImageParameters(context, target, level, GL_NONE, false, true, xoffset,
- yoffset, width, height, 0, format, type, pixels);
+ yoffset, width, height, 0, format, type, -1, pixels);
}
- ASSERT(context->getClientVersion() >= 3);
+ ASSERT(context->getClientMajorVersion() >= 3);
return ValidateES3TexImage2DParameters(context, target, level, GL_NONE, false, true, xoffset,
- yoffset, 0, width, height, 1, 0, format, type, pixels);
+ yoffset, 0, width, height, 1, 0, format, type, -1,
+ pixels);
}
bool ValidateCompressedTexImage2D(Context *context,
@@ -1810,19 +2053,19 @@ bool ValidateCompressedTexImage2D(Context *context,
GLsizei imageSize,
const GLvoid *data)
{
- if (context->getClientVersion() < 3)
+ if (context->getClientMajorVersion() < 3)
{
if (!ValidateES2TexImageParameters(context, target, level, internalformat, true, false, 0,
- 0, width, height, border, GL_NONE, GL_NONE, data))
+ 0, width, height, border, GL_NONE, GL_NONE, -1, data))
{
return false;
}
}
else
{
- ASSERT(context->getClientVersion() >= 3);
+ ASSERT(context->getClientMajorVersion() >= 3);
if (!ValidateES3TexImage2DParameters(context, target, level, internalformat, true, false, 0,
- 0, 0, width, height, 1, border, GL_NONE, GL_NONE,
+ 0, 0, width, height, 1, border, GL_NONE, GL_NONE, -1,
data))
{
return false;
@@ -1858,19 +2101,19 @@ bool ValidateCompressedTexSubImage2D(Context *context,
GLsizei imageSize,
const GLvoid *data)
{
- if (context->getClientVersion() < 3)
+ if (context->getClientMajorVersion() < 3)
{
if (!ValidateES2TexImageParameters(context, target, level, GL_NONE, true, true, xoffset,
- yoffset, width, height, 0, GL_NONE, GL_NONE, data))
+ yoffset, width, height, 0, GL_NONE, GL_NONE, -1, data))
{
return false;
}
}
else
{
- ASSERT(context->getClientVersion() >= 3);
+ ASSERT(context->getClientMajorVersion() >= 3);
if (!ValidateES3TexImage2DParameters(context, target, level, GL_NONE, true, true, xoffset,
- yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE,
+ yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE, -1,
data))
{
return false;
@@ -1994,6 +2237,13 @@ bool ValidateBindTexture(Context *context, GLenum target, GLuint texture)
return false;
}
+ if (!context->getGLState().isBindGeneratesResourceEnabled() &&
+ !context->isTextureGenerated(texture))
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Texture was not generated"));
+ return false;
+ }
+
switch (target)
{
case GL_TEXTURE_2D:
@@ -2002,7 +2252,7 @@ bool ValidateBindTexture(Context *context, GLenum target, GLuint texture)
case GL_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
- if (context->getClientVersion() < 3)
+ if (context->getClientMajorVersion() < 3)
{
context->handleError(Error(GL_INVALID_ENUM, "GLES 3.0 disabled"));
return false;
@@ -2552,4 +2802,666 @@ bool ValidateIsPath(Context *context)
return true;
}
+bool ValidateCoverFillPathInstanced(Context *context,
+ GLsizei numPaths,
+ GLenum pathNameType,
+ const void *paths,
+ GLuint pathBase,
+ GLenum coverMode,
+ GLenum transformType,
+ const GLfloat *transformValues)
+{
+ if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase,
+ transformType, transformValues))
+ return false;
+
+ switch (coverMode)
+ {
+ case GL_CONVEX_HULL_CHROMIUM:
+ case GL_BOUNDING_BOX_CHROMIUM:
+ case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM:
+ break;
+ default:
+ context->handleError(Error(GL_INVALID_ENUM, "Invalid cover mode."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateCoverStrokePathInstanced(Context *context,
+ GLsizei numPaths,
+ GLenum pathNameType,
+ const void *paths,
+ GLuint pathBase,
+ GLenum coverMode,
+ GLenum transformType,
+ const GLfloat *transformValues)
+{
+ if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase,
+ transformType, transformValues))
+ return false;
+
+ switch (coverMode)
+ {
+ case GL_CONVEX_HULL_CHROMIUM:
+ case GL_BOUNDING_BOX_CHROMIUM:
+ case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM:
+ break;
+ default:
+ context->handleError(Error(GL_INVALID_ENUM, "Invalid cover mode."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateStencilFillPathInstanced(Context *context,
+ GLsizei numPaths,
+ GLenum pathNameType,
+ const void *paths,
+ GLuint pathBase,
+ GLenum fillMode,
+ GLuint mask,
+ GLenum transformType,
+ const GLfloat *transformValues)
+{
+
+ if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase,
+ transformType, transformValues))
+ return false;
+
+ switch (fillMode)
+ {
+ case GL_COUNT_UP_CHROMIUM:
+ case GL_COUNT_DOWN_CHROMIUM:
+ break;
+ default:
+ context->handleError(Error(GL_INVALID_ENUM, "Invalid fill mode."));
+ return false;
+ }
+ if (!isPow2(mask + 1))
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Invalid stencil bit mask."));
+ return false;
+ }
+ return true;
+}
+
+bool ValidateStencilStrokePathInstanced(Context *context,
+ GLsizei numPaths,
+ GLenum pathNameType,
+ const void *paths,
+ GLuint pathBase,
+ GLint reference,
+ GLuint mask,
+ GLenum transformType,
+ const GLfloat *transformValues)
+{
+ if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase,
+ transformType, transformValues))
+ return false;
+
+ // no more validation here.
+
+ return true;
+}
+
+bool ValidateStencilThenCoverFillPathInstanced(Context *context,
+ GLsizei numPaths,
+ GLenum pathNameType,
+ const void *paths,
+ GLuint pathBase,
+ GLenum fillMode,
+ GLuint mask,
+ GLenum coverMode,
+ GLenum transformType,
+ const GLfloat *transformValues)
+{
+ if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase,
+ transformType, transformValues))
+ return false;
+
+ switch (coverMode)
+ {
+ case GL_CONVEX_HULL_CHROMIUM:
+ case GL_BOUNDING_BOX_CHROMIUM:
+ case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM:
+ break;
+ default:
+ context->handleError(Error(GL_INVALID_ENUM, "Invalid cover mode."));
+ return false;
+ }
+
+ switch (fillMode)
+ {
+ case GL_COUNT_UP_CHROMIUM:
+ case GL_COUNT_DOWN_CHROMIUM:
+ break;
+ default:
+ context->handleError(Error(GL_INVALID_ENUM, "Invalid fill mode."));
+ return false;
+ }
+ if (!isPow2(mask + 1))
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Invalid stencil bit mask."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateStencilThenCoverStrokePathInstanced(Context *context,
+ GLsizei numPaths,
+ GLenum pathNameType,
+ const void *paths,
+ GLuint pathBase,
+ GLint reference,
+ GLuint mask,
+ GLenum coverMode,
+ GLenum transformType,
+ const GLfloat *transformValues)
+{
+ if (!ValidateInstancedPathParameters(context, numPaths, pathNameType, paths, pathBase,
+ transformType, transformValues))
+ return false;
+
+ switch (coverMode)
+ {
+ case GL_CONVEX_HULL_CHROMIUM:
+ case GL_BOUNDING_BOX_CHROMIUM:
+ case GL_BOUNDING_BOX_OF_BOUNDING_BOXES_CHROMIUM:
+ break;
+ default:
+ context->handleError(Error(GL_INVALID_ENUM, "Invalid cover mode."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateBindFragmentInputLocation(Context *context,
+ GLuint program,
+ GLint location,
+ const GLchar *name)
+{
+ if (!context->getExtensions().pathRendering)
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION, "GL_CHROMIUM_path_rendering is not available."));
+ return false;
+ }
+
+ const GLint MaxLocation = context->getCaps().maxVaryingVectors * 4;
+ if (location >= MaxLocation)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Location exceeds max varying."));
+ return false;
+ }
+
+ const auto *programObject = context->getProgram(program);
+ if (!programObject)
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "No such program."));
+ return false;
+ }
+
+ if (!name)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "No name given."));
+ return false;
+ }
+
+ if (angle::BeginsWith(name, "gl_"))
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Cannot bind a built-in variable."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateProgramPathFragmentInputGen(Context *context,
+ GLuint program,
+ GLint location,
+ GLenum genMode,
+ GLint components,
+ const GLfloat *coeffs)
+{
+ if (!context->getExtensions().pathRendering)
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION, "GL_CHROMIUM_path_rendering is not available."));
+ return false;
+ }
+
+ const auto *programObject = context->getProgram(program);
+ if (!programObject || programObject->isFlaggedForDeletion())
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "No such program."));
+ return false;
+ }
+
+ if (!programObject->isLinked())
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Program is not linked."));
+ return false;
+ }
+
+ switch (genMode)
+ {
+ case GL_NONE:
+ if (components != 0)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Invalid components."));
+ return false;
+ }
+ break;
+
+ case GL_OBJECT_LINEAR_CHROMIUM:
+ case GL_EYE_LINEAR_CHROMIUM:
+ case GL_CONSTANT_CHROMIUM:
+ if (components < 1 || components > 4)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Invalid components."));
+ return false;
+ }
+ if (!coeffs)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "No coefficients array given."));
+ return false;
+ }
+ break;
+
+ default:
+ context->handleError(Error(GL_INVALID_ENUM, "Invalid gen mode."));
+ return false;
+ }
+
+ // If the location is -1 then the command is silently ignored
+ // and no further validation is needed.
+ if (location == -1)
+ return true;
+
+ const auto &binding = programObject->getFragmentInputBindingInfo(location);
+
+ if (!binding.valid)
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "No such binding."));
+ return false;
+ }
+
+ if (binding.type != GL_NONE)
+ {
+ GLint expectedComponents = 0;
+ switch (binding.type)
+ {
+ case GL_FLOAT:
+ expectedComponents = 1;
+ break;
+ case GL_FLOAT_VEC2:
+ expectedComponents = 2;
+ break;
+ case GL_FLOAT_VEC3:
+ expectedComponents = 3;
+ break;
+ case GL_FLOAT_VEC4:
+ expectedComponents = 4;
+ break;
+ default:
+ context->handleError(Error(GL_INVALID_OPERATION,
+ "Fragment input type is not a floating point scalar or vector."));
+ return false;
+ }
+ if (expectedComponents != components && genMode != GL_NONE)
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Unexpected number of components"));
+ return false;
+ }
+ }
+ return true;
+}
+
+bool ValidateCopyTextureCHROMIUM(Context *context,
+ GLuint sourceId,
+ GLuint destId,
+ GLint internalFormat,
+ GLenum destType,
+ GLboolean unpackFlipY,
+ GLboolean unpackPremultiplyAlpha,
+ GLboolean unpackUnmultiplyAlpha)
+{
+ if (!context->getExtensions().copyTexture)
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION, "GL_CHROMIUM_copy_texture extension not available."));
+ return false;
+ }
+
+ const gl::Texture *source = context->getTexture(sourceId);
+ if (source == nullptr)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Source texture is not a valid texture object."));
+ return false;
+ }
+
+ if (!IsValidCopyTextureSourceTarget(context, source->getTarget()))
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Source texture a valid texture type."));
+ return false;
+ }
+
+ GLenum sourceTarget = source->getTarget();
+ ASSERT(sourceTarget != GL_TEXTURE_CUBE_MAP);
+ if (source->getWidth(sourceTarget, 0) == 0 || source->getHeight(sourceTarget, 0) == 0)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Level 0 of the source texture must be defined."));
+ return false;
+ }
+
+ const gl::Format &sourceFormat = source->getFormat(sourceTarget, 0);
+ if (!IsValidCopyTextureFormat(context, sourceFormat.format))
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION, "Source texture internal format is invalid."));
+ return false;
+ }
+
+ const gl::Texture *dest = context->getTexture(destId);
+ if (dest == nullptr)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Destination texture is not a valid texture object."));
+ return false;
+ }
+
+ if (!IsValidCopyTextureDestinationTarget(context, dest->getTarget()))
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Destination texture a valid texture type."));
+ return false;
+ }
+
+ if (!IsValidCopyTextureDestinationFormatType(context, internalFormat, destType))
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION,
+ "Destination internal format and type combination is not valid."));
+ return false;
+ }
+
+ if (dest->getImmutableFormat())
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Destination texture is immutable."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateCopySubTextureCHROMIUM(Context *context,
+ GLuint sourceId,
+ GLuint destId,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLboolean unpackFlipY,
+ GLboolean unpackPremultiplyAlpha,
+ GLboolean unpackUnmultiplyAlpha)
+{
+ if (!context->getExtensions().copyTexture)
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION, "GL_CHROMIUM_copy_texture extension not available."));
+ return false;
+ }
+
+ const gl::Texture *source = context->getTexture(sourceId);
+ if (source == nullptr)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Source texture is not a valid texture object."));
+ return false;
+ }
+
+ if (!IsValidCopyTextureSourceTarget(context, source->getTarget()))
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Source texture a valid texture type."));
+ return false;
+ }
+
+ GLenum sourceTarget = source->getTarget();
+ ASSERT(sourceTarget != GL_TEXTURE_CUBE_MAP);
+ if (source->getWidth(sourceTarget, 0) == 0 || source->getHeight(sourceTarget, 0) == 0)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Level 0 of the source texture must be defined."));
+ return false;
+ }
+
+ if (x < 0 || y < 0)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "x and y cannot be negative."));
+ return false;
+ }
+
+ if (width < 0 || height < 0)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "width and height cannot be negative."));
+ return false;
+ }
+
+ if (static_cast<size_t>(x + width) > source->getWidth(sourceTarget, 0) ||
+ static_cast<size_t>(y + height) > source->getHeight(sourceTarget, 0))
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Source texture not large enough to copy from."));
+ return false;
+ }
+
+ const gl::Format &sourceFormat = source->getFormat(sourceTarget, 0);
+ if (!IsValidCopyTextureFormat(context, sourceFormat.format))
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION, "Source texture internal format is invalid."));
+ return false;
+ }
+
+ const gl::Texture *dest = context->getTexture(destId);
+ if (dest == nullptr)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Destination texture is not a valid texture object."));
+ return false;
+ }
+
+ if (!IsValidCopyTextureDestinationTarget(context, dest->getTarget()))
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Destination texture a valid texture type."));
+ return false;
+ }
+
+ GLenum destTarget = dest->getTarget();
+ ASSERT(destTarget != GL_TEXTURE_CUBE_MAP);
+ if (dest->getWidth(sourceTarget, 0) == 0 || dest->getHeight(sourceTarget, 0) == 0)
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Level 0 of the destination texture must be defined."));
+ return false;
+ }
+
+ const gl::Format &destFormat = dest->getFormat(destTarget, 0);
+ if (!IsValidCopyTextureDestinationFormatType(context, destFormat.format, destFormat.type))
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION,
+ "Destination internal format and type combination is not valid."));
+ return false;
+ }
+
+ if (xoffset < 0 || yoffset < 0)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "xoffset and yoffset cannot be negative."));
+ return false;
+ }
+
+ if (static_cast<size_t>(xoffset + width) > dest->getWidth(destTarget, 0) ||
+ static_cast<size_t>(yoffset + height) > dest->getHeight(destTarget, 0))
+ {
+ context->handleError(
+ Error(GL_INVALID_VALUE, "Destination texture not large enough to copy to."));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateCreateShader(Context *context, GLenum type)
+{
+ switch (type)
+ {
+ case GL_VERTEX_SHADER:
+ case GL_FRAGMENT_SHADER:
+ break;
+ case GL_COMPUTE_SHADER:
+ if (context->getGLVersion().isES31())
+ {
+ break;
+ }
+ default:
+ context->handleError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateBufferData(ValidationContext *context,
+ GLenum target,
+ GLsizeiptr size,
+ const GLvoid *data,
+ GLenum usage)
+{
+ if (size < 0)
+ {
+ context->handleError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ switch (usage)
+ {
+ case GL_STREAM_DRAW:
+ case GL_STATIC_DRAW:
+ case GL_DYNAMIC_DRAW:
+ break;
+
+ case GL_STREAM_READ:
+ case GL_STREAM_COPY:
+ case GL_STATIC_READ:
+ case GL_STATIC_COPY:
+ case GL_DYNAMIC_READ:
+ case GL_DYNAMIC_COPY:
+ if (context->getClientMajorVersion() < 3)
+ {
+ context->handleError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+ break;
+
+ default:
+ context->handleError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ if (!ValidBufferTarget(context, target))
+ {
+ context->handleError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ Buffer *buffer = context->getGLState().getTargetBuffer(target);
+
+ if (!buffer)
+ {
+ context->handleError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateBufferSubData(ValidationContext *context,
+ GLenum target,
+ GLintptr offset,
+ GLsizeiptr size,
+ const GLvoid *data)
+{
+ if (size < 0 || offset < 0)
+ {
+ context->handleError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ if (!ValidBufferTarget(context, target))
+ {
+ context->handleError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+
+ Buffer *buffer = context->getGLState().getTargetBuffer(target);
+
+ if (!buffer)
+ {
+ context->handleError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ if (buffer->isMapped())
+ {
+ context->handleError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ // Check for possible overflow of size + offset
+ angle::CheckedNumeric<size_t> checkedSize(size);
+ checkedSize += offset;
+ if (!checkedSize.IsValid())
+ {
+ context->handleError(Error(GL_OUT_OF_MEMORY));
+ return false;
+ }
+
+ if (size + offset > buffer->getSize())
+ {
+ context->handleError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateEnableExtensionANGLE(ValidationContext *context, const GLchar *name)
+{
+ if (!context->getExtensions().webglCompatibility)
+ {
+ context->handleError(
+ Error(GL_INVALID_OPERATION, "GL_ANGLE_webgl_compatibility is not available."));
+ return false;
+ }
+
+ const ExtensionInfoMap &extensionInfos = GetExtensionInfoMap();
+ auto extension = extensionInfos.find(name);
+ if (extension == extensionInfos.end() || !extension->second.Enableable)
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Extension %s is not enableable.", name));
+ return false;
+ }
+
+ return true;
+}
+
} // namespace gl