summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/angle/src/libGLESv2/validationES.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/angle/src/libGLESv2/validationES.cpp')
-rw-r--r--src/3rdparty/angle/src/libGLESv2/validationES.cpp757
1 files changed, 547 insertions, 210 deletions
diff --git a/src/3rdparty/angle/src/libGLESv2/validationES.cpp b/src/3rdparty/angle/src/libGLESv2/validationES.cpp
index 309c4daedb..f79bc97e4f 100644
--- a/src/3rdparty/angle/src/libGLESv2/validationES.cpp
+++ b/src/3rdparty/angle/src/libGLESv2/validationES.cpp
@@ -1,4 +1,3 @@
-#include "precompiled.h"
//
// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
@@ -20,6 +19,7 @@
#include "libGLESv2/ProgramBinary.h"
#include "libGLESv2/TransformFeedback.h"
#include "libGLESv2/VertexArray.h"
+#include "libGLESv2/renderer/BufferImpl.h"
#include "common/mathutil.h"
#include "common/utilities.h"
@@ -168,7 +168,7 @@ bool ValidMipLevel(const Context *context, GLenum target, GLint level)
return level <= gl::log2(maxDimension);
}
-bool ValidImageSize(const gl::Context *context, GLenum target, GLint level,
+bool ValidImageSize(const Context *context, GLenum target, GLint level,
GLsizei width, GLsizei height, GLsizei depth)
{
if (level < 0 || width < 0 || height < 0 || depth < 0)
@@ -190,17 +190,16 @@ bool ValidImageSize(const gl::Context *context, GLenum target, GLint level,
return true;
}
-bool ValidCompressedImageSize(const gl::Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
+bool ValidCompressedImageSize(const Context *context, GLenum internalFormat, GLsizei width, GLsizei height)
{
- if (!IsFormatCompressed(internalFormat))
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
+ if (!formatInfo.compressed)
{
return false;
}
- GLint blockWidth = GetCompressedBlockWidth(internalFormat);
- GLint blockHeight = GetCompressedBlockHeight(internalFormat);
- if (width < 0 || (width > blockWidth && width % blockWidth != 0) ||
- height < 0 || (height > blockHeight && height % blockHeight != 0))
+ if (width < 0 || (static_cast<GLuint>(width) > formatInfo.compressedBlockWidth && width % formatInfo.compressedBlockWidth != 0) ||
+ height < 0 || (static_cast<GLuint>(height) > formatInfo.compressedBlockHeight && height % formatInfo.compressedBlockHeight != 0))
{
return false;
}
@@ -225,7 +224,7 @@ bool ValidQueryType(const Context *context, GLenum queryType)
}
}
-bool ValidProgram(const Context *context, GLuint id)
+bool ValidProgram(Context *context, GLuint id)
{
// ES3 spec (section 2.11.1) -- "Commands that accept shader or program object names will generate the
// error INVALID_VALUE if the provided name is not the name of either a shader or program object and
@@ -238,16 +237,18 @@ bool ValidProgram(const Context *context, GLuint id)
else if (context->getShader(id) != NULL)
{
// ID is the wrong type
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
else
{
// No shader/program object has this ID
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
}
-bool ValidateAttachmentTarget(const gl::Context *context, GLenum attachment)
+bool ValidateAttachmentTarget(gl::Context *context, GLenum attachment)
{
if (attachment >= GL_COLOR_ATTACHMENT0_EXT && attachment <= GL_COLOR_ATTACHMENT15_EXT)
{
@@ -255,7 +256,8 @@ bool ValidateAttachmentTarget(const gl::Context *context, GLenum attachment)
if (colorAttachment >= context->getCaps().maxColorAttachments)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
}
else
@@ -269,19 +271,21 @@ bool ValidateAttachmentTarget(const gl::Context *context, GLenum attachment)
case GL_DEPTH_STENCIL_ATTACHMENT:
if (context->getClientVersion() < 3)
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
}
return true;
}
-bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum target, GLsizei samples,
+bool ValidateRenderbufferStorageParameters(gl::Context *context, GLenum target, GLsizei samples,
GLenum internalformat, GLsizei width, GLsizei height,
bool angleExtension)
{
@@ -290,43 +294,44 @@ bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum ta
case GL_RENDERBUFFER:
break;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if (width < 0 || height < 0 || samples < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
- if (!gl::IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion()))
+ const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
+ if (!formatCaps.renderable)
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
// ANGLE_framebuffer_multisample does not explicitly state that the internal format must be
// sized but it does state that the format must be in the ES2.0 spec table 4.5 which contains
// only sized internal formats. The ES3 spec (section 4.4.2) does, however, state that the
// internal format must be sized and not an integer format if samples is greater than zero.
- if (!gl::IsSizedInternalFormat(internalformat))
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+ if (formatInfo.pixelBytes == 0)
{
- return gl::error(GL_INVALID_ENUM, false);
- }
-
- GLenum componentType = gl::GetComponentType(internalformat);
- if ((componentType == GL_UNSIGNED_INT || componentType == GL_INT) && samples > 0)
- {
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
- const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
- if (!formatCaps.renderable)
+ if ((formatInfo.componentType == GL_UNSIGNED_INT || formatInfo.componentType == GL_INT) && samples > 0)
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (static_cast<GLuint>(std::max(width, height)) > context->getCaps().maxRenderbufferSize)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
// ANGLE_framebuffer_multisample states that the value of samples must be less than or equal
@@ -335,23 +340,34 @@ bool ValidateRenderbufferStorageParameters(const gl::Context *context, GLenum ta
// internal format.
if (angleExtension)
{
- if (samples > context->getMaxSupportedSamples())
+ ASSERT(context->getExtensions().framebufferMultisample);
+ if (static_cast<GLuint>(samples) > context->getExtensions().maxSamples)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ // Check if this specific format supports enough samples
+ if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
+ {
+ context->recordError(Error(GL_OUT_OF_MEMORY));
+ return false;
}
}
else
{
- if (samples > context->getMaxSupportedFormatSamples(internalformat))
+ if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
}
GLuint handle = context->getState().getRenderbufferId();
if (handle == 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
return true;
@@ -362,7 +378,8 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ
{
if (!ValidFramebufferTarget(target))
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
gl::Framebuffer *framebuffer = context->getState().getTargetFramebuffer(target);
@@ -370,7 +387,8 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ
if (!framebuffer || (framebufferHandle == 0 && renderbuffer != 0))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (!ValidateAttachmentTarget(context, attachment))
@@ -386,7 +404,8 @@ bool ValidateFramebufferRenderbufferParameters(gl::Context *context, GLenum targ
{
if (!context->getRenderbuffer(renderbuffer))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
@@ -428,16 +447,19 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
case GL_LINEAR:
if (fromAngleExtension)
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if ((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
if (mask == 0)
@@ -450,14 +472,16 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
if (fromAngleExtension && (srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0))
{
ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation.");
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
// ES3.0 spec, section 4.3.2 states that linear filtering is only available for the
// color buffer, leaving only nearest being unfiltered from above
if ((mask & ~GL_COLOR_BUFFER_BIT) != 0 && filter != GL_NEAREST)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (context->getState().getReadFramebuffer()->id() == context->getState().getDrawFramebuffer()->id())
@@ -467,7 +491,8 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
ERR("Blits with the same source and destination framebuffer are not supported by this "
"implementation.");
}
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
gl::Framebuffer *readFramebuffer = context->getState().getReadFramebuffer();
@@ -475,12 +500,14 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
if (!readFramebuffer || readFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE ||
!drawFramebuffer || drawFramebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
- return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+ context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
+ return false;
}
if (drawFramebuffer->getSamples() != 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
bool sameBounds = srcX0 == dstX0 && srcY0 == dstY0 && srcX1 == dstX1 && srcY1 == dstY1;
@@ -493,45 +520,50 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
if (readColorBuffer && drawColorBuffer)
{
GLenum readInternalFormat = readColorBuffer->getActualFormat();
- GLenum readComponentType = gl::GetComponentType(readInternalFormat);
+ const InternalFormat &readFormatInfo = GetInternalFormatInfo(readInternalFormat);
for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; i++)
{
if (drawFramebuffer->isEnabledColorAttachment(i))
{
GLenum drawInternalFormat = drawFramebuffer->getColorbuffer(i)->getActualFormat();
- GLenum drawComponentType = gl::GetComponentType(drawInternalFormat);
+ const InternalFormat &drawFormatInfo = GetInternalFormatInfo(drawInternalFormat);
// The GL ES 3.0.2 spec (pg 193) states that:
// 1) If the read buffer is fixed point format, the draw buffer must be as well
// 2) If the read buffer is an unsigned integer format, the draw buffer must be as well
// 3) If the read buffer is a signed integer format, the draw buffer must be as well
- if ( (readComponentType == GL_UNSIGNED_NORMALIZED || readComponentType == GL_SIGNED_NORMALIZED) &&
- !(drawComponentType == GL_UNSIGNED_NORMALIZED || drawComponentType == GL_SIGNED_NORMALIZED))
+ if ( (readFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || readFormatInfo.componentType == GL_SIGNED_NORMALIZED) &&
+ !(drawFormatInfo.componentType == GL_UNSIGNED_NORMALIZED || drawFormatInfo.componentType == GL_SIGNED_NORMALIZED))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- if (readComponentType == GL_UNSIGNED_INT && drawComponentType != GL_UNSIGNED_INT)
+ if (readFormatInfo.componentType == GL_UNSIGNED_INT && drawFormatInfo.componentType != GL_UNSIGNED_INT)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- if (readComponentType == GL_INT && drawComponentType != GL_INT)
+ if (readFormatInfo.componentType == GL_INT && drawFormatInfo.componentType != GL_INT)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (readColorBuffer->getSamples() > 0 && (readInternalFormat != drawInternalFormat || !sameBounds))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
}
- if ((readComponentType == GL_INT || readComponentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
+ if ((readFormatInfo.componentType == GL_INT || readFormatInfo.componentType == GL_UNSIGNED_INT) && filter == GL_LINEAR)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (fromAngleExtension)
@@ -539,7 +571,8 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
const GLenum readColorbufferType = readFramebuffer->getReadColorbufferType();
if (readColorbufferType != GL_TEXTURE_2D && readColorbufferType != GL_RENDERBUFFER)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
for (unsigned int colorAttachment = 0; colorAttachment < gl::IMPLEMENTATION_MAX_DRAW_BUFFERS; colorAttachment++)
@@ -551,12 +584,14 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (attachment->getActualFormat() != readColorBuffer->getActualFormat())
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
}
@@ -564,7 +599,8 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
}
@@ -579,12 +615,14 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
{
if (readDepthBuffer->getActualFormat() != drawDepthBuffer->getActualFormat())
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (readDepthBuffer->getSamples() > 0 && !sameBounds)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (fromAngleExtension)
@@ -593,12 +631,14 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
{
ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
- return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
+ context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
+ return false;
}
if (readDepthBuffer->getSamples() != 0 || drawDepthBuffer->getSamples() != 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
}
@@ -613,12 +653,14 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
{
if (readStencilBuffer->getActualFormat() != drawStencilBuffer->getActualFormat())
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (readStencilBuffer->getSamples() > 0 && !sameBounds)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (fromAngleExtension)
@@ -627,12 +669,14 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1))
{
ERR("Only whole-buffer depth and stencil blits are supported by this implementation.");
- return gl::error(GL_INVALID_OPERATION, false); // only whole-buffer copies are permitted
+ context->recordError(Error(GL_INVALID_OPERATION)); // only whole-buffer copies are permitted
+ return false;
}
if (readStencilBuffer->getSamples() != 0 || drawStencilBuffer->getSamples() != 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
}
@@ -641,7 +685,7 @@ bool ValidateBlitFramebufferParameters(gl::Context *context, GLint srcX0, GLint
return true;
}
-bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
+bool ValidateGetVertexAttribParameters(Context *context, GLenum pname)
{
switch (pname)
{
@@ -661,10 +705,16 @@ bool ValidateGetVertexAttribParameters(GLenum pname, int clientVersion)
return true;
case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
- return ((clientVersion >= 3) ? true : gl::error(GL_INVALID_ENUM, false));
+ if (context->getClientVersion() < 3)
+ {
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
+ }
+ return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
}
@@ -685,7 +735,8 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_TEXTURE_MAX_LOD:
if (context->getClientVersion() < 3)
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
@@ -704,7 +755,8 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_MIRRORED_REPEAT:
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
case GL_TEXTURE_MIN_FILTER:
@@ -718,7 +770,8 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_LINEAR_MIPMAP_LINEAR:
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
@@ -729,7 +782,8 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_LINEAR:
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
@@ -740,20 +794,23 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
if (!context->getExtensions().textureFilterAnisotropic)
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
// we assume the parameter passed to this validation method is truncated, not rounded
if (param < 1)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
return true;
@@ -770,7 +827,8 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_COMPARE_REF_TO_TEXTURE:
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
@@ -788,7 +846,8 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_NEVER:
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
@@ -806,7 +865,8 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_ONE:
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
@@ -814,16 +874,18 @@ bool ValidateTexParamParameters(gl::Context *context, GLenum pname, GLint param)
case GL_TEXTURE_MAX_LEVEL:
if (param < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
}
-bool ValidateSamplerObjectParameter(GLenum pname)
+bool ValidateSamplerObjectParameter(gl::Context *context, GLenum pname)
{
switch (pname)
{
@@ -839,7 +901,8 @@ bool ValidateSamplerObjectParameter(GLenum pname)
return true;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
}
@@ -851,17 +914,20 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
- return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+ context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
+ return false;
}
if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (!framebuffer->getReadColorbuffer())
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
GLenum currentInternalFormat, currentFormat, currentType;
@@ -874,20 +940,22 @@ bool ValidateReadPixelsParameters(gl::Context *context, GLint x, GLint y, GLsize
if (!(currentFormat == format && currentType == type) && !validReadFormat)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
- : GetSizedInternalFormat(format, type);
+ GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
+ const InternalFormat &sizedFormatInfo = GetInternalFormatInfo(sizedInternalFormat);
- GLsizei outputPitch = GetRowPitch(sizedInternalFormat, type, width, context->getState().getPackAlignment());
+ GLsizei outputPitch = sizedFormatInfo.computeRowPitch(type, width, context->getState().getPackAlignment());
// sized query sanity check
if (bufSize)
{
int requiredSize = outputPitch * height;
if (requiredSize > *bufSize)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
@@ -898,12 +966,14 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
{
if (!ValidQueryType(context, target))
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if (id == 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
// From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
@@ -923,7 +993,8 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
// no query may be active for either if glBeginQuery targets either.
if (context->getState().isQueryActive())
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
Query *queryObject = context->getQuery(id, true, target);
@@ -931,13 +1002,15 @@ bool ValidateBeginQuery(gl::Context *context, GLenum target, GLuint id)
// check that name was obtained with glGenQueries
if (!queryObject)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
// check for type mismatch
if (queryObject->getType() != target)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
return true;
@@ -947,19 +1020,16 @@ bool ValidateEndQuery(gl::Context *context, GLenum target)
{
if (!ValidQueryType(context, target))
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
const Query *queryObject = context->getState().getActiveQuery(target);
if (queryObject == NULL)
{
- return gl::error(GL_INVALID_OPERATION, false);
- }
-
- if (!queryObject->isStarted())
- {
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
return true;
@@ -970,13 +1040,15 @@ static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniform
{
if (count < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
if (!programBinary)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (location == -1)
@@ -987,7 +1059,8 @@ static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniform
if (!programBinary->isValidUniformLocation(location))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
LinkedUniform *uniform = programBinary->getUniformByLocation(location);
@@ -995,7 +1068,8 @@ static bool ValidateUniformCommonBase(gl::Context *context, GLenum targetUniform
// attempting to write an array to a non-array uniform is an INVALID_OPERATION
if (uniform->elementCount() == 1 && count > 1)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
*uniformOut = uniform;
@@ -1007,7 +1081,8 @@ bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, G
// Check for ES3 uniform entry points
if (VariableComponentType(uniformType) == GL_UNSIGNED_INT && context->getClientVersion() < 3)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
LinkedUniform *uniform = NULL;
@@ -1020,7 +1095,8 @@ bool ValidateUniform(gl::Context *context, GLenum uniformType, GLint location, G
bool samplerUniformCheck = (IsSampler(uniform->type) && uniformType == GL_INT);
if (!samplerUniformCheck && uniformType != uniform->type && targetBoolType != uniform->type)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
return true;
@@ -1034,12 +1110,14 @@ bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint locati
int cols = VariableColumnCount(matrixType);
if (rows != cols && context->getClientVersion() < 3)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (transpose != GL_FALSE && context->getClientVersion() < 3)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
LinkedUniform *uniform = NULL;
@@ -1050,7 +1128,8 @@ bool ValidateUniformMatrix(gl::Context *context, GLenum matrixType, GLint locati
if (uniform->type != matrixType)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
return true;
@@ -1060,7 +1139,8 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
{
if (!context->getQueryParameterInfo(pname, nativeType, numParams))
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if (pname >= GL_DRAW_BUFFER0 && pname <= GL_DRAW_BUFFER15)
@@ -1069,7 +1149,8 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
if (colorAttachment >= context->getCaps().maxDrawBuffers)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
@@ -1079,9 +1160,10 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
case GL_TEXTURE_BINDING_CUBE_MAP:
case GL_TEXTURE_BINDING_3D:
case GL_TEXTURE_BINDING_2D_ARRAY:
- if (context->getState().getActiveSampler() >= context->getMaximumCombinedTextureImageUnits())
+ if (context->getState().getActiveSampler() >= context->getCaps().maxCombinedTextureImageUnits)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
break;
@@ -1092,13 +1174,15 @@ bool ValidateStateQuery(gl::Context *context, GLenum pname, GLenum *nativeType,
ASSERT(framebuffer);
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
FramebufferAttachment *attachment = framebuffer->getReadColorbuffer();
if (!attachment)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
break;
@@ -1123,46 +1207,51 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
if (!ValidTexture2DDestinationTarget(context, target))
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
if (border != 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
if (!ValidMipLevel(context, target, level))
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
gl::Framebuffer *framebuffer = context->getState().getReadFramebuffer();
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
- return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+ context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
+ return false;
}
if (context->getState().getReadFramebuffer()->id() != 0 && framebuffer->getSamples() != 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
const gl::Caps &caps = context->getCaps();
gl::Texture *texture = NULL;
GLenum textureInternalFormat = GL_NONE;
- bool textureCompressed = false;
- bool textureIsDepth = false;
GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0;
@@ -1176,8 +1265,6 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
if (texture2d)
{
textureInternalFormat = texture2d->getInternalFormat(level);
- textureCompressed = texture2d->isCompressed(level);
- textureIsDepth = texture2d->isDepth(level);
textureLevelWidth = texture2d->getWidth(level);
textureLevelHeight = texture2d->getHeight(level);
textureLevelDepth = 1;
@@ -1198,8 +1285,6 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
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;
@@ -1215,8 +1300,6 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
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);
@@ -1232,8 +1315,6 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
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);
@@ -1244,33 +1325,37 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
break;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if (!texture)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (texture->isImmutable() && !isSubImage)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- if (textureIsDepth)
+ const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalformat);
+
+ if (formatInfo.depthBits > 0)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- if (textureCompressed)
+ if (formatInfo.compressed)
{
- GLint blockWidth = GetCompressedBlockWidth(textureInternalFormat);
- GLint blockHeight = GetCompressedBlockHeight(textureInternalFormat);
-
- if (((width % blockWidth) != 0 && width != textureLevelWidth) ||
- ((height % blockHeight) != 0 && height != textureLevelHeight))
+ if (((width % formatInfo.compressedBlockWidth) != 0 && width != textureLevelWidth) ||
+ ((height % formatInfo.compressedBlockHeight) != 0 && height != textureLevelHeight))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
@@ -1280,25 +1365,29 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
yoffset + height > textureLevelHeight ||
zoffset >= textureLevelDepth)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
}
else
{
if (IsCubemapTextureTarget(target) && width != height)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
- if (!IsValidInternalFormat(internalformat, context->getExtensions(), context->getClientVersion()))
+ if (!formatInfo.textureSupport(context->getClientVersion(), context->getExtensions()))
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
int maxLevelDimension = (maxDimension >> level);
if (static_cast<int>(width) > maxLevelDimension || static_cast<int>(height) > maxLevelDimension)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
}
@@ -1306,7 +1395,7 @@ bool ValidateCopyTexImageParametersBase(gl::Context* context, GLenum target, GLi
return true;
}
-static bool ValidateDrawBase(const gl::Context *context, GLenum mode, GLsizei count)
+static bool ValidateDrawBase(Context *context, GLenum mode, GLsizei count, GLsizei maxVertex, GLsizei primcount)
{
switch (mode)
{
@@ -1319,71 +1408,128 @@ static bool ValidateDrawBase(const gl::Context *context, GLenum mode, GLsizei co
case GL_TRIANGLE_FAN:
break;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if (count < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
+ const State &state = context->getState();
+
// Check for mapped buffers
- if (context->hasMappedBuffer(GL_ARRAY_BUFFER))
+ if (state.hasMappedBuffer(GL_ARRAY_BUFFER))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- const gl::DepthStencilState &depthStencilState = context->getState().getDepthStencilState();
+ const gl::DepthStencilState &depthStencilState = state.getDepthStencilState();
if (depthStencilState.stencilWritemask != depthStencilState.stencilBackWritemask ||
- context->getState().getStencilRef() != context->getState().getStencilBackRef() ||
+ state.getStencilRef() != state.getStencilBackRef() ||
depthStencilState.stencilMask != depthStencilState.stencilBackMask)
{
// Note: these separate values are not supported in WebGL, due to D3D's limitations.
// See Section 6.10 of the WebGL 1.0 spec
ERR("This ANGLE implementation does not support separate front/back stencil "
"writemasks, reference values, or stencil mask values.");
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- const gl::Framebuffer *fbo = context->getState().getDrawFramebuffer();
+ const gl::Framebuffer *fbo = state.getDrawFramebuffer();
if (!fbo || fbo->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
- return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
+ context->recordError(Error(GL_INVALID_FRAMEBUFFER_OPERATION));
+ return false;
+ }
+
+ if (state.getCurrentProgramId() == 0)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- if (context->getState().getCurrentProgramId() == 0)
+ gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
+ if (!programBinary->validateSamplers(NULL, context->getCaps()))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
- if (!programBinary->validateSamplers(NULL))
+ // Buffer validations
+ const VertexArray *vao = state.getVertexArray();
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
+ bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
+ if (attribActive && attrib.enabled)
+ {
+ gl::Buffer *buffer = attrib.buffer.get();
+
+ if (buffer)
+ {
+ GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
+ GLint64 maxVertexElement = 0;
+
+ if (attrib.divisor > 0)
+ {
+ maxVertexElement = static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
+ }
+ else
+ {
+ maxVertexElement = static_cast<GLint64>(maxVertex);
+ }
+
+ GLint64 attribDataSize = maxVertexElement * attribStride;
+
+ // [OpenGL ES 3.0.2] section 2.9.4 page 40:
+ // We can return INVALID_OPERATION if our vertex attribute does not have
+ // enough backing data.
+ if (attribDataSize > buffer->getSize())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ }
+ else if (attrib.pointer == NULL)
+ {
+ // This is an application error that would normally result in a crash,
+ // but we catch it and return an error
+ context->recordError(Error(GL_INVALID_OPERATION, "An enabled vertex array has no buffer and no pointer."));
+ return false;
+ }
+ }
}
// No-op if zero count
return (count > 0);
}
-bool ValidateDrawArrays(const gl::Context *context, GLenum mode, GLint first, GLsizei count)
+bool ValidateDrawArrays(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
if (first < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
- gl::TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback();
+ const State &state = context->getState();
+ gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused() &&
curTransformFeedback->getDrawMode() != mode)
{
// It is an invalid operation to call DrawArrays or DrawArraysInstanced with a draw mode
// that does not match the current transform feedback object's draw mode (if transform feedback
// is active), (3.0.2, section 2.14, pg 86)
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- if (!ValidateDrawBase(context, mode, count))
+ if (!ValidateDrawBase(context, mode, count, count, primcount))
{
return false;
}
@@ -1391,14 +1537,15 @@ bool ValidateDrawArrays(const gl::Context *context, GLenum mode, GLint first, GL
return true;
}
-bool ValidateDrawArraysInstanced(const gl::Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+bool ValidateDrawArraysInstanced(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
{
if (primcount < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
- if (!ValidateDrawArrays(context, mode, first, count))
+ if (!ValidateDrawArrays(context, mode, first, count, primcount))
{
return false;
}
@@ -1407,7 +1554,41 @@ bool ValidateDrawArraysInstanced(const gl::Context *context, GLenum mode, GLint
return (primcount > 0);
}
-bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
+static bool ValidateDrawInstancedANGLE(Context *context)
+{
+ // Verify there is at least one active attribute with a divisor of zero
+ const gl::State& state = context->getState();
+
+ gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
+
+ const VertexArray *vao = state.getVertexArray();
+ for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+ {
+ const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
+ bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
+ if (active && attrib.divisor == 0)
+ {
+ return true;
+ }
+ }
+
+ context->recordError(Error(GL_INVALID_OPERATION, "ANGLE_instanced_arrays requires that at least one active attribute"
+ "has a divisor of zero."));
+ return false;
+}
+
+bool ValidateDrawArraysInstancedANGLE(Context *context, GLenum mode, GLint first, GLsizei count, GLsizei primcount)
+{
+ if (!ValidateDrawInstancedANGLE(context))
+ {
+ return false;
+ }
+
+ return ValidateDrawArraysInstanced(context, mode, first, count, primcount);
+}
+
+bool ValidateDrawElements(Context *context, GLenum mode, GLsizei count, GLenum type,
+ const GLvoid* indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
{
switch (type)
{
@@ -1417,34 +1598,89 @@ bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count
case GL_UNSIGNED_INT:
if (!context->getExtensions().elementIndexUint)
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
break;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
- gl::TransformFeedback *curTransformFeedback = context->getState().getCurrentTransformFeedback();
+ const State &state = context->getState();
+
+ gl::TransformFeedback *curTransformFeedback = state.getCurrentTransformFeedback();
if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
{
// It is an invalid operation to call DrawElements, DrawRangeElements or DrawElementsInstanced
// while transform feedback is active, (3.0.2, section 2.14, pg 86)
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
// Check for mapped buffers
- if (context->hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
+ if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ const gl::VertexArray *vao = state.getVertexArray();
+ const gl::Buffer *elementArrayBuffer = vao->getElementArrayBuffer();
+ if (!indices && !elementArrayBuffer)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ if (elementArrayBuffer)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ const gl::Type &typeInfo = gl::GetTypeInfo(type);
+
+ GLint64 offset = reinterpret_cast<GLint64>(indices);
+ GLint64 byteCount = static_cast<GLint64>(typeInfo.bytes) * static_cast<GLint64>(count)+offset;
+
+ // check for integer overflows
+ if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeInfo.bytes) ||
+ byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
+ {
+ context->recordError(Error(GL_OUT_OF_MEMORY));
+ return false;
+ }
+
+ // Check for reading past the end of the bound buffer object
+ if (byteCount > elementArrayBuffer->getSize())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+ }
+ else if (!indices)
+ {
+ // Catch this programming error here
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
- gl::VertexArray *vao = context->getState().getVertexArray();
- if (!indices && !vao->getElementArrayBuffer())
+ // Use max index to validate if our vertex buffers are large enough for the pull.
+ // TODO: offer fast path, with disabled index validation.
+ // TODO: also disable index checking on back-ends that are robust to out-of-range accesses.
+ if (elementArrayBuffer)
+ {
+ GLint64 offset = reinterpret_cast<GLint64>(indices);
+ if (!elementArrayBuffer->getIndexRangeCache()->findRange(type, offset, count, indexRangeOut, NULL))
+ {
+ const void *dataPointer = elementArrayBuffer->getImplementation()->getData();
+ const uint8_t *offsetPointer = static_cast<const uint8_t *>(dataPointer) + offset;
+ *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, offsetPointer, count);
+ }
+ }
+ else
{
- return gl::error(GL_INVALID_OPERATION, false);
+ *indexRangeOut = rx::IndexRangeCache::ComputeRange(type, indices, count);
}
- if (!ValidateDrawBase(context, mode, count))
+ if (!ValidateDrawBase(context, mode, count, static_cast<GLsizei>(indexRangeOut->end), primcount))
{
return false;
}
@@ -1452,15 +1688,18 @@ bool ValidateDrawElements(const gl::Context *context, GLenum mode, GLsizei count
return true;
}
-bool ValidateDrawElementsInstanced(const gl::Context *context, GLenum mode, GLsizei count, GLenum type,
- const GLvoid *indices, GLsizei primcount)
+bool ValidateDrawElementsInstanced(Context *context,
+ GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei primcount,
+ rx::RangeUI *indexRangeOut)
{
if (primcount < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
- if (!ValidateDrawElements(context, mode, count, type, indices))
+ if (!ValidateDrawElements(context, mode, count, type, indices, primcount, indexRangeOut))
{
return false;
}
@@ -1469,12 +1708,24 @@ bool ValidateDrawElementsInstanced(const gl::Context *context, GLenum mode, GLsi
return (primcount > 0);
}
-bool ValidateFramebufferTextureBase(const gl::Context *context, GLenum target, GLenum attachment,
+bool ValidateDrawElementsInstancedANGLE(Context *context, GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices, GLsizei primcount, rx::RangeUI *indexRangeOut)
+{
+ if (!ValidateDrawInstancedANGLE(context))
+ {
+ return false;
+ }
+
+ return ValidateDrawElementsInstanced(context, mode, count, type, indices, primcount, indexRangeOut);
+}
+
+bool ValidateFramebufferTextureBase(Context *context, GLenum target, GLenum attachment,
GLuint texture, GLint level)
{
if (!ValidFramebufferTarget(target))
{
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
if (!ValidateAttachmentTarget(context, attachment))
@@ -1488,12 +1739,14 @@ bool ValidateFramebufferTextureBase(const gl::Context *context, GLenum target, G
if (tex == NULL)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
if (level < 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
}
@@ -1502,19 +1755,21 @@ bool ValidateFramebufferTextureBase(const gl::Context *context, GLenum target, G
if (framebufferHandle == 0 || !framebuffer)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
return true;
}
-bool ValidateFramebufferTexture2D(const gl::Context *context, GLenum target, GLenum attachment,
+bool ValidateFramebufferTexture2D(Context *context, GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
{
// Attachments are required to be bound to level 0 in ES2
if (context->getClientVersion() < 3 && level != 0)
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
if (!ValidateFramebufferTextureBase(context, target, attachment, texture, level))
@@ -1535,16 +1790,19 @@ bool ValidateFramebufferTexture2D(const gl::Context *context, GLenum target, GLe
{
if (level > gl::log2(caps.max2DTextureSize))
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
if (tex->getTarget() != GL_TEXTURE_2D)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
gl::Texture2D *tex2d = static_cast<gl::Texture2D *>(tex);
if (tex2d->isCompressed(level))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
break;
@@ -1558,26 +1816,105 @@ bool ValidateFramebufferTexture2D(const gl::Context *context, GLenum target, GLe
{
if (level > gl::log2(caps.maxCubeMapTextureSize))
{
- return gl::error(GL_INVALID_VALUE, false);
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
}
if (tex->getTarget() != GL_TEXTURE_CUBE_MAP)
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
gl::TextureCubeMap *texcube = static_cast<gl::TextureCubeMap *>(tex);
if (texcube->isCompressed(textarget, level))
{
- return gl::error(GL_INVALID_OPERATION, false);
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
}
}
break;
default:
- return gl::error(GL_INVALID_ENUM, false);
+ context->recordError(Error(GL_INVALID_ENUM));
+ return false;
}
}
return true;
}
+bool ValidateGetUniformBase(Context *context, GLuint program, GLint location)
+{
+ if (program == 0)
+ {
+ context->recordError(Error(GL_INVALID_VALUE));
+ return false;
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+
+ if (!programObject || !programObject->isLinked())
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+ if (!programBinary)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ if (!programBinary->isValidUniformLocation(location))
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetUniformfv(Context *context, GLuint program, GLint location, GLfloat* params)
+{
+ return ValidateGetUniformBase(context, program, location);
+}
+
+bool ValidateGetUniformiv(Context *context, GLuint program, GLint location, GLint* params)
+{
+ return ValidateGetUniformBase(context, program, location);
+}
+
+static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
+{
+ if (!ValidateGetUniformBase(context, program, location))
+ {
+ return false;
+ }
+
+ gl::Program *programObject = context->getProgram(program);
+ ASSERT(programObject);
+ gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+
+ // sized queries -- ensure the provided buffer is large enough
+ LinkedUniform *uniform = programBinary->getUniformByLocation(location);
+ size_t requiredBytes = VariableExternalSize(uniform->type);
+ if (static_cast<size_t>(bufSize) < requiredBytes)
+ {
+ context->recordError(Error(GL_INVALID_OPERATION));
+ return false;
+ }
+
+ return true;
+}
+
+bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
+{
+ return ValidateSizedGetUniform(context, program, location, bufSize);
+}
+
+bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
+{
+ return ValidateSizedGetUniform(context, program, location, bufSize);
+}
+
}