#include "textureview.h"
#include "mtypes.h"
#include "glformats.h"
+#include "texstore.h"
/**
}
}
- if (ctx->Extensions.ATI_envmap_bumpmap) {
- switch (internalFormat) {
- case GL_DUDV_ATI:
- case GL_DU8DV8_ATI:
- return GL_DUDV_ATI;
- default:
- ; /* fallthrough */
- }
- }
-
if (ctx->Extensions.EXT_texture_snorm) {
switch (internalFormat) {
case GL_RED_SNORM:
/* check zoffset and depth */
if (dims > 2) {
- GLint zBorder = (target == GL_TEXTURE_2D_ARRAY) ? 0 : destImage->Border;
+ GLint zBorder = (target == GL_TEXTURE_2D_ARRAY ||
+ target == GL_TEXTURE_CUBE_MAP_ARRAY) ?
+ 0 : destImage->Border;
+
if (zoffset < -zBorder) {
_mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset)", function);
return GL_TRUE;
return true;
}
+static bool
+texture_formats_agree(GLenum internalFormat,
+ GLenum format)
+{
+ GLboolean colorFormat;
+ GLboolean is_format_depth_or_depthstencil;
+ GLboolean is_internalFormat_depth_or_depthstencil;
+
+ /* Even though there are no color-index textures, we still have to support
+ * uploading color-index data and remapping it to RGB via the
+ * GL_PIXEL_MAP_I_TO_[RGBA] tables.
+ */
+ const GLboolean indexFormat = (format == GL_COLOR_INDEX);
+
+ is_internalFormat_depth_or_depthstencil =
+ _mesa_is_depth_format(internalFormat) ||
+ _mesa_is_depthstencil_format(internalFormat);
+
+ is_format_depth_or_depthstencil =
+ _mesa_is_depth_format(format) ||
+ _mesa_is_depthstencil_format(format);
+
+ colorFormat = _mesa_is_color_format(format);
+
+ if (_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat)
+ return false;
+
+ if (is_internalFormat_depth_or_depthstencil !=
+ is_format_depth_or_depthstencil)
+ return false;
+
+ if (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format))
+ return false;
+
+ return true;
+}
+
/**
* Test the glTexImage[123]D() parameters for errors.
*
GLint width, GLint height,
GLint depth, GLint border )
{
- GLboolean colorFormat;
- GLboolean is_format_depth_or_depthstencil;
- GLboolean is_internalFormat_depth_or_depthstencil;
GLenum err;
- /* Even though there are no color-index textures, we still have to support
- * uploading color-index data and remapping it to RGB via the
- * GL_PIXEL_MAP_I_TO_[RGBA] tables.
- */
- const GLboolean indexFormat = (format == GL_COLOR_INDEX);
-
/* Note: for proxy textures, some error conditions immediately generate
* a GL error in the usual way. But others do not generate a GL error.
* Instead, they cause the width, height, depth, format fields of the
}
/* make sure internal format and format basically agree */
- is_internalFormat_depth_or_depthstencil =
- _mesa_is_depth_format(internalFormat) ||
- _mesa_is_depthstencil_format(internalFormat);
-
- is_format_depth_or_depthstencil =
- _mesa_is_depth_format(format) ||
- _mesa_is_depthstencil_format(format);
-
- colorFormat = _mesa_is_color_format(format);
- if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) ||
- (is_internalFormat_depth_or_depthstencil != is_format_depth_or_depthstencil) ||
- (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) ||
- (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) {
+ if (!texture_formats_agree(internalFormat, format)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glTexImage%dD(incompatible internalFormat = %s, format = %s)",
dimensions, _mesa_lookup_enum_by_nr(internalFormat),
}
+bool
+_mesa_compressed_texture_pixel_storage_error_check(struct gl_context *ctx,
+ GLint dimensions,
+ struct gl_pixelstore_attrib *packing,
+ const char *caller)
+{
+ if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize)
+ return true;
+
+ if (packing->CompressedBlockWidth && packing->SkipPixels % packing->CompressedBlockWidth) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(skip-pixels %% block-width)", caller);
+ return false;
+ }
+
+ if (dimensions > 1 && packing->CompressedBlockHeight && packing->SkipRows % packing->CompressedBlockHeight) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(skip-rows %% block-height)", caller);
+ return false;
+ }
+
+ if (dimensions > 2 && packing->CompressedBlockDepth && packing->SkipImages % packing->CompressedBlockDepth) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(skip-images %% block-depth)", caller);
+ return false;
+ }
+
+ return true;
+}
+
/**
* Error checking for glCompressedTexImage[123]D().
* Note that the width, height and depth values are not fully error checked
goto error;
}
+ /* Check for invalid pixel storage modes */
+ if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dimensions,
+ &ctx->Unpack,
+ "glCompressedTexImage")) {
+ return GL_FALSE;
+ }
+
/* check image size in bytes */
if (expectedSize != imageSize) {
/* Per GL_ARB_texture_compression: GL_INVALID_VALUE is generated [...]
}
/* choose format from scratch */
- f = ctx->Driver.ChooseTextureFormat(ctx, texObj->Target, internalFormat,
+ f = ctx->Driver.ChooseTextureFormat(ctx, target, internalFormat,
format, type);
ASSERT(f != MESA_FORMAT_NONE);
return f;
x, y, width, height);
}
+static bool
+check_clear_tex_image(struct gl_context *ctx,
+ const char *function,
+ struct gl_texture_image *texImage,
+ GLenum format, GLenum type,
+ const void *data,
+ GLubyte *clearValue)
+{
+ struct gl_texture_object *texObj = texImage->TexObject;
+ static const GLubyte zeroData[MAX_PIXEL_BYTES];
+ GLenum internalFormat = texImage->InternalFormat;
+ GLenum err;
+
+ if (texObj->Target == GL_TEXTURE_BUFFER) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(buffer texture)", function);
+ return false;
+ }
+
+ if (_mesa_is_compressed_format(ctx, internalFormat)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(compressed texture)", function);
+ return false;
+ }
+
+ err = _mesa_error_check_format_and_type(ctx, format, type);
+ if (err != GL_NO_ERROR) {
+ _mesa_error(ctx, err,
+ "%s(incompatible format = %s, type = %s)",
+ function,
+ _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(type));
+ return false;
+ }
+
+ /* make sure internal format and format basically agree */
+ if (!texture_formats_agree(internalFormat, format)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(incompatible internalFormat = %s, format = %s)",
+ function,
+ _mesa_lookup_enum_by_nr(internalFormat),
+ _mesa_lookup_enum_by_nr(format));
+ return false;
+ }
+
+ if (ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) {
+ /* both source and dest must be integer-valued, or neither */
+ if (_mesa_is_format_integer_color(texImage->TexFormat) !=
+ _mesa_is_enum_format_integer(format)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(integer/non-integer format mismatch)",
+ function);
+ return false;
+ }
+ }
+
+ if (!_mesa_texstore(ctx,
+ 1, /* dims */
+ texImage->_BaseFormat,
+ texImage->TexFormat,
+ 0, /* dstRowStride */
+ &clearValue,
+ 1, 1, 1, /* srcWidth/Height/Depth */
+ format, type,
+ data ? data : zeroData,
+ &ctx->DefaultPacking)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid format)", function);
+ return false;
+ }
+
+ return true;
+}
+
+static struct gl_texture_object *
+get_tex_obj_for_clear(struct gl_context *ctx,
+ const char *function,
+ GLuint texture)
+{
+ struct gl_texture_object *texObj;
+
+ if (texture == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function);
+ return NULL;
+ }
+
+ texObj = _mesa_lookup_texture(ctx, texture);
+
+ if (texObj == NULL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function);
+ return NULL;
+ }
+
+ if (texObj->Target == 0) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function);
+ return NULL;
+ }
+
+ return texObj;
+}
+
+static int
+get_tex_images_for_clear(struct gl_context *ctx,
+ const char *function,
+ struct gl_texture_object *texObj,
+ GLint level,
+ struct gl_texture_image **texImages)
+{
+ GLenum target;
+ int i;
+
+ if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
+ return 0;
+ }
+
+ if (texObj->Target == GL_TEXTURE_CUBE_MAP) {
+ for (i = 0; i < MAX_FACES; i++) {
+ target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
+
+ texImages[i] = _mesa_select_tex_image(ctx, texObj, target, level);
+ if (texImages[i] == NULL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(invalid level)", function);
+ return 0;
+ }
+ }
+
+ return MAX_FACES;
+ }
+
+ texImages[0] = _mesa_select_tex_image(ctx, texObj, texObj->Target, level);
+
+ if (texImages[0] == NULL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function);
+ return 0;
+ }
+
+ return 1;
+}
+
+void GLAPIENTRY
+_mesa_ClearTexSubImage( GLuint texture, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei width, GLsizei height, GLsizei depth,
+ GLenum format, GLenum type, const void *data )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImages[MAX_FACES];
+ GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES];
+ int i, numImages;
+ int minDepth, maxDepth;
+
+ texObj = get_tex_obj_for_clear(ctx, "glClearTexSubImage", texture);
+
+ if (texObj == NULL)
+ return;
+
+ _mesa_lock_texture(ctx, texObj);
+
+ numImages = get_tex_images_for_clear(ctx, "glClearTexSubImage",
+ texObj, level, texImages);
+ if (numImages == 0)
+ goto out;
+
+ if (numImages == 1) {
+ minDepth = -(int) texImages[0]->Border;
+ maxDepth = texImages[0]->Depth;
+ } else {
+ minDepth = 0;
+ maxDepth = numImages;
+ }
+
+ if (xoffset < -(GLint) texImages[0]->Border ||
+ yoffset < -(GLint) texImages[0]->Border ||
+ zoffset < minDepth ||
+ width < 0 ||
+ height < 0 ||
+ depth < 0 ||
+ xoffset + width > texImages[0]->Width ||
+ yoffset + height > texImages[0]->Height ||
+ zoffset + depth > maxDepth) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glClearSubTexImage(invalid dimensions)");
+ goto out;
+ }
+
+ if (numImages == 1) {
+ if (check_clear_tex_image(ctx, "glClearTexSubImage",
+ texImages[0],
+ format, type, data, clearValue[0])) {
+ ctx->Driver.ClearTexSubImage(ctx,
+ texImages[0],
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ data ? clearValue[0] : NULL);
+ }
+ } else {
+ for (i = zoffset; i < zoffset + depth; i++) {
+ if (!check_clear_tex_image(ctx, "glClearTexSubImage",
+ texImages[i],
+ format, type, data, clearValue[i]))
+ goto out;
+ }
+ for (i = zoffset; i < zoffset + depth; i++) {
+ ctx->Driver.ClearTexSubImage(ctx,
+ texImages[i],
+ xoffset, yoffset, 0,
+ width, height, 1,
+ data ? clearValue[i] : NULL);
+ }
+ }
+
+ out:
+ _mesa_unlock_texture(ctx, texObj);
+}
+
+void GLAPIENTRY
+_mesa_ClearTexImage( GLuint texture, GLint level,
+ GLenum format, GLenum type, const void *data )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImages[MAX_FACES];
+ GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES];
+ int i, numImages;
+
+ texObj = get_tex_obj_for_clear(ctx, "glClearTexImage", texture);
+
+ if (texObj == NULL)
+ return;
+
+ _mesa_lock_texture(ctx, texObj);
+
+ numImages = get_tex_images_for_clear(ctx, "glClearTexImage",
+ texObj, level, texImages);
+
+ for (i = 0; i < numImages; i++) {
+ if (!check_clear_tex_image(ctx, "glClearTexImage",
+ texImages[i],
+ format, type, data,
+ clearValue[i]))
+ goto out;
+ }
+
+ for (i = 0; i < numImages; i++) {
+ ctx->Driver.ClearTexSubImage(ctx, texImages[i],
+ -(GLint) texImages[i]->Border, /* xoffset */
+ -(GLint) texImages[i]->Border, /* yoffset */
+ -(GLint) texImages[i]->Border, /* zoffset */
+ texImages[i]->Width,
+ texImages[i]->Height,
+ texImages[i]->Depth,
+ data ? clearValue[i] : NULL);
+ }
+
+out:
+ _mesa_unlock_texture(ctx, texObj);
+}
+
}
if (!targetOK) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target)",
+ _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexSubImage%uD(target)",
dims);
return GL_TRUE;
}
}
if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(level=%d)",
+ _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(level=%d)",
dims, level);
return GL_TRUE;
}
+ /* Check for invalid pixel storage modes */
+ if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dims,
+ &ctx->Unpack,
+ "glCompressedTexSubImage")) {
+ return GL_FALSE;
+ }
+
+
expectedSize = compressed_tex_size(width, height, depth, format);
if (expectedSize != imageSize) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(size=%d)",
+ _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(size=%d)",
dims, imageSize);
return GL_TRUE;
}
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
- GLboolean sizeOK, dimensionsOK;
+ GLboolean sizeOK, dimensionsOK, samplesOK;
mesa_format texFormat;
GLenum sample_count_error;
sample_count_error = _mesa_check_sample_count(ctx, target,
internalformat, samples);
- if (sample_count_error != GL_NO_ERROR) {
+ samplesOK = sample_count_error == GL_NO_ERROR;
+
+ /* Page 254 of OpenGL 4.4 spec says:
+ * "Proxy arrays for two-dimensional multisample and two-dimensional
+ * multisample array textures are operated on in the same way when
+ * TexImage2DMultisample is called with target specified as
+ * PROXY_TEXTURE_2D_MULTISAMPLE, or TexImage3DMultisample is called
+ * with target specified as PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY.
+ * However, if samples is not supported, then no error is generated.
+ */
+ if (!samplesOK && !_mesa_is_proxy_texture(target)) {
_mesa_error(ctx, sample_count_error, "%s(samples)", func);
return;
}
width, height, depth, 0);
if (_mesa_is_proxy_texture(target)) {
- if (dimensionsOK && sizeOK) {
+ if (samplesOK && dimensionsOK && sizeOK) {
init_teximage_fields_ms(ctx, texImage, width, height, depth, 0,
internalformat, texFormat,
samples, fixedsamplelocations);
"glTexStorage2DMultisample");
}
-
void GLAPIENTRY
_mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
GLenum internalformat, GLsizei width,