* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
#include "image.h"
#include "imports.h"
#include "macros.h"
-#include "mfeatures.h"
+#include "multisample.h"
#include "state.h"
#include "texcompress.h"
#include "texcompress_cpal.h"
#include "teximage.h"
#include "texobj.h"
#include "texstate.h"
+#include "texstorage.h"
#include "mtypes.h"
#include "glformats.h"
-/* Inexplicably, GL_HALF_FLOAT_OES has a different value than GL_HALF_FLOAT.
- */
-#ifndef GL_HALF_FLOAT_OES
-#define GL_HALF_FLOAT_OES 0x8D61
-#endif
-
/**
* State changes which we care about for glCopyTex[Sub]Image() calls.
* In particular, we care about pixel transfer state and buffer state
default:
; /* fallthrough */
}
-
+
if (ctx->Extensions.TDFX_texture_compression_FXT1) {
switch (internalFormat) {
case GL_COMPRESSED_RGB_FXT1_3DFX:
}
}
- if (ctx->Extensions.EXT_texture_compression_s3tc) {
+ /* Assume that the ANGLE flag will always be set if the EXT flag is set.
+ */
+ if (ctx->Extensions.ANGLE_texture_compression_dxt) {
switch (internalFormat) {
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
return GL_RGB;
}
}
- if (ctx->Extensions.S3_s3tc) {
+ if (_mesa_is_desktop_gl(ctx)
+ && ctx->Extensions.ANGLE_texture_compression_dxt) {
switch (internalFormat) {
case GL_RGB_S3TC:
case GL_RGB4_S3TC:
}
}
-#if FEATURE_EXT_texture_sRGB
if (ctx->Extensions.EXT_texture_sRGB) {
switch (internalFormat) {
case GL_SRGB_EXT:
case GL_SRGB8_EXT:
case GL_COMPRESSED_SRGB_EXT:
- case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
return GL_RGB;
+ case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+ return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGB : -1;
case GL_SRGB_ALPHA_EXT:
case GL_SRGB8_ALPHA8_EXT:
case GL_COMPRESSED_SRGB_ALPHA_EXT:
+ return GL_RGBA;
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
- return GL_RGBA;
+ return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGBA : -1;
case GL_SLUMINANCE_ALPHA_EXT:
case GL_SLUMINANCE8_ALPHA8_EXT:
case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
; /* fallthrough */
}
}
-#endif /* FEATURE_EXT_texture_sRGB */
if (ctx->Version >= 30 ||
ctx->Extensions.EXT_texture_integer) {
}
}
+ if (_mesa_is_gles3(ctx) || ctx->Extensions.ARB_ES3_compatibility) {
+ switch (internalFormat) {
+ case GL_COMPRESSED_RGB8_ETC2:
+ case GL_COMPRESSED_SRGB8_ETC2:
+ return GL_RGB;
+ case GL_COMPRESSED_RGBA8_ETC2_EAC:
+ case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+ case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+ return GL_RGBA;
+ case GL_COMPRESSED_R11_EAC:
+ case GL_COMPRESSED_SIGNED_R11_EAC:
+ return GL_RED;
+ case GL_COMPRESSED_RG11_EAC:
+ case GL_COMPRESSED_SIGNED_RG11_EAC:
+ return GL_RG;
+ default:
+ ; /* fallthrough */
+ }
+ }
+
if (ctx->API == API_OPENGLES) {
switch (internalFormat) {
case GL_PALETTE4_RGB8_OES:
/**
* Allocate a texture image structure.
- *
+ *
* Called via ctx->Driver.NewTextureImage() unless overriden by a device
* driver.
*
GLboolean
_mesa_is_proxy_texture(GLenum target)
{
+ unsigned i;
+ static const GLenum targets[] = {
+ GL_PROXY_TEXTURE_1D,
+ GL_PROXY_TEXTURE_2D,
+ GL_PROXY_TEXTURE_3D,
+ GL_PROXY_TEXTURE_CUBE_MAP,
+ GL_PROXY_TEXTURE_RECTANGLE,
+ GL_PROXY_TEXTURE_1D_ARRAY,
+ GL_PROXY_TEXTURE_2D_ARRAY,
+ GL_PROXY_TEXTURE_CUBE_MAP_ARRAY,
+ GL_PROXY_TEXTURE_2D_MULTISAMPLE,
+ GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY
+ };
/*
- * NUM_TEXTURE_TARGETS should match number of terms below, except there's no
+ * NUM_TEXTURE_TARGETS should match number of terms above, except there's no
* proxy for GL_TEXTURE_BUFFER and GL_TEXTURE_EXTERNAL_OES.
*/
- assert(NUM_TEXTURE_TARGETS == 7 + 2);
+ STATIC_ASSERT(NUM_TEXTURE_TARGETS == Elements(targets) + 2);
- return (target == GL_PROXY_TEXTURE_1D ||
- target == GL_PROXY_TEXTURE_2D ||
- target == GL_PROXY_TEXTURE_3D ||
- target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
- target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
- target == GL_PROXY_TEXTURE_1D_ARRAY_EXT ||
- target == GL_PROXY_TEXTURE_2D_ARRAY_EXT);
+ for (i = 0; i < Elements(targets); ++i)
+ if (target == targets[i])
+ return GL_TRUE;
+ return GL_FALSE;
}
case GL_TEXTURE_2D_ARRAY_EXT:
case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
return GL_PROXY_TEXTURE_2D_ARRAY_EXT;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ return GL_PROXY_TEXTURE_CUBE_MAP_ARRAY;
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ return GL_PROXY_TEXTURE_2D_MULTISAMPLE;
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ return GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY;
default:
_mesa_problem(NULL, "unexpected target in _mesa_get_proxy_target()");
return 0;
case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
return ctx->Extensions.ARB_texture_cube_map
? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ return ctx->Extensions.ARB_texture_cube_map_array
+ ? texUnit->CurrentTex[TEXTURE_CUBE_ARRAY_INDEX] : NULL;
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ return ctx->Extensions.ARB_texture_cube_map_array
+ ? ctx->Texture.ProxyTex[TEXTURE_CUBE_ARRAY_INDEX] : NULL;
case GL_TEXTURE_RECTANGLE_NV:
return ctx->Extensions.NV_texture_rectangle
? texUnit->CurrentTex[TEXTURE_RECT_INDEX] : NULL;
case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL;
case GL_TEXTURE_BUFFER:
- return _mesa_is_desktop_gl(ctx)
- && ctx->Extensions.ARB_texture_buffer_object
- ? texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL;
+ return ctx->API == API_OPENGL_CORE &&
+ ctx->Extensions.ARB_texture_buffer_object ?
+ texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL;
case GL_TEXTURE_EXTERNAL_OES:
- return ctx->Extensions.OES_EGL_image_external
+ return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
? texUnit->CurrentTex[TEXTURE_EXTERNAL_INDEX] : NULL;
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ return ctx->Extensions.ARB_texture_multisample
+ ? texUnit->CurrentTex[TEXTURE_2D_MULTISAMPLE_INDEX] : NULL;
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ return ctx->Extensions.ARB_texture_multisample
+ ? ctx->Texture.ProxyTex[TEXTURE_2D_MULTISAMPLE_INDEX] : NULL;
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ return ctx->Extensions.ARB_texture_multisample
+ ? texUnit->CurrentTex[TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX] : NULL;
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ return ctx->Extensions.ARB_texture_multisample
+ ? ctx->Texture.ProxyTex[TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX] : NULL;
default:
_mesa_problem(NULL, "bad target in _mesa_select_tex_object()");
return NULL;
if (!texObj)
return NULL;
-
+
texImage = _mesa_select_tex_image(ctx, texObj, target, level);
if (!texImage) {
texImage = ctx->Driver.NewTextureImage(ctx);
return NULL;
texIndex = TEXTURE_2D_ARRAY_INDEX;
break;
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ if (level >= ctx->Const.MaxCubeTextureLevels)
+ return NULL;
+ texIndex = TEXTURE_CUBE_ARRAY_INDEX;
+ break;
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ if (level > 0)
+ return 0;
+ texIndex = TEXTURE_2D_MULTISAMPLE_INDEX;
+ break;
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ if (level > 0)
+ return 0;
+ texIndex = TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX;
+ break;
default:
return NULL;
}
*
* \param ctx GL context.
* \param target texture target.
- *
+ *
* \return the maximum number of allowed mipmap levels for the given
* texture target, or zero if passed a bad target.
*
return (ctx->Extensions.MESA_texture_array ||
ctx->Extensions.EXT_texture_array)
? ctx->Const.MaxTextureLevels : 0;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ return ctx->Extensions.ARB_texture_cube_map_array
+ ? ctx->Const.MaxCubeTextureLevels : 0;
case GL_TEXTURE_BUFFER:
+ return ctx->API == API_OPENGL_CORE &&
+ ctx->Extensions.ARB_texture_buffer_object ? 1 : 0;
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
return _mesa_is_desktop_gl(ctx)
- && ctx->Extensions.ARB_texture_buffer_object
+ && ctx->Extensions.ARB_texture_multisample
? 1 : 0;
case GL_TEXTURE_EXTERNAL_OES:
/* fall-through */
case GL_TEXTURE_1D_ARRAY:
case GL_PROXY_TEXTURE_1D_ARRAY:
case GL_TEXTURE_EXTERNAL_OES:
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
return 2;
case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
case GL_TEXTURE_2D_ARRAY:
case GL_PROXY_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
return 3;
case GL_TEXTURE_BUFFER:
/* fall-through */
}
+/**
+ * Return the maximum number of mipmap levels for the given target
+ * and the dimensions.
+ * The dimensions are expected not to include the border.
+ */
+GLsizei
+_mesa_get_tex_max_num_levels(GLenum target, GLsizei width, GLsizei height,
+ GLsizei depth)
+{
+ GLsizei size;
+
+ switch (target) {
+ case GL_TEXTURE_1D:
+ case GL_TEXTURE_1D_ARRAY:
+ case GL_PROXY_TEXTURE_1D:
+ case GL_PROXY_TEXTURE_1D_ARRAY:
+ size = width;
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ size = width;
+ break;
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_2D_ARRAY:
+ case GL_PROXY_TEXTURE_2D:
+ case GL_PROXY_TEXTURE_2D_ARRAY:
+ size = MAX2(width, height);
+ break;
+ case GL_TEXTURE_3D:
+ case GL_PROXY_TEXTURE_3D:
+ size = MAX3(width, height, depth);
+ break;
+ case GL_TEXTURE_RECTANGLE:
+ case GL_TEXTURE_EXTERNAL_OES:
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_RECTANGLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ return 1;
+ default:
+ assert(0);
+ return 1;
+ }
+
+ return _mesa_logbase2(size) + 1;
+}
#if 000 /* not used anymore */
img->HeightLog2 = 0;
img->DepthLog2 = 0;
img->TexFormat = MESA_FORMAT_NONE;
+ img->NumSamples = 0;
+ img->FixedSampleLocations = GL_TRUE;
}
img->Width2 = width - 2 * border; /* == 1 << img->WidthLog2; */
img->WidthLog2 = _mesa_logbase2(img->Width2);
+ img->NumSamples = 0;
+ img->FixedSampleLocations = GL_TRUE;
+
switch(target) {
case GL_TEXTURE_1D:
case GL_TEXTURE_BUFFER:
case GL_PROXY_TEXTURE_2D:
case GL_PROXY_TEXTURE_RECTANGLE:
case GL_PROXY_TEXTURE_CUBE_MAP:
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
img->HeightLog2 = _mesa_logbase2(img->Height2);
if (depth == 0)
break;
case GL_TEXTURE_2D_ARRAY:
case GL_PROXY_TEXTURE_2D_ARRAY:
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
img->HeightLog2 = _mesa_logbase2(img->Height2);
img->Depth2 = depth; /* no border */
target);
}
- img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
+ img->MaxNumLevels =
+ _mesa_get_tex_max_num_levels(target,
+ img->Width2, img->Height2, img->Depth2);
img->TexFormat = format;
}
/**
- * This is the fallback for Driver.TestProxyTexImage(). Test the texture
- * level, width, height and depth against the ctx->Const limits for textures.
- *
- * A hardware driver might override this function if, for example, the
- * max 3D texture size is 512x512x64 (i.e. not a cube).
- *
- * Note that width, height, depth == 0 is not an error. However, a
- * 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 level as passed to glTexImage
- * \param internalFormat as passed to glTexImage
- * \param format as passed to glTexImage
- * \param type as passed to glTexImage
- * \param width as passed to glTexImage
- * \param height as passed to glTexImage
- * \param depth as passed to glTexImage
- * \param border as passed to glTexImage
- * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable.
+ * 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.
*/
GLboolean
-_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
- GLint internalFormat, GLenum format, GLenum type,
- GLint width, GLint height, GLint depth, GLint border)
+_mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target,
+ GLint level, GLint width, GLint height,
+ GLint depth, GLint border)
{
GLint maxSize;
- (void) internalFormat;
- (void) format;
- (void) type;
-
switch (target) {
+ case GL_TEXTURE_1D:
case GL_PROXY_TEXTURE_1D:
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1); /* level zero size */
maxSize >>= level; /* level size */
if (width < 2 * border || width > 2 * border + maxSize)
}
return GL_TRUE;
+ case GL_TEXTURE_2D:
case GL_PROXY_TEXTURE_2D:
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
maxSize >>= level;
if (width < 2 * border || width > 2 * border + maxSize)
}
return GL_TRUE;
+ case GL_TEXTURE_3D:
case GL_PROXY_TEXTURE_3D:
- if (level >= ctx->Const.Max3DTextureLevels)
- return GL_FALSE;
maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
maxSize >>= level;
if (width < 2 * border || width > 2 * border + maxSize)
}
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:
+ 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:
- if (level >= ctx->Const.MaxCubeTextureLevels)
- return GL_FALSE;
maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
maxSize >>= level;
+ if (width != height)
+ return GL_FALSE;
if (width < 2 * border || width > 2 * border + maxSize)
return GL_FALSE;
if (height < 2 * border || height > 2 * border + maxSize)
}
return GL_TRUE;
+ case GL_TEXTURE_1D_ARRAY_EXT:
case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
maxSize >>= level;
if (width < 2 * border || width > 2 * border + maxSize)
}
return GL_TRUE;
+ case GL_TEXTURE_2D_ARRAY_EXT:
case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
- if (level >= ctx->Const.MaxTextureLevels)
- return GL_FALSE;
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
maxSize >>= level;
if (width < 2 * border || width > 2 * border + maxSize)
}
return GL_TRUE;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
+ if (width < 2 * border || width > 2 * border + maxSize)
+ return GL_FALSE;
+ if (height < 2 * border || height > 2 * border + maxSize)
+ return GL_FALSE;
+ if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers || depth % 6)
+ return GL_FALSE;
+ if (width != height)
+ return GL_FALSE;
+ if (level >= ctx->Const.MaxCubeTextureLevels)
+ return GL_FALSE;
+ if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+ if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+ return GL_FALSE;
+ if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+ return GL_FALSE;
+ }
+ return GL_TRUE;
default:
- _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
+ _mesa_problem(ctx, "Invalid target in _mesa_legal_texture_dimensions()");
return GL_FALSE;
}
}
/**
- * 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.
+ * Do error checking of xoffset, yoffset, zoffset, width, height and depth
+ * for glTexSubImage, glCopyTexSubImage and glCompressedTexSubImage.
+ * \param destImage the destination texture image.
+ * \return GL_TRUE if error found, GL_FALSE otherwise.
*/
static GLboolean
-legal_texture_size(struct gl_context *ctx, gl_format format,
- GLint width, GLint height, GLint depth)
+error_check_subtexture_dimensions(struct gl_context *ctx,
+ const char *function, GLuint dims,
+ const struct gl_texture_image *destImage,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLsizei subWidth, GLsizei subHeight,
+ GLsizei subDepth)
+{
+ const GLenum target = destImage->TexObject->Target;
+ GLuint bw, bh;
+
+ /* Check size */
+ if (subWidth < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s%dD(width=%d)", function, dims, subWidth);
+ return GL_TRUE;
+ }
+
+ if (dims > 1 && subHeight < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s%dD(height=%d)", function, dims, subHeight);
+ return GL_TRUE;
+ }
+
+ if (dims > 2 && subDepth < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s%dD(depth=%d)", function, dims, subDepth);
+ return GL_TRUE;
+ }
+
+ /* check xoffset and width */
+ if (xoffset < - (GLint) destImage->Border) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset)",
+ function, dims);
+ return GL_TRUE;
+ }
+
+ if (xoffset + subWidth > (GLint) destImage->Width) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset+width)",
+ function, dims);
+ return GL_TRUE;
+ }
+
+ /* check yoffset and height */
+ if (dims > 1) {
+ GLint yBorder = (target == GL_TEXTURE_1D_ARRAY) ? 0 : destImage->Border;
+ if (yoffset < -yBorder) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset)",
+ function, dims);
+ return GL_TRUE;
+ }
+ if (yoffset + subHeight > (GLint) destImage->Height) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset+height)",
+ function, dims);
+ return GL_TRUE;
+ }
+ }
+
+ /* check zoffset and depth */
+ if (dims > 2) {
+ GLint zBorder = (target == GL_TEXTURE_2D_ARRAY) ? 0 : destImage->Border;
+ if (zoffset < -zBorder) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset)", function);
+ return GL_TRUE;
+ }
+ if (zoffset + subDepth > (GLint) destImage->Depth) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset+depth)", function);
+ return GL_TRUE;
+ }
+ }
+
+ /*
+ * The OpenGL spec (and GL_ARB_texture_compression) says only whole
+ * compressed texture images can be updated. But, that restriction may be
+ * relaxed for particular compressed formats. At this time, all the
+ * compressed formats supported by Mesa allow sub-textures to be updated
+ * along compressed block boundaries.
+ */
+ _mesa_get_format_block_size(destImage->TexFormat, &bw, &bh);
+
+ if (bw != 1 || bh != 1) {
+ /* offset must be multiple of block size */
+ if ((xoffset % bw != 0) || (yoffset % bh != 0)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s%dD(xoffset = %d, yoffset = %d)",
+ function, dims, xoffset, yoffset);
+ return GL_TRUE;
+ }
+
+ /* The size must be a multiple of bw x bh, or we must be using a
+ * offset+size that exactly hits the edge of the image. This
+ * is important for small mipmap levels (1x1, 2x1, etc) and for
+ * NPOT textures.
+ */
+ if ((subWidth % bw != 0) &&
+ (xoffset + subWidth != (GLint) destImage->Width)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s%dD(width = %d)", function, dims, subWidth);
+ return GL_TRUE;
+ }
+
+ if ((subHeight % bh != 0) &&
+ (yoffset + subHeight != (GLint) destImage->Height)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s%dD(height = %d)", function, dims, subHeight);
+ return GL_TRUE;
+ }
+ }
+
+ return GL_FALSE;
+}
+
+
+
+
+/**
+ * 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).
+ *
+ * Note that width, height, depth == 0 is not an error. However, a
+ * texture with zero width/height/depth will be considered "incomplete"
+ * and texturing will effectively be disabled.
+ *
+ * \param target any texture target/type
+ * \param level 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
+ * \param border as passed to glTexImage
+ * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable.
+ */
+GLboolean
+_mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
+ gl_format format,
+ GLint width, GLint height, GLint depth, GLint border)
{
+ /* 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 */
+ mbytes *= _mesa_num_tex_faces(target);
return mbytes <= (uint64_t) ctx->Const.MaxTextureMbytes;
}
case GL_TEXTURE_2D_ARRAY_EXT:
return (ctx->Extensions.MESA_texture_array ||
ctx->Extensions.EXT_texture_array);
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ return ctx->Extensions.ARB_texture_cube_map_array;
default:
return GL_FALSE;
- }
+ }
}
return _mesa_is_desktop_gl(ctx)
&& (ctx->Extensions.MESA_texture_array ||
ctx->Extensions.EXT_texture_array);
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ return ctx->Extensions.ARB_texture_cube_map_array;
default:
return GL_FALSE;
}
&& (ctx->Extensions.MESA_texture_array ||
ctx->Extensions.EXT_texture_array))
|| _mesa_is_gles3(ctx);
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
+ return ctx->Extensions.ARB_texture_cube_map_array;
default:
return GL_FALSE;
}
static GLboolean
mutable_tex_object(struct gl_context *ctx, GLenum target)
{
- if (ctx->Extensions.ARB_texture_storage) {
- struct gl_texture_object *texObj =
- _mesa_get_current_tex_object(ctx, target);
- return !texObj->Immutable;
- }
- return GL_TRUE;
-}
-
-
-GLenum
-_mesa_es_error_check_format_and_type(GLenum format, GLenum type,
- unsigned dimensions)
-{
- bool type_valid = true;
-
- switch (format) {
- case GL_ALPHA:
- case GL_LUMINANCE:
- case GL_LUMINANCE_ALPHA:
- type_valid = (type == GL_UNSIGNED_BYTE
- || type == GL_FLOAT
- || type == GL_HALF_FLOAT_OES);
- break;
-
- case GL_RGB:
- type_valid = (type == GL_UNSIGNED_BYTE
- || type == GL_UNSIGNED_SHORT_5_6_5
- || type == GL_FLOAT
- || type == GL_HALF_FLOAT_OES);
- break;
-
- case GL_RGBA:
- type_valid = (type == GL_UNSIGNED_BYTE
- || type == GL_UNSIGNED_SHORT_4_4_4_4
- || type == GL_UNSIGNED_SHORT_5_5_5_1
- || type == GL_FLOAT
- || type == GL_HALF_FLOAT_OES
- || type == GL_UNSIGNED_INT_2_10_10_10_REV);
- break;
-
- case GL_DEPTH_COMPONENT:
- /* This format is filtered against invalid dimensionalities elsewhere.
- */
- type_valid = (type == GL_UNSIGNED_SHORT
- || type == GL_UNSIGNED_INT);
- break;
-
- case GL_DEPTH_STENCIL:
- /* This format is filtered against invalid dimensionalities elsewhere.
- */
- type_valid = (type == GL_UNSIGNED_INT_24_8);
- break;
-
- case GL_BGRA_EXT:
- type_valid = (type == GL_UNSIGNED_BYTE);
-
- /* This feels like a bug in the EXT_texture_format_BGRA8888 spec, but
- * the format does not appear to be allowed for 3D textures in OpenGL
- * ES.
- */
- if (dimensions != 2)
- return GL_INVALID_VALUE;
-
- break;
-
- default:
- return GL_INVALID_VALUE;
- }
-
- return type_valid ? GL_NO_ERROR : GL_INVALID_OPERATION;
+ struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target);
+ return !texObj->Immutable;
}
-
/**
* Return expected size of a compressed texture.
*/
}
-/*
- * Return compressed texture block size, in pixels.
- */
-static void
-get_compressed_block_size(GLenum glformat, GLuint *bw, GLuint *bh)
-{
- gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat);
- _mesa_get_format_block_size(mesaFormat, bw, bh);
-}
-
-
-/**
- * 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 ctx GL context.
* \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
+ * \param target texture target given by the user (already validated).
* \param level image level given by the user.
* \param internalFormat internal format given by the user.
* \param format pixel data format given by the user.
* \param height image height given by the user.
* \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
* to the OpenGL specification.
+ * Note that we don't fully error-check the width, height, depth values
+ * here. That's done in _mesa_legal_texture_dimensions() which is used
+ * 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;
* zero-out behaviour is only used in cases related to memory allocation.
*/
- /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+ /* level check */
+ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glTexImage%dD(level=%d)", dimensions, level);
return GL_TRUE;
/* Check border */
if (border < 0 || border > 1 ||
- ((ctx->API != API_OPENGL ||
+ ((ctx->API != API_OPENGL_COMPAT ||
target == GL_TEXTURE_RECTANGLE_NV ||
target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
_mesa_error(ctx, GL_INVALID_VALUE,
* Formats and types that require additional extensions (e.g., GL_FLOAT
* requires GL_OES_texture_float) are filtered elsewhere.
*/
- if (_mesa_is_gles(ctx) && !_mesa_is_gles3(ctx)) {
- if (format != internalFormat) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%dD(format = %s, internalFormat = %s)",
- dimensions,
- _mesa_lookup_enum_by_nr(format),
- _mesa_lookup_enum_by_nr(internalFormat));
- return GL_TRUE;
- }
- err = _mesa_es_error_check_format_and_type(format, type, dimensions);
+ if (_mesa_is_gles(ctx)) {
+ if (_mesa_is_gles3(ctx)) {
+ err = _mesa_es3_error_check_format_and_type(format, type,
+ internalFormat);
+ } else {
+ if (format != internalFormat) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glTexImage%dD(format = %s, internalFormat = %s)",
+ dimensions,
+ _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(internalFormat));
+ return GL_TRUE;
+ }
+
+ err = _mesa_es_error_check_format_and_type(format, type, dimensions);
+ }
if (err != GL_NO_ERROR) {
_mesa_error(ctx, err,
- "glTexImage%dD(format = %s, type = %s)",
+ "glTexImage%dD(format = %s, type = %s, internalFormat = %s)",
dimensions,
_mesa_lookup_enum_by_nr(format),
- _mesa_lookup_enum_by_nr(type));
- return GL_TRUE;
- }
- }
-
- /* 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);
+ _mesa_lookup_enum_by_nr(type),
+ _mesa_lookup_enum_by_nr(internalFormat));
return GL_TRUE;
}
}
err = _mesa_error_check_format_and_type(ctx, format, type);
if (err != GL_NO_ERROR) {
_mesa_error(ctx, err,
- "glTexImage%dD(incompatible format 0x%x, type 0x%x)",
- dimensions, format, type);
+ "glTexImage%dD(incompatible format = %s, type = %s)",
+ dimensions, _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(type));
return GL_TRUE;
}
(_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) ||
(_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexImage%dD(incompatible internalFormat 0x%x, format 0x%x)",
- dimensions, internalFormat, format);
+ "glTexImage%dD(incompatible internalFormat = %s, format = %s)",
+ dimensions, _mesa_lookup_enum_by_nr(internalFormat),
+ _mesa_lookup_enum_by_nr(format));
return GL_TRUE;
}
}
/* additional checks for depth textures */
- if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) {
+ if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT
+ || _mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_STENCIL) {
/* Only 1D, 2D, rect, array and cube textures supported, not 3D
* Cubemaps are only supported for GL version > 3.0 or with EXT_gpu_shader4 */
if (target != GL_TEXTURE_1D &&
target != GL_TEXTURE_RECTANGLE_ARB &&
target != GL_PROXY_TEXTURE_RECTANGLE_ARB &&
!((_mesa_is_cube_face(target) || target == GL_PROXY_TEXTURE_CUBE_MAP) &&
- (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4))) {
+ (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4
+ || (ctx->API == API_OPENGLES2 && ctx->Extensions.OES_depth_texture_cube_map))) &&
+ !((target == GL_TEXTURE_CUBE_MAP_ARRAY ||
+ target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) &&
+ ctx->Extensions.ARB_texture_cube_map_array)) {
_mesa_error(ctx, GL_INVALID_ENUM,
"glTexImage%dD(bad target for depth texture)",
dimensions);
/**
* 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;
- GLenum choose_type;
- GLenum proxy_format;
GLenum error = GL_NO_ERROR;
char *reason = ""; /* no error */
}
switch (internalFormat) {
-#if FEATURE_ES
case GL_PALETTE4_RGB8_OES:
case GL_PALETTE4_RGBA8_OES:
case GL_PALETTE4_R5_G6_B5_OES:
case GL_PALETTE8_R5_G6_B5_OES:
case GL_PALETTE8_RGBA4_OES:
case GL_PALETTE8_RGB5_A1_OES:
- _mesa_cpal_compressed_format_type(internalFormat, &choose_format,
- &choose_type);
- proxy_format = choose_format;
-
/* check level (note that level should be zero or less!) */
if (level > 0 || level < -maxLevels) {
reason = "level";
*/
level = -level;
break;
-#endif
default:
- choose_format = GL_NONE;
- choose_type = GL_NONE;
- proxy_format = internalFormat;
-
/* check level */
if (level < 0 || level >= maxLevels) {
reason = "level";
goto error;
}
- /* For cube map, width must equal height */
- if (_mesa_is_cube_face(target) && width != height) {
- reason = "width != height";
- error = GL_INVALID_VALUE;
- goto error;
- }
-
- /* check image size against compression block size */
- {
- gl_format texFormat =
- ctx->Driver.ChooseTextureFormat(ctx, target, proxy_format,
- choose_format, choose_type);
- GLuint bw, bh;
-
- _mesa_get_format_block_size(texFormat, &bw, &bh);
- if ((width > bw && width % bw > 0) ||
- (height > bh && height % bh > 0)) {
- /*
- * Per GL_ARB_texture_compression: GL_INVALID_OPERATION is
- * generated [...] if any parameter combinations are not
- * supported by the specific compressed internal format.
- */
- reason = "invalid width or height for compression format";
- error = GL_INVALID_OPERATION;
- 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;
}
/**
* Test glTexSubImage[123]D() parameters for errors.
- *
+ *
* \param ctx GL context.
* \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
+ * \param target texture target given by the user (already validated)
* \param level image level given by the user.
* \param xoffset sub-image x offset given by the user.
* \param yoffset sub-image y offset given by the user.
* \param width image width given by the user.
* \param height image height given by the user.
* \param depth image depth given by the user.
- *
+ *
* \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
*
* Verifies each of the parameters against the constants specified in
* to the OpenGL specification.
*/
static GLboolean
-subtexture_error_check( struct gl_context *ctx, GLuint dimensions,
+texsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLint width, GLint height, GLint depth,
- GLenum format, GLenum type )
+ GLenum format, GLenum type)
{
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
GLenum err;
- /* Basic level check */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level);
+ /* check target (proxies not allowed) */
+ if (!legal_texsubimage_target(ctx, dimensions, target)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
+ dimensions, _mesa_lookup_enum_by_nr(target));
return GL_TRUE;
}
- /* Check for negative sizes */
- if (width < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexSubImage%dD(width=%d)", dimensions, width);
- return GL_TRUE;
- }
- if (height < 0 && dimensions > 1) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexSubImage%dD(height=%d)", dimensions, height);
- return GL_TRUE;
- }
- if (depth < 0 && dimensions > 2) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glTexSubImage%dD(depth=%d)", dimensions, depth);
+ /* level check */
+ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(level=%d)",
+ dimensions, level);
return GL_TRUE;
}
err = _mesa_error_check_format_and_type(ctx, format, type);
if (err != GL_NO_ERROR) {
_mesa_error(ctx, err,
- "glTexSubImage%dD(incompatible format 0x%x, type 0x%x)",
- dimensions, format, type);
+ "glTexSubImage%dD(incompatible format = %s, type = %s)",
+ dimensions, _mesa_lookup_enum_by_nr(format),
+ _mesa_lookup_enum_by_nr(type));
return GL_TRUE;
}
- return GL_FALSE;
-}
-
-
-/**
- * Do second part of glTexSubImage which depends on the destination texture.
- * \return GL_TRUE if error recorded, GL_FALSE otherwise
- */
-static GLboolean
-subtexture_error_check2( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLint width, GLint height, GLint depth,
- GLenum format, GLenum type,
- const struct gl_texture_image *destTex )
-{
- if (!destTex) {
- /* undefined image level */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions);
+ /* Get dest texture object / image pointers */
+ texObj = _mesa_get_current_tex_object(ctx, target);
+ if (!texObj) {
+ /* must be out of memory */
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage%dD()", dimensions);
return GL_TRUE;
}
- if (xoffset < -((GLint)destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset)",
- dimensions);
+ texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+ if (!texImage) {
+ /* non-existant texture level */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glTexSubImage%dD(invalid texture image)", dimensions);
return GL_TRUE;
}
- if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset+width)",
- dimensions);
+
+ if (error_check_subtexture_dimensions(ctx, "glTexSubImage", dimensions,
+ texImage, xoffset, yoffset, 0,
+ width, height, 1)) {
return GL_TRUE;
}
- if (dimensions > 1) {
- GLint yBorder = (target == GL_TEXTURE_1D_ARRAY) ? 0 : destTex->Border;
- if (yoffset < -yBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset)",
- dimensions);
- return GL_TRUE;
- }
- if (yoffset + height > (GLint) destTex->Height + yBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset+height)",
- dimensions);
- return GL_TRUE;
- }
- }
- if (dimensions > 2) {
- GLint zBorder = (target == GL_TEXTURE_2D_ARRAY) ? 0 : destTex->Border;
- if (zoffset < -zBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)");
- return GL_TRUE;
- }
- if (zoffset + depth > (GLint) destTex->Depth + zBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)");
- return GL_TRUE;
- }
- }
-
- if (_mesa_is_format_compressed(destTex->TexFormat)) {
- GLuint bw, bh;
- if (compressedteximage_only_format(ctx, destTex->InternalFormat)) {
+ if (_mesa_is_format_compressed(texImage->TexFormat)) {
+ if (compressedteximage_only_format(ctx, texImage->InternalFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glTexSubImage%dD(no compression for format)", dimensions);
return GL_TRUE;
}
-
- /* do tests which depend on compression block size */
- _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh);
-
- /* offset must be multiple of block size */
- if ((xoffset % bw != 0) || (yoffset % bh != 0)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexSubImage%dD(xoffset = %d, yoffset = %d)",
- dimensions, xoffset, yoffset);
- return GL_TRUE;
- }
- /* size must be multiple of bw by bh or equal to whole texture size */
- if ((width % bw != 0) && (GLuint) width != destTex->Width) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexSubImage%dD(width = %d)", dimensions, width);
- return GL_TRUE;
- }
- if ((height % bh != 0) && (GLuint) height != destTex->Height) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glTexSubImage%dD(height = %d)", dimensions, height);
- return GL_TRUE;
- }
}
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(destTex->TexFormat) !=
+ if (_mesa_is_format_integer_color(texImage->TexFormat) !=
_mesa_is_enum_format_integer(format)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glTexSubImage%dD(integer/non-integer format mismatch)",
/**
* Test glCopyTexImage[12]D() parameters for errors.
- *
+ *
* \param ctx GL context.
* \param dimensions texture image dimensions (must be 1, 2 or 3).
* \param target texture target given by the user.
* \param width image width given by the user.
* \param height image height given by the user.
* \param border texture border.
- *
+ *
* \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
- *
+ *
* Verifies each of the parameters against the constants specified in
* __struct gl_contextRec::Const and the supported extensions, and according
* to the OpenGL specification.
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;
+ GLint rb_base_format;
+ struct gl_renderbuffer *rb;
+ GLenum rb_internal_format;
/* check target */
if (!legal_texsubimage_target(ctx, dimensions, target)) {
_mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)",
dimensions, _mesa_lookup_enum_by_nr(target));
return GL_TRUE;
- }
+ }
- /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+ /* level check */
+ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyTexImage%dD(level=%d)", dimensions, level);
return GL_TRUE;
/* Check border */
if (border < 0 || border > 1 ||
- ((ctx->API != API_OPENGL ||
+ ((ctx->API != API_OPENGL_COMPAT ||
target == GL_TEXTURE_RECTANGLE_NV ||
target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
_mesa_error(ctx, GL_INVALID_VALUE,
return GL_TRUE;
}
+ rb = _mesa_get_read_renderbuffer_for_format(ctx, internalFormat);
+ if (rb == NULL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyTexImage%dD(read buffer)", dimensions);
+ return GL_TRUE;
+ }
+
/* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
* internalFormat.
*/
baseFormat = _mesa_base_tex_format(ctx, internalFormat);
if (baseFormat < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
+ _mesa_error(ctx, GL_INVALID_OPERATION,
"glCopyTexImage%dD(internalFormat)", dimensions);
return GL_TRUE;
}
+ rb_internal_format = rb->InternalFormat;
+ rb_base_format = _mesa_base_tex_format(ctx, rb->InternalFormat);
+ if (_mesa_is_color_format(internalFormat)) {
+ if (rb_base_format < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCopyTexImage%dD(internalFormat)", dimensions);
+ return GL_TRUE;
+ }
+ }
+
+ if (_mesa_is_gles(ctx)) {
+ bool valid = true;
+ if (_mesa_base_format_component_count(baseFormat) >
+ _mesa_base_format_component_count(rb_base_format)) {
+ valid = false;
+ }
+ if (baseFormat == GL_DEPTH_COMPONENT ||
+ baseFormat == GL_DEPTH_STENCIL ||
+ rb_base_format == GL_DEPTH_COMPONENT ||
+ rb_base_format == GL_DEPTH_STENCIL ||
+ ((baseFormat == GL_LUMINANCE_ALPHA ||
+ baseFormat == GL_ALPHA) &&
+ rb_base_format != GL_RGBA) ||
+ internalFormat == GL_RGB9_E5) {
+ valid = false;
+ }
+ if (internalFormat == GL_RGB9_E5) {
+ valid = false;
+ }
+ if (!valid) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyTexImage%dD(internalFormat)", dimensions);
+ return GL_TRUE;
+ }
+ }
+
+ if (_mesa_is_gles3(ctx)) {
+ bool rb_is_srgb = false;
+ bool dst_is_srgb = false;
+
+ if (ctx->Extensions.EXT_framebuffer_sRGB &&
+ _mesa_get_format_color_encoding(rb->Format) == GL_SRGB) {
+ rb_is_srgb = true;
+ }
+
+ if (_mesa_get_linear_internalformat(internalFormat) != internalFormat) {
+ dst_is_srgb = true;
+ }
+
+ if (rb_is_srgb != dst_is_srgb) {
+ /* Page 137 (page 149 of the PDF) in section 3.8.5 of the
+ * OpenGLES 3.0.0 spec says:
+ *
+ * "The error INVALID_OPERATION is also generated if the
+ * value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the
+ * framebuffer attachment corresponding to the read buffer
+ * is LINEAR (see section 6.1.13) and internalformat is
+ * one of the sRGB formats described in section 3.8.16, or
+ * if the value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING is
+ * SRGB and internalformat is not one of the sRGB formats."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyTexImage%dD(srgb usage mismatch)", dimensions);
+ return GL_TRUE;
+ }
+ }
+
if (!_mesa_source_buffer_exists(ctx, baseFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glCopyTexImage%dD(missing readbuffer)", dimensions);
* integer format and the read color buffer is an integer format."
*/
if (_mesa_is_color_format(internalFormat)) {
- struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
-
- if (_mesa_is_enum_format_integer(rb->InternalFormat) !=
- _mesa_is_enum_format_integer(internalFormat)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexImage%dD(integer vs non-integer)", dimensions);
- return GL_TRUE;
- }
- }
-
- /* 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);
+ bool is_int = _mesa_is_enum_format_integer(internalFormat);
+ bool is_rbint = _mesa_is_enum_format_integer(rb_internal_format);
+ if (is_int || is_rbint) {
+ if (is_int != is_rbint) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyTexImage%dD(integer vs non-integer)", dimensions);
+ return GL_TRUE;
+ } else if (_mesa_is_gles(ctx) &&
+ _mesa_is_enum_format_unsigned_int(internalFormat) !=
+ _mesa_is_enum_format_unsigned_int(rb_internal_format)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyTexImage%dD(signed vs unsigned integer)", dimensions);
+ return GL_TRUE;
+ }
}
- return GL_TRUE;
}
if (_mesa_is_compressed_format(ctx, internalFormat)) {
/**
* Test glCopyTexSubImage[12]D() parameters for errors.
- * Note that this is the first part of error checking.
- * See also copytexsubimage_error_check2() below for the second part.
- *
- * \param ctx GL context.
- * \param dimensions texture image dimensions (must be 1, 2 or 3).
- * \param target texture target given by the user.
- * \param level image level given by the user.
- *
* \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
*/
static GLboolean
-copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level)
+copytexsubimage_error_check(struct gl_context *ctx, GLuint dimensions,
+ GLenum target, GLint level,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ GLint width, GLint height)
{
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+
/* Check that the source buffer is complete */
if (_mesa_is_user_fbo(ctx->ReadBuffer)) {
if (ctx->ReadBuffer->_Status == 0) {
}
/* Check level */
- if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
+ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
_mesa_error(ctx, GL_INVALID_VALUE,
"glCopyTexSubImage%dD(level=%d)", dimensions, level);
return GL_TRUE;
}
- return GL_FALSE;
-}
-
-
-/**
- * Second part of error checking for glCopyTexSubImage[12]D().
- * \param xoffset sub-image x offset given by the user.
- * \param yoffset sub-image y offset given by the user.
- * \param zoffset sub-image z offset given by the user.
- * \param width image width given by the user.
- * \param height image height given by the user.
- */
-static GLboolean
-copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions,
- GLenum target, GLint level,
- GLint xoffset, GLint yoffset, GLint zoffset,
- GLsizei width, GLsizei height,
- const struct gl_texture_image *teximage )
-{
- /* check that dest tex image exists */
- if (!teximage) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glCopyTexSubImage%dD(undefined texture level: %d)",
- dimensions, level);
+ /* Get dest texture object / image pointers */
+ texObj = _mesa_get_current_tex_object(ctx, target);
+ if (!texObj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexSubImage%dD()", dimensions);
return GL_TRUE;
}
- /* Check size */
- if (width < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(width=%d)", dimensions, width);
- return GL_TRUE;
- }
- if (dimensions > 1 && height < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(height=%d)", dimensions, height);
+ texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+ if (!texImage) {
+ /* destination image does not exist */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCopyTexSubImage%dD(invalid texture image)", dimensions);
return GL_TRUE;
}
- /* check x/y offsets */
- if (xoffset < -((GLint)teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(xoffset=%d)", dimensions, xoffset);
+ if (error_check_subtexture_dimensions(ctx, "glCopyTexSubImage",
+ dimensions, texImage,
+ xoffset, yoffset, zoffset,
+ width, height, 1)) {
return GL_TRUE;
}
- if (xoffset + width > (GLint) (teximage->Width + teximage->Border)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(xoffset+width)", dimensions);
- return GL_TRUE;
- }
- if (dimensions > 1) {
- GLint yBorder = (target == GL_TEXTURE_1D_ARRAY) ? 0 : teximage->Border;
- if (yoffset < -yBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(yoffset=%d)", dimensions, yoffset);
- return GL_TRUE;
- }
- /* NOTE: we're adding the border here, not subtracting! */
- if (yoffset + height > (GLint) teximage->Height + yBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(yoffset+height)", dimensions);
- return GL_TRUE;
- }
- }
-
- /* check z offset */
- if (dimensions > 2) {
- GLint zBorder = (target == GL_TEXTURE_2D_ARRAY) ? 0 : teximage->Border;
- if (zoffset < -zBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(zoffset)", dimensions);
- return GL_TRUE;
- }
- if (zoffset > (GLint) teximage->Depth + zBorder) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(zoffset+depth)", dimensions);
- return GL_TRUE;
- }
- }
- if (_mesa_is_format_compressed(teximage->TexFormat)) {
- if (compressedteximage_only_format(ctx, teximage->InternalFormat)) {
+ if (_mesa_is_format_compressed(texImage->TexFormat)) {
+ if (compressedteximage_only_format(ctx, texImage->InternalFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glCopyTexSubImage%dD(no compression for format)", dimensions);
return GL_TRUE;
}
- /* offset must be multiple of 4 */
- if ((xoffset & 3) || (yoffset & 3)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(xoffset or yoffset)", dimensions);
- return GL_TRUE;
- }
- /* size must be multiple of 4 */
- if ((width & 3) != 0 && (GLuint) width != teximage->Width) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(width)", dimensions);
- return GL_TRUE;
- }
- if ((height & 3) != 0 && (GLuint) height != teximage->Height) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCopyTexSubImage%dD(height)", dimensions);
- return GL_TRUE;
- }
}
- if (teximage->InternalFormat == GL_YCBCR_MESA) {
+ if (texImage->InternalFormat == GL_YCBCR_MESA) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D");
return GL_TRUE;
}
- if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) {
+ if (!_mesa_source_buffer_exists(ctx, texImage->_BaseFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glCopyTexSubImage%dD(missing readbuffer, format=0x%x)",
- dimensions, teximage->_BaseFormat);
+ dimensions, texImage->_BaseFormat);
return GL_TRUE;
}
* buffer is not an integer format, or if the internalformat is not an
* integer format and the read color buffer is an integer format."
*/
- if (_mesa_is_color_format(teximage->InternalFormat)) {
+ if (_mesa_is_color_format(texImage->InternalFormat)) {
struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
if (_mesa_is_format_integer_color(rb->Format) !=
- _mesa_is_format_integer_color(teximage->TexFormat)) {
+ _mesa_is_format_integer_color(texImage->TexFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glCopyTexImage%dD(integer vs non-integer)", dimensions);
return GL_TRUE;
att->Texture == texObj &&
att->TextureLevel == level &&
att->CubeMapFace == face) {
- ASSERT(_mesa_get_attachment_teximage(att));
- /* Tell driver about the new renderbuffer texture */
- ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
+ _mesa_update_texture_renderbuffer(ctx, ctx->DrawBuffer, att);
+ ASSERT(att->Renderbuffer->TexImage);
/* Mark fb status as indeterminate to force re-validation */
fb->_Status = 0;
}
/* If the application requested compression to an S3TC format but we don't
* have the DTXn library, force a generic compressed format instead.
*/
- if (internalFormat != format) {
+ if (internalFormat != format && format != GL_NONE) {
const GLenum before = internalFormat;
switch (internalFormat) {
return f;
}
+
/**
* Adjust pixel unpack params and image dimensions to strip off the
* one-pixel texture border.
*height = *height - 2; /* reduce the height by two border pixels */
}
- if (*depth >= 3 && target != GL_TEXTURE_2D_ARRAY) {
+ if (*depth >= 3 &&
+ target != GL_TEXTURE_2D_ARRAY &&
+ target != GL_TEXTURE_CUBE_MAP_ARRAY) {
unpackNew->SkipImages++; /* skip the border */
*depth = *depth - 2; /* reduce the depth by two border pixels */
}
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);
+ FLUSH_VERTICES(ctx, 0);
if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) {
if (compressed)
/* 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);
+
+ if (compressed) {
+ /* For glCompressedTexImage() the driver has no choice about the
+ * texture format since we'll never transcode the user's compressed
+ * image data. The internalFormat was error checked earlier.
+ */
+ texFormat = _mesa_glenum_to_compressed_format(internalFormat);
+ }
+ else {
+ 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);
+ _mesa_init_teximage_fields(ctx, texImage,
+ width, height, depth,
+ border, internalFormat, texFormat);
- /* Give the texture to the driver. <pixels> may be null. */
+ /* Give the texture to the driver. <pixels> may be null. */
+ if (width > 0 && height > 0 && depth > 0) {
if (compressed) {
ctx->Driver.CompressedTexImage(ctx, dims, texImage,
imageSize, pixels);
ctx->Driver.TexImage(ctx, dims, texImage, format,
type, pixels, unpack);
}
+ }
- 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 {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s%uD", func, dims);
- }
+ _mesa_dirty_texobj(ctx, texObj);
}
}
_mesa_unlock_texture(ctx, texObj);
}
+
/*
* Called from the API. Note that width includes the border.
*/
}
-#if FEATURE_OES_EGL_image
void GLAPIENTRY
_mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
{
struct gl_texture_image *texImage;
bool valid_target;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ FLUSH_VERTICES(ctx, 0);
switch (target) {
case GL_TEXTURE_2D:
valid_target = ctx->Extensions.OES_EGL_image;
break;
case GL_TEXTURE_EXTERNAL_OES:
- valid_target = ctx->Extensions.OES_EGL_image_external;
+ valid_target =
+ _mesa_is_gles(ctx) ? ctx->Extensions.OES_EGL_image_external : false;
break;
default:
valid_target = false;
return;
}
+ if (!image) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEGLImageTargetTexture2D(image=%p)", image);
+ return;
+ }
+
if (ctx->NewState & _NEW_PIXEL)
_mesa_update_state(ctx);
ctx->Driver.EGLImageTargetTexture2D(ctx, target,
texObj, texImage, image);
- _mesa_dirty_texobj(ctx, texObj, GL_TRUE);
+ _mesa_dirty_texobj(ctx, texObj);
}
_mesa_unlock_texture(ctx, texObj);
}
-#endif
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ FLUSH_VERTICES(ctx, 0);
if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
_mesa_debug(ctx, "glTexSubImage%uD %s %d %d %d %d %d %d %d %s %s %p\n",
_mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
dims, _mesa_lookup_enum_by_nr(target));
return;
- }
+ }
if (ctx->NewState & _NEW_PIXEL)
_mesa_update_state(ctx);
- if (subtexture_error_check(ctx, dims, target, level, xoffset, yoffset, zoffset,
- width, height, depth, format, type)) {
+ if (texsubimage_error_check(ctx, dims, target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth, format, type)) {
return; /* error was detected */
}
{
texImage = _mesa_select_tex_image(ctx, texObj, target, level);
- if (subtexture_error_check2(ctx, dims, target, level,
- xoffset, yoffset, zoffset,
- width, height, depth,
- format, type, texImage)) {
- /* error was recorded */
- }
- else if (width > 0 && height > 0 && depth > 0) {
+ if (width > 0 && height > 0 && depth > 0) {
/* If we have a border, offset=-1 is legal. Bias by border width. */
switch (dims) {
case 3:
}
}
+static void
+copytexsubimage_by_slice(struct gl_context *ctx,
+ struct gl_texture_image *texImage,
+ GLuint dims,
+ GLint xoffset, GLint yoffset, GLint zoffset,
+ struct gl_renderbuffer *rb,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height)
+{
+ if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
+ int slice;
+
+ /* For 1D arrays, we copy each scanline of the source rectangle into the
+ * next array slice.
+ */
+ assert(zoffset == 0);
+
+ for (slice = 0; slice < height; slice++) {
+ assert(yoffset + slice < texImage->Height);
+ ctx->Driver.CopyTexSubImage(ctx, 2, texImage,
+ xoffset, 0, yoffset + slice,
+ rb, x, y + slice, width, 1);
+ }
+ } else {
+ ctx->Driver.CopyTexSubImage(ctx, dims, texImage,
+ xoffset, yoffset, zoffset,
+ rb, x, y, width, height);
+ }
+}
/**
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);
+ FLUSH_VERTICES(ctx, 0);
if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
_mesa_debug(ctx, "glCopyTexImage%uD %s %d %s %d %d %d %d %d\n",
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);
+ GLint srcX = x, srcY = y, dstX = 0, dstY = 0, dstZ = 0;
- if (legal_texture_size(ctx, texFormat, width, height, 1)) {
- 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);
+ if (width && height) {
/* Allocate texture memory (no pixel data yet) */
- ctx->Driver.TexImage(ctx, dims, texImage,
- GL_NONE, GL_NONE,
- NULL, &ctx->Unpack);
+ ctx->Driver.AllocTextureImageBuffer(ctx, texImage);
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);
+ copytexsubimage_by_slice(ctx, texImage, dims,
+ dstX, dstY, dstZ,
+ srcRb, srcX, srcY, width, height);
}
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);
}
}
_mesa_unlock_texture(ctx, texObj);
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
+ FLUSH_VERTICES(ctx, 0);
if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
_mesa_debug(ctx, "glCopyTexSubImage%uD %s %d %d %d %d %d %d %d %d\n",
if (ctx->NewState & NEW_COPY_TEX_STATE)
_mesa_update_state(ctx);
- if (copytexsubimage_error_check1(ctx, dims, target, level))
+ if (copytexsubimage_error_check(ctx, dims, target, level,
+ xoffset, yoffset, zoffset, width, height)) {
return;
+ }
texObj = _mesa_get_current_tex_object(ctx, target);
{
texImage = _mesa_select_tex_image(ctx, texObj, target, level);
- if (copytexsubimage_error_check2(ctx, dims, target, level, xoffset, yoffset,
- zoffset, width, height, texImage)) {
- /* error was recored */
+ /* If we have a border, offset=-1 is legal. Bias by border width. */
+ switch (dims) {
+ case 3:
+ if (target != GL_TEXTURE_2D_ARRAY)
+ zoffset += texImage->Border;
+ /* fall-through */
+ case 2:
+ if (target != GL_TEXTURE_1D_ARRAY)
+ yoffset += texImage->Border;
+ /* fall-through */
+ case 1:
+ xoffset += texImage->Border;
}
- else {
- /* If we have a border, offset=-1 is legal. Bias by border width. */
- switch (dims) {
- case 3:
- if (target != GL_TEXTURE_2D_ARRAY)
- zoffset += texImage->Border;
- /* fall-through */
- case 2:
- if (target != GL_TEXTURE_1D_ARRAY)
- yoffset += texImage->Border;
- /* fall-through */
- case 1:
- xoffset += texImage->Border;
- }
- if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
- &width, &height)) {
- struct gl_renderbuffer *srcRb =
- get_copy_tex_image_source(ctx, texImage->TexFormat);
+ if (_mesa_clip_copytexsubimage(ctx, &xoffset, &yoffset, &x, &y,
+ &width, &height)) {
+ struct gl_renderbuffer *srcRb =
+ get_copy_tex_image_source(ctx, texImage->TexFormat);
- ctx->Driver.CopyTexSubImage(ctx, dims, texImage,
- xoffset, yoffset, zoffset,
- srcRb, x, y, width, height);
+ copytexsubimage_by_slice(ctx, texImage, dims,
+ xoffset, yoffset, zoffset,
+ srcRb, x, y, width, height);
- check_gen_mipmap(ctx, target, texObj, level);
+ check_gen_mipmap(ctx, target, texObj, level);
- ctx->NewState |= _NEW_TEXTURE;
- }
+ ctx->NewState |= _NEW_TEXTURE;
}
}
_mesa_unlock_texture(ctx, texObj);
/**
* Error checking for glCompressedTexSubImage[123]D().
- * \warning There are some bad assumptions here about the size of compressed
- * texture tiles (multiple of 4) used to test the validity of the
- * offset and size parameters.
* \return error code or GL_NO_ERROR.
*/
static GLenum
-compressed_subtexture_error_check(struct gl_context *ctx, GLint dimensions,
+compressed_subtexture_error_check(struct gl_context *ctx, GLint dims,
GLenum target, GLint level,
GLint xoffset, GLint yoffset, GLint zoffset,
GLsizei width, GLsizei height, GLsizei depth,
GLenum format, GLsizei imageSize)
{
- GLint expectedSize, maxLevels = 0, maxTextureSize;
- GLuint bw, bh;
- (void) zoffset;
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+ GLint expectedSize;
+ GLboolean targetOK;
- if (dimensions == 1) {
- /* 1D compressed textures not allowed */
- return GL_INVALID_ENUM;
- }
- else if (dimensions == 2) {
- if (target == GL_PROXY_TEXTURE_2D) {
- maxLevels = ctx->Const.MaxTextureLevels;
- }
- else if (target == GL_TEXTURE_2D) {
- maxLevels = ctx->Const.MaxTextureLevels;
- }
- else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
- if (!ctx->Extensions.ARB_texture_cube_map)
- return GL_INVALID_ENUM; /*target*/
- maxLevels = ctx->Const.MaxCubeTextureLevels;
- }
- else if (_mesa_is_cube_face(target)) {
- if (!ctx->Extensions.ARB_texture_cube_map)
- return GL_INVALID_ENUM; /*target*/
- maxLevels = ctx->Const.MaxCubeTextureLevels;
- }
- else {
- return GL_INVALID_ENUM; /*target*/
+ switch (dims) {
+ case 2:
+ switch (target) {
+ case GL_TEXTURE_2D:
+ 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:
+ targetOK = GL_TRUE;
+ break;
+ default:
+ targetOK = GL_FALSE;
+ break;
}
- }
- else if (dimensions == 3) {
- /* 3D compressed textures not allowed */
- return GL_INVALID_ENUM;
+ break;
+ case 3:
+ targetOK = (target == GL_TEXTURE_2D_ARRAY);
+ break;
+ default:
+ assert(dims == 1);
+ /* no 1D compressed textures at this time */
+ targetOK = GL_FALSE;
+ break;
}
- maxTextureSize = 1 << (maxLevels - 1);
+ if (!targetOK) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target)",
+ dims);
+ return GL_TRUE;
+ }
/* this will catch any invalid compressed format token */
- if (!_mesa_is_compressed_format(ctx, format))
- return GL_INVALID_ENUM;
-
- if (width < 1 || width > maxTextureSize)
- return GL_INVALID_VALUE;
-
- if ((height < 1 || height > maxTextureSize)
- && dimensions > 1)
- return GL_INVALID_VALUE;
-
- if (level < 0 || level >= maxLevels)
- return GL_INVALID_VALUE;
-
- /*
- * do checks which depend on compression block size
- */
- get_compressed_block_size(format, &bw, &bh);
-
- if ((xoffset % bw != 0) || (yoffset % bh != 0))
- return GL_INVALID_VALUE;
-
- if ((width % bw != 0) && width != 2 && width != 1)
- return GL_INVALID_VALUE;
+ if (!_mesa_is_compressed_format(ctx, format)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(format)",
+ dims);
+ return GL_TRUE;
+ }
- if ((height % bh != 0) && height != 2 && height != 1)
- return GL_INVALID_VALUE;
+ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(level=%d)",
+ dims, level);
+ return GL_TRUE;
+ }
expectedSize = compressed_tex_size(width, height, depth, format);
- if (expectedSize != imageSize)
- return GL_INVALID_VALUE;
-
- return GL_NO_ERROR;
-}
+ if (expectedSize != imageSize) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(size=%d)",
+ dims, imageSize);
+ return GL_TRUE;
+ }
+ texObj = _mesa_get_current_tex_object(ctx, target);
+ if (!texObj) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "glCompressedTexSubImage%uD()", dims);
+ return GL_TRUE;
+ }
-/**
- * Do second part of glCompressedTexSubImage error checking.
- * \return GL_TRUE if error found, GL_FALSE otherwise.
- */
-static GLboolean
-compressed_subtexture_error_check2(struct gl_context *ctx, GLuint dims,
- GLsizei width, GLsizei height,
- GLsizei depth, GLenum format,
- struct gl_texture_image *texImage)
-{
+ texImage = _mesa_select_tex_image(ctx, texObj, target, level);
+ if (!texImage) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glCompressedTexSubImage%uD(invalid texture image)", dims);
+ return GL_TRUE;
+ }
if ((GLint) format != texImage->InternalFormat) {
_mesa_error(ctx, GL_INVALID_OPERATION,
return GL_TRUE;
}
- if (((width == 1 || width == 2) &&
- width != (GLsizei) texImage->Width) ||
- (width > (GLsizei) texImage->Width)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCompressedTexSubImage%uD(width=%d)", dims, width);
+ if (error_check_subtexture_dimensions(ctx, "glCompressedTexSubImage", dims,
+ texImage, xoffset, yoffset, zoffset,
+ width, height, depth)) {
return GL_TRUE;
}
- if (dims >= 2) {
- if (((height == 1 || height == 2) &&
- height != (GLsizei) texImage->Height) ||
- (height > (GLsizei) texImage->Height)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCompressedTexSubImage%uD(height=%d)", dims, height);
- return GL_TRUE;
- }
- }
-
- if (dims >= 3) {
- if (((depth == 1 || depth == 2) &&
- depth != (GLsizei) texImage->Depth) ||
- (depth > (GLsizei) texImage->Depth)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glCompressedTexSubImage%uD(depth=%d)", dims, depth);
- return GL_TRUE;
- }
- }
-
return GL_FALSE;
}
void GLAPIENTRY
-_mesa_CompressedTexImage1DARB(GLenum target, GLint level,
+_mesa_CompressedTexImage1D(GLenum target, GLint level,
GLenum internalFormat, GLsizei width,
GLint border, GLsizei imageSize,
const GLvoid *data)
void GLAPIENTRY
-_mesa_CompressedTexImage2DARB(GLenum target, GLint level,
+_mesa_CompressedTexImage2D(GLenum target, GLint level,
GLenum internalFormat, GLsizei width,
GLsizei height, GLint border, GLsizei imageSize,
const GLvoid *data)
void GLAPIENTRY
-_mesa_CompressedTexImage3DARB(GLenum target, GLint level,
+_mesa_CompressedTexImage3D(GLenum target, GLint level,
GLenum internalFormat, GLsizei width,
GLsizei height, GLsizei depth, GLint border,
GLsizei imageSize, const GLvoid *data)
{
struct gl_texture_object *texObj;
struct gl_texture_image *texImage;
- GLenum error;
GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- error = compressed_subtexture_error_check(ctx, dims, target, level,
- xoffset, 0, 0, /* pos */
- width, height, depth, /* size */
- format, imageSize);
- if (error) {
- _mesa_error(ctx, error, "glCompressedTexSubImage%uD", dims);
+ FLUSH_VERTICES(ctx, 0);
+
+ if (compressed_subtexture_error_check(ctx, dims, target, level,
+ xoffset, yoffset, zoffset,
+ width, height, depth,
+ format, imageSize)) {
return;
}
texImage = _mesa_select_tex_image(ctx, texObj, target, level);
assert(texImage);
- if (compressed_subtexture_error_check2(ctx, dims, width, height, depth,
- format, texImage)) {
- /* error was recorded */
- }
- else if (width > 0 && height > 0 && depth > 0) {
+ if (width > 0 && height > 0 && depth > 0) {
ctx->Driver.CompressedTexSubImage(ctx, dims, texImage,
xoffset, yoffset, zoffset,
width, height, depth,
void GLAPIENTRY
-_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
+_mesa_CompressedTexSubImage1D(GLenum target, GLint level, GLint xoffset,
GLsizei width, GLenum format,
GLsizei imageSize, const GLvoid *data)
{
void GLAPIENTRY
-_mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
+_mesa_CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLsizei width, GLsizei height,
GLenum format, GLsizei imageSize,
const GLvoid *data)
void GLAPIENTRY
-_mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
+_mesa_CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset,
GLint yoffset, GLint zoffset, GLsizei width,
GLsizei height, GLsizei depth, GLenum format,
GLsizei imageSize, const GLvoid *data)
case GL_RG8:
return MESA_FORMAT_GR88;
case GL_RG16:
- return MESA_FORMAT_RG1616;
+ return MESA_FORMAT_GR1616;
case GL_RG16F:
return MESA_FORMAT_RG_FLOAT16;
case GL_RG32F:
case GL_R32UI:
return MESA_FORMAT_R_UINT32;
+ case GL_RGB32F:
+ return MESA_FORMAT_RGB_FLOAT32;
+ case GL_RGB32UI:
+ return MESA_FORMAT_RGB_UINT32;
+ case GL_RGB32I:
+ return MESA_FORMAT_RGB_INT32;
+
default:
return MESA_FORMAT_NONE;
}
}
+
static gl_format
validate_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat)
{
if (base_format == GL_R || base_format == GL_RG)
return MESA_FORMAT_NONE;
}
+
+ if (!ctx->Extensions.ARB_texture_buffer_object_rgb32) {
+ GLenum base_format = _mesa_get_format_base_format(format);
+ if (base_format == GL_RGB)
+ return MESA_FORMAT_NONE;
+ }
return format;
}
-/** GL_ARB_texture_buffer_object */
-void GLAPIENTRY
-_mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
+static void
+texbufferrange(struct gl_context *ctx, GLenum target, GLenum internalFormat,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset, GLsizeiptr size)
{
struct gl_texture_object *texObj;
- struct gl_buffer_object *bufObj;
gl_format format;
- GET_CURRENT_CONTEXT(ctx);
- ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
-
- if (!(ctx->Extensions.ARB_texture_buffer_object
- && _mesa_is_desktop_gl(ctx))) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer");
- return;
- }
+ FLUSH_VERTICES(ctx, 0);
if (target != GL_TEXTURE_BUFFER_ARB) {
_mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(target)");
return;
}
- bufObj = _mesa_lookup_bufferobj(ctx, buffer);
- if (buffer && !bufObj) {
- _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer(buffer %u)", buffer);
- return;
- }
-
texObj = _mesa_get_current_tex_object(ctx, target);
_mesa_lock_texture(ctx, texObj);
_mesa_reference_buffer_object(ctx, &texObj->BufferObject, bufObj);
texObj->BufferObjectFormat = internalFormat;
texObj->_BufferObjectFormat = format;
+ texObj->BufferOffset = offset;
+ texObj->BufferSize = size;
}
_mesa_unlock_texture(ctx, texObj);
}
+
+
+/** GL_ARB_texture_buffer_object */
+void GLAPIENTRY
+_mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer)
+{
+ struct gl_buffer_object *bufObj;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* NOTE: ARB_texture_buffer_object has interactions with
+ * the compatibility profile that are not implemented.
+ */
+ if (!(ctx->API == API_OPENGL_CORE &&
+ ctx->Extensions.ARB_texture_buffer_object)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer");
+ return;
+ }
+
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (!bufObj && buffer) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBuffer(buffer %u)", buffer);
+ return;
+ }
+
+ texbufferrange(ctx, target, internalFormat, bufObj, 0, buffer ? -1 : 0);
+}
+
+
+/** GL_ARB_texture_buffer_range */
+void GLAPIENTRY
+_mesa_TexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer,
+ GLintptr offset, GLsizeiptr size)
+{
+ struct gl_buffer_object *bufObj;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!(ctx->API == API_OPENGL_CORE &&
+ ctx->Extensions.ARB_texture_buffer_range)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBufferRange");
+ return;
+ }
+
+ bufObj = _mesa_lookup_bufferobj(ctx, buffer);
+ if (bufObj) {
+ if (offset < 0 ||
+ size <= 0 ||
+ (offset + size) > bufObj->Size) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "glTexBufferRange");
+ return;
+ }
+ if (offset % ctx->Const.TextureBufferOffsetAlignment) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glTexBufferRange(invalid offset alignment)");
+ return;
+ }
+ } else if (buffer) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBufferRange(buffer %u)",
+ buffer);
+ return;
+ } else {
+ offset = 0;
+ size = 0;
+ }
+
+ texbufferrange(ctx, target, internalFormat, bufObj, offset, size);
+}
+
+
+static GLboolean
+is_renderable_texture_format(struct gl_context *ctx, GLenum internalformat)
+{
+ /* Everything that is allowed for renderbuffers,
+ * except for a base format of GL_STENCIL_INDEX.
+ */
+ GLenum baseFormat = _mesa_base_fbo_format(ctx, internalformat);
+ return baseFormat != 0 && baseFormat != GL_STENCIL_INDEX;
+}
+
+
+/** GL_ARB_texture_multisample */
+static GLboolean
+check_multisample_target(GLuint dims, GLenum target)
+{
+ switch(target) {
+ case GL_TEXTURE_2D_MULTISAMPLE:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
+ return dims == 2;
+
+ case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
+ return dims == 3;
+
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+static void
+teximagemultisample(GLuint dims, GLenum target, GLsizei samples,
+ GLint internalformat, GLsizei width, GLsizei height,
+ GLsizei depth, GLboolean fixedsamplelocations,
+ GLboolean immutable, const char *func)
+{
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *texImage;
+ GLboolean sizeOK, dimensionsOK;
+ gl_format texFormat;
+ GLenum sample_count_error;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!(ctx->Extensions.ARB_texture_multisample
+ && _mesa_is_desktop_gl(ctx))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unsupported)", func);
+ return;
+ }
+
+ if (!check_multisample_target(dims, target)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", func);
+ return;
+ }
+
+ /* check that the specified internalformat is color/depth/stencil-renderable;
+ * refer GL3.1 spec 4.4.4
+ */
+
+ if (immutable && !_mesa_is_legal_tex_storage_format(ctx, internalformat)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(internalformat=%s not legal for immutable-format)",
+ func, _mesa_lookup_enum_by_nr(internalformat));
+ return;
+ }
+
+ if (!is_renderable_texture_format(ctx, internalformat)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(internalformat=%s)",
+ func, _mesa_lookup_enum_by_nr(internalformat));
+ return;
+ }
+
+ sample_count_error = _mesa_check_sample_count(ctx, target,
+ internalformat, samples);
+ if (sample_count_error != GL_NO_ERROR) {
+ _mesa_error(ctx, sample_count_error, "%s(samples)", func);
+ return;
+ }
+
+ texObj = _mesa_get_current_tex_object(ctx, target);
+
+ if (immutable && (!texObj || (texObj->Name == 0))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(texture object 0)",
+ func);
+ return;
+ }
+
+ texImage = _mesa_get_tex_image(ctx, texObj, 0, 0);
+
+ if (texImage == NULL) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s()", func);
+ return;
+ }
+
+ texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
+ internalformat, GL_NONE, GL_NONE);
+ assert(texFormat != MESA_FORMAT_NONE);
+
+ dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
+ width, height, depth, 0);
+
+ sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat,
+ width, height, depth, 0);
+
+ if (_mesa_is_proxy_texture(target)) {
+ if (dimensionsOK && sizeOK) {
+ _mesa_init_teximage_fields(ctx, texImage,
+ width, height, depth, 0, internalformat, texFormat);
+ texImage->NumSamples = samples;
+ texImage->FixedSampleLocations = fixedsamplelocations;
+ }
+ else {
+ /* clear all image fields */
+ _mesa_init_teximage_fields(ctx, texImage,
+ 0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE);
+ }
+ }
+ else {
+ if (!dimensionsOK) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(invalid width or height)", func);
+ return;
+ }
+
+ if (!sizeOK) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "%s(texture too large)", func);
+ return;
+ }
+
+ /* Check if texObj->Immutable is set */
+ if (texObj->Immutable) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(immutable)", func);
+ return;
+ }
+
+ ctx->Driver.FreeTextureImageBuffer(ctx, texImage);
+
+ _mesa_init_teximage_fields(ctx, texImage,
+ width, height, depth, 0, internalformat, texFormat);
+
+ texImage->NumSamples = samples;
+ texImage->FixedSampleLocations = fixedsamplelocations;
+
+ if (width > 0 && height > 0 && depth > 0) {
+ if (!ctx->Driver.AllocTextureStorage(ctx, texObj, 1,
+ width, height, depth)) {
+ /* tidy up the texture image state. strictly speaking,
+ * we're allowed to just leave this in whatever state we
+ * like, but being tidy is good.
+ */
+ _mesa_init_teximage_fields(ctx, texImage,
+ 0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE);
+ }
+ }
+
+ texObj->Immutable = immutable;
+ _mesa_update_fbo_texture(ctx, texObj, 0, 0);
+ }
+}
+
+
+void GLAPIENTRY
+_mesa_TexImage2DMultisample(GLenum target, GLsizei samples,
+ GLenum internalformat, GLsizei width,
+ GLsizei height, GLboolean fixedsamplelocations)
+{
+ teximagemultisample(2, target, samples, internalformat,
+ width, height, 1, fixedsamplelocations, GL_FALSE,
+ "glTexImage2DMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_TexImage3DMultisample(GLenum target, GLsizei samples,
+ GLenum internalformat, GLsizei width,
+ GLsizei height, GLsizei depth,
+ GLboolean fixedsamplelocations)
+{
+ teximagemultisample(3, target, samples, internalformat,
+ width, height, depth, fixedsamplelocations, GL_FALSE,
+ "glTexImage3DMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_TexStorage2DMultisample(GLenum target, GLsizei samples,
+ GLenum internalformat, GLsizei width,
+ GLsizei height, GLboolean fixedsamplelocations)
+{
+ teximagemultisample(2, target, samples, internalformat,
+ width, height, 1, fixedsamplelocations, GL_TRUE,
+ "glTexStorage2DMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_TexStorage3DMultisample(GLenum target, GLsizei samples,
+ GLenum internalformat, GLsizei width,
+ GLsizei height, GLsizei depth,
+ GLboolean fixedsamplelocations)
+{
+ teximagemultisample(3, target, samples, internalformat,
+ width, height, depth, fixedsamplelocations, GL_TRUE,
+ "glTexStorage3DMultisample");
+}