/**
- * Check the width, height, depth and border of a texture image
- * against the max texture size constants.
+ * Check the width, height, depth and border of a texture image are legal.
+ * Used by all the glTexImage, glCompressedTexImage and glCopyTexImage
+ * functions.
* The target and level parameters will have already been validated.
* \return GL_TRUE if size is OK, GL_FALSE otherwise.
*/
GLint maxSize;
switch (target) {
+ case GL_TEXTURE_1D:
case GL_PROXY_TEXTURE_1D:
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); /* level zero size */
maxSize >>= level; /* level size */
}
return GL_TRUE;
+ case GL_TEXTURE_2D:
case GL_PROXY_TEXTURE_2D:
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
maxSize >>= level;
}
return GL_TRUE;
+ case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
maxSize >>= level;
}
return GL_TRUE;
+ case GL_TEXTURE_RECTANGLE_NV:
case GL_PROXY_TEXTURE_RECTANGLE_NV:
if (level != 0)
return GL_FALSE;
return GL_FALSE;
return GL_TRUE;
+ 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:
case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
maxSize >>= level;
}
return GL_TRUE;
+ case GL_TEXTURE_1D_ARRAY_EXT:
case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
maxSize >>= level;
}
return GL_TRUE;
+ case GL_TEXTURE_2D_ARRAY_EXT:
case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
maxSize >>= level;
/**
- * This is the fallback for Driver.TestProxyTexImage(). Test the texture
- * width, height and depth against the ctx->Const limits for textures.
+ * This is the fallback for Driver.TestProxyTexImage() for doing device-
+ * specific texture image size checks.
*
* A hardware driver might override this function if, for example, the
* max 3D texture size is 512x512x64 (i.e. not a cube).
* texture with zero width/height/depth will be considered "incomplete"
* and texturing will effectively be disabled.
*
- * \param target one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D,
- * GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV,
- * GL_PROXY_TEXTURE_CUBE_MAP_ARB.
+ * \param target any texture target/type
* \param level as passed to glTexImage
- * \param internalFormat as passed to glTexImage
- * \param format as passed to glTexImage
- * \param type as passed to glTexImage
+ * \param format the MESA_FORMAT_x for the tex image
* \param width as passed to glTexImage
* \param height as passed to glTexImage
* \param depth as passed to glTexImage
*/
GLboolean
_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
- GLint internalFormat, GLenum format, GLenum type,
+ gl_format format,
GLint width, GLint height, GLint depth, GLint border)
{
- (void) internalFormat;
- (void) format;
- (void) type;
-
- return _mesa_legal_texture_dimensions(ctx, target, level,
- width, height, depth, border);
-}
-
-
-/**
- * Check if the memory used by the texture would exceed the driver's limit.
- * This lets us support a max 3D texture size of 8K (for example) but
- * prevents allocating a full 8K x 8K x 8K texture.
- * XXX this could be rolled into the proxy texture size test (above) but
- * we don't have the actual texture internal format at that point.
- */
-static GLboolean
-legal_texture_size(struct gl_context *ctx, gl_format format,
- GLint width, GLint height, GLint depth)
-{
+ /* We just check if the image size is less than MaxTextureMbytes.
+ * Some drivers may do more specific checks.
+ */
uint64_t bytes = _mesa_format_image_size64(format, width, height, depth);
uint64_t mbytes = bytes / (1024 * 1024); /* convert to MB */
return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes;
}
-/**
- * Special value returned by error some texture error checking functions when
- * an error is detected and the proxy texture image's width/height/depth/format
- * fields should be zeroed-out.
- */
-#define PROXY_ERROR 2
-
-
/**
* Test the glTexImage[123]D() parameters for errors.
*
* \param depth image depth given by the user.
* \param border image border given by the user.
*
- * \return PROXY_ERROR if there's an error that should zero-out the proxy image,
- * GL_TRUE if a regular GL error is found, or GL_FALSE if no error,
+ * \return GL_TRUE if a error is found, GL_FALSE otherwise
*
* Verifies each of the parameters against the constants specified in
* __struct gl_contextRec::Const and the supported extensions, and according
* by several other GL entrypoints. Plus, texture dims have a special
* interaction with proxy textures.
*/
-static GLenum
+static GLboolean
texture_error_check( struct gl_context *ctx,
GLuint dimensions, GLenum target,
GLint level, GLint internalFormat,
GLint width, GLint height,
GLint depth, GLint border )
{
- const GLenum proxyTarget = _mesa_get_proxy_target(target);
- const GLboolean isProxy = target == proxyTarget;
- GLboolean sizeOK = GL_TRUE;
GLboolean colorFormat;
GLenum err;
}
}
- /* Do this simple check before calling the TestProxyTexImage() function */
- if (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
- sizeOK = (width == height);
- }
-
- /*
- * Use the proxy texture driver hook to see if the size/level/etc are
- * legal.
- */
- sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
- internalFormat, format,
- type, width, height,
- depth, border);
- if (!sizeOK) {
- if (isProxy) {
- /* No GL error is recorded, but we need to zero-out the image dims */
- return PROXY_ERROR;
- }
- else {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexImage%dD(level=%d, width=%d, height=%d, depth=%d)",
- dimensions, level, width, height, depth);
- return GL_TRUE;
- }
+ if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
+ _mesa_is_cube_face(target)) && width != height) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glTexImage2D(cube width != height)");
+ return GL_TRUE;
}
/* Check internalFormat */
/**
* Error checking for glCompressedTexImage[123]D().
- * \param reason returns reason for error, if any
- * \return error code or GL_NO_ERROR or PROXY_ERROR.
+ * Note that the width, height and depth values are not fully error checked
+ * here.
+ * \return GL_TRUE if a error is found, GL_FALSE otherwise
*/
static GLenum
compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
GLsizei height, GLsizei depth, GLint border,
GLsizei imageSize)
{
- const GLenum proxyTarget = _mesa_get_proxy_target(target);
const GLint maxLevels = _mesa_max_texture_levels(ctx, target);
GLint expectedSize;
GLenum choose_format;
}
/* For cube map, width must equal height */
- if (_mesa_is_cube_face(target) && width != height) {
+ if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
+ _mesa_is_cube_face(target)) && width != height) {
reason = "width != height";
error = GL_INVALID_VALUE;
goto error;
}
}
- /* check image sizes */
- if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
- proxy_format, choose_format,
- choose_type,
- width, height, depth, border)) {
- /* See error comment above */
- if (target == proxyTarget) {
- return PROXY_ERROR;
- }
- reason = "invalid width, height or format";
- error = GL_INVALID_OPERATION;
- goto error;
- }
-
/* check image size in bytes */
if (expectedSize != imageSize) {
/* Per GL_ARB_texture_compression: GL_INVALID_VALUE is generated [...]
goto error;
}
- return GL_NO_ERROR;
+ return GL_FALSE;
error:
_mesa_error(ctx, error, "glCompressedTexImage%dD(%s)", dimensions, reason);
- return error;
+ return GL_TRUE;
}
GLenum target, GLint level, GLint internalFormat,
GLint width, GLint height, GLint border )
{
- const GLenum proxyTarget = _mesa_get_proxy_target(target);
- const GLenum type = GL_FLOAT;
- GLboolean sizeOK;
GLint baseFormat;
/* check target */
}
}
- /* Do size, level checking */
- sizeOK = (proxyTarget == GL_PROXY_TEXTURE_CUBE_MAP_ARB)
- ? (width == height) : 1;
-
- sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
- internalFormat, baseFormat,
- type, width, height,
- 1, border);
-
- if (!sizeOK) {
- if (dimensions == 1) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexImage1D(width=%d)", width);
- }
- else {
- ASSERT(dimensions == 2);
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexImage2D(width=%d, height=%d)", width, height);
- }
+ if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
+ _mesa_is_cube_face(target)) && width != height) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glTexImage2D(cube width != height)");
return GL_TRUE;
}
GLsizei imageSize, const GLvoid *pixels)
{
const char *func = compressed ? "glCompressedTexImage" : "glTexImage";
- GLenum error;
struct gl_pixelstore_attrib unpack_no_border;
const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
+ struct gl_texture_object *texObj;
+ gl_format texFormat;
+ GLboolean dimensionsOK, sizeOK;
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
/* general error checking */
if (compressed) {
- error = compressed_texture_error_check(ctx, dims, target, level,
- internalFormat,
- width, height, depth,
- border, imageSize);
+ if (compressed_texture_error_check(ctx, dims, target, level,
+ internalFormat,
+ width, height, depth,
+ border, imageSize))
+ return;
}
else {
- error = texture_error_check(ctx, dims, target, level, internalFormat,
- format, type, width, height, depth, border);
+ if (texture_error_check(ctx, dims, target, level, internalFormat,
+ format, type, width, height, depth, border))
+ return;
}
-#if FEATURE_ES
/* Here we convert a cpal compressed image into a regular glTexImage2D
* call by decompressing the texture. If we really want to support cpal
* textures in any driver this would have to be changed.
*/
- if (compressed && !error && dims == 2) {
+ if (ctx->API == API_OPENGLES && compressed && dims == 2) {
switch (internalFormat) {
case GL_PALETTE4_RGB8_OES:
case GL_PALETTE4_RGBA8_OES:
return;
}
}
-#endif
+
+ texObj = _mesa_get_current_tex_object(ctx, target);
+ assert(texObj);
+
+ texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+ internalFormat, format, type);
+ assert(texFormat != MESA_FORMAT_NONE);
+
+ /* check that width, height, depth are legal for the mipmap level */
+ dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, level, width,
+ height, depth, border);
+
+ /* check that the texture won't take too much memory, etc */
+ sizeOK = ctx->Driver.TestProxyTexImage(ctx, _mesa_get_proxy_target(target),
+ level, texFormat,
+ width, height, depth, border);
if (_mesa_is_proxy_texture(target)) {
/* Proxy texture: just clear or set state depending on error checking */
struct gl_texture_image *texImage =
get_proxy_tex_image(ctx, target, level);
- gl_format texFormat = MESA_FORMAT_NONE;
- if (!error) {
- /* No parameter errors. Choose a texture format and see if we
- * can really allocate the texture.
- */
- struct gl_texture_object *texObj =
- _mesa_get_current_tex_object(ctx, target);
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, format, type);
- if (!legal_texture_size(ctx, texFormat, width, height, depth)) {
- error = PROXY_ERROR;
- }
- }
+ if (!texImage)
+ return; /* GL_OUT_OF_MEMORY already recorded */
- if (error == PROXY_ERROR) {
- /* image too large, etc. Clear all proxy texture image parameters. */
- if (texImage)
- clear_teximage_fields(texImage);
- }
- else if (error == GL_FALSE) {
- /* no error: store the teximage parameters */
- if (texImage)
- _mesa_init_teximage_fields(ctx, texImage, width, height, depth,
- border, internalFormat, texFormat);
+ if (dimensionsOK && sizeOK) {
+ _mesa_init_teximage_fields(ctx, texImage, width, height, depth,
+ border, internalFormat, texFormat);
}
else {
- /* other, regular error (was already recorded) */
+ clear_teximage_fields(texImage);
}
}
else {
/* non-proxy target */
const GLuint face = _mesa_tex_target_to_face(target);
- struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
- if (error) {
- return; /* error was recorded */
+ if (!dimensionsOK) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glTexImage%uD(invalid width or height or depth)",
+ dims);
+ return;
+ }
+
+ if (!sizeOK) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "glTexImage%uD(image too large)", dims);
+ return;
}
/* Allow a hardware driver to just strip out the border, to provide
if (ctx->NewState & _NEW_PIXEL)
_mesa_update_state(ctx);
- texObj = _mesa_get_current_tex_object(ctx, target);
-
_mesa_lock_texture(ctx, texObj);
{
texImage = _mesa_get_tex_image(ctx, texObj, target, level);
_mesa_error(ctx, GL_OUT_OF_MEMORY, "%s%uD", func, dims);
}
else {
- gl_format texFormat;
-
ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
- texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
- internalFormat, format,
- type);
-
- if (legal_texture_size(ctx, texFormat, width, height, depth)) {
- _mesa_init_teximage_fields(ctx, texImage,
- width, height, depth,
- border, internalFormat, texFormat);
-
- /* Give the texture to the driver. <pixels> may be null. */
- if (compressed) {
- ctx->Driver.CompressedTexImage(ctx, dims, texImage,
- imageSize, pixels);
- }
- else {
- ctx->Driver.TexImage(ctx, dims, texImage, format,
- type, pixels, unpack);
- }
-
- check_gen_mipmap(ctx, target, texObj, level);
-
- _mesa_update_fbo_texture(ctx, texObj, face, level);
+ _mesa_init_teximage_fields(ctx, texImage,
+ width, height, depth,
+ border, internalFormat, texFormat);
- _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
+ /* Give the texture to the driver. <pixels> may be null. */
+ if (compressed) {
+ ctx->Driver.CompressedTexImage(ctx, dims, texImage,
+ imageSize, pixels);
}
else {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s%uD", func, dims);
+ ctx->Driver.TexImage(ctx, dims, texImage, format,
+ type, pixels, unpack);
}
+
+ check_gen_mipmap(ctx, target, texObj, level);
+
+ _mesa_update_fbo_texture(ctx, texObj, face, level);
+
+ _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
}
}
_mesa_unlock_texture(ctx, texObj);
}
+
/*
* Called from the API. Note that width includes the border.
*/
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
const GLuint face = _mesa_tex_target_to_face(target);
+ gl_format texFormat;
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
width, height, border))
return;
+ if (!_mesa_legal_texture_dimensions(ctx, target, level, width, height,
+ 1, border)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyTexImage%uD(invalid width or height)", dims);
+ return;
+ }
+
texObj = _mesa_get_current_tex_object(ctx, target);
+ assert(texObj);
+
+ texFormat = _mesa_choose_texture_format(ctx, texObj, target, level,
+ internalFormat, GL_NONE, GL_NONE);
+ assert(texFormat != MESA_FORMAT_NONE);
+
+ if (!ctx->Driver.TestProxyTexImage(ctx, _mesa_get_proxy_target(target),
+ level, texFormat,
+ width, height, 1, border)) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "glCopyTexImage%uD(image too large)", dims);
+ return;
+ }
if (border && ctx->Const.StripTextureBorder) {
x += border;
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
}
else {
- /* choose actual hw format */
- gl_format texFormat = _mesa_choose_texture_format(ctx, texObj,
- target, level,
- internalFormat,
- GL_NONE, GL_NONE);
-
- if (legal_texture_size(ctx, texFormat, width, height, 1)) {
- GLint srcX = x, srcY = y, dstX = 0, dstY = 0, dstZ = 0;
+ GLint srcX = x, srcY = y, dstX = 0, dstY = 0, dstZ = 0;
- /* Free old texture image */
- ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
+ /* Free old texture image */
+ ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
- _mesa_init_teximage_fields(ctx, texImage, width, height, 1,
- border, internalFormat, texFormat);
+ _mesa_init_teximage_fields(ctx, texImage, width, height, 1,
+ border, internalFormat, texFormat);
- /* Allocate texture memory (no pixel data yet) */
- ctx->Driver.TexImage(ctx, dims, texImage,
- GL_NONE, GL_NONE,
- NULL, &ctx->Unpack);
+ /* Allocate texture memory (no pixel data yet) */
+ ctx->Driver.TexImage(ctx, dims, texImage,
+ GL_NONE, GL_NONE,
+ NULL, &ctx->Unpack);
- if (_mesa_clip_copytexsubimage(ctx, &dstX, &dstY, &srcX, &srcY,
- &width, &height)) {
- struct gl_renderbuffer *srcRb =
- get_copy_tex_image_source(ctx, texImage->TexFormat);
+ if (_mesa_clip_copytexsubimage(ctx, &dstX, &dstY, &srcX, &srcY,
+ &width, &height)) {
+ struct gl_renderbuffer *srcRb =
+ get_copy_tex_image_source(ctx, texImage->TexFormat);
- ctx->Driver.CopyTexSubImage(ctx, dims, texImage, dstX, dstY, dstZ,
- srcRb, srcX, srcY, width, height);
- }
+ ctx->Driver.CopyTexSubImage(ctx, dims, texImage, dstX, dstY, dstZ,
+ srcRb, srcX, srcY, width, height);
+ }
- check_gen_mipmap(ctx, target, texObj, level);
+ check_gen_mipmap(ctx, target, texObj, level);
- _mesa_update_fbo_texture(ctx, texObj, face, level);
+ _mesa_update_fbo_texture(ctx, texObj, face, level);
- _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
- }
- else {
- /* probably too large of image */
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage%uD", dims);
- }
+ _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
}
}
_mesa_unlock_texture(ctx, texObj);