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 @@
#include "libGLESv2/Query.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)
{
return false;
}
if (gl::getContext() && gl::getContext()->supportsNonPower2Texture())
if (context->supportsNonPower2Texture())
{
return true;
}
......@@ -47,6 +47,21 @@ bool validImageSize(GLint level, GLsizei width, GLsizei height, GLsizei depth)
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.
bool checkTextureFormatType(GLenum format, GLenum type)
{
......@@ -223,39 +238,30 @@ bool validateSubImageParamsCube(bool compressed, GLsizei width, GLsizei height,
return true;
}
bool validateES3TexImageParameters(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 border, GLenum format, GLenum type)
bool validateES2TexImageParameters(gl::Context *context, GLenum target, GLint level, GLint internalformat, bool isCompressed, bool isSubImage,
GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
GLint border, GLenum format, GLenum type, const GLvoid *pixels)
{
// Validate image size
if (level < 0 || width < 0 || height < 0 || depth < 0 )
if (!validImageSize(context, level, width, height, 1))
{
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);
}
if (height != 1 && height != 2 && height % 4 != 0)
{
return gl::error(GL_INVALID_OPERATION, false);
}
return gl::error(GL_INVALID_OPERATION, false);
}
// Verify zero border
if (border != 0)
if (level < 0 || xoffset < 0 ||
std::numeric_limits<GLsizei>::max() - xoffset < width ||
std::numeric_limits<GLsizei>::max() - yoffset < height)
{
return gl::error(GL_INVALID_VALUE, false);
}
// Validate dimensions based on Context limits and validate the texture
if (level > context->getMaximumTextureLevel())
if (!isSubImage && !isCompressed && internalformat != GLint(format))
{
return gl::error(GL_INVALID_VALUE, false);
return gl::error(GL_INVALID_OPERATION, false);
}
gl::Texture *texture = NULL;
......@@ -263,7 +269,6 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le
GLenum textureInternalFormat = GL_NONE;
GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0;
switch (target)
{
case GL_TEXTURE_2D:
......@@ -274,16 +279,23 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le
return gl::error(GL_INVALID_VALUE, false);
}
gl::Texture2D *texture2d = context->getTexture2D();
if (texture2d)
gl::Texture2D *tex2d = context->getTexture2D();
if (tex2d)
{
textureCompressed = texture2d->isCompressed(level);
textureInternalFormat = texture2d->getInternalFormat(level);
textureLevelWidth = texture2d->getWidth(level);
textureLevelHeight = texture2d->getHeight(level);
textureLevelDepth = 1;
texture = texture2d;
textureCompressed = tex2d->isCompressed(level);
textureInternalFormat = tex2d->getInternalFormat(level);
textureLevelWidth = tex2d->getWidth(level);
textureLevelHeight = tex2d->getHeight(level);
texture = tex2d;
}
if (isSubImage && !validateSubImageParams2D(isCompressed, width, height, xoffset, yoffset,
level, format, type, tex2d))
{
return false;
}
texture = tex2d;
}
break;
......@@ -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_NEGATIVE_Z:
{
if (width != height)
if (!isSubImage && width != height)
{
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);
}
gl::TextureCubeMap *textureCube = context->getTextureCubeMap();
if (textureCube)
{
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))
gl::TextureCubeMap *texCube = context->getTextureCubeMap();
if (texCube)
{
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 (texture3d)
if (isSubImage && !validateSubImageParamsCube(isCompressed, width, height, xoffset, yoffset,
target, level, format, type, texCube))
{
textureCompressed = texture3d->isCompressed(level);
textureInternalFormat = texture3d->getInternalFormat(level);
textureLevelWidth = texture3d->getWidth(level);
textureLevelHeight = texture3d->getHeight(level);
textureLevelDepth = texture3d->getDepth(level);
texture = texture3d;
return false;
}
}
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:
return gl::error(GL_INVALID_ENUM, false);
}
......@@ -370,146 +344,253 @@ bool validateES3TexImageParameters(gl::Context *context, GLenum target, GLint le
return gl::error(GL_INVALID_OPERATION, false);
}
if (texture->isImmutable())
if (!isSubImage && texture->isImmutable())
{
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;
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);
}
if (target == GL_TEXTURE_3D)
{
return gl::error(GL_INVALID_OPERATION, false);
}
}
else
{
if (!gl::IsValidInternalFormat(actualInternalFormat, context) ||
!gl::IsValidFormat(format, context->getClientVersion()) ||
!gl::IsValidType(type, context->getClientVersion()))
// 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, false);
}
if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getClientVersion()))
{
return gl::error(GL_INVALID_OPERATION, false);
}
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)
// validate <format> + <type> combinations
// - invalid <format> -> sets INVALID_ENUM
// - invalid <format>+<type> combination -> sets INVALID_OPERATION
switch (format)
{
GLenum internalformat = gl::GetSizedInternalFormat(format, type, context->getClientVersion());
if (internalformat != textureInternalFormat)
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, false);
}
}
if (isCompressed)
{
if ((width % 4 != 0 && width != textureLevelWidth) ||
(height % 4 != 0 && height != textureLevelHeight))
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, 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);
}
break;
default:
return gl::error(GL_INVALID_ENUM, false);
}
if (width == 0 || height == 0 || depth == 0)
switch (format)
{
return false;
}
if (xoffset < 0 || yoffset < 0 || zoffset < 0)
{
return gl::error(GL_INVALID_VALUE, false);
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_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 ||
std::numeric_limits<GLsizei>::max() - yoffset < height ||
std::numeric_limits<GLsizei>::max() - zoffset < depth)
if (type == GL_FLOAT)
{
return gl::error(GL_INVALID_VALUE, false);
if (!context->supportsFloat32Textures())
{
return gl::error(GL_INVALID_ENUM, false);
}
}
if (xoffset + width > textureLevelWidth ||
yoffset + height > textureLevelHeight ||
zoffset + depth > textureLevelDepth)
else if (type == GL_HALF_FLOAT_OES)
{
return gl::error(GL_INVALID_VALUE, false);
if (!context->supportsFloat16Textures())
{
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)
bool validateES3TexImageParameters(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 border, GLenum format, GLenum type)
{
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)
// Validate image size
if (!validImageSize(context, level, width, height, depth))
{
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)
{
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);
}
gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
GLenum colorbufferFormat = source->getInternalFormat();
gl::Texture *texture = NULL;
GLenum textureFormat = GL_RGBA;
bool textureCompressed = false;
GLenum textureInternalFormat = GL_NONE;
GLint textureLevelWidth = 0;
GLint textureLevelHeight = 0;
GLint textureLevelDepth = 0;
......@@ -517,11 +598,17 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
{
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();
if (texture2d)
{
textureFormat = gl::GetFormat(texture2d->getInternalFormat(level), context->getClientVersion());
textureCompressed = texture2d->isCompressed(level);
textureInternalFormat = texture2d->getInternalFormat(level);
textureLevelWidth = texture2d->getWidth(level);
textureLevelHeight = texture2d->getHeight(level);
textureLevelDepth = 1;
......@@ -537,11 +624,21 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
case GL_TEXTURE_CUBE_MAP_POSITIVE_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();
if (textureCube)
{
textureFormat = gl::GetFormat(textureCube->getInternalFormat(target, level), context->getClientVersion());
textureCompressed = textureCube->isCompressed(target, level);
textureInternalFormat = textureCube->getInternalFormat(target, level);
textureLevelWidth = textureCube->getWidth(target, level);
textureLevelHeight = textureCube->getHeight(target, level);
textureLevelDepth = 1;
......@@ -552,11 +649,18 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
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();
if (texture3d)
{
textureFormat = gl::GetFormat(texture3d->getInternalFormat(level), context->getClientVersion());
textureCompressed = texture3d->isCompressed(level);
textureInternalFormat = texture3d->getInternalFormat(level);
textureLevelWidth = texture3d->getWidth(level);
textureLevelHeight = texture3d->getHeight(level);
textureLevelDepth = texture3d->getDepth(level);
......@@ -565,6 +669,28 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
}
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:
return gl::error(GL_INVALID_ENUM, false);
}
......@@ -574,106 +700,581 @@ bool validateES3CopyTexImageParameters(gl::Context *context, GLenum target, GLin
return gl::error(GL_INVALID_OPERATION, false);
}
if (texture->isImmutable() && !isSubImage)
if (texture->isImmutable())
{
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) ||
(height % 4 != 0 && height != textureLevelHeight))
if (!gl::IsFormatCompressed(actualInternalFormat, context->getClientVersion()))
{
return gl::error(GL_INVALID_OPERATION, false);
return gl::error(GL_INVALID_ENUM, false);
}
}
if (xoffset + width > textureLevelWidth ||
yoffset + height > textureLevelHeight ||
zoffset >= textureLevelDepth)
{
return gl::error(GL_INVALID_VALUE, false);
if (target == GL_TEXTURE_3D)
{
return gl::error(GL_INVALID_OPERATION, false);
}
}
if (!gl::IsValidCopyTexImageCombination(textureFormat, colorbufferFormat, context->getClientVersion()))
else
{
return gl::error(GL_INVALID_OPERATION, false);
}
return true;
}
if (!gl::IsValidInternalFormat(actualInternalFormat, context) ||
!gl::IsValidFormat(format, context->getClientVersion()) ||
!gl::IsValidType(type, context->getClientVersion()))
{
return gl::error(GL_INVALID_ENUM, false);
}
// 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)
if (!gl::IsValidFormatCombination(actualInternalFormat, format, type, context->getClientVersion()))
{
case GL_UNSIGNED_BYTE:
break;
default:
return false;
return gl::error(GL_INVALID_OPERATION, false);
}
break;
case GL_BGRA_EXT:
switch (type)
if ((target == GL_TEXTURE_3D || target == GL_TEXTURE_2D_ARRAY) &&
(format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL))
{
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;
return gl::error(GL_INVALID_OPERATION, 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:
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);
}
if (isCompressed != textureCompressed)
{
return gl::error(GL_INVALID_OPERATION, false);
}
for (int i = 0; i < numAttachments; ++i)
{
if (attachments[i] >= GL_COLOR_ATTACHMENT0 && attachments[i] <= GL_COLOR_ATTACHMENT15)
if (format != GL_NONE)
{
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);
}
}
else
if (width == 0 || height == 0 || depth == 0)
{
switch (attachments[i])
{
case GL_DEPTH_ATTACHMENT:
case GL_STENCIL_ATTACHMENT:
case GL_DEPTH_STENCIL_ATTACHMENT:
if (defaultFramebuffer)
return false;
}
if (xoffset < 0 || yoffset < 0 || zoffset < 0)
{
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);
}
......@@ -1480,375 +2081,109 @@ void __stdcall glClear(GLbitfield mask)
}
}
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)
void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
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);
EVENT("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
red, green, blue, alpha);
try
{
if (!gl::IsInternalTextureTarget(target))
{
return gl::error(GL_INVALID_ENUM);
}
gl::Context *context = gl::getNonLostContext();
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:
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);
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 (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();
if (context)
{
if (level > context->getMaximumTextureLevel())
{
return gl::error(GL_INVALID_VALUE);
}
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);
}
}
switch (format) {
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();
}
void __stdcall glCompileShader(GLuint shader)
{
EVENT("(GLuint shader = %d)", shader);
if (imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, context->getClientVersion(), width, height))
{
return gl::error(GL_INVALID_VALUE);
}
try
{
gl::Context *context = gl::getNonLostContext();
if (xoffset % 4 != 0 || yoffset % 4 != 0)
{
return gl::error(GL_INVALID_OPERATION); // we wait to check the offsets until this point, because the multiple-of-four restriction
// does not exist unless DXT textures are supported.
}
if (context)
{
gl::Shader *shaderObject = context->getShader(shader);
if (target == GL_TEXTURE_2D)
if (!shaderObject)
{
gl::Texture2D *texture = context->getTexture2D();
if (validateSubImageParams2D(true, width, height, xoffset, yoffset, level, format, GL_UNSIGNED_BYTE, texture))
if (context->getProgram(shader))
{
texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
return gl::error(GL_INVALID_OPERATION);
}
}
else if (gl::IsCubemapTextureTarget(target))
{
gl::TextureCubeMap *texture = context->getTextureCubeMap();
if (validateSubImageParamsCube(true, width, height, xoffset, yoffset, target, level, format, GL_UNSIGNED_BYTE, texture))
else
{
texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
return gl::error(GL_INVALID_VALUE);
}
}
else
{
UNREACHABLE();
}
shaderObject->compile();
}
}
catch(std::bad_alloc&)
......@@ -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, "
"GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)",
target, level, internalformat, x, y, width, height, border);
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))
{
return gl::error(GL_INVALID_VALUE);
}
if (border != 0)
{
return gl::error(GL_INVALID_VALUE);
}
gl::Context *context = gl::getNonLostContext();
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);
}
......@@ -1887,164 +2227,152 @@ void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalforma
switch (target)
{
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;
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->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
}
break;
default:
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();
GLenum colorbufferFormat = source->getInternalFormat();
if (imageSize < 0 || imageSize != (GLsizei)gl::GetBlockSize(format, GL_UNSIGNED_BYTE, context->getClientVersion(), width, height))
{
return gl::error(GL_INVALID_VALUE);
}
// [OpenGL ES 2.0.24] table 3.9
switch (internalformat)
switch (target)
{
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);
}
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
case GL_TEXTURE_2D:
{
return gl::error(GL_INVALID_ENUM);
gl::Texture2D *texture = context->getTexture2D();
texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
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_ENUM);
gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
}
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:
return gl::error(GL_INVALID_ENUM);
}
}
}
catch(std::bad_alloc&)
{
return gl::error(GL_OUT_OF_MEMORY);
}
}
if (target == GL_TEXTURE_2D)
{
gl::Texture2D *texture = context->getTexture2D();
if (!texture)
{
return gl::error(GL_INVALID_OPERATION);
}
void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
{
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)",
target, level, internalformat, x, y, width, height, border);
if (texture->isImmutable())
{
return gl::error(GL_INVALID_OPERATION);
}
try
{
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&)
......@@ -2061,121 +2389,50 @@ void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GL
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();
if (context)
{
if (level > context->getMaximumTextureLevel())
{
return gl::error(GL_INVALID_VALUE);
}
gl::Framebuffer *framebuffer = context->getReadFramebuffer();
if (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
if (context->getClientVersion() < 3 &&
!validateES2CopyTexImageParameters(context, target, level, GL_NONE, true,
xoffset, yoffset, x, y, width, height, 0))
{
return gl::error(GL_INVALID_FRAMEBUFFER_OPERATION);
}
if (context->getReadFramebufferHandle() != 0 && framebuffer->getSamples() != 0)
{
return gl::error(GL_INVALID_OPERATION);
return;
}
gl::Renderbuffer *source = framebuffer->getReadColorbuffer();
GLenum colorbufferFormat = source->getInternalFormat();
gl::Texture *texture = NULL;
GLenum textureFormat = GL_RGBA;
if (target == GL_TEXTURE_2D)
if (context->getClientVersion() >= 3 &&
!validateES3CopyTexImageParameters(context, target, level, GL_NONE, true,
xoffset, yoffset, 0, x, y, width, height, 0))
{
gl::Texture2D *tex2d = context->getTexture2D();
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;
return;
}
else if (gl::IsCubemapTextureTarget(target))
{
gl::TextureCubeMap *texcube = context->getTextureCubeMap();
if (!validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, GL_NONE, GL_NONE, texcube))
{
return; // error already registered by validateSubImageParams
}
textureFormat = gl::GetFormat(texcube->getInternalFormat(target, level), context->getClientVersion());
texture = texcube;
}
else UNREACHABLE();
gl::Framebuffer *framebuffer = context->getReadFramebuffer();
// [OpenGL ES 2.0.24] table 3.9
switch (textureFormat)
switch (target)
{
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);
}
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)
case GL_TEXTURE_2D:
{
return gl::error(GL_INVALID_OPERATION);
gl::Texture2D *texture = context->getTexture2D();
texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
}
break;
case GL_LUMINANCE_ALPHA:
case GL_RGBA:
if (colorbufferFormat != GL_RGBA4 &&
colorbufferFormat != GL_RGB5_A1 &&
colorbufferFormat != GL_RGBA8_OES)
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->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, framebuffer);
}
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:
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
case GL_INCR_WRAP:
case GL_DECR_WRAP:
break;
default:
return gl::error(GL_INVALID_ENUM);
}
gl::Context *context = gl::getNonLostContext();
if (context)
{
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)
default:
return gl::error(GL_INVALID_ENUM);
}
gl::Context *context = gl::getNonLostContext();
if (context)
{
if (face == GL_FRONT || face == GL_FRONT_AND_BACK)
{
case GL_UNSIGNED_SHORT:
case GL_UNSIGNED_INT:
break;
default:
return gl::error(GL_INVALID_OPERATION);
context->setStencilOperations(fail, zfail, zpass);
}
break;
case GL_DEPTH_STENCIL_OES:
switch (type)
if (face == GL_BACK || face == GL_FRONT_AND_BACK)
{
case GL_UNSIGNED_INT_24_8_OES:
break;
default:
return gl::error(GL_INVALID_OPERATION);
context->setStencilBackOperations(fail, zfail, zpass);
}
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();
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)
{
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;
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;
default:
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
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
{
return gl::error(GL_INVALID_ENUM);
gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImageNegX(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE:
if (context->supportsDXT3Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
{
return gl::error(GL_INVALID_ENUM);
gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImagePosY(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
}
break;
case GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE:
if (context->supportsDXT5Textures())
{
return gl::error(GL_INVALID_OPERATION);
}
else
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
{
return gl::error(GL_INVALID_ENUM);
gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImageNegY(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
}
break;
case GL_DEPTH_COMPONENT:
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)
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
{
return gl::error(GL_INVALID_OPERATION);
gl::TextureCubeMap *texture = context->getTextureCubeMap();
texture->setImagePosZ(level, width, height, internalformat, format, type, context->getUnpackAlignment(), pixels);
}
break;
default:
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_NEGATIVE_Z:
{
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
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:
gl::TextureCubeMap *texture = context->getTextureCubeMap();
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
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();
if (context)
{
if (level > context->getMaximumTextureLevel())
{
return gl::error(GL_INVALID_VALUE);
}
if (type == GL_FLOAT)
{
if (!context->supportsFloat32Textures())
{
return gl::error(GL_INVALID_ENUM);
}
}
else if (type == GL_HALF_FLOAT_OES)
if (context->getClientVersion() < 3 &&
!validateES2TexImageParameters(context, target, level, GL_NONE, false, true,
0, 0, width, height, 0, format, type, pixels))
{
if (!context->supportsFloat16Textures())
{
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);
return;
}
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;
}
if (target == GL_TEXTURE_2D)
switch (target)
{
gl::Texture2D *texture = context->getTexture2D();
if (validateSubImageParams2D(false, width, height, xoffset, yoffset, level, format, type, texture))
case GL_TEXTURE_2D:
{
gl::Texture2D *texture = context->getTexture2D();
texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
}
}
else if (gl::IsCubemapTextureTarget(target))
{
gl::TextureCubeMap *texture = context->getTextureCubeMap();
if (validateSubImageParamsCube(false, width, height, xoffset, yoffset, target, level, format, type, texture))
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 *texture = context->getTextureCubeMap();
texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackAlignment(), pixels);
}
}
else
{
UNREACHABLE();
break;
default:
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