X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fteximage.c;h=5f8edff87c699847a1b64331ee393ccaab37364e;hb=c1df492d03862f75698ba5d50d4f46cd528ffc0d;hp=74e985d576c6700bcad5d1990fe99f7a7ee16f95;hpb=3d8d5b298a268b119d840bc9bae0ee9e0c9244a9;p=mesa.git diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index 74e985d576c..5f8edff87c6 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -48,8 +48,10 @@ #include "texobj.h" #include "texstate.h" #include "texstorage.h" +#include "textureview.h" #include "mtypes.h" #include "glformats.h" +#include "texstore.h" /** @@ -159,6 +161,9 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + return GL_DEPTH_STENCIL; default: ; /* fallthrough */ } @@ -180,7 +185,7 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) default: ; /* fallthrough */ } - + if (ctx->Extensions.TDFX_texture_compression_FXT1) { switch (internalFormat) { case GL_COMPRESSED_RGB_FXT1_3DFX: @@ -251,16 +256,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) } } - if (ctx->Extensions.ATI_envmap_bumpmap) { - switch (internalFormat) { - case GL_DUDV_ATI: - case GL_DU8DV8_ATI: - return GL_DUDV_ATI; - default: - ; /* fallthrough */ - } - } - if (ctx->Extensions.EXT_texture_snorm) { switch (internalFormat) { case GL_RED_SNORM: @@ -300,30 +295,22 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) } } - if (ctx->Extensions.EXT_packed_depth_stencil) { - switch (internalFormat) { - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - return GL_DEPTH_STENCIL_EXT; - default: - ; /* fallthrough */ - } - } - 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: @@ -396,11 +383,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) if (ctx->Extensions.ARB_texture_rg) { switch (internalFormat) { case GL_R16F: - /* R16F depends on both ARB_half_float_pixel and ARB_texture_float. - */ - if (!ctx->Extensions.ARB_half_float_pixel) - break; - /* FALLTHROUGH */ case GL_R32F: if (!ctx->Extensions.ARB_texture_float) break; @@ -421,11 +403,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) return GL_RED; case GL_RG16F: - /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float. - */ - if (!ctx->Extensions.ARB_half_float_pixel) - break; - /* FALLTHROUGH */ case GL_RG32F: if (!ctx->Extensions.ARB_texture_float) break; @@ -543,6 +520,20 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) } } + if (_mesa_is_desktop_gl(ctx) && + ctx->Extensions.ARB_texture_compression_bptc) { + switch (internalFormat) { + case GL_COMPRESSED_RGBA_BPTC_UNORM: + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: + return GL_RGBA; + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: + return GL_RGB; + default: + ; /* fallthrough */ + } + } + if (ctx->API == API_OPENGLES) { switch (internalFormat) { case GL_PALETTE4_RGB8_OES: @@ -613,7 +604,7 @@ set_tex_image(struct gl_texture_object *tObj, /** * Allocate a texture image structure. - * + * * Called via ctx->Driver.NewTextureImage() unless overriden by a device * driver. * @@ -659,30 +650,37 @@ _mesa_delete_texture_image(struct gl_context *ctx, 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 == 10 + 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 || - target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY || - target == GL_PROXY_TEXTURE_2D_MULTISAMPLE || - target == GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY); + STATIC_ASSERT(NUM_TEXTURE_TARGETS == Elements(targets) + 2); + + for (i = 0; i < Elements(targets); ++i) + if (target == targets[i]) + return GL_TRUE; + return GL_FALSE; } /** * Return the proxy target which corresponds to the given texture target */ -GLenum -_mesa_get_proxy_target(GLenum target) +static GLenum +proxy_target(GLenum target) { switch (target) { case GL_TEXTURE_1D: @@ -722,29 +720,22 @@ _mesa_get_proxy_target(GLenum target) 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()"); + _mesa_problem(NULL, "unexpected target in proxy_target()"); return 0; } } /** - * Get the texture object that corresponds to the target of the given - * texture unit. The target should have already been checked for validity. - * - * \param ctx GL context. - * \param texUnit texture unit. - * \param target texture target. - * - * \return pointer to the texture object on success, or NULL on failure. + * Return a pointer to the current texture object for the given target + * on the current texture unit. + * Note: all error checking should have been done by this point. */ struct gl_texture_object * -_mesa_select_tex_object(struct gl_context *ctx, - const struct gl_texture_unit *texUnit, - GLenum target) +_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target) { - const GLboolean arrayTex = (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + const GLboolean arrayTex = ctx->Extensions.EXT_texture_array; switch (target) { case GL_TEXTURE_1D: @@ -796,7 +787,7 @@ _mesa_select_tex_object(struct gl_context *ctx, 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 @@ -811,22 +802,12 @@ _mesa_select_tex_object(struct gl_context *ctx, 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()"); + _mesa_problem(NULL, "bad target in _mesa_get_current_tex_object()"); return NULL; } } -/** - * Return pointer to texture object for given target on current texture unit. - */ -struct gl_texture_object * -_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target) -{ - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - return _mesa_select_tex_object(ctx, texUnit, target); -} - /** * Get a texture image pointer from a texture object, given a texture @@ -868,7 +849,7 @@ _mesa_get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj, if (!texObj) return NULL; - + texImage = _mesa_select_tex_image(ctx, texObj, target, level); if (!texImage) { texImage = ctx->Driver.NewTextureImage(ctx); @@ -974,7 +955,7 @@ get_proxy_tex_image(struct gl_context *ctx, GLenum target, GLint level) * * \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. * @@ -1009,8 +990,7 @@ _mesa_max_texture_levels(struct gl_context *ctx, GLenum target) case GL_PROXY_TEXTURE_1D_ARRAY_EXT: case GL_TEXTURE_2D_ARRAY_EXT: case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array) + return ctx->Extensions.EXT_texture_array ? ctx->Const.MaxTextureLevels : 0; case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: @@ -1081,6 +1061,93 @@ _mesa_get_texture_dimensions(GLenum target) } +/** + * Check if a texture target can have more than one layer. + */ +GLboolean +_mesa_tex_target_is_layered(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE: + case GL_PROXY_TEXTURE_RECTANGLE: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_PROXY_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_BUFFER: + 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_TEXTURE_EXTERNAL_OES: + return GL_FALSE; + + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_1D_ARRAY: + 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 GL_TRUE; + + default: + assert(!"Invalid texture target."); + return GL_FALSE; + } +} + + +/** + * Return the number of layers present in the given level of an array, + * cubemap or 3D texture. If the texture is not layered return zero. + */ +GLuint +_mesa_get_texture_layers(const struct gl_texture_object *texObj, GLint level) +{ + assert(level >= 0 && level < MAX_TEXTURE_LEVELS); + + switch (texObj->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_BUFFER: + case GL_TEXTURE_EXTERNAL_OES: + return 0; + + case GL_TEXTURE_CUBE_MAP: + return 6; + + case GL_TEXTURE_1D_ARRAY: { + struct gl_texture_image *img = texObj->Image[0][level]; + return img ? img->Height : 0; + } + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { + struct gl_texture_image *img = texObj->Image[0][level]; + return img ? img->Depth : 0; + } + + default: + assert(!"Invalid texture target."); + return 0; + } +} + + /** * Return the maximum number of mipmap levels for the given target * and the dimensions. @@ -1095,24 +1162,33 @@ _mesa_get_tex_max_num_levels(GLenum target, GLsizei width, GLsizei height, 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: - ASSERT(width == height); + 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); @@ -1214,16 +1290,19 @@ clear_teximage_fields(struct gl_texture_image *img) * \param border image border. * \param internalFormat internal format. * \param format the actual hardware format (one of MESA_FORMAT_*) + * \param numSamples number of samples per texel, or zero for non-MS. + * \param fixedSampleLocations are sample locations fixed? * * Fills in the fields of \p img with the given information. * Note: width, height and depth include the border. */ -void -_mesa_init_teximage_fields(struct gl_context *ctx, - struct gl_texture_image *img, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum internalFormat, - gl_format format) +static void +init_teximage_fields_ms(struct gl_context *ctx, + struct gl_texture_image *img, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum internalFormat, + mesa_format format, + GLuint numSamples, GLboolean fixedSampleLocations) { GLenum target; ASSERT(img); @@ -1321,6 +1400,20 @@ _mesa_init_teximage_fields(struct gl_context *ctx, _mesa_get_tex_max_num_levels(target, img->Width2, img->Height2, img->Depth2); img->TexFormat = format; + img->NumSamples = numSamples; + img->FixedSampleLocations = fixedSampleLocations; +} + + +void +_mesa_init_teximage_fields(struct gl_context *ctx, + struct gl_texture_image *img, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum internalFormat, + mesa_format format) +{ + init_teximage_fields_ms(ctx, img, width, height, depth, border, + internalFormat, format, 0, GL_TRUE); } @@ -1428,6 +1521,8 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target, case GL_PROXY_TEXTURE_CUBE_MAP_ARB: 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) @@ -1464,7 +1559,7 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target, return GL_FALSE; if (height < 2 * border || height > 2 * border + maxSize) return GL_FALSE; - if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) + if (depth < 0 || depth > ctx->Const.MaxArrayTextureLayers) return GL_FALSE; if (!ctx->Extensions.ARB_texture_non_power_of_two) { if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) @@ -1481,7 +1576,9 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target, return GL_FALSE; if (height < 2 * border || height > 2 * border + maxSize) return GL_FALSE; - if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) + if (depth < 0 || depth > ctx->Const.MaxArrayTextureLayers || depth % 6) + return GL_FALSE; + if (width != height) return GL_FALSE; if (level >= ctx->Const.MaxCubeTextureLevels) return GL_FALSE; @@ -1536,13 +1633,13 @@ error_check_subtexture_dimensions(struct gl_context *ctx, } /* check xoffset and width */ - if (xoffset < -destImage->Border) { + if (xoffset < - (GLint) destImage->Border) { _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset)", function, dims); return GL_TRUE; } - if (xoffset + subWidth > destImage->Width) { + if (xoffset + subWidth > (GLint) destImage->Width) { _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(xoffset+width)", function, dims); return GL_TRUE; @@ -1556,7 +1653,7 @@ error_check_subtexture_dimensions(struct gl_context *ctx, function, dims); return GL_TRUE; } - if (yoffset + subHeight > destImage->Height) { + if (yoffset + subHeight > (GLint) destImage->Height) { _mesa_error(ctx, GL_INVALID_VALUE, "%s%dD(yoffset+height)", function, dims); return GL_TRUE; @@ -1565,7 +1662,10 @@ error_check_subtexture_dimensions(struct gl_context *ctx, /* check zoffset and depth */ if (dims > 2) { - GLint zBorder = (target == GL_TEXTURE_2D_ARRAY) ? 0 : destImage->Border; + GLint zBorder = (target == GL_TEXTURE_2D_ARRAY || + target == GL_TEXTURE_CUBE_MAP_ARRAY) ? + 0 : destImage->Border; + if (zoffset < -zBorder) { _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset)", function); return GL_TRUE; @@ -1594,18 +1694,24 @@ error_check_subtexture_dimensions(struct gl_context *ctx, return GL_TRUE; } - /* size must be multiple of bw by bh or equal to whole texture size */ - if ((subWidth % bw != 0) && subWidth != destImage->Width) { + /* 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) && subHeight != destImage->Height) { + 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; @@ -1636,7 +1742,7 @@ error_check_subtexture_dimensions(struct gl_context *ctx, */ GLboolean _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level, - gl_format format, + mesa_format format, GLint width, GLint height, GLint depth, GLint border) { /* We just check if the image size is less than MaxTextureMbytes. @@ -1678,9 +1784,9 @@ compressedteximage_only_format(const struct gl_context *ctx, GLenum format) * Helper function to determine whether a target and specific compression * format are supported. */ -static GLboolean -target_can_be_compressed(const struct gl_context *ctx, GLenum target, - GLenum intFormat) +GLboolean +_mesa_target_can_be_compressed(const struct gl_context *ctx, GLenum target, + GLenum intFormat) { (void) intFormat; /* not used yet */ @@ -1689,6 +1795,7 @@ target_can_be_compressed(const struct gl_context *ctx, GLenum target, case GL_PROXY_TEXTURE_2D: return GL_TRUE; /* true for any compressed format so far */ case GL_PROXY_TEXTURE_CUBE_MAP: + 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: @@ -1698,14 +1805,13 @@ target_can_be_compressed(const struct gl_context *ctx, GLenum target, return ctx->Extensions.ARB_texture_cube_map; case GL_PROXY_TEXTURE_2D_ARRAY_EXT: case GL_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return 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; - } + } } @@ -1747,9 +1853,7 @@ legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target) && ctx->Extensions.NV_texture_rectangle; case GL_TEXTURE_1D_ARRAY_EXT: case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - return _mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array; default: return GL_FALSE; } @@ -1760,14 +1864,10 @@ legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target) case GL_PROXY_TEXTURE_3D: return _mesa_is_desktop_gl(ctx); case GL_TEXTURE_2D_ARRAY_EXT: - return (_mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array)) + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array) || _mesa_is_gles3(ctx); case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return _mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return _mesa_is_desktop_gl(ctx) && 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; @@ -1808,9 +1908,7 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle; case GL_TEXTURE_1D_ARRAY_EXT: - return _mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array; default: return GL_FALSE; } @@ -1819,9 +1917,7 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) case GL_TEXTURE_3D: return GL_TRUE; case GL_TEXTURE_2D_ARRAY_EXT: - return (_mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array)) + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array) || _mesa_is_gles3(ctx); case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: @@ -1844,12 +1940,8 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) 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; + struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target); + return !texObj->Immutable; } @@ -1860,14 +1952,120 @@ static GLuint compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth, GLenum glformat) { - gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); + mesa_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); return _mesa_format_image_size(mesaFormat, width, height, depth); } +/** + * Verify that a texture format is valid with a particular target + * + * In particular, textures with base format of \c GL_DEPTH_COMPONENT or + * \c GL_DEPTH_STENCIL are only valid with certain, context dependent texture + * targets. + * + * \param ctx GL context + * \param target Texture target + * \param internalFormat Internal format of the texture image + * \param dimensions Dimensionality at the caller. This is \b not used + * in the validation. It is only used when logging + * error messages. + * \param caller Base name of the calling function (e.g., + * "glTexImage" or "glTexStorage"). + * + * \returns true if the combination is legal, false otherwise. + */ +bool +_mesa_legal_texture_base_format_for_target(struct gl_context *ctx, + GLenum target, GLenum internalFormat, + unsigned dimensions, + const char *caller) +{ + if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT + || _mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_STENCIL) { + /* Section 3.8.3 (Texture Image Specification) of the OpenGL 3.3 Core + * Profile spec says: + * + * "Textures with a base internal format of DEPTH_COMPONENT or + * DEPTH_STENCIL are supported by texture image specification + * commands only if target is TEXTURE_1D, TEXTURE_2D, + * TEXTURE_1D_ARRAY, TEXTURE_2D_ARRAY, TEXTURE_RECTANGLE, + * TEXTURE_CUBE_MAP, PROXY_TEXTURE_1D, PROXY_TEXTURE_2D, + * PROXY_TEXTURE_1D_ARRAY, PROXY_TEXTURE_2D_ARRAY, + * PROXY_TEXTURE_RECTANGLE, or PROXY_TEXTURE_CUBE_MAP. Using these + * formats in conjunction with any other target will result in an + * INVALID_OPERATION error." + * + * Cubemaps are only supported with desktop OpenGL version >= 3.0, + * EXT_gpu_shader4, or, on OpenGL ES 2.0+, OES_depth_texture_cube_map. + */ + if (target != GL_TEXTURE_1D && + target != GL_PROXY_TEXTURE_1D && + target != GL_TEXTURE_2D && + target != GL_PROXY_TEXTURE_2D && + target != GL_TEXTURE_1D_ARRAY && + target != GL_PROXY_TEXTURE_1D_ARRAY && + target != GL_TEXTURE_2D_ARRAY && + target != GL_PROXY_TEXTURE_2D_ARRAY && + target != GL_TEXTURE_RECTANGLE_ARB && + target != GL_PROXY_TEXTURE_RECTANGLE_ARB && + !((_mesa_is_cube_face(target) || + target == GL_TEXTURE_CUBE_MAP || + target == GL_PROXY_TEXTURE_CUBE_MAP) && + (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_OPERATION, + "%s%dD(bad target for depth texture)", + caller, dimensions); + return false; + } + } + + return true; +} + +static bool +texture_formats_agree(GLenum internalFormat, + GLenum format) +{ + GLboolean colorFormat; + GLboolean is_format_depth_or_depthstencil; + GLboolean is_internalFormat_depth_or_depthstencil; + + /* Even though there are no color-index textures, we still have to support + * uploading color-index data and remapping it to RGB via the + * GL_PIXEL_MAP_I_TO_[RGBA] tables. + */ + const GLboolean indexFormat = (format == GL_COLOR_INDEX); + + is_internalFormat_depth_or_depthstencil = + _mesa_is_depth_format(internalFormat) || + _mesa_is_depthstencil_format(internalFormat); + + is_format_depth_or_depthstencil = + _mesa_is_depth_format(format) || + _mesa_is_depthstencil_format(format); + + colorFormat = _mesa_is_color_format(format); + + if (_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) + return false; + + if (is_internalFormat_depth_or_depthstencil != + is_format_depth_or_depthstencil) + return false; + + if (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) + return false; + + return true; +} /** * Test the glTexImage[123]D() parameters for errors. - * + * * \param ctx GL context. * \param dimensions texture image dimensions (must be 1, 2 or 3). * \param target texture target given by the user (already validated). @@ -1879,7 +2077,7 @@ compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth, * \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 GL_TRUE if a error is found, GL_FALSE otherwise * * Verifies each of the parameters against the constants specified in @@ -1898,15 +2096,8 @@ texture_error_check( struct gl_context *ctx, GLint width, GLint height, GLint depth, GLint border ) { - GLboolean colorFormat; GLenum err; - /* Even though there are no color-index textures, we still have to support - * uploading color-index data and remapping it to RGB via the - * GL_PIXEL_MAP_I_TO_[RGBA] tables. - */ - const GLboolean indexFormat = (format == GL_COLOR_INDEX); - /* Note: for proxy textures, some error conditions immediately generate * a GL error in the usual way. But others do not generate a GL error. * Instead, they cause the width, height, depth, format fields of the @@ -1949,12 +2140,12 @@ texture_error_check( struct gl_context *ctx, 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; + _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); @@ -1970,27 +2161,6 @@ texture_error_check( struct gl_context *ctx, } } - 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; - } - - if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY || - target == GL_TEXTURE_CUBE_MAP_ARRAY) && width != height) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage3D(cube array width != height)"); - return GL_TRUE; - } - - if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY || - target == GL_TEXTURE_CUBE_MAP_ARRAY) && (depth % 6)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage3D(cube array depth not multiple of 6)"); - return GL_TRUE; - } - /* Check internalFormat */ if (_mesa_base_tex_format(ctx, internalFormat) < 0) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -2010,12 +2180,7 @@ texture_error_check( struct gl_context *ctx, } /* make sure internal format and format basically agree */ - colorFormat = _mesa_is_color_format(format); - if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) || - (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) || - (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) || - (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) || - (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) { + if (!texture_formats_agree(internalFormat, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexImage%dD(incompatible internalFormat = %s, format = %s)", dimensions, _mesa_lookup_enum_by_nr(internalFormat), @@ -2055,36 +2220,13 @@ texture_error_check( struct gl_context *ctx, } /* additional checks for depth textures */ - 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_PROXY_TEXTURE_1D && - target != GL_TEXTURE_2D && - target != GL_PROXY_TEXTURE_2D && - target != GL_TEXTURE_1D_ARRAY && - target != GL_PROXY_TEXTURE_1D_ARRAY && - target != GL_TEXTURE_2D_ARRAY && - target != GL_PROXY_TEXTURE_2D_ARRAY && - 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->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); - return GL_TRUE; - } - } + if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalFormat, + dimensions, "glTexImage")) + return GL_TRUE; /* additional checks for compressed textures */ if (_mesa_is_compressed_format(ctx, internalFormat)) { - if (!target_can_be_compressed(ctx, target, internalFormat)) { + if (!_mesa_target_can_be_compressed(ctx, target, internalFormat)) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage%dD(target can't be compressed)", dimensions); return GL_TRUE; @@ -2122,6 +2264,36 @@ texture_error_check( struct gl_context *ctx, } +bool +_mesa_compressed_texture_pixel_storage_error_check(struct gl_context *ctx, + GLint dimensions, + struct gl_pixelstore_attrib *packing, + const char *caller) +{ + if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize) + return true; + + if (packing->CompressedBlockWidth && packing->SkipPixels % packing->CompressedBlockWidth) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(skip-pixels %% block-width)", caller); + return false; + } + + if (dimensions > 1 && packing->CompressedBlockHeight && packing->SkipRows % packing->CompressedBlockHeight) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(skip-rows %% block-height)", caller); + return false; + } + + if (dimensions > 2 && packing->CompressedBlockDepth && packing->SkipImages % packing->CompressedBlockDepth) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(skip-images %% block-depth)", caller); + return false; + } + + return true; +} + /** * Error checking for glCompressedTexImage[123]D(). * Note that the width, height and depth values are not fully error checked @@ -2140,17 +2312,25 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, GLenum error = GL_NO_ERROR; char *reason = ""; /* no error */ - if (!target_can_be_compressed(ctx, target, internalFormat)) { + if (!_mesa_target_can_be_compressed(ctx, target, internalFormat)) { reason = "target"; - error = GL_INVALID_ENUM; + /* From section 3.8.6, page 146 of OpenGL ES 3.0 spec: + * + * "The ETC2/EAC texture compression algorithm supports only + * two-dimensional images. If internalformat is an ETC2/EAC format, + * CompressedTexImage3D will generate an INVALID_OPERATION error if + * target is not TEXTURE_2D_ARRAY." + */ + error = _mesa_is_desktop_gl(ctx) ? GL_INVALID_ENUM : GL_INVALID_OPERATION; goto error; } /* This will detect any invalid internalFormat value */ if (!_mesa_is_compressed_format(ctx, internalFormat)) { - reason = "internalFormat"; - error = GL_INVALID_ENUM; - goto error; + _mesa_error(ctx, GL_INVALID_ENUM, + "glCompressedTexImage%dD(internalFormat=%s)", + dimensions, _mesa_lookup_enum_by_nr(internalFormat)); + return GL_TRUE; } switch (internalFormat) { @@ -2222,12 +2402,11 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, goto error; } - /* For cube map, width must equal 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 for invalid pixel storage modes */ + if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dimensions, + &ctx->Unpack, + "glCompressedTexImage")) { + return GL_FALSE; } /* check image size in bytes */ @@ -2250,6 +2429,7 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, return GL_FALSE; error: + /* Note: not all error paths exit through here. */ _mesa_error(ctx, error, "glCompressedTexImage%dD(%s)", dimensions, reason); return GL_TRUE; } @@ -2258,7 +2438,7 @@ error: /** * 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 (already validated) @@ -2271,7 +2451,7 @@ error: * \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 @@ -2376,7 +2556,7 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions, /** * 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. @@ -2385,9 +2565,9 @@ texsubimage_error_check(struct gl_context *ctx, GLuint dimensions, * \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. @@ -2407,7 +2587,7 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)", dimensions, _mesa_lookup_enum_by_nr(target)); return GL_TRUE; - } + } /* level check */ if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) { @@ -2465,7 +2645,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, break; default: _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } } @@ -2473,7 +2654,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, baseFormat = _mesa_base_tex_format(ctx, internalFormat); if (baseFormat < 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } @@ -2482,7 +2664,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, if (_mesa_is_color_format(internalFormat)) { if (rb_base_format < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } } @@ -2508,7 +2691,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, } if (!valid) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } } @@ -2542,6 +2726,17 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, "glCopyTexImage%dD(srgb usage mismatch)", dimensions); return GL_TRUE; } + + /* Page 139, Table 3.15 of OpenGL ES 3.0 spec does not define ReadPixels + * types for SNORM formats. Also, conversion to SNORM formats is not + * allowed by Table 3.2 on Page 110. + */ + if(_mesa_is_enum_format_snorm(internalFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); + return GL_TRUE; + } } if (!_mesa_source_buffer_exists(ctx, baseFormat)) { @@ -2560,6 +2755,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, if (_mesa_is_color_format(internalFormat)) { bool is_int = _mesa_is_enum_format_integer(internalFormat); bool is_rbint = _mesa_is_enum_format_integer(rb_internal_format); + bool is_unorm = _mesa_is_enum_format_unorm(internalFormat); + bool is_rbunorm = _mesa_is_enum_format_unorm(rb_internal_format); if (is_int || is_rbint) { if (is_int != is_rbint) { _mesa_error(ctx, GL_INVALID_OPERATION, @@ -2573,17 +2770,23 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, 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; + /* From page 138 of OpenGL ES 3.0 spec: + * "The error INVALID_OPERATION is generated if floating-point RGBA + * data is required; if signed integer RGBA data is required and the + * format of the current color buffer is not signed integer; if + * unsigned integer RGBA data is required and the format of the + * current color buffer is not unsigned integer; or if fixed-point + * RGBA data is required and the format of the current color buffer + * is not fixed-point. + */ + if (_mesa_is_gles(ctx) && is_unorm != is_rbunorm) + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%dD(unorm vs non-unorm)", dimensions); } if (_mesa_is_compressed_format(ctx, internalFormat)) { - if (!target_can_be_compressed(ctx, target, internalFormat)) { + if (!_mesa_target_can_be_compressed(ctx, target, internalFormat)) { _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%dD(target)", dimensions); return GL_TRUE; @@ -2753,9 +2956,8 @@ check_rtt_cb(GLuint key, void *data, void *userData) 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; } @@ -2858,13 +3060,13 @@ override_internal_format(GLenum internalFormat, GLint width, GLint height) * for efficient texture memory layout/allocation. In particular, this * comes up during automatic mipmap generation. */ -gl_format +mesa_format _mesa_choose_texture_format(struct gl_context *ctx, struct gl_texture_object *texObj, GLenum target, GLint level, GLenum internalFormat, GLenum format, GLenum type) { - gl_format f; + mesa_format f; /* see if we've already chosen a format for the previous level */ if (level > 0) { @@ -2883,7 +3085,7 @@ _mesa_choose_texture_format(struct gl_context *ctx, } /* If the application requested compression to an S3TC format but we don't - * have the DTXn library, force a generic compressed format instead. + * have the DXTn library, force a generic compressed format instead. */ if (internalFormat != format && format != GL_NONE) { const GLenum before = internalFormat; @@ -2914,12 +3116,13 @@ _mesa_choose_texture_format(struct gl_context *ctx, } /* choose format from scratch */ - f = ctx->Driver.ChooseTextureFormat(ctx, texObj->Target, internalFormat, + f = ctx->Driver.ChooseTextureFormat(ctx, target, internalFormat, format, type); ASSERT(f != MESA_FORMAT_NONE); return f; } + /** * Adjust pixel unpack params and image dimensions to strip off the * one-pixel texture border. @@ -2957,7 +3160,9 @@ strip_texture_border(GLenum target, *height = *height - 2; /* reduce the height by two border pixels */ } - if (*depth >= 3 && target != GL_TEXTURE_2D_ARRAY && target != GL_TEXTURE_CUBE_MAP_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 */ } @@ -2983,7 +3188,7 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims, struct gl_pixelstore_attrib unpack_no_border; const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; struct gl_texture_object *texObj; - gl_format texFormat; + mesa_format texFormat; GLboolean dimensionsOK, sizeOK; FLUSH_VERTICES(ctx, 0); @@ -3074,7 +3279,7 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims, height, depth, border); /* check that the texture won't take too much memory, etc */ - sizeOK = ctx->Driver.TestProxyTexImage(ctx, _mesa_get_proxy_target(target), + sizeOK = ctx->Driver.TestProxyTexImage(ctx, proxy_target(target), level, texFormat, width, height, depth, border); @@ -3156,7 +3361,7 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims, _mesa_update_fbo_texture(ctx, texObj, face, level); - _mesa_dirty_texobj(ctx, texObj, GL_TRUE); + _mesa_dirty_texobj(ctx, texObj); } } _mesa_unlock_texture(ctx, texObj); @@ -3233,7 +3438,8 @@ _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) 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; @@ -3274,7 +3480,7 @@ _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) 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); @@ -3309,7 +3515,7 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, _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); @@ -3348,7 +3554,9 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, check_gen_mipmap(ctx, target, texObj, level); - ctx->NewState |= _NEW_TEXTURE; + /* NOTE: Don't signal _NEW_TEXTURE since we've only changed + * the texel data, not the texture format, size, etc. + */ } } _mesa_unlock_texture(ctx, texObj); @@ -3406,7 +3614,7 @@ _mesa_TexSubImage3D( GLenum target, GLint level, * from. This depends on whether the texture contains color or depth values. */ static struct gl_renderbuffer * -get_copy_tex_image_source(struct gl_context *ctx, gl_format texFormat) +get_copy_tex_image_source(struct gl_context *ctx, mesa_format texFormat) { if (_mesa_get_format_bits(texFormat, GL_DEPTH_BITS) > 0) { /* reading from depth/stencil buffer */ @@ -3418,7 +3626,58 @@ get_copy_tex_image_source(struct gl_context *ctx, gl_format texFormat) } } +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); + } +} + +static GLboolean +formats_differ_in_component_sizes (mesa_format f1, + mesa_format f2) +{ + GLint f1_r_bits = _mesa_get_format_bits(f1, GL_RED_BITS); + GLint f1_g_bits = _mesa_get_format_bits(f1, GL_GREEN_BITS); + GLint f1_b_bits = _mesa_get_format_bits(f1, GL_BLUE_BITS); + GLint f1_a_bits = _mesa_get_format_bits(f1, GL_ALPHA_BITS); + + GLint f2_r_bits = _mesa_get_format_bits(f2, GL_RED_BITS); + GLint f2_g_bits = _mesa_get_format_bits(f2, GL_GREEN_BITS); + GLint f2_b_bits = _mesa_get_format_bits(f2, GL_BLUE_BITS); + GLint f2_a_bits = _mesa_get_format_bits(f2, GL_ALPHA_BITS); + + if ((f1_r_bits && f2_r_bits && f1_r_bits != f2_r_bits) + || (f1_g_bits && f2_g_bits && f1_g_bits != f2_g_bits) + || (f1_b_bits && f2_b_bits && f1_b_bits != f2_b_bits) + || (f1_a_bits && f2_a_bits && f1_a_bits != f2_a_bits)) + return GL_TRUE; + return GL_FALSE; +} /** * Implement the glCopyTexImage1/2D() functions. @@ -3431,7 +3690,8 @@ copyteximage(struct gl_context *ctx, GLuint dims, struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLuint face = _mesa_tex_target_to_face(target); - gl_format texFormat; + mesa_format texFormat; + struct gl_renderbuffer *rb; FLUSH_VERTICES(ctx, 0); @@ -3461,9 +3721,43 @@ copyteximage(struct gl_context *ctx, GLuint dims, texFormat = _mesa_choose_texture_format(ctx, texObj, target, level, internalFormat, GL_NONE, GL_NONE); + + rb = _mesa_get_read_renderbuffer_for_format(ctx, internalFormat); + + if (_mesa_is_gles3(ctx)) { + if (_mesa_is_enum_format_unsized(internalFormat)) { + /* Conversion from GL_RGB10_A2 source buffer format is not allowed in + * OpenGL ES 3.0. Khronos bug# 9807. + */ + if (rb->InternalFormat == GL_RGB10_A2) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%uD(Reading from GL_RGB10_A2 buffer and" + " writing to unsized internal format)", dims); + return; + } + } + /* From Page 139 of OpenGL ES 3.0 spec: + * "If internalformat is sized, the internal format of the new texel + * array is internalformat, and this is also the new texel array’s + * effective internal format. If the component sizes of internalformat + * do not exactly match the corresponding component sizes of the source + * buffer’s effective internal format, described below, an + * INVALID_OPERATION error is generated. If internalformat is unsized, + * the internal format of the new texel array is the effective internal + * format of the source buffer, and this is also the new texel array’s + * effective internal format. + */ + else if (formats_differ_in_component_sizes (texFormat, rb->Format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyTexImage%uD(componenet size changed in" + " internal format)", dims); + return; + } + } + assert(texFormat != MESA_FORMAT_NONE); - if (!ctx->Driver.TestProxyTexImage(ctx, _mesa_get_proxy_target(target), + if (!ctx->Driver.TestProxyTexImage(ctx, proxy_target(target), level, texFormat, width, height, 1, border)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, @@ -3506,8 +3800,9 @@ copyteximage(struct gl_context *ctx, GLuint dims, 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); @@ -3515,7 +3810,7 @@ copyteximage(struct gl_context *ctx, GLuint dims, _mesa_update_fbo_texture(ctx, texObj, face, level); - _mesa_dirty_texobj(ctx, texObj, GL_TRUE); + _mesa_dirty_texobj(ctx, texObj); } } _mesa_unlock_texture(ctx, texObj); @@ -3599,13 +3894,15 @@ copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, 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); - ctx->NewState |= _NEW_TEXTURE; + /* NOTE: Don't signal _NEW_TEXTURE since we've only changed + * the texel data, not the texture format, size, etc. + */ } } _mesa_unlock_texture(ctx, texObj); @@ -3644,6 +3941,266 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, x, y, width, height); } +static bool +check_clear_tex_image(struct gl_context *ctx, + const char *function, + struct gl_texture_image *texImage, + GLenum format, GLenum type, + const void *data, + GLubyte *clearValue) +{ + struct gl_texture_object *texObj = texImage->TexObject; + static const GLubyte zeroData[MAX_PIXEL_BYTES]; + GLenum internalFormat = texImage->InternalFormat; + GLenum err; + + if (texObj->Target == GL_TEXTURE_BUFFER) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(buffer texture)", function); + return false; + } + + if (_mesa_is_compressed_format(ctx, internalFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(compressed texture)", function); + return false; + } + + err = _mesa_error_check_format_and_type(ctx, format, type); + if (err != GL_NO_ERROR) { + _mesa_error(ctx, err, + "%s(incompatible format = %s, type = %s)", + function, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type)); + return false; + } + + /* make sure internal format and format basically agree */ + if (!texture_formats_agree(internalFormat, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(incompatible internalFormat = %s, format = %s)", + function, + _mesa_lookup_enum_by_nr(internalFormat), + _mesa_lookup_enum_by_nr(format)); + return false; + } + + if (ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) { + /* both source and dest must be integer-valued, or neither */ + if (_mesa_is_format_integer_color(texImage->TexFormat) != + _mesa_is_enum_format_integer(format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(integer/non-integer format mismatch)", + function); + return false; + } + } + + if (!_mesa_texstore(ctx, + 1, /* dims */ + texImage->_BaseFormat, + texImage->TexFormat, + 0, /* dstRowStride */ + &clearValue, + 1, 1, 1, /* srcWidth/Height/Depth */ + format, type, + data ? data : zeroData, + &ctx->DefaultPacking)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid format)", function); + return false; + } + + return true; +} + +static struct gl_texture_object * +get_tex_obj_for_clear(struct gl_context *ctx, + const char *function, + GLuint texture) +{ + struct gl_texture_object *texObj; + + if (texture == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function); + return NULL; + } + + texObj = _mesa_lookup_texture(ctx, texture); + + if (texObj == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function); + return NULL; + } + + if (texObj->Target == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function); + return NULL; + } + + return texObj; +} + +static int +get_tex_images_for_clear(struct gl_context *ctx, + const char *function, + struct gl_texture_object *texObj, + GLint level, + struct gl_texture_image **texImages) +{ + GLenum target; + int i; + + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function); + return 0; + } + + if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + for (i = 0; i < MAX_FACES; i++) { + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; + + texImages[i] = _mesa_select_tex_image(ctx, texObj, target, level); + if (texImages[i] == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid level)", function); + return 0; + } + } + + return MAX_FACES; + } + + texImages[0] = _mesa_select_tex_image(ctx, texObj, texObj->Target, level); + + if (texImages[0] == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function); + return 0; + } + + return 1; +} + +void GLAPIENTRY +_mesa_ClearTexSubImage( GLuint texture, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const void *data ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_object *texObj; + struct gl_texture_image *texImages[MAX_FACES]; + GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES]; + int i, numImages; + int minDepth, maxDepth; + + texObj = get_tex_obj_for_clear(ctx, "glClearTexSubImage", texture); + + if (texObj == NULL) + return; + + _mesa_lock_texture(ctx, texObj); + + numImages = get_tex_images_for_clear(ctx, "glClearTexSubImage", + texObj, level, texImages); + if (numImages == 0) + goto out; + + if (numImages == 1) { + minDepth = -(int) texImages[0]->Border; + maxDepth = texImages[0]->Depth; + } else { + minDepth = 0; + maxDepth = numImages; + } + + if (xoffset < -(GLint) texImages[0]->Border || + yoffset < -(GLint) texImages[0]->Border || + zoffset < minDepth || + width < 0 || + height < 0 || + depth < 0 || + xoffset + width > texImages[0]->Width || + yoffset + height > texImages[0]->Height || + zoffset + depth > maxDepth) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearSubTexImage(invalid dimensions)"); + goto out; + } + + if (numImages == 1) { + if (check_clear_tex_image(ctx, "glClearTexSubImage", + texImages[0], + format, type, data, clearValue[0])) { + ctx->Driver.ClearTexSubImage(ctx, + texImages[0], + xoffset, yoffset, zoffset, + width, height, depth, + data ? clearValue[0] : NULL); + } + } else { + for (i = zoffset; i < zoffset + depth; i++) { + if (!check_clear_tex_image(ctx, "glClearTexSubImage", + texImages[i], + format, type, data, clearValue[i])) + goto out; + } + for (i = zoffset; i < zoffset + depth; i++) { + ctx->Driver.ClearTexSubImage(ctx, + texImages[i], + xoffset, yoffset, 0, + width, height, 1, + data ? clearValue[i] : NULL); + } + } + + out: + _mesa_unlock_texture(ctx, texObj); +} + +void GLAPIENTRY +_mesa_ClearTexImage( GLuint texture, GLint level, + GLenum format, GLenum type, const void *data ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_object *texObj; + struct gl_texture_image *texImages[MAX_FACES]; + GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES]; + int i, numImages; + + texObj = get_tex_obj_for_clear(ctx, "glClearTexImage", texture); + + if (texObj == NULL) + return; + + _mesa_lock_texture(ctx, texObj); + + numImages = get_tex_images_for_clear(ctx, "glClearTexImage", + texObj, level, texImages); + + for (i = 0; i < numImages; i++) { + if (!check_clear_tex_image(ctx, "glClearTexImage", + texImages[i], + format, type, data, + clearValue[i])) + goto out; + } + + for (i = 0; i < numImages; i++) { + ctx->Driver.ClearTexSubImage(ctx, texImages[i], + -(GLint) texImages[i]->Border, /* xoffset */ + -(GLint) texImages[i]->Border, /* yoffset */ + -(GLint) texImages[i]->Border, /* zoffset */ + texImages[i]->Width, + texImages[i]->Height, + texImages[i]->Depth, + data ? clearValue[i] : NULL); + } + +out: + _mesa_unlock_texture(ctx, texObj); +} + @@ -3694,9 +4251,9 @@ compressed_subtexture_error_check(struct gl_context *ctx, GLint dims, targetOK = GL_FALSE; break; } - + if (!targetOK) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target)", + _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexSubImage%uD(target)", dims); return GL_TRUE; } @@ -3709,14 +4266,22 @@ compressed_subtexture_error_check(struct gl_context *ctx, GLint dims, } if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(level=%d)", + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(level=%d)", dims, level); return GL_TRUE; } + /* Check for invalid pixel storage modes */ + if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dims, + &ctx->Unpack, + "glCompressedTexSubImage")) { + return GL_FALSE; + } + + expectedSize = compressed_tex_size(width, height, depth, format); if (expectedSize != imageSize) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(size=%d)", + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(size=%d)", dims, imageSize); return GL_TRUE; } @@ -3830,7 +4395,9 @@ compressed_tex_sub_image(GLuint dims, GLenum target, GLint level, check_gen_mipmap(ctx, target, texObj, level); - ctx->NewState |= _NEW_TEXTURE; + /* NOTE: Don't signal _NEW_TEXTURE since we've only changed + * the texel data, not the texture format, size, etc. + */ } } _mesa_unlock_texture(ctx, texObj); @@ -3868,104 +4435,125 @@ _mesa_CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, width, height, depth, format, imageSize, data); } -static gl_format +static mesa_format get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) { + if (ctx->API != API_OPENGL_CORE) { + switch (internalFormat) { + case GL_ALPHA8: + return MESA_FORMAT_A_UNORM8; + case GL_ALPHA16: + return MESA_FORMAT_A_UNORM16; + case GL_ALPHA16F_ARB: + return MESA_FORMAT_A_FLOAT16; + case GL_ALPHA32F_ARB: + return MESA_FORMAT_A_FLOAT32; + case GL_ALPHA8I_EXT: + return MESA_FORMAT_A_SINT8; + case GL_ALPHA16I_EXT: + return MESA_FORMAT_A_SINT16; + case GL_ALPHA32I_EXT: + return MESA_FORMAT_A_SINT32; + case GL_ALPHA8UI_EXT: + return MESA_FORMAT_A_UINT8; + case GL_ALPHA16UI_EXT: + return MESA_FORMAT_A_UINT16; + case GL_ALPHA32UI_EXT: + return MESA_FORMAT_A_UINT32; + case GL_LUMINANCE8: + return MESA_FORMAT_L_UNORM8; + case GL_LUMINANCE16: + return MESA_FORMAT_L_UNORM16; + case GL_LUMINANCE16F_ARB: + return MESA_FORMAT_L_FLOAT16; + case GL_LUMINANCE32F_ARB: + return MESA_FORMAT_L_FLOAT32; + case GL_LUMINANCE8I_EXT: + return MESA_FORMAT_L_SINT8; + case GL_LUMINANCE16I_EXT: + return MESA_FORMAT_L_SINT16; + case GL_LUMINANCE32I_EXT: + return MESA_FORMAT_L_SINT32; + case GL_LUMINANCE8UI_EXT: + return MESA_FORMAT_L_UINT8; + case GL_LUMINANCE16UI_EXT: + return MESA_FORMAT_L_UINT16; + case GL_LUMINANCE32UI_EXT: + return MESA_FORMAT_L_UINT32; + case GL_LUMINANCE8_ALPHA8: + return MESA_FORMAT_L8A8_UNORM; + case GL_LUMINANCE16_ALPHA16: + return MESA_FORMAT_L16A16_UNORM; + case GL_LUMINANCE_ALPHA16F_ARB: + return MESA_FORMAT_LA_FLOAT16; + case GL_LUMINANCE_ALPHA32F_ARB: + return MESA_FORMAT_LA_FLOAT32; + case GL_LUMINANCE_ALPHA8I_EXT: + return MESA_FORMAT_LA_SINT8; + case GL_LUMINANCE_ALPHA16I_EXT: + return MESA_FORMAT_LA_SINT8; + case GL_LUMINANCE_ALPHA32I_EXT: + return MESA_FORMAT_LA_SINT16; + case GL_LUMINANCE_ALPHA8UI_EXT: + return MESA_FORMAT_LA_UINT8; + case GL_LUMINANCE_ALPHA16UI_EXT: + return MESA_FORMAT_LA_UINT16; + case GL_LUMINANCE_ALPHA32UI_EXT: + return MESA_FORMAT_LA_UINT32; + case GL_INTENSITY8: + return MESA_FORMAT_I_UNORM8; + case GL_INTENSITY16: + return MESA_FORMAT_I_UNORM16; + case GL_INTENSITY16F_ARB: + return MESA_FORMAT_I_FLOAT16; + case GL_INTENSITY32F_ARB: + return MESA_FORMAT_I_FLOAT32; + case GL_INTENSITY8I_EXT: + return MESA_FORMAT_I_SINT8; + case GL_INTENSITY16I_EXT: + return MESA_FORMAT_I_SINT16; + case GL_INTENSITY32I_EXT: + return MESA_FORMAT_I_SINT32; + case GL_INTENSITY8UI_EXT: + return MESA_FORMAT_I_UINT8; + case GL_INTENSITY16UI_EXT: + return MESA_FORMAT_I_UINT16; + case GL_INTENSITY32UI_EXT: + return MESA_FORMAT_I_UINT32; + default: + break; + } + } + + if (ctx->API == API_OPENGL_CORE && + ctx->Extensions.ARB_texture_buffer_object_rgb32) { + switch (internalFormat) { + case GL_RGB32F: + return MESA_FORMAT_RGB_FLOAT32; + case GL_RGB32UI: + return MESA_FORMAT_RGB_UINT32; + case GL_RGB32I: + return MESA_FORMAT_RGB_SINT32; + default: + break; + } + } + switch (internalFormat) { - case GL_ALPHA8: - return MESA_FORMAT_A8; - case GL_ALPHA16: - return MESA_FORMAT_A16; - case GL_ALPHA16F_ARB: - return MESA_FORMAT_ALPHA_FLOAT16; - case GL_ALPHA32F_ARB: - return MESA_FORMAT_ALPHA_FLOAT32; - case GL_ALPHA8I_EXT: - return MESA_FORMAT_ALPHA_INT8; - case GL_ALPHA16I_EXT: - return MESA_FORMAT_ALPHA_INT16; - case GL_ALPHA32I_EXT: - return MESA_FORMAT_ALPHA_INT32; - case GL_ALPHA8UI_EXT: - return MESA_FORMAT_ALPHA_UINT8; - case GL_ALPHA16UI_EXT: - return MESA_FORMAT_ALPHA_UINT16; - case GL_ALPHA32UI_EXT: - return MESA_FORMAT_ALPHA_UINT32; - case GL_LUMINANCE8: - return MESA_FORMAT_L8; - case GL_LUMINANCE16: - return MESA_FORMAT_L16; - case GL_LUMINANCE16F_ARB: - return MESA_FORMAT_LUMINANCE_FLOAT16; - case GL_LUMINANCE32F_ARB: - return MESA_FORMAT_LUMINANCE_FLOAT32; - case GL_LUMINANCE8I_EXT: - return MESA_FORMAT_LUMINANCE_INT8; - case GL_LUMINANCE16I_EXT: - return MESA_FORMAT_LUMINANCE_INT16; - case GL_LUMINANCE32I_EXT: - return MESA_FORMAT_LUMINANCE_INT32; - case GL_LUMINANCE8UI_EXT: - return MESA_FORMAT_LUMINANCE_UINT8; - case GL_LUMINANCE16UI_EXT: - return MESA_FORMAT_LUMINANCE_UINT16; - case GL_LUMINANCE32UI_EXT: - return MESA_FORMAT_LUMINANCE_UINT32; - case GL_LUMINANCE8_ALPHA8: - return MESA_FORMAT_AL88; - case GL_LUMINANCE16_ALPHA16: - return MESA_FORMAT_AL1616; - case GL_LUMINANCE_ALPHA16F_ARB: - return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16; - case GL_LUMINANCE_ALPHA32F_ARB: - return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32; - case GL_LUMINANCE_ALPHA8I_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_INT8; - case GL_LUMINANCE_ALPHA16I_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_INT8; - case GL_LUMINANCE_ALPHA32I_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_INT16; - case GL_LUMINANCE_ALPHA8UI_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_UINT8; - case GL_LUMINANCE_ALPHA16UI_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_UINT16; - case GL_LUMINANCE_ALPHA32UI_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_UINT32; - case GL_INTENSITY8: - return MESA_FORMAT_I8; - case GL_INTENSITY16: - return MESA_FORMAT_I16; - case GL_INTENSITY16F_ARB: - return MESA_FORMAT_INTENSITY_FLOAT16; - case GL_INTENSITY32F_ARB: - return MESA_FORMAT_INTENSITY_FLOAT32; - case GL_INTENSITY8I_EXT: - return MESA_FORMAT_INTENSITY_INT8; - case GL_INTENSITY16I_EXT: - return MESA_FORMAT_INTENSITY_INT16; - case GL_INTENSITY32I_EXT: - return MESA_FORMAT_INTENSITY_INT32; - case GL_INTENSITY8UI_EXT: - return MESA_FORMAT_INTENSITY_UINT8; - case GL_INTENSITY16UI_EXT: - return MESA_FORMAT_INTENSITY_UINT16; - case GL_INTENSITY32UI_EXT: - return MESA_FORMAT_INTENSITY_UINT32; case GL_RGBA8: - return MESA_FORMAT_RGBA8888_REV; + return MESA_FORMAT_R8G8B8A8_UNORM; case GL_RGBA16: - return MESA_FORMAT_RGBA_16; + return MESA_FORMAT_RGBA_UNORM16; case GL_RGBA16F_ARB: return MESA_FORMAT_RGBA_FLOAT16; case GL_RGBA32F_ARB: return MESA_FORMAT_RGBA_FLOAT32; case GL_RGBA8I_EXT: - return MESA_FORMAT_RGBA_INT8; + return MESA_FORMAT_RGBA_SINT8; case GL_RGBA16I_EXT: - return MESA_FORMAT_RGBA_INT16; + return MESA_FORMAT_RGBA_SINT16; case GL_RGBA32I_EXT: - return MESA_FORMAT_RGBA_INT32; + return MESA_FORMAT_RGBA_SINT32; case GL_RGBA8UI_EXT: return MESA_FORMAT_RGBA_UINT8; case GL_RGBA16UI_EXT: @@ -3974,19 +4562,19 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) return MESA_FORMAT_RGBA_UINT32; case GL_RG8: - return MESA_FORMAT_GR88; + return MESA_FORMAT_R8G8_UNORM; case GL_RG16: - return MESA_FORMAT_GR1616; + return MESA_FORMAT_R16G16_UNORM; case GL_RG16F: return MESA_FORMAT_RG_FLOAT16; case GL_RG32F: return MESA_FORMAT_RG_FLOAT32; case GL_RG8I: - return MESA_FORMAT_RG_INT8; + return MESA_FORMAT_RG_SINT8; case GL_RG16I: - return MESA_FORMAT_RG_INT16; + return MESA_FORMAT_RG_SINT16; case GL_RG32I: - return MESA_FORMAT_RG_INT32; + return MESA_FORMAT_RG_SINT32; case GL_RG8UI: return MESA_FORMAT_RG_UINT8; case GL_RG16UI: @@ -3995,19 +4583,19 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) return MESA_FORMAT_RG_UINT32; case GL_R8: - return MESA_FORMAT_R8; + return MESA_FORMAT_R_UNORM8; case GL_R16: - return MESA_FORMAT_R16; + return MESA_FORMAT_R_UNORM16; case GL_R16F: return MESA_FORMAT_R_FLOAT16; case GL_R32F: return MESA_FORMAT_R_FLOAT32; case GL_R8I: - return MESA_FORMAT_R_INT8; + return MESA_FORMAT_R_SINT8; case GL_R16I: - return MESA_FORMAT_R_INT16; + return MESA_FORMAT_R_SINT16; case GL_R32I: - return MESA_FORMAT_R_INT32; + return MESA_FORMAT_R_SINT32; case GL_R8UI: return MESA_FORMAT_R_UINT8; case GL_R16UI: @@ -4015,43 +4603,41 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) 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) + +mesa_format +_mesa_validate_texbuffer_format(const struct gl_context *ctx, + GLenum internalFormat) { - gl_format format = get_texbuffer_format(ctx, internalFormat); + mesa_format format = get_texbuffer_format(ctx, internalFormat); GLenum datatype; if (format == MESA_FORMAT_NONE) return MESA_FORMAT_NONE; datatype = _mesa_get_format_datatype(format); - if (datatype == GL_FLOAT && !ctx->Extensions.ARB_texture_float) - return MESA_FORMAT_NONE; - if (datatype == GL_HALF_FLOAT && !ctx->Extensions.ARB_half_float_pixel) + /* The GL_ARB_texture_buffer_object spec says: + * + * "If ARB_texture_float is not supported, references to the + * floating-point internal formats provided by that extension should be + * removed, and such formats may not be passed to TexBufferARB." + * + * As a result, GL_HALF_FLOAT internal format depends on both + * GL_ARB_texture_float and GL_ARB_half_float_pixel. + */ + if ((datatype == GL_FLOAT || datatype == GL_HALF_FLOAT) && + !ctx->Extensions.ARB_texture_float) return MESA_FORMAT_NONE; - /* The GL_ARB_texture_rg and GL_ARB_texture_buffer_object specs don't make - * any mention of R/RG formats, but they appear in the GL 3.1 core - * specification. - */ - if (ctx->Version <= 30) { + if (!ctx->Extensions.ARB_texture_rg) { GLenum base_format = _mesa_get_format_base_format(format); - if (base_format == GL_R || base_format == GL_RG) - return MESA_FORMAT_NONE; + return MESA_FORMAT_NONE; } if (!ctx->Extensions.ARB_texture_buffer_object_rgb32) { @@ -4069,7 +4655,7 @@ texbufferrange(struct gl_context *ctx, GLenum target, GLenum internalFormat, GLintptr offset, GLsizeiptr size) { struct gl_texture_object *texObj; - gl_format format; + mesa_format format; FLUSH_VERTICES(ctx, 0); @@ -4078,7 +4664,7 @@ texbufferrange(struct gl_context *ctx, GLenum target, GLenum internalFormat, return; } - format = validate_texbuffer_format(ctx, internalFormat); + format = _mesa_validate_texbuffer_format(ctx, internalFormat); if (format == MESA_FORMAT_NONE) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(internalFormat 0x%x)", internalFormat); @@ -4098,6 +4684,7 @@ texbufferrange(struct gl_context *ctx, GLenum target, GLenum internalFormat, _mesa_unlock_texture(ctx, texObj); } + /** GL_ARB_texture_buffer_object */ void GLAPIENTRY _mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer) @@ -4124,6 +4711,7 @@ _mesa_TexBuffer(GLenum target, GLenum internalFormat, GLuint buffer) texbufferrange(ctx, target, internalFormat, bufObj, 0, buffer ? -1 : 0); } + /** GL_ARB_texture_buffer_range */ void GLAPIENTRY _mesa_TexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer, @@ -4164,6 +4752,7 @@ _mesa_TexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer, texbufferrange(ctx, target, internalFormat, bufObj, offset, size); } + static GLboolean is_renderable_texture_format(struct gl_context *ctx, GLenum internalformat) { @@ -4174,6 +4763,7 @@ is_renderable_texture_format(struct gl_context *ctx, GLenum internalformat) return baseFormat != 0 && baseFormat != GL_STENCIL_INDEX; } + /** GL_ARB_texture_multisample */ static GLboolean check_multisample_target(GLuint dims, GLenum target) @@ -4192,6 +4782,7 @@ check_multisample_target(GLuint dims, GLenum target) } } + static void teximagemultisample(GLuint dims, GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, @@ -4200,8 +4791,8 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, { struct gl_texture_object *texObj; struct gl_texture_image *texImage; - GLboolean sizeOK, dimensionsOK; - gl_format texFormat; + GLboolean sizeOK, dimensionsOK, samplesOK; + mesa_format texFormat; GLenum sample_count_error; GET_CURRENT_CONTEXT(ctx); @@ -4237,7 +4828,17 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, sample_count_error = _mesa_check_sample_count(ctx, target, internalformat, samples); - if (sample_count_error != GL_NO_ERROR) { + samplesOK = sample_count_error == GL_NO_ERROR; + + /* Page 254 of OpenGL 4.4 spec says: + * "Proxy arrays for two-dimensional multisample and two-dimensional + * multisample array textures are operated on in the same way when + * TexImage2DMultisample is called with target specified as + * PROXY_TEXTURE_2D_MULTISAMPLE, or TexImage3DMultisample is called + * with target specified as PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY. + * However, if samples is not supported, then no error is generated. + */ + if (!samplesOK && !_mesa_is_proxy_texture(target)) { _mesa_error(ctx, sample_count_error, "%s(samples)", func); return; } @@ -4269,16 +4870,14 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, 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; + if (samplesOK && dimensionsOK && sizeOK) { + init_teximage_fields_ms(ctx, texImage, width, height, depth, 0, + internalformat, texFormat, + samples, fixedsamplelocations); } else { /* clear all image fields */ - _mesa_init_teximage_fields(ctx, texImage, - 0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE); + clear_teximage_fields(texImage); } } else { @@ -4302,14 +4901,11 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, ctx->Driver.FreeTextureImageBuffer(ctx, texImage); - _mesa_init_teximage_fields(ctx, texImage, - width, height, depth, 0, internalformat, texFormat); - - texImage->NumSamples = samples; - texImage->FixedSampleLocations = fixedsamplelocations; + init_teximage_fields_ms(ctx, texImage, width, height, depth, 0, + internalformat, texFormat, + samples, 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, @@ -4322,27 +4918,36 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, } texObj->Immutable = immutable; + + if (immutable) { + _mesa_set_texture_view_state(ctx, texObj, target, 1); + } + _mesa_update_fbo_texture(ctx, texObj, 0, 0); } } + void GLAPIENTRY _mesa_TexImage2DMultisample(GLenum target, GLsizei samples, - GLint internalformat, GLsizei width, + GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) { teximagemultisample(2, target, samples, internalformat, - width, height, 1, fixedsamplelocations, GL_FALSE, "glTexImage2DMultisample"); + width, height, 1, fixedsamplelocations, GL_FALSE, + "glTexImage2DMultisample"); } + void GLAPIENTRY _mesa_TexImage3DMultisample(GLenum target, GLsizei samples, - GLint internalformat, GLsizei width, + GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) { teximagemultisample(3, target, samples, internalformat, - width, height, depth, fixedsamplelocations, GL_FALSE, "glTexImage3DMultisample"); + width, height, depth, fixedsamplelocations, GL_FALSE, + "glTexImage3DMultisample"); } @@ -4352,7 +4957,8 @@ _mesa_TexStorage2DMultisample(GLenum target, GLsizei samples, GLsizei height, GLboolean fixedsamplelocations) { teximagemultisample(2, target, samples, internalformat, - width, height, 1, fixedsamplelocations, GL_TRUE, "glTexStorage2DMultisample"); + width, height, 1, fixedsamplelocations, GL_TRUE, + "glTexStorage2DMultisample"); } void GLAPIENTRY @@ -4362,5 +4968,6 @@ _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples, GLboolean fixedsamplelocations) { teximagemultisample(3, target, samples, internalformat, - width, height, depth, fixedsamplelocations, GL_TRUE, "glTexStorage3DMultisample"); + width, height, depth, fixedsamplelocations, GL_TRUE, + "glTexStorage3DMultisample"); }