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
3101e04c3fSmrg#include <stdio.h>
323464ebd5Sriastradh#include "bufferobj.h"
337117f1b4Smrg#include "context.h"
347117f1b4Smrg#include "enums.h"
357117f1b4Smrg#include "fbobject.h"
364a49301eSmrg#include "formats.h"
377117f1b4Smrg#include "hash.h"
387ec681f3Smrg
397117f1b4Smrg#include "macros.h"
4001e04c3fSmrg#include "shaderimage.h"
417117f1b4Smrg#include "teximage.h"
427117f1b4Smrg#include "texobj.h"
433464ebd5Sriastradh#include "texstate.h"
447117f1b4Smrg#include "mtypes.h"
453464ebd5Sriastradh#include "program/prog_instruction.h"
4601e04c3fSmrg#include "texturebindless.h"
477ec681f3Smrg#include "util/u_memory.h"
484a49301eSmrg
497117f1b4Smrg
507117f1b4Smrg
517117f1b4Smrg/**********************************************************************/
527117f1b4Smrg/** \name Internal functions */
537117f1b4Smrg/*@{*/
547117f1b4Smrg
5501e04c3fSmrg/**
5601e04c3fSmrg * This function checks for all valid combinations of Min and Mag filters for
5701e04c3fSmrg * Float types, when extensions like OES_texture_float and
5801e04c3fSmrg * OES_texture_float_linear are supported. OES_texture_float mentions support
5901e04c3fSmrg * for NEAREST, NEAREST_MIPMAP_NEAREST magnification and minification filters.
6001e04c3fSmrg * Mag filters like LINEAR and min filters like NEAREST_MIPMAP_LINEAR,
6101e04c3fSmrg * LINEAR_MIPMAP_NEAREST and LINEAR_MIPMAP_LINEAR are only valid in case
6201e04c3fSmrg * OES_texture_float_linear is supported.
6301e04c3fSmrg *
6401e04c3fSmrg * Returns true in case the filter is valid for given Float type else false.
6501e04c3fSmrg */
6601e04c3fSmrgstatic bool
6701e04c3fSmrgvalid_filter_for_float(const struct gl_context *ctx,
6801e04c3fSmrg                       const struct gl_texture_object *obj)
6901e04c3fSmrg{
707ec681f3Smrg   switch (obj->Sampler.Attrib.MagFilter) {
7101e04c3fSmrg   case GL_LINEAR:
7201e04c3fSmrg      if (obj->_IsHalfFloat && !ctx->Extensions.OES_texture_half_float_linear) {
7301e04c3fSmrg         return false;
7401e04c3fSmrg      } else if (obj->_IsFloat && !ctx->Extensions.OES_texture_float_linear) {
7501e04c3fSmrg         return false;
7601e04c3fSmrg      }
777ec681f3Smrg      FALLTHROUGH;
7801e04c3fSmrg   case GL_NEAREST:
7901e04c3fSmrg   case GL_NEAREST_MIPMAP_NEAREST:
8001e04c3fSmrg      break;
8101e04c3fSmrg   default:
8201e04c3fSmrg      unreachable("Invalid mag filter");
8301e04c3fSmrg   }
8401e04c3fSmrg
857ec681f3Smrg   switch (obj->Sampler.Attrib.MinFilter) {
8601e04c3fSmrg   case GL_LINEAR:
8701e04c3fSmrg   case GL_NEAREST_MIPMAP_LINEAR:
8801e04c3fSmrg   case GL_LINEAR_MIPMAP_NEAREST:
8901e04c3fSmrg   case GL_LINEAR_MIPMAP_LINEAR:
9001e04c3fSmrg      if (obj->_IsHalfFloat && !ctx->Extensions.OES_texture_half_float_linear) {
9101e04c3fSmrg         return false;
9201e04c3fSmrg      } else if (obj->_IsFloat && !ctx->Extensions.OES_texture_float_linear) {
9301e04c3fSmrg         return false;
9401e04c3fSmrg      }
957ec681f3Smrg      FALLTHROUGH;
9601e04c3fSmrg   case GL_NEAREST:
9701e04c3fSmrg   case GL_NEAREST_MIPMAP_NEAREST:
9801e04c3fSmrg      break;
9901e04c3fSmrg   default:
10001e04c3fSmrg      unreachable("Invalid min filter");
10101e04c3fSmrg   }
10201e04c3fSmrg
10301e04c3fSmrg   return true;
10401e04c3fSmrg}
1057117f1b4Smrg
1067117f1b4Smrg/**
1077117f1b4Smrg * Return the gl_texture_object for a given ID.
1087117f1b4Smrg */
1097117f1b4Smrgstruct gl_texture_object *
1103464ebd5Sriastradh_mesa_lookup_texture(struct gl_context *ctx, GLuint id)
1117117f1b4Smrg{
1127117f1b4Smrg   return (struct gl_texture_object *)
1137117f1b4Smrg      _mesa_HashLookup(ctx->Shared->TexObjects, id);
1147117f1b4Smrg}
1157117f1b4Smrg
11601e04c3fSmrg/**
11701e04c3fSmrg * Wrapper around _mesa_lookup_texture that throws GL_INVALID_OPERATION if id
11801e04c3fSmrg * is not in the hash table. After calling _mesa_error, it returns NULL.
11901e04c3fSmrg */
12001e04c3fSmrgstruct gl_texture_object *
12101e04c3fSmrg_mesa_lookup_texture_err(struct gl_context *ctx, GLuint id, const char* func)
122af69d88dSmrg{
12301e04c3fSmrg   struct gl_texture_object *texObj = NULL;
124af69d88dSmrg
12501e04c3fSmrg   if (id > 0)
12601e04c3fSmrg      texObj = _mesa_lookup_texture(ctx, id); /* Returns NULL if not found. */
127af69d88dSmrg
12801e04c3fSmrg   if (!texObj)
12901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "%s(texture)", func);
13001e04c3fSmrg
13101e04c3fSmrg   return texObj;
132af69d88dSmrg}
133af69d88dSmrg
134af69d88dSmrg
135af69d88dSmrgstruct gl_texture_object *
136af69d88dSmrg_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id)
137af69d88dSmrg{
138af69d88dSmrg   return (struct gl_texture_object *)
139af69d88dSmrg      _mesa_HashLookupLocked(ctx->Shared->TexObjects, id);
140af69d88dSmrg}
141af69d88dSmrg
14201e04c3fSmrg/**
14301e04c3fSmrg * Return a pointer to the current texture object for the given target
14401e04c3fSmrg * on the current texture unit.
14501e04c3fSmrg * Note: all <target> error checking should have been done by this point.
14601e04c3fSmrg */
14701e04c3fSmrgstruct gl_texture_object *
14801e04c3fSmrg_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target)
14901e04c3fSmrg{
15001e04c3fSmrg   struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx);
15101e04c3fSmrg   const GLboolean arrayTex = ctx->Extensions.EXT_texture_array;
15201e04c3fSmrg
15301e04c3fSmrg   switch (target) {
15401e04c3fSmrg      case GL_TEXTURE_1D:
15501e04c3fSmrg         return texUnit->CurrentTex[TEXTURE_1D_INDEX];
15601e04c3fSmrg      case GL_PROXY_TEXTURE_1D:
15701e04c3fSmrg         return ctx->Texture.ProxyTex[TEXTURE_1D_INDEX];
15801e04c3fSmrg      case GL_TEXTURE_2D:
15901e04c3fSmrg         return texUnit->CurrentTex[TEXTURE_2D_INDEX];
16001e04c3fSmrg      case GL_PROXY_TEXTURE_2D:
16101e04c3fSmrg         return ctx->Texture.ProxyTex[TEXTURE_2D_INDEX];
16201e04c3fSmrg      case GL_TEXTURE_3D:
16301e04c3fSmrg         return texUnit->CurrentTex[TEXTURE_3D_INDEX];
16401e04c3fSmrg      case GL_PROXY_TEXTURE_3D:
16501e04c3fSmrg         return ctx->Texture.ProxyTex[TEXTURE_3D_INDEX];
16601e04c3fSmrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
16701e04c3fSmrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
16801e04c3fSmrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
16901e04c3fSmrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
17001e04c3fSmrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
17101e04c3fSmrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
17201e04c3fSmrg      case GL_TEXTURE_CUBE_MAP:
17301e04c3fSmrg         return ctx->Extensions.ARB_texture_cube_map
17401e04c3fSmrg                ? texUnit->CurrentTex[TEXTURE_CUBE_INDEX] : NULL;
17501e04c3fSmrg      case GL_PROXY_TEXTURE_CUBE_MAP:
17601e04c3fSmrg         return ctx->Extensions.ARB_texture_cube_map
17701e04c3fSmrg                ? ctx->Texture.ProxyTex[TEXTURE_CUBE_INDEX] : NULL;
17801e04c3fSmrg      case GL_TEXTURE_CUBE_MAP_ARRAY:
17901e04c3fSmrg         return _mesa_has_texture_cube_map_array(ctx)
18001e04c3fSmrg                ? texUnit->CurrentTex[TEXTURE_CUBE_ARRAY_INDEX] : NULL;
18101e04c3fSmrg      case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
18201e04c3fSmrg         return _mesa_has_texture_cube_map_array(ctx)
18301e04c3fSmrg                ? ctx->Texture.ProxyTex[TEXTURE_CUBE_ARRAY_INDEX] : NULL;
18401e04c3fSmrg      case GL_TEXTURE_RECTANGLE_NV:
18501e04c3fSmrg         return ctx->Extensions.NV_texture_rectangle
18601e04c3fSmrg                ? texUnit->CurrentTex[TEXTURE_RECT_INDEX] : NULL;
18701e04c3fSmrg      case GL_PROXY_TEXTURE_RECTANGLE_NV:
18801e04c3fSmrg         return ctx->Extensions.NV_texture_rectangle
18901e04c3fSmrg                ? ctx->Texture.ProxyTex[TEXTURE_RECT_INDEX] : NULL;
19001e04c3fSmrg      case GL_TEXTURE_1D_ARRAY_EXT:
19101e04c3fSmrg         return arrayTex ? texUnit->CurrentTex[TEXTURE_1D_ARRAY_INDEX] : NULL;
19201e04c3fSmrg      case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
19301e04c3fSmrg         return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_1D_ARRAY_INDEX] : NULL;
19401e04c3fSmrg      case GL_TEXTURE_2D_ARRAY_EXT:
19501e04c3fSmrg         return arrayTex ? texUnit->CurrentTex[TEXTURE_2D_ARRAY_INDEX] : NULL;
19601e04c3fSmrg      case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
19701e04c3fSmrg         return arrayTex ? ctx->Texture.ProxyTex[TEXTURE_2D_ARRAY_INDEX] : NULL;
19801e04c3fSmrg      case GL_TEXTURE_BUFFER:
19901e04c3fSmrg         return (_mesa_has_ARB_texture_buffer_object(ctx) ||
20001e04c3fSmrg                 _mesa_has_OES_texture_buffer(ctx)) ?
20101e04c3fSmrg                texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL;
20201e04c3fSmrg      case GL_TEXTURE_EXTERNAL_OES:
20301e04c3fSmrg         return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
20401e04c3fSmrg            ? texUnit->CurrentTex[TEXTURE_EXTERNAL_INDEX] : NULL;
20501e04c3fSmrg      case GL_TEXTURE_2D_MULTISAMPLE:
20601e04c3fSmrg         return ctx->Extensions.ARB_texture_multisample
20701e04c3fSmrg            ? texUnit->CurrentTex[TEXTURE_2D_MULTISAMPLE_INDEX] : NULL;
20801e04c3fSmrg      case GL_PROXY_TEXTURE_2D_MULTISAMPLE:
20901e04c3fSmrg         return ctx->Extensions.ARB_texture_multisample
21001e04c3fSmrg            ? ctx->Texture.ProxyTex[TEXTURE_2D_MULTISAMPLE_INDEX] : NULL;
21101e04c3fSmrg      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
21201e04c3fSmrg         return ctx->Extensions.ARB_texture_multisample
21301e04c3fSmrg            ? texUnit->CurrentTex[TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX] : NULL;
21401e04c3fSmrg      case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY:
21501e04c3fSmrg         return ctx->Extensions.ARB_texture_multisample
21601e04c3fSmrg            ? ctx->Texture.ProxyTex[TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX] : NULL;
21701e04c3fSmrg      default:
21801e04c3fSmrg         _mesa_problem(NULL, "bad target in _mesa_get_current_tex_object()");
21901e04c3fSmrg         return NULL;
22001e04c3fSmrg   }
22101e04c3fSmrg}
22201e04c3fSmrg
2237117f1b4Smrg
2247ec681f3Smrg/**
2257ec681f3Smrg * Get the texture object for given target and texunit
2267ec681f3Smrg * Proxy targets are accepted only allowProxyTarget is true.
2277ec681f3Smrg * Return NULL if any error (and record the error).
2287ec681f3Smrg */
2297ec681f3Smrgstruct gl_texture_object *
2307ec681f3Smrg_mesa_get_texobj_by_target_and_texunit(struct gl_context *ctx, GLenum target,
2317ec681f3Smrg                                       GLuint texunit, bool allowProxyTarget,
2327ec681f3Smrg                                       const char* caller)
2337ec681f3Smrg{
2347ec681f3Smrg   struct gl_texture_unit *texUnit;
2357ec681f3Smrg   int targetIndex;
2367ec681f3Smrg
2377ec681f3Smrg   if (_mesa_is_proxy_texture(target) && allowProxyTarget) {
2387ec681f3Smrg      return _mesa_get_current_tex_object(ctx, target);
2397ec681f3Smrg   }
2407ec681f3Smrg
2417ec681f3Smrg   if (texunit >= ctx->Const.MaxCombinedTextureImageUnits) {
2427ec681f3Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
2437ec681f3Smrg                  "%s(texunit=%d)", caller, texunit);
2447ec681f3Smrg      return NULL;
2457ec681f3Smrg   }
2467ec681f3Smrg
2477ec681f3Smrg   texUnit = _mesa_get_tex_unit(ctx, texunit);
2487ec681f3Smrg
2497ec681f3Smrg   targetIndex = _mesa_tex_target_to_index(ctx, target);
2507ec681f3Smrg   if (targetIndex < 0 || targetIndex == TEXTURE_BUFFER_INDEX) {
2517ec681f3Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", caller);
2527ec681f3Smrg      return NULL;
2537ec681f3Smrg   }
2547ec681f3Smrg   assert(targetIndex < NUM_TEXTURE_TARGETS);
2557ec681f3Smrg
2567ec681f3Smrg   return texUnit->CurrentTex[targetIndex];
2577ec681f3Smrg}
2587ec681f3Smrg
2597ec681f3Smrg
2607117f1b4Smrg/**
2617117f1b4Smrg * Allocate and initialize a new texture object.  But don't put it into the
2627117f1b4Smrg * texture object hash table.
2637117f1b4Smrg *
2647117f1b4Smrg * Called via ctx->Driver.NewTextureObject, unless overridden by a device
2657117f1b4Smrg * driver.
26601e04c3fSmrg *
2677117f1b4Smrg * \param shared the shared GL state structure to contain the texture object
2687117f1b4Smrg * \param name integer name for the texture object
2697117f1b4Smrg * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D,
27001e04c3fSmrg * GL_TEXTURE_CUBE_MAP or GL_TEXTURE_RECTANGLE_NV.  zero is ok for the sake
2717117f1b4Smrg * of GenTextures()
2727117f1b4Smrg *
2737117f1b4Smrg * \return pointer to new texture object.
2747117f1b4Smrg */
2757117f1b4Smrgstruct gl_texture_object *
27601e04c3fSmrg_mesa_new_texture_object(struct gl_context *ctx, GLuint name, GLenum target)
2777117f1b4Smrg{
2787117f1b4Smrg   struct gl_texture_object *obj;
27901e04c3fSmrg
2807117f1b4Smrg   obj = MALLOC_STRUCT(gl_texture_object);
28101e04c3fSmrg   if (!obj)
28201e04c3fSmrg      return NULL;
28301e04c3fSmrg
284af69d88dSmrg   _mesa_initialize_texture_object(ctx, obj, name, target);
2857117f1b4Smrg   return obj;
2867117f1b4Smrg}
2877117f1b4Smrg
2887117f1b4Smrg
2897117f1b4Smrg/**
2907117f1b4Smrg * Initialize a new texture object to default values.
2917117f1b4Smrg * \param obj  the texture object
2927117f1b4Smrg * \param name  the texture name
2937117f1b4Smrg * \param target  the texture target
2947117f1b4Smrg */
2957117f1b4Smrgvoid
296af69d88dSmrg_mesa_initialize_texture_object( struct gl_context *ctx,
297af69d88dSmrg                                 struct gl_texture_object *obj,
2987117f1b4Smrg                                 GLuint name, GLenum target )
2997117f1b4Smrg{
30001e04c3fSmrg   assert(target == 0 ||
3017117f1b4Smrg          target == GL_TEXTURE_1D ||
3027117f1b4Smrg          target == GL_TEXTURE_2D ||
3037117f1b4Smrg          target == GL_TEXTURE_3D ||
30401e04c3fSmrg          target == GL_TEXTURE_CUBE_MAP ||
305c1f859d4Smrg          target == GL_TEXTURE_RECTANGLE_NV ||
306c1f859d4Smrg          target == GL_TEXTURE_1D_ARRAY_EXT ||
3073464ebd5Sriastradh          target == GL_TEXTURE_2D_ARRAY_EXT ||
308af69d88dSmrg          target == GL_TEXTURE_EXTERNAL_OES ||
309af69d88dSmrg          target == GL_TEXTURE_CUBE_MAP_ARRAY ||
310af69d88dSmrg          target == GL_TEXTURE_BUFFER ||
311af69d88dSmrg          target == GL_TEXTURE_2D_MULTISAMPLE ||
312af69d88dSmrg          target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY);
3137117f1b4Smrg
314cdc920a0Smrg   memset(obj, 0, sizeof(*obj));
3157117f1b4Smrg   /* init the non-zero fields */
3167117f1b4Smrg   obj->RefCount = 1;
3177117f1b4Smrg   obj->Name = name;
3187117f1b4Smrg   obj->Target = target;
31901e04c3fSmrg   if (target != 0) {
32001e04c3fSmrg      obj->TargetIndex = _mesa_tex_target_to_index(ctx, target);
32101e04c3fSmrg   }
32201e04c3fSmrg   else {
32301e04c3fSmrg      obj->TargetIndex = NUM_TEXTURE_TARGETS; /* invalid/error value */
32401e04c3fSmrg   }
3257ec681f3Smrg   obj->Attrib.Priority = 1.0F;
3267ec681f3Smrg   obj->Attrib.BaseLevel = 0;
3277ec681f3Smrg   obj->Attrib.MaxLevel = 1000;
3283464ebd5Sriastradh
329af69d88dSmrg   /* must be one; no support for (YUV) planes in separate buffers */
330af69d88dSmrg   obj->RequiredTextureImageUnits = 1;
331af69d88dSmrg
3323464ebd5Sriastradh   /* sampler state */
3337ec681f3Smrg   if (target == GL_TEXTURE_RECTANGLE_NV ||
3347ec681f3Smrg       target == GL_TEXTURE_EXTERNAL_OES) {
3357ec681f3Smrg      obj->Sampler.Attrib.WrapS = GL_CLAMP_TO_EDGE;
3367ec681f3Smrg      obj->Sampler.Attrib.WrapT = GL_CLAMP_TO_EDGE;
3377ec681f3Smrg      obj->Sampler.Attrib.WrapR = GL_CLAMP_TO_EDGE;
3387ec681f3Smrg      obj->Sampler.Attrib.MinFilter = GL_LINEAR;
3397ec681f3Smrg      obj->Sampler.Attrib.state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
3407ec681f3Smrg      obj->Sampler.Attrib.state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
3417ec681f3Smrg      obj->Sampler.Attrib.state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
3427ec681f3Smrg      obj->Sampler.Attrib.state.min_img_filter = PIPE_TEX_FILTER_LINEAR;
3437ec681f3Smrg      obj->Sampler.Attrib.state.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
3447117f1b4Smrg   }
3457ec681f3Smrg   else {
3467ec681f3Smrg      obj->Sampler.Attrib.WrapS = GL_REPEAT;
3477ec681f3Smrg      obj->Sampler.Attrib.WrapT = GL_REPEAT;
3487ec681f3Smrg      obj->Sampler.Attrib.WrapR = GL_REPEAT;
3497ec681f3Smrg      obj->Sampler.Attrib.MinFilter = GL_NEAREST_MIPMAP_LINEAR;
3507ec681f3Smrg      obj->Sampler.Attrib.state.wrap_s = PIPE_TEX_WRAP_REPEAT;
3517ec681f3Smrg      obj->Sampler.Attrib.state.wrap_t = PIPE_TEX_WRAP_REPEAT;
3527ec681f3Smrg      obj->Sampler.Attrib.state.wrap_r = PIPE_TEX_WRAP_REPEAT;
3537ec681f3Smrg      obj->Sampler.Attrib.state.min_img_filter = PIPE_TEX_FILTER_NEAREST;
3547ec681f3Smrg      obj->Sampler.Attrib.state.min_mip_filter = PIPE_TEX_MIPFILTER_LINEAR;
3557ec681f3Smrg   }
3567ec681f3Smrg   obj->Sampler.Attrib.MagFilter = GL_LINEAR;
3577ec681f3Smrg   obj->Sampler.Attrib.state.mag_img_filter = PIPE_TEX_FILTER_LINEAR;
3587ec681f3Smrg   obj->Sampler.Attrib.MinLod = -1000.0;
3597ec681f3Smrg   obj->Sampler.Attrib.MaxLod = 1000.0;
3607ec681f3Smrg   obj->Sampler.Attrib.state.min_lod = 0; /* no negative numbers */
3617ec681f3Smrg   obj->Sampler.Attrib.state.max_lod = 1000;
3627ec681f3Smrg   obj->Sampler.Attrib.LodBias = 0.0;
3637ec681f3Smrg   obj->Sampler.Attrib.state.lod_bias = 0;
3647ec681f3Smrg   obj->Sampler.Attrib.MaxAnisotropy = 1.0;
3657ec681f3Smrg   obj->Sampler.Attrib.state.max_anisotropy = 0; /* gallium sets 0 instead of 1 */
3667ec681f3Smrg   obj->Sampler.Attrib.CompareMode = GL_NONE;         /* ARB_shadow */
3677ec681f3Smrg   obj->Sampler.Attrib.CompareFunc = GL_LEQUAL;       /* ARB_shadow */
3687ec681f3Smrg   obj->Sampler.Attrib.state.compare_mode = PIPE_TEX_COMPARE_NONE;
3697ec681f3Smrg   obj->Sampler.Attrib.state.compare_func = PIPE_FUNC_LEQUAL;
3707ec681f3Smrg   obj->Attrib.DepthMode = ctx->API == API_OPENGL_CORE ? GL_RED : GL_LUMINANCE;
371af69d88dSmrg   obj->StencilSampling = false;
3727ec681f3Smrg   obj->Sampler.Attrib.CubeMapSeamless = GL_FALSE;
3737ec681f3Smrg   obj->Sampler.Attrib.state.seamless_cube_map = false;
37401e04c3fSmrg   obj->Sampler.HandleAllocated = GL_FALSE;
3757ec681f3Smrg   obj->Attrib.Swizzle[0] = GL_RED;
3767ec681f3Smrg   obj->Attrib.Swizzle[1] = GL_GREEN;
3777ec681f3Smrg   obj->Attrib.Swizzle[2] = GL_BLUE;
3787ec681f3Smrg   obj->Attrib.Swizzle[3] = GL_ALPHA;
3797ec681f3Smrg   obj->Attrib._Swizzle = SWIZZLE_NOOP;
3807ec681f3Smrg   obj->Sampler.Attrib.sRGBDecode = GL_DECODE_EXT;
3817ec681f3Smrg   obj->Sampler.Attrib.ReductionMode = GL_WEIGHTED_AVERAGE_EXT;
3827ec681f3Smrg   obj->Sampler.Attrib.state.reduction_mode = PIPE_TEX_REDUCTION_WEIGHTED_AVERAGE;
3837ec681f3Smrg   obj->BufferObjectFormat = ctx->API == API_OPENGL_COMPAT ? GL_LUMINANCE8 : GL_R8;
3847ec681f3Smrg   obj->_BufferObjectFormat = ctx->API == API_OPENGL_COMPAT
3857ec681f3Smrg      ? MESA_FORMAT_L_UNORM8 : MESA_FORMAT_R_UNORM8;
3867ec681f3Smrg   obj->Attrib.ImageFormatCompatibilityType = GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE;
38701e04c3fSmrg
38801e04c3fSmrg   /* GL_ARB_bindless_texture */
38901e04c3fSmrg   _mesa_init_texture_handles(obj);
390c1f859d4Smrg}
391c1f859d4Smrg
392c1f859d4Smrg
393c1f859d4Smrg/**
394c1f859d4Smrg * Some texture initialization can't be finished until we know which
395c1f859d4Smrg * target it's getting bound to (GL_TEXTURE_1D/2D/etc).
396c1f859d4Smrg */
397c1f859d4Smrgstatic void
3983464ebd5Sriastradhfinish_texture_init(struct gl_context *ctx, GLenum target,
39901e04c3fSmrg                    struct gl_texture_object *obj, int targetIndex)
400c1f859d4Smrg{
401af69d88dSmrg   GLenum filter = GL_LINEAR;
402c1f859d4Smrg   assert(obj->Target == 0);
403c1f859d4Smrg
40401e04c3fSmrg   obj->Target = target;
40501e04c3fSmrg   obj->TargetIndex = targetIndex;
40601e04c3fSmrg   assert(obj->TargetIndex < NUM_TEXTURE_TARGETS);
40701e04c3fSmrg
408af69d88dSmrg   switch (target) {
409af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE:
410af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
411af69d88dSmrg         filter = GL_NEAREST;
4127ec681f3Smrg         FALLTHROUGH;
413af69d88dSmrg
414af69d88dSmrg      case GL_TEXTURE_RECTANGLE_NV:
415af69d88dSmrg      case GL_TEXTURE_EXTERNAL_OES:
416af69d88dSmrg         /* have to init wrap and filter state here - kind of klunky */
4177ec681f3Smrg         obj->Sampler.Attrib.WrapS = GL_CLAMP_TO_EDGE;
4187ec681f3Smrg         obj->Sampler.Attrib.WrapT = GL_CLAMP_TO_EDGE;
4197ec681f3Smrg         obj->Sampler.Attrib.WrapR = GL_CLAMP_TO_EDGE;
4207ec681f3Smrg         obj->Sampler.Attrib.state.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
4217ec681f3Smrg         obj->Sampler.Attrib.state.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
4227ec681f3Smrg         obj->Sampler.Attrib.state.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE;
4237ec681f3Smrg         obj->Sampler.Attrib.MinFilter = filter;
4247ec681f3Smrg         obj->Sampler.Attrib.MagFilter = filter;
4257ec681f3Smrg         obj->Sampler.Attrib.state.min_img_filter = filter_to_gallium(filter);
4267ec681f3Smrg         obj->Sampler.Attrib.state.min_mip_filter = mipfilter_to_gallium(filter);
4277ec681f3Smrg         obj->Sampler.Attrib.state.mag_img_filter = filter_to_gallium(filter);
428af69d88dSmrg         if (ctx->Driver.TexParameter) {
42901e04c3fSmrg            /* XXX we probably don't need to make all these calls */
43001e04c3fSmrg            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_S);
43101e04c3fSmrg            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_T);
43201e04c3fSmrg            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_R);
43301e04c3fSmrg            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_MIN_FILTER);
43401e04c3fSmrg            ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_MAG_FILTER);
435af69d88dSmrg         }
436af69d88dSmrg         break;
437af69d88dSmrg
438af69d88dSmrg      default:
439af69d88dSmrg         /* nothing needs done */
440af69d88dSmrg         break;
441c1f859d4Smrg   }
4427117f1b4Smrg}
4437117f1b4Smrg
4447117f1b4Smrg
4457117f1b4Smrg/**
4467117f1b4Smrg * Deallocate a texture object struct.  It should have already been
4477117f1b4Smrg * removed from the texture object pool.
448c1f859d4Smrg * Called via ctx->Driver.DeleteTexture() if not overriden by a driver.
4497117f1b4Smrg *
4507117f1b4Smrg * \param shared the shared GL state to which the object belongs.
4514a49301eSmrg * \param texObj the texture object to delete.
4527117f1b4Smrg */
4537117f1b4Smrgvoid
4543464ebd5Sriastradh_mesa_delete_texture_object(struct gl_context *ctx,
4553464ebd5Sriastradh                            struct gl_texture_object *texObj)
4567117f1b4Smrg{
4577117f1b4Smrg   GLuint i, face;
4587117f1b4Smrg
4597117f1b4Smrg   /* Set Target to an invalid value.  With some assertions elsewhere
4607117f1b4Smrg    * we can try to detect possible use of deleted textures.
4617117f1b4Smrg    */
4627117f1b4Smrg   texObj->Target = 0x99;
4637117f1b4Smrg
4647117f1b4Smrg   /* free the texture images */
4657117f1b4Smrg   for (face = 0; face < 6; face++) {
4667117f1b4Smrg      for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
4673464ebd5Sriastradh         if (texObj->Image[face][i]) {
468af69d88dSmrg            ctx->Driver.DeleteTextureImage(ctx, texObj->Image[face][i]);
4693464ebd5Sriastradh         }
4707117f1b4Smrg      }
4717117f1b4Smrg   }
4727117f1b4Smrg
47301e04c3fSmrg   /* Delete all texture/image handles. */
47401e04c3fSmrg   _mesa_delete_texture_handles(ctx, texObj);
47501e04c3fSmrg
4767ec681f3Smrg   _mesa_reference_buffer_object_shared(ctx, &texObj->BufferObject, NULL);
477af69d88dSmrg   free(texObj->Label);
4787117f1b4Smrg
4797117f1b4Smrg   /* free this object */
480cdc920a0Smrg   free(texObj);
4817117f1b4Smrg}
4827117f1b4Smrg
4837117f1b4Smrg
4844a49301eSmrg/**
48501e04c3fSmrg * Free all texture images of the given texture objectm, except for
48601e04c3fSmrg * \p retainTexImage.
4874a49301eSmrg *
4884a49301eSmrg * \param ctx GL context.
48901e04c3fSmrg * \param texObj texture object.
49001e04c3fSmrg * \param retainTexImage a texture image that will \em not be freed.
4914a49301eSmrg *
4924a49301eSmrg * \sa _mesa_clear_texture_image().
4934a49301eSmrg */
4944a49301eSmrgvoid
4953464ebd5Sriastradh_mesa_clear_texture_object(struct gl_context *ctx,
49601e04c3fSmrg                           struct gl_texture_object *texObj,
49701e04c3fSmrg                           struct gl_texture_image *retainTexImage)
4984a49301eSmrg{
4994a49301eSmrg   GLuint i, j;
5004a49301eSmrg
5014a49301eSmrg   if (texObj->Target == 0)
5024a49301eSmrg      return;
5034a49301eSmrg
5044a49301eSmrg   for (i = 0; i < MAX_FACES; i++) {
5054a49301eSmrg      for (j = 0; j < MAX_TEXTURE_LEVELS; j++) {
5064a49301eSmrg         struct gl_texture_image *texImage = texObj->Image[i][j];
50701e04c3fSmrg         if (texImage && texImage != retainTexImage)
5084a49301eSmrg            _mesa_clear_texture_image(ctx, texImage);
5094a49301eSmrg      }
5104a49301eSmrg   }
5117117f1b4Smrg}
5127117f1b4Smrg
5137117f1b4Smrg
5147117f1b4Smrg/**
5157117f1b4Smrg * Check if the given texture object is valid by examining its Target field.
5167117f1b4Smrg * For debugging only.
5177117f1b4Smrg */
5187117f1b4Smrgstatic GLboolean
5197117f1b4Smrgvalid_texture_object(const struct gl_texture_object *tex)
5207117f1b4Smrg{
5217117f1b4Smrg   switch (tex->Target) {
5227117f1b4Smrg   case 0:
5237117f1b4Smrg   case GL_TEXTURE_1D:
5247117f1b4Smrg   case GL_TEXTURE_2D:
5257117f1b4Smrg   case GL_TEXTURE_3D:
52601e04c3fSmrg   case GL_TEXTURE_CUBE_MAP:
5277117f1b4Smrg   case GL_TEXTURE_RECTANGLE_NV:
528c1f859d4Smrg   case GL_TEXTURE_1D_ARRAY_EXT:
529c1f859d4Smrg   case GL_TEXTURE_2D_ARRAY_EXT:
5303464ebd5Sriastradh   case GL_TEXTURE_BUFFER:
531af69d88dSmrg   case GL_TEXTURE_EXTERNAL_OES:
532af69d88dSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
533af69d88dSmrg   case GL_TEXTURE_2D_MULTISAMPLE:
534af69d88dSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
5357117f1b4Smrg      return GL_TRUE;
5367117f1b4Smrg   case 0x99:
5377117f1b4Smrg      _mesa_problem(NULL, "invalid reference to a deleted texture object");
5387117f1b4Smrg      return GL_FALSE;
5397117f1b4Smrg   default:
5404a49301eSmrg      _mesa_problem(NULL, "invalid texture object Target 0x%x, Id = %u",
5414a49301eSmrg                    tex->Target, tex->Name);
5427117f1b4Smrg      return GL_FALSE;
5437117f1b4Smrg   }
5447117f1b4Smrg}
5457117f1b4Smrg
5467117f1b4Smrg
5477117f1b4Smrg/**
5487117f1b4Smrg * Reference (or unreference) a texture object.
5497117f1b4Smrg * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero).
5507117f1b4Smrg * If 'tex' is non-null, increment its refcount.
551af69d88dSmrg * This is normally only called from the _mesa_reference_texobj() macro
552af69d88dSmrg * when there's a real pointer change.
5537117f1b4Smrg */
5547117f1b4Smrgvoid
555af69d88dSmrg_mesa_reference_texobj_(struct gl_texture_object **ptr,
556af69d88dSmrg                        struct gl_texture_object *tex)
5577117f1b4Smrg{
5587117f1b4Smrg   assert(ptr);
5597117f1b4Smrg
5607117f1b4Smrg   if (*ptr) {
5617117f1b4Smrg      /* Unreference the old texture */
5627117f1b4Smrg      struct gl_texture_object *oldTex = *ptr;
5637117f1b4Smrg
56401e04c3fSmrg      assert(valid_texture_object(oldTex));
5653464ebd5Sriastradh      (void) valid_texture_object; /* silence warning in release builds */
5667117f1b4Smrg
56701e04c3fSmrg      assert(oldTex->RefCount > 0);
5687117f1b4Smrg
5697ec681f3Smrg      if (p_atomic_dec_zero(&oldTex->RefCount)) {
57001e04c3fSmrg         /* Passing in the context drastically changes the driver code for
57101e04c3fSmrg          * framebuffer deletion.
57201e04c3fSmrg          */
5737117f1b4Smrg         GET_CURRENT_CONTEXT(ctx);
5747117f1b4Smrg         if (ctx)
5757117f1b4Smrg            ctx->Driver.DeleteTexture(ctx, oldTex);
5767117f1b4Smrg         else
5777117f1b4Smrg            _mesa_problem(NULL, "Unable to delete texture, no context");
5787117f1b4Smrg      }
5797117f1b4Smrg   }
5807117f1b4Smrg
5817117f1b4Smrg   if (tex) {
5827117f1b4Smrg      /* reference new texture */
58301e04c3fSmrg      assert(valid_texture_object(tex));
58401e04c3fSmrg      assert(tex->RefCount > 0);
58501e04c3fSmrg
5867ec681f3Smrg      p_atomic_inc(&tex->RefCount);
5877117f1b4Smrg   }
5887ec681f3Smrg
5897ec681f3Smrg   *ptr = tex;
5907117f1b4Smrg}
5917117f1b4Smrg
5927117f1b4Smrg
593af69d88dSmrgenum base_mipmap { BASE, MIPMAP };
594af69d88dSmrg
5957117f1b4Smrg
5967117f1b4Smrg/**
597af69d88dSmrg * Mark a texture object as incomplete.  There are actually three kinds of
598af69d88dSmrg * (in)completeness:
599af69d88dSmrg * 1. "base incomplete": the base level of the texture is invalid so no
600af69d88dSmrg *    texturing is possible.
601af69d88dSmrg * 2. "mipmap incomplete": a non-base level of the texture is invalid so
602af69d88dSmrg *    mipmap filtering isn't possible, but non-mipmap filtering is.
603af69d88dSmrg * 3. "texture incompleteness": some combination of texture state and
604af69d88dSmrg *    sampler state renders the texture incomplete.
605af69d88dSmrg *
6063464ebd5Sriastradh * \param t  texture object
607af69d88dSmrg * \param bm  either BASE or MIPMAP to indicate what's incomplete
6083464ebd5Sriastradh * \param fmt...  string describing why it's incomplete (for debugging).
6097117f1b4Smrg */
6107117f1b4Smrgstatic void
611af69d88dSmrgincomplete(struct gl_texture_object *t, enum base_mipmap bm,
612af69d88dSmrg           const char *fmt, ...)
6137117f1b4Smrg{
614af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_TEXTURE) {
615af69d88dSmrg      va_list args;
616af69d88dSmrg      char s[100];
6173464ebd5Sriastradh
618af69d88dSmrg      va_start(args, fmt);
619af69d88dSmrg      vsnprintf(s, sizeof(s), fmt, args);
620af69d88dSmrg      va_end(args);
621af69d88dSmrg
622af69d88dSmrg      _mesa_debug(NULL, "Texture Obj %d incomplete because: %s\n", t->Name, s);
623af69d88dSmrg   }
6243464ebd5Sriastradh
625af69d88dSmrg   if (bm == BASE)
626af69d88dSmrg      t->_BaseComplete = GL_FALSE;
627af69d88dSmrg   t->_MipmapComplete = GL_FALSE;
6283464ebd5Sriastradh}
6297117f1b4Smrg
6307117f1b4Smrg
6317117f1b4Smrg/**
6327117f1b4Smrg * Examine a texture object to determine if it is complete.
6337117f1b4Smrg *
6347117f1b4Smrg * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE
6357117f1b4Smrg * accordingly.
6367117f1b4Smrg *
6377117f1b4Smrg * \param ctx GL context.
6387117f1b4Smrg * \param t texture object.
6397117f1b4Smrg *
6407117f1b4Smrg * According to the texture target, verifies that each of the mipmaps is
6417117f1b4Smrg * present and has the expected size.
6427117f1b4Smrg */
6437117f1b4Smrgvoid
6443464ebd5Sriastradh_mesa_test_texobj_completeness( const struct gl_context *ctx,
6457117f1b4Smrg                                struct gl_texture_object *t )
6467117f1b4Smrg{
6477ec681f3Smrg   const GLint baseLevel = t->Attrib.BaseLevel;
648af69d88dSmrg   const struct gl_texture_image *baseImage;
649af69d88dSmrg   GLint maxLevels = 0;
6507117f1b4Smrg
651af69d88dSmrg   /* We'll set these to FALSE if tests fail below */
652af69d88dSmrg   t->_BaseComplete = GL_TRUE;
653af69d88dSmrg   t->_MipmapComplete = GL_TRUE;
654af69d88dSmrg
655af69d88dSmrg   if (t->Target == GL_TEXTURE_BUFFER) {
656af69d88dSmrg      /* Buffer textures are always considered complete.  The obvious case where
657af69d88dSmrg       * they would be incomplete (no BO attached) is actually specced to be
658af69d88dSmrg       * undefined rendering results.
659af69d88dSmrg       */
660af69d88dSmrg      return;
661af69d88dSmrg   }
662c1f859d4Smrg
663c1f859d4Smrg   /* Detect cases where the application set the base level to an invalid
664c1f859d4Smrg    * value.
665c1f859d4Smrg    */
6664a49301eSmrg   if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) {
667af69d88dSmrg      incomplete(t, BASE, "base level = %d is invalid", baseLevel);
668c1f859d4Smrg      return;
669c1f859d4Smrg   }
6707117f1b4Smrg
6717ec681f3Smrg   if (t->Attrib.MaxLevel < baseLevel) {
672af69d88dSmrg      incomplete(t, MIPMAP, "MAX_LEVEL (%d) < BASE_LEVEL (%d)",
6737ec681f3Smrg		 t->Attrib.MaxLevel, baseLevel);
674af69d88dSmrg      return;
675af69d88dSmrg   }
676af69d88dSmrg
677af69d88dSmrg   baseImage = t->Image[0][baseLevel];
678af69d88dSmrg
6797117f1b4Smrg   /* Always need the base level image */
680af69d88dSmrg   if (!baseImage) {
681af69d88dSmrg      incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel);
6827117f1b4Smrg      return;
6837117f1b4Smrg   }
6847117f1b4Smrg
6857117f1b4Smrg   /* Check width/height/depth for zero */
686af69d88dSmrg   if (baseImage->Width == 0 ||
687af69d88dSmrg       baseImage->Height == 0 ||
688af69d88dSmrg       baseImage->Depth == 0) {
689af69d88dSmrg      incomplete(t, BASE, "texture width or height or depth = 0");
6907117f1b4Smrg      return;
6917117f1b4Smrg   }
6927117f1b4Smrg
693af69d88dSmrg   /* Check if the texture values are integer */
694af69d88dSmrg   {
695af69d88dSmrg      GLenum datatype = _mesa_get_format_datatype(baseImage->TexFormat);
696af69d88dSmrg      t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT;
6977117f1b4Smrg   }
698af69d88dSmrg
69901e04c3fSmrg   /* Check if the texture type is Float or HalfFloatOES and ensure Min and Mag
70001e04c3fSmrg    * filters are supported in this case.
70101e04c3fSmrg    */
70201e04c3fSmrg   if (_mesa_is_gles(ctx) && !valid_filter_for_float(ctx, t)) {
70301e04c3fSmrg      incomplete(t, BASE, "Filter is not supported with Float types.");
70401e04c3fSmrg      return;
70501e04c3fSmrg   }
70601e04c3fSmrg
7077ec681f3Smrg   maxLevels = _mesa_max_texture_levels(ctx, t->Target);
7087ec681f3Smrg   if (maxLevels == 0) {
7097117f1b4Smrg      _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness");
7107117f1b4Smrg      return;
7117117f1b4Smrg   }
7127117f1b4Smrg
71301e04c3fSmrg   assert(maxLevels > 0);
7147117f1b4Smrg
7157ec681f3Smrg   t->_MaxLevel = MIN3(t->Attrib.MaxLevel,
716af69d88dSmrg                       /* 'p' in the GL spec */
717af69d88dSmrg                       (int) (baseLevel + baseImage->MaxNumLevels - 1),
718af69d88dSmrg                       /* 'q' in the GL spec */
719af69d88dSmrg                       maxLevels - 1);
720af69d88dSmrg
721af69d88dSmrg   if (t->Immutable) {
722af69d88dSmrg      /* Adjust max level for views: the data store may have more levels than
723af69d88dSmrg       * the view exposes.
724af69d88dSmrg       */
7257ec681f3Smrg      t->_MaxLevel = MAX2(MIN2(t->_MaxLevel, t->Attrib.NumLevels - 1), 0);
7263464ebd5Sriastradh   }
7273464ebd5Sriastradh
728af69d88dSmrg   /* Compute _MaxLambda = q - p in the spec used during mipmapping */
729af69d88dSmrg   t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel);
7307117f1b4Smrg
731af69d88dSmrg   if (t->Immutable) {
732af69d88dSmrg      /* This texture object was created with glTexStorage1/2/3D() so we
733af69d88dSmrg       * know that all the mipmap levels are the right size and all cube
734af69d88dSmrg       * map faces are the same size.
735af69d88dSmrg       * We don't need to do any of the additional checks below.
736af69d88dSmrg       */
737af69d88dSmrg      return;
738af69d88dSmrg   }
7397117f1b4Smrg
74001e04c3fSmrg   if (t->Target == GL_TEXTURE_CUBE_MAP) {
74101e04c3fSmrg      /* Make sure that all six cube map level 0 images are the same size and
74201e04c3fSmrg       * format.
743af69d88dSmrg       * Note:  we know that the image's width==height (we enforce that
744af69d88dSmrg       * at glTexImage time) so we only need to test the width here.
745af69d88dSmrg       */
7467117f1b4Smrg      GLuint face;
747af69d88dSmrg      assert(baseImage->Width2 == baseImage->Height);
7487117f1b4Smrg      for (face = 1; face < 6; face++) {
749af69d88dSmrg         assert(t->Image[face][baseLevel] == NULL ||
750af69d88dSmrg                t->Image[face][baseLevel]->Width2 ==
751af69d88dSmrg                t->Image[face][baseLevel]->Height2);
7523464ebd5Sriastradh         if (t->Image[face][baseLevel] == NULL ||
753af69d88dSmrg             t->Image[face][baseLevel]->Width2 != baseImage->Width2) {
754af69d88dSmrg            incomplete(t, BASE, "Cube face missing or mismatched size");
7553464ebd5Sriastradh            return;
7563464ebd5Sriastradh         }
75701e04c3fSmrg         if (t->Image[face][baseLevel]->InternalFormat !=
75801e04c3fSmrg             baseImage->InternalFormat) {
75901e04c3fSmrg            incomplete(t, BASE, "Cube face format mismatch");
76001e04c3fSmrg            return;
76101e04c3fSmrg         }
76201e04c3fSmrg         if (t->Image[face][baseLevel]->Border != baseImage->Border) {
76301e04c3fSmrg            incomplete(t, BASE, "Cube face border size mismatch");
76401e04c3fSmrg            return;
76501e04c3fSmrg         }
7667117f1b4Smrg      }
7677117f1b4Smrg   }
7687117f1b4Smrg
769af69d88dSmrg   /*
770af69d88dSmrg    * Do mipmap consistency checking.
771af69d88dSmrg    * Note: we don't care about the current texture sampler state here.
772af69d88dSmrg    * To determine texture completeness we'll either look at _BaseComplete
773af69d88dSmrg    * or _MipmapComplete depending on the current minification filter mode.
774af69d88dSmrg    */
775af69d88dSmrg   {
7767117f1b4Smrg      GLint i;
777af69d88dSmrg      const GLint minLevel = baseLevel;
778af69d88dSmrg      const GLint maxLevel = t->_MaxLevel;
779af69d88dSmrg      const GLuint numFaces = _mesa_num_tex_faces(t->Target);
780af69d88dSmrg      GLuint width, height, depth, face;
7817117f1b4Smrg
7827117f1b4Smrg      if (minLevel > maxLevel) {
783af69d88dSmrg         incomplete(t, MIPMAP, "minLevel > maxLevel");
7847117f1b4Smrg         return;
7857117f1b4Smrg      }
7867117f1b4Smrg
787af69d88dSmrg      /* Get the base image's dimensions */
788af69d88dSmrg      width = baseImage->Width2;
789af69d88dSmrg      height = baseImage->Height2;
790af69d88dSmrg      depth = baseImage->Depth2;
7917117f1b4Smrg
792af69d88dSmrg      /* Note: this loop will be a no-op for RECT, BUFFER, EXTERNAL,
793af69d88dSmrg       * MULTISAMPLE and MULTISAMPLE_ARRAY textures
794af69d88dSmrg       */
795af69d88dSmrg      for (i = baseLevel + 1; i < maxLevels; i++) {
796af69d88dSmrg         /* Compute the expected size of image at level[i] */
797af69d88dSmrg         if (width > 1) {
798af69d88dSmrg            width /= 2;
7997117f1b4Smrg         }
800af69d88dSmrg         if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) {
801af69d88dSmrg            height /= 2;
802af69d88dSmrg         }
80301e04c3fSmrg         if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY
80401e04c3fSmrg             && t->Target != GL_TEXTURE_CUBE_MAP_ARRAY) {
805af69d88dSmrg            depth /= 2;
806af69d88dSmrg         }
807af69d88dSmrg
808af69d88dSmrg         /* loop over cube faces (or single face otherwise) */
809af69d88dSmrg         for (face = 0; face < numFaces; face++) {
8107117f1b4Smrg            if (i >= minLevel && i <= maxLevel) {
811af69d88dSmrg               const struct gl_texture_image *img = t->Image[face][i];
812af69d88dSmrg
813af69d88dSmrg               if (!img) {
814af69d88dSmrg                  incomplete(t, MIPMAP, "TexImage[%d] is missing", i);
8157117f1b4Smrg                  return;
8167117f1b4Smrg               }
81701e04c3fSmrg               if (img->InternalFormat != baseImage->InternalFormat) {
818af69d88dSmrg                  incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]");
8197117f1b4Smrg                  return;
8207117f1b4Smrg               }
821af69d88dSmrg               if (img->Border != baseImage->Border) {
822af69d88dSmrg                  incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]");
8237117f1b4Smrg                  return;
8247117f1b4Smrg               }
825af69d88dSmrg               if (img->Width2 != width) {
82601e04c3fSmrg                  incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i,
82701e04c3fSmrg                             img->Width2);
8287117f1b4Smrg                  return;
8297117f1b4Smrg               }
830af69d88dSmrg               if (img->Height2 != height) {
83101e04c3fSmrg                  incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i,
83201e04c3fSmrg                             img->Height2);
8337117f1b4Smrg                  return;
8347117f1b4Smrg               }
835af69d88dSmrg               if (img->Depth2 != depth) {
83601e04c3fSmrg                  incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i,
83701e04c3fSmrg                             img->Depth2);
8387117f1b4Smrg                  return;
8397117f1b4Smrg               }
8407117f1b4Smrg            }
8417117f1b4Smrg         }
84201e04c3fSmrg
843af69d88dSmrg         if (width == 1 && height == 1 && depth == 1) {
844af69d88dSmrg            return;  /* found smallest needed mipmap, all done! */
845af69d88dSmrg         }
8467117f1b4Smrg      }
8477117f1b4Smrg   }
8487117f1b4Smrg}
8497117f1b4Smrg
8504a49301eSmrg
8513464ebd5SriastradhGLboolean
85201e04c3fSmrg_mesa_cube_level_complete(const struct gl_texture_object *texObj,
85301e04c3fSmrg                          const GLint level)
8543464ebd5Sriastradh{
8553464ebd5Sriastradh   const struct gl_texture_image *img0, *img;
8563464ebd5Sriastradh   GLuint face;
8573464ebd5Sriastradh
8583464ebd5Sriastradh   if (texObj->Target != GL_TEXTURE_CUBE_MAP)
8593464ebd5Sriastradh      return GL_FALSE;
8603464ebd5Sriastradh
86101e04c3fSmrg   if ((level < 0) || (level >= MAX_TEXTURE_LEVELS))
8623464ebd5Sriastradh      return GL_FALSE;
8633464ebd5Sriastradh
8643464ebd5Sriastradh   /* check first face */
86501e04c3fSmrg   img0 = texObj->Image[0][level];
8663464ebd5Sriastradh   if (!img0 ||
8673464ebd5Sriastradh       img0->Width < 1 ||
8683464ebd5Sriastradh       img0->Width != img0->Height)
8693464ebd5Sriastradh      return GL_FALSE;
8703464ebd5Sriastradh
8713464ebd5Sriastradh   /* check remaining faces vs. first face */
8723464ebd5Sriastradh   for (face = 1; face < 6; face++) {
87301e04c3fSmrg      img = texObj->Image[face][level];
8743464ebd5Sriastradh      if (!img ||
8753464ebd5Sriastradh          img->Width != img0->Width ||
8763464ebd5Sriastradh          img->Height != img0->Height ||
8773464ebd5Sriastradh          img->TexFormat != img0->TexFormat)
8783464ebd5Sriastradh         return GL_FALSE;
8793464ebd5Sriastradh   }
8803464ebd5Sriastradh
8813464ebd5Sriastradh   return GL_TRUE;
8823464ebd5Sriastradh}
8833464ebd5Sriastradh
88401e04c3fSmrg/**
88501e04c3fSmrg * Check if the given cube map texture is "cube complete" as defined in
88601e04c3fSmrg * the OpenGL specification.
88701e04c3fSmrg */
88801e04c3fSmrgGLboolean
88901e04c3fSmrg_mesa_cube_complete(const struct gl_texture_object *texObj)
89001e04c3fSmrg{
8917ec681f3Smrg   return _mesa_cube_level_complete(texObj, texObj->Attrib.BaseLevel);
89201e04c3fSmrg}
8933464ebd5Sriastradh
8944a49301eSmrg/**
8954a49301eSmrg * Mark a texture object dirty.  It forces the object to be incomplete
896af69d88dSmrg * and forces the context to re-validate its state.
8974a49301eSmrg *
8984a49301eSmrg * \param ctx GL context.
8994a49301eSmrg * \param texObj texture object.
9004a49301eSmrg */
9014a49301eSmrgvoid
902af69d88dSmrg_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj)
9034a49301eSmrg{
904af69d88dSmrg   texObj->_BaseComplete = GL_FALSE;
905af69d88dSmrg   texObj->_MipmapComplete = GL_FALSE;
90601e04c3fSmrg   ctx->NewState |= _NEW_TEXTURE_OBJECT;
9077ec681f3Smrg   ctx->PopAttribState |= GL_TEXTURE_BIT;
9084a49301eSmrg}
9094a49301eSmrg
9104a49301eSmrg
9114a49301eSmrg/**
912af69d88dSmrg * Return pointer to a default/fallback texture of the given type/target.
913af69d88dSmrg * The texture is an RGBA texture with all texels = (0,0,0,1).
914af69d88dSmrg * That's the value a GLSL sampler should get when sampling from an
9154a49301eSmrg * incomplete texture.
9164a49301eSmrg */
9174a49301eSmrgstruct gl_texture_object *
918af69d88dSmrg_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex)
9194a49301eSmrg{
920af69d88dSmrg   if (!ctx->Shared->FallbackTex[tex]) {
9214a49301eSmrg      /* create fallback texture now */
92201e04c3fSmrg      const GLsizei width = 1, height = 1;
92301e04c3fSmrg      GLsizei depth = 1;
92401e04c3fSmrg      GLubyte texel[24];
9254a49301eSmrg      struct gl_texture_object *texObj;
9264a49301eSmrg      struct gl_texture_image *texImage;
927af69d88dSmrg      mesa_format texFormat;
928af69d88dSmrg      GLuint dims, face, numFaces = 1;
929af69d88dSmrg      GLenum target;
930af69d88dSmrg
93101e04c3fSmrg      for (face = 0; face < 6; face++) {
93201e04c3fSmrg         texel[4*face + 0] =
93301e04c3fSmrg         texel[4*face + 1] =
93401e04c3fSmrg         texel[4*face + 2] = 0x0;
93501e04c3fSmrg         texel[4*face + 3] = 0xff;
93601e04c3fSmrg      }
937af69d88dSmrg
938af69d88dSmrg      switch (tex) {
939af69d88dSmrg      case TEXTURE_2D_ARRAY_INDEX:
940af69d88dSmrg         dims = 3;
941af69d88dSmrg         target = GL_TEXTURE_2D_ARRAY;
942af69d88dSmrg         break;
943af69d88dSmrg      case TEXTURE_1D_ARRAY_INDEX:
944af69d88dSmrg         dims = 2;
945af69d88dSmrg         target = GL_TEXTURE_1D_ARRAY;
946af69d88dSmrg         break;
947af69d88dSmrg      case TEXTURE_CUBE_INDEX:
948af69d88dSmrg         dims = 2;
949af69d88dSmrg         target = GL_TEXTURE_CUBE_MAP;
950af69d88dSmrg         numFaces = 6;
951af69d88dSmrg         break;
952af69d88dSmrg      case TEXTURE_3D_INDEX:
953af69d88dSmrg         dims = 3;
954af69d88dSmrg         target = GL_TEXTURE_3D;
955af69d88dSmrg         break;
956af69d88dSmrg      case TEXTURE_RECT_INDEX:
957af69d88dSmrg         dims = 2;
958af69d88dSmrg         target = GL_TEXTURE_RECTANGLE;
959af69d88dSmrg         break;
960af69d88dSmrg      case TEXTURE_2D_INDEX:
961af69d88dSmrg         dims = 2;
962af69d88dSmrg         target = GL_TEXTURE_2D;
963af69d88dSmrg         break;
964af69d88dSmrg      case TEXTURE_1D_INDEX:
965af69d88dSmrg         dims = 1;
966af69d88dSmrg         target = GL_TEXTURE_1D;
967af69d88dSmrg         break;
968af69d88dSmrg      case TEXTURE_BUFFER_INDEX:
969af69d88dSmrg         dims = 0;
970af69d88dSmrg         target = GL_TEXTURE_BUFFER;
971af69d88dSmrg         break;
972af69d88dSmrg      case TEXTURE_CUBE_ARRAY_INDEX:
973af69d88dSmrg         dims = 3;
974af69d88dSmrg         target = GL_TEXTURE_CUBE_MAP_ARRAY;
97501e04c3fSmrg         depth = 6;
976af69d88dSmrg         break;
977af69d88dSmrg      case TEXTURE_EXTERNAL_INDEX:
978af69d88dSmrg         dims = 2;
979af69d88dSmrg         target = GL_TEXTURE_EXTERNAL_OES;
980af69d88dSmrg         break;
981af69d88dSmrg      case TEXTURE_2D_MULTISAMPLE_INDEX:
982af69d88dSmrg         dims = 2;
983af69d88dSmrg         target = GL_TEXTURE_2D_MULTISAMPLE;
984af69d88dSmrg         break;
985af69d88dSmrg      case TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX:
986af69d88dSmrg         dims = 3;
987af69d88dSmrg         target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
988af69d88dSmrg         break;
989af69d88dSmrg      default:
990af69d88dSmrg         /* no-op */
991af69d88dSmrg         return NULL;
9924a49301eSmrg      }
9934a49301eSmrg
9944a49301eSmrg      /* create texture object */
995af69d88dSmrg      texObj = ctx->Driver.NewTextureObject(ctx, 0, target);
996af69d88dSmrg      if (!texObj)
997af69d88dSmrg         return NULL;
998af69d88dSmrg
9994a49301eSmrg      assert(texObj->RefCount == 1);
10007ec681f3Smrg      texObj->Sampler.Attrib.MinFilter = GL_NEAREST;
10017ec681f3Smrg      texObj->Sampler.Attrib.MagFilter = GL_NEAREST;
10027ec681f3Smrg      texObj->Sampler.Attrib.state.min_img_filter = PIPE_TEX_FILTER_NEAREST;
10037ec681f3Smrg      texObj->Sampler.Attrib.state.min_mip_filter = PIPE_TEX_MIPFILTER_NONE;
10047ec681f3Smrg      texObj->Sampler.Attrib.state.mag_img_filter = PIPE_TEX_FILTER_NEAREST;
10054a49301eSmrg
1006af69d88dSmrg      texFormat = ctx->Driver.ChooseTextureFormat(ctx, target,
1007af69d88dSmrg                                                  GL_RGBA, GL_RGBA,
10083464ebd5Sriastradh                                                  GL_UNSIGNED_BYTE);
10093464ebd5Sriastradh
1010af69d88dSmrg      /* need a loop here just for cube maps */
1011af69d88dSmrg      for (face = 0; face < numFaces; face++) {
101201e04c3fSmrg         const GLenum faceTarget = _mesa_cube_face_target(target, face);
10134a49301eSmrg
1014af69d88dSmrg         /* initialize level[0] texture image */
1015af69d88dSmrg         texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0);
10164a49301eSmrg
1017af69d88dSmrg         _mesa_init_teximage_fields(ctx, texImage,
1018af69d88dSmrg                                    width,
1019af69d88dSmrg                                    (dims > 1) ? height : 1,
1020af69d88dSmrg                                    (dims > 2) ? depth : 1,
1021af69d88dSmrg                                    0, /* border */
1022af69d88dSmrg                                    GL_RGBA, texFormat);
1023af69d88dSmrg
1024af69d88dSmrg         ctx->Driver.TexImage(ctx, dims, texImage,
1025af69d88dSmrg                              GL_RGBA, GL_UNSIGNED_BYTE, texel,
1026af69d88dSmrg                              &ctx->DefaultPacking);
1027af69d88dSmrg      }
10284a49301eSmrg
10294a49301eSmrg      _mesa_test_texobj_completeness(ctx, texObj);
1030af69d88dSmrg      assert(texObj->_BaseComplete);
1031af69d88dSmrg      assert(texObj->_MipmapComplete);
1032af69d88dSmrg
1033af69d88dSmrg      ctx->Shared->FallbackTex[tex] = texObj;
103401e04c3fSmrg
103501e04c3fSmrg      /* Complete the driver's operation in case another context will also
103601e04c3fSmrg       * use the same fallback texture. */
103701e04c3fSmrg      if (ctx->Driver.Finish)
103801e04c3fSmrg         ctx->Driver.Finish(ctx);
1039af69d88dSmrg   }
1040af69d88dSmrg   return ctx->Shared->FallbackTex[tex];
1041af69d88dSmrg}
1042af69d88dSmrg
1043af69d88dSmrg
1044af69d88dSmrg/**
1045af69d88dSmrg * Compute the size of the given texture object, in bytes.
1046af69d88dSmrg */
1047af69d88dSmrgstatic GLuint
1048af69d88dSmrgtexture_size(const struct gl_texture_object *texObj)
1049af69d88dSmrg{
1050af69d88dSmrg   const GLuint numFaces = _mesa_num_tex_faces(texObj->Target);
1051af69d88dSmrg   GLuint face, level, size = 0;
1052af69d88dSmrg
1053af69d88dSmrg   for (face = 0; face < numFaces; face++) {
1054af69d88dSmrg      for (level = 0; level < MAX_TEXTURE_LEVELS; level++) {
1055af69d88dSmrg         const struct gl_texture_image *img = texObj->Image[face][level];
1056af69d88dSmrg         if (img) {
1057af69d88dSmrg            GLuint sz = _mesa_format_image_size(img->TexFormat, img->Width,
1058af69d88dSmrg                                                img->Height, img->Depth);
1059af69d88dSmrg            size += sz;
1060af69d88dSmrg         }
1061af69d88dSmrg      }
1062af69d88dSmrg   }
1063af69d88dSmrg
1064af69d88dSmrg   return size;
1065af69d88dSmrg}
1066af69d88dSmrg
1067af69d88dSmrg
1068af69d88dSmrg/**
1069af69d88dSmrg * Callback called from _mesa_HashWalk()
1070af69d88dSmrg */
1071af69d88dSmrgstatic void
10727ec681f3Smrgcount_tex_size(void *data, void *userData)
1073af69d88dSmrg{
1074af69d88dSmrg   const struct gl_texture_object *texObj =
1075af69d88dSmrg      (const struct gl_texture_object *) data;
1076af69d88dSmrg   GLuint *total = (GLuint *) userData;
1077af69d88dSmrg
1078af69d88dSmrg   *total = *total + texture_size(texObj);
1079af69d88dSmrg}
1080af69d88dSmrg
1081af69d88dSmrg
1082af69d88dSmrg/**
1083af69d88dSmrg * Compute total size (in bytes) of all textures for the given context.
1084af69d88dSmrg * For debugging purposes.
1085af69d88dSmrg */
1086af69d88dSmrgGLuint
1087af69d88dSmrg_mesa_total_texture_memory(struct gl_context *ctx)
1088af69d88dSmrg{
1089af69d88dSmrg   GLuint tgt, total = 0;
1090af69d88dSmrg
1091af69d88dSmrg   _mesa_HashWalk(ctx->Shared->TexObjects, count_tex_size, &total);
1092af69d88dSmrg
1093af69d88dSmrg   /* plus, the default texture objects */
1094af69d88dSmrg   for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) {
1095af69d88dSmrg      total += texture_size(ctx->Shared->DefaultTex[tgt]);
10964a49301eSmrg   }
1097af69d88dSmrg
1098af69d88dSmrg   return total;
10994a49301eSmrg}
11004a49301eSmrg
110101e04c3fSmrg
110201e04c3fSmrg/**
110301e04c3fSmrg * Return the base format for the given texture object by looking
110401e04c3fSmrg * at the base texture image.
110501e04c3fSmrg * \return base format (such as GL_RGBA) or GL_NONE if it can't be determined
110601e04c3fSmrg */
110701e04c3fSmrgGLenum
110801e04c3fSmrg_mesa_texture_base_format(const struct gl_texture_object *texObj)
110901e04c3fSmrg{
111001e04c3fSmrg   const struct gl_texture_image *texImage = _mesa_base_tex_image(texObj);
111101e04c3fSmrg
111201e04c3fSmrg   return texImage ? texImage->_BaseFormat : GL_NONE;
111301e04c3fSmrg}
111401e04c3fSmrg
111501e04c3fSmrg
1116af69d88dSmrgstatic struct gl_texture_object *
1117af69d88dSmrginvalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture,
1118af69d88dSmrg                                 GLint level, const char *name)
1119af69d88dSmrg{
1120af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
1121af69d88dSmrg    *
1122af69d88dSmrg    *     "If <texture> is zero or is not the name of a texture, the error
1123af69d88dSmrg    *     INVALID_VALUE is generated."
1124af69d88dSmrg    *
1125af69d88dSmrg    * This performs the error check in a different order than listed in the
1126af69d88dSmrg    * spec.  We have to get the texture object before we can validate the
1127af69d88dSmrg    * other parameters against values in the texture object.
1128af69d88dSmrg    */
1129af69d88dSmrg   struct gl_texture_object *const t = _mesa_lookup_texture(ctx, texture);
1130af69d88dSmrg   if (texture == 0 || t == NULL) {
1131af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(texture)", name);
1132af69d88dSmrg      return NULL;
1133af69d88dSmrg   }
1134af69d88dSmrg
1135af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
1136af69d88dSmrg    *
1137af69d88dSmrg    *     "If <level> is less than zero or greater than the base 2 logarithm
1138af69d88dSmrg    *     of the maximum texture width, height, or depth, the error
1139af69d88dSmrg    *     INVALID_VALUE is generated."
1140af69d88dSmrg    */
11417ec681f3Smrg   if (level < 0 || level > t->Attrib.MaxLevel) {
1142af69d88dSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name);
1143af69d88dSmrg      return NULL;
1144af69d88dSmrg   }
1145af69d88dSmrg
1146af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
1147af69d88dSmrg    *
1148af69d88dSmrg    *     "If the target of <texture> is TEXTURE_RECTANGLE, TEXTURE_BUFFER,
1149af69d88dSmrg    *     TEXTURE_2D_MULTISAMPLE, or TEXTURE_2D_MULTISAMPLE_ARRAY, and <level>
1150af69d88dSmrg    *     is not zero, the error INVALID_VALUE is generated."
1151af69d88dSmrg    */
1152af69d88dSmrg   if (level != 0) {
1153af69d88dSmrg      switch (t->Target) {
1154af69d88dSmrg      case GL_TEXTURE_RECTANGLE:
1155af69d88dSmrg      case GL_TEXTURE_BUFFER:
1156af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE:
1157af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
1158af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name);
1159af69d88dSmrg         return NULL;
1160af69d88dSmrg
1161af69d88dSmrg      default:
1162af69d88dSmrg         break;
1163af69d88dSmrg      }
1164af69d88dSmrg   }
1165af69d88dSmrg
1166af69d88dSmrg   return t;
1167af69d88dSmrg}
11684a49301eSmrg
11697117f1b4Smrg
11707117f1b4Smrg/**
117101e04c3fSmrg * Helper function for glCreateTextures and glGenTextures. Need this because
117201e04c3fSmrg * glCreateTextures should throw errors if target = 0. This is not exposed to
117301e04c3fSmrg * the rest of Mesa to encourage Mesa internals to use nameless textures,
117401e04c3fSmrg * which do not require expensive hash lookups.
117501e04c3fSmrg * \param target  either 0 or a valid / error-checked texture target enum
117601e04c3fSmrg */
117701e04c3fSmrgstatic void
117801e04c3fSmrgcreate_textures(struct gl_context *ctx, GLenum target,
117901e04c3fSmrg                GLsizei n, GLuint *textures, const char *caller)
11807117f1b4Smrg{
11817117f1b4Smrg   GLint i;
1182af69d88dSmrg
11837117f1b4Smrg   if (!textures)
11847117f1b4Smrg      return;
11857117f1b4Smrg
11867117f1b4Smrg   /*
11877117f1b4Smrg    * This must be atomic (generation and allocation of texture IDs)
11887117f1b4Smrg    */
118901e04c3fSmrg   _mesa_HashLockMutex(ctx->Shared->TexObjects);
11907117f1b4Smrg
11917ec681f3Smrg   _mesa_HashFindFreeKeys(ctx->Shared->TexObjects, textures, n);
11927117f1b4Smrg
11937117f1b4Smrg   /* Allocate new, empty texture objects */
11947117f1b4Smrg   for (i = 0; i < n; i++) {
11957117f1b4Smrg      struct gl_texture_object *texObj;
11967ec681f3Smrg      texObj = ctx->Driver.NewTextureObject(ctx, textures[i], target);
11977117f1b4Smrg      if (!texObj) {
119801e04c3fSmrg         _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
119901e04c3fSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
12007117f1b4Smrg         return;
12017117f1b4Smrg      }
12027117f1b4Smrg
12037117f1b4Smrg      /* insert into hash table */
12047ec681f3Smrg      _mesa_HashInsertLocked(ctx->Shared->TexObjects, texObj->Name, texObj, true);
12057117f1b4Smrg   }
12067117f1b4Smrg
120701e04c3fSmrg   _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
12087117f1b4Smrg}
12097117f1b4Smrg
12107117f1b4Smrg
121101e04c3fSmrgstatic void
121201e04c3fSmrgcreate_textures_err(struct gl_context *ctx, GLenum target,
121301e04c3fSmrg                    GLsizei n, GLuint *textures, const char *caller)
121401e04c3fSmrg{
121501e04c3fSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
121601e04c3fSmrg      _mesa_debug(ctx, "%s %d\n", caller, n);
121701e04c3fSmrg
121801e04c3fSmrg   if (n < 0) {
121901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", caller);
122001e04c3fSmrg      return;
122101e04c3fSmrg   }
122201e04c3fSmrg
122301e04c3fSmrg   create_textures(ctx, target, n, textures, caller);
122401e04c3fSmrg}
122501e04c3fSmrg
122601e04c3fSmrg/*@}*/
122701e04c3fSmrg
122801e04c3fSmrg
122901e04c3fSmrg/***********************************************************************/
123001e04c3fSmrg/** \name API functions */
123101e04c3fSmrg/*@{*/
123201e04c3fSmrg
123301e04c3fSmrg
123401e04c3fSmrg/**
123501e04c3fSmrg * Generate texture names.
123601e04c3fSmrg *
123701e04c3fSmrg * \param n number of texture names to be generated.
123801e04c3fSmrg * \param textures an array in which will hold the generated texture names.
123901e04c3fSmrg *
124001e04c3fSmrg * \sa glGenTextures(), glCreateTextures().
124101e04c3fSmrg *
12427ec681f3Smrg * Calls _mesa_HashFindFreeKeys() to find a block of free texture
124301e04c3fSmrg * IDs which are stored in \p textures.  Corresponding empty texture
124401e04c3fSmrg * objects are also generated.
124501e04c3fSmrg */
124601e04c3fSmrgvoid GLAPIENTRY
124701e04c3fSmrg_mesa_GenTextures_no_error(GLsizei n, GLuint *textures)
124801e04c3fSmrg{
124901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
125001e04c3fSmrg   create_textures(ctx, 0, n, textures, "glGenTextures");
125101e04c3fSmrg}
125201e04c3fSmrg
125301e04c3fSmrg
125401e04c3fSmrgvoid GLAPIENTRY
125501e04c3fSmrg_mesa_GenTextures(GLsizei n, GLuint *textures)
125601e04c3fSmrg{
125701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
125801e04c3fSmrg   create_textures_err(ctx, 0, n, textures, "glGenTextures");
125901e04c3fSmrg}
126001e04c3fSmrg
126101e04c3fSmrg/**
126201e04c3fSmrg * Create texture objects.
126301e04c3fSmrg *
126401e04c3fSmrg * \param target the texture target for each name to be generated.
126501e04c3fSmrg * \param n number of texture names to be generated.
126601e04c3fSmrg * \param textures an array in which will hold the generated texture names.
126701e04c3fSmrg *
126801e04c3fSmrg * \sa glCreateTextures(), glGenTextures().
126901e04c3fSmrg *
12707ec681f3Smrg * Calls _mesa_HashFindFreeKeys() to find a block of free texture
127101e04c3fSmrg * IDs which are stored in \p textures.  Corresponding empty texture
127201e04c3fSmrg * objects are also generated.
127301e04c3fSmrg */
127401e04c3fSmrgvoid GLAPIENTRY
127501e04c3fSmrg_mesa_CreateTextures_no_error(GLenum target, GLsizei n, GLuint *textures)
127601e04c3fSmrg{
127701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
127801e04c3fSmrg   create_textures(ctx, target, n, textures, "glCreateTextures");
127901e04c3fSmrg}
128001e04c3fSmrg
128101e04c3fSmrg
128201e04c3fSmrgvoid GLAPIENTRY
128301e04c3fSmrg_mesa_CreateTextures(GLenum target, GLsizei n, GLuint *textures)
128401e04c3fSmrg{
128501e04c3fSmrg   GLint targetIndex;
128601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
128701e04c3fSmrg
128801e04c3fSmrg   /*
128901e04c3fSmrg    * The 4.5 core profile spec (30.10.2014) doesn't specify what
129001e04c3fSmrg    * glCreateTextures should do with invalid targets, which was probably an
129101e04c3fSmrg    * oversight.  This conforms to the spec for glBindTexture.
129201e04c3fSmrg    */
129301e04c3fSmrg   targetIndex = _mesa_tex_target_to_index(ctx, target);
129401e04c3fSmrg   if (targetIndex < 0) {
129501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateTextures(target)");
129601e04c3fSmrg      return;
129701e04c3fSmrg   }
129801e04c3fSmrg
129901e04c3fSmrg   create_textures_err(ctx, target, n, textures, "glCreateTextures");
130001e04c3fSmrg}
130101e04c3fSmrg
13027117f1b4Smrg/**
13037117f1b4Smrg * Check if the given texture object is bound to the current draw or
13047117f1b4Smrg * read framebuffer.  If so, Unbind it.
13057117f1b4Smrg */
13067117f1b4Smrgstatic void
13073464ebd5Sriastradhunbind_texobj_from_fbo(struct gl_context *ctx,
13083464ebd5Sriastradh                       struct gl_texture_object *texObj)
13097117f1b4Smrg{
1310af69d88dSmrg   bool progress = false;
1311af69d88dSmrg
1312af69d88dSmrg   /* Section 4.4.2 (Attaching Images to Framebuffer Objects), subsection
1313af69d88dSmrg    * "Attaching Texture Images to a Framebuffer," of the OpenGL 3.1 spec
1314af69d88dSmrg    * says:
1315af69d88dSmrg    *
1316af69d88dSmrg    *     "If a texture object is deleted while its image is attached to one
1317af69d88dSmrg    *     or more attachment points in the currently bound framebuffer, then
1318af69d88dSmrg    *     it is as if FramebufferTexture* had been called, with a texture of
1319af69d88dSmrg    *     zero, for each attachment point to which this image was attached in
1320af69d88dSmrg    *     the currently bound framebuffer. In other words, this texture image
1321af69d88dSmrg    *     is first detached from all attachment points in the currently bound
1322af69d88dSmrg    *     framebuffer. Note that the texture image is specifically not
1323af69d88dSmrg    *     detached from any other framebuffer objects. Detaching the texture
1324af69d88dSmrg    *     image from any other framebuffer objects is the responsibility of
1325af69d88dSmrg    *     the application."
1326af69d88dSmrg    */
1327af69d88dSmrg   if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
1328af69d88dSmrg      progress = _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, texObj);
1329af69d88dSmrg   }
1330af69d88dSmrg   if (_mesa_is_user_fbo(ctx->ReadBuffer)
1331af69d88dSmrg       && ctx->ReadBuffer != ctx->DrawBuffer) {
1332af69d88dSmrg      progress = _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, texObj)
1333af69d88dSmrg         || progress;
13347117f1b4Smrg   }
1335af69d88dSmrg
1336af69d88dSmrg   if (progress)
1337af69d88dSmrg      /* Vertices are already flushed by _mesa_DeleteTextures */
1338af69d88dSmrg      ctx->NewState |= _NEW_BUFFERS;
13397117f1b4Smrg}
13407117f1b4Smrg
13417117f1b4Smrg
13427117f1b4Smrg/**
13437117f1b4Smrg * Check if the given texture object is bound to any texture image units and
13447117f1b4Smrg * unbind it if so (revert to default textures).
13457117f1b4Smrg */
13467117f1b4Smrgstatic void
13473464ebd5Sriastradhunbind_texobj_from_texunits(struct gl_context *ctx,
13483464ebd5Sriastradh                            struct gl_texture_object *texObj)
13497117f1b4Smrg{
1350af69d88dSmrg   const gl_texture_index index = texObj->TargetIndex;
1351af69d88dSmrg   GLuint u;
13527117f1b4Smrg
135301e04c3fSmrg   if (texObj->Target == 0) {
135401e04c3fSmrg      /* texture was never bound */
1355af69d88dSmrg      return;
135601e04c3fSmrg   }
135701e04c3fSmrg
135801e04c3fSmrg   assert(index < NUM_TEXTURE_TARGETS);
1359af69d88dSmrg
1360af69d88dSmrg   for (u = 0; u < ctx->Texture.NumCurrentTexUsed; u++) {
13617117f1b4Smrg      struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
1362af69d88dSmrg
1363af69d88dSmrg      if (texObj == unit->CurrentTex[index]) {
1364af69d88dSmrg         /* Bind the default texture for this unit/target */
1365af69d88dSmrg         _mesa_reference_texobj(&unit->CurrentTex[index],
1366af69d88dSmrg                                ctx->Shared->DefaultTex[index]);
1367af69d88dSmrg         unit->_BoundTextures &= ~(1 << index);
13687117f1b4Smrg      }
13697117f1b4Smrg   }
13707117f1b4Smrg}
13717117f1b4Smrg
13727117f1b4Smrg
1373af69d88dSmrg/**
1374af69d88dSmrg * Check if the given texture object is bound to any shader image unit
1375af69d88dSmrg * and unbind it if that's the case.
1376af69d88dSmrg */
1377af69d88dSmrgstatic void
1378af69d88dSmrgunbind_texobj_from_image_units(struct gl_context *ctx,
1379af69d88dSmrg                               struct gl_texture_object *texObj)
1380af69d88dSmrg{
1381af69d88dSmrg   GLuint i;
1382af69d88dSmrg
1383af69d88dSmrg   for (i = 0; i < ctx->Const.MaxImageUnits; i++) {
1384af69d88dSmrg      struct gl_image_unit *unit = &ctx->ImageUnits[i];
1385af69d88dSmrg
138601e04c3fSmrg      if (texObj == unit->TexObj) {
1387af69d88dSmrg         _mesa_reference_texobj(&unit->TexObj, NULL);
138801e04c3fSmrg         *unit = _mesa_default_image_unit(ctx);
138901e04c3fSmrg      }
1390af69d88dSmrg   }
1391af69d88dSmrg}
1392af69d88dSmrg
139301e04c3fSmrg
1394af69d88dSmrg/**
1395af69d88dSmrg * Unbinds all textures bound to the given texture image unit.
1396af69d88dSmrg */
1397af69d88dSmrgstatic void
1398af69d88dSmrgunbind_textures_from_unit(struct gl_context *ctx, GLuint unit)
1399af69d88dSmrg{
1400af69d88dSmrg   struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
1401af69d88dSmrg
1402af69d88dSmrg   while (texUnit->_BoundTextures) {
1403af69d88dSmrg      const GLuint index = ffs(texUnit->_BoundTextures) - 1;
1404af69d88dSmrg      struct gl_texture_object *texObj = ctx->Shared->DefaultTex[index];
1405af69d88dSmrg
1406af69d88dSmrg      _mesa_reference_texobj(&texUnit->CurrentTex[index], texObj);
1407af69d88dSmrg
1408af69d88dSmrg      /* Pass BindTexture call to device driver */
1409af69d88dSmrg      if (ctx->Driver.BindTexture)
1410af69d88dSmrg         ctx->Driver.BindTexture(ctx, unit, 0, texObj);
1411af69d88dSmrg
1412af69d88dSmrg      texUnit->_BoundTextures &= ~(1 << index);
141301e04c3fSmrg      ctx->NewState |= _NEW_TEXTURE_OBJECT;
14147ec681f3Smrg      ctx->PopAttribState |= GL_TEXTURE_BIT;
1415af69d88dSmrg   }
1416af69d88dSmrg}
1417af69d88dSmrg
141801e04c3fSmrg
14197117f1b4Smrg/**
14207117f1b4Smrg * Delete named textures.
14217117f1b4Smrg *
14227117f1b4Smrg * \param n number of textures to be deleted.
14237117f1b4Smrg * \param textures array of texture IDs to be deleted.
14247117f1b4Smrg *
14257117f1b4Smrg * \sa glDeleteTextures().
14267117f1b4Smrg *
14277117f1b4Smrg * If we're about to delete a texture that's currently bound to any
14287117f1b4Smrg * texture unit, unbind the texture first.  Decrement the reference
14297117f1b4Smrg * count on the texture object and delete it if it's zero.
14307117f1b4Smrg * Recall that texture objects can be shared among several rendering
14317117f1b4Smrg * contexts.
14327117f1b4Smrg */
143301e04c3fSmrgstatic void
143401e04c3fSmrgdelete_textures(struct gl_context *ctx, GLsizei n, const GLuint *textures)
14357117f1b4Smrg{
14367ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0); /* too complex */
14377117f1b4Smrg
14387117f1b4Smrg   if (!textures)
14397117f1b4Smrg      return;
14407117f1b4Smrg
144101e04c3fSmrg   for (GLsizei i = 0; i < n; i++) {
14427117f1b4Smrg      if (textures[i] > 0) {
14437117f1b4Smrg         struct gl_texture_object *delObj
14447117f1b4Smrg            = _mesa_lookup_texture(ctx, textures[i]);
14457117f1b4Smrg
14467117f1b4Smrg         if (delObj) {
14473464ebd5Sriastradh            _mesa_lock_texture(ctx, delObj);
14487117f1b4Smrg
14497117f1b4Smrg            /* Check if texture is bound to any framebuffer objects.
14507117f1b4Smrg             * If so, unbind.
14517117f1b4Smrg             * See section 4.4.2.3 of GL_EXT_framebuffer_object.
14527117f1b4Smrg             */
14537117f1b4Smrg            unbind_texobj_from_fbo(ctx, delObj);
14547117f1b4Smrg
14557117f1b4Smrg            /* Check if this texture is currently bound to any texture units.
14567117f1b4Smrg             * If so, unbind it.
14577117f1b4Smrg             */
14587117f1b4Smrg            unbind_texobj_from_texunits(ctx, delObj);
14597117f1b4Smrg
1460af69d88dSmrg            /* Check if this texture is currently bound to any shader
1461af69d88dSmrg             * image unit.  If so, unbind it.
1462af69d88dSmrg             * See section 3.9.X of GL_ARB_shader_image_load_store.
1463af69d88dSmrg             */
1464af69d88dSmrg            unbind_texobj_from_image_units(ctx, delObj);
1465af69d88dSmrg
146601e04c3fSmrg            /* Make all handles that reference this texture object non-resident
146701e04c3fSmrg             * in the current context.
146801e04c3fSmrg             */
146901e04c3fSmrg            _mesa_make_texture_handles_non_resident(ctx, delObj);
147001e04c3fSmrg
14713464ebd5Sriastradh            _mesa_unlock_texture(ctx, delObj);
14727117f1b4Smrg
147301e04c3fSmrg            ctx->NewState |= _NEW_TEXTURE_OBJECT;
14747ec681f3Smrg            ctx->PopAttribState |= GL_TEXTURE_BIT;
14757117f1b4Smrg
14767117f1b4Smrg            /* The texture _name_ is now free for re-use.
14777117f1b4Smrg             * Remove it from the hash table now.
14787117f1b4Smrg             */
14797117f1b4Smrg            _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name);
14807117f1b4Smrg
14817ec681f3Smrg            if (ctx->Driver.TextureRemovedFromShared) {
14827ec681f3Smrg               ctx->Driver.TextureRemovedFromShared(ctx, delObj);
14837ec681f3Smrg            }
14847ec681f3Smrg
14857117f1b4Smrg            /* Unreference the texobj.  If refcount hits zero, the texture
14867117f1b4Smrg             * will be deleted.
14877117f1b4Smrg             */
14887117f1b4Smrg            _mesa_reference_texobj(&delObj, NULL);
14897117f1b4Smrg         }
14907117f1b4Smrg      }
14917117f1b4Smrg   }
14927117f1b4Smrg}
14937117f1b4Smrg
149401e04c3fSmrg/**
149501e04c3fSmrg * This deletes a texObj without altering the hash table.
149601e04c3fSmrg */
149701e04c3fSmrgvoid
149801e04c3fSmrg_mesa_delete_nameless_texture(struct gl_context *ctx,
149901e04c3fSmrg                              struct gl_texture_object *texObj)
150001e04c3fSmrg{
150101e04c3fSmrg   if (!texObj)
150201e04c3fSmrg      return;
150301e04c3fSmrg
15047ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT, GL_TEXTURE_BIT);
150501e04c3fSmrg
150601e04c3fSmrg   _mesa_lock_texture(ctx, texObj);
150701e04c3fSmrg   {
150801e04c3fSmrg      /* Check if texture is bound to any framebuffer objects.
150901e04c3fSmrg       * If so, unbind.
151001e04c3fSmrg       * See section 4.4.2.3 of GL_EXT_framebuffer_object.
151101e04c3fSmrg       */
151201e04c3fSmrg      unbind_texobj_from_fbo(ctx, texObj);
151301e04c3fSmrg
151401e04c3fSmrg      /* Check if this texture is currently bound to any texture units.
151501e04c3fSmrg       * If so, unbind it.
151601e04c3fSmrg       */
151701e04c3fSmrg      unbind_texobj_from_texunits(ctx, texObj);
151801e04c3fSmrg
151901e04c3fSmrg      /* Check if this texture is currently bound to any shader
152001e04c3fSmrg       * image unit.  If so, unbind it.
152101e04c3fSmrg       * See section 3.9.X of GL_ARB_shader_image_load_store.
152201e04c3fSmrg       */
152301e04c3fSmrg      unbind_texobj_from_image_units(ctx, texObj);
152401e04c3fSmrg   }
152501e04c3fSmrg   _mesa_unlock_texture(ctx, texObj);
152601e04c3fSmrg
152701e04c3fSmrg   /* Unreference the texobj.  If refcount hits zero, the texture
152801e04c3fSmrg    * will be deleted.
152901e04c3fSmrg    */
153001e04c3fSmrg   _mesa_reference_texobj(&texObj, NULL);
153101e04c3fSmrg}
153201e04c3fSmrg
153301e04c3fSmrg
153401e04c3fSmrgvoid GLAPIENTRY
153501e04c3fSmrg_mesa_DeleteTextures_no_error(GLsizei n, const GLuint *textures)
153601e04c3fSmrg{
153701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
153801e04c3fSmrg   delete_textures(ctx, n, textures);
153901e04c3fSmrg}
154001e04c3fSmrg
154101e04c3fSmrg
154201e04c3fSmrgvoid GLAPIENTRY
154301e04c3fSmrg_mesa_DeleteTextures(GLsizei n, const GLuint *textures)
154401e04c3fSmrg{
154501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
154601e04c3fSmrg
154701e04c3fSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
154801e04c3fSmrg      _mesa_debug(ctx, "glDeleteTextures %d\n", n);
154901e04c3fSmrg
155001e04c3fSmrg   if (n < 0) {
155101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteTextures(n < 0)");
155201e04c3fSmrg      return;
155301e04c3fSmrg   }
155401e04c3fSmrg
155501e04c3fSmrg   delete_textures(ctx, n, textures);
155601e04c3fSmrg}
155701e04c3fSmrg
15587117f1b4Smrg
1559c1f859d4Smrg/**
1560c1f859d4Smrg * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D
1561c1f859d4Smrg * into the corresponding Mesa texture target index.
1562cdc920a0Smrg * Note that proxy targets are not valid here.
1563cdc920a0Smrg * \return TEXTURE_x_INDEX or -1 if target is invalid
1564c1f859d4Smrg */
1565af69d88dSmrgint
1566af69d88dSmrg_mesa_tex_target_to_index(const struct gl_context *ctx, GLenum target)
1567c1f859d4Smrg{
1568c1f859d4Smrg   switch (target) {
1569c1f859d4Smrg   case GL_TEXTURE_1D:
1570af69d88dSmrg      return _mesa_is_desktop_gl(ctx) ? TEXTURE_1D_INDEX : -1;
1571c1f859d4Smrg   case GL_TEXTURE_2D:
1572c1f859d4Smrg      return TEXTURE_2D_INDEX;
1573c1f859d4Smrg   case GL_TEXTURE_3D:
1574af69d88dSmrg      return ctx->API != API_OPENGLES ? TEXTURE_3D_INDEX : -1;
1575af69d88dSmrg   case GL_TEXTURE_CUBE_MAP:
1576af69d88dSmrg      return ctx->Extensions.ARB_texture_cube_map
1577af69d88dSmrg         ? TEXTURE_CUBE_INDEX : -1;
1578af69d88dSmrg   case GL_TEXTURE_RECTANGLE:
1579af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle
1580af69d88dSmrg         ? TEXTURE_RECT_INDEX : -1;
1581af69d88dSmrg   case GL_TEXTURE_1D_ARRAY:
1582af69d88dSmrg      return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array
1583af69d88dSmrg         ? TEXTURE_1D_ARRAY_INDEX : -1;
1584af69d88dSmrg   case GL_TEXTURE_2D_ARRAY:
1585af69d88dSmrg      return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array)
1586af69d88dSmrg         || _mesa_is_gles3(ctx)
1587af69d88dSmrg         ? TEXTURE_2D_ARRAY_INDEX : -1;
1588af69d88dSmrg   case GL_TEXTURE_BUFFER:
158901e04c3fSmrg      return (_mesa_has_ARB_texture_buffer_object(ctx) ||
159001e04c3fSmrg              _mesa_has_OES_texture_buffer(ctx)) ?
1591af69d88dSmrg             TEXTURE_BUFFER_INDEX : -1;
1592af69d88dSmrg   case GL_TEXTURE_EXTERNAL_OES:
1593af69d88dSmrg      return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external
1594af69d88dSmrg         ? TEXTURE_EXTERNAL_INDEX : -1;
1595af69d88dSmrg   case GL_TEXTURE_CUBE_MAP_ARRAY:
159601e04c3fSmrg      return _mesa_has_texture_cube_map_array(ctx)
1597af69d88dSmrg         ? TEXTURE_CUBE_ARRAY_INDEX : -1;
1598af69d88dSmrg   case GL_TEXTURE_2D_MULTISAMPLE:
159901e04c3fSmrg      return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample) ||
160001e04c3fSmrg              _mesa_is_gles31(ctx)) ? TEXTURE_2D_MULTISAMPLE_INDEX: -1;
1601af69d88dSmrg   case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
160201e04c3fSmrg      return ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample) ||
160301e04c3fSmrg              _mesa_is_gles31(ctx))
1604af69d88dSmrg         ? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: -1;
1605c1f859d4Smrg   default:
1606c1f859d4Smrg      return -1;
1607c1f859d4Smrg   }
1608c1f859d4Smrg}
1609c1f859d4Smrg
1610c1f859d4Smrg
16117117f1b4Smrg/**
161201e04c3fSmrg * Do actual texture binding.  All error checking should have been done prior
161301e04c3fSmrg * to calling this function.  Note that the texture target (1D, 2D, etc) is
161401e04c3fSmrg * always specified by the texObj->TargetIndex.
161501e04c3fSmrg *
161601e04c3fSmrg * \param unit  index of texture unit to update
161701e04c3fSmrg * \param texObj  the new texture object (cannot be NULL)
161801e04c3fSmrg */
161901e04c3fSmrgstatic void
162001e04c3fSmrgbind_texture_object(struct gl_context *ctx, unsigned unit,
162101e04c3fSmrg                    struct gl_texture_object *texObj)
162201e04c3fSmrg{
162301e04c3fSmrg   struct gl_texture_unit *texUnit;
162401e04c3fSmrg   int targetIndex;
162501e04c3fSmrg
162601e04c3fSmrg   assert(unit < ARRAY_SIZE(ctx->Texture.Unit));
162701e04c3fSmrg   texUnit = &ctx->Texture.Unit[unit];
162801e04c3fSmrg
162901e04c3fSmrg   assert(texObj);
163001e04c3fSmrg   assert(valid_texture_object(texObj));
163101e04c3fSmrg
163201e04c3fSmrg   targetIndex = texObj->TargetIndex;
163301e04c3fSmrg   assert(targetIndex >= 0);
163401e04c3fSmrg   assert(targetIndex < NUM_TEXTURE_TARGETS);
163501e04c3fSmrg
163601e04c3fSmrg   /* Check if this texture is only used by this context and is already bound.
163701e04c3fSmrg    * If so, just return. For GL_OES_image_external, rebinding the texture
163801e04c3fSmrg    * always must invalidate cached resources.
163901e04c3fSmrg    */
16407ec681f3Smrg   if (targetIndex != TEXTURE_EXTERNAL_INDEX &&
16417ec681f3Smrg       ctx->Shared->RefCount == 1 &&
16427ec681f3Smrg       texObj == texUnit->CurrentTex[targetIndex])
16437ec681f3Smrg      return;
164401e04c3fSmrg
16457ec681f3Smrg   /* Flush before changing binding.
16467ec681f3Smrg    *
16477ec681f3Smrg    * Note: Multisample textures don't need to flag GL_TEXTURE_BIT because
16487ec681f3Smrg    *       they are not restored by glPopAttrib according to the GL 4.6
16497ec681f3Smrg    *       Compatibility Profile specification. We set GL_TEXTURE_BIT anyway
16507ec681f3Smrg    *       to simplify the code. This has no effect on behavior.
16517ec681f3Smrg    */
16527ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT, GL_TEXTURE_BIT);
165301e04c3fSmrg
165401e04c3fSmrg   /* If the refcount on the previously bound texture is decremented to
165501e04c3fSmrg    * zero, it'll be deleted here.
165601e04c3fSmrg    */
165701e04c3fSmrg   _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], texObj);
165801e04c3fSmrg
165901e04c3fSmrg   ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
166001e04c3fSmrg                                         unit + 1);
166101e04c3fSmrg
166201e04c3fSmrg   if (texObj->Name != 0)
166301e04c3fSmrg      texUnit->_BoundTextures |= (1 << targetIndex);
166401e04c3fSmrg   else
166501e04c3fSmrg      texUnit->_BoundTextures &= ~(1 << targetIndex);
166601e04c3fSmrg
166701e04c3fSmrg   /* Pass BindTexture call to device driver */
166801e04c3fSmrg   if (ctx->Driver.BindTexture) {
166901e04c3fSmrg      ctx->Driver.BindTexture(ctx, unit, texObj->Target, texObj);
167001e04c3fSmrg   }
167101e04c3fSmrg}
167201e04c3fSmrg
167301e04c3fSmrg/**
167401e04c3fSmrg * Light-weight bind texture for internal users
167501e04c3fSmrg *
167601e04c3fSmrg * This is really just \c finish_texture_init plus \c bind_texture_object.
167701e04c3fSmrg * This is intended to be used by internal Mesa functions that use
167801e04c3fSmrg * \c _mesa_CreateTexture and need to bind textures (e.g., meta).
167901e04c3fSmrg */
168001e04c3fSmrgvoid
168101e04c3fSmrg_mesa_bind_texture(struct gl_context *ctx, GLenum target,
168201e04c3fSmrg                   struct gl_texture_object *tex_obj)
168301e04c3fSmrg{
168401e04c3fSmrg   const GLint targetIndex = _mesa_tex_target_to_index(ctx, target);
168501e04c3fSmrg
168601e04c3fSmrg   assert(targetIndex >= 0 && targetIndex < NUM_TEXTURE_TARGETS);
168701e04c3fSmrg
168801e04c3fSmrg   if (tex_obj->Target == 0)
168901e04c3fSmrg      finish_texture_init(ctx, target, tex_obj, targetIndex);
169001e04c3fSmrg
169101e04c3fSmrg   assert(tex_obj->Target == target);
169201e04c3fSmrg   assert(tex_obj->TargetIndex == targetIndex);
169301e04c3fSmrg
169401e04c3fSmrg   bind_texture_object(ctx, ctx->Texture.CurrentUnit, tex_obj);
169501e04c3fSmrg}
169601e04c3fSmrg
16977ec681f3Smrgstruct gl_texture_object *
16987ec681f3Smrg_mesa_lookup_or_create_texture(struct gl_context *ctx, GLenum target,
16997ec681f3Smrg                               GLuint texName, bool no_error, bool is_ext_dsa,
17007ec681f3Smrg                               const char *caller)
17017117f1b4Smrg{
17023464ebd5Sriastradh   struct gl_texture_object *newTexObj = NULL;
170301e04c3fSmrg   int targetIndex;
17047117f1b4Smrg
17057ec681f3Smrg   if (is_ext_dsa) {
17067ec681f3Smrg      if (_mesa_is_proxy_texture(target)) {
17077ec681f3Smrg         /* EXT_dsa allows proxy targets only when texName is 0 */
17087ec681f3Smrg         if (texName != 0) {
17097ec681f3Smrg            _mesa_error(ctx, GL_INVALID_OPERATION, "%s(target = %s)", caller,
17107ec681f3Smrg                        _mesa_enum_to_string(target));
17117ec681f3Smrg            return NULL;
17127ec681f3Smrg         }
17137ec681f3Smrg         return _mesa_get_current_tex_object(ctx, target);
17147ec681f3Smrg      }
17157ec681f3Smrg      if (GL_TEXTURE_CUBE_MAP_POSITIVE_X <= target &&
17167ec681f3Smrg          target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z) {
17177ec681f3Smrg         target = GL_TEXTURE_CUBE_MAP;
17187ec681f3Smrg      }
17197ec681f3Smrg   }
17207ec681f3Smrg
1721af69d88dSmrg   targetIndex = _mesa_tex_target_to_index(ctx, target);
172201e04c3fSmrg   if (!no_error && targetIndex < 0) {
17237ec681f3Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(target = %s)", caller,
172401e04c3fSmrg                  _mesa_enum_to_string(target));
17257ec681f3Smrg      return NULL;
1726c1f859d4Smrg   }
1727c1f859d4Smrg   assert(targetIndex < NUM_TEXTURE_TARGETS);
1728c1f859d4Smrg
17297117f1b4Smrg   /*
17307117f1b4Smrg    * Get pointer to new texture object (newTexObj)
17317117f1b4Smrg    */
17327117f1b4Smrg   if (texName == 0) {
17333464ebd5Sriastradh      /* Use a default texture object */
17343464ebd5Sriastradh      newTexObj = ctx->Shared->DefaultTex[targetIndex];
173501e04c3fSmrg   } else {
17367117f1b4Smrg      /* non-default texture object */
17377117f1b4Smrg      newTexObj = _mesa_lookup_texture(ctx, texName);
17387117f1b4Smrg      if (newTexObj) {
17397117f1b4Smrg         /* error checking */
174001e04c3fSmrg         if (!no_error &&
174101e04c3fSmrg             newTexObj->Target != 0 && newTexObj->Target != target) {
174201e04c3fSmrg            /* The named texture object's target doesn't match the
174301e04c3fSmrg             * given target
174401e04c3fSmrg             */
17457ec681f3Smrg            _mesa_error(ctx, GL_INVALID_OPERATION,
17467ec681f3Smrg                        "%s(target mismatch)", caller);
17477ec681f3Smrg            return NULL;
17487117f1b4Smrg         }
1749c1f859d4Smrg         if (newTexObj->Target == 0) {
175001e04c3fSmrg            finish_texture_init(ctx, target, newTexObj, targetIndex);
17517117f1b4Smrg         }
17527ec681f3Smrg      } else {
175301e04c3fSmrg         if (!no_error && ctx->API == API_OPENGL_CORE) {
175401e04c3fSmrg            _mesa_error(ctx, GL_INVALID_OPERATION,
17557ec681f3Smrg                        "%s(non-gen name)", caller);
17567ec681f3Smrg            return NULL;
1757af69d88dSmrg         }
1758af69d88dSmrg
17597117f1b4Smrg         /* if this is a new texture id, allocate a texture object now */
1760af69d88dSmrg         newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target);
17617117f1b4Smrg         if (!newTexObj) {
17627ec681f3Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", caller);
17637ec681f3Smrg            return NULL;
17647117f1b4Smrg         }
17657117f1b4Smrg
17667117f1b4Smrg         /* and insert it into hash table */
17677ec681f3Smrg         _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj, false);
17687117f1b4Smrg      }
17697117f1b4Smrg   }
17707117f1b4Smrg
177101e04c3fSmrg   assert(newTexObj->Target == target);
177201e04c3fSmrg   assert(newTexObj->TargetIndex == targetIndex);
17737117f1b4Smrg
17747ec681f3Smrg   return newTexObj;
17757ec681f3Smrg}
17767ec681f3Smrg
17777ec681f3Smrg/**
17787ec681f3Smrg * Implement glBindTexture().  Do error checking, look-up or create a new
17797ec681f3Smrg * texture object, then bind it in the current texture unit.
17807ec681f3Smrg *
17817ec681f3Smrg * \param target texture target.
17827ec681f3Smrg * \param texName texture name.
17837ec681f3Smrg * \param texunit texture unit.
17847ec681f3Smrg */
17857ec681f3Smrgstatic ALWAYS_INLINE void
17867ec681f3Smrgbind_texture(struct gl_context *ctx, GLenum target, GLuint texName,
17877ec681f3Smrg             GLenum texunit, bool no_error, const char *caller)
17887ec681f3Smrg{
17897ec681f3Smrg   struct gl_texture_object *newTexObj =
17907ec681f3Smrg      _mesa_lookup_or_create_texture(ctx, target, texName, no_error, false,
17917ec681f3Smrg                                     caller);
17927ec681f3Smrg   if (!newTexObj)
17937ec681f3Smrg      return;
17947ec681f3Smrg
17957ec681f3Smrg   bind_texture_object(ctx, texunit, newTexObj);
179601e04c3fSmrg}
179701e04c3fSmrg
179801e04c3fSmrgvoid GLAPIENTRY
179901e04c3fSmrg_mesa_BindTexture_no_error(GLenum target, GLuint texName)
180001e04c3fSmrg{
180101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
18027ec681f3Smrg   bind_texture(ctx, target, texName, ctx->Texture.CurrentUnit, true,
18037ec681f3Smrg                "glBindTexture");
180401e04c3fSmrg}
180501e04c3fSmrg
180601e04c3fSmrg
180701e04c3fSmrgvoid GLAPIENTRY
180801e04c3fSmrg_mesa_BindTexture(GLenum target, GLuint texName)
180901e04c3fSmrg{
181001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
181101e04c3fSmrg
181201e04c3fSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
181301e04c3fSmrg      _mesa_debug(ctx, "glBindTexture %s %d\n",
181401e04c3fSmrg                  _mesa_enum_to_string(target), (GLint) texName);
181501e04c3fSmrg
18167ec681f3Smrg   bind_texture(ctx, target, texName, ctx->Texture.CurrentUnit, false,
18177ec681f3Smrg                "glBindTexture");
18187ec681f3Smrg}
18197ec681f3Smrg
18207ec681f3Smrg
18217ec681f3Smrgvoid GLAPIENTRY
18227ec681f3Smrg_mesa_BindMultiTextureEXT(GLenum texunit, GLenum target, GLuint texture)
18237ec681f3Smrg{
18247ec681f3Smrg   GET_CURRENT_CONTEXT(ctx);
18257ec681f3Smrg
18267ec681f3Smrg   unsigned unit = texunit - GL_TEXTURE0;
18277ec681f3Smrg
18287ec681f3Smrg   if (texunit < GL_TEXTURE0 || unit >= _mesa_max_tex_unit(ctx)) {
18297ec681f3Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBindMultiTextureEXT(texunit=%s)",
18307ec681f3Smrg                  _mesa_enum_to_string(texunit));
18317ec681f3Smrg      return;
18327ec681f3Smrg   }
18337ec681f3Smrg
18347ec681f3Smrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
18357ec681f3Smrg      _mesa_debug(ctx, "glBindMultiTextureEXT %s %d\n",
18367ec681f3Smrg                  _mesa_enum_to_string(texunit), (GLint) texture);
18377ec681f3Smrg
18387ec681f3Smrg   bind_texture(ctx, target, texture, unit, false, "glBindMultiTextureEXT");
183901e04c3fSmrg}
184001e04c3fSmrg
184101e04c3fSmrg
184201e04c3fSmrg/**
184301e04c3fSmrg * OpenGL 4.5 / GL_ARB_direct_state_access glBindTextureUnit().
184401e04c3fSmrg *
184501e04c3fSmrg * \param unit texture unit.
184601e04c3fSmrg * \param texture texture name.
184701e04c3fSmrg *
184801e04c3fSmrg * \sa glBindTexture().
184901e04c3fSmrg *
185001e04c3fSmrg * If the named texture is 0, this will reset each target for the specified
185101e04c3fSmrg * texture unit to its default texture.
185201e04c3fSmrg * If the named texture is not 0 or a recognized texture name, this throws
185301e04c3fSmrg * GL_INVALID_OPERATION.
185401e04c3fSmrg */
185501e04c3fSmrgstatic ALWAYS_INLINE void
185601e04c3fSmrgbind_texture_unit(struct gl_context *ctx, GLuint unit, GLuint texture,
185701e04c3fSmrg                  bool no_error)
185801e04c3fSmrg{
185901e04c3fSmrg   struct gl_texture_object *texObj;
186001e04c3fSmrg
186101e04c3fSmrg   /* Section 8.1 (Texture Objects) of the OpenGL 4.5 core profile spec
186201e04c3fSmrg    * (20141030) says:
186301e04c3fSmrg    *    "When texture is zero, each of the targets enumerated at the
186401e04c3fSmrg    *    beginning of this section is reset to its default texture for the
186501e04c3fSmrg    *    corresponding texture image unit."
18663464ebd5Sriastradh    */
186701e04c3fSmrg   if (texture == 0) {
186801e04c3fSmrg      unbind_textures_from_unit(ctx, unit);
186901e04c3fSmrg      return;
187001e04c3fSmrg   }
187101e04c3fSmrg
187201e04c3fSmrg   /* Get the non-default texture object */
187301e04c3fSmrg   texObj = _mesa_lookup_texture(ctx, texture);
187401e04c3fSmrg   if (!no_error) {
187501e04c3fSmrg      /* Error checking */
187601e04c3fSmrg      if (!texObj) {
187701e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
187801e04c3fSmrg                     "glBindTextureUnit(non-gen name)");
187901e04c3fSmrg         return;
188001e04c3fSmrg      }
188101e04c3fSmrg
188201e04c3fSmrg      if (texObj->Target == 0) {
188301e04c3fSmrg         /* Texture object was gen'd but never bound so the target is not set */
188401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTextureUnit(target)");
18853464ebd5Sriastradh         return;
18863464ebd5Sriastradh      }
18874a49301eSmrg   }
18884a49301eSmrg
188901e04c3fSmrg   assert(valid_texture_object(texObj));
18907117f1b4Smrg
189101e04c3fSmrg   bind_texture_object(ctx, unit, texObj);
189201e04c3fSmrg}
18937117f1b4Smrg
1894af69d88dSmrg
189501e04c3fSmrgvoid GLAPIENTRY
189601e04c3fSmrg_mesa_BindTextureUnit_no_error(GLuint unit, GLuint texture)
189701e04c3fSmrg{
189801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
189901e04c3fSmrg   bind_texture_unit(ctx, unit, texture, true);
1900af69d88dSmrg}
1901af69d88dSmrg
1902af69d88dSmrg
1903af69d88dSmrgvoid GLAPIENTRY
190401e04c3fSmrg_mesa_BindTextureUnit(GLuint unit, GLuint texture)
1905af69d88dSmrg{
1906af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
1907af69d88dSmrg
190801e04c3fSmrg   if (unit >= _mesa_max_tex_unit(ctx)) {
190901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "glBindTextureUnit(unit=%u)", unit);
1910af69d88dSmrg      return;
1911af69d88dSmrg   }
1912af69d88dSmrg
191301e04c3fSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
191401e04c3fSmrg      _mesa_debug(ctx, "glBindTextureUnit %s %d\n",
191501e04c3fSmrg                  _mesa_enum_to_string(GL_TEXTURE0+unit), (GLint) texture);
191601e04c3fSmrg
191701e04c3fSmrg   bind_texture_unit(ctx, unit, texture, false);
191801e04c3fSmrg}
1919af69d88dSmrg
192001e04c3fSmrg
192101e04c3fSmrg/**
192201e04c3fSmrg * OpenGL 4.4 / GL_ARB_multi_bind glBindTextures().
192301e04c3fSmrg */
192401e04c3fSmrgstatic ALWAYS_INLINE void
192501e04c3fSmrgbind_textures(struct gl_context *ctx, GLuint first, GLsizei count,
192601e04c3fSmrg              const GLuint *textures, bool no_error)
192701e04c3fSmrg{
192801e04c3fSmrg   GLsizei i;
1929af69d88dSmrg
1930af69d88dSmrg   if (textures) {
1931af69d88dSmrg      /* Note that the error semantics for multi-bind commands differ from
1932af69d88dSmrg       * those of other GL commands.
1933af69d88dSmrg       *
1934af69d88dSmrg       * The issues section in the ARB_multi_bind spec says:
1935af69d88dSmrg       *
1936af69d88dSmrg       *    "(11) Typically, OpenGL specifies that if an error is generated by
1937af69d88dSmrg       *          a command, that command has no effect.  This is somewhat
1938af69d88dSmrg       *          unfortunate for multi-bind commands, because it would require
1939af69d88dSmrg       *          a first pass to scan the entire list of bound objects for
1940af69d88dSmrg       *          errors and then a second pass to actually perform the
1941af69d88dSmrg       *          bindings.  Should we have different error semantics?
1942af69d88dSmrg       *
1943af69d88dSmrg       *       RESOLVED:  Yes.  In this specification, when the parameters for
1944af69d88dSmrg       *       one of the <count> binding points are invalid, that binding
1945af69d88dSmrg       *       point is not updated and an error will be generated.  However,
1946af69d88dSmrg       *       other binding points in the same command will be updated if
1947af69d88dSmrg       *       their parameters are valid and no other error occurs."
1948af69d88dSmrg       */
1949af69d88dSmrg
195001e04c3fSmrg      _mesa_HashLockMutex(ctx->Shared->TexObjects);
1951af69d88dSmrg
1952af69d88dSmrg      for (i = 0; i < count; i++) {
1953af69d88dSmrg         if (textures[i] != 0) {
1954af69d88dSmrg            struct gl_texture_unit *texUnit = &ctx->Texture.Unit[first + i];
1955af69d88dSmrg            struct gl_texture_object *current = texUnit->_Current;
1956af69d88dSmrg            struct gl_texture_object *texObj;
1957af69d88dSmrg
1958af69d88dSmrg            if (current && current->Name == textures[i])
1959af69d88dSmrg               texObj = current;
1960af69d88dSmrg            else
1961af69d88dSmrg               texObj = _mesa_lookup_texture_locked(ctx, textures[i]);
1962af69d88dSmrg
1963af69d88dSmrg            if (texObj && texObj->Target != 0) {
196401e04c3fSmrg               bind_texture_object(ctx, first + i, texObj);
196501e04c3fSmrg            } else if (!no_error) {
1966af69d88dSmrg               /* The ARB_multi_bind spec says:
1967af69d88dSmrg                *
1968af69d88dSmrg                *     "An INVALID_OPERATION error is generated if any value
1969af69d88dSmrg                *      in <textures> is not zero or the name of an existing
1970af69d88dSmrg                *      texture object (per binding)."
1971af69d88dSmrg                */
1972af69d88dSmrg               _mesa_error(ctx, GL_INVALID_OPERATION,
1973af69d88dSmrg                           "glBindTextures(textures[%d]=%u is not zero "
1974af69d88dSmrg                           "or the name of an existing texture object)",
1975af69d88dSmrg                           i, textures[i]);
1976af69d88dSmrg            }
1977af69d88dSmrg         } else {
1978af69d88dSmrg            unbind_textures_from_unit(ctx, first + i);
1979af69d88dSmrg         }
1980af69d88dSmrg      }
1981af69d88dSmrg
198201e04c3fSmrg      _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
1983af69d88dSmrg   } else {
1984af69d88dSmrg      /* Unbind all textures in the range <first> through <first>+<count>-1 */
1985af69d88dSmrg      for (i = 0; i < count; i++)
1986af69d88dSmrg         unbind_textures_from_unit(ctx, first + i);
1987af69d88dSmrg   }
19887117f1b4Smrg}
19897117f1b4Smrg
19907117f1b4Smrg
199101e04c3fSmrgvoid GLAPIENTRY
199201e04c3fSmrg_mesa_BindTextures_no_error(GLuint first, GLsizei count, const GLuint *textures)
199301e04c3fSmrg{
199401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
199501e04c3fSmrg   bind_textures(ctx, first, count, textures, true);
199601e04c3fSmrg}
199701e04c3fSmrg
199801e04c3fSmrg
199901e04c3fSmrgvoid GLAPIENTRY
200001e04c3fSmrg_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
200101e04c3fSmrg{
200201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
200301e04c3fSmrg
200401e04c3fSmrg   /* The ARB_multi_bind spec says:
200501e04c3fSmrg    *
200601e04c3fSmrg    *     "An INVALID_OPERATION error is generated if <first> + <count>
200701e04c3fSmrg    *      is greater than the number of texture image units supported
200801e04c3fSmrg    *      by the implementation."
200901e04c3fSmrg    */
201001e04c3fSmrg   if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
201101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
201201e04c3fSmrg                  "glBindTextures(first=%u + count=%d > the value of "
201301e04c3fSmrg                  "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
201401e04c3fSmrg                  first, count, ctx->Const.MaxCombinedTextureImageUnits);
201501e04c3fSmrg      return;
201601e04c3fSmrg   }
201701e04c3fSmrg
201801e04c3fSmrg   bind_textures(ctx, first, count, textures, false);
201901e04c3fSmrg}
202001e04c3fSmrg
202101e04c3fSmrg
20227117f1b4Smrg/**
20237117f1b4Smrg * Set texture priorities.
202401e04c3fSmrg *
20257117f1b4Smrg * \param n number of textures.
20267117f1b4Smrg * \param texName texture names.
20277117f1b4Smrg * \param priorities corresponding texture priorities.
202801e04c3fSmrg *
20297117f1b4Smrg * \sa glPrioritizeTextures().
203001e04c3fSmrg *
20317117f1b4Smrg * Looks up each texture in the hash, clamps the corresponding priority between
20327117f1b4Smrg * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture.
20337117f1b4Smrg */
20347117f1b4Smrgvoid GLAPIENTRY
20357117f1b4Smrg_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName,
20367117f1b4Smrg                          const GLclampf *priorities )
20377117f1b4Smrg{
20387117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
20397117f1b4Smrg   GLint i;
2040af69d88dSmrg
2041af69d88dSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
2042af69d88dSmrg      _mesa_debug(ctx, "glPrioritizeTextures %d\n", n);
2043af69d88dSmrg
20447117f1b4Smrg
20457117f1b4Smrg   if (n < 0) {
20467117f1b4Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" );
20477117f1b4Smrg      return;
20487117f1b4Smrg   }
20497117f1b4Smrg
20507117f1b4Smrg   if (!priorities)
20517117f1b4Smrg      return;
20527117f1b4Smrg
20537ec681f3Smrg   FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT, GL_TEXTURE_BIT);
20547ec681f3Smrg
20557117f1b4Smrg   for (i = 0; i < n; i++) {
20567117f1b4Smrg      if (texName[i] > 0) {
20577117f1b4Smrg         struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]);
20587117f1b4Smrg         if (t) {
20597ec681f3Smrg            t->Attrib.Priority = CLAMP( priorities[i], 0.0F, 1.0F );
20607117f1b4Smrg         }
20617117f1b4Smrg      }
20627117f1b4Smrg   }
20637117f1b4Smrg}
20647117f1b4Smrg
20653464ebd5Sriastradh
20663464ebd5Sriastradh
20677117f1b4Smrg/**
20687117f1b4Smrg * See if textures are loaded in texture memory.
206901e04c3fSmrg *
20707117f1b4Smrg * \param n number of textures to query.
20717117f1b4Smrg * \param texName array with the texture names.
20727117f1b4Smrg * \param residences array which will hold the residence status.
20737117f1b4Smrg *
207401e04c3fSmrg * \return GL_TRUE if all textures are resident and
207501e04c3fSmrg *                 residences is left unchanged,
207601e04c3fSmrg *
2077af69d88dSmrg * Note: we assume all textures are always resident
20787117f1b4Smrg */
20797117f1b4SmrgGLboolean GLAPIENTRY
20807117f1b4Smrg_mesa_AreTexturesResident(GLsizei n, const GLuint *texName,
20817117f1b4Smrg                          GLboolean *residences)
20827117f1b4Smrg{
20837117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
20847117f1b4Smrg   GLboolean allResident = GL_TRUE;
2085af69d88dSmrg   GLint i;
20867117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
20877117f1b4Smrg
2088af69d88dSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
2089af69d88dSmrg      _mesa_debug(ctx, "glAreTexturesResident %d\n", n);
2090af69d88dSmrg
20917117f1b4Smrg   if (n < 0) {
20927117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)");
20937117f1b4Smrg      return GL_FALSE;
20947117f1b4Smrg   }
20957117f1b4Smrg
20967117f1b4Smrg   if (!texName || !residences)
20977117f1b4Smrg      return GL_FALSE;
20987117f1b4Smrg
2099af69d88dSmrg   /* We only do error checking on the texture names */
21007117f1b4Smrg   for (i = 0; i < n; i++) {
21017117f1b4Smrg      struct gl_texture_object *t;
21027117f1b4Smrg      if (texName[i] == 0) {
21037117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
21047117f1b4Smrg         return GL_FALSE;
21057117f1b4Smrg      }
21067117f1b4Smrg      t = _mesa_lookup_texture(ctx, texName[i]);
21077117f1b4Smrg      if (!t) {
21087117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident");
21097117f1b4Smrg         return GL_FALSE;
21107117f1b4Smrg      }
21117117f1b4Smrg   }
211201e04c3fSmrg
21137117f1b4Smrg   return allResident;
21147117f1b4Smrg}
21157117f1b4Smrg
21163464ebd5Sriastradh
21177117f1b4Smrg/**
21187117f1b4Smrg * See if a name corresponds to a texture.
21197117f1b4Smrg *
21207117f1b4Smrg * \param texture texture name.
21217117f1b4Smrg *
21227117f1b4Smrg * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE
21237117f1b4Smrg * otherwise.
212401e04c3fSmrg *
21257117f1b4Smrg * \sa glIsTexture().
21267117f1b4Smrg *
21277117f1b4Smrg * Calls _mesa_HashLookup().
21287117f1b4Smrg */
21297117f1b4SmrgGLboolean GLAPIENTRY
21307117f1b4Smrg_mesa_IsTexture( GLuint texture )
21317117f1b4Smrg{
21327117f1b4Smrg   struct gl_texture_object *t;
21337117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
21347117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
21357117f1b4Smrg
2136af69d88dSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
2137af69d88dSmrg      _mesa_debug(ctx, "glIsTexture %d\n", texture);
2138af69d88dSmrg
21397117f1b4Smrg   if (!texture)
21407117f1b4Smrg      return GL_FALSE;
21417117f1b4Smrg
21427117f1b4Smrg   t = _mesa_lookup_texture(ctx, texture);
21437117f1b4Smrg
21447117f1b4Smrg   /* IsTexture is true only after object has been bound once. */
21457117f1b4Smrg   return t && t->Target;
21467117f1b4Smrg}
21477117f1b4Smrg
2148c1f859d4Smrg
2149c1f859d4Smrg/**
21504a49301eSmrg * Simplest implementation of texture locking: grab the shared tex
21514a49301eSmrg * mutex.  Examine the shared context state timestamp and if there has
21524a49301eSmrg * been a change, set the appropriate bits in ctx->NewState.
21537117f1b4Smrg *
2154c1f859d4Smrg * This is used to deal with synchronizing things when a texture object
2155c1f859d4Smrg * is used/modified by different contexts (or threads) which are sharing
2156c1f859d4Smrg * the texture.
2157c1f859d4Smrg *
2158c1f859d4Smrg * See also _mesa_lock/unlock_texture() in teximage.h
21597117f1b4Smrg */
2160c1f859d4Smrgvoid
21613464ebd5Sriastradh_mesa_lock_context_textures( struct gl_context *ctx )
21627117f1b4Smrg{
21637ec681f3Smrg   if (!ctx->TexturesLocked)
21647ec681f3Smrg      mtx_lock(&ctx->Shared->TexMutex);
21657117f1b4Smrg
21667117f1b4Smrg   if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) {
216701e04c3fSmrg      ctx->NewState |= _NEW_TEXTURE_OBJECT;
21687ec681f3Smrg      ctx->PopAttribState |= GL_TEXTURE_BIT;
21697117f1b4Smrg      ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp;
21707117f1b4Smrg   }
21717117f1b4Smrg}
21727117f1b4Smrg
21737117f1b4Smrg
2174c1f859d4Smrgvoid
21753464ebd5Sriastradh_mesa_unlock_context_textures( struct gl_context *ctx )
21767117f1b4Smrg{
21777117f1b4Smrg   assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp);
21787ec681f3Smrg   if (!ctx->TexturesLocked)
21797ec681f3Smrg      mtx_unlock(&ctx->Shared->TexMutex);
2180af69d88dSmrg}
2181af69d88dSmrg
218201e04c3fSmrg
218301e04c3fSmrgvoid GLAPIENTRY
218401e04c3fSmrg_mesa_InvalidateTexSubImage_no_error(GLuint texture, GLint level, GLint xoffset,
218501e04c3fSmrg                                     GLint yoffset, GLint zoffset,
218601e04c3fSmrg                                     GLsizei width, GLsizei height,
218701e04c3fSmrg                                     GLsizei depth)
218801e04c3fSmrg{
218901e04c3fSmrg   /* no-op */
219001e04c3fSmrg}
219101e04c3fSmrg
219201e04c3fSmrg
2193af69d88dSmrgvoid GLAPIENTRY
2194af69d88dSmrg_mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset,
2195af69d88dSmrg                            GLint yoffset, GLint zoffset, GLsizei width,
2196af69d88dSmrg                            GLsizei height, GLsizei depth)
2197af69d88dSmrg{
2198af69d88dSmrg   struct gl_texture_object *t;
2199af69d88dSmrg   struct gl_texture_image *image;
2200af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
2201af69d88dSmrg
2202af69d88dSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
2203af69d88dSmrg      _mesa_debug(ctx, "glInvalidateTexSubImage %d\n", texture);
2204af69d88dSmrg
2205af69d88dSmrg   t = invalidate_tex_image_error_check(ctx, texture, level,
2206af69d88dSmrg                                        "glInvalidateTexSubImage");
2207af69d88dSmrg
2208af69d88dSmrg   /* The GL_ARB_invalidate_subdata spec says:
2209af69d88dSmrg    *
2210af69d88dSmrg    *     "...the specified subregion must be between -<b> and <dim>+<b> where
2211af69d88dSmrg    *     <dim> is the size of the dimension of the texture image, and <b> is
2212af69d88dSmrg    *     the size of the border of that texture image, otherwise
2213af69d88dSmrg    *     INVALID_VALUE is generated (border is not applied to dimensions that
2214af69d88dSmrg    *     don't exist in a given texture target)."
2215af69d88dSmrg    */
2216af69d88dSmrg   image = t->Image[0][level];
2217af69d88dSmrg   if (image) {
2218af69d88dSmrg      int xBorder;
2219af69d88dSmrg      int yBorder;
2220af69d88dSmrg      int zBorder;
2221af69d88dSmrg      int imageWidth;
2222af69d88dSmrg      int imageHeight;
2223af69d88dSmrg      int imageDepth;
2224af69d88dSmrg
2225af69d88dSmrg      /* The GL_ARB_invalidate_subdata spec says:
2226af69d88dSmrg       *
2227af69d88dSmrg       *     "For texture targets that don't have certain dimensions, this
2228af69d88dSmrg       *     command treats those dimensions as having a size of 1. For
2229af69d88dSmrg       *     example, to invalidate a portion of a two-dimensional texture,
2230af69d88dSmrg       *     the application would use <zoffset> equal to zero and <depth>
2231af69d88dSmrg       *     equal to one."
2232af69d88dSmrg       */
2233af69d88dSmrg      switch (t->Target) {
2234af69d88dSmrg      case GL_TEXTURE_BUFFER:
2235af69d88dSmrg         xBorder = 0;
2236af69d88dSmrg         yBorder = 0;
2237af69d88dSmrg         zBorder = 0;
2238af69d88dSmrg         imageWidth = 1;
2239af69d88dSmrg         imageHeight = 1;
2240af69d88dSmrg         imageDepth = 1;
2241af69d88dSmrg         break;
2242af69d88dSmrg      case GL_TEXTURE_1D:
2243af69d88dSmrg         xBorder = image->Border;
2244af69d88dSmrg         yBorder = 0;
2245af69d88dSmrg         zBorder = 0;
2246af69d88dSmrg         imageWidth = image->Width;
2247af69d88dSmrg         imageHeight = 1;
2248af69d88dSmrg         imageDepth = 1;
2249af69d88dSmrg         break;
2250af69d88dSmrg      case GL_TEXTURE_1D_ARRAY:
2251af69d88dSmrg         xBorder = image->Border;
2252af69d88dSmrg         yBorder = 0;
2253af69d88dSmrg         zBorder = 0;
2254af69d88dSmrg         imageWidth = image->Width;
2255af69d88dSmrg         imageHeight = image->Height;
2256af69d88dSmrg         imageDepth = 1;
2257af69d88dSmrg         break;
2258af69d88dSmrg      case GL_TEXTURE_2D:
2259af69d88dSmrg      case GL_TEXTURE_CUBE_MAP:
2260af69d88dSmrg      case GL_TEXTURE_RECTANGLE:
2261af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE:
2262af69d88dSmrg         xBorder = image->Border;
2263af69d88dSmrg         yBorder = image->Border;
2264af69d88dSmrg         zBorder = 0;
2265af69d88dSmrg         imageWidth = image->Width;
2266af69d88dSmrg         imageHeight = image->Height;
2267af69d88dSmrg         imageDepth = 1;
2268af69d88dSmrg         break;
2269af69d88dSmrg      case GL_TEXTURE_2D_ARRAY:
2270af69d88dSmrg      case GL_TEXTURE_CUBE_MAP_ARRAY:
2271af69d88dSmrg      case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
2272af69d88dSmrg         xBorder = image->Border;
2273af69d88dSmrg         yBorder = image->Border;
2274af69d88dSmrg         zBorder = 0;
2275af69d88dSmrg         imageWidth = image->Width;
2276af69d88dSmrg         imageHeight = image->Height;
2277af69d88dSmrg         imageDepth = image->Depth;
2278af69d88dSmrg         break;
2279af69d88dSmrg      case GL_TEXTURE_3D:
2280af69d88dSmrg         xBorder = image->Border;
2281af69d88dSmrg         yBorder = image->Border;
2282af69d88dSmrg         zBorder = image->Border;
2283af69d88dSmrg         imageWidth = image->Width;
2284af69d88dSmrg         imageHeight = image->Height;
2285af69d88dSmrg         imageDepth = image->Depth;
2286af69d88dSmrg         break;
2287af69d88dSmrg      default:
2288af69d88dSmrg         assert(!"Should not get here.");
2289af69d88dSmrg         xBorder = 0;
2290af69d88dSmrg         yBorder = 0;
2291af69d88dSmrg         zBorder = 0;
2292af69d88dSmrg         imageWidth = 0;
2293af69d88dSmrg         imageHeight = 0;
2294af69d88dSmrg         imageDepth = 0;
2295af69d88dSmrg         break;
2296af69d88dSmrg      }
2297af69d88dSmrg
2298af69d88dSmrg      if (xoffset < -xBorder) {
2299af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(xoffset)");
2300af69d88dSmrg         return;
2301af69d88dSmrg      }
2302af69d88dSmrg
2303af69d88dSmrg      if (xoffset + width > imageWidth + xBorder) {
2304af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
2305af69d88dSmrg                     "glInvalidateSubTexImage(xoffset+width)");
2306af69d88dSmrg         return;
2307af69d88dSmrg      }
2308af69d88dSmrg
2309af69d88dSmrg      if (yoffset < -yBorder) {
2310af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(yoffset)");
2311af69d88dSmrg         return;
2312af69d88dSmrg      }
2313af69d88dSmrg
2314af69d88dSmrg      if (yoffset + height > imageHeight + yBorder) {
2315af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
2316af69d88dSmrg                     "glInvalidateSubTexImage(yoffset+height)");
2317af69d88dSmrg         return;
2318af69d88dSmrg      }
2319af69d88dSmrg
2320af69d88dSmrg      if (zoffset < -zBorder) {
2321af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
2322af69d88dSmrg                     "glInvalidateSubTexImage(zoffset)");
2323af69d88dSmrg         return;
2324af69d88dSmrg      }
2325af69d88dSmrg
2326af69d88dSmrg      if (zoffset + depth  > imageDepth + zBorder) {
2327af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
2328af69d88dSmrg                     "glInvalidateSubTexImage(zoffset+depth)");
2329af69d88dSmrg         return;
2330af69d88dSmrg      }
2331af69d88dSmrg   }
2332af69d88dSmrg
2333af69d88dSmrg   /* We don't actually do anything for this yet.  Just return after
2334af69d88dSmrg    * validating the parameters and generating the required errors.
2335af69d88dSmrg    */
2336af69d88dSmrg   return;
2337af69d88dSmrg}
2338af69d88dSmrg
233901e04c3fSmrg
234001e04c3fSmrgvoid GLAPIENTRY
234101e04c3fSmrg_mesa_InvalidateTexImage_no_error(GLuint texture, GLint level)
234201e04c3fSmrg{
234301e04c3fSmrg   /* no-op */
234401e04c3fSmrg}
234501e04c3fSmrg
234601e04c3fSmrg
2347af69d88dSmrgvoid GLAPIENTRY
2348af69d88dSmrg_mesa_InvalidateTexImage(GLuint texture, GLint level)
2349af69d88dSmrg{
2350af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
2351af69d88dSmrg
2352af69d88dSmrg   if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
2353af69d88dSmrg      _mesa_debug(ctx, "glInvalidateTexImage(%d, %d)\n", texture, level);
2354af69d88dSmrg
2355af69d88dSmrg   invalidate_tex_image_error_check(ctx, texture, level,
2356af69d88dSmrg                                    "glInvalidateTexImage");
2357af69d88dSmrg
2358af69d88dSmrg   /* We don't actually do anything for this yet.  Just return after
2359af69d88dSmrg    * validating the parameters and generating the required errors.
2360af69d88dSmrg    */
2361af69d88dSmrg   return;
23627117f1b4Smrg}
23637117f1b4Smrg
23647117f1b4Smrg/*@}*/
2365