Refactored validation for gl*Tex*Image2D.

TRAC #22956 Signed-off-by: Jamie Madill Signed-off-by: Shannon Woods Author: Geoff Lang git-svn-id: https://angleproject.googlecode.com/svn/branches/es3proto@2354 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 6cf2b0e9
...@@ -22,14 +22,14 @@ ...@@ -22,14 +22,14 @@
#include "libGLESv2/Query.h" #include "libGLESv2/Query.h"
#include "libGLESv2/Context.h" #include "libGLESv2/Context.h"
bool validImageSize(GLint level, GLsizei width, GLsizei height, GLsizei depth) bool validImageSize(const gl::Context *context, GLint level, GLsizei width, GLsizei height, GLsizei depth)
{ {
if (level < 0 || width < 0 || height < 0 || depth < 0) if (level < 0 || width < 0 || height < 0 || depth < 0)
{ {
return false; return false;
} }
if (gl::getContext() && gl::getContext()->supportsNonPower2Texture()) if (context->supportsNonPower2Texture())
{ {
return true; return true;
} }
...@@ -47,6 +47,21 @@ bool validImageSize(GLint level, GLsizei width, GLsizei height, GLsizei depth) ...@@ -47,6 +47,21 @@ bool validImageSize(GLint level, GLsizei width, GLsizei height, GLsizei depth)
return false; return false;
} }
bool validCompressedImageSize(GLsizei width, GLsizei height)
{
if (width != 1 && width != 2 && width % 4 != 0)
{
return false;
}
if (height != 1 && height != 2 && height % 4 != 0)
{
return false;
}
return true;
}
// Verify that format/type are one of the combinations from table 3.4. // Verify that format/type are one of the combinations from table 3.4.
bool checkTextureFormatType(GLenum format, GLenum type) bool checkTextureFormatType(GLenum format, GLenum type)
{ {
...@@ -223,39 +238,30 @@ bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height, ...@@ -223,39 +238,30 @@ bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height,
return true; return true;
} }
bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage, bool validateES2TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type) GLint border, GLenum format, GLenum type, const GLvoid *pixels)
{ {
// Validate image size if (!validImageSize(context, level, width, height, 1))
if (level < 0 || width < 0 || height < 0 || depth < 0 )
{ {
return gl::error(GL_INVALID_VALUE, false); return gl::error(GL_INVALID_VALUE, false);
} }
if (isCompressed) if (isCompressed && !validCompressedImageSize(width, height))
{ {
if (width != 1 && width != 2 && width % 4 != 0) return gl::error(GL_INVALID_OPERATION, false);
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (height != 1 && height != 2 && height % 4 != 0)
{
return gl::error(GL_INVALID_OPERATION, false);
}
} }
// Verify zero border if (level < 0 || xoffset < 0 ||
if (border != 0) std::numeric_limits<GLsizei>::max() - xoffset < width ||
std::numeric_limits<GLsizei>::max() - yoffset < height)
{ {
return gl::error(GL_INVALID_VALUE, false); return gl::error(GL_INVALID_VALUE, false);
} }
// Validate dimensions based on Context limits and validate the texture if (!isSubImage && !isCompressed && internalformat != GLint(format))
if (level > context->getMaximumTextureLevel())
{ {
return gl::error(GL_INVALID_VALUE, false); return gl::error(GL_INVALID_OPERATION, false);
} }
gl::Texture *texture = NULL; gl::Texture *texture = NULL;
...@@ -263,7 +269,6 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le ...@@ -263,7 +269,6 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le
GLenum textureInternalFormat = GL_NONE; GLenum textureInternalFormat = GL_NONE;
GLint textureLevelWidth = 0; GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0; GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0;
switch (target) switch (target)
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
...@@ -274,16 +279,23 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le ...@@ -274,16 +279,23 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le
return gl::error(GL_INVALID_VALUE, false); return gl::error(GL_INVALID_VALUE, false);
} }
gl::Texture2D *texture2d = context->getTexture2D(); gl::Texture2D *tex2d = context->getTexture2D();
if (texture2d) if (tex2d)
{ {
textureCompressed = texture2d->isCompressed(level); textureCompressed = tex2d->isCompressed(level);
textureInternalFormat = texture2d->getInternalFormat(level); textureInternalFormat = tex2d->getInternalFormat(level);
textureLevelWidth = texture2d->getWidth(level); textureLevelWidth = tex2d->getWidth(level);
textureLevelHeight = texture2d->getHeight(level); textureLevelHeight = tex2d->getHeight(level);
textureLevelDepth = 1; texture = tex2d;
texture = texture2d; }
if (isSubImage && !validateSubImageParams2D(isCompressed, width, height, xoffset, yoffset,
level, format, type, tex2d))
{
return false;
} }
texture = tex2d;
} }
break; break;
...@@ -294,73 +306,35 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le ...@@ -294,73 +306,35 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
{ {
if (width != height) if (!isSubImage && width != height)
{ {
return gl::error(GL_INVALID_VALUE, false); return gl::error(GL_INVALID_VALUE, false);
} }
if (width > (context->getMaximumCubeTextureDimension() >> level)) if (width > (context->getMaximumCubeTextureDimension() >> level) ||
height > (context->getMaximumCubeTextureDimension() >> level))
{ {
return gl::error(GL_INVALID_VALUE, false); return gl::error(GL_INVALID_VALUE, false);
} }
gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); gl::TextureCubeMap *texCube = context->getTextureCubeMap();
if (textureCube) if (texCube)
{
textureCompressed = textureCube->isCompressed(target, level);
textureInternalFormat = textureCube->getInternalFormat(target, level);
textureLevelWidth = textureCube->getWidth(target, level);
textureLevelHeight = textureCube->getHeight(target, level);
textureLevelDepth = 1;
texture = textureCube;
}
}
break;
case GL_TEXTURE_3D:
{
if (width > (context->getMaximum3DTextureDimension() >> level) ||
height > (context->getMaximum3DTextureDimension() >> level) ||
depth > (context->getMaximum3DTextureDimension() >> level))
{ {
return gl::error(GL_INVALID_VALUE, false); textureCompressed = texCube->isCompressed(target, level);
textureInternalFormat = texCube->getInternalFormat(target, level);
textureLevelWidth = texCube->getWidth(target, level);
textureLevelHeight = texCube->getHeight(target, level);
texture = texCube;
} }
gl::Texture3D *texture3d = context->getTexture3D(); if (isSubImage && !validateSubImageParamsCube(isCompressed, width, height, xoffset, yoffset,
if (texture3d) target, level, format, type, texCube))
{ {
textureCompressed = texture3d->isCompressed(level); return false;
textureInternalFormat = texture3d->getInternalFormat(level);
textureLevelWidth = texture3d->getWidth(level);
textureLevelHeight = texture3d->getHeight(level);
textureLevelDepth = texture3d->getDepth(level);
texture = texture3d;
} }
} }
break; break;
case GL_TEXTURE_2D_ARRAY:
{
if (width > (context->getMaximum2DTextureDimension() >> level) ||
height > (context->getMaximum2DTextureDimension() >> level) ||
depth > (context->getMaximum2DArrayTextureLayers() >> level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::Texture2DArray *texture2darray = context->getTexture2DArray();
if (texture2darray)
{
textureCompressed = texture2darray->isCompressed(level);
textureInternalFormat = texture2darray->getInternalFormat(level);
textureLevelWidth = texture2darray->getWidth(level);
textureLevelHeight = texture2darray->getHeight(level);
textureLevelDepth = texture2darray->getDepth(level);
texture = texture2darray;
}
}
break;
default: default:
return gl::error(GL_INVALID_ENUM, false); return gl::error(GL_INVALID_ENUM, false);
} }
...@@ -370,146 +344,253 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le ...@@ -370,146 +344,253 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
if (texture->isImmutable()) if (!isSubImage && texture->isImmutable())
{ {
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
// Validate texture formats // Verify zero border
if (border != 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
// Verify texture is not requesting more mip levels than are available.
if (level > context->getMaximumTextureLevel())
{
return gl::error(GL_INVALID_VALUE, false);
}
GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat; GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
if (isCompressed) if (isCompressed)
{ {
if (!gl::IsFormatCompressed(actualInternalFormat, context->getClientVersion())) switch (actualInternalFormat)
{ {
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
if (!context->supportsDXT1Textures())
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
if (!context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (!context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
default:
return gl::error(GL_INVALID_ENUM, false); return gl::error(GL_INVALID_ENUM, false);
} }
if (target == GL_TEXTURE_3D)
{
return gl::error(GL_INVALID_OPERATION, false);
}
} }
else else
{ {
if (!gl::IsValidInternalFormat(actualInternalFormat, context) || // validate <type> by itself (used as secondary key below)
!gl::IsValidFormat(format, context->getClientVersion()) || switch (type)
!gl::IsValidType(type, context->getClientVersion()))
{ {
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_INT:
case GL_UNSIGNED_INT_24_8_OES:
case GL_HALF_FLOAT_OES:
case GL_FLOAT:
break;
default:
return gl::error(GL_INVALID_ENUM, false); return gl::error(GL_INVALID_ENUM, false);
} }
if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getClientVersion())) // validate <format> + <type> combinations
{ // - invalid <format> -> sets INVALID_ENUM
return gl::error(GL_INVALID_OPERATION, false); // - invalid <format>+<type> combination -> sets INVALID_OPERATION
} switch (format)
if ((target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY) &&
(format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
{
return gl::error(GL_INVALID_OPERATION, false);
}
}
// Validate sub image parameters
if (isSubImage)
{
if (isCompressed != textureCompressed)
{
return gl::error(GL_INVALID_OPERATION, false);
}
if (format != GL_NONE)
{ {
GLenum internalformat = gl::GetSizedInternalFormat(format, type, context->getClientVersion()); case GL_ALPHA:
if (internalformat != textureInternalFormat) case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
switch (type)
{ {
case GL_UNSIGNED_BYTE:
case GL_FLOAT:
case GL_HALF_FLOAT_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
} break;
case GL_RGB:
if (isCompressed) switch (type)
{ {
if ((width % 4 != 0 && width != textureLevelWidth) || case GL_UNSIGNED_BYTE:
(height % 4 != 0 && height != textureLevelHeight)) case GL_UNSIGNED_SHORT_5_6_5:
case GL_FLOAT:
case GL_HALF_FLOAT_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_RGBA:
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_FLOAT:
case GL_HALF_FLOAT_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_BGRA_EXT:
switch (type)
{
case GL_UNSIGNED_BYTE:
break;
default:
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
break;
case GL_DEPTH_COMPONENT:
switch (type)
{
case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_INT:
break;
default:
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_DEPTH_STENCIL_OES:
switch (type)
{ {
case GL_UNSIGNED_INT_24_8_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
break;
default:
return gl::error(GL_INVALID_ENUM, false);
} }
if (width == 0 || height == 0 || depth == 0) switch (format)
{ {
return false; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
} case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
if (context->supportsDXT1Textures())
if (xoffset < 0 || yoffset < 0 || zoffset < 0) {
{ return gl::error(GL_INVALID_OPERATION, false);
return gl::error(GL_INVALID_VALUE, false); }
else
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
if (context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_OPERATION, false);
}
else
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_OPERATION, false);
}
else
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL_OES:
if (!context->supportsDepthTextures())
{
return gl::error(GL_INVALID_VALUE, false);
}
if (target != GL_TEXTURE_2D)
{
return gl::error(GL_INVALID_OPERATION, false);
}
// OES_depth_texture supports loading depth data and multiple levels,
// but ANGLE_depth_texture does not
if (pixels != NULL || level != 0)
{
return gl::error(GL_INVALID_OPERATION, false);
}
break;
default:
break;
} }
if (std::numeric_limits<GLsizei>::max() - xoffset < width || if (type == GL_FLOAT)
std::numeric_limits<GLsizei>::max() - yoffset < height ||
std::numeric_limits<GLsizei>::max() - zoffset < depth)
{ {
return gl::error(GL_INVALID_VALUE, false); if (!context->supportsFloat32Textures())
{
return gl::error(GL_INVALID_ENUM, false);
}
} }
else if (type == GL_HALF_FLOAT_OES)
if (xoffset + width > textureLevelWidth ||
yoffset + height > textureLevelHeight ||
zoffset + depth > textureLevelDepth)
{ {
return gl::error(GL_INVALID_VALUE, false); if (!context->supportsFloat16Textures())
{
return gl::error(GL_INVALID_ENUM, false);
}
} }
} }
return true; return true;
} }
bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLint level, GLenum internalformat, bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage,
bool isSubImage, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
GLsizei width, GLsizei height, GLint border) GLint border, GLenum format, GLenum type)
{ {
if (level < 0 || xoffset < 0 || yoffset < 0 || zoffset < 0 || width < 0 || height < 0) // Validate image size
{ if (!validImageSize(context, level, width, height, depth))
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); return gl::error(GL_INVALID_VALUE, false);
} }
if (width == 0 || height == 0) if (isCompressed && !validCompressedImageSize(width, height))
{ {
return false; return gl::error(GL_INVALID_OPERATION, false);
} }
// Verify zero border
if (border != 0) if (border != 0)
{ {
return gl::error(GL_INVALID_VALUE, false); return gl::error(GL_INVALID_VALUE, false);
} }
// Validate dimensions based on Context limits and validate the texture
if (level > context->getMaximumTextureLevel()) if (level > context->getMaximumTextureLevel())
{ {
return gl::error(GL_INVALID_VALUE, false); 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 colorbufferFormat = source->getInternalFormat();
gl::Texture *texture = NULL; gl::Texture *texture = NULL;
GLenum textureFormat = GL_RGBA;
bool textureCompressed = false; bool textureCompressed = false;
GLenum textureInternalFormat = GL_NONE;
GLint textureLevelWidth = 0; GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0; GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0; GLint textureLevelDepth = 0;
...@@ -517,11 +598,17 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin ...@@ -517,11 +598,17 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
{ {
if (width > (context->getMaximum2DTextureDimension() >> level) ||
height > (context->getMaximum2DTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::Texture2D *texture2d = context->getTexture2D(); gl::Texture2D *texture2d = context->getTexture2D();
if (texture2d) if (texture2d)
{ {
textureFormat = gl::GetFormat(texture2d->getInternalFormat(level), context->getClientVersion());
textureCompressed = texture2d->isCompressed(level); textureCompressed = texture2d->isCompressed(level);
textureInternalFormat = texture2d->getInternalFormat(level);
textureLevelWidth = texture2d->getWidth(level); textureLevelWidth = texture2d->getWidth(level);
textureLevelHeight = texture2d->getHeight(level); textureLevelHeight = texture2d->getHeight(level);
textureLevelDepth = 1; textureLevelDepth = 1;
...@@ -537,11 +624,21 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin ...@@ -537,11 +624,21 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
{ {
if (width != height)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (width > (context->getMaximumCubeTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::TextureCubeMap *textureCube = context->getTextureCubeMap(); gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
if (textureCube) if (textureCube)
{ {
textureFormat = gl::GetFormat(textureCube->getInternalFormat(target, level), context->getClientVersion());
textureCompressed = textureCube->isCompressed(target, level); textureCompressed = textureCube->isCompressed(target, level);
textureInternalFormat = textureCube->getInternalFormat(target, level);
textureLevelWidth = textureCube->getWidth(target, level); textureLevelWidth = textureCube->getWidth(target, level);
textureLevelHeight = textureCube->getHeight(target, level); textureLevelHeight = textureCube->getHeight(target, level);
textureLevelDepth = 1; textureLevelDepth = 1;
...@@ -552,11 +649,18 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin ...@@ -552,11 +649,18 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
case GL_TEXTURE_3D: case GL_TEXTURE_3D:
{ {
if (width > (context->getMaximum3DTextureDimension() >> level) ||
height > (context->getMaximum3DTextureDimension() >> level) ||
depth > (context->getMaximum3DTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::Texture3D *texture3d = context->getTexture3D(); gl::Texture3D *texture3d = context->getTexture3D();
if (texture3d) if (texture3d)
{ {
textureFormat = gl::GetFormat(texture3d->getInternalFormat(level), context->getClientVersion());
textureCompressed = texture3d->isCompressed(level); textureCompressed = texture3d->isCompressed(level);
textureInternalFormat = texture3d->getInternalFormat(level);
textureLevelWidth = texture3d->getWidth(level); textureLevelWidth = texture3d->getWidth(level);
textureLevelHeight = texture3d->getHeight(level); textureLevelHeight = texture3d->getHeight(level);
textureLevelDepth = texture3d->getDepth(level); textureLevelDepth = texture3d->getDepth(level);
...@@ -565,6 +669,28 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin ...@@ -565,6 +669,28 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
} }
break; break;
case GL_TEXTURE_2D_ARRAY:
{
if (width > (context->getMaximum2DTextureDimension() >> level) ||
height > (context->getMaximum2DTextureDimension() >> level) ||
depth > (context->getMaximum2DArrayTextureLayers() >> level))
{
return gl::error(GL_INVALID_VALUE, false);
}
gl::Texture2DArray *texture2darray = context->getTexture2DArray();
if (texture2darray)
{
textureCompressed = texture2darray->isCompressed(level);
textureInternalFormat = texture2darray->getInternalFormat(level);
textureLevelWidth = texture2darray->getWidth(level);
textureLevelHeight = texture2darray->getHeight(level);
textureLevelDepth = texture2darray->getDepth(level);
texture = texture2darray;
}
}
break;
default: default:
return gl::error(GL_INVALID_ENUM, false); return gl::error(GL_INVALID_ENUM, false);
} }
...@@ -574,106 +700,581 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin ...@@ -574,106 +700,581 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
if (texture->isImmutable() && !isSubImage) if (texture->isImmutable())
{ {
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
if (textureCompressed) // Validate texture formats
GLenum actualInternalFormat = isSubImage ? textureInternalFormat : internalformat;
if (isCompressed)
{ {
if ((width % 4 != 0 && width != textureLevelWidth) || if (!gl::IsFormatCompressed(actualInternalFormat, context->getClientVersion()))
(height % 4 != 0 && height != textureLevelHeight))
{ {
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_ENUM, false);
} }
}
if (xoffset + width > textureLevelWidth || if (target == GL_TEXTURE_3D)
yoffset + height > textureLevelHeight || {
zoffset >= textureLevelDepth) return gl::error(GL_INVALID_OPERATION, false);
{ }
return gl::error(GL_INVALID_VALUE, false);
} }
else
if (!gl::IsValidCopyTexImageCombination(textureFormat, colorbufferFormat, context->getClientVersion()))
{ {
return gl::error(GL_INVALID_OPERATION, false); if (!gl::IsValidInternalFormat(actualInternalFormat, context) ||
} !gl::IsValidFormat(format, context->getClientVersion()) ||
!gl::IsValidType(type, context->getClientVersion()))
return true; {
} return gl::error(GL_INVALID_ENUM, false);
}
// check for combinations of format and type that are valid for ReadPixels if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getClientVersion()))
bool validReadFormatType(GLenum format, GLenum type)
{
switch (format)
{
case GL_RGBA:
switch (type)
{ {
case GL_UNSIGNED_BYTE: return gl::error(GL_INVALID_OPERATION, false);
break;
default:
return false;
} }
break;
case GL_BGRA_EXT: if ((target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY) &&
switch (type) (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
{ {
case GL_UNSIGNED_BYTE: return gl::error(GL_INVALID_OPERATION, false);
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;
default:
return false;
} }
return true;
}
bool validateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
const GLenum* attachments)
{
bool defaultFramebuffer = false;
switch (target) // Validate sub image parameters
if (isSubImage)
{ {
case GL_DRAW_FRAMEBUFFER: if (isCompressed != textureCompressed)
case GL_FRAMEBUFFER: {
defaultFramebuffer = context->getDrawFramebufferHandle() == 0; return gl::error(GL_INVALID_OPERATION, false);
break; }
case GL_READ_FRAMEBUFFER:
defaultFramebuffer = context->getReadFramebufferHandle() == 0;
break;
default:
return gl::error(GL_INVALID_ENUM, false);
}
for (int i = 0; i < numAttachments; ++i) if (format != GL_NONE)
{
if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
{ {
if (defaultFramebuffer) GLenum internalformat = gl::GetSizedInternalFormat(format, type, context->getClientVersion());
if (internalformat != textureInternalFormat)
{ {
return gl::error(GL_INVALID_ENUM, false); return gl::error(GL_INVALID_OPERATION, false);
} }
}
if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets()) if (isCompressed)
{
if ((width % 4 != 0 && width != textureLevelWidth) ||
(height % 4 != 0 && height != textureLevelHeight))
{ {
return gl::error(GL_INVALID_OPERATION, false); return gl::error(GL_INVALID_OPERATION, false);
} }
} }
else
if (width == 0 || height == 0 || depth == 0)
{ {
switch (attachments[i]) return false;
{ }
case GL_DEPTH_ATTACHMENT:
case GL_STENCIL_ATTACHMENT: if (xoffset < 0 || yoffset < 0 || zoffset < 0)
case GL_DEPTH_STENCIL_ATTACHMENT: {
if (defaultFramebuffer) return gl::error(GL_INVALID_VALUE, false);
}
if (std::numeric_limits<GLsizei>::max() - xoffset < width ||
std::numeric_limits<GLsizei>::max() - yoffset < height ||
std::numeric_limits<GLsizei>::max() - zoffset < depth)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (xoffset + width > textureLevelWidth ||
yoffset + height > textureLevelHeight ||
zoffset + depth > textureLevelDepth)
{
return gl::error(GL_INVALID_VALUE, false);
}
}
return true;
}
bool validateES2CopyTexImageParameters(gl::Context* context, GLenum target, GLint level, GLenum internalformat, bool isSubImage,
GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height,
GLint border)
{
if (!gl::IsInternalTextureTarget(target))
{
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);
}
if (width == 0 || height == 0)
{
return false;
}
// Verify zero border
if (border != 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
// Validate dimensions based on Context limits and validate the texture
if (level > context->getMaximumTextureLevel())
{
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);
}
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);
}
// [OpenGL ES 2.0.24] table 3.9
if (isSubImage)
{
switch (textureFormat)
{
case GL_ALPHA:
if (colorbufferFormat != GL_ALPHA8_EXT &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_LUMINANCE:
case GL_RGB:
if (colorbufferFormat != GL_RGB565 &&
colorbufferFormat != GL_RGB8_OES &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_LUMINANCE_ALPHA:
case GL_RGBA:
if (colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
return gl::error(GL_INVALID_OPERATION, false);
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL_OES:
return gl::error(GL_INVALID_OPERATION, false);
default:
return gl::error(GL_INVALID_OPERATION, false);
}
}
else
{
switch (internalformat)
{
case GL_ALPHA:
if (colorbufferFormat != GL_ALPHA8_EXT &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_BGRA8_EXT &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_LUMINANCE:
case GL_RGB:
if (colorbufferFormat != GL_RGB565 &&
colorbufferFormat != GL_RGB8_OES &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_BGRA8_EXT &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_LUMINANCE_ALPHA:
case GL_RGBA:
if (colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_BGRA8_EXT &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
if (context->supportsDXT1Textures())
{
return gl::error(GL_INVALID_OPERATION, false);
}
else
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
if (context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_OPERATION, false);
}
else
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_OPERATION, false);
}
else
{
return gl::error(GL_INVALID_ENUM, false);
}
break;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT32_OES:
case GL_DEPTH_STENCIL_OES:
case GL_DEPTH24_STENCIL8_OES:
if (context->supportsDepthTextures())
{
return gl::error(GL_INVALID_OPERATION, false);
}
else
{
return gl::error(GL_INVALID_ENUM, false);
}
default:
return gl::error(GL_INVALID_ENUM, false);
}
}
return true;
}
bool validateES3CopyTexImageParameters(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)
{
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 (width == 0 || height == 0)
{
return false;
}
if (border != 0)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (level > context->getMaximumTextureLevel())
{
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 colorbufferFormat = source->getInternalFormat();
gl::Texture *texture = NULL;
GLenum textureFormat = GL_RGBA;
bool textureCompressed = false;
GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0;
switch (target)
{
case GL_TEXTURE_2D:
{
gl::Texture2D *texture2d = context->getTexture2D();
if (texture2d)
{
textureFormat = gl::GetFormat(texture2d->getInternalFormat(level), context->getClientVersion());
textureCompressed = texture2d->isCompressed(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)
{
textureFormat = gl::GetFormat(textureCube->getInternalFormat(target, level), context->getClientVersion());
textureCompressed = textureCube->isCompressed(target, level);
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)
{
textureFormat = gl::GetFormat(texture2dArray->getInternalFormat(level), context->getClientVersion());
textureCompressed = texture2dArray->isCompressed(level);
textureLevelWidth = texture2dArray->getWidth(level);
textureLevelHeight = texture2dArray->getHeight(level);
textureLevelDepth = texture2dArray->getDepth(level);
texture = texture2dArray;
}
}
break;
case GL_TEXTURE_3D:
{
gl::Texture3D *texture3d = context->getTexture3D();
if (texture3d)
{
textureFormat = gl::GetFormat(texture3d->getInternalFormat(level), context->getClientVersion());
textureCompressed = texture3d->isCompressed(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 (textureCompressed)
{
if ((width % 4 != 0 && width != textureLevelWidth) ||
(height % 4 != 0 && height != textureLevelHeight))
{
return gl::error(GL_INVALID_OPERATION, false);
}
}
if (xoffset + width > textureLevelWidth ||
yoffset + height > textureLevelHeight ||
zoffset >= textureLevelDepth)
{
return gl::error(GL_INVALID_VALUE, false);
}
if (!gl::IsValidCopyTexImageCombination(textureFormat, colorbufferFormat, context->getClientVersion()))
{
return gl::error(GL_INVALID_OPERATION, false);
}
return true;
}
// check for combinations of format and type that are valid for ReadPixels
bool validReadFormatType(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;
default:
return false;
}
return true;
}
bool validateInvalidateFramebufferParameters(gl::Context *context, GLenum target, GLsizei numAttachments,
const GLenum* attachments)
{
bool defaultFramebuffer = false;
switch (target)
{
case GL_DRAW_FRAMEBUFFER:
case GL_FRAMEBUFFER:
defaultFramebuffer = context->getDrawFramebufferHandle() == 0;
break;
case GL_READ_FRAMEBUFFER:
defaultFramebuffer = context->getReadFramebufferHandle() == 0;
break;
default:
return gl::error(GL_INVALID_ENUM, false);
}
for (int i = 0; i < numAttachments; ++i)
{
if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
{
if (defaultFramebuffer)
{
return gl::error(GL_INVALID_ENUM, false);
}
if (attachments[i] >= GL_COLOR_ATTACHMENT0 + context->getMaximumRenderTargets())
{
return gl::error(GL_INVALID_OPERATION, false);
}
}
else
{
switch (attachments[i])
{
case GL_DEPTH_ATTACHMENT:
case GL_STENCIL_ATTACHMENT:
case GL_DEPTH_STENCIL_ATTACHMENT:
if (defaultFramebuffer)
{ {
return gl::error(GL_INVALID_ENUM, false); return gl::error(GL_INVALID_ENUM, false);
} }
...@@ -1480,375 +2081,109 @@ void __stdcall glClear(GLbitfield mask) ...@@ -1480,375 +2081,109 @@ void __stdcall glClear(GLbitfield mask)
} }
} }
void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
red, green, blue, alpha);
try
{
gl::Context *context = gl::getNonLostContext();
if (context)
{
context->setClearColor(red, green, blue, alpha);
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glClearDepthf(GLclampf depth)
{
EVENT("(GLclampf depth = %f)", depth);
try
{
gl::Context *context = gl::getNonLostContext();
if (context)
{
context->setClearDepth(depth);
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glClearStencil(GLint s)
{
EVENT("(GLint s = %d)", s);
try
{
gl::Context *context = gl::getNonLostContext();
if (context)
{
context->setClearStencil(s);
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
{
EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)",
red, green, blue, alpha);
try
{
gl::Context *context = gl::getNonLostContext();
if (context)
{
context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE);
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glCompileShader(GLuint shader)
{
EVENT("(GLuint shader = %d)", shader);
try
{
gl::Context *context = gl::getNonLostContext();
if (context)
{
gl::Shader *shaderObject = context->getShader(shader);
if (!shaderObject)
{
if (context->getProgram(shader))
{
return gl::error(GL_INVALID_OPERATION);
}
else
{
return gl::error(GL_INVALID_VALUE);
}
}
shaderObject->compile();
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
GLint border, GLsizei imageSize, const GLvoid* data)
{
EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
"GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
target, level, internalformat, width, height, border, imageSize, data);
try
{
if (!validImageSize(level, width, height, 1) || border != 0 || imageSize < 0)
{
return gl::error(GL_INVALID_VALUE);
}
switch (internalformat)
{
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
break;
default:
return gl::error(GL_INVALID_ENUM);
}
if (border != 0)
{
return gl::error(GL_INVALID_OPERATION);
}
if (width != 1 && width != 2 && width % 4 != 0)
{
return gl::error(GL_INVALID_OPERATION);
}
if (height != 1 && height != 2 && height % 4 != 0)
{
return gl::error(GL_INVALID_OPERATION);
}
gl::Context *context = gl::getNonLostContext();
if (context)
{
if (level > context->getMaximumTextureLevel())
{
return gl::error(GL_INVALID_VALUE);
}
switch (target)
{
case GL_TEXTURE_2D:
if (width > (context->getMaximum2DTextureDimension() >> level) ||
height > (context->getMaximum2DTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE);
}
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 (width != height)
{
return gl::error(GL_INVALID_VALUE);
}
if (width > (context->getMaximumCubeTextureDimension() >> level) ||
height > (context->getMaximumCubeTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE);
}
break;
default:
return gl::error(GL_INVALID_ENUM);
}
switch (internalformat) {
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
if (!context->supportsDXT1Textures())
{
return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
if (!context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (!context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
}
break;
default: UNREACHABLE();
}
if (imageSize != (GLsizei)gl::GetBlockSize(internalformat, GL_UNSIGNED_BYTE, context->getClientVersion(), width, height))
{
return gl::error(GL_INVALID_VALUE);
}
if (target == GL_TEXTURE_2D)
{
gl::Texture2D *texture = context->getTexture2D();
if (!texture)
{
return gl::error(GL_INVALID_OPERATION);
}
if (texture->isImmutable())
{
return gl::error(GL_INVALID_OPERATION);
}
texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
}
else
{
gl::TextureCubeMap *texture = context->getTextureCubeMap();
if (!texture)
{
return gl::error(GL_INVALID_OPERATION);
}
if (texture->isImmutable())
{
return gl::error(GL_INVALID_OPERATION);
}
switch (target)
{
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:
texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
break;
default: UNREACHABLE();
}
}
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLsizei imageSize, const GLvoid* data)
{ {
EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, " EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
"GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, " red, green, blue, alpha);
"GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
target, level, xoffset, yoffset, width, height, format, imageSize, data);
try try
{ {
if (!gl::IsInternalTextureTarget(target)) gl::Context *context = gl::getNonLostContext();
{
return gl::error(GL_INVALID_ENUM);
}
if (xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height, 1) || imageSize < 0) if (context)
{ {
return gl::error(GL_INVALID_VALUE); context->setClearColor(red, green, blue, alpha);
} }
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
switch (format) void __stdcall glClearDepthf(GLclampf depth)
{
EVENT("(GLclampf depth = %f)", depth);
try
{
gl::Context *context = gl::getNonLostContext();
if (context)
{ {
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: context->setClearDepth(depth);
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
break;
default:
return gl::error(GL_INVALID_ENUM);
} }
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glClearStencil(GLint s)
{
EVENT("(GLint s = %d)", s);
try
{
gl::Context *context = gl::getNonLostContext();
if (width == 0 || height == 0 || data == NULL) if (context)
{ {
return; context->setClearStencil(s);
} }
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
{
EVENT("(GLboolean red = %d, GLboolean green = %u, GLboolean blue = %u, GLboolean alpha = %u)",
red, green, blue, alpha);
try
{
gl::Context *context = gl::getNonLostContext(); gl::Context *context = gl::getNonLostContext();
if (context) if (context)
{ {
if (level > context->getMaximumTextureLevel()) context->setColorMask(red == GL_TRUE, green == GL_TRUE, blue == GL_TRUE, alpha == GL_TRUE);
{ }
return gl::error(GL_INVALID_VALUE); }
} catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
switch (format) { void __stdcall glCompileShader(GLuint shader)
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: {
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: EVENT("(GLuint shader = %d)", shader);
if (!context->supportsDXT1Textures())
{
return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
if (!context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (!context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_ENUM); // in this case, it's as though the internal format switch failed
}
break;
default: UNREACHABLE();
}
if (imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, context->getClientVersion(), width, height)) try
{ {
return gl::error(GL_INVALID_VALUE); gl::Context *context = gl::getNonLostContext();
}
if (xoffset % 4 != 0 || yoffset % 4 != 0) if (context)
{ {
return gl::error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction gl::Shader *shaderObject = context->getShader(shader);
// does not exist unless DXT textures are supported.
}
if (target == GL_TEXTURE_2D) if (!shaderObject)
{ {
gl::Texture2D *texture = context->getTexture2D(); if (context->getProgram(shader))
if (validateSubImageParams2D(true, width, height, xoffset, yoffset, level, format, GL_UNSIGNED_BYTE, texture))
{ {
texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data); return gl::error(GL_INVALID_OPERATION);
} }
} else
else if (gl::IsCubemapTextureTarget(target))
{
gl::TextureCubeMap *texture = context->getTextureCubeMap();
if (validateSubImageParamsCube(true, width, height, xoffset, yoffset, target, level, format, GL_UNSIGNED_BYTE, texture))
{ {
texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data); return gl::error(GL_INVALID_VALUE);
} }
} }
else
{ shaderObject->compile();
UNREACHABLE();
}
} }
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
...@@ -1857,29 +2192,34 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs ...@@ -1857,29 +2192,34 @@ void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffs
} }
} }
void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
GLint border, GLsizei imageSize, const GLvoid* data)
{ {
EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, " EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
"GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)", "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
target, level, internalformat, x, y, width, height, border); target, level, internalformat, width, height, border, imageSize, data);
try try
{ {
if (!validImageSize(level, width, height, 1))
{
return gl::error(GL_INVALID_VALUE);
}
if (border != 0)
{
return gl::error(GL_INVALID_VALUE);
}
gl::Context *context = gl::getNonLostContext(); gl::Context *context = gl::getNonLostContext();
if (context) if (context)
{ {
if (level > context->getMaximumTextureLevel()) if (context->getClientVersion() < 3 &&
!validateES2TexImageParameters(context, target, level, internalformat, true, false,
0, 0, width, height, 0, GL_NONE, GL_NONE, data))
{
return;
}
if (context->getClientVersion() >= 3 &&
!validateES3TexImageParameters(context, target, level, internalformat, true, false,
0, 0, 0, width, height, 1, 0, GL_NONE, GL_NONE))
{
return;
}
if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(internalformat, GL_UNSIGNED_BYTE, context->getClientVersion(), width, height))
{ {
return gl::error(GL_INVALID_VALUE); return gl::error(GL_INVALID_VALUE);
} }
...@@ -1887,164 +2227,152 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma ...@@ -1887,164 +2227,152 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma
switch (target) switch (target)
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
if (width > (context->getMaximum2DTextureDimension() >> level) ||
height > (context->getMaximum2DTextureDimension() >> level))
{ {
return gl::error(GL_INVALID_VALUE); gl::Texture2D *texture = context->getTexture2D();
texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
} }
break; break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X: case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
if (width != height)
{ {
return gl::error(GL_INVALID_VALUE); gl::TextureCubeMap *texture = context->getTextureCubeMap();
} texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
if (width > (context->getMaximumCubeTextureDimension() >> level) ||
height > (context->getMaximumCubeTextureDimension() >> level))
{
return gl::error(GL_INVALID_VALUE);
} }
break; break;
default: default:
return gl::error(GL_INVALID_ENUM); return gl::error(GL_INVALID_ENUM);
} }
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
gl::Framebuffer *framebuffer = context->getReadFramebuffer(); void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLsizei imageSize, const GLvoid* data)
{
EVENT("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
"GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, "
"GLsizei imageSize = %d, const GLvoid* data = 0x%0.8p)",
target, level, xoffset, yoffset, width, height, format, imageSize, data);
try
{
gl::Context *context = gl::getNonLostContext();
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE) if (context)
{
if (context->getClientVersion() < 3 &&
!validateES2TexImageParameters(context, target, level, GL_NONE, true, true,
xoffset, yoffset, width, height, 0, GL_NONE, GL_NONE, data))
{ {
return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); return;
} }
if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0) if (context->getClientVersion() >= 3 &&
!validateES3TexImageParameters(context, target, level, GL_NONE, true, true,
xoffset, yoffset, 0, width, height, 1, 0, GL_NONE, GL_NONE))
{ {
return gl::error(GL_INVALID_OPERATION); return;
} }
gl::Renderbuffer *source = framebuffer->getReadColorbuffer(); if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, context->getClientVersion(), width, height))
GLenum colorbufferFormat = source->getInternalFormat(); {
return gl::error(GL_INVALID_VALUE);
}
// [OpenGL ES 2.0.24] table 3.9 switch (target)
switch (internalformat)
{ {
case GL_ALPHA: case GL_TEXTURE_2D:
if (colorbufferFormat != GL_ALPHA8_EXT &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_BGRA8_EXT &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_LUMINANCE:
case GL_RGB:
if (colorbufferFormat != GL_RGB565 &&
colorbufferFormat != GL_RGB8_OES &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_BGRA8_EXT &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_LUMINANCE_ALPHA:
case GL_RGBA:
if (colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_BGRA8_EXT &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
if (context->supportsDXT1Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
{
return gl::error(GL_INVALID_ENUM);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
if (context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
{ {
return gl::error(GL_INVALID_ENUM); gl::Texture2D *texture = context->getTexture2D();
texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
} }
break; break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (context->supportsDXT5Textures()) case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
{ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
return gl::error(GL_INVALID_OPERATION); case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
} case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
else case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
{ {
return gl::error(GL_INVALID_ENUM); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
} }
break; break;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16:
case GL_DEPTH_COMPONENT32_OES:
case GL_DEPTH_STENCIL_OES:
case GL_DEPTH24_STENCIL8_OES:
if (context->supportsDepthTextures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
{
return gl::error(GL_INVALID_ENUM);
}
default: default:
return gl::error(GL_INVALID_ENUM); return gl::error(GL_INVALID_ENUM);
} }
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
if (target == GL_TEXTURE_2D) void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
{ {
gl::Texture2D *texture = context->getTexture2D(); EVENT("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
"GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)",
if (!texture) target, level, internalformat, x, y, width, height, border);
{
return gl::error(GL_INVALID_OPERATION);
}
if (texture->isImmutable()) try
{ {
return gl::error(GL_INVALID_OPERATION); gl::Context *context = gl::getNonLostContext();
}
texture->copyImage(level, internalformat, x, y, width, height, framebuffer); if (context)
{
if (context->getClientVersion() < 3 &&
!validateES2CopyTexImageParameters(context, target, level, internalformat, false,
0, 0, x, y, width, height, border))
{
return;
} }
else if (gl::IsCubemapTextureTarget(target))
if (context->getClientVersion() >= 3 &&
!validateES3CopyTexImageParameters(context, target, level, internalformat, false,
0, 0, 0, x, y, width, height, border))
{ {
gl::TextureCubeMap *texture = context->getTextureCubeMap(); return;
}
if (!texture) gl::Framebuffer *framebuffer = context->getReadFramebuffer();
switch (target)
{
case GL_TEXTURE_2D:
{ {
return gl::error(GL_INVALID_OPERATION); gl::Texture2D *texture = context->getTexture2D();
texture->copyImage(level, internalformat, x, y, width, height, framebuffer);
} }
break;
if (texture->isImmutable()) 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:
{ {
return gl::error(GL_INVALID_OPERATION); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer);
} }
break;
texture->copyImage(target, level, internalformat, x, y, width, height, framebuffer); default:
return gl::error(GL_INVALID_ENUM);
} }
else UNREACHABLE();
} }
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
...@@ -2061,121 +2389,50 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL ...@@ -2061,121 +2389,50 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL
try try
{ {
if (!gl::IsInternalTextureTarget(target))
{
return gl::error(GL_INVALID_ENUM);
}
if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
{
return gl::error(GL_INVALID_VALUE);
}
if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
{
return gl::error(GL_INVALID_VALUE);
}
if (width == 0 || height == 0)
{
return;
}
gl::Context *context = gl::getNonLostContext(); gl::Context *context = gl::getNonLostContext();
if (context) if (context)
{ {
if (level > context->getMaximumTextureLevel()) if (context->getClientVersion() < 3 &&
{ !validateES2CopyTexImageParameters(context, target, level, GL_NONE, true,
return gl::error(GL_INVALID_VALUE); xoffset, yoffset, x, y, width, height, 0))
}
gl::Framebuffer *framebuffer = context->getReadFramebuffer();
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
{ {
return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION); return;
}
if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
{
return gl::error(GL_INVALID_OPERATION);
} }
gl::Renderbuffer *source = framebuffer->getReadColorbuffer(); if (context->getClientVersion() >= 3 &&
GLenum colorbufferFormat = source->getInternalFormat(); !validateES3CopyTexImageParameters(context, target, level, GL_NONE, true,
gl::Texture *texture = NULL; xoffset, yoffset, 0, x, y, width, height, 0))
GLenum textureFormat = GL_RGBA;
if (target == GL_TEXTURE_2D)
{ {
gl::Texture2D *tex2d = context->getTexture2D(); return;
if (!validateSubImageParams2D(false, width, height, xoffset, yoffset, level, GL_NONE, GL_NONE, tex2d))
{
return; // error already registered by validateSubImageParams
}
textureFormat = gl::GetFormat(tex2d->getInternalFormat(level), context->getClientVersion());
texture = tex2d;
} }
else if (gl::IsCubemapTextureTarget(target))
{
gl::TextureCubeMap *texcube = context->getTextureCubeMap();
if (!validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube)) gl::Framebuffer *framebuffer = context->getReadFramebuffer();
{
return; // error already registered by validateSubImageParams
}
textureFormat = gl::GetFormat(texcube->getInternalFormat(target, level), context->getClientVersion());
texture = texcube;
}
else UNREACHABLE();
// [OpenGL ES 2.0.24] table 3.9 switch (target)
switch (textureFormat)
{ {
case GL_ALPHA: case GL_TEXTURE_2D:
if (colorbufferFormat != GL_ALPHA8_EXT &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_RGBA8_OES)
{
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_LUMINANCE:
case GL_RGB:
if (colorbufferFormat != GL_RGB565 &&
colorbufferFormat != GL_RGB8_OES &&
colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_RGBA8_OES)
{ {
return gl::error(GL_INVALID_OPERATION); gl::Texture2D *texture = context->getTexture2D();
texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
} }
break; break;
case GL_LUMINANCE_ALPHA:
case GL_RGBA: case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
if (colorbufferFormat != GL_RGBA4 && case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
colorbufferFormat != GL_RGB5_A1 && case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
colorbufferFormat != GL_RGBA8_OES) case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
{ {
return gl::error(GL_INVALID_OPERATION); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
} }
break; break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
return gl::error(GL_INVALID_OPERATION);
case GL_DEPTH_COMPONENT:
case GL_DEPTH_STENCIL_OES:
return gl::error(GL_INVALID_OPERATION);
default: default:
return gl::error(GL_INVALID_OPERATION); return gl::error(GL_INVALID_ENUM);
} }
texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
} }
} }
...@@ -5923,339 +6180,131 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu ...@@ -5923,339 +6180,131 @@ void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenu
case GL_INCR_WRAP: case GL_INCR_WRAP:
case GL_DECR_WRAP: case GL_DECR_WRAP:
break; break;
default: default:
return gl::error(GL_INVALID_ENUM); return gl::error(GL_INVALID_ENUM);
} }
gl::Context *context = gl::getNonLostContext(); gl::Context *context = gl::getNonLostContext();
if (context) if (context)
{ {
if (face == GL_FRONT || face == GL_FRONT_AND_BACK) if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
{
context->setStencilOperations(fail, zfail, zpass);
}
if (face == GL_BACK || face == GL_FRONT_AND_BACK)
{
context->setStencilBackOperations(fail, zfail, zpass);
}
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
GLboolean __stdcall glTestFenceNV(GLuint fence)
{
EVENT("(GLuint fence = %d)", fence);
try
{
gl::Context *context = gl::getNonLostContext();
if (context)
{
gl::Fence *fenceObject = context->getFence(fence);
if (fenceObject == NULL)
{
return gl::error(GL_INVALID_OPERATION, GL_TRUE);
}
return fenceObject->testFence();
}
}
catch(std::bad_alloc&)
{
gl::error(GL_OUT_OF_MEMORY);
}
return GL_TRUE;
}
void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid* pixels)
{
EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "
"GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)",
target, level, internalformat, width, height, border, format, type, pixels);
try
{
if (!validImageSize(level, width, height, 1))
{
return gl::error(GL_INVALID_VALUE);
}
if (internalformat != GLint(format))
{
return gl::error(GL_INVALID_OPERATION);
}
// validate <type> by itself (used as secondary key below)
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_INT:
case GL_UNSIGNED_INT_24_8_OES:
case GL_HALF_FLOAT_OES:
case GL_FLOAT:
break;
default:
return gl::error(GL_INVALID_ENUM);
}
// validate <format> + <type> combinations
// - invalid <format> -> sets INVALID_ENUM
// - invalid <format>+<type> combination -> sets INVALID_OPERATION
switch (format)
{
case GL_ALPHA:
case GL_LUMINANCE:
case GL_LUMINANCE_ALPHA:
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_FLOAT:
case GL_HALF_FLOAT_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_RGB:
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_5_6_5:
case GL_FLOAT:
case GL_HALF_FLOAT_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_RGBA:
switch (type)
{
case GL_UNSIGNED_BYTE:
case GL_UNSIGNED_SHORT_4_4_4_4:
case GL_UNSIGNED_SHORT_5_5_5_1:
case GL_FLOAT:
case GL_HALF_FLOAT_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_BGRA_EXT:
switch (type)
{
case GL_UNSIGNED_BYTE:
break;
default:
return gl::error(GL_INVALID_OPERATION);
}
break;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // error cases for compressed textures are handled below
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
break;
case GL_DEPTH_COMPONENT:
switch (type)
{ {
case GL_UNSIGNED_SHORT: context->setStencilOperations(fail, zfail, zpass);
case GL_UNSIGNED_INT:
break;
default:
return gl::error(GL_INVALID_OPERATION);
} }
break;
case GL_DEPTH_STENCIL_OES: if (face == GL_BACK || face == GL_FRONT_AND_BACK)
switch (type)
{ {
case GL_UNSIGNED_INT_24_8_OES: context->setStencilBackOperations(fail, zfail, zpass);
break;
default:
return gl::error(GL_INVALID_OPERATION);
} }
break;
default:
return gl::error(GL_INVALID_ENUM);
} }
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
GLboolean __stdcall glTestFenceNV(GLuint fence)
{
EVENT("(GLuint fence = %d)", fence);
try
{
gl::Context *context = gl::getNonLostContext();
if (border != 0) if (context)
{ {
return gl::error(GL_INVALID_VALUE); gl::Fence *fenceObject = context->getFence(fence);
if (fenceObject == NULL)
{
return gl::error(GL_INVALID_OPERATION, GL_TRUE);
}
return fenceObject->testFence();
} }
}
catch(std::bad_alloc&)
{
gl::error(GL_OUT_OF_MEMORY);
}
return GL_TRUE;
}
void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid* pixels)
{
EVENT("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "
"GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* pixels = 0x%0.8p)",
target, level, internalformat, width, height, border, format, type, pixels);
try
{
gl::Context *context = gl::getNonLostContext(); gl::Context *context = gl::getNonLostContext();
if (context) if (context)
{ {
if (level > context->getMaximumTextureLevel()) if (context->getClientVersion() < 3 &&
!validateES2TexImageParameters(context, target, level, internalformat, false, false,
0, 0, width, height, border, format, type, pixels))
{ {
return gl::error(GL_INVALID_VALUE); return;
}
if (context->getClientVersion() >= 3 &&
!validateES3TexImageParameters(context, target, level, internalformat, false, false,
0, 0, 0, width, height, 1, border, format, type))
{
return;
} }
switch (target) switch (target)
{ {
case GL_TEXTURE_2D: case GL_TEXTURE_2D:
if (width > (context->getMaximum2DTextureDimension() >> level) ||
height > (context->getMaximum2DTextureDimension() >> level))
{ {
return gl::error(GL_INVALID_VALUE); gl::Texture2D *texture = context->getTexture2D();
texture->setImage(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
} }
break; break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_X: 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 (width != height)
{
return gl::error(GL_INVALID_VALUE);
}
if (width > (context->getMaximumCubeTextureDimension() >> level) ||
height > (context->getMaximumCubeTextureDimension() >> level))
{ {
return gl::error(GL_INVALID_VALUE); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImagePosX(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
} }
break; break;
default: case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
return gl::error(GL_INVALID_ENUM);
}
switch (format) {
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
if (context->supportsDXT1Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
{ {
return gl::error(GL_INVALID_ENUM); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImageNegX(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
} }
break; break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE: case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
if (context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
{ {
return gl::error(GL_INVALID_ENUM); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImagePosY(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
} }
break; break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
if (context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
{ {
return gl::error(GL_INVALID_ENUM); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImageNegY(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
} }
break; break;
case GL_DEPTH_COMPONENT: case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
case GL_DEPTH_STENCIL_OES:
if (!context->supportsDepthTextures())
{
return gl::error(GL_INVALID_VALUE);
}
if (target != GL_TEXTURE_2D)
{
return gl::error(GL_INVALID_OPERATION);
}
// OES_depth_texture supports loading depth data and multiple levels,
// but ANGLE_depth_texture does not
if (pixels != NULL || level != 0)
{ {
return gl::error(GL_INVALID_OPERATION); gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImagePosZ(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
} }
break; break;
default: case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
break;
}
if (type == GL_FLOAT)
{
if (!context->supportsFloat32Textures())
{
return gl::error(GL_INVALID_ENUM);
}
}
else if (type == GL_HALF_FLOAT_OES)
{
if (!context->supportsFloat16Textures())
{
return gl::error(GL_INVALID_ENUM);
}
}
if (target == GL_TEXTURE_2D)
{
gl::Texture2D *texture = context->getTexture2D();
if (!texture)
{
return gl::error(GL_INVALID_OPERATION);
}
if (texture->isImmutable())
{
return gl::error(GL_INVALID_OPERATION);
}
texture->setImage(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
}
else
{
gl::TextureCubeMap *texture = context->getTextureCubeMap();
if (!texture)
{
return gl::error(GL_INVALID_OPERATION);
}
if (texture->isImmutable())
{
return gl::error(GL_INVALID_OPERATION);
}
switch (target)
{ {
case GL_TEXTURE_CUBE_MAP_POSITIVE_X: gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImagePosX(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
texture->setImageNegX(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
texture->setImagePosY(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
texture->setImageNegY(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
break;
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
texture->setImagePosZ(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
break;
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
texture->setImageNegZ(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels); texture->setImageNegZ(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
break;
default: UNREACHABLE();
} }
break;
default: UNREACHABLE();
} }
} }
} }
...@@ -6653,88 +6702,47 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint ...@@ -6653,88 +6702,47 @@ void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint
try try
{ {
if (!gl::IsInternalTextureTarget(target))
{
return gl::error(GL_INVALID_ENUM);
}
if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
{
return gl::error(GL_INVALID_VALUE);
}
if (std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
{
return gl::error(GL_INVALID_VALUE);
}
if (!checkTextureFormatType(format, type))
{
return; // error is set by helper function
}
gl::Context *context = gl::getNonLostContext(); gl::Context *context = gl::getNonLostContext();
if (context) if (context)
{ {
if (level > context->getMaximumTextureLevel()) if (context->getClientVersion() < 3 &&
{ !validateES2TexImageParameters(context, target, level, GL_NONE, false, true,
return gl::error(GL_INVALID_VALUE); 0, 0, width, height, 0, format, type, pixels))
}
if (type == GL_FLOAT)
{
if (!context->supportsFloat32Textures())
{
return gl::error(GL_INVALID_ENUM);
}
}
else if (type == GL_HALF_FLOAT_OES)
{ {
if (!context->supportsFloat16Textures()) return;
{
return gl::error(GL_INVALID_ENUM);
}
}
if (format == GL_DEPTH_COMPONENT)
{
if (!context->supportsDepthTextures())
{
return gl::error(GL_INVALID_ENUM);
}
if (target != GL_TEXTURE_2D)
{
return gl::error(GL_INVALID_OPERATION);
}
// OES_depth_texture supports loading depth data, but ANGLE_depth_texture does not
return gl::error(GL_INVALID_OPERATION);
} }
if (width == 0 || height == 0 || pixels == NULL) if (context->getClientVersion() >= 3 &&
!validateES3TexImageParameters(context, target, level, GL_NONE, false, true,
0, 0, 0, width, height, 1, 0, format, type))
{ {
return; return;
} }
if (target == GL_TEXTURE_2D) switch (target)
{ {
gl::Texture2D *texture = context->getTexture2D(); case GL_TEXTURE_2D:
if (validateSubImageParams2D(false, width, height, xoffset, yoffset, level, format, type, texture))
{ {
gl::Texture2D *texture = context->getTexture2D();
texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
} }
} break;
else if (gl::IsCubemapTextureTarget(target))
{ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
gl::TextureCubeMap *texture = context->getTextureCubeMap(); case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
if (validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, format, type, texture)) 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 *texture = context->getTextureCubeMap();
texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels); texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
} }
} break;
else
{ default:
UNREACHABLE(); return gl::error(GL_INVALID_ENUM);
} }
} }
} }
......
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