texobj.c revision af69d88d
17117f1b4Smrg/** 27117f1b4Smrg * \file texobj.c 37117f1b4Smrg * Texture object management. 47117f1b4Smrg */ 57117f1b4Smrg 67117f1b4Smrg/* 77117f1b4Smrg * Mesa 3-D graphics library 87117f1b4Smrg * 9c1f859d4Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 107117f1b4Smrg * 117117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 127117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 137117f1b4Smrg * to deal in the Software without restriction, including without limitation 147117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 157117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 167117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 177117f1b4Smrg * 187117f1b4Smrg * The above copyright notice and this permission notice shall be included 197117f1b4Smrg * in all copies or substantial portions of the Software. 207117f1b4Smrg * 217117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 227117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 237117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 287117f1b4Smrg */ 297117f1b4Smrg 307117f1b4Smrg 313464ebd5Sriastradh#include "bufferobj.h" 327117f1b4Smrg#include "colortab.h" 337117f1b4Smrg#include "context.h" 347117f1b4Smrg#include "enums.h" 357117f1b4Smrg#include "fbobject.h" 364a49301eSmrg#include "formats.h" 377117f1b4Smrg#include "hash.h" 387117f1b4Smrg#include "imports.h" 397117f1b4Smrg#include "macros.h" 407117f1b4Smrg#include "teximage.h" 417117f1b4Smrg#include "texobj.h" 423464ebd5Sriastradh#include "texstate.h" 437117f1b4Smrg#include "mtypes.h" 443464ebd5Sriastradh#include "program/prog_instruction.h" 454a49301eSmrg 467117f1b4Smrg 477117f1b4Smrg 487117f1b4Smrg/**********************************************************************/ 497117f1b4Smrg/** \name Internal functions */ 507117f1b4Smrg/*@{*/ 517117f1b4Smrg 527117f1b4Smrg 537117f1b4Smrg/** 547117f1b4Smrg * Return the gl_texture_object for a given ID. 557117f1b4Smrg */ 567117f1b4Smrgstruct gl_texture_object * 573464ebd5Sriastradh_mesa_lookup_texture(struct gl_context *ctx, GLuint id) 587117f1b4Smrg{ 597117f1b4Smrg return (struct gl_texture_object *) 607117f1b4Smrg _mesa_HashLookup(ctx->Shared->TexObjects, id); 617117f1b4Smrg} 627117f1b4Smrg 637117f1b4Smrg 64af69d88dSmrgvoid 65af69d88dSmrg_mesa_begin_texture_lookups(struct gl_context *ctx) 66af69d88dSmrg{ 67af69d88dSmrg _mesa_HashLockMutex(ctx->Shared->TexObjects); 68af69d88dSmrg} 69af69d88dSmrg 70af69d88dSmrg 71af69d88dSmrgvoid 72af69d88dSmrg_mesa_end_texture_lookups(struct gl_context *ctx) 73af69d88dSmrg{ 74af69d88dSmrg _mesa_HashUnlockMutex(ctx->Shared->TexObjects); 75af69d88dSmrg} 76af69d88dSmrg 77af69d88dSmrg 78af69d88dSmrgstruct gl_texture_object * 79af69d88dSmrg_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id) 80af69d88dSmrg{ 81af69d88dSmrg return (struct gl_texture_object *) 82af69d88dSmrg _mesa_HashLookupLocked(ctx->Shared->TexObjects, id); 83af69d88dSmrg} 84af69d88dSmrg 857117f1b4Smrg 867117f1b4Smrg/** 877117f1b4Smrg * Allocate and initialize a new texture object. But don't put it into the 887117f1b4Smrg * texture object hash table. 897117f1b4Smrg * 907117f1b4Smrg * Called via ctx->Driver.NewTextureObject, unless overridden by a device 917117f1b4Smrg * driver. 927117f1b4Smrg * 937117f1b4Smrg * \param shared the shared GL state structure to contain the texture object 947117f1b4Smrg * \param name integer name for the texture object 957117f1b4Smrg * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, 967117f1b4Smrg * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake 977117f1b4Smrg * of GenTextures() 987117f1b4Smrg * 997117f1b4Smrg * \return pointer to new texture object. 1007117f1b4Smrg */ 1017117f1b4Smrgstruct gl_texture_object * 1023464ebd5Sriastradh_mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target ) 1037117f1b4Smrg{ 1047117f1b4Smrg struct gl_texture_object *obj; 1057117f1b4Smrg (void) ctx; 1067117f1b4Smrg obj = MALLOC_STRUCT(gl_texture_object); 107af69d88dSmrg _mesa_initialize_texture_object(ctx, obj, name, target); 1087117f1b4Smrg return obj; 1097117f1b4Smrg} 1107117f1b4Smrg 1117117f1b4Smrg 1127117f1b4Smrg/** 1137117f1b4Smrg * Initialize a new texture object to default values. 1147117f1b4Smrg * \param obj the texture object 1157117f1b4Smrg * \param name the texture name 1167117f1b4Smrg * \param target the texture target 1177117f1b4Smrg */ 1187117f1b4Smrgvoid 119af69d88dSmrg_mesa_initialize_texture_object( struct gl_context *ctx, 120af69d88dSmrg struct gl_texture_object *obj, 1217117f1b4Smrg GLuint name, GLenum target ) 1227117f1b4Smrg{ 1237117f1b4Smrg ASSERT(target == 0 || 1247117f1b4Smrg target == GL_TEXTURE_1D || 1257117f1b4Smrg target == GL_TEXTURE_2D || 1267117f1b4Smrg target == GL_TEXTURE_3D || 1277117f1b4Smrg target == GL_TEXTURE_CUBE_MAP_ARB || 128c1f859d4Smrg target == GL_TEXTURE_RECTANGLE_NV || 129c1f859d4Smrg target == GL_TEXTURE_1D_ARRAY_EXT || 1303464ebd5Sriastradh target == GL_TEXTURE_2D_ARRAY_EXT || 131af69d88dSmrg target == GL_TEXTURE_EXTERNAL_OES || 132af69d88dSmrg target == GL_TEXTURE_CUBE_MAP_ARRAY || 133af69d88dSmrg target == GL_TEXTURE_BUFFER || 134af69d88dSmrg target == GL_TEXTURE_2D_MULTISAMPLE || 135af69d88dSmrg target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); 1367117f1b4Smrg 137cdc920a0Smrg memset(obj, 0, sizeof(*obj)); 1387117f1b4Smrg /* init the non-zero fields */ 139af69d88dSmrg mtx_init(&obj->Mutex, mtx_plain); 1407117f1b4Smrg obj->RefCount = 1; 1417117f1b4Smrg obj->Name = name; 1427117f1b4Smrg obj->Target = target; 1437117f1b4Smrg obj->Priority = 1.0F; 1443464ebd5Sriastradh obj->BaseLevel = 0; 1453464ebd5Sriastradh obj->MaxLevel = 1000; 1463464ebd5Sriastradh 147af69d88dSmrg /* must be one; no support for (YUV) planes in separate buffers */ 148af69d88dSmrg obj->RequiredTextureImageUnits = 1; 149af69d88dSmrg 1503464ebd5Sriastradh /* sampler state */ 151af69d88dSmrg if (target == GL_TEXTURE_RECTANGLE_NV || 152af69d88dSmrg target == GL_TEXTURE_EXTERNAL_OES) { 1533464ebd5Sriastradh obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; 1543464ebd5Sriastradh obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; 1553464ebd5Sriastradh obj->Sampler.WrapR = GL_CLAMP_TO_EDGE; 1563464ebd5Sriastradh obj->Sampler.MinFilter = GL_LINEAR; 1577117f1b4Smrg } 1587117f1b4Smrg else { 1593464ebd5Sriastradh obj->Sampler.WrapS = GL_REPEAT; 1603464ebd5Sriastradh obj->Sampler.WrapT = GL_REPEAT; 1613464ebd5Sriastradh obj->Sampler.WrapR = GL_REPEAT; 1623464ebd5Sriastradh obj->Sampler.MinFilter = GL_NEAREST_MIPMAP_LINEAR; 1637117f1b4Smrg } 1643464ebd5Sriastradh obj->Sampler.MagFilter = GL_LINEAR; 1653464ebd5Sriastradh obj->Sampler.MinLod = -1000.0; 1663464ebd5Sriastradh obj->Sampler.MaxLod = 1000.0; 1673464ebd5Sriastradh obj->Sampler.LodBias = 0.0; 1683464ebd5Sriastradh obj->Sampler.MaxAnisotropy = 1.0; 1693464ebd5Sriastradh obj->Sampler.CompareMode = GL_NONE; /* ARB_shadow */ 1703464ebd5Sriastradh obj->Sampler.CompareFunc = GL_LEQUAL; /* ARB_shadow */ 171af69d88dSmrg obj->DepthMode = ctx->API == API_OPENGL_CORE ? GL_RED : GL_LUMINANCE; 172af69d88dSmrg obj->StencilSampling = false; 1733464ebd5Sriastradh obj->Sampler.CubeMapSeamless = GL_FALSE; 1744a49301eSmrg obj->Swizzle[0] = GL_RED; 1754a49301eSmrg obj->Swizzle[1] = GL_GREEN; 1764a49301eSmrg obj->Swizzle[2] = GL_BLUE; 1774a49301eSmrg obj->Swizzle[3] = GL_ALPHA; 1784a49301eSmrg obj->_Swizzle = SWIZZLE_NOOP; 1793464ebd5Sriastradh obj->Sampler.sRGBDecode = GL_DECODE_EXT; 180af69d88dSmrg obj->BufferObjectFormat = GL_R8; 181af69d88dSmrg obj->_BufferObjectFormat = MESA_FORMAT_R_UNORM8; 182af69d88dSmrg obj->ImageFormatCompatibilityType = GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE; 183c1f859d4Smrg} 184c1f859d4Smrg 185c1f859d4Smrg 186c1f859d4Smrg/** 187c1f859d4Smrg * Some texture initialization can't be finished until we know which 188c1f859d4Smrg * target it's getting bound to (GL_TEXTURE_1D/2D/etc). 189c1f859d4Smrg */ 190c1f859d4Smrgstatic void 1913464ebd5Sriastradhfinish_texture_init(struct gl_context *ctx, GLenum target, 192c1f859d4Smrg struct gl_texture_object *obj) 193c1f859d4Smrg{ 194af69d88dSmrg GLenum filter = GL_LINEAR; 195c1f859d4Smrg assert(obj->Target == 0); 196c1f859d4Smrg 197af69d88dSmrg switch (target) { 198af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 199af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 200af69d88dSmrg filter = GL_NEAREST; 201af69d88dSmrg /* fallthrough */ 202af69d88dSmrg 203af69d88dSmrg case GL_TEXTURE_RECTANGLE_NV: 204af69d88dSmrg case GL_TEXTURE_EXTERNAL_OES: 205af69d88dSmrg /* have to init wrap and filter state here - kind of klunky */ 206af69d88dSmrg obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; 207af69d88dSmrg obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; 208af69d88dSmrg obj->Sampler.WrapR = GL_CLAMP_TO_EDGE; 209af69d88dSmrg obj->Sampler.MinFilter = filter; 210af69d88dSmrg obj->Sampler.MagFilter = filter; 211af69d88dSmrg if (ctx->Driver.TexParameter) { 212af69d88dSmrg static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE}; 213af69d88dSmrg const GLfloat fparam_filter[1] = {(GLfloat) filter}; 214af69d88dSmrg ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_S, fparam_wrap); 215af69d88dSmrg ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_T, fparam_wrap); 216af69d88dSmrg ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_R, fparam_wrap); 217af69d88dSmrg ctx->Driver.TexParameter(ctx, obj, 218af69d88dSmrg GL_TEXTURE_MIN_FILTER, fparam_filter); 219af69d88dSmrg ctx->Driver.TexParameter(ctx, obj, 220af69d88dSmrg GL_TEXTURE_MAG_FILTER, fparam_filter); 221af69d88dSmrg } 222af69d88dSmrg break; 223af69d88dSmrg 224af69d88dSmrg default: 225af69d88dSmrg /* nothing needs done */ 226af69d88dSmrg break; 227c1f859d4Smrg } 2287117f1b4Smrg} 2297117f1b4Smrg 2307117f1b4Smrg 2317117f1b4Smrg/** 2327117f1b4Smrg * Deallocate a texture object struct. It should have already been 2337117f1b4Smrg * removed from the texture object pool. 234c1f859d4Smrg * Called via ctx->Driver.DeleteTexture() if not overriden by a driver. 2357117f1b4Smrg * 2367117f1b4Smrg * \param shared the shared GL state to which the object belongs. 2374a49301eSmrg * \param texObj the texture object to delete. 2387117f1b4Smrg */ 2397117f1b4Smrgvoid 2403464ebd5Sriastradh_mesa_delete_texture_object(struct gl_context *ctx, 2413464ebd5Sriastradh struct gl_texture_object *texObj) 2427117f1b4Smrg{ 2437117f1b4Smrg GLuint i, face; 2447117f1b4Smrg 2457117f1b4Smrg /* Set Target to an invalid value. With some assertions elsewhere 2467117f1b4Smrg * we can try to detect possible use of deleted textures. 2477117f1b4Smrg */ 2487117f1b4Smrg texObj->Target = 0x99; 2497117f1b4Smrg 2507117f1b4Smrg /* free the texture images */ 2517117f1b4Smrg for (face = 0; face < 6; face++) { 2527117f1b4Smrg for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 2533464ebd5Sriastradh if (texObj->Image[face][i]) { 254af69d88dSmrg ctx->Driver.DeleteTextureImage(ctx, texObj->Image[face][i]); 2553464ebd5Sriastradh } 2567117f1b4Smrg } 2577117f1b4Smrg } 2587117f1b4Smrg 2593464ebd5Sriastradh _mesa_reference_buffer_object(ctx, &texObj->BufferObject, NULL); 2603464ebd5Sriastradh 2617117f1b4Smrg /* destroy the mutex -- it may have allocated memory (eg on bsd) */ 262af69d88dSmrg mtx_destroy(&texObj->Mutex); 263af69d88dSmrg 264af69d88dSmrg free(texObj->Label); 2657117f1b4Smrg 2667117f1b4Smrg /* free this object */ 267cdc920a0Smrg free(texObj); 2687117f1b4Smrg} 2697117f1b4Smrg 2707117f1b4Smrg 2717117f1b4Smrg 2727117f1b4Smrg/** 2737117f1b4Smrg * Copy texture object state from one texture object to another. 2747117f1b4Smrg * Use for glPush/PopAttrib. 2757117f1b4Smrg * 2767117f1b4Smrg * \param dest destination texture object. 2777117f1b4Smrg * \param src source texture object. 2787117f1b4Smrg */ 2797117f1b4Smrgvoid 2807117f1b4Smrg_mesa_copy_texture_object( struct gl_texture_object *dest, 2817117f1b4Smrg const struct gl_texture_object *src ) 2827117f1b4Smrg{ 2837117f1b4Smrg dest->Target = src->Target; 284af69d88dSmrg dest->TargetIndex = src->TargetIndex; 2857117f1b4Smrg dest->Name = src->Name; 2867117f1b4Smrg dest->Priority = src->Priority; 2873464ebd5Sriastradh dest->Sampler.BorderColor.f[0] = src->Sampler.BorderColor.f[0]; 2883464ebd5Sriastradh dest->Sampler.BorderColor.f[1] = src->Sampler.BorderColor.f[1]; 2893464ebd5Sriastradh dest->Sampler.BorderColor.f[2] = src->Sampler.BorderColor.f[2]; 2903464ebd5Sriastradh dest->Sampler.BorderColor.f[3] = src->Sampler.BorderColor.f[3]; 2913464ebd5Sriastradh dest->Sampler.WrapS = src->Sampler.WrapS; 2923464ebd5Sriastradh dest->Sampler.WrapT = src->Sampler.WrapT; 2933464ebd5Sriastradh dest->Sampler.WrapR = src->Sampler.WrapR; 2943464ebd5Sriastradh dest->Sampler.MinFilter = src->Sampler.MinFilter; 2953464ebd5Sriastradh dest->Sampler.MagFilter = src->Sampler.MagFilter; 2963464ebd5Sriastradh dest->Sampler.MinLod = src->Sampler.MinLod; 2973464ebd5Sriastradh dest->Sampler.MaxLod = src->Sampler.MaxLod; 2983464ebd5Sriastradh dest->Sampler.LodBias = src->Sampler.LodBias; 2997117f1b4Smrg dest->BaseLevel = src->BaseLevel; 3007117f1b4Smrg dest->MaxLevel = src->MaxLevel; 3013464ebd5Sriastradh dest->Sampler.MaxAnisotropy = src->Sampler.MaxAnisotropy; 3023464ebd5Sriastradh dest->Sampler.CompareMode = src->Sampler.CompareMode; 3033464ebd5Sriastradh dest->Sampler.CompareFunc = src->Sampler.CompareFunc; 3043464ebd5Sriastradh dest->Sampler.CubeMapSeamless = src->Sampler.CubeMapSeamless; 305af69d88dSmrg dest->DepthMode = src->DepthMode; 306af69d88dSmrg dest->StencilSampling = src->StencilSampling; 3073464ebd5Sriastradh dest->Sampler.sRGBDecode = src->Sampler.sRGBDecode; 3087117f1b4Smrg dest->_MaxLevel = src->_MaxLevel; 3097117f1b4Smrg dest->_MaxLambda = src->_MaxLambda; 3107117f1b4Smrg dest->GenerateMipmap = src->GenerateMipmap; 311af69d88dSmrg dest->_BaseComplete = src->_BaseComplete; 312af69d88dSmrg dest->_MipmapComplete = src->_MipmapComplete; 3134a49301eSmrg COPY_4V(dest->Swizzle, src->Swizzle); 3144a49301eSmrg dest->_Swizzle = src->_Swizzle; 315af69d88dSmrg 316af69d88dSmrg dest->RequiredTextureImageUnits = src->RequiredTextureImageUnits; 3174a49301eSmrg} 3184a49301eSmrg 3194a49301eSmrg 3204a49301eSmrg/** 3213464ebd5Sriastradh * Free all texture images of the given texture object. 3224a49301eSmrg * 3234a49301eSmrg * \param ctx GL context. 3244a49301eSmrg * \param t texture object. 3254a49301eSmrg * 3264a49301eSmrg * \sa _mesa_clear_texture_image(). 3274a49301eSmrg */ 3284a49301eSmrgvoid 3293464ebd5Sriastradh_mesa_clear_texture_object(struct gl_context *ctx, 3303464ebd5Sriastradh struct gl_texture_object *texObj) 3314a49301eSmrg{ 3324a49301eSmrg GLuint i, j; 3334a49301eSmrg 3344a49301eSmrg if (texObj->Target == 0) 3354a49301eSmrg return; 3364a49301eSmrg 3374a49301eSmrg for (i = 0; i < MAX_FACES; i++) { 3384a49301eSmrg for (j = 0; j < MAX_TEXTURE_LEVELS; j++) { 3394a49301eSmrg struct gl_texture_image *texImage = texObj->Image[i][j]; 3404a49301eSmrg if (texImage) 3414a49301eSmrg _mesa_clear_texture_image(ctx, texImage); 3424a49301eSmrg } 3434a49301eSmrg } 3447117f1b4Smrg} 3457117f1b4Smrg 3467117f1b4Smrg 3477117f1b4Smrg/** 3487117f1b4Smrg * Check if the given texture object is valid by examining its Target field. 3497117f1b4Smrg * For debugging only. 3507117f1b4Smrg */ 3517117f1b4Smrgstatic GLboolean 3527117f1b4Smrgvalid_texture_object(const struct gl_texture_object *tex) 3537117f1b4Smrg{ 3547117f1b4Smrg switch (tex->Target) { 3557117f1b4Smrg case 0: 3567117f1b4Smrg case GL_TEXTURE_1D: 3577117f1b4Smrg case GL_TEXTURE_2D: 3587117f1b4Smrg case GL_TEXTURE_3D: 3597117f1b4Smrg case GL_TEXTURE_CUBE_MAP_ARB: 3607117f1b4Smrg case GL_TEXTURE_RECTANGLE_NV: 361c1f859d4Smrg case GL_TEXTURE_1D_ARRAY_EXT: 362c1f859d4Smrg case GL_TEXTURE_2D_ARRAY_EXT: 3633464ebd5Sriastradh case GL_TEXTURE_BUFFER: 364af69d88dSmrg case GL_TEXTURE_EXTERNAL_OES: 365af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 366af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 367af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 3687117f1b4Smrg return GL_TRUE; 3697117f1b4Smrg case 0x99: 3707117f1b4Smrg _mesa_problem(NULL, "invalid reference to a deleted texture object"); 3717117f1b4Smrg return GL_FALSE; 3727117f1b4Smrg default: 3734a49301eSmrg _mesa_problem(NULL, "invalid texture object Target 0x%x, Id = %u", 3744a49301eSmrg tex->Target, tex->Name); 3757117f1b4Smrg return GL_FALSE; 3767117f1b4Smrg } 3777117f1b4Smrg} 3787117f1b4Smrg 3797117f1b4Smrg 3807117f1b4Smrg/** 3817117f1b4Smrg * Reference (or unreference) a texture object. 3827117f1b4Smrg * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero). 3837117f1b4Smrg * If 'tex' is non-null, increment its refcount. 384af69d88dSmrg * This is normally only called from the _mesa_reference_texobj() macro 385af69d88dSmrg * when there's a real pointer change. 3867117f1b4Smrg */ 3877117f1b4Smrgvoid 388af69d88dSmrg_mesa_reference_texobj_(struct gl_texture_object **ptr, 389af69d88dSmrg struct gl_texture_object *tex) 3907117f1b4Smrg{ 3917117f1b4Smrg assert(ptr); 3927117f1b4Smrg 3937117f1b4Smrg if (*ptr) { 3947117f1b4Smrg /* Unreference the old texture */ 3957117f1b4Smrg GLboolean deleteFlag = GL_FALSE; 3967117f1b4Smrg struct gl_texture_object *oldTex = *ptr; 3977117f1b4Smrg 3984a49301eSmrg ASSERT(valid_texture_object(oldTex)); 3993464ebd5Sriastradh (void) valid_texture_object; /* silence warning in release builds */ 4007117f1b4Smrg 401af69d88dSmrg mtx_lock(&oldTex->Mutex); 4027117f1b4Smrg ASSERT(oldTex->RefCount > 0); 4037117f1b4Smrg oldTex->RefCount--; 4047117f1b4Smrg 4057117f1b4Smrg deleteFlag = (oldTex->RefCount == 0); 406af69d88dSmrg mtx_unlock(&oldTex->Mutex); 4077117f1b4Smrg 4087117f1b4Smrg if (deleteFlag) { 4097117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 4107117f1b4Smrg if (ctx) 4117117f1b4Smrg ctx->Driver.DeleteTexture(ctx, oldTex); 4127117f1b4Smrg else 4137117f1b4Smrg _mesa_problem(NULL, "Unable to delete texture, no context"); 4147117f1b4Smrg } 4157117f1b4Smrg 4167117f1b4Smrg *ptr = NULL; 4177117f1b4Smrg } 4187117f1b4Smrg assert(!*ptr); 4197117f1b4Smrg 4207117f1b4Smrg if (tex) { 4217117f1b4Smrg /* reference new texture */ 4224a49301eSmrg ASSERT(valid_texture_object(tex)); 423af69d88dSmrg mtx_lock(&tex->Mutex); 4247117f1b4Smrg if (tex->RefCount == 0) { 4257117f1b4Smrg /* this texture's being deleted (look just above) */ 4267117f1b4Smrg /* Not sure this can every really happen. Warn if it does. */ 4277117f1b4Smrg _mesa_problem(NULL, "referencing deleted texture object"); 4287117f1b4Smrg *ptr = NULL; 4297117f1b4Smrg } 4307117f1b4Smrg else { 4317117f1b4Smrg tex->RefCount++; 4327117f1b4Smrg *ptr = tex; 4337117f1b4Smrg } 434af69d88dSmrg mtx_unlock(&tex->Mutex); 4357117f1b4Smrg } 4367117f1b4Smrg} 4377117f1b4Smrg 4387117f1b4Smrg 439af69d88dSmrgenum base_mipmap { BASE, MIPMAP }; 440af69d88dSmrg 4417117f1b4Smrg 4427117f1b4Smrg/** 443af69d88dSmrg * Mark a texture object as incomplete. There are actually three kinds of 444af69d88dSmrg * (in)completeness: 445af69d88dSmrg * 1. "base incomplete": the base level of the texture is invalid so no 446af69d88dSmrg * texturing is possible. 447af69d88dSmrg * 2. "mipmap incomplete": a non-base level of the texture is invalid so 448af69d88dSmrg * mipmap filtering isn't possible, but non-mipmap filtering is. 449af69d88dSmrg * 3. "texture incompleteness": some combination of texture state and 450af69d88dSmrg * sampler state renders the texture incomplete. 451af69d88dSmrg * 4523464ebd5Sriastradh * \param t texture object 453af69d88dSmrg * \param bm either BASE or MIPMAP to indicate what's incomplete 4543464ebd5Sriastradh * \param fmt... string describing why it's incomplete (for debugging). 4557117f1b4Smrg */ 4567117f1b4Smrgstatic void 457af69d88dSmrgincomplete(struct gl_texture_object *t, enum base_mipmap bm, 458af69d88dSmrg const char *fmt, ...) 4597117f1b4Smrg{ 460af69d88dSmrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_TEXTURE) { 461af69d88dSmrg va_list args; 462af69d88dSmrg char s[100]; 4633464ebd5Sriastradh 464af69d88dSmrg va_start(args, fmt); 465af69d88dSmrg vsnprintf(s, sizeof(s), fmt, args); 466af69d88dSmrg va_end(args); 467af69d88dSmrg 468af69d88dSmrg _mesa_debug(NULL, "Texture Obj %d incomplete because: %s\n", t->Name, s); 469af69d88dSmrg } 4703464ebd5Sriastradh 471af69d88dSmrg if (bm == BASE) 472af69d88dSmrg t->_BaseComplete = GL_FALSE; 473af69d88dSmrg t->_MipmapComplete = GL_FALSE; 4743464ebd5Sriastradh} 4757117f1b4Smrg 4767117f1b4Smrg 4777117f1b4Smrg/** 4787117f1b4Smrg * Examine a texture object to determine if it is complete. 4797117f1b4Smrg * 4807117f1b4Smrg * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE 4817117f1b4Smrg * accordingly. 4827117f1b4Smrg * 4837117f1b4Smrg * \param ctx GL context. 4847117f1b4Smrg * \param t texture object. 4857117f1b4Smrg * 4867117f1b4Smrg * According to the texture target, verifies that each of the mipmaps is 4877117f1b4Smrg * present and has the expected size. 4887117f1b4Smrg */ 4897117f1b4Smrgvoid 4903464ebd5Sriastradh_mesa_test_texobj_completeness( const struct gl_context *ctx, 4917117f1b4Smrg struct gl_texture_object *t ) 4927117f1b4Smrg{ 4937117f1b4Smrg const GLint baseLevel = t->BaseLevel; 494af69d88dSmrg const struct gl_texture_image *baseImage; 495af69d88dSmrg GLint maxLevels = 0; 4967117f1b4Smrg 497af69d88dSmrg /* We'll set these to FALSE if tests fail below */ 498af69d88dSmrg t->_BaseComplete = GL_TRUE; 499af69d88dSmrg t->_MipmapComplete = GL_TRUE; 500af69d88dSmrg 501af69d88dSmrg if (t->Target == GL_TEXTURE_BUFFER) { 502af69d88dSmrg /* Buffer textures are always considered complete. The obvious case where 503af69d88dSmrg * they would be incomplete (no BO attached) is actually specced to be 504af69d88dSmrg * undefined rendering results. 505af69d88dSmrg */ 506af69d88dSmrg return; 507af69d88dSmrg } 508c1f859d4Smrg 509c1f859d4Smrg /* Detect cases where the application set the base level to an invalid 510c1f859d4Smrg * value. 511c1f859d4Smrg */ 5124a49301eSmrg if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) { 513af69d88dSmrg incomplete(t, BASE, "base level = %d is invalid", baseLevel); 514c1f859d4Smrg return; 515c1f859d4Smrg } 5167117f1b4Smrg 517af69d88dSmrg if (t->MaxLevel < baseLevel) { 518af69d88dSmrg incomplete(t, MIPMAP, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", 519af69d88dSmrg t->MaxLevel, baseLevel); 520af69d88dSmrg return; 521af69d88dSmrg } 522af69d88dSmrg 523af69d88dSmrg baseImage = t->Image[0][baseLevel]; 524af69d88dSmrg 5257117f1b4Smrg /* Always need the base level image */ 526af69d88dSmrg if (!baseImage) { 527af69d88dSmrg incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel); 5287117f1b4Smrg return; 5297117f1b4Smrg } 5307117f1b4Smrg 5317117f1b4Smrg /* Check width/height/depth for zero */ 532af69d88dSmrg if (baseImage->Width == 0 || 533af69d88dSmrg baseImage->Height == 0 || 534af69d88dSmrg baseImage->Depth == 0) { 535af69d88dSmrg incomplete(t, BASE, "texture width or height or depth = 0"); 5367117f1b4Smrg return; 5377117f1b4Smrg } 5387117f1b4Smrg 539af69d88dSmrg /* Check if the texture values are integer */ 540af69d88dSmrg { 541af69d88dSmrg GLenum datatype = _mesa_get_format_datatype(baseImage->TexFormat); 542af69d88dSmrg t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT; 5437117f1b4Smrg } 544af69d88dSmrg 545af69d88dSmrg /* Compute _MaxLevel (the maximum mipmap level we'll sample from given the 546af69d88dSmrg * mipmap image sizes and GL_TEXTURE_MAX_LEVEL state). 547af69d88dSmrg */ 548af69d88dSmrg switch (t->Target) { 549af69d88dSmrg case GL_TEXTURE_1D: 550af69d88dSmrg case GL_TEXTURE_1D_ARRAY_EXT: 5517117f1b4Smrg maxLevels = ctx->Const.MaxTextureLevels; 552af69d88dSmrg break; 553af69d88dSmrg case GL_TEXTURE_2D: 554af69d88dSmrg case GL_TEXTURE_2D_ARRAY_EXT: 555af69d88dSmrg maxLevels = ctx->Const.MaxTextureLevels; 556af69d88dSmrg break; 557af69d88dSmrg case GL_TEXTURE_3D: 5587117f1b4Smrg maxLevels = ctx->Const.Max3DTextureLevels; 559af69d88dSmrg break; 560af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARB: 561af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 5627117f1b4Smrg maxLevels = ctx->Const.MaxCubeTextureLevels; 563af69d88dSmrg break; 564af69d88dSmrg case GL_TEXTURE_RECTANGLE_NV: 565af69d88dSmrg case GL_TEXTURE_BUFFER: 566af69d88dSmrg case GL_TEXTURE_EXTERNAL_OES: 567af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 568af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 5697117f1b4Smrg maxLevels = 1; /* no mipmapping */ 570af69d88dSmrg break; 571af69d88dSmrg default: 5727117f1b4Smrg _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); 5737117f1b4Smrg return; 5747117f1b4Smrg } 5757117f1b4Smrg 5767117f1b4Smrg ASSERT(maxLevels > 0); 5777117f1b4Smrg 578af69d88dSmrg t->_MaxLevel = MIN3(t->MaxLevel, 579af69d88dSmrg /* 'p' in the GL spec */ 580af69d88dSmrg (int) (baseLevel + baseImage->MaxNumLevels - 1), 581af69d88dSmrg /* 'q' in the GL spec */ 582af69d88dSmrg maxLevels - 1); 583af69d88dSmrg 584af69d88dSmrg if (t->Immutable) { 585af69d88dSmrg /* Adjust max level for views: the data store may have more levels than 586af69d88dSmrg * the view exposes. 587af69d88dSmrg */ 588af69d88dSmrg t->_MaxLevel = MIN2(t->_MaxLevel, t->NumLevels - 1); 5893464ebd5Sriastradh } 5903464ebd5Sriastradh 591af69d88dSmrg /* Compute _MaxLambda = q - p in the spec used during mipmapping */ 592af69d88dSmrg t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel); 5937117f1b4Smrg 594af69d88dSmrg if (t->Immutable) { 595af69d88dSmrg /* This texture object was created with glTexStorage1/2/3D() so we 596af69d88dSmrg * know that all the mipmap levels are the right size and all cube 597af69d88dSmrg * map faces are the same size. 598af69d88dSmrg * We don't need to do any of the additional checks below. 599af69d88dSmrg */ 600af69d88dSmrg return; 601af69d88dSmrg } 6027117f1b4Smrg 6037117f1b4Smrg if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 604af69d88dSmrg /* Make sure that all six cube map level 0 images are the same size. 605af69d88dSmrg * Note: we know that the image's width==height (we enforce that 606af69d88dSmrg * at glTexImage time) so we only need to test the width here. 607af69d88dSmrg */ 6087117f1b4Smrg GLuint face; 609af69d88dSmrg assert(baseImage->Width2 == baseImage->Height); 6107117f1b4Smrg for (face = 1; face < 6; face++) { 611af69d88dSmrg assert(t->Image[face][baseLevel] == NULL || 612af69d88dSmrg t->Image[face][baseLevel]->Width2 == 613af69d88dSmrg t->Image[face][baseLevel]->Height2); 6143464ebd5Sriastradh if (t->Image[face][baseLevel] == NULL || 615af69d88dSmrg t->Image[face][baseLevel]->Width2 != baseImage->Width2) { 616af69d88dSmrg incomplete(t, BASE, "Cube face missing or mismatched size"); 6173464ebd5Sriastradh return; 6183464ebd5Sriastradh } 6197117f1b4Smrg } 6207117f1b4Smrg } 6217117f1b4Smrg 622af69d88dSmrg /* 623af69d88dSmrg * Do mipmap consistency checking. 624af69d88dSmrg * Note: we don't care about the current texture sampler state here. 625af69d88dSmrg * To determine texture completeness we'll either look at _BaseComplete 626af69d88dSmrg * or _MipmapComplete depending on the current minification filter mode. 627af69d88dSmrg */ 628af69d88dSmrg { 6297117f1b4Smrg GLint i; 630af69d88dSmrg const GLint minLevel = baseLevel; 631af69d88dSmrg const GLint maxLevel = t->_MaxLevel; 632af69d88dSmrg const GLuint numFaces = _mesa_num_tex_faces(t->Target); 633af69d88dSmrg GLuint width, height, depth, face; 6347117f1b4Smrg 6357117f1b4Smrg if (minLevel > maxLevel) { 636af69d88dSmrg incomplete(t, MIPMAP, "minLevel > maxLevel"); 6377117f1b4Smrg return; 6387117f1b4Smrg } 6397117f1b4Smrg 640af69d88dSmrg /* Get the base image's dimensions */ 641af69d88dSmrg width = baseImage->Width2; 642af69d88dSmrg height = baseImage->Height2; 643af69d88dSmrg depth = baseImage->Depth2; 6447117f1b4Smrg 645af69d88dSmrg /* Note: this loop will be a no-op for RECT, BUFFER, EXTERNAL, 646af69d88dSmrg * MULTISAMPLE and MULTISAMPLE_ARRAY textures 647af69d88dSmrg */ 648af69d88dSmrg for (i = baseLevel + 1; i < maxLevels; i++) { 649af69d88dSmrg /* Compute the expected size of image at level[i] */ 650af69d88dSmrg if (width > 1) { 651af69d88dSmrg width /= 2; 6527117f1b4Smrg } 653af69d88dSmrg if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) { 654af69d88dSmrg height /= 2; 655af69d88dSmrg } 656af69d88dSmrg if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY && t->Target != GL_TEXTURE_CUBE_MAP_ARRAY) { 657af69d88dSmrg depth /= 2; 658af69d88dSmrg } 659af69d88dSmrg 660af69d88dSmrg /* loop over cube faces (or single face otherwise) */ 661af69d88dSmrg for (face = 0; face < numFaces; face++) { 6627117f1b4Smrg if (i >= minLevel && i <= maxLevel) { 663af69d88dSmrg const struct gl_texture_image *img = t->Image[face][i]; 664af69d88dSmrg 665af69d88dSmrg if (!img) { 666af69d88dSmrg incomplete(t, MIPMAP, "TexImage[%d] is missing", i); 6677117f1b4Smrg return; 6687117f1b4Smrg } 669af69d88dSmrg if (img->TexFormat != baseImage->TexFormat) { 670af69d88dSmrg incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]"); 6717117f1b4Smrg return; 6727117f1b4Smrg } 673af69d88dSmrg if (img->Border != baseImage->Border) { 674af69d88dSmrg incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]"); 6757117f1b4Smrg return; 6767117f1b4Smrg } 677af69d88dSmrg if (img->Width2 != width) { 678af69d88dSmrg incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2); 6797117f1b4Smrg return; 6807117f1b4Smrg } 681af69d88dSmrg if (img->Height2 != height) { 682af69d88dSmrg incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2); 6837117f1b4Smrg return; 6847117f1b4Smrg } 685af69d88dSmrg if (img->Depth2 != depth) { 686af69d88dSmrg incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2); 6877117f1b4Smrg return; 6887117f1b4Smrg } 689af69d88dSmrg 690af69d88dSmrg /* Extra checks for cube textures */ 691af69d88dSmrg if (face > 0) { 692af69d88dSmrg /* check that cube faces are the same size */ 693af69d88dSmrg if (img->Width2 != t->Image[0][i]->Width2 || 694af69d88dSmrg img->Height2 != t->Image[0][i]->Height2) { 695af69d88dSmrg incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size"); 6967117f1b4Smrg return; 6977117f1b4Smrg } 698af69d88dSmrg } 6997117f1b4Smrg } 7007117f1b4Smrg } 701af69d88dSmrg 702af69d88dSmrg if (width == 1 && height == 1 && depth == 1) { 703af69d88dSmrg return; /* found smallest needed mipmap, all done! */ 704af69d88dSmrg } 7057117f1b4Smrg } 7067117f1b4Smrg } 7077117f1b4Smrg} 7087117f1b4Smrg 7094a49301eSmrg 7103464ebd5Sriastradh/** 7113464ebd5Sriastradh * Check if the given cube map texture is "cube complete" as defined in 7123464ebd5Sriastradh * the OpenGL specification. 7133464ebd5Sriastradh */ 7143464ebd5SriastradhGLboolean 7153464ebd5Sriastradh_mesa_cube_complete(const struct gl_texture_object *texObj) 7163464ebd5Sriastradh{ 7173464ebd5Sriastradh const GLint baseLevel = texObj->BaseLevel; 7183464ebd5Sriastradh const struct gl_texture_image *img0, *img; 7193464ebd5Sriastradh GLuint face; 7203464ebd5Sriastradh 7213464ebd5Sriastradh if (texObj->Target != GL_TEXTURE_CUBE_MAP) 7223464ebd5Sriastradh return GL_FALSE; 7233464ebd5Sriastradh 7243464ebd5Sriastradh if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) 7253464ebd5Sriastradh return GL_FALSE; 7263464ebd5Sriastradh 7273464ebd5Sriastradh /* check first face */ 7283464ebd5Sriastradh img0 = texObj->Image[0][baseLevel]; 7293464ebd5Sriastradh if (!img0 || 7303464ebd5Sriastradh img0->Width < 1 || 7313464ebd5Sriastradh img0->Width != img0->Height) 7323464ebd5Sriastradh return GL_FALSE; 7333464ebd5Sriastradh 7343464ebd5Sriastradh /* check remaining faces vs. first face */ 7353464ebd5Sriastradh for (face = 1; face < 6; face++) { 7363464ebd5Sriastradh img = texObj->Image[face][baseLevel]; 7373464ebd5Sriastradh if (!img || 7383464ebd5Sriastradh img->Width != img0->Width || 7393464ebd5Sriastradh img->Height != img0->Height || 7403464ebd5Sriastradh img->TexFormat != img0->TexFormat) 7413464ebd5Sriastradh return GL_FALSE; 7423464ebd5Sriastradh } 7433464ebd5Sriastradh 7443464ebd5Sriastradh return GL_TRUE; 7453464ebd5Sriastradh} 7463464ebd5Sriastradh 7473464ebd5Sriastradh 7484a49301eSmrg/** 7494a49301eSmrg * Mark a texture object dirty. It forces the object to be incomplete 750af69d88dSmrg * and forces the context to re-validate its state. 7514a49301eSmrg * 7524a49301eSmrg * \param ctx GL context. 7534a49301eSmrg * \param texObj texture object. 7544a49301eSmrg */ 7554a49301eSmrgvoid 756af69d88dSmrg_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj) 7574a49301eSmrg{ 758af69d88dSmrg texObj->_BaseComplete = GL_FALSE; 759af69d88dSmrg texObj->_MipmapComplete = GL_FALSE; 760af69d88dSmrg ctx->NewState |= _NEW_TEXTURE; 7614a49301eSmrg} 7624a49301eSmrg 7634a49301eSmrg 7644a49301eSmrg/** 765af69d88dSmrg * Return pointer to a default/fallback texture of the given type/target. 766af69d88dSmrg * The texture is an RGBA texture with all texels = (0,0,0,1). 767af69d88dSmrg * That's the value a GLSL sampler should get when sampling from an 7684a49301eSmrg * incomplete texture. 7694a49301eSmrg */ 7704a49301eSmrgstruct gl_texture_object * 771af69d88dSmrg_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex) 7724a49301eSmrg{ 773af69d88dSmrg if (!ctx->Shared->FallbackTex[tex]) { 7744a49301eSmrg /* create fallback texture now */ 775af69d88dSmrg const GLsizei width = 1, height = 1, depth = 1; 776af69d88dSmrg GLubyte texel[4]; 7774a49301eSmrg struct gl_texture_object *texObj; 7784a49301eSmrg struct gl_texture_image *texImage; 779af69d88dSmrg mesa_format texFormat; 780af69d88dSmrg GLuint dims, face, numFaces = 1; 781af69d88dSmrg GLenum target; 782af69d88dSmrg 783af69d88dSmrg texel[0] = 784af69d88dSmrg texel[1] = 785af69d88dSmrg texel[2] = 0x0; 786af69d88dSmrg texel[3] = 0xff; 787af69d88dSmrg 788af69d88dSmrg switch (tex) { 789af69d88dSmrg case TEXTURE_2D_ARRAY_INDEX: 790af69d88dSmrg dims = 3; 791af69d88dSmrg target = GL_TEXTURE_2D_ARRAY; 792af69d88dSmrg break; 793af69d88dSmrg case TEXTURE_1D_ARRAY_INDEX: 794af69d88dSmrg dims = 2; 795af69d88dSmrg target = GL_TEXTURE_1D_ARRAY; 796af69d88dSmrg break; 797af69d88dSmrg case TEXTURE_CUBE_INDEX: 798af69d88dSmrg dims = 2; 799af69d88dSmrg target = GL_TEXTURE_CUBE_MAP; 800af69d88dSmrg numFaces = 6; 801af69d88dSmrg break; 802af69d88dSmrg case TEXTURE_3D_INDEX: 803af69d88dSmrg dims = 3; 804af69d88dSmrg target = GL_TEXTURE_3D; 805af69d88dSmrg break; 806af69d88dSmrg case TEXTURE_RECT_INDEX: 807af69d88dSmrg dims = 2; 808af69d88dSmrg target = GL_TEXTURE_RECTANGLE; 809af69d88dSmrg break; 810af69d88dSmrg case TEXTURE_2D_INDEX: 811af69d88dSmrg dims = 2; 812af69d88dSmrg target = GL_TEXTURE_2D; 813af69d88dSmrg break; 814af69d88dSmrg case TEXTURE_1D_INDEX: 815af69d88dSmrg dims = 1; 816af69d88dSmrg target = GL_TEXTURE_1D; 817af69d88dSmrg break; 818af69d88dSmrg case TEXTURE_BUFFER_INDEX: 819af69d88dSmrg dims = 0; 820af69d88dSmrg target = GL_TEXTURE_BUFFER; 821af69d88dSmrg break; 822af69d88dSmrg case TEXTURE_CUBE_ARRAY_INDEX: 823af69d88dSmrg dims = 3; 824af69d88dSmrg target = GL_TEXTURE_CUBE_MAP_ARRAY; 825af69d88dSmrg break; 826af69d88dSmrg case TEXTURE_EXTERNAL_INDEX: 827af69d88dSmrg dims = 2; 828af69d88dSmrg target = GL_TEXTURE_EXTERNAL_OES; 829af69d88dSmrg break; 830af69d88dSmrg case TEXTURE_2D_MULTISAMPLE_INDEX: 831af69d88dSmrg dims = 2; 832af69d88dSmrg target = GL_TEXTURE_2D_MULTISAMPLE; 833af69d88dSmrg break; 834af69d88dSmrg case TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: 835af69d88dSmrg dims = 3; 836af69d88dSmrg target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; 837af69d88dSmrg break; 838af69d88dSmrg default: 839af69d88dSmrg /* no-op */ 840af69d88dSmrg return NULL; 8414a49301eSmrg } 8424a49301eSmrg 8434a49301eSmrg /* create texture object */ 844af69d88dSmrg texObj = ctx->Driver.NewTextureObject(ctx, 0, target); 845af69d88dSmrg if (!texObj) 846af69d88dSmrg return NULL; 847af69d88dSmrg 8484a49301eSmrg assert(texObj->RefCount == 1); 8493464ebd5Sriastradh texObj->Sampler.MinFilter = GL_NEAREST; 8503464ebd5Sriastradh texObj->Sampler.MagFilter = GL_NEAREST; 8514a49301eSmrg 852af69d88dSmrg texFormat = ctx->Driver.ChooseTextureFormat(ctx, target, 853af69d88dSmrg GL_RGBA, GL_RGBA, 8543464ebd5Sriastradh GL_UNSIGNED_BYTE); 8553464ebd5Sriastradh 856af69d88dSmrg /* need a loop here just for cube maps */ 857af69d88dSmrg for (face = 0; face < numFaces; face++) { 858af69d88dSmrg GLenum faceTarget; 859af69d88dSmrg 860af69d88dSmrg if (target == GL_TEXTURE_CUBE_MAP) 861af69d88dSmrg faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; 862af69d88dSmrg else 863af69d88dSmrg faceTarget = target; 8644a49301eSmrg 865af69d88dSmrg /* initialize level[0] texture image */ 866af69d88dSmrg texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0); 8674a49301eSmrg 868af69d88dSmrg _mesa_init_teximage_fields(ctx, texImage, 869af69d88dSmrg width, 870af69d88dSmrg (dims > 1) ? height : 1, 871af69d88dSmrg (dims > 2) ? depth : 1, 872af69d88dSmrg 0, /* border */ 873af69d88dSmrg GL_RGBA, texFormat); 874af69d88dSmrg 875af69d88dSmrg ctx->Driver.TexImage(ctx, dims, texImage, 876af69d88dSmrg GL_RGBA, GL_UNSIGNED_BYTE, texel, 877af69d88dSmrg &ctx->DefaultPacking); 878af69d88dSmrg } 8794a49301eSmrg 8804a49301eSmrg _mesa_test_texobj_completeness(ctx, texObj); 881af69d88dSmrg assert(texObj->_BaseComplete); 882af69d88dSmrg assert(texObj->_MipmapComplete); 883af69d88dSmrg 884af69d88dSmrg ctx->Shared->FallbackTex[tex] = texObj; 885af69d88dSmrg } 886af69d88dSmrg return ctx->Shared->FallbackTex[tex]; 887af69d88dSmrg} 888af69d88dSmrg 889af69d88dSmrg 890af69d88dSmrg/** 891af69d88dSmrg * Compute the size of the given texture object, in bytes. 892af69d88dSmrg */ 893af69d88dSmrgstatic GLuint 894af69d88dSmrgtexture_size(const struct gl_texture_object *texObj) 895af69d88dSmrg{ 896af69d88dSmrg const GLuint numFaces = _mesa_num_tex_faces(texObj->Target); 897af69d88dSmrg GLuint face, level, size = 0; 898af69d88dSmrg 899af69d88dSmrg for (face = 0; face < numFaces; face++) { 900af69d88dSmrg for (level = 0; level < MAX_TEXTURE_LEVELS; level++) { 901af69d88dSmrg const struct gl_texture_image *img = texObj->Image[face][level]; 902af69d88dSmrg if (img) { 903af69d88dSmrg GLuint sz = _mesa_format_image_size(img->TexFormat, img->Width, 904af69d88dSmrg img->Height, img->Depth); 905af69d88dSmrg size += sz; 906af69d88dSmrg } 907af69d88dSmrg } 908af69d88dSmrg } 909af69d88dSmrg 910af69d88dSmrg return size; 911af69d88dSmrg} 912af69d88dSmrg 913af69d88dSmrg 914af69d88dSmrg/** 915af69d88dSmrg * Callback called from _mesa_HashWalk() 916af69d88dSmrg */ 917af69d88dSmrgstatic void 918af69d88dSmrgcount_tex_size(GLuint key, void *data, void *userData) 919af69d88dSmrg{ 920af69d88dSmrg const struct gl_texture_object *texObj = 921af69d88dSmrg (const struct gl_texture_object *) data; 922af69d88dSmrg GLuint *total = (GLuint *) userData; 923af69d88dSmrg 924af69d88dSmrg (void) key; 9254a49301eSmrg 926af69d88dSmrg *total = *total + texture_size(texObj); 927af69d88dSmrg} 928af69d88dSmrg 929af69d88dSmrg 930af69d88dSmrg/** 931af69d88dSmrg * Compute total size (in bytes) of all textures for the given context. 932af69d88dSmrg * For debugging purposes. 933af69d88dSmrg */ 934af69d88dSmrgGLuint 935af69d88dSmrg_mesa_total_texture_memory(struct gl_context *ctx) 936af69d88dSmrg{ 937af69d88dSmrg GLuint tgt, total = 0; 938af69d88dSmrg 939af69d88dSmrg _mesa_HashWalk(ctx->Shared->TexObjects, count_tex_size, &total); 940af69d88dSmrg 941af69d88dSmrg /* plus, the default texture objects */ 942af69d88dSmrg for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { 943af69d88dSmrg total += texture_size(ctx->Shared->DefaultTex[tgt]); 9444a49301eSmrg } 945af69d88dSmrg 946af69d88dSmrg return total; 9474a49301eSmrg} 9484a49301eSmrg 949af69d88dSmrgstatic struct gl_texture_object * 950af69d88dSmrginvalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture, 951af69d88dSmrg GLint level, const char *name) 952af69d88dSmrg{ 953af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 954af69d88dSmrg * 955af69d88dSmrg * "If <texture> is zero or is not the name of a texture, the error 956af69d88dSmrg * INVALID_VALUE is generated." 957af69d88dSmrg * 958af69d88dSmrg * This performs the error check in a different order than listed in the 959af69d88dSmrg * spec. We have to get the texture object before we can validate the 960af69d88dSmrg * other parameters against values in the texture object. 961af69d88dSmrg */ 962af69d88dSmrg struct gl_texture_object *const t = _mesa_lookup_texture(ctx, texture); 963af69d88dSmrg if (texture == 0 || t == NULL) { 964af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(texture)", name); 965af69d88dSmrg return NULL; 966af69d88dSmrg } 967af69d88dSmrg 968af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 969af69d88dSmrg * 970af69d88dSmrg * "If <level> is less than zero or greater than the base 2 logarithm 971af69d88dSmrg * of the maximum texture width, height, or depth, the error 972af69d88dSmrg * INVALID_VALUE is generated." 973af69d88dSmrg */ 974af69d88dSmrg if (level < 0 || level > t->MaxLevel) { 975af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); 976af69d88dSmrg return NULL; 977af69d88dSmrg } 978af69d88dSmrg 979af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 980af69d88dSmrg * 981af69d88dSmrg * "If the target of <texture> is TEXTURE_RECTANGLE, TEXTURE_BUFFER, 982af69d88dSmrg * TEXTURE_2D_MULTISAMPLE, or TEXTURE_2D_MULTISAMPLE_ARRAY, and <level> 983af69d88dSmrg * is not zero, the error INVALID_VALUE is generated." 984af69d88dSmrg */ 985af69d88dSmrg if (level != 0) { 986af69d88dSmrg switch (t->Target) { 987af69d88dSmrg case GL_TEXTURE_RECTANGLE: 988af69d88dSmrg case GL_TEXTURE_BUFFER: 989af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 990af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 991af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); 992af69d88dSmrg return NULL; 993af69d88dSmrg 994af69d88dSmrg default: 995af69d88dSmrg break; 996af69d88dSmrg } 997af69d88dSmrg } 998af69d88dSmrg 999af69d88dSmrg return t; 1000af69d88dSmrg} 10014a49301eSmrg 10027117f1b4Smrg/*@}*/ 10037117f1b4Smrg 10047117f1b4Smrg 10057117f1b4Smrg/***********************************************************************/ 10067117f1b4Smrg/** \name API functions */ 10077117f1b4Smrg/*@{*/ 10087117f1b4Smrg 10097117f1b4Smrg 10107117f1b4Smrg/** 10117117f1b4Smrg * Generate texture names. 10127117f1b4Smrg * 10137117f1b4Smrg * \param n number of texture names to be generated. 10147117f1b4Smrg * \param textures an array in which will hold the generated texture names. 10157117f1b4Smrg * 10167117f1b4Smrg * \sa glGenTextures(). 10177117f1b4Smrg * 1018c1f859d4Smrg * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture 1019c1f859d4Smrg * IDs which are stored in \p textures. Corresponding empty texture 1020c1f859d4Smrg * objects are also generated. 10217117f1b4Smrg */ 10227117f1b4Smrgvoid GLAPIENTRY 10237117f1b4Smrg_mesa_GenTextures( GLsizei n, GLuint *textures ) 10247117f1b4Smrg{ 10257117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 10267117f1b4Smrg GLuint first; 10277117f1b4Smrg GLint i; 1028af69d88dSmrg 1029af69d88dSmrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1030af69d88dSmrg _mesa_debug(ctx, "glGenTextures %d\n", n); 10317117f1b4Smrg 10327117f1b4Smrg if (n < 0) { 10337117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" ); 10347117f1b4Smrg return; 10357117f1b4Smrg } 10367117f1b4Smrg 10377117f1b4Smrg if (!textures) 10387117f1b4Smrg return; 10397117f1b4Smrg 10407117f1b4Smrg /* 10417117f1b4Smrg * This must be atomic (generation and allocation of texture IDs) 10427117f1b4Smrg */ 1043af69d88dSmrg mtx_lock(&ctx->Shared->Mutex); 10447117f1b4Smrg 10457117f1b4Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n); 10467117f1b4Smrg 10477117f1b4Smrg /* Allocate new, empty texture objects */ 10487117f1b4Smrg for (i = 0; i < n; i++) { 10497117f1b4Smrg struct gl_texture_object *texObj; 10507117f1b4Smrg GLuint name = first + i; 10517117f1b4Smrg GLenum target = 0; 1052af69d88dSmrg texObj = ctx->Driver.NewTextureObject(ctx, name, target); 10537117f1b4Smrg if (!texObj) { 1054af69d88dSmrg mtx_unlock(&ctx->Shared->Mutex); 10557117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); 10567117f1b4Smrg return; 10577117f1b4Smrg } 10587117f1b4Smrg 10597117f1b4Smrg /* insert into hash table */ 10607117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); 10617117f1b4Smrg 10627117f1b4Smrg textures[i] = name; 10637117f1b4Smrg } 10647117f1b4Smrg 1065af69d88dSmrg mtx_unlock(&ctx->Shared->Mutex); 10667117f1b4Smrg} 10677117f1b4Smrg 10687117f1b4Smrg 10697117f1b4Smrg/** 10707117f1b4Smrg * Check if the given texture object is bound to the current draw or 10717117f1b4Smrg * read framebuffer. If so, Unbind it. 10727117f1b4Smrg */ 10737117f1b4Smrgstatic void 10743464ebd5Sriastradhunbind_texobj_from_fbo(struct gl_context *ctx, 10753464ebd5Sriastradh struct gl_texture_object *texObj) 10767117f1b4Smrg{ 1077af69d88dSmrg bool progress = false; 1078af69d88dSmrg 1079af69d88dSmrg /* Section 4.4.2 (Attaching Images to Framebuffer Objects), subsection 1080af69d88dSmrg * "Attaching Texture Images to a Framebuffer," of the OpenGL 3.1 spec 1081af69d88dSmrg * says: 1082af69d88dSmrg * 1083af69d88dSmrg * "If a texture object is deleted while its image is attached to one 1084af69d88dSmrg * or more attachment points in the currently bound framebuffer, then 1085af69d88dSmrg * it is as if FramebufferTexture* had been called, with a texture of 1086af69d88dSmrg * zero, for each attachment point to which this image was attached in 1087af69d88dSmrg * the currently bound framebuffer. In other words, this texture image 1088af69d88dSmrg * is first detached from all attachment points in the currently bound 1089af69d88dSmrg * framebuffer. Note that the texture image is specifically not 1090af69d88dSmrg * detached from any other framebuffer objects. Detaching the texture 1091af69d88dSmrg * image from any other framebuffer objects is the responsibility of 1092af69d88dSmrg * the application." 1093af69d88dSmrg */ 1094af69d88dSmrg if (_mesa_is_user_fbo(ctx->DrawBuffer)) { 1095af69d88dSmrg progress = _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, texObj); 1096af69d88dSmrg } 1097af69d88dSmrg if (_mesa_is_user_fbo(ctx->ReadBuffer) 1098af69d88dSmrg && ctx->ReadBuffer != ctx->DrawBuffer) { 1099af69d88dSmrg progress = _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, texObj) 1100af69d88dSmrg || progress; 11017117f1b4Smrg } 1102af69d88dSmrg 1103af69d88dSmrg if (progress) 1104af69d88dSmrg /* Vertices are already flushed by _mesa_DeleteTextures */ 1105af69d88dSmrg ctx->NewState |= _NEW_BUFFERS; 11067117f1b4Smrg} 11077117f1b4Smrg 11087117f1b4Smrg 11097117f1b4Smrg/** 11107117f1b4Smrg * Check if the given texture object is bound to any texture image units and 11117117f1b4Smrg * unbind it if so (revert to default textures). 11127117f1b4Smrg */ 11137117f1b4Smrgstatic void 11143464ebd5Sriastradhunbind_texobj_from_texunits(struct gl_context *ctx, 11153464ebd5Sriastradh struct gl_texture_object *texObj) 11167117f1b4Smrg{ 1117af69d88dSmrg const gl_texture_index index = texObj->TargetIndex; 1118af69d88dSmrg GLuint u; 11197117f1b4Smrg 1120af69d88dSmrg if (texObj->Target == 0) 1121af69d88dSmrg return; 1122af69d88dSmrg 1123af69d88dSmrg for (u = 0; u < ctx->Texture.NumCurrentTexUsed; u++) { 11247117f1b4Smrg struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; 1125af69d88dSmrg 1126af69d88dSmrg if (texObj == unit->CurrentTex[index]) { 1127af69d88dSmrg /* Bind the default texture for this unit/target */ 1128af69d88dSmrg _mesa_reference_texobj(&unit->CurrentTex[index], 1129af69d88dSmrg ctx->Shared->DefaultTex[index]); 1130af69d88dSmrg unit->_BoundTextures &= ~(1 << index); 11317117f1b4Smrg } 11327117f1b4Smrg } 11337117f1b4Smrg} 11347117f1b4Smrg 11357117f1b4Smrg 1136af69d88dSmrg/** 1137af69d88dSmrg * Check if the given texture object is bound to any shader image unit 1138af69d88dSmrg * and unbind it if that's the case. 1139af69d88dSmrg */ 1140af69d88dSmrgstatic void 1141af69d88dSmrgunbind_texobj_from_image_units(struct gl_context *ctx, 1142af69d88dSmrg struct gl_texture_object *texObj) 1143af69d88dSmrg{ 1144af69d88dSmrg GLuint i; 1145af69d88dSmrg 1146af69d88dSmrg for (i = 0; i < ctx->Const.MaxImageUnits; i++) { 1147af69d88dSmrg struct gl_image_unit *unit = &ctx->ImageUnits[i]; 1148af69d88dSmrg 1149af69d88dSmrg if (texObj == unit->TexObj) 1150af69d88dSmrg _mesa_reference_texobj(&unit->TexObj, NULL); 1151af69d88dSmrg } 1152af69d88dSmrg} 1153af69d88dSmrg 1154af69d88dSmrg/** 1155af69d88dSmrg * Unbinds all textures bound to the given texture image unit. 1156af69d88dSmrg */ 1157af69d88dSmrgstatic void 1158af69d88dSmrgunbind_textures_from_unit(struct gl_context *ctx, GLuint unit) 1159af69d88dSmrg{ 1160af69d88dSmrg struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 1161af69d88dSmrg 1162af69d88dSmrg while (texUnit->_BoundTextures) { 1163af69d88dSmrg const GLuint index = ffs(texUnit->_BoundTextures) - 1; 1164af69d88dSmrg struct gl_texture_object *texObj = ctx->Shared->DefaultTex[index]; 1165af69d88dSmrg 1166af69d88dSmrg _mesa_reference_texobj(&texUnit->CurrentTex[index], texObj); 1167af69d88dSmrg 1168af69d88dSmrg /* Pass BindTexture call to device driver */ 1169af69d88dSmrg if (ctx->Driver.BindTexture) 1170af69d88dSmrg ctx->Driver.BindTexture(ctx, unit, 0, texObj); 1171af69d88dSmrg 1172af69d88dSmrg texUnit->_BoundTextures &= ~(1 << index); 1173af69d88dSmrg ctx->NewState |= _NEW_TEXTURE; 1174af69d88dSmrg } 1175af69d88dSmrg} 1176af69d88dSmrg 11777117f1b4Smrg/** 11787117f1b4Smrg * Delete named textures. 11797117f1b4Smrg * 11807117f1b4Smrg * \param n number of textures to be deleted. 11817117f1b4Smrg * \param textures array of texture IDs to be deleted. 11827117f1b4Smrg * 11837117f1b4Smrg * \sa glDeleteTextures(). 11847117f1b4Smrg * 11857117f1b4Smrg * If we're about to delete a texture that's currently bound to any 11867117f1b4Smrg * texture unit, unbind the texture first. Decrement the reference 11877117f1b4Smrg * count on the texture object and delete it if it's zero. 11887117f1b4Smrg * Recall that texture objects can be shared among several rendering 11897117f1b4Smrg * contexts. 11907117f1b4Smrg */ 11917117f1b4Smrgvoid GLAPIENTRY 11927117f1b4Smrg_mesa_DeleteTextures( GLsizei n, const GLuint *textures) 11937117f1b4Smrg{ 11947117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 11957117f1b4Smrg GLint i; 1196af69d88dSmrg 1197af69d88dSmrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1198af69d88dSmrg _mesa_debug(ctx, "glDeleteTextures %d\n", n); 1199af69d88dSmrg 1200af69d88dSmrg FLUSH_VERTICES(ctx, 0); /* too complex */ 12017117f1b4Smrg 12027117f1b4Smrg if (!textures) 12037117f1b4Smrg return; 12047117f1b4Smrg 12057117f1b4Smrg for (i = 0; i < n; i++) { 12067117f1b4Smrg if (textures[i] > 0) { 12077117f1b4Smrg struct gl_texture_object *delObj 12087117f1b4Smrg = _mesa_lookup_texture(ctx, textures[i]); 12097117f1b4Smrg 12107117f1b4Smrg if (delObj) { 12113464ebd5Sriastradh _mesa_lock_texture(ctx, delObj); 12127117f1b4Smrg 12137117f1b4Smrg /* Check if texture is bound to any framebuffer objects. 12147117f1b4Smrg * If so, unbind. 12157117f1b4Smrg * See section 4.4.2.3 of GL_EXT_framebuffer_object. 12167117f1b4Smrg */ 12177117f1b4Smrg unbind_texobj_from_fbo(ctx, delObj); 12187117f1b4Smrg 12197117f1b4Smrg /* Check if this texture is currently bound to any texture units. 12207117f1b4Smrg * If so, unbind it. 12217117f1b4Smrg */ 12227117f1b4Smrg unbind_texobj_from_texunits(ctx, delObj); 12237117f1b4Smrg 1224af69d88dSmrg /* Check if this texture is currently bound to any shader 1225af69d88dSmrg * image unit. If so, unbind it. 1226af69d88dSmrg * See section 3.9.X of GL_ARB_shader_image_load_store. 1227af69d88dSmrg */ 1228af69d88dSmrg unbind_texobj_from_image_units(ctx, delObj); 1229af69d88dSmrg 12303464ebd5Sriastradh _mesa_unlock_texture(ctx, delObj); 12317117f1b4Smrg 12327117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 12337117f1b4Smrg 12347117f1b4Smrg /* The texture _name_ is now free for re-use. 12357117f1b4Smrg * Remove it from the hash table now. 12367117f1b4Smrg */ 1237af69d88dSmrg mtx_lock(&ctx->Shared->Mutex); 12387117f1b4Smrg _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); 1239af69d88dSmrg mtx_unlock(&ctx->Shared->Mutex); 12407117f1b4Smrg 12417117f1b4Smrg /* Unreference the texobj. If refcount hits zero, the texture 12427117f1b4Smrg * will be deleted. 12437117f1b4Smrg */ 12447117f1b4Smrg _mesa_reference_texobj(&delObj, NULL); 12457117f1b4Smrg } 12467117f1b4Smrg } 12477117f1b4Smrg } 12487117f1b4Smrg} 12497117f1b4Smrg 12507117f1b4Smrg 1251c1f859d4Smrg/** 1252c1f859d4Smrg * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D 1253c1f859d4Smrg * into the corresponding Mesa texture target index. 1254cdc920a0Smrg * Note that proxy targets are not valid here. 1255cdc920a0Smrg * \return TEXTURE_x_INDEX or -1 if target is invalid 1256c1f859d4Smrg */ 1257af69d88dSmrgint 1258af69d88dSmrg_mesa_tex_target_to_index(const struct gl_context *ctx, GLenum target) 1259c1f859d4Smrg{ 1260c1f859d4Smrg switch (target) { 1261c1f859d4Smrg case GL_TEXTURE_1D: 1262af69d88dSmrg return _mesa_is_desktop_gl(ctx) ? TEXTURE_1D_INDEX : -1; 1263c1f859d4Smrg case GL_TEXTURE_2D: 1264c1f859d4Smrg return TEXTURE_2D_INDEX; 1265c1f859d4Smrg case GL_TEXTURE_3D: 1266af69d88dSmrg return ctx->API != API_OPENGLES ? TEXTURE_3D_INDEX : -1; 1267af69d88dSmrg case GL_TEXTURE_CUBE_MAP: 1268af69d88dSmrg return ctx->Extensions.ARB_texture_cube_map 1269af69d88dSmrg ? TEXTURE_CUBE_INDEX : -1; 1270af69d88dSmrg case GL_TEXTURE_RECTANGLE: 1271af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle 1272af69d88dSmrg ? TEXTURE_RECT_INDEX : -1; 1273af69d88dSmrg case GL_TEXTURE_1D_ARRAY: 1274af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array 1275af69d88dSmrg ? TEXTURE_1D_ARRAY_INDEX : -1; 1276af69d88dSmrg case GL_TEXTURE_2D_ARRAY: 1277af69d88dSmrg return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array) 1278af69d88dSmrg || _mesa_is_gles3(ctx) 1279af69d88dSmrg ? TEXTURE_2D_ARRAY_INDEX : -1; 1280af69d88dSmrg case GL_TEXTURE_BUFFER: 1281af69d88dSmrg return ctx->API == API_OPENGL_CORE && 1282af69d88dSmrg ctx->Extensions.ARB_texture_buffer_object ? 1283af69d88dSmrg TEXTURE_BUFFER_INDEX : -1; 1284af69d88dSmrg case GL_TEXTURE_EXTERNAL_OES: 1285af69d88dSmrg return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external 1286af69d88dSmrg ? TEXTURE_EXTERNAL_INDEX : -1; 1287af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 1288af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_cube_map_array 1289af69d88dSmrg ? TEXTURE_CUBE_ARRAY_INDEX : -1; 1290af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 1291af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample 1292af69d88dSmrg ? TEXTURE_2D_MULTISAMPLE_INDEX: -1; 1293af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 1294af69d88dSmrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample 1295af69d88dSmrg ? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: -1; 1296c1f859d4Smrg default: 1297c1f859d4Smrg return -1; 1298c1f859d4Smrg } 1299c1f859d4Smrg} 1300c1f859d4Smrg 1301c1f859d4Smrg 13027117f1b4Smrg/** 13037117f1b4Smrg * Bind a named texture to a texturing target. 13047117f1b4Smrg * 13057117f1b4Smrg * \param target texture target. 13067117f1b4Smrg * \param texName texture name. 13077117f1b4Smrg * 13087117f1b4Smrg * \sa glBindTexture(). 13097117f1b4Smrg * 13107117f1b4Smrg * Determines the old texture object bound and returns immediately if rebinding 13117117f1b4Smrg * the same texture. Get the current texture which is either a default texture 13127117f1b4Smrg * if name is null, a named texture from the hash, or a new texture if the 13137117f1b4Smrg * given texture name is new. Increments its reference count, binds it, and 13147117f1b4Smrg * calls dd_function_table::BindTexture. Decrements the old texture reference 13157117f1b4Smrg * count and deletes it if it reaches zero. 13167117f1b4Smrg */ 13177117f1b4Smrgvoid GLAPIENTRY 13187117f1b4Smrg_mesa_BindTexture( GLenum target, GLuint texName ) 13197117f1b4Smrg{ 13207117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 13213464ebd5Sriastradh struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); 13223464ebd5Sriastradh struct gl_texture_object *newTexObj = NULL; 1323c1f859d4Smrg GLint targetIndex; 13247117f1b4Smrg 13257117f1b4Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 13267117f1b4Smrg _mesa_debug(ctx, "glBindTexture %s %d\n", 13277117f1b4Smrg _mesa_lookup_enum_by_nr(target), (GLint) texName); 13287117f1b4Smrg 1329af69d88dSmrg targetIndex = _mesa_tex_target_to_index(ctx, target); 1330c1f859d4Smrg if (targetIndex < 0) { 1331c1f859d4Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); 1332c1f859d4Smrg return; 1333c1f859d4Smrg } 1334c1f859d4Smrg assert(targetIndex < NUM_TEXTURE_TARGETS); 1335c1f859d4Smrg 13367117f1b4Smrg /* 13377117f1b4Smrg * Get pointer to new texture object (newTexObj) 13387117f1b4Smrg */ 13397117f1b4Smrg if (texName == 0) { 13403464ebd5Sriastradh /* Use a default texture object */ 13413464ebd5Sriastradh newTexObj = ctx->Shared->DefaultTex[targetIndex]; 13427117f1b4Smrg } 13437117f1b4Smrg else { 13447117f1b4Smrg /* non-default texture object */ 13457117f1b4Smrg newTexObj = _mesa_lookup_texture(ctx, texName); 13467117f1b4Smrg if (newTexObj) { 13477117f1b4Smrg /* error checking */ 13487117f1b4Smrg if (newTexObj->Target != 0 && newTexObj->Target != target) { 1349c1f859d4Smrg /* the named texture object's target doesn't match the given target */ 13507117f1b4Smrg _mesa_error( ctx, GL_INVALID_OPERATION, 1351c1f859d4Smrg "glBindTexture(target mismatch)" ); 13527117f1b4Smrg return; 13537117f1b4Smrg } 1354c1f859d4Smrg if (newTexObj->Target == 0) { 1355c1f859d4Smrg finish_texture_init(ctx, target, newTexObj); 13567117f1b4Smrg } 13577117f1b4Smrg } 13587117f1b4Smrg else { 1359af69d88dSmrg if (ctx->API == API_OPENGL_CORE) { 1360af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture(non-gen name)"); 1361af69d88dSmrg return; 1362af69d88dSmrg } 1363af69d88dSmrg 13647117f1b4Smrg /* if this is a new texture id, allocate a texture object now */ 1365af69d88dSmrg newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target); 13667117f1b4Smrg if (!newTexObj) { 13677117f1b4Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); 13687117f1b4Smrg return; 13697117f1b4Smrg } 13707117f1b4Smrg 13717117f1b4Smrg /* and insert it into hash table */ 1372af69d88dSmrg mtx_lock(&ctx->Shared->Mutex); 13737117f1b4Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); 1374af69d88dSmrg mtx_unlock(&ctx->Shared->Mutex); 13757117f1b4Smrg } 13767117f1b4Smrg newTexObj->Target = target; 1377af69d88dSmrg newTexObj->TargetIndex = targetIndex; 13787117f1b4Smrg } 13797117f1b4Smrg 13807117f1b4Smrg assert(valid_texture_object(newTexObj)); 13817117f1b4Smrg 13823464ebd5Sriastradh /* Check if this texture is only used by this context and is already bound. 13833464ebd5Sriastradh * If so, just return. 13843464ebd5Sriastradh */ 13853464ebd5Sriastradh { 13863464ebd5Sriastradh GLboolean early_out; 1387af69d88dSmrg mtx_lock(&ctx->Shared->Mutex); 13883464ebd5Sriastradh early_out = ((ctx->Shared->RefCount == 1) 13893464ebd5Sriastradh && (newTexObj == texUnit->CurrentTex[targetIndex])); 1390af69d88dSmrg mtx_unlock(&ctx->Shared->Mutex); 13913464ebd5Sriastradh if (early_out) { 13923464ebd5Sriastradh return; 13933464ebd5Sriastradh } 13944a49301eSmrg } 13954a49301eSmrg 13967117f1b4Smrg /* flush before changing binding */ 13977117f1b4Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE); 13987117f1b4Smrg 13997117f1b4Smrg /* Do the actual binding. The refcount on the previously bound 14007117f1b4Smrg * texture object will be decremented. It'll be deleted if the 14017117f1b4Smrg * count hits zero. 14027117f1b4Smrg */ 1403c1f859d4Smrg _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); 1404af69d88dSmrg ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed, 1405af69d88dSmrg ctx->Texture.CurrentUnit + 1); 1406c1f859d4Smrg ASSERT(texUnit->CurrentTex[targetIndex]); 14077117f1b4Smrg 1408af69d88dSmrg if (texName != 0) 1409af69d88dSmrg texUnit->_BoundTextures |= (1 << targetIndex); 1410af69d88dSmrg else 1411af69d88dSmrg texUnit->_BoundTextures &= ~(1 << targetIndex); 1412af69d88dSmrg 14137117f1b4Smrg /* Pass BindTexture call to device driver */ 14147117f1b4Smrg if (ctx->Driver.BindTexture) 1415af69d88dSmrg ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj); 1416af69d88dSmrg} 1417af69d88dSmrg 1418af69d88dSmrg 1419af69d88dSmrgvoid GLAPIENTRY 1420af69d88dSmrg_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures) 1421af69d88dSmrg{ 1422af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 1423af69d88dSmrg GLint i; 1424af69d88dSmrg 1425af69d88dSmrg /* The ARB_multi_bind spec says: 1426af69d88dSmrg * 1427af69d88dSmrg * "An INVALID_OPERATION error is generated if <first> + <count> 1428af69d88dSmrg * is greater than the number of texture image units supported 1429af69d88dSmrg * by the implementation." 1430af69d88dSmrg */ 1431af69d88dSmrg if (first + count > ctx->Const.MaxCombinedTextureImageUnits) { 1432af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 1433af69d88dSmrg "glBindTextures(first=%u + count=%d > the value of " 1434af69d88dSmrg "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)", 1435af69d88dSmrg first, count, ctx->Const.MaxCombinedTextureImageUnits); 1436af69d88dSmrg return; 1437af69d88dSmrg } 1438af69d88dSmrg 1439af69d88dSmrg /* Flush before changing bindings */ 1440af69d88dSmrg FLUSH_VERTICES(ctx, 0); 1441af69d88dSmrg 1442af69d88dSmrg ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed, 1443af69d88dSmrg first + count); 1444af69d88dSmrg 1445af69d88dSmrg if (textures) { 1446af69d88dSmrg /* Note that the error semantics for multi-bind commands differ from 1447af69d88dSmrg * those of other GL commands. 1448af69d88dSmrg * 1449af69d88dSmrg * The issues section in the ARB_multi_bind spec says: 1450af69d88dSmrg * 1451af69d88dSmrg * "(11) Typically, OpenGL specifies that if an error is generated by 1452af69d88dSmrg * a command, that command has no effect. This is somewhat 1453af69d88dSmrg * unfortunate for multi-bind commands, because it would require 1454af69d88dSmrg * a first pass to scan the entire list of bound objects for 1455af69d88dSmrg * errors and then a second pass to actually perform the 1456af69d88dSmrg * bindings. Should we have different error semantics? 1457af69d88dSmrg * 1458af69d88dSmrg * RESOLVED: Yes. In this specification, when the parameters for 1459af69d88dSmrg * one of the <count> binding points are invalid, that binding 1460af69d88dSmrg * point is not updated and an error will be generated. However, 1461af69d88dSmrg * other binding points in the same command will be updated if 1462af69d88dSmrg * their parameters are valid and no other error occurs." 1463af69d88dSmrg */ 1464af69d88dSmrg 1465af69d88dSmrg _mesa_begin_texture_lookups(ctx); 1466af69d88dSmrg 1467af69d88dSmrg for (i = 0; i < count; i++) { 1468af69d88dSmrg if (textures[i] != 0) { 1469af69d88dSmrg struct gl_texture_unit *texUnit = &ctx->Texture.Unit[first + i]; 1470af69d88dSmrg struct gl_texture_object *current = texUnit->_Current; 1471af69d88dSmrg struct gl_texture_object *texObj; 1472af69d88dSmrg 1473af69d88dSmrg if (current && current->Name == textures[i]) 1474af69d88dSmrg texObj = current; 1475af69d88dSmrg else 1476af69d88dSmrg texObj = _mesa_lookup_texture_locked(ctx, textures[i]); 1477af69d88dSmrg 1478af69d88dSmrg if (texObj && texObj->Target != 0) { 1479af69d88dSmrg const gl_texture_index targetIndex = texObj->TargetIndex; 1480af69d88dSmrg 1481af69d88dSmrg if (texUnit->CurrentTex[targetIndex] != texObj) { 1482af69d88dSmrg /* Do the actual binding. The refcount on the previously 1483af69d88dSmrg * bound texture object will be decremented. It will be 1484af69d88dSmrg * deleted if the count hits zero. 1485af69d88dSmrg */ 1486af69d88dSmrg _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], 1487af69d88dSmrg texObj); 1488af69d88dSmrg 1489af69d88dSmrg texUnit->_BoundTextures |= (1 << targetIndex); 1490af69d88dSmrg ctx->NewState |= _NEW_TEXTURE; 1491af69d88dSmrg 1492af69d88dSmrg /* Pass the BindTexture call to the device driver */ 1493af69d88dSmrg if (ctx->Driver.BindTexture) 1494af69d88dSmrg ctx->Driver.BindTexture(ctx, first + i, 1495af69d88dSmrg texObj->Target, texObj); 1496af69d88dSmrg } 1497af69d88dSmrg } else { 1498af69d88dSmrg /* The ARB_multi_bind spec says: 1499af69d88dSmrg * 1500af69d88dSmrg * "An INVALID_OPERATION error is generated if any value 1501af69d88dSmrg * in <textures> is not zero or the name of an existing 1502af69d88dSmrg * texture object (per binding)." 1503af69d88dSmrg */ 1504af69d88dSmrg _mesa_error(ctx, GL_INVALID_OPERATION, 1505af69d88dSmrg "glBindTextures(textures[%d]=%u is not zero " 1506af69d88dSmrg "or the name of an existing texture object)", 1507af69d88dSmrg i, textures[i]); 1508af69d88dSmrg } 1509af69d88dSmrg } else { 1510af69d88dSmrg unbind_textures_from_unit(ctx, first + i); 1511af69d88dSmrg } 1512af69d88dSmrg } 1513af69d88dSmrg 1514af69d88dSmrg _mesa_end_texture_lookups(ctx); 1515af69d88dSmrg } else { 1516af69d88dSmrg /* Unbind all textures in the range <first> through <first>+<count>-1 */ 1517af69d88dSmrg for (i = 0; i < count; i++) 1518af69d88dSmrg unbind_textures_from_unit(ctx, first + i); 1519af69d88dSmrg } 15207117f1b4Smrg} 15217117f1b4Smrg 15227117f1b4Smrg 15237117f1b4Smrg/** 15247117f1b4Smrg * Set texture priorities. 15257117f1b4Smrg * 15267117f1b4Smrg * \param n number of textures. 15277117f1b4Smrg * \param texName texture names. 15287117f1b4Smrg * \param priorities corresponding texture priorities. 15297117f1b4Smrg * 15307117f1b4Smrg * \sa glPrioritizeTextures(). 15317117f1b4Smrg * 15327117f1b4Smrg * Looks up each texture in the hash, clamps the corresponding priority between 15337117f1b4Smrg * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. 15347117f1b4Smrg */ 15357117f1b4Smrgvoid GLAPIENTRY 15367117f1b4Smrg_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, 15377117f1b4Smrg const GLclampf *priorities ) 15387117f1b4Smrg{ 15397117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 15407117f1b4Smrg GLint i; 1541af69d88dSmrg 1542af69d88dSmrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1543af69d88dSmrg _mesa_debug(ctx, "glPrioritizeTextures %d\n", n); 1544af69d88dSmrg 1545af69d88dSmrg FLUSH_VERTICES(ctx, 0); 15467117f1b4Smrg 15477117f1b4Smrg if (n < 0) { 15487117f1b4Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); 15497117f1b4Smrg return; 15507117f1b4Smrg } 15517117f1b4Smrg 15527117f1b4Smrg if (!priorities) 15537117f1b4Smrg return; 15547117f1b4Smrg 15557117f1b4Smrg for (i = 0; i < n; i++) { 15567117f1b4Smrg if (texName[i] > 0) { 15577117f1b4Smrg struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); 15587117f1b4Smrg if (t) { 15597117f1b4Smrg t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); 15607117f1b4Smrg } 15617117f1b4Smrg } 15627117f1b4Smrg } 15637117f1b4Smrg 15647117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 15657117f1b4Smrg} 15667117f1b4Smrg 15673464ebd5Sriastradh 15683464ebd5Sriastradh 15697117f1b4Smrg/** 15707117f1b4Smrg * See if textures are loaded in texture memory. 15717117f1b4Smrg * 15727117f1b4Smrg * \param n number of textures to query. 15737117f1b4Smrg * \param texName array with the texture names. 15747117f1b4Smrg * \param residences array which will hold the residence status. 15757117f1b4Smrg * 15767117f1b4Smrg * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 15777117f1b4Smrg * 1578af69d88dSmrg * Note: we assume all textures are always resident 15797117f1b4Smrg */ 15807117f1b4SmrgGLboolean GLAPIENTRY 15817117f1b4Smrg_mesa_AreTexturesResident(GLsizei n, const GLuint *texName, 15827117f1b4Smrg GLboolean *residences) 15837117f1b4Smrg{ 15847117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 15857117f1b4Smrg GLboolean allResident = GL_TRUE; 1586af69d88dSmrg GLint i; 15877117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 15887117f1b4Smrg 1589af69d88dSmrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1590af69d88dSmrg _mesa_debug(ctx, "glAreTexturesResident %d\n", n); 1591af69d88dSmrg 15927117f1b4Smrg if (n < 0) { 15937117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); 15947117f1b4Smrg return GL_FALSE; 15957117f1b4Smrg } 15967117f1b4Smrg 15977117f1b4Smrg if (!texName || !residences) 15987117f1b4Smrg return GL_FALSE; 15997117f1b4Smrg 1600af69d88dSmrg /* We only do error checking on the texture names */ 16017117f1b4Smrg for (i = 0; i < n; i++) { 16027117f1b4Smrg struct gl_texture_object *t; 16037117f1b4Smrg if (texName[i] == 0) { 16047117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 16057117f1b4Smrg return GL_FALSE; 16067117f1b4Smrg } 16077117f1b4Smrg t = _mesa_lookup_texture(ctx, texName[i]); 16087117f1b4Smrg if (!t) { 16097117f1b4Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 16107117f1b4Smrg return GL_FALSE; 16117117f1b4Smrg } 16127117f1b4Smrg } 16137117f1b4Smrg 16147117f1b4Smrg return allResident; 16157117f1b4Smrg} 16167117f1b4Smrg 16173464ebd5Sriastradh 16187117f1b4Smrg/** 16197117f1b4Smrg * See if a name corresponds to a texture. 16207117f1b4Smrg * 16217117f1b4Smrg * \param texture texture name. 16227117f1b4Smrg * 16237117f1b4Smrg * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE 16247117f1b4Smrg * otherwise. 16257117f1b4Smrg * 16267117f1b4Smrg * \sa glIsTexture(). 16277117f1b4Smrg * 16287117f1b4Smrg * Calls _mesa_HashLookup(). 16297117f1b4Smrg */ 16307117f1b4SmrgGLboolean GLAPIENTRY 16317117f1b4Smrg_mesa_IsTexture( GLuint texture ) 16327117f1b4Smrg{ 16337117f1b4Smrg struct gl_texture_object *t; 16347117f1b4Smrg GET_CURRENT_CONTEXT(ctx); 16357117f1b4Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 16367117f1b4Smrg 1637af69d88dSmrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1638af69d88dSmrg _mesa_debug(ctx, "glIsTexture %d\n", texture); 1639af69d88dSmrg 16407117f1b4Smrg if (!texture) 16417117f1b4Smrg return GL_FALSE; 16427117f1b4Smrg 16437117f1b4Smrg t = _mesa_lookup_texture(ctx, texture); 16447117f1b4Smrg 16457117f1b4Smrg /* IsTexture is true only after object has been bound once. */ 16467117f1b4Smrg return t && t->Target; 16477117f1b4Smrg} 16487117f1b4Smrg 1649c1f859d4Smrg 1650c1f859d4Smrg/** 16514a49301eSmrg * Simplest implementation of texture locking: grab the shared tex 16524a49301eSmrg * mutex. Examine the shared context state timestamp and if there has 16534a49301eSmrg * been a change, set the appropriate bits in ctx->NewState. 16547117f1b4Smrg * 1655c1f859d4Smrg * This is used to deal with synchronizing things when a texture object 1656c1f859d4Smrg * is used/modified by different contexts (or threads) which are sharing 1657c1f859d4Smrg * the texture. 1658c1f859d4Smrg * 1659c1f859d4Smrg * See also _mesa_lock/unlock_texture() in teximage.h 16607117f1b4Smrg */ 1661c1f859d4Smrgvoid 16623464ebd5Sriastradh_mesa_lock_context_textures( struct gl_context *ctx ) 16637117f1b4Smrg{ 1664af69d88dSmrg mtx_lock(&ctx->Shared->TexMutex); 16657117f1b4Smrg 16667117f1b4Smrg if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) { 16677117f1b4Smrg ctx->NewState |= _NEW_TEXTURE; 16687117f1b4Smrg ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp; 16697117f1b4Smrg } 16707117f1b4Smrg} 16717117f1b4Smrg 16727117f1b4Smrg 1673c1f859d4Smrgvoid 16743464ebd5Sriastradh_mesa_unlock_context_textures( struct gl_context *ctx ) 16757117f1b4Smrg{ 16767117f1b4Smrg assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp); 1677af69d88dSmrg mtx_unlock(&ctx->Shared->TexMutex); 1678af69d88dSmrg} 1679af69d88dSmrg 1680af69d88dSmrgvoid GLAPIENTRY 1681af69d88dSmrg_mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset, 1682af69d88dSmrg GLint yoffset, GLint zoffset, GLsizei width, 1683af69d88dSmrg GLsizei height, GLsizei depth) 1684af69d88dSmrg{ 1685af69d88dSmrg struct gl_texture_object *t; 1686af69d88dSmrg struct gl_texture_image *image; 1687af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 1688af69d88dSmrg 1689af69d88dSmrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1690af69d88dSmrg _mesa_debug(ctx, "glInvalidateTexSubImage %d\n", texture); 1691af69d88dSmrg 1692af69d88dSmrg t = invalidate_tex_image_error_check(ctx, texture, level, 1693af69d88dSmrg "glInvalidateTexSubImage"); 1694af69d88dSmrg 1695af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 1696af69d88dSmrg * 1697af69d88dSmrg * "...the specified subregion must be between -<b> and <dim>+<b> where 1698af69d88dSmrg * <dim> is the size of the dimension of the texture image, and <b> is 1699af69d88dSmrg * the size of the border of that texture image, otherwise 1700af69d88dSmrg * INVALID_VALUE is generated (border is not applied to dimensions that 1701af69d88dSmrg * don't exist in a given texture target)." 1702af69d88dSmrg */ 1703af69d88dSmrg image = t->Image[0][level]; 1704af69d88dSmrg if (image) { 1705af69d88dSmrg int xBorder; 1706af69d88dSmrg int yBorder; 1707af69d88dSmrg int zBorder; 1708af69d88dSmrg int imageWidth; 1709af69d88dSmrg int imageHeight; 1710af69d88dSmrg int imageDepth; 1711af69d88dSmrg 1712af69d88dSmrg /* The GL_ARB_invalidate_subdata spec says: 1713af69d88dSmrg * 1714af69d88dSmrg * "For texture targets that don't have certain dimensions, this 1715af69d88dSmrg * command treats those dimensions as having a size of 1. For 1716af69d88dSmrg * example, to invalidate a portion of a two-dimensional texture, 1717af69d88dSmrg * the application would use <zoffset> equal to zero and <depth> 1718af69d88dSmrg * equal to one." 1719af69d88dSmrg */ 1720af69d88dSmrg switch (t->Target) { 1721af69d88dSmrg case GL_TEXTURE_BUFFER: 1722af69d88dSmrg xBorder = 0; 1723af69d88dSmrg yBorder = 0; 1724af69d88dSmrg zBorder = 0; 1725af69d88dSmrg imageWidth = 1; 1726af69d88dSmrg imageHeight = 1; 1727af69d88dSmrg imageDepth = 1; 1728af69d88dSmrg break; 1729af69d88dSmrg case GL_TEXTURE_1D: 1730af69d88dSmrg xBorder = image->Border; 1731af69d88dSmrg yBorder = 0; 1732af69d88dSmrg zBorder = 0; 1733af69d88dSmrg imageWidth = image->Width; 1734af69d88dSmrg imageHeight = 1; 1735af69d88dSmrg imageDepth = 1; 1736af69d88dSmrg break; 1737af69d88dSmrg case GL_TEXTURE_1D_ARRAY: 1738af69d88dSmrg xBorder = image->Border; 1739af69d88dSmrg yBorder = 0; 1740af69d88dSmrg zBorder = 0; 1741af69d88dSmrg imageWidth = image->Width; 1742af69d88dSmrg imageHeight = image->Height; 1743af69d88dSmrg imageDepth = 1; 1744af69d88dSmrg break; 1745af69d88dSmrg case GL_TEXTURE_2D: 1746af69d88dSmrg case GL_TEXTURE_CUBE_MAP: 1747af69d88dSmrg case GL_TEXTURE_RECTANGLE: 1748af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE: 1749af69d88dSmrg xBorder = image->Border; 1750af69d88dSmrg yBorder = image->Border; 1751af69d88dSmrg zBorder = 0; 1752af69d88dSmrg imageWidth = image->Width; 1753af69d88dSmrg imageHeight = image->Height; 1754af69d88dSmrg imageDepth = 1; 1755af69d88dSmrg break; 1756af69d88dSmrg case GL_TEXTURE_2D_ARRAY: 1757af69d88dSmrg case GL_TEXTURE_CUBE_MAP_ARRAY: 1758af69d88dSmrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 1759af69d88dSmrg xBorder = image->Border; 1760af69d88dSmrg yBorder = image->Border; 1761af69d88dSmrg zBorder = 0; 1762af69d88dSmrg imageWidth = image->Width; 1763af69d88dSmrg imageHeight = image->Height; 1764af69d88dSmrg imageDepth = image->Depth; 1765af69d88dSmrg break; 1766af69d88dSmrg case GL_TEXTURE_3D: 1767af69d88dSmrg xBorder = image->Border; 1768af69d88dSmrg yBorder = image->Border; 1769af69d88dSmrg zBorder = image->Border; 1770af69d88dSmrg imageWidth = image->Width; 1771af69d88dSmrg imageHeight = image->Height; 1772af69d88dSmrg imageDepth = image->Depth; 1773af69d88dSmrg break; 1774af69d88dSmrg default: 1775af69d88dSmrg assert(!"Should not get here."); 1776af69d88dSmrg xBorder = 0; 1777af69d88dSmrg yBorder = 0; 1778af69d88dSmrg zBorder = 0; 1779af69d88dSmrg imageWidth = 0; 1780af69d88dSmrg imageHeight = 0; 1781af69d88dSmrg imageDepth = 0; 1782af69d88dSmrg break; 1783af69d88dSmrg } 1784af69d88dSmrg 1785af69d88dSmrg if (xoffset < -xBorder) { 1786af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(xoffset)"); 1787af69d88dSmrg return; 1788af69d88dSmrg } 1789af69d88dSmrg 1790af69d88dSmrg if (xoffset + width > imageWidth + xBorder) { 1791af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 1792af69d88dSmrg "glInvalidateSubTexImage(xoffset+width)"); 1793af69d88dSmrg return; 1794af69d88dSmrg } 1795af69d88dSmrg 1796af69d88dSmrg if (yoffset < -yBorder) { 1797af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(yoffset)"); 1798af69d88dSmrg return; 1799af69d88dSmrg } 1800af69d88dSmrg 1801af69d88dSmrg if (yoffset + height > imageHeight + yBorder) { 1802af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 1803af69d88dSmrg "glInvalidateSubTexImage(yoffset+height)"); 1804af69d88dSmrg return; 1805af69d88dSmrg } 1806af69d88dSmrg 1807af69d88dSmrg if (zoffset < -zBorder) { 1808af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 1809af69d88dSmrg "glInvalidateSubTexImage(zoffset)"); 1810af69d88dSmrg return; 1811af69d88dSmrg } 1812af69d88dSmrg 1813af69d88dSmrg if (zoffset + depth > imageDepth + zBorder) { 1814af69d88dSmrg _mesa_error(ctx, GL_INVALID_VALUE, 1815af69d88dSmrg "glInvalidateSubTexImage(zoffset+depth)"); 1816af69d88dSmrg return; 1817af69d88dSmrg } 1818af69d88dSmrg } 1819af69d88dSmrg 1820af69d88dSmrg /* We don't actually do anything for this yet. Just return after 1821af69d88dSmrg * validating the parameters and generating the required errors. 1822af69d88dSmrg */ 1823af69d88dSmrg return; 1824af69d88dSmrg} 1825af69d88dSmrg 1826af69d88dSmrgvoid GLAPIENTRY 1827af69d88dSmrg_mesa_InvalidateTexImage(GLuint texture, GLint level) 1828af69d88dSmrg{ 1829af69d88dSmrg GET_CURRENT_CONTEXT(ctx); 1830af69d88dSmrg 1831af69d88dSmrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1832af69d88dSmrg _mesa_debug(ctx, "glInvalidateTexImage(%d, %d)\n", texture, level); 1833af69d88dSmrg 1834af69d88dSmrg invalidate_tex_image_error_check(ctx, texture, level, 1835af69d88dSmrg "glInvalidateTexImage"); 1836af69d88dSmrg 1837af69d88dSmrg /* We don't actually do anything for this yet. Just return after 1838af69d88dSmrg * validating the parameters and generating the required errors. 1839af69d88dSmrg */ 1840af69d88dSmrg return; 18417117f1b4Smrg} 18427117f1b4Smrg 18437117f1b4Smrg/*@}*/ 1844