teximage.c revision 7117f1b4
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg * Version:  7.0.3
47117f1b4Smrg *
57117f1b4Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
217117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
227117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
267117f1b4Smrg/**
277117f1b4Smrg * \file teximage.c
287117f1b4Smrg * Texture image-related functions.
297117f1b4Smrg */
307117f1b4Smrg
317117f1b4Smrg
327117f1b4Smrg#include "glheader.h"
337117f1b4Smrg#include "bufferobj.h"
347117f1b4Smrg#include "context.h"
357117f1b4Smrg#include "convolve.h"
367117f1b4Smrg#include "fbobject.h"
377117f1b4Smrg#include "framebuffer.h"
387117f1b4Smrg#include "image.h"
397117f1b4Smrg#include "imports.h"
407117f1b4Smrg#include "macros.h"
417117f1b4Smrg#include "state.h"
427117f1b4Smrg#include "texcompress.h"
437117f1b4Smrg#include "texformat.h"
447117f1b4Smrg#include "teximage.h"
457117f1b4Smrg#include "texstate.h"
467117f1b4Smrg#include "texstore.h"
477117f1b4Smrg#include "mtypes.h"
487117f1b4Smrg
497117f1b4Smrg
507117f1b4Smrg/**
517117f1b4Smrg * We allocate texture memory on 512-byte boundaries so we can use MMX/SSE
527117f1b4Smrg * elsewhere.
537117f1b4Smrg */
547117f1b4Smrgvoid *
557117f1b4Smrg_mesa_alloc_texmemory(GLsizei bytes)
567117f1b4Smrg{
577117f1b4Smrg   return _mesa_align_malloc(bytes, 512);
587117f1b4Smrg}
597117f1b4Smrg
607117f1b4Smrg
617117f1b4Smrg/**
627117f1b4Smrg * Free texture memory allocated with _mesa_alloc_texmemory()
637117f1b4Smrg */
647117f1b4Smrgvoid
657117f1b4Smrg_mesa_free_texmemory(void *m)
667117f1b4Smrg{
677117f1b4Smrg   _mesa_align_free(m);
687117f1b4Smrg}
697117f1b4Smrg
707117f1b4Smrg
717117f1b4Smrg
727117f1b4Smrg
737117f1b4Smrg#if 0
747117f1b4Smrgstatic void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img)
757117f1b4Smrg{
767117f1b4Smrg#if CHAN_TYPE != GL_UNSIGNED_BYTE
777117f1b4Smrg   _mesa_problem(NULL, "PrintTexture not supported");
787117f1b4Smrg#else
797117f1b4Smrg   GLuint i, j, c;
807117f1b4Smrg   const GLubyte *data = (const GLubyte *) img->Data;
817117f1b4Smrg
827117f1b4Smrg   if (!data) {
837117f1b4Smrg      _mesa_printf("No texture data\n");
847117f1b4Smrg      return;
857117f1b4Smrg   }
867117f1b4Smrg
877117f1b4Smrg   switch (img->Format) {
887117f1b4Smrg      case GL_ALPHA:
897117f1b4Smrg      case GL_LUMINANCE:
907117f1b4Smrg      case GL_INTENSITY:
917117f1b4Smrg      case GL_COLOR_INDEX:
927117f1b4Smrg         c = 1;
937117f1b4Smrg         break;
947117f1b4Smrg      case GL_LUMINANCE_ALPHA:
957117f1b4Smrg         c = 2;
967117f1b4Smrg         break;
977117f1b4Smrg      case GL_RGB:
987117f1b4Smrg         c = 3;
997117f1b4Smrg         break;
1007117f1b4Smrg      case GL_RGBA:
1017117f1b4Smrg         c = 4;
1027117f1b4Smrg         break;
1037117f1b4Smrg      default:
1047117f1b4Smrg         _mesa_problem(NULL, "error in PrintTexture\n");
1057117f1b4Smrg         return;
1067117f1b4Smrg   }
1077117f1b4Smrg
1087117f1b4Smrg   for (i = 0; i < img->Height; i++) {
1097117f1b4Smrg      for (j = 0; j < img->Width; j++) {
1107117f1b4Smrg         if (c==1)
1117117f1b4Smrg            _mesa_printf("%02x  ", data[0]);
1127117f1b4Smrg         else if (c==2)
1137117f1b4Smrg            _mesa_printf("%02x%02x  ", data[0], data[1]);
1147117f1b4Smrg         else if (c==3)
1157117f1b4Smrg            _mesa_printf("%02x%02x%02x  ", data[0], data[1], data[2]);
1167117f1b4Smrg         else if (c==4)
1177117f1b4Smrg            _mesa_printf("%02x%02x%02x%02x  ", data[0], data[1], data[2], data[3]);
1187117f1b4Smrg         data += (img->RowStride - img->Width) * c;
1197117f1b4Smrg      }
1207117f1b4Smrg      /* XXX use img->ImageStride here */
1217117f1b4Smrg      _mesa_printf("\n");
1227117f1b4Smrg   }
1237117f1b4Smrg#endif
1247117f1b4Smrg}
1257117f1b4Smrg#endif
1267117f1b4Smrg
1277117f1b4Smrg
1287117f1b4Smrg/*
1297117f1b4Smrg * Compute floor(log_base_2(n)).
1307117f1b4Smrg * If n < 0 return -1.
1317117f1b4Smrg */
1327117f1b4Smrgstatic int
1337117f1b4Smrglogbase2( int n )
1347117f1b4Smrg{
1357117f1b4Smrg   GLint i = 1;
1367117f1b4Smrg   GLint log2 = 0;
1377117f1b4Smrg
1387117f1b4Smrg   if (n < 0)
1397117f1b4Smrg      return -1;
1407117f1b4Smrg
1417117f1b4Smrg   if (n == 0)
1427117f1b4Smrg      return 0;
1437117f1b4Smrg
1447117f1b4Smrg   while ( n > i ) {
1457117f1b4Smrg      i *= 2;
1467117f1b4Smrg      log2++;
1477117f1b4Smrg   }
1487117f1b4Smrg   if (i != n) {
1497117f1b4Smrg      return log2 - 1;
1507117f1b4Smrg   }
1517117f1b4Smrg   else {
1527117f1b4Smrg      return log2;
1537117f1b4Smrg   }
1547117f1b4Smrg}
1557117f1b4Smrg
1567117f1b4Smrg
1577117f1b4Smrg
1587117f1b4Smrg/**
1597117f1b4Smrg * Return the simple base format for a given internal texture format.
1607117f1b4Smrg * For example, given GL_LUMINANCE12_ALPHA4, return GL_LUMINANCE_ALPHA.
1617117f1b4Smrg *
1627117f1b4Smrg * \param ctx GL context.
1637117f1b4Smrg * \param internalFormat the internal texture format token or 1, 2, 3, or 4.
1647117f1b4Smrg *
1657117f1b4Smrg * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE,
1667117f1b4Smrg * GL_LUMANCE_ALPHA, GL_INTENSITY, GL_RGB, or GL_RGBA), or -1 if invalid enum.
1677117f1b4Smrg *
1687117f1b4Smrg * This is the format which is used during texture application (i.e. the
1697117f1b4Smrg * texture format and env mode determine the arithmetic used.
1707117f1b4Smrg */
1717117f1b4SmrgGLint
1727117f1b4Smrg_mesa_base_tex_format( GLcontext *ctx, GLint internalFormat )
1737117f1b4Smrg{
1747117f1b4Smrg   switch (internalFormat) {
1757117f1b4Smrg      case GL_ALPHA:
1767117f1b4Smrg      case GL_ALPHA4:
1777117f1b4Smrg      case GL_ALPHA8:
1787117f1b4Smrg      case GL_ALPHA12:
1797117f1b4Smrg      case GL_ALPHA16:
1807117f1b4Smrg         return GL_ALPHA;
1817117f1b4Smrg      case 1:
1827117f1b4Smrg      case GL_LUMINANCE:
1837117f1b4Smrg      case GL_LUMINANCE4:
1847117f1b4Smrg      case GL_LUMINANCE8:
1857117f1b4Smrg      case GL_LUMINANCE12:
1867117f1b4Smrg      case GL_LUMINANCE16:
1877117f1b4Smrg         return GL_LUMINANCE;
1887117f1b4Smrg      case 2:
1897117f1b4Smrg      case GL_LUMINANCE_ALPHA:
1907117f1b4Smrg      case GL_LUMINANCE4_ALPHA4:
1917117f1b4Smrg      case GL_LUMINANCE6_ALPHA2:
1927117f1b4Smrg      case GL_LUMINANCE8_ALPHA8:
1937117f1b4Smrg      case GL_LUMINANCE12_ALPHA4:
1947117f1b4Smrg      case GL_LUMINANCE12_ALPHA12:
1957117f1b4Smrg      case GL_LUMINANCE16_ALPHA16:
1967117f1b4Smrg         return GL_LUMINANCE_ALPHA;
1977117f1b4Smrg      case GL_INTENSITY:
1987117f1b4Smrg      case GL_INTENSITY4:
1997117f1b4Smrg      case GL_INTENSITY8:
2007117f1b4Smrg      case GL_INTENSITY12:
2017117f1b4Smrg      case GL_INTENSITY16:
2027117f1b4Smrg         return GL_INTENSITY;
2037117f1b4Smrg      case 3:
2047117f1b4Smrg      case GL_RGB:
2057117f1b4Smrg      case GL_R3_G3_B2:
2067117f1b4Smrg      case GL_RGB4:
2077117f1b4Smrg      case GL_RGB5:
2087117f1b4Smrg      case GL_RGB8:
2097117f1b4Smrg      case GL_RGB10:
2107117f1b4Smrg      case GL_RGB12:
2117117f1b4Smrg      case GL_RGB16:
2127117f1b4Smrg         return GL_RGB;
2137117f1b4Smrg      case 4:
2147117f1b4Smrg      case GL_RGBA:
2157117f1b4Smrg      case GL_RGBA2:
2167117f1b4Smrg      case GL_RGBA4:
2177117f1b4Smrg      case GL_RGB5_A1:
2187117f1b4Smrg      case GL_RGBA8:
2197117f1b4Smrg      case GL_RGB10_A2:
2207117f1b4Smrg      case GL_RGBA12:
2217117f1b4Smrg      case GL_RGBA16:
2227117f1b4Smrg         return GL_RGBA;
2237117f1b4Smrg      default:
2247117f1b4Smrg         ; /* fallthrough */
2257117f1b4Smrg   }
2267117f1b4Smrg
2277117f1b4Smrg   if (ctx->Extensions.EXT_paletted_texture) {
2287117f1b4Smrg      switch (internalFormat) {
2297117f1b4Smrg         case GL_COLOR_INDEX:
2307117f1b4Smrg         case GL_COLOR_INDEX1_EXT:
2317117f1b4Smrg         case GL_COLOR_INDEX2_EXT:
2327117f1b4Smrg         case GL_COLOR_INDEX4_EXT:
2337117f1b4Smrg         case GL_COLOR_INDEX8_EXT:
2347117f1b4Smrg         case GL_COLOR_INDEX12_EXT:
2357117f1b4Smrg         case GL_COLOR_INDEX16_EXT:
2367117f1b4Smrg            return GL_COLOR_INDEX;
2377117f1b4Smrg         default:
2387117f1b4Smrg            ; /* fallthrough */
2397117f1b4Smrg      }
2407117f1b4Smrg   }
2417117f1b4Smrg
2427117f1b4Smrg   if (ctx->Extensions.SGIX_depth_texture ||
2437117f1b4Smrg       ctx->Extensions.ARB_depth_texture) {
2447117f1b4Smrg      switch (internalFormat) {
2457117f1b4Smrg         case GL_DEPTH_COMPONENT:
2467117f1b4Smrg         case GL_DEPTH_COMPONENT16_SGIX:
2477117f1b4Smrg         case GL_DEPTH_COMPONENT24_SGIX:
2487117f1b4Smrg         case GL_DEPTH_COMPONENT32_SGIX:
2497117f1b4Smrg            return GL_DEPTH_COMPONENT;
2507117f1b4Smrg         default:
2517117f1b4Smrg            ; /* fallthrough */
2527117f1b4Smrg      }
2537117f1b4Smrg   }
2547117f1b4Smrg
2557117f1b4Smrg   if (ctx->Extensions.ARB_texture_compression) {
2567117f1b4Smrg      switch (internalFormat) {
2577117f1b4Smrg         case GL_COMPRESSED_ALPHA:
2587117f1b4Smrg            return GL_ALPHA;
2597117f1b4Smrg         case GL_COMPRESSED_LUMINANCE:
2607117f1b4Smrg            return GL_LUMINANCE;
2617117f1b4Smrg         case GL_COMPRESSED_LUMINANCE_ALPHA:
2627117f1b4Smrg            return GL_LUMINANCE_ALPHA;
2637117f1b4Smrg         case GL_COMPRESSED_INTENSITY:
2647117f1b4Smrg            return GL_INTENSITY;
2657117f1b4Smrg         case GL_COMPRESSED_RGB:
2667117f1b4Smrg            return GL_RGB;
2677117f1b4Smrg         case GL_COMPRESSED_RGBA:
2687117f1b4Smrg            return GL_RGBA;
2697117f1b4Smrg         default:
2707117f1b4Smrg            ; /* fallthrough */
2717117f1b4Smrg      }
2727117f1b4Smrg   }
2737117f1b4Smrg
2747117f1b4Smrg   if (ctx->Extensions.TDFX_texture_compression_FXT1) {
2757117f1b4Smrg      switch (internalFormat) {
2767117f1b4Smrg         case GL_COMPRESSED_RGB_FXT1_3DFX:
2777117f1b4Smrg            return GL_RGB;
2787117f1b4Smrg         case GL_COMPRESSED_RGBA_FXT1_3DFX:
2797117f1b4Smrg            return GL_RGBA;
2807117f1b4Smrg         default:
2817117f1b4Smrg            ; /* fallthrough */
2827117f1b4Smrg      }
2837117f1b4Smrg   }
2847117f1b4Smrg
2857117f1b4Smrg   if (ctx->Extensions.EXT_texture_compression_s3tc) {
2867117f1b4Smrg      switch (internalFormat) {
2877117f1b4Smrg         case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
2887117f1b4Smrg            return GL_RGB;
2897117f1b4Smrg         case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
2907117f1b4Smrg         case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
2917117f1b4Smrg         case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
2927117f1b4Smrg            return GL_RGBA;
2937117f1b4Smrg         default:
2947117f1b4Smrg            ; /* fallthrough */
2957117f1b4Smrg      }
2967117f1b4Smrg   }
2977117f1b4Smrg
2987117f1b4Smrg   if (ctx->Extensions.S3_s3tc) {
2997117f1b4Smrg      switch (internalFormat) {
3007117f1b4Smrg         case GL_RGB_S3TC:
3017117f1b4Smrg         case GL_RGB4_S3TC:
3027117f1b4Smrg            return GL_RGB;
3037117f1b4Smrg         case GL_RGBA_S3TC:
3047117f1b4Smrg         case GL_RGBA4_S3TC:
3057117f1b4Smrg            return GL_RGBA;
3067117f1b4Smrg         default:
3077117f1b4Smrg            ; /* fallthrough */
3087117f1b4Smrg      }
3097117f1b4Smrg   }
3107117f1b4Smrg
3117117f1b4Smrg   if (ctx->Extensions.MESA_ycbcr_texture) {
3127117f1b4Smrg      if (internalFormat == GL_YCBCR_MESA)
3137117f1b4Smrg         return GL_YCBCR_MESA;
3147117f1b4Smrg   }
3157117f1b4Smrg
3167117f1b4Smrg   if (ctx->Extensions.ARB_texture_float) {
3177117f1b4Smrg      switch (internalFormat) {
3187117f1b4Smrg         case GL_ALPHA16F_ARB:
3197117f1b4Smrg         case GL_ALPHA32F_ARB:
3207117f1b4Smrg            return GL_ALPHA;
3217117f1b4Smrg         case GL_RGBA16F_ARB:
3227117f1b4Smrg         case GL_RGBA32F_ARB:
3237117f1b4Smrg            return GL_RGBA;
3247117f1b4Smrg         case GL_RGB16F_ARB:
3257117f1b4Smrg         case GL_RGB32F_ARB:
3267117f1b4Smrg            return GL_RGB;
3277117f1b4Smrg         case GL_INTENSITY16F_ARB:
3287117f1b4Smrg         case GL_INTENSITY32F_ARB:
3297117f1b4Smrg            return GL_INTENSITY;
3307117f1b4Smrg         case GL_LUMINANCE16F_ARB:
3317117f1b4Smrg         case GL_LUMINANCE32F_ARB:
3327117f1b4Smrg            return GL_LUMINANCE;
3337117f1b4Smrg         case GL_LUMINANCE_ALPHA16F_ARB:
3347117f1b4Smrg         case GL_LUMINANCE_ALPHA32F_ARB:
3357117f1b4Smrg            return GL_LUMINANCE_ALPHA;
3367117f1b4Smrg         default:
3377117f1b4Smrg            ; /* fallthrough */
3387117f1b4Smrg      }
3397117f1b4Smrg   }
3407117f1b4Smrg
3417117f1b4Smrg   if (ctx->Extensions.EXT_packed_depth_stencil) {
3427117f1b4Smrg      switch (internalFormat) {
3437117f1b4Smrg         case GL_DEPTH_STENCIL_EXT:
3447117f1b4Smrg         case GL_DEPTH24_STENCIL8_EXT:
3457117f1b4Smrg            return GL_DEPTH_STENCIL_EXT;
3467117f1b4Smrg         default:
3477117f1b4Smrg            ; /* fallthrough */
3487117f1b4Smrg      }
3497117f1b4Smrg   }
3507117f1b4Smrg
3517117f1b4Smrg#if FEATURE_EXT_texture_sRGB
3527117f1b4Smrg   if (ctx->Extensions.EXT_texture_sRGB) {
3537117f1b4Smrg      switch (internalFormat) {
3547117f1b4Smrg      case GL_SRGB_EXT:
3557117f1b4Smrg      case GL_SRGB8_EXT:
3567117f1b4Smrg      case GL_COMPRESSED_SRGB_EXT:
3577117f1b4Smrg      case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
3587117f1b4Smrg         return GL_RGB;
3597117f1b4Smrg      case GL_SRGB_ALPHA_EXT:
3607117f1b4Smrg      case GL_SRGB8_ALPHA8_EXT:
3617117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_EXT:
3627117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
3637117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
3647117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
3657117f1b4Smrg         return GL_RGBA;
3667117f1b4Smrg      case GL_SLUMINANCE_ALPHA_EXT:
3677117f1b4Smrg      case GL_SLUMINANCE8_ALPHA8_EXT:
3687117f1b4Smrg      case GL_COMPRESSED_SLUMINANCE_EXT:
3697117f1b4Smrg      case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
3707117f1b4Smrg         return GL_LUMINANCE_ALPHA;
3717117f1b4Smrg      case GL_SLUMINANCE_EXT:
3727117f1b4Smrg      case GL_SLUMINANCE8_EXT:
3737117f1b4Smrg         return GL_LUMINANCE;
3747117f1b4Smrg      default:
3757117f1b4Smrg            ; /* fallthrough */
3767117f1b4Smrg      }
3777117f1b4Smrg   }
3787117f1b4Smrg
3797117f1b4Smrg#endif /* FEATURE_EXT_texture_sRGB */
3807117f1b4Smrg
3817117f1b4Smrg   return -1; /* error */
3827117f1b4Smrg}
3837117f1b4Smrg
3847117f1b4Smrg
3857117f1b4Smrg/**
3867117f1b4Smrg * Test if the given image format is a color/RGBA format (i.e., not color
3877117f1b4Smrg * index, depth, stencil, etc).
3887117f1b4Smrg * \param format  the image format value (may by an internal texture format)
3897117f1b4Smrg * \return GL_TRUE if its a color/RGBA format, GL_FALSE otherwise.
3907117f1b4Smrg */
3917117f1b4Smrgstatic GLboolean
3927117f1b4Smrgis_color_format(GLenum format)
3937117f1b4Smrg{
3947117f1b4Smrg   switch (format) {
3957117f1b4Smrg      case GL_RED:
3967117f1b4Smrg      case GL_GREEN:
3977117f1b4Smrg      case GL_BLUE:
3987117f1b4Smrg      case GL_ALPHA:
3997117f1b4Smrg      case GL_ALPHA4:
4007117f1b4Smrg      case GL_ALPHA8:
4017117f1b4Smrg      case GL_ALPHA12:
4027117f1b4Smrg      case GL_ALPHA16:
4037117f1b4Smrg      case 1:
4047117f1b4Smrg      case GL_LUMINANCE:
4057117f1b4Smrg      case GL_LUMINANCE4:
4067117f1b4Smrg      case GL_LUMINANCE8:
4077117f1b4Smrg      case GL_LUMINANCE12:
4087117f1b4Smrg      case GL_LUMINANCE16:
4097117f1b4Smrg      case 2:
4107117f1b4Smrg      case GL_LUMINANCE_ALPHA:
4117117f1b4Smrg      case GL_LUMINANCE4_ALPHA4:
4127117f1b4Smrg      case GL_LUMINANCE6_ALPHA2:
4137117f1b4Smrg      case GL_LUMINANCE8_ALPHA8:
4147117f1b4Smrg      case GL_LUMINANCE12_ALPHA4:
4157117f1b4Smrg      case GL_LUMINANCE12_ALPHA12:
4167117f1b4Smrg      case GL_LUMINANCE16_ALPHA16:
4177117f1b4Smrg      case GL_INTENSITY:
4187117f1b4Smrg      case GL_INTENSITY4:
4197117f1b4Smrg      case GL_INTENSITY8:
4207117f1b4Smrg      case GL_INTENSITY12:
4217117f1b4Smrg      case GL_INTENSITY16:
4227117f1b4Smrg      case 3:
4237117f1b4Smrg      case GL_RGB:
4247117f1b4Smrg      case GL_BGR:
4257117f1b4Smrg      case GL_R3_G3_B2:
4267117f1b4Smrg      case GL_RGB4:
4277117f1b4Smrg      case GL_RGB5:
4287117f1b4Smrg      case GL_RGB8:
4297117f1b4Smrg      case GL_RGB10:
4307117f1b4Smrg      case GL_RGB12:
4317117f1b4Smrg      case GL_RGB16:
4327117f1b4Smrg      case 4:
4337117f1b4Smrg      case GL_ABGR_EXT:
4347117f1b4Smrg      case GL_RGBA:
4357117f1b4Smrg      case GL_BGRA:
4367117f1b4Smrg      case GL_RGBA2:
4377117f1b4Smrg      case GL_RGBA4:
4387117f1b4Smrg      case GL_RGB5_A1:
4397117f1b4Smrg      case GL_RGBA8:
4407117f1b4Smrg      case GL_RGB10_A2:
4417117f1b4Smrg      case GL_RGBA12:
4427117f1b4Smrg      case GL_RGBA16:
4437117f1b4Smrg      /* float texture formats */
4447117f1b4Smrg      case GL_ALPHA16F_ARB:
4457117f1b4Smrg      case GL_ALPHA32F_ARB:
4467117f1b4Smrg      case GL_LUMINANCE16F_ARB:
4477117f1b4Smrg      case GL_LUMINANCE32F_ARB:
4487117f1b4Smrg      case GL_LUMINANCE_ALPHA16F_ARB:
4497117f1b4Smrg      case GL_LUMINANCE_ALPHA32F_ARB:
4507117f1b4Smrg      case GL_INTENSITY16F_ARB:
4517117f1b4Smrg      case GL_INTENSITY32F_ARB:
4527117f1b4Smrg      case GL_RGB16F_ARB:
4537117f1b4Smrg      case GL_RGB32F_ARB:
4547117f1b4Smrg      case GL_RGBA16F_ARB:
4557117f1b4Smrg      case GL_RGBA32F_ARB:
4567117f1b4Smrg      /* compressed formats */
4577117f1b4Smrg      case GL_COMPRESSED_ALPHA:
4587117f1b4Smrg      case GL_COMPRESSED_LUMINANCE:
4597117f1b4Smrg      case GL_COMPRESSED_LUMINANCE_ALPHA:
4607117f1b4Smrg      case GL_COMPRESSED_INTENSITY:
4617117f1b4Smrg      case GL_COMPRESSED_RGB:
4627117f1b4Smrg      case GL_COMPRESSED_RGBA:
4637117f1b4Smrg      case GL_RGB_S3TC:
4647117f1b4Smrg      case GL_RGB4_S3TC:
4657117f1b4Smrg      case GL_RGBA_S3TC:
4667117f1b4Smrg      case GL_RGBA4_S3TC:
4677117f1b4Smrg      case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
4687117f1b4Smrg      case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
4697117f1b4Smrg      case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
4707117f1b4Smrg      case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
4717117f1b4Smrg      case GL_COMPRESSED_RGB_FXT1_3DFX:
4727117f1b4Smrg      case GL_COMPRESSED_RGBA_FXT1_3DFX:
4737117f1b4Smrg#if FEATURE_EXT_texture_sRGB
4747117f1b4Smrg      case GL_SRGB_EXT:
4757117f1b4Smrg      case GL_SRGB8_EXT:
4767117f1b4Smrg      case GL_SRGB_ALPHA_EXT:
4777117f1b4Smrg      case GL_SRGB8_ALPHA8_EXT:
4787117f1b4Smrg      case GL_SLUMINANCE_ALPHA_EXT:
4797117f1b4Smrg      case GL_SLUMINANCE8_ALPHA8_EXT:
4807117f1b4Smrg      case GL_SLUMINANCE_EXT:
4817117f1b4Smrg      case GL_SLUMINANCE8_EXT:
4827117f1b4Smrg      case GL_COMPRESSED_SRGB_EXT:
4837117f1b4Smrg      case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
4847117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_EXT:
4857117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
4867117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
4877117f1b4Smrg      case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
4887117f1b4Smrg      case GL_COMPRESSED_SLUMINANCE_EXT:
4897117f1b4Smrg      case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
4907117f1b4Smrg#endif /* FEATURE_EXT_texture_sRGB */
4917117f1b4Smrg         return GL_TRUE;
4927117f1b4Smrg      case GL_YCBCR_MESA:  /* not considered to be RGB */
4937117f1b4Smrg      default:
4947117f1b4Smrg         return GL_FALSE;
4957117f1b4Smrg   }
4967117f1b4Smrg}
4977117f1b4Smrg
4987117f1b4Smrg
4997117f1b4Smrg/**
5007117f1b4Smrg * Test if the given image format is a color index format.
5017117f1b4Smrg */
5027117f1b4Smrgstatic GLboolean
5037117f1b4Smrgis_index_format(GLenum format)
5047117f1b4Smrg{
5057117f1b4Smrg   switch (format) {
5067117f1b4Smrg      case GL_COLOR_INDEX:
5077117f1b4Smrg      case GL_COLOR_INDEX1_EXT:
5087117f1b4Smrg      case GL_COLOR_INDEX2_EXT:
5097117f1b4Smrg      case GL_COLOR_INDEX4_EXT:
5107117f1b4Smrg      case GL_COLOR_INDEX8_EXT:
5117117f1b4Smrg      case GL_COLOR_INDEX12_EXT:
5127117f1b4Smrg      case GL_COLOR_INDEX16_EXT:
5137117f1b4Smrg         return GL_TRUE;
5147117f1b4Smrg      default:
5157117f1b4Smrg         return GL_FALSE;
5167117f1b4Smrg   }
5177117f1b4Smrg}
5187117f1b4Smrg
5197117f1b4Smrg
5207117f1b4Smrg/**
5217117f1b4Smrg * Test if the given image format is a depth component format.
5227117f1b4Smrg */
5237117f1b4Smrgstatic GLboolean
5247117f1b4Smrgis_depth_format(GLenum format)
5257117f1b4Smrg{
5267117f1b4Smrg   switch (format) {
5277117f1b4Smrg      case GL_DEPTH_COMPONENT16_ARB:
5287117f1b4Smrg      case GL_DEPTH_COMPONENT24_ARB:
5297117f1b4Smrg      case GL_DEPTH_COMPONENT32_ARB:
5307117f1b4Smrg      case GL_DEPTH_COMPONENT:
5317117f1b4Smrg         return GL_TRUE;
5327117f1b4Smrg      default:
5337117f1b4Smrg         return GL_FALSE;
5347117f1b4Smrg   }
5357117f1b4Smrg}
5367117f1b4Smrg
5377117f1b4Smrg
5387117f1b4Smrg/**
5397117f1b4Smrg * Test if the given image format is a YCbCr format.
5407117f1b4Smrg */
5417117f1b4Smrgstatic GLboolean
5427117f1b4Smrgis_ycbcr_format(GLenum format)
5437117f1b4Smrg{
5447117f1b4Smrg   switch (format) {
5457117f1b4Smrg      case GL_YCBCR_MESA:
5467117f1b4Smrg         return GL_TRUE;
5477117f1b4Smrg      default:
5487117f1b4Smrg         return GL_FALSE;
5497117f1b4Smrg   }
5507117f1b4Smrg}
5517117f1b4Smrg
5527117f1b4Smrg
5537117f1b4Smrg/**
5547117f1b4Smrg * Test if the given image format is a Depth/Stencil format.
5557117f1b4Smrg */
5567117f1b4Smrgstatic GLboolean
5577117f1b4Smrgis_depthstencil_format(GLenum format)
5587117f1b4Smrg{
5597117f1b4Smrg   switch (format) {
5607117f1b4Smrg      case GL_DEPTH24_STENCIL8_EXT:
5617117f1b4Smrg      case GL_DEPTH_STENCIL_EXT:
5627117f1b4Smrg         return GL_TRUE;
5637117f1b4Smrg      default:
5647117f1b4Smrg         return GL_FALSE;
5657117f1b4Smrg   }
5667117f1b4Smrg}
5677117f1b4Smrg
5687117f1b4Smrg
5697117f1b4Smrg
5707117f1b4Smrg/**
5717117f1b4Smrg * Test if it is a supported compressed format.
5727117f1b4Smrg *
5737117f1b4Smrg * \param internalFormat the internal format token provided by the user.
5747117f1b4Smrg *
5757117f1b4Smrg * \ret GL_TRUE if \p internalFormat is a supported compressed format, or
5767117f1b4Smrg * GL_FALSE otherwise.
5777117f1b4Smrg *
5787117f1b4Smrg * Currently only GL_COMPRESSED_RGB_FXT1_3DFX and GL_COMPRESSED_RGBA_FXT1_3DFX
5797117f1b4Smrg * are supported.
5807117f1b4Smrg */
5817117f1b4Smrgstatic GLboolean
5827117f1b4Smrgis_compressed_format(GLcontext *ctx, GLenum internalFormat)
5837117f1b4Smrg{
5847117f1b4Smrg   GLint supported[100]; /* 100 should be plenty */
5857117f1b4Smrg   GLuint i, n;
5867117f1b4Smrg
5877117f1b4Smrg   n = _mesa_get_compressed_formats(ctx, supported, GL_TRUE);
5887117f1b4Smrg   ASSERT(n < 100);
5897117f1b4Smrg   for (i = 0; i < n; i++) {
5907117f1b4Smrg      if ((GLint) internalFormat == supported[i]) {
5917117f1b4Smrg         return GL_TRUE;
5927117f1b4Smrg      }
5937117f1b4Smrg   }
5947117f1b4Smrg   return GL_FALSE;
5957117f1b4Smrg}
5967117f1b4Smrg
5977117f1b4Smrg
5987117f1b4Smrgstatic GLuint
5997117f1b4Smrgtexture_face(GLenum target)
6007117f1b4Smrg{
6017117f1b4Smrg   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
6027117f1b4Smrg       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)
6037117f1b4Smrg      return (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X;
6047117f1b4Smrg   else
6057117f1b4Smrg      return 0;
6067117f1b4Smrg}
6077117f1b4Smrg
6087117f1b4Smrg
6097117f1b4Smrg
6107117f1b4Smrg/**
6117117f1b4Smrg * Store a gl_texture_image pointer in a gl_texture_object structure
6127117f1b4Smrg * according to the target and level parameters.
6137117f1b4Smrg *
6147117f1b4Smrg * \param tObj texture object.
6157117f1b4Smrg * \param target texture target.
6167117f1b4Smrg * \param level image level.
6177117f1b4Smrg * \param texImage texture image.
6187117f1b4Smrg *
6197117f1b4Smrg * This was basically prompted by the introduction of cube maps.
6207117f1b4Smrg */
6217117f1b4Smrgvoid
6227117f1b4Smrg_mesa_set_tex_image(struct gl_texture_object *tObj,
6237117f1b4Smrg                    GLenum target, GLint level,
6247117f1b4Smrg                    struct gl_texture_image *texImage)
6257117f1b4Smrg{
6267117f1b4Smrg   ASSERT(tObj);
6277117f1b4Smrg   ASSERT(texImage);
6287117f1b4Smrg   switch (target) {
6297117f1b4Smrg      case GL_TEXTURE_1D:
6307117f1b4Smrg      case GL_TEXTURE_2D:
6317117f1b4Smrg      case GL_TEXTURE_3D:
6327117f1b4Smrg         tObj->Image[0][level] = texImage;
6337117f1b4Smrg         break;
6347117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
6357117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
6367117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
6377117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
6387117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
6397117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
6407117f1b4Smrg         {
6417117f1b4Smrg            GLuint face = ((GLuint) target -
6427117f1b4Smrg                           (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
6437117f1b4Smrg            tObj->Image[face][level] = texImage;
6447117f1b4Smrg         }
6457117f1b4Smrg         break;
6467117f1b4Smrg      case GL_TEXTURE_RECTANGLE_NV:
6477117f1b4Smrg         ASSERT(level == 0);
6487117f1b4Smrg         tObj->Image[0][level] = texImage;
6497117f1b4Smrg         break;
6507117f1b4Smrg      default:
6517117f1b4Smrg         _mesa_problem(NULL, "bad target in _mesa_set_tex_image()");
6527117f1b4Smrg         return;
6537117f1b4Smrg   }
6547117f1b4Smrg   /* Set the 'back' pointer */
6557117f1b4Smrg   texImage->TexObject = tObj;
6567117f1b4Smrg}
6577117f1b4Smrg
6587117f1b4Smrg
6597117f1b4Smrg/**
6607117f1b4Smrg * Allocate a texture image structure.
6617117f1b4Smrg *
6627117f1b4Smrg * Called via ctx->Driver.NewTextureImage() unless overriden by a device
6637117f1b4Smrg * driver.
6647117f1b4Smrg *
6657117f1b4Smrg * \return a pointer to gl_texture_image struct with all fields initialized to
6667117f1b4Smrg * zero.
6677117f1b4Smrg */
6687117f1b4Smrgstruct gl_texture_image *
6697117f1b4Smrg_mesa_new_texture_image( GLcontext *ctx )
6707117f1b4Smrg{
6717117f1b4Smrg   (void) ctx;
6727117f1b4Smrg   return CALLOC_STRUCT(gl_texture_image);
6737117f1b4Smrg}
6747117f1b4Smrg
6757117f1b4Smrg
6767117f1b4Smrg/**
6777117f1b4Smrg * Free texture image data.
6787117f1b4Smrg * This function is a fallback called via ctx->Driver.FreeTexImageData().
6797117f1b4Smrg *
6807117f1b4Smrg * \param teximage texture image.
6817117f1b4Smrg *
6827117f1b4Smrg * Free the texture image data if it's not marked as client data.
6837117f1b4Smrg */
6847117f1b4Smrgvoid
6857117f1b4Smrg_mesa_free_texture_image_data(GLcontext *ctx,
6867117f1b4Smrg                              struct gl_texture_image *texImage)
6877117f1b4Smrg{
6887117f1b4Smrg   (void) ctx;
6897117f1b4Smrg
6907117f1b4Smrg   if (texImage->Data && !texImage->IsClientData) {
6917117f1b4Smrg      /* free the old texture data */
6927117f1b4Smrg      _mesa_free_texmemory(texImage->Data);
6937117f1b4Smrg   }
6947117f1b4Smrg
6957117f1b4Smrg   texImage->Data = NULL;
6967117f1b4Smrg}
6977117f1b4Smrg
6987117f1b4Smrg
6997117f1b4Smrg/**
7007117f1b4Smrg * Free texture image.
7017117f1b4Smrg *
7027117f1b4Smrg * \param teximage texture image.
7037117f1b4Smrg *
7047117f1b4Smrg * Free the texture image structure and the associated image data.
7057117f1b4Smrg */
7067117f1b4Smrgvoid
7077117f1b4Smrg_mesa_delete_texture_image( GLcontext *ctx, struct gl_texture_image *texImage )
7087117f1b4Smrg{
7097117f1b4Smrg   /* Free texImage->Data and/or any other driver-specific texture
7107117f1b4Smrg    * image storage.
7117117f1b4Smrg    */
7127117f1b4Smrg   ASSERT(ctx->Driver.FreeTexImageData);
7137117f1b4Smrg   ctx->Driver.FreeTexImageData( ctx, texImage );
7147117f1b4Smrg
7157117f1b4Smrg   ASSERT(texImage->Data == NULL);
7167117f1b4Smrg   if (texImage->ImageOffsets)
7177117f1b4Smrg      _mesa_free(texImage->ImageOffsets);
7187117f1b4Smrg   _mesa_free(texImage);
7197117f1b4Smrg}
7207117f1b4Smrg
7217117f1b4Smrg
7227117f1b4Smrg/**
7237117f1b4Smrg * Test if a target is a proxy target.
7247117f1b4Smrg *
7257117f1b4Smrg * \param target texture target.
7267117f1b4Smrg *
7277117f1b4Smrg * \return GL_TRUE if the target is a proxy target, GL_FALSE otherwise.
7287117f1b4Smrg */
7297117f1b4SmrgGLboolean
7307117f1b4Smrg_mesa_is_proxy_texture(GLenum target)
7317117f1b4Smrg{
7327117f1b4Smrg   return (target == GL_PROXY_TEXTURE_1D ||
7337117f1b4Smrg           target == GL_PROXY_TEXTURE_2D ||
7347117f1b4Smrg           target == GL_PROXY_TEXTURE_3D ||
7357117f1b4Smrg           target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
7367117f1b4Smrg           target == GL_PROXY_TEXTURE_RECTANGLE_NV);
7377117f1b4Smrg}
7387117f1b4Smrg
7397117f1b4Smrg
7407117f1b4Smrg/**
7417117f1b4Smrg * Get the texture object that corresponds to the target of the given texture unit.
7427117f1b4Smrg *
7437117f1b4Smrg * \param ctx GL context.
7447117f1b4Smrg * \param texUnit texture unit.
7457117f1b4Smrg * \param target texture target.
7467117f1b4Smrg *
7477117f1b4Smrg * \return pointer to the texture object on success, or NULL on failure.
7487117f1b4Smrg *
7497117f1b4Smrg * \sa gl_texture_unit.
7507117f1b4Smrg */
7517117f1b4Smrgstruct gl_texture_object *
7527117f1b4Smrg_mesa_select_tex_object(GLcontext *ctx, const struct gl_texture_unit *texUnit,
7537117f1b4Smrg                        GLenum target)
7547117f1b4Smrg{
7557117f1b4Smrg   switch (target) {
7567117f1b4Smrg      case GL_TEXTURE_1D:
7577117f1b4Smrg         return texUnit->Current1D;
7587117f1b4Smrg      case GL_PROXY_TEXTURE_1D:
7597117f1b4Smrg         return ctx->Texture.Proxy1D;
7607117f1b4Smrg      case GL_TEXTURE_2D:
7617117f1b4Smrg         return texUnit->Current2D;
7627117f1b4Smrg      case GL_PROXY_TEXTURE_2D:
7637117f1b4Smrg         return ctx->Texture.Proxy2D;
7647117f1b4Smrg      case GL_TEXTURE_3D:
7657117f1b4Smrg         return texUnit->Current3D;
7667117f1b4Smrg      case GL_PROXY_TEXTURE_3D:
7677117f1b4Smrg         return ctx->Texture.Proxy3D;
7687117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
7697117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
7707117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
7717117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
7727117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
7737117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
7747117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_ARB:
7757117f1b4Smrg         return ctx->Extensions.ARB_texture_cube_map
7767117f1b4Smrg                ? texUnit->CurrentCubeMap : NULL;
7777117f1b4Smrg      case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
7787117f1b4Smrg         return ctx->Extensions.ARB_texture_cube_map
7797117f1b4Smrg                ? ctx->Texture.ProxyCubeMap : NULL;
7807117f1b4Smrg      case GL_TEXTURE_RECTANGLE_NV:
7817117f1b4Smrg         return ctx->Extensions.NV_texture_rectangle
7827117f1b4Smrg                ? texUnit->CurrentRect : NULL;
7837117f1b4Smrg      case GL_PROXY_TEXTURE_RECTANGLE_NV:
7847117f1b4Smrg         return ctx->Extensions.NV_texture_rectangle
7857117f1b4Smrg                ? ctx->Texture.ProxyRect : NULL;
7867117f1b4Smrg      default:
7877117f1b4Smrg         _mesa_problem(NULL, "bad target in _mesa_select_tex_object()");
7887117f1b4Smrg         return NULL;
7897117f1b4Smrg   }
7907117f1b4Smrg}
7917117f1b4Smrg
7927117f1b4Smrg
7937117f1b4Smrg/**
7947117f1b4Smrg * Get the texture image struct which corresponds to target and level
7957117f1b4Smrg * of the given texture unit.
7967117f1b4Smrg *
7977117f1b4Smrg * \param ctx GL context.
7987117f1b4Smrg * \param texUnit texture unit.
7997117f1b4Smrg * \param target texture target.
8007117f1b4Smrg * \param level image level.
8017117f1b4Smrg *
8027117f1b4Smrg * \return pointer to the texture image structure on success, or NULL on failure.
8037117f1b4Smrg *
8047117f1b4Smrg * \sa gl_texture_unit.
8057117f1b4Smrg */
8067117f1b4Smrgstruct gl_texture_image *
8077117f1b4Smrg_mesa_select_tex_image(GLcontext *ctx, const struct gl_texture_object *texObj,
8087117f1b4Smrg		       GLenum target, GLint level)
8097117f1b4Smrg{
8107117f1b4Smrg   ASSERT(texObj);
8117117f1b4Smrg
8127117f1b4Smrg   if (level < 0 || level >= MAX_TEXTURE_LEVELS)
8137117f1b4Smrg      return NULL;
8147117f1b4Smrg
8157117f1b4Smrg   switch (target) {
8167117f1b4Smrg      case GL_TEXTURE_1D:
8177117f1b4Smrg      case GL_PROXY_TEXTURE_1D:
8187117f1b4Smrg      case GL_TEXTURE_2D:
8197117f1b4Smrg      case GL_PROXY_TEXTURE_2D:
8207117f1b4Smrg      case GL_TEXTURE_3D:
8217117f1b4Smrg      case GL_PROXY_TEXTURE_3D:
8227117f1b4Smrg         return texObj->Image[0][level];
8237117f1b4Smrg
8247117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
8257117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
8267117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
8277117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
8287117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
8297117f1b4Smrg      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
8307117f1b4Smrg         if (ctx->Extensions.ARB_texture_cube_map) {
8317117f1b4Smrg	    GLuint face = ((GLuint) target -
8327117f1b4Smrg			   (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X);
8337117f1b4Smrg            return texObj->Image[face][level];
8347117f1b4Smrg	 }
8357117f1b4Smrg         else
8367117f1b4Smrg            return NULL;
8377117f1b4Smrg
8387117f1b4Smrg      case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
8397117f1b4Smrg         if (ctx->Extensions.ARB_texture_cube_map)
8407117f1b4Smrg            return texObj->Image[0][level];
8417117f1b4Smrg         else
8427117f1b4Smrg            return NULL;
8437117f1b4Smrg
8447117f1b4Smrg      case GL_TEXTURE_RECTANGLE_NV:
8457117f1b4Smrg      case GL_PROXY_TEXTURE_RECTANGLE_NV:
8467117f1b4Smrg         if (ctx->Extensions.NV_texture_rectangle && level == 0)
8477117f1b4Smrg            return texObj->Image[0][level];
8487117f1b4Smrg         else
8497117f1b4Smrg            return NULL;
8507117f1b4Smrg
8517117f1b4Smrg      default:
8527117f1b4Smrg         return NULL;
8537117f1b4Smrg   }
8547117f1b4Smrg}
8557117f1b4Smrg
8567117f1b4Smrg
8577117f1b4Smrg/**
8587117f1b4Smrg * Like _mesa_select_tex_image() but if the image doesn't exist, allocate
8597117f1b4Smrg * it and install it.  Only return NULL if passed a bad parameter or run
8607117f1b4Smrg * out of memory.
8617117f1b4Smrg */
8627117f1b4Smrgstruct gl_texture_image *
8637117f1b4Smrg_mesa_get_tex_image(GLcontext *ctx, struct gl_texture_object *texObj,
8647117f1b4Smrg                    GLenum target, GLint level)
8657117f1b4Smrg{
8667117f1b4Smrg   struct gl_texture_image *texImage;
8677117f1b4Smrg
8687117f1b4Smrg   if (!texObj)
8697117f1b4Smrg      return NULL;
8707117f1b4Smrg
8717117f1b4Smrg   texImage = _mesa_select_tex_image(ctx, texObj, target, level);
8727117f1b4Smrg   if (!texImage) {
8737117f1b4Smrg      texImage = ctx->Driver.NewTextureImage(ctx);
8747117f1b4Smrg      if (!texImage) {
8757117f1b4Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "texture image allocation");
8767117f1b4Smrg         return NULL;
8777117f1b4Smrg      }
8787117f1b4Smrg
8797117f1b4Smrg      _mesa_set_tex_image(texObj, target, level, texImage);
8807117f1b4Smrg   }
8817117f1b4Smrg
8827117f1b4Smrg   return texImage;
8837117f1b4Smrg}
8847117f1b4Smrg
8857117f1b4Smrg
8867117f1b4Smrg/**
8877117f1b4Smrg * Return pointer to the specified proxy texture image.
8887117f1b4Smrg * Note that proxy textures are per-context, not per-texture unit.
8897117f1b4Smrg * \return pointer to texture image or NULL if invalid target, invalid
8907117f1b4Smrg *         level, or out of memory.
8917117f1b4Smrg */
8927117f1b4Smrgstruct gl_texture_image *
8937117f1b4Smrg_mesa_get_proxy_tex_image(GLcontext *ctx, GLenum target, GLint level)
8947117f1b4Smrg{
8957117f1b4Smrg   struct gl_texture_image *texImage;
8967117f1b4Smrg
8977117f1b4Smrg   if (level < 0 )
8987117f1b4Smrg      return NULL;
8997117f1b4Smrg
9007117f1b4Smrg   switch (target) {
9017117f1b4Smrg   case GL_PROXY_TEXTURE_1D:
9027117f1b4Smrg      if (level >= ctx->Const.MaxTextureLevels)
9037117f1b4Smrg         return NULL;
9047117f1b4Smrg      texImage = ctx->Texture.Proxy1D->Image[0][level];
9057117f1b4Smrg      if (!texImage) {
9067117f1b4Smrg         texImage = ctx->Driver.NewTextureImage(ctx);
9077117f1b4Smrg         if (!texImage) {
9087117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
9097117f1b4Smrg            return NULL;
9107117f1b4Smrg         }
9117117f1b4Smrg         ctx->Texture.Proxy1D->Image[0][level] = texImage;
9127117f1b4Smrg         /* Set the 'back' pointer */
9137117f1b4Smrg         texImage->TexObject = ctx->Texture.Proxy1D;
9147117f1b4Smrg      }
9157117f1b4Smrg      return texImage;
9167117f1b4Smrg   case GL_PROXY_TEXTURE_2D:
9177117f1b4Smrg      if (level >= ctx->Const.MaxTextureLevels)
9187117f1b4Smrg         return NULL;
9197117f1b4Smrg      texImage = ctx->Texture.Proxy2D->Image[0][level];
9207117f1b4Smrg      if (!texImage) {
9217117f1b4Smrg         texImage = ctx->Driver.NewTextureImage(ctx);
9227117f1b4Smrg         if (!texImage) {
9237117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
9247117f1b4Smrg            return NULL;
9257117f1b4Smrg         }
9267117f1b4Smrg         ctx->Texture.Proxy2D->Image[0][level] = texImage;
9277117f1b4Smrg         /* Set the 'back' pointer */
9287117f1b4Smrg         texImage->TexObject = ctx->Texture.Proxy2D;
9297117f1b4Smrg      }
9307117f1b4Smrg      return texImage;
9317117f1b4Smrg   case GL_PROXY_TEXTURE_3D:
9327117f1b4Smrg      if (level >= ctx->Const.Max3DTextureLevels)
9337117f1b4Smrg         return NULL;
9347117f1b4Smrg      texImage = ctx->Texture.Proxy3D->Image[0][level];
9357117f1b4Smrg      if (!texImage) {
9367117f1b4Smrg         texImage = ctx->Driver.NewTextureImage(ctx);
9377117f1b4Smrg         if (!texImage) {
9387117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
9397117f1b4Smrg            return NULL;
9407117f1b4Smrg         }
9417117f1b4Smrg         ctx->Texture.Proxy3D->Image[0][level] = texImage;
9427117f1b4Smrg         /* Set the 'back' pointer */
9437117f1b4Smrg         texImage->TexObject = ctx->Texture.Proxy3D;
9447117f1b4Smrg      }
9457117f1b4Smrg      return texImage;
9467117f1b4Smrg   case GL_PROXY_TEXTURE_CUBE_MAP:
9477117f1b4Smrg      if (level >= ctx->Const.MaxCubeTextureLevels)
9487117f1b4Smrg         return NULL;
9497117f1b4Smrg      texImage = ctx->Texture.ProxyCubeMap->Image[0][level];
9507117f1b4Smrg      if (!texImage) {
9517117f1b4Smrg         texImage = ctx->Driver.NewTextureImage(ctx);
9527117f1b4Smrg         if (!texImage) {
9537117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
9547117f1b4Smrg            return NULL;
9557117f1b4Smrg         }
9567117f1b4Smrg         ctx->Texture.ProxyCubeMap->Image[0][level] = texImage;
9577117f1b4Smrg         /* Set the 'back' pointer */
9587117f1b4Smrg         texImage->TexObject = ctx->Texture.ProxyCubeMap;
9597117f1b4Smrg      }
9607117f1b4Smrg      return texImage;
9617117f1b4Smrg   case GL_PROXY_TEXTURE_RECTANGLE_NV:
9627117f1b4Smrg      if (level > 0)
9637117f1b4Smrg         return NULL;
9647117f1b4Smrg      texImage = ctx->Texture.ProxyRect->Image[0][level];
9657117f1b4Smrg      if (!texImage) {
9667117f1b4Smrg         texImage = ctx->Driver.NewTextureImage(ctx);
9677117f1b4Smrg         if (!texImage) {
9687117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "proxy texture allocation");
9697117f1b4Smrg            return NULL;
9707117f1b4Smrg         }
9717117f1b4Smrg         ctx->Texture.ProxyRect->Image[0][level] = texImage;
9727117f1b4Smrg         /* Set the 'back' pointer */
9737117f1b4Smrg         texImage->TexObject = ctx->Texture.ProxyRect;
9747117f1b4Smrg      }
9757117f1b4Smrg      return texImage;
9767117f1b4Smrg   default:
9777117f1b4Smrg      return NULL;
9787117f1b4Smrg   }
9797117f1b4Smrg}
9807117f1b4Smrg
9817117f1b4Smrg
9827117f1b4Smrg/**
9837117f1b4Smrg * Get the maximum number of allowed mipmap levels.
9847117f1b4Smrg *
9857117f1b4Smrg * \param ctx GL context.
9867117f1b4Smrg * \param target texture target.
9877117f1b4Smrg *
9887117f1b4Smrg * \return the maximum number of allowed mipmap levels for the given
9897117f1b4Smrg * texture target, or zero if passed a bad target.
9907117f1b4Smrg *
9917117f1b4Smrg * \sa gl_constants.
9927117f1b4Smrg */
9937117f1b4SmrgGLint
9947117f1b4Smrg_mesa_max_texture_levels(GLcontext *ctx, GLenum target)
9957117f1b4Smrg{
9967117f1b4Smrg   switch (target) {
9977117f1b4Smrg   case GL_TEXTURE_1D:
9987117f1b4Smrg   case GL_PROXY_TEXTURE_1D:
9997117f1b4Smrg   case GL_TEXTURE_2D:
10007117f1b4Smrg   case GL_PROXY_TEXTURE_2D:
10017117f1b4Smrg      return ctx->Const.MaxTextureLevels;
10027117f1b4Smrg   case GL_TEXTURE_3D:
10037117f1b4Smrg   case GL_PROXY_TEXTURE_3D:
10047117f1b4Smrg      return ctx->Const.Max3DTextureLevels;
10057117f1b4Smrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB:
10067117f1b4Smrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB:
10077117f1b4Smrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB:
10087117f1b4Smrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB:
10097117f1b4Smrg   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB:
10107117f1b4Smrg   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB:
10117117f1b4Smrg   case GL_TEXTURE_CUBE_MAP_ARB:
10127117f1b4Smrg   case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
10137117f1b4Smrg      return ctx->Const.MaxCubeTextureLevels;
10147117f1b4Smrg   case GL_TEXTURE_RECTANGLE_NV:
10157117f1b4Smrg   case GL_PROXY_TEXTURE_RECTANGLE_NV:
10167117f1b4Smrg      return 1;
10177117f1b4Smrg   default:
10187117f1b4Smrg      return 0; /* bad target */
10197117f1b4Smrg   }
10207117f1b4Smrg}
10217117f1b4Smrg
10227117f1b4Smrg
10237117f1b4Smrg
10247117f1b4Smrg#if 000 /* not used anymore */
10257117f1b4Smrg/*
10267117f1b4Smrg * glTexImage[123]D can accept a NULL image pointer.  In this case we
10277117f1b4Smrg * create a texture image with unspecified image contents per the OpenGL
10287117f1b4Smrg * spec.
10297117f1b4Smrg */
10307117f1b4Smrgstatic GLubyte *
10317117f1b4Smrgmake_null_texture(GLint width, GLint height, GLint depth, GLenum format)
10327117f1b4Smrg{
10337117f1b4Smrg   const GLint components = _mesa_components_in_format(format);
10347117f1b4Smrg   const GLint numPixels = width * height * depth;
10357117f1b4Smrg   GLubyte *data = (GLubyte *) MALLOC(numPixels * components * sizeof(GLubyte));
10367117f1b4Smrg
10377117f1b4Smrg#ifdef DEBUG
10387117f1b4Smrg   /*
10397117f1b4Smrg    * Let's see if anyone finds this.  If glTexImage2D() is called with
10407117f1b4Smrg    * a NULL image pointer then load the texture image with something
10417117f1b4Smrg    * interesting instead of leaving it indeterminate.
10427117f1b4Smrg    */
10437117f1b4Smrg   if (data) {
10447117f1b4Smrg      static const char message[8][32] = {
10457117f1b4Smrg         "   X   X  XXXXX   XXX     X    ",
10467117f1b4Smrg         "   XX XX  X      X   X   X X   ",
10477117f1b4Smrg         "   X X X  X      X      X   X  ",
10487117f1b4Smrg         "   X   X  XXXX    XXX   XXXXX  ",
10497117f1b4Smrg         "   X   X  X          X  X   X  ",
10507117f1b4Smrg         "   X   X  X      X   X  X   X  ",
10517117f1b4Smrg         "   X   X  XXXXX   XXX   X   X  ",
10527117f1b4Smrg         "                               "
10537117f1b4Smrg      };
10547117f1b4Smrg
10557117f1b4Smrg      GLubyte *imgPtr = data;
10567117f1b4Smrg      GLint h, i, j, k;
10577117f1b4Smrg      for (h = 0; h < depth; h++) {
10587117f1b4Smrg         for (i = 0; i < height; i++) {
10597117f1b4Smrg            GLint srcRow = 7 - (i % 8);
10607117f1b4Smrg            for (j = 0; j < width; j++) {
10617117f1b4Smrg               GLint srcCol = j % 32;
10627117f1b4Smrg               GLubyte texel = (message[srcRow][srcCol]=='X') ? 255 : 70;
10637117f1b4Smrg               for (k = 0; k < components; k++) {
10647117f1b4Smrg                  *imgPtr++ = texel;
10657117f1b4Smrg               }
10667117f1b4Smrg            }
10677117f1b4Smrg         }
10687117f1b4Smrg      }
10697117f1b4Smrg   }
10707117f1b4Smrg#endif
10717117f1b4Smrg
10727117f1b4Smrg   return data;
10737117f1b4Smrg}
10747117f1b4Smrg#endif
10757117f1b4Smrg
10767117f1b4Smrg
10777117f1b4Smrg
10787117f1b4Smrg/**
10797117f1b4Smrg * Reset the fields of a gl_texture_image struct to zero.
10807117f1b4Smrg *
10817117f1b4Smrg * \param img texture image structure.
10827117f1b4Smrg *
10837117f1b4Smrg * This is called when a proxy texture test fails, we set all the
10847117f1b4Smrg * image members (except DriverData) to zero.
10857117f1b4Smrg * It's also used in glTexImage[123]D as a safeguard to be sure all
10867117f1b4Smrg * required fields get initialized properly by the Driver.TexImage[123]D
10877117f1b4Smrg * functions.
10887117f1b4Smrg */
10897117f1b4Smrgstatic void
10907117f1b4Smrgclear_teximage_fields(struct gl_texture_image *img)
10917117f1b4Smrg{
10927117f1b4Smrg   ASSERT(img);
10937117f1b4Smrg   img->_BaseFormat = 0;
10947117f1b4Smrg   img->InternalFormat = 0;
10957117f1b4Smrg   img->Border = 0;
10967117f1b4Smrg   img->Width = 0;
10977117f1b4Smrg   img->Height = 0;
10987117f1b4Smrg   img->Depth = 0;
10997117f1b4Smrg   img->RowStride = 0;
11007117f1b4Smrg   if (img->ImageOffsets) {
11017117f1b4Smrg      _mesa_free(img->ImageOffsets);
11027117f1b4Smrg      img->ImageOffsets = NULL;
11037117f1b4Smrg   }
11047117f1b4Smrg   img->Width2 = 0;
11057117f1b4Smrg   img->Height2 = 0;
11067117f1b4Smrg   img->Depth2 = 0;
11077117f1b4Smrg   img->WidthLog2 = 0;
11087117f1b4Smrg   img->HeightLog2 = 0;
11097117f1b4Smrg   img->DepthLog2 = 0;
11107117f1b4Smrg   img->Data = NULL;
11117117f1b4Smrg   img->TexFormat = &_mesa_null_texformat;
11127117f1b4Smrg   img->FetchTexelc = NULL;
11137117f1b4Smrg   img->FetchTexelf = NULL;
11147117f1b4Smrg   img->IsCompressed = 0;
11157117f1b4Smrg   img->CompressedSize = 0;
11167117f1b4Smrg}
11177117f1b4Smrg
11187117f1b4Smrg
11197117f1b4Smrg/**
11207117f1b4Smrg * Initialize basic fields of the gl_texture_image struct.
11217117f1b4Smrg *
11227117f1b4Smrg * \param ctx GL context.
11237117f1b4Smrg * \param target texture target (GL_TEXTURE_1D, GL_TEXTURE_RECTANGLE, etc).
11247117f1b4Smrg * \param img texture image structure to be initialized.
11257117f1b4Smrg * \param width image width.
11267117f1b4Smrg * \param height image height.
11277117f1b4Smrg * \param depth image depth.
11287117f1b4Smrg * \param border image border.
11297117f1b4Smrg * \param internalFormat internal format.
11307117f1b4Smrg *
11317117f1b4Smrg * Fills in the fields of \p img with the given information.
11327117f1b4Smrg * Note: width, height and depth include the border.
11337117f1b4Smrg */
11347117f1b4Smrgvoid
11357117f1b4Smrg_mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
11367117f1b4Smrg                           struct gl_texture_image *img,
11377117f1b4Smrg                           GLsizei width, GLsizei height, GLsizei depth,
11387117f1b4Smrg                           GLint border, GLenum internalFormat)
11397117f1b4Smrg{
11407117f1b4Smrg   GLint i;
11417117f1b4Smrg
11427117f1b4Smrg   ASSERT(img);
11437117f1b4Smrg   ASSERT(width >= 0);
11447117f1b4Smrg   ASSERT(height >= 0);
11457117f1b4Smrg   ASSERT(depth >= 0);
11467117f1b4Smrg
11477117f1b4Smrg   img->_BaseFormat = _mesa_base_tex_format( ctx, internalFormat );
11487117f1b4Smrg   ASSERT(img->_BaseFormat > 0);
11497117f1b4Smrg   img->InternalFormat = internalFormat;
11507117f1b4Smrg   img->Border = border;
11517117f1b4Smrg   img->Width = width;
11527117f1b4Smrg   img->Height = height;
11537117f1b4Smrg   img->Depth = depth;
11547117f1b4Smrg   img->Width2 = width - 2 * border;   /* == 1 << img->WidthLog2; */
11557117f1b4Smrg   img->Height2 = height - 2 * border; /* == 1 << img->HeightLog2; */
11567117f1b4Smrg   img->Depth2 = depth - 2 * border;   /* == 1 << img->DepthLog2; */
11577117f1b4Smrg   img->WidthLog2 = logbase2(img->Width2);
11587117f1b4Smrg   if (height == 1)  /* 1-D texture */
11597117f1b4Smrg      img->HeightLog2 = 0;
11607117f1b4Smrg   else
11617117f1b4Smrg      img->HeightLog2 = logbase2(img->Height2);
11627117f1b4Smrg   if (depth == 1)   /* 2-D texture */
11637117f1b4Smrg      img->DepthLog2 = 0;
11647117f1b4Smrg   else
11657117f1b4Smrg      img->DepthLog2 = logbase2(img->Depth2);
11667117f1b4Smrg   img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
11677117f1b4Smrg   img->IsCompressed = GL_FALSE;
11687117f1b4Smrg   img->CompressedSize = 0;
11697117f1b4Smrg
11707117f1b4Smrg   if ((width == 1 || _mesa_bitcount(img->Width2) == 1) &&
11717117f1b4Smrg       (height == 1 || _mesa_bitcount(img->Height2) == 1) &&
11727117f1b4Smrg       (depth == 1 || _mesa_bitcount(img->Depth2) == 1))
11737117f1b4Smrg      img->_IsPowerOfTwo = GL_TRUE;
11747117f1b4Smrg   else
11757117f1b4Smrg      img->_IsPowerOfTwo = GL_FALSE;
11767117f1b4Smrg
11777117f1b4Smrg   /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
11787117f1b4Smrg   img->RowStride = width;
11797117f1b4Smrg   /* Allocate the ImageOffsets array and initialize to typical values.
11807117f1b4Smrg    * We allocate the array for 1D/2D textures too in order to avoid special-
11817117f1b4Smrg    * case code in the texstore routines.
11827117f1b4Smrg    */
11837117f1b4Smrg   img->ImageOffsets = (GLuint *) _mesa_malloc(depth * sizeof(GLuint));
11847117f1b4Smrg   for (i = 0; i < depth; i++) {
11857117f1b4Smrg      img->ImageOffsets[i] = i * width * height;
11867117f1b4Smrg   }
11877117f1b4Smrg
11887117f1b4Smrg   /* Compute Width/Height/DepthScale for mipmap lod computation */
11897117f1b4Smrg   if (target == GL_TEXTURE_RECTANGLE_NV) {
11907117f1b4Smrg      /* scale = 1.0 since texture coords directly map to texels */
11917117f1b4Smrg      img->WidthScale = 1.0;
11927117f1b4Smrg      img->HeightScale = 1.0;
11937117f1b4Smrg      img->DepthScale = 1.0;
11947117f1b4Smrg   }
11957117f1b4Smrg   else {
11967117f1b4Smrg      img->WidthScale = (GLfloat) img->Width;
11977117f1b4Smrg      img->HeightScale = (GLfloat) img->Height;
11987117f1b4Smrg      img->DepthScale = (GLfloat) img->Depth;
11997117f1b4Smrg   }
12007117f1b4Smrg}
12017117f1b4Smrg
12027117f1b4Smrg
12037117f1b4Smrg/**
12047117f1b4Smrg * This is the fallback for Driver.TestProxyTexImage().  Test the texture
12057117f1b4Smrg * level, width, height and depth against the ctx->Const limits for textures.
12067117f1b4Smrg *
12077117f1b4Smrg * A hardware driver might override this function if, for example, the
12087117f1b4Smrg * max 3D texture size is 512x512x64 (i.e. not a cube).
12097117f1b4Smrg *
12107117f1b4Smrg * Note that width, height, depth == 0 is not an error.  However, a
12117117f1b4Smrg * texture with zero width/height/depth will be considered "incomplete"
12127117f1b4Smrg * and texturing will effectively be disabled.
12137117f1b4Smrg *
12147117f1b4Smrg * \param target  one of GL_PROXY_TEXTURE_1D, GL_PROXY_TEXTURE_2D,
12157117f1b4Smrg *                GL_PROXY_TEXTURE_3D, GL_PROXY_TEXTURE_RECTANGLE_NV,
12167117f1b4Smrg *                GL_PROXY_TEXTURE_CUBE_MAP_ARB.
12177117f1b4Smrg * \param level  as passed to glTexImage
12187117f1b4Smrg * \param internalFormat  as passed to glTexImage
12197117f1b4Smrg * \param format  as passed to glTexImage
12207117f1b4Smrg * \param type  as passed to glTexImage
12217117f1b4Smrg * \param width  as passed to glTexImage
12227117f1b4Smrg * \param height  as passed to glTexImage
12237117f1b4Smrg * \param depth  as passed to glTexImage
12247117f1b4Smrg * \param border  as passed to glTexImage
12257117f1b4Smrg * \return GL_TRUE if the image is acceptable, GL_FALSE if not acceptable.
12267117f1b4Smrg */
12277117f1b4SmrgGLboolean
12287117f1b4Smrg_mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
12297117f1b4Smrg                          GLint internalFormat, GLenum format, GLenum type,
12307117f1b4Smrg                          GLint width, GLint height, GLint depth, GLint border)
12317117f1b4Smrg{
12327117f1b4Smrg   GLint maxSize;
12337117f1b4Smrg
12347117f1b4Smrg   (void) internalFormat;
12357117f1b4Smrg   (void) format;
12367117f1b4Smrg   (void) type;
12377117f1b4Smrg
12387117f1b4Smrg   switch (target) {
12397117f1b4Smrg   case GL_PROXY_TEXTURE_1D:
12407117f1b4Smrg      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
12417117f1b4Smrg      if (width < 2 * border || width > 2 + maxSize ||
12427117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12437117f1b4Smrg           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
12447117f1b4Smrg          level >= ctx->Const.MaxTextureLevels) {
12457117f1b4Smrg         /* bad width or level */
12467117f1b4Smrg         return GL_FALSE;
12477117f1b4Smrg      }
12487117f1b4Smrg      return GL_TRUE;
12497117f1b4Smrg   case GL_PROXY_TEXTURE_2D:
12507117f1b4Smrg      maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
12517117f1b4Smrg      if (width < 2 * border || width > 2 + maxSize ||
12527117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12537117f1b4Smrg           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
12547117f1b4Smrg          height < 2 * border || height > 2 + maxSize ||
12557117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12567117f1b4Smrg           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
12577117f1b4Smrg          level >= ctx->Const.MaxTextureLevels) {
12587117f1b4Smrg         /* bad width or height or level */
12597117f1b4Smrg         return GL_FALSE;
12607117f1b4Smrg      }
12617117f1b4Smrg      return GL_TRUE;
12627117f1b4Smrg   case GL_PROXY_TEXTURE_3D:
12637117f1b4Smrg      maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
12647117f1b4Smrg      if (width < 2 * border || width > 2 + maxSize ||
12657117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12667117f1b4Smrg           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
12677117f1b4Smrg          height < 2 * border || height > 2 + maxSize ||
12687117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12697117f1b4Smrg           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
12707117f1b4Smrg          depth < 2 * border || depth > 2 + maxSize ||
12717117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12727117f1b4Smrg           depth > 0 && _mesa_bitcount(depth - 2 * border) != 1) ||
12737117f1b4Smrg          level >= ctx->Const.Max3DTextureLevels) {
12747117f1b4Smrg         /* bad width or height or depth or level */
12757117f1b4Smrg         return GL_FALSE;
12767117f1b4Smrg      }
12777117f1b4Smrg      return GL_TRUE;
12787117f1b4Smrg   case GL_PROXY_TEXTURE_RECTANGLE_NV:
12797117f1b4Smrg      if (width < 0 || width > ctx->Const.MaxTextureRectSize ||
12807117f1b4Smrg          height < 0 || height > ctx->Const.MaxTextureRectSize ||
12817117f1b4Smrg          level != 0) {
12827117f1b4Smrg         /* bad width or height or level */
12837117f1b4Smrg         return GL_FALSE;
12847117f1b4Smrg      }
12857117f1b4Smrg      return GL_TRUE;
12867117f1b4Smrg   case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
12877117f1b4Smrg      maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
12887117f1b4Smrg      if (width < 2 * border || width > 2 + maxSize ||
12897117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12907117f1b4Smrg           width > 0 && _mesa_bitcount(width - 2 * border) != 1) ||
12917117f1b4Smrg          height < 2 * border || height > 2 + maxSize ||
12927117f1b4Smrg          (!ctx->Extensions.ARB_texture_non_power_of_two &&
12937117f1b4Smrg           height > 0 && _mesa_bitcount(height - 2 * border) != 1) ||
12947117f1b4Smrg          level >= ctx->Const.MaxCubeTextureLevels) {
12957117f1b4Smrg         /* bad width or height */
12967117f1b4Smrg         return GL_FALSE;
12977117f1b4Smrg      }
12987117f1b4Smrg      return GL_TRUE;
12997117f1b4Smrg   default:
13007117f1b4Smrg      _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
13017117f1b4Smrg      return GL_FALSE;
13027117f1b4Smrg   }
13037117f1b4Smrg}
13047117f1b4Smrg
13057117f1b4Smrg
13067117f1b4Smrg/**
13077117f1b4Smrg * Helper function to determine whether a target supports compressed textures
13087117f1b4Smrg */
13097117f1b4Smrgstatic GLboolean
13107117f1b4Smrgtarget_can_be_compressed(GLcontext *ctx, GLenum target)
13117117f1b4Smrg{
13127117f1b4Smrg   return (((target == GL_TEXTURE_2D || target == GL_PROXY_TEXTURE_2D))
13137117f1b4Smrg           || ((ctx->Extensions.ARB_texture_cube_map &&
13147117f1b4Smrg                (target == GL_PROXY_TEXTURE_CUBE_MAP ||
13157117f1b4Smrg                 (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
13167117f1b4Smrg                  target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z)))));
13177117f1b4Smrg}
13187117f1b4Smrg
13197117f1b4Smrg
13207117f1b4Smrg/**
13217117f1b4Smrg * Test the glTexImage[123]D() parameters for errors.
13227117f1b4Smrg *
13237117f1b4Smrg * \param ctx GL context.
13247117f1b4Smrg * \param target texture target given by the user.
13257117f1b4Smrg * \param level image level given by the user.
13267117f1b4Smrg * \param internalFormat internal format given by the user.
13277117f1b4Smrg * \param format pixel data format given by the user.
13287117f1b4Smrg * \param type pixel data type given by the user.
13297117f1b4Smrg * \param dimensions texture image dimensions (must be 1, 2 or 3).
13307117f1b4Smrg * \param width image width given by the user.
13317117f1b4Smrg * \param height image height given by the user.
13327117f1b4Smrg * \param depth image depth given by the user.
13337117f1b4Smrg * \param border image border given by the user.
13347117f1b4Smrg *
13357117f1b4Smrg * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
13367117f1b4Smrg *
13377117f1b4Smrg * Verifies each of the parameters against the constants specified in
13387117f1b4Smrg * __GLcontextRec::Const and the supported extensions, and according to the
13397117f1b4Smrg * OpenGL specification.
13407117f1b4Smrg */
13417117f1b4Smrgstatic GLboolean
13427117f1b4Smrgtexture_error_check( GLcontext *ctx, GLenum target,
13437117f1b4Smrg                     GLint level, GLint internalFormat,
13447117f1b4Smrg                     GLenum format, GLenum type,
13457117f1b4Smrg                     GLuint dimensions,
13467117f1b4Smrg                     GLint width, GLint height,
13477117f1b4Smrg                     GLint depth, GLint border )
13487117f1b4Smrg{
13497117f1b4Smrg   const GLboolean isProxy = _mesa_is_proxy_texture(target);
13507117f1b4Smrg   GLboolean sizeOK = GL_TRUE;
13517117f1b4Smrg   GLboolean colorFormat, indexFormat;
13527117f1b4Smrg   GLenum proxy_target;
13537117f1b4Smrg
13547117f1b4Smrg   /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
13557117f1b4Smrg   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
13567117f1b4Smrg      if (!isProxy) {
13577117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
13587117f1b4Smrg                     "glTexImage%dD(level=%d)", dimensions, level);
13597117f1b4Smrg      }
13607117f1b4Smrg      return GL_TRUE;
13617117f1b4Smrg   }
13627117f1b4Smrg
13637117f1b4Smrg   /* Check border */
13647117f1b4Smrg   if (border < 0 || border > 1 ||
13657117f1b4Smrg       ((target == GL_TEXTURE_RECTANGLE_NV ||
13667117f1b4Smrg         target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
13677117f1b4Smrg      if (!isProxy) {
13687117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
13697117f1b4Smrg                     "glTexImage%dD(border=%d)", dimensions, border);
13707117f1b4Smrg      }
13717117f1b4Smrg      return GL_TRUE;
13727117f1b4Smrg   }
13737117f1b4Smrg
13747117f1b4Smrg   if (width < 0 || height < 0 || depth < 0) {
13757117f1b4Smrg      if (!isProxy) {
13767117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
13777117f1b4Smrg                     "glTexImage%dD(width, height or depth < 0)", dimensions);
13787117f1b4Smrg      }
13797117f1b4Smrg      return GL_TRUE;
13807117f1b4Smrg   }
13817117f1b4Smrg
13827117f1b4Smrg   /* Check target and call ctx->Driver.TestProxyTexImage() to check the
13837117f1b4Smrg    * level, width, height and depth.
13847117f1b4Smrg    */
13857117f1b4Smrg   if (dimensions == 1) {
13867117f1b4Smrg      if (target == GL_PROXY_TEXTURE_1D || target == GL_TEXTURE_1D) {
13877117f1b4Smrg         proxy_target = GL_PROXY_TEXTURE_1D;
13887117f1b4Smrg         height = 1;
13897117f1b4Smrg         depth = 1;
13907117f1b4Smrg      }
13917117f1b4Smrg      else {
13927117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
13937117f1b4Smrg         return GL_TRUE;
13947117f1b4Smrg      }
13957117f1b4Smrg   }
13967117f1b4Smrg   else if (dimensions == 2) {
13977117f1b4Smrg      depth = 1;
13987117f1b4Smrg      if (target == GL_PROXY_TEXTURE_2D || target == GL_TEXTURE_2D) {
13997117f1b4Smrg         proxy_target = GL_PROXY_TEXTURE_2D;
14007117f1b4Smrg      }
14017117f1b4Smrg      else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB ||
14027117f1b4Smrg               (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
14037117f1b4Smrg                target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) {
14047117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map) {
14057117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
14067117f1b4Smrg            return GL_TRUE;
14077117f1b4Smrg         }
14087117f1b4Smrg         proxy_target = GL_PROXY_TEXTURE_CUBE_MAP_ARB;
14097117f1b4Smrg         sizeOK = (width == height);
14107117f1b4Smrg      }
14117117f1b4Smrg      else if (target == GL_PROXY_TEXTURE_RECTANGLE_NV ||
14127117f1b4Smrg               target == GL_TEXTURE_RECTANGLE_NV) {
14137117f1b4Smrg         if (!ctx->Extensions.NV_texture_rectangle) {
14147117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
14157117f1b4Smrg            return GL_TRUE;
14167117f1b4Smrg         }
14177117f1b4Smrg         proxy_target = GL_PROXY_TEXTURE_RECTANGLE_NV;
14187117f1b4Smrg      }
14197117f1b4Smrg      else {
14207117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage2D(target)");
14217117f1b4Smrg         return GL_TRUE;
14227117f1b4Smrg      }
14237117f1b4Smrg   }
14247117f1b4Smrg   else if (dimensions == 3) {
14257117f1b4Smrg      if (target == GL_PROXY_TEXTURE_3D || target == GL_TEXTURE_3D) {
14267117f1b4Smrg         proxy_target = GL_PROXY_TEXTURE_3D;
14277117f1b4Smrg      }
14287117f1b4Smrg      else {
14297117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" );
14307117f1b4Smrg         return GL_TRUE;
14317117f1b4Smrg      }
14327117f1b4Smrg   }
14337117f1b4Smrg   else {
14347117f1b4Smrg      _mesa_problem( ctx, "bad dims in texture_error_check" );
14357117f1b4Smrg      return GL_TRUE;
14367117f1b4Smrg   }
14377117f1b4Smrg
14387117f1b4Smrg   sizeOK = sizeOK && ctx->Driver.TestProxyTexImage(ctx, proxy_target, level,
14397117f1b4Smrg                                                    internalFormat, format,
14407117f1b4Smrg                                                    type, width, height,
14417117f1b4Smrg                                                    depth, border);
14427117f1b4Smrg   if (!sizeOK) {
14437117f1b4Smrg      if (!isProxy) {
14447117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
14457117f1b4Smrg                     "glTexImage%dD(level=%d, width=%d, height=%d, depth=%d)",
14467117f1b4Smrg                     dimensions, level, width, height, depth);
14477117f1b4Smrg      }
14487117f1b4Smrg      return GL_TRUE;
14497117f1b4Smrg   }
14507117f1b4Smrg
14517117f1b4Smrg   /* Check internalFormat */
14527117f1b4Smrg   if (_mesa_base_tex_format(ctx, internalFormat) < 0) {
14537117f1b4Smrg      if (!isProxy) {
14547117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
14557117f1b4Smrg                     "glTexImage%dD(internalFormat=0x%x)",
14567117f1b4Smrg                     dimensions, internalFormat);
14577117f1b4Smrg      }
14587117f1b4Smrg      return GL_TRUE;
14597117f1b4Smrg   }
14607117f1b4Smrg
14617117f1b4Smrg   /* Check incoming image format and type */
14627117f1b4Smrg   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
14637117f1b4Smrg      /* Yes, generate GL_INVALID_OPERATION, not GL_INVALID_ENUM, if there
14647117f1b4Smrg       * is a type/format mismatch.  See 1.2 spec page 94, sec 3.6.4.
14657117f1b4Smrg       */
14667117f1b4Smrg      if (!isProxy) {
14677117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
14687117f1b4Smrg                     "glTexImage%dD(format or type)", dimensions);
14697117f1b4Smrg      }
14707117f1b4Smrg      return GL_TRUE;
14717117f1b4Smrg   }
14727117f1b4Smrg
14737117f1b4Smrg   /* make sure internal format and format basically agree */
14747117f1b4Smrg   colorFormat = is_color_format(format);
14757117f1b4Smrg   indexFormat = is_index_format(format);
14767117f1b4Smrg   if ((is_color_format(internalFormat) && !colorFormat && !indexFormat) ||
14777117f1b4Smrg       (is_index_format(internalFormat) && !indexFormat) ||
14787117f1b4Smrg       (is_depth_format(internalFormat) != is_depth_format(format)) ||
14797117f1b4Smrg       (is_ycbcr_format(internalFormat) != is_ycbcr_format(format)) ||
14807117f1b4Smrg       (is_depthstencil_format(internalFormat) != is_depthstencil_format(format))) {
14817117f1b4Smrg      if (!isProxy)
14827117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
14837117f1b4Smrg                     "glTexImage(internalFormat/format)");
14847117f1b4Smrg      return GL_TRUE;
14857117f1b4Smrg   }
14867117f1b4Smrg
14877117f1b4Smrg   /* additional checks for ycbcr textures */
14887117f1b4Smrg   if (internalFormat == GL_YCBCR_MESA) {
14897117f1b4Smrg      ASSERT(ctx->Extensions.MESA_ycbcr_texture);
14907117f1b4Smrg      if (type != GL_UNSIGNED_SHORT_8_8_MESA &&
14917117f1b4Smrg          type != GL_UNSIGNED_SHORT_8_8_REV_MESA) {
14927117f1b4Smrg         char message[100];
14937117f1b4Smrg         _mesa_sprintf(message,
14947117f1b4Smrg                 "glTexImage%d(format/type YCBCR mismatch", dimensions);
14957117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, message);
14967117f1b4Smrg         return GL_TRUE; /* error */
14977117f1b4Smrg      }
14987117f1b4Smrg      if (target != GL_TEXTURE_2D &&
14997117f1b4Smrg          target != GL_PROXY_TEXTURE_2D &&
15007117f1b4Smrg          target != GL_TEXTURE_RECTANGLE_NV &&
15017117f1b4Smrg          target != GL_PROXY_TEXTURE_RECTANGLE_NV) {
15027117f1b4Smrg         if (!isProxy)
15037117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glTexImage(target)");
15047117f1b4Smrg         return GL_TRUE;
15057117f1b4Smrg      }
15067117f1b4Smrg      if (border != 0) {
15077117f1b4Smrg         if (!isProxy) {
15087117f1b4Smrg            char message[100];
15097117f1b4Smrg            _mesa_sprintf(message,
15107117f1b4Smrg                    "glTexImage%d(format=GL_YCBCR_MESA and border=%d)",
15117117f1b4Smrg                    dimensions, border);
15127117f1b4Smrg            _mesa_error(ctx, GL_INVALID_VALUE, message);
15137117f1b4Smrg         }
15147117f1b4Smrg         return GL_TRUE;
15157117f1b4Smrg      }
15167117f1b4Smrg   }
15177117f1b4Smrg
15187117f1b4Smrg   /* additional checks for depth textures */
15197117f1b4Smrg   if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT) {
15207117f1b4Smrg      /* Only 1D, 2D and rectangular textures supported, not 3D or cubes */
15217117f1b4Smrg      if (target != GL_TEXTURE_1D &&
15227117f1b4Smrg          target != GL_PROXY_TEXTURE_1D &&
15237117f1b4Smrg          target != GL_TEXTURE_2D &&
15247117f1b4Smrg          target != GL_PROXY_TEXTURE_2D &&
15257117f1b4Smrg          target != GL_TEXTURE_RECTANGLE_ARB &&
15267117f1b4Smrg          target != GL_PROXY_TEXTURE_RECTANGLE_ARB) {
15277117f1b4Smrg         if (!isProxy)
15287117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM,
15297117f1b4Smrg                        "glTexImage(target/internalFormat)");
15307117f1b4Smrg         return GL_TRUE;
15317117f1b4Smrg      }
15327117f1b4Smrg   }
15337117f1b4Smrg
15347117f1b4Smrg   /* additional checks for compressed textures */
15357117f1b4Smrg   if (is_compressed_format(ctx, internalFormat)) {
15367117f1b4Smrg      if (!target_can_be_compressed(ctx, target) && !isProxy) {
15377117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
15387117f1b4Smrg                     "glTexImage%d(target)", dimensions);
15397117f1b4Smrg         return GL_TRUE;
15407117f1b4Smrg      }
15417117f1b4Smrg      if (border != 0) {
15427117f1b4Smrg         if (!isProxy) {
15437117f1b4Smrg            _mesa_error(ctx, GL_INVALID_OPERATION,
15447117f1b4Smrg                        "glTexImage%D(border!=0)", dimensions);
15457117f1b4Smrg         }
15467117f1b4Smrg         return GL_TRUE;
15477117f1b4Smrg      }
15487117f1b4Smrg   }
15497117f1b4Smrg
15507117f1b4Smrg   /* if we get here, the parameters are OK */
15517117f1b4Smrg   return GL_FALSE;
15527117f1b4Smrg}
15537117f1b4Smrg
15547117f1b4Smrg
15557117f1b4Smrg/**
15567117f1b4Smrg * Test glTexSubImage[123]D() parameters for errors.
15577117f1b4Smrg *
15587117f1b4Smrg * \param ctx GL context.
15597117f1b4Smrg * \param dimensions texture image dimensions (must be 1, 2 or 3).
15607117f1b4Smrg * \param target texture target given by the user.
15617117f1b4Smrg * \param level image level given by the user.
15627117f1b4Smrg * \param xoffset sub-image x offset given by the user.
15637117f1b4Smrg * \param yoffset sub-image y offset given by the user.
15647117f1b4Smrg * \param zoffset sub-image z offset given by the user.
15657117f1b4Smrg * \param format pixel data format given by the user.
15667117f1b4Smrg * \param type pixel data type given by the user.
15677117f1b4Smrg * \param width image width given by the user.
15687117f1b4Smrg * \param height image height given by the user.
15697117f1b4Smrg * \param depth image depth given by the user.
15707117f1b4Smrg *
15717117f1b4Smrg * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
15727117f1b4Smrg *
15737117f1b4Smrg * Verifies each of the parameters against the constants specified in
15747117f1b4Smrg * __GLcontextRec::Const and the supported extensions, and according to the
15757117f1b4Smrg * OpenGL specification.
15767117f1b4Smrg */
15777117f1b4Smrgstatic GLboolean
15787117f1b4Smrgsubtexture_error_check( GLcontext *ctx, GLuint dimensions,
15797117f1b4Smrg                        GLenum target, GLint level,
15807117f1b4Smrg                        GLint xoffset, GLint yoffset, GLint zoffset,
15817117f1b4Smrg                        GLint width, GLint height, GLint depth,
15827117f1b4Smrg                        GLenum format, GLenum type )
15837117f1b4Smrg{
15847117f1b4Smrg   /* Check target */
15857117f1b4Smrg   if (dimensions == 1) {
15867117f1b4Smrg      if (target != GL_TEXTURE_1D) {
15877117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage1D(target)" );
15887117f1b4Smrg         return GL_TRUE;
15897117f1b4Smrg      }
15907117f1b4Smrg   }
15917117f1b4Smrg   else if (dimensions == 2) {
15927117f1b4Smrg      if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
15937117f1b4Smrg          target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
15947117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map) {
15957117f1b4Smrg            _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
15967117f1b4Smrg            return GL_TRUE;
15977117f1b4Smrg         }
15987117f1b4Smrg      }
15997117f1b4Smrg      else if (target == GL_TEXTURE_RECTANGLE_NV) {
16007117f1b4Smrg         if (!ctx->Extensions.NV_texture_rectangle) {
16017117f1b4Smrg            _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
16027117f1b4Smrg            return GL_TRUE;
16037117f1b4Smrg         }
16047117f1b4Smrg      }
16057117f1b4Smrg      else if (target != GL_TEXTURE_2D) {
16067117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage2D(target)" );
16077117f1b4Smrg         return GL_TRUE;
16087117f1b4Smrg      }
16097117f1b4Smrg   }
16107117f1b4Smrg   else if (dimensions == 3) {
16117117f1b4Smrg      if (target != GL_TEXTURE_3D) {
16127117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glTexSubImage3D(target)" );
16137117f1b4Smrg         return GL_TRUE;
16147117f1b4Smrg      }
16157117f1b4Smrg   }
16167117f1b4Smrg   else {
16177117f1b4Smrg      _mesa_problem( ctx, "invalid dims in texture_error_check" );
16187117f1b4Smrg      return GL_TRUE;
16197117f1b4Smrg   }
16207117f1b4Smrg
16217117f1b4Smrg   /* Basic level check */
16227117f1b4Smrg   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
16237117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage2D(level=%d)", level);
16247117f1b4Smrg      return GL_TRUE;
16257117f1b4Smrg   }
16267117f1b4Smrg
16277117f1b4Smrg   if (width < 0) {
16287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
16297117f1b4Smrg                  "glTexSubImage%dD(width=%d)", dimensions, width);
16307117f1b4Smrg      return GL_TRUE;
16317117f1b4Smrg   }
16327117f1b4Smrg   if (height < 0 && dimensions > 1) {
16337117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
16347117f1b4Smrg                  "glTexSubImage%dD(height=%d)", dimensions, height);
16357117f1b4Smrg      return GL_TRUE;
16367117f1b4Smrg   }
16377117f1b4Smrg   if (depth < 0 && dimensions > 2) {
16387117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
16397117f1b4Smrg                  "glTexSubImage%dD(depth=%d)", dimensions, depth);
16407117f1b4Smrg      return GL_TRUE;
16417117f1b4Smrg   }
16427117f1b4Smrg
16437117f1b4Smrg   if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
16447117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM,
16457117f1b4Smrg                  "glTexSubImage%dD(format or type)", dimensions);
16467117f1b4Smrg      return GL_TRUE;
16477117f1b4Smrg   }
16487117f1b4Smrg
16497117f1b4Smrg   return GL_FALSE;
16507117f1b4Smrg}
16517117f1b4Smrg
16527117f1b4Smrgstatic GLboolean
16537117f1b4Smrgsubtexture_error_check2( GLcontext *ctx, GLuint dimensions,
16547117f1b4Smrg			 GLenum target, GLint level,
16557117f1b4Smrg			 GLint xoffset, GLint yoffset, GLint zoffset,
16567117f1b4Smrg			 GLint width, GLint height, GLint depth,
16577117f1b4Smrg			 GLenum format, GLenum type,
16587117f1b4Smrg			 const struct gl_texture_image *destTex )
16597117f1b4Smrg{
16607117f1b4Smrg   if (!destTex) {
16617117f1b4Smrg      /* undefined image level */
16627117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexSubImage%dD", dimensions);
16637117f1b4Smrg      return GL_TRUE;
16647117f1b4Smrg   }
16657117f1b4Smrg
16667117f1b4Smrg   if (xoffset < -((GLint)destTex->Border)) {
16677117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset)",
16687117f1b4Smrg                  dimensions);
16697117f1b4Smrg      return GL_TRUE;
16707117f1b4Smrg   }
16717117f1b4Smrg   if (xoffset + width > (GLint) (destTex->Width + destTex->Border)) {
16727117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(xoffset+width)",
16737117f1b4Smrg                  dimensions);
16747117f1b4Smrg      return GL_TRUE;
16757117f1b4Smrg   }
16767117f1b4Smrg   if (dimensions > 1) {
16777117f1b4Smrg      if (yoffset < -((GLint)destTex->Border)) {
16787117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset)",
16797117f1b4Smrg                     dimensions);
16807117f1b4Smrg         return GL_TRUE;
16817117f1b4Smrg      }
16827117f1b4Smrg      if (yoffset + height > (GLint) (destTex->Height + destTex->Border)) {
16837117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage%dD(yoffset+height)",
16847117f1b4Smrg                     dimensions);
16857117f1b4Smrg         return GL_TRUE;
16867117f1b4Smrg      }
16877117f1b4Smrg   }
16887117f1b4Smrg   if (dimensions > 2) {
16897117f1b4Smrg      if (zoffset < -((GLint)destTex->Border)) {
16907117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset)");
16917117f1b4Smrg         return GL_TRUE;
16927117f1b4Smrg      }
16937117f1b4Smrg      if (zoffset + depth  > (GLint) (destTex->Depth + destTex->Border)) {
16947117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glTexSubImage3D(zoffset+depth)");
16957117f1b4Smrg         return GL_TRUE;
16967117f1b4Smrg      }
16977117f1b4Smrg   }
16987117f1b4Smrg
16997117f1b4Smrg#if FEATURE_EXT_texture_sRGB
17007117f1b4Smrg   if (destTex->InternalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT ||
17017117f1b4Smrg       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ||
17027117f1b4Smrg       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ||
17037117f1b4Smrg       destTex->InternalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
17047117f1b4Smrg      if ((width & 0x3) || (height & 0x3) ||
17057117f1b4Smrg          (xoffset & 0x3) || (yoffset & 0x3))
17067117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
17077117f1b4Smrg                     "glTexSubImage%dD(size or offset not multiple of 4)",
17087117f1b4Smrg                     dimensions);
17097117f1b4Smrg      return GL_TRUE;
17107117f1b4Smrg   }
17117117f1b4Smrg#endif
17127117f1b4Smrg
17137117f1b4Smrg   if (destTex->IsCompressed) {
17147117f1b4Smrg      if (!target_can_be_compressed(ctx, target)) {
17157117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
17167117f1b4Smrg                     "glTexSubImage%D(target)", dimensions);
17177117f1b4Smrg         return GL_TRUE;
17187117f1b4Smrg      }
17197117f1b4Smrg      /* offset must be multiple of 4 */
17207117f1b4Smrg      if ((xoffset & 3) || (yoffset & 3)) {
17217117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
17227117f1b4Smrg                     "glTexSubImage%D(xoffset or yoffset)", dimensions);
17237117f1b4Smrg         return GL_TRUE;
17247117f1b4Smrg      }
17257117f1b4Smrg      /* size must be multiple of 4 or equal to whole texture size */
17267117f1b4Smrg      if ((width & 3) && (GLuint) width != destTex->Width) {
17277117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
17287117f1b4Smrg                     "glTexSubImage%D(width)", dimensions);
17297117f1b4Smrg         return GL_TRUE;
17307117f1b4Smrg      }
17317117f1b4Smrg      if ((height & 3) && (GLuint) height != destTex->Height) {
17327117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
17337117f1b4Smrg                     "glTexSubImage%D(width)", dimensions);
17347117f1b4Smrg         return GL_TRUE;
17357117f1b4Smrg      }
17367117f1b4Smrg   }
17377117f1b4Smrg
17387117f1b4Smrg   return GL_FALSE;
17397117f1b4Smrg}
17407117f1b4Smrg
17417117f1b4Smrg
17427117f1b4Smrg/**
17437117f1b4Smrg * Test glCopyTexImage[12]D() parameters for errors.
17447117f1b4Smrg *
17457117f1b4Smrg * \param ctx GL context.
17467117f1b4Smrg * \param dimensions texture image dimensions (must be 1, 2 or 3).
17477117f1b4Smrg * \param target texture target given by the user.
17487117f1b4Smrg * \param level image level given by the user.
17497117f1b4Smrg * \param internalFormat internal format given by the user.
17507117f1b4Smrg * \param width image width given by the user.
17517117f1b4Smrg * \param height image height given by the user.
17527117f1b4Smrg * \param depth image depth given by the user.
17537117f1b4Smrg * \param border texture border.
17547117f1b4Smrg *
17557117f1b4Smrg * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
17567117f1b4Smrg *
17577117f1b4Smrg * Verifies each of the parameters against the constants specified in
17587117f1b4Smrg * __GLcontextRec::Const and the supported extensions, and according to the
17597117f1b4Smrg * OpenGL specification.
17607117f1b4Smrg */
17617117f1b4Smrgstatic GLboolean
17627117f1b4Smrgcopytexture_error_check( GLcontext *ctx, GLuint dimensions,
17637117f1b4Smrg                         GLenum target, GLint level, GLint internalFormat,
17647117f1b4Smrg                         GLint width, GLint height, GLint border )
17657117f1b4Smrg{
17667117f1b4Smrg   GLenum type;
17677117f1b4Smrg   GLboolean sizeOK;
17687117f1b4Smrg   GLint format;
17697117f1b4Smrg
17707117f1b4Smrg   /* Basic level check (more checking in ctx->Driver.TestProxyTexImage) */
17717117f1b4Smrg   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
17727117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
17737117f1b4Smrg                  "glCopyTexImage%dD(level=%d)", dimensions, level);
17747117f1b4Smrg      return GL_TRUE;
17757117f1b4Smrg   }
17767117f1b4Smrg
17777117f1b4Smrg   /* Check that the source buffer is complete */
17787117f1b4Smrg   if (ctx->ReadBuffer->Name) {
17797117f1b4Smrg      _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
17807117f1b4Smrg      if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
17817117f1b4Smrg         _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
17827117f1b4Smrg                     "glCopyTexImage%dD(invalid readbuffer)", dimensions);
17837117f1b4Smrg         return GL_TRUE;
17847117f1b4Smrg      }
17857117f1b4Smrg   }
17867117f1b4Smrg
17877117f1b4Smrg   /* Check border */
17887117f1b4Smrg   if (border < 0 || border > 1 ||
17897117f1b4Smrg       ((target == GL_TEXTURE_RECTANGLE_NV ||
17907117f1b4Smrg         target == GL_PROXY_TEXTURE_RECTANGLE_NV) && border != 0)) {
17917117f1b4Smrg      return GL_TRUE;
17927117f1b4Smrg   }
17937117f1b4Smrg
17947117f1b4Smrg   format = _mesa_base_tex_format(ctx, internalFormat);
17957117f1b4Smrg   if (format < 0) {
17967117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
17977117f1b4Smrg                  "glCopyTexImage%dD(internalFormat)", dimensions);
17987117f1b4Smrg      return GL_TRUE;
17997117f1b4Smrg   }
18007117f1b4Smrg
18017117f1b4Smrg   /* NOTE: the format and type aren't really significant for
18027117f1b4Smrg    * TestProxyTexImage().  Only the internalformat really matters.
18037117f1b4Smrg   if (!_mesa_source_buffer_exists(ctx, format)) {
18047117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
18057117f1b4Smrg                  "glCopyTexImage%dD(missing readbuffer)", dimensions);
18067117f1b4Smrg      return GL_TRUE;
18077117f1b4Smrg   }
18087117f1b4Smrg
18097117f1b4Smrg    */
18107117f1b4Smrg   type = GL_FLOAT;
18117117f1b4Smrg
18127117f1b4Smrg   /* Check target and call ctx->Driver.TestProxyTexImage() to check the
18137117f1b4Smrg    * level, width, height and depth.
18147117f1b4Smrg    */
18157117f1b4Smrg   if (dimensions == 1) {
18167117f1b4Smrg      if (target == GL_TEXTURE_1D) {
18177117f1b4Smrg         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_1D,
18187117f1b4Smrg                                                level, internalFormat,
18197117f1b4Smrg                                                format, type,
18207117f1b4Smrg                                                width, 1, 1, border);
18217117f1b4Smrg      }
18227117f1b4Smrg      else {
18237117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage1D(target)" );
18247117f1b4Smrg         return GL_TRUE;
18257117f1b4Smrg      }
18267117f1b4Smrg   }
18277117f1b4Smrg   else if (dimensions == 2) {
18287117f1b4Smrg      if (target == GL_TEXTURE_2D) {
18297117f1b4Smrg         sizeOK = ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_2D,
18307117f1b4Smrg                                                level, internalFormat,
18317117f1b4Smrg                                                format, type,
18327117f1b4Smrg                                                width, height, 1, border);
18337117f1b4Smrg      }
18347117f1b4Smrg      else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
18357117f1b4Smrg               target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
18367117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map) {
18377117f1b4Smrg            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
18387117f1b4Smrg            return GL_TRUE;
18397117f1b4Smrg         }
18407117f1b4Smrg         sizeOK = (width == height) &&
18417117f1b4Smrg            ctx->Driver.TestProxyTexImage(ctx, GL_PROXY_TEXTURE_CUBE_MAP_ARB,
18427117f1b4Smrg                                          level, internalFormat, format, type,
18437117f1b4Smrg                                          width, height, 1, border);
18447117f1b4Smrg      }
18457117f1b4Smrg      else if (target == GL_TEXTURE_RECTANGLE_NV) {
18467117f1b4Smrg         if (!ctx->Extensions.NV_texture_rectangle) {
18477117f1b4Smrg            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
18487117f1b4Smrg            return GL_TRUE;
18497117f1b4Smrg         }
18507117f1b4Smrg         sizeOK = ctx->Driver.TestProxyTexImage(ctx,
18517117f1b4Smrg                                                GL_PROXY_TEXTURE_RECTANGLE_NV,
18527117f1b4Smrg                                                level, internalFormat,
18537117f1b4Smrg                                                format, type,
18547117f1b4Smrg                                                width, height, 1, border);
18557117f1b4Smrg      }
18567117f1b4Smrg      else {
18577117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexImage2D(target)" );
18587117f1b4Smrg         return GL_TRUE;
18597117f1b4Smrg      }
18607117f1b4Smrg   }
18617117f1b4Smrg   else {
18627117f1b4Smrg      _mesa_problem(ctx, "invalid dimensions in copytexture_error_check");
18637117f1b4Smrg      return GL_TRUE;
18647117f1b4Smrg   }
18657117f1b4Smrg
18667117f1b4Smrg   if (!sizeOK) {
18677117f1b4Smrg      if (dimensions == 1) {
18687117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
18697117f1b4Smrg                     "glCopyTexImage1D(width=%d)", width);
18707117f1b4Smrg      }
18717117f1b4Smrg      else {
18727117f1b4Smrg         ASSERT(dimensions == 2);
18737117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
18747117f1b4Smrg                     "glCopyTexImage2D(width=%d, height=%d)", width, height);
18757117f1b4Smrg      }
18767117f1b4Smrg      return GL_TRUE;
18777117f1b4Smrg   }
18787117f1b4Smrg
18797117f1b4Smrg   if (is_compressed_format(ctx, internalFormat)) {
18807117f1b4Smrg      if (target != GL_TEXTURE_2D) {
18817117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
18827117f1b4Smrg                     "glCopyTexImage%d(target)", dimensions);
18837117f1b4Smrg         return GL_TRUE;
18847117f1b4Smrg      }
18857117f1b4Smrg      if (border != 0) {
18867117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
18877117f1b4Smrg                     "glCopyTexImage%D(border!=0)", dimensions);
18887117f1b4Smrg         return GL_TRUE;
18897117f1b4Smrg      }
18907117f1b4Smrg   }
18917117f1b4Smrg   else if (is_depth_format(internalFormat)) {
18927117f1b4Smrg      /* make sure we have depth/stencil buffers */
18937117f1b4Smrg      if (!ctx->ReadBuffer->_DepthBuffer) {
18947117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
18957117f1b4Smrg                     "glCopyTexImage%D(no depth)", dimensions);
18967117f1b4Smrg         return GL_TRUE;
18977117f1b4Smrg      }
18987117f1b4Smrg   }
18997117f1b4Smrg   else if (is_depthstencil_format(internalFormat)) {
19007117f1b4Smrg      /* make sure we have depth/stencil buffers */
19017117f1b4Smrg      if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
19027117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
19037117f1b4Smrg                     "glCopyTexImage%D(no depth/stencil buffer)", dimensions);
19047117f1b4Smrg         return GL_TRUE;
19057117f1b4Smrg      }
19067117f1b4Smrg   }
19077117f1b4Smrg
19087117f1b4Smrg   /* if we get here, the parameters are OK */
19097117f1b4Smrg   return GL_FALSE;
19107117f1b4Smrg}
19117117f1b4Smrg
19127117f1b4Smrg
19137117f1b4Smrg/**
19147117f1b4Smrg * Test glCopyTexSubImage[12]D() parameters for errors.
19157117f1b4Smrg *
19167117f1b4Smrg * \param ctx GL context.
19177117f1b4Smrg * \param dimensions texture image dimensions (must be 1, 2 or 3).
19187117f1b4Smrg * \param target texture target given by the user.
19197117f1b4Smrg * \param level image level given by the user.
19207117f1b4Smrg * \param xoffset sub-image x offset given by the user.
19217117f1b4Smrg * \param yoffset sub-image y offset given by the user.
19227117f1b4Smrg * \param zoffset sub-image z offset given by the user.
19237117f1b4Smrg * \param width image width given by the user.
19247117f1b4Smrg * \param height image height given by the user.
19257117f1b4Smrg *
19267117f1b4Smrg * \return GL_TRUE if an error was detected, or GL_FALSE if no errors.
19277117f1b4Smrg *
19287117f1b4Smrg * Verifies each of the parameters against the constants specified in
19297117f1b4Smrg * __GLcontextRec::Const and the supported extensions, and according to the
19307117f1b4Smrg * OpenGL specification.
19317117f1b4Smrg */
19327117f1b4Smrgstatic GLboolean
19337117f1b4Smrgcopytexsubimage_error_check( GLcontext *ctx, GLuint dimensions,
19347117f1b4Smrg                             GLenum target, GLint level,
19357117f1b4Smrg                             GLint xoffset, GLint yoffset, GLint zoffset,
19367117f1b4Smrg                             GLsizei width, GLsizei height)
19377117f1b4Smrg{
19387117f1b4Smrg   /* Check target */
19397117f1b4Smrg   /* Check that the source buffer is complete */
19407117f1b4Smrg   if (ctx->ReadBuffer->Name) {
19417117f1b4Smrg      _mesa_test_framebuffer_completeness(ctx, ctx->ReadBuffer);
19427117f1b4Smrg      if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
19437117f1b4Smrg         _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
19447117f1b4Smrg                     "glCopyTexImage%dD(invalid readbuffer)", dimensions);
19457117f1b4Smrg         return GL_TRUE;
19467117f1b4Smrg      }
19477117f1b4Smrg   }
19487117f1b4Smrg
19497117f1b4Smrg   if (dimensions == 1) {
19507117f1b4Smrg      if (target != GL_TEXTURE_1D) {
19517117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage1D(target)" );
19527117f1b4Smrg         return GL_TRUE;
19537117f1b4Smrg      }
19547117f1b4Smrg   }
19557117f1b4Smrg   else if (dimensions == 2) {
19567117f1b4Smrg      if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
19577117f1b4Smrg          target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
19587117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map) {
19597117f1b4Smrg            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
19607117f1b4Smrg            return GL_TRUE;
19617117f1b4Smrg         }
19627117f1b4Smrg      }
19637117f1b4Smrg      else if (target == GL_TEXTURE_RECTANGLE_NV) {
19647117f1b4Smrg         if (!ctx->Extensions.NV_texture_rectangle) {
19657117f1b4Smrg            _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
19667117f1b4Smrg            return GL_TRUE;
19677117f1b4Smrg         }
19687117f1b4Smrg      }
19697117f1b4Smrg      else if (target != GL_TEXTURE_2D) {
19707117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage2D(target)" );
19717117f1b4Smrg         return GL_TRUE;
19727117f1b4Smrg      }
19737117f1b4Smrg   }
19747117f1b4Smrg   else if (dimensions == 3) {
19757117f1b4Smrg      if (target != GL_TEXTURE_3D) {
19767117f1b4Smrg         _mesa_error( ctx, GL_INVALID_ENUM, "glCopyTexSubImage3D(target)" );
19777117f1b4Smrg         return GL_TRUE;
19787117f1b4Smrg      }
19797117f1b4Smrg   }
19807117f1b4Smrg
19817117f1b4Smrg   /* Check level */
19827117f1b4Smrg   if (level < 0 || level >= MAX_TEXTURE_LEVELS) {
19837117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
19847117f1b4Smrg                  "glCopyTexSubImage%dD(level=%d)", dimensions, level);
19857117f1b4Smrg      return GL_TRUE;
19867117f1b4Smrg   }
19877117f1b4Smrg
19887117f1b4Smrg   /* Check size */
19897117f1b4Smrg   if (width < 0) {
19907117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
19917117f1b4Smrg                  "glCopyTexSubImage%dD(width=%d)", dimensions, width);
19927117f1b4Smrg      return GL_TRUE;
19937117f1b4Smrg   }
19947117f1b4Smrg   if (dimensions > 1 && height < 0) {
19957117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
19967117f1b4Smrg                  "glCopyTexSubImage%dD(height=%d)", dimensions, height);
19977117f1b4Smrg      return GL_TRUE;
19987117f1b4Smrg   }
19997117f1b4Smrg
20007117f1b4Smrg   return GL_FALSE;
20017117f1b4Smrg}
20027117f1b4Smrg
20037117f1b4Smrgstatic GLboolean
20047117f1b4Smrgcopytexsubimage_error_check2( GLcontext *ctx, GLuint dimensions,
20057117f1b4Smrg			      GLenum target, GLint level,
20067117f1b4Smrg			      GLint xoffset, GLint yoffset, GLint zoffset,
20077117f1b4Smrg			      GLsizei width, GLsizei height,
20087117f1b4Smrg			      const struct gl_texture_image *teximage )
20097117f1b4Smrg{
20107117f1b4Smrg   if (!teximage) {
20117117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
20127117f1b4Smrg                  "glCopyTexSubImage%dD(undefined texture level: %d)",
20137117f1b4Smrg                  dimensions, level);
20147117f1b4Smrg      return GL_TRUE;
20157117f1b4Smrg   }
20167117f1b4Smrg
20177117f1b4Smrg   if (xoffset < -((GLint)teximage->Border)) {
20187117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
20197117f1b4Smrg                  "glCopyTexSubImage%dD(xoffset=%d)", dimensions, xoffset);
20207117f1b4Smrg      return GL_TRUE;
20217117f1b4Smrg   }
20227117f1b4Smrg   if (xoffset + width > (GLint) (teximage->Width + teximage->Border)) {
20237117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE,
20247117f1b4Smrg                  "glCopyTexSubImage%dD(xoffset+width)", dimensions);
20257117f1b4Smrg      return GL_TRUE;
20267117f1b4Smrg   }
20277117f1b4Smrg   if (dimensions > 1) {
20287117f1b4Smrg      if (yoffset < -((GLint)teximage->Border)) {
20297117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
20307117f1b4Smrg                     "glCopyTexSubImage%dD(yoffset=%d)", dimensions, yoffset);
20317117f1b4Smrg         return GL_TRUE;
20327117f1b4Smrg      }
20337117f1b4Smrg      /* NOTE: we're adding the border here, not subtracting! */
20347117f1b4Smrg      if (yoffset + height > (GLint) (teximage->Height + teximage->Border)) {
20357117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
20367117f1b4Smrg                     "glCopyTexSubImage%dD(yoffset+height)", dimensions);
20377117f1b4Smrg         return GL_TRUE;
20387117f1b4Smrg      }
20397117f1b4Smrg   }
20407117f1b4Smrg
20417117f1b4Smrg   if (dimensions > 2) {
20427117f1b4Smrg      if (zoffset < -((GLint)teximage->Border)) {
20437117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
20447117f1b4Smrg                     "glCopyTexSubImage%dD(zoffset)", dimensions);
20457117f1b4Smrg         return GL_TRUE;
20467117f1b4Smrg      }
20477117f1b4Smrg      if (zoffset > (GLint) (teximage->Depth + teximage->Border)) {
20487117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
20497117f1b4Smrg                     "glCopyTexSubImage%dD(zoffset+depth)", dimensions);
20507117f1b4Smrg         return GL_TRUE;
20517117f1b4Smrg      }
20527117f1b4Smrg   }
20537117f1b4Smrg
20547117f1b4Smrg   if (teximage->IsCompressed) {
20557117f1b4Smrg      if (target != GL_TEXTURE_2D) {
20567117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM,
20577117f1b4Smrg                     "glCopyTexSubImage%d(target)", dimensions);
20587117f1b4Smrg         return GL_TRUE;
20597117f1b4Smrg      }
20607117f1b4Smrg      /* offset must be multiple of 4 */
20617117f1b4Smrg      if ((xoffset & 3) || (yoffset & 3)) {
20627117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
20637117f1b4Smrg                     "glCopyTexSubImage%D(xoffset or yoffset)", dimensions);
20647117f1b4Smrg         return GL_TRUE;
20657117f1b4Smrg      }
20667117f1b4Smrg      /* size must be multiple of 4 */
20677117f1b4Smrg      if ((width & 3) != 0 && (GLuint) width != teximage->Width) {
20687117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
20697117f1b4Smrg                     "glCopyTexSubImage%D(width)", dimensions);
20707117f1b4Smrg         return GL_TRUE;
20717117f1b4Smrg      }
20727117f1b4Smrg      if ((height & 3) != 0 && (GLuint) height != teximage->Height) {
20737117f1b4Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
20747117f1b4Smrg                     "glCopyTexSubImage%D(height)", dimensions);
20757117f1b4Smrg         return GL_TRUE;
20767117f1b4Smrg      }
20777117f1b4Smrg   }
20787117f1b4Smrg
20797117f1b4Smrg   if (teximage->InternalFormat == GL_YCBCR_MESA) {
20807117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glCopyTexSubImage2D");
20817117f1b4Smrg      return GL_TRUE;
20827117f1b4Smrg   }
20837117f1b4Smrg
20847117f1b4Smrg   if (!_mesa_source_buffer_exists(ctx, teximage->_BaseFormat)) {
20857117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
20867117f1b4Smrg               "glCopyTexSubImage%dD(missing readbuffer)", dimensions);
20877117f1b4Smrg      return GL_TRUE;
20887117f1b4Smrg   }
20897117f1b4Smrg
20907117f1b4Smrg   if (teximage->_BaseFormat == GL_DEPTH_COMPONENT) {
20917117f1b4Smrg      if (!ctx->ReadBuffer->_DepthBuffer) {
20927117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
20937117f1b4Smrg                     "glCopyTexSubImage%D(no depth buffer)",
20947117f1b4Smrg                     dimensions);
20957117f1b4Smrg         return GL_TRUE;
20967117f1b4Smrg      }
20977117f1b4Smrg   }
20987117f1b4Smrg   else if (teximage->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
20997117f1b4Smrg      if (!ctx->ReadBuffer->_DepthBuffer || !ctx->ReadBuffer->_StencilBuffer) {
21007117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
21017117f1b4Smrg                     "glCopyTexSubImage%D(no depth/stencil buffer)",
21027117f1b4Smrg                     dimensions);
21037117f1b4Smrg         return GL_TRUE;
21047117f1b4Smrg      }
21057117f1b4Smrg   }
21067117f1b4Smrg
21077117f1b4Smrg   /* if we get here, the parameters are OK */
21087117f1b4Smrg   return GL_FALSE;
21097117f1b4Smrg}
21107117f1b4Smrg
21117117f1b4Smrg
21127117f1b4Smrg/**
21137117f1b4Smrg * Get texture image.  Called by glGetTexImage.
21147117f1b4Smrg *
21157117f1b4Smrg * \param target texture target.
21167117f1b4Smrg * \param level image level.
21177117f1b4Smrg * \param format pixel data format for returned image.
21187117f1b4Smrg * \param type pixel data type for returned image.
21197117f1b4Smrg * \param pixels returned pixel data.
21207117f1b4Smrg */
21217117f1b4Smrgvoid GLAPIENTRY
21227117f1b4Smrg_mesa_GetTexImage( GLenum target, GLint level, GLenum format,
21237117f1b4Smrg                   GLenum type, GLvoid *pixels )
21247117f1b4Smrg{
21257117f1b4Smrg   const struct gl_texture_unit *texUnit;
21267117f1b4Smrg   struct gl_texture_object *texObj;
21277117f1b4Smrg   struct gl_texture_image *texImage;
21287117f1b4Smrg   GLint maxLevels = 0;
21297117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
21307117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
21317117f1b4Smrg
21327117f1b4Smrg   texUnit = &(ctx->Texture.Unit[ctx->Texture.CurrentUnit]);
21337117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
21347117f1b4Smrg   if (!texObj || _mesa_is_proxy_texture(target)) {
21357117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(target)");
21367117f1b4Smrg      return;
21377117f1b4Smrg   }
21387117f1b4Smrg
21397117f1b4Smrg   maxLevels = _mesa_max_texture_levels(ctx, target);
21407117f1b4Smrg   ASSERT(maxLevels > 0);  /* 0 indicates bad target, caught above */
21417117f1b4Smrg
21427117f1b4Smrg   if (level < 0 || level >= maxLevels) {
21437117f1b4Smrg      _mesa_error( ctx, GL_INVALID_VALUE, "glGetTexImage(level)" );
21447117f1b4Smrg      return;
21457117f1b4Smrg   }
21467117f1b4Smrg
21477117f1b4Smrg   if (_mesa_sizeof_packed_type(type) <= 0) {
21487117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(type)" );
21497117f1b4Smrg      return;
21507117f1b4Smrg   }
21517117f1b4Smrg
21527117f1b4Smrg   if (_mesa_components_in_format(format) <= 0 ||
21537117f1b4Smrg       format == GL_STENCIL_INDEX) {
21547117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexImage(format)" );
21557117f1b4Smrg      return;
21567117f1b4Smrg   }
21577117f1b4Smrg
21587117f1b4Smrg   if (!ctx->Extensions.EXT_paletted_texture && is_index_format(format)) {
21597117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
21607117f1b4Smrg      return;
21617117f1b4Smrg   }
21627117f1b4Smrg
21637117f1b4Smrg   if (!ctx->Extensions.SGIX_depth_texture &&
21647117f1b4Smrg       !ctx->Extensions.ARB_depth_texture && is_depth_format(format)) {
21657117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
21667117f1b4Smrg      return;
21677117f1b4Smrg   }
21687117f1b4Smrg
21697117f1b4Smrg   if (!ctx->Extensions.MESA_ycbcr_texture && is_ycbcr_format(format)) {
21707117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
21717117f1b4Smrg      return;
21727117f1b4Smrg   }
21737117f1b4Smrg
21747117f1b4Smrg   if (!ctx->Extensions.EXT_packed_depth_stencil
21757117f1b4Smrg       && is_depthstencil_format(format)) {
21767117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format)");
21777117f1b4Smrg      return;
21787117f1b4Smrg   }
21797117f1b4Smrg
21807117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
21817117f1b4Smrg   {
21827117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
21837117f1b4Smrg      if (!texImage) {
21847117f1b4Smrg	 /* invalid mipmap level, not an error */
21857117f1b4Smrg	 goto out;
21867117f1b4Smrg      }
21877117f1b4Smrg
21887117f1b4Smrg
21897117f1b4Smrg      /* Make sure the requested image format is compatible with the
21907117f1b4Smrg       * texture's format.  Note that a color index texture can be converted
21917117f1b4Smrg       * to RGBA so that combo is allowed.
21927117f1b4Smrg       */
21937117f1b4Smrg      if (is_color_format(format)
21947117f1b4Smrg	  && !is_color_format(texImage->TexFormat->BaseFormat)
21957117f1b4Smrg	  && !is_index_format(texImage->TexFormat->BaseFormat)) {
21967117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
21977117f1b4Smrg	 goto out;
21987117f1b4Smrg      }
21997117f1b4Smrg      else if (is_index_format(format)
22007117f1b4Smrg	       && !is_index_format(texImage->TexFormat->BaseFormat)) {
22017117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
22027117f1b4Smrg	 goto out;
22037117f1b4Smrg      }
22047117f1b4Smrg      else if (is_depth_format(format)
22057117f1b4Smrg	       && !is_depth_format(texImage->TexFormat->BaseFormat)
22067117f1b4Smrg	       && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
22077117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
22087117f1b4Smrg	 goto out;
22097117f1b4Smrg      }
22107117f1b4Smrg      else if (is_ycbcr_format(format)
22117117f1b4Smrg	       && !is_ycbcr_format(texImage->TexFormat->BaseFormat)) {
22127117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
22137117f1b4Smrg	 goto out;
22147117f1b4Smrg      }
22157117f1b4Smrg      else if (is_depthstencil_format(format)
22167117f1b4Smrg	       && !is_depthstencil_format(texImage->TexFormat->BaseFormat)) {
22177117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
22187117f1b4Smrg	 goto out;
22197117f1b4Smrg      }
22207117f1b4Smrg
22217117f1b4Smrg      if (ctx->Pack.BufferObj->Name) {
22227117f1b4Smrg	 /* packing texture image into a PBO */
22237117f1b4Smrg	 const GLuint dimensions = (target == GL_TEXTURE_3D) ? 3 : 2;
22247117f1b4Smrg	 if (!_mesa_validate_pbo_access(dimensions, &ctx->Pack, texImage->Width,
22257117f1b4Smrg					texImage->Height, texImage->Depth,
22267117f1b4Smrg					format, type, pixels)) {
22277117f1b4Smrg	    _mesa_error(ctx, GL_INVALID_OPERATION,
22287117f1b4Smrg			"glGetTexImage(invalid PBO access)");
22297117f1b4Smrg	    goto out;
22307117f1b4Smrg	 }
22317117f1b4Smrg      }
22327117f1b4Smrg
22337117f1b4Smrg      /* typically, this will call _mesa_get_teximage() */
22347117f1b4Smrg      ctx->Driver.GetTexImage(ctx, target, level, format, type, pixels,
22357117f1b4Smrg			      texObj, texImage);
22367117f1b4Smrg
22377117f1b4Smrg   }
22387117f1b4Smrg out:
22397117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
22407117f1b4Smrg}
22417117f1b4Smrg
22427117f1b4Smrg
22437117f1b4Smrg
22447117f1b4Smrg/**
22457117f1b4Smrg * Check if the given texture image is bound to any framebuffer objects
22467117f1b4Smrg * and update/invalidate them.
22477117f1b4Smrg * XXX We're only checking the currently bound framebuffer object for now.
22487117f1b4Smrg * In the future, perhaps struct gl_texture_image should have a pointer (or
22497117f1b4Smrg * list of pointers (yikes)) to the gl_framebuffer(s) which it's bound to.
22507117f1b4Smrg */
22517117f1b4Smrgstatic void
22527117f1b4Smrgupdate_fbo_texture(GLcontext *ctx, struct gl_texture_object *texObj,
22537117f1b4Smrg                   GLuint face, GLuint level)
22547117f1b4Smrg{
22557117f1b4Smrg   if (ctx->DrawBuffer->Name) {
22567117f1b4Smrg      GLuint i;
22577117f1b4Smrg      for (i = 0; i < BUFFER_COUNT; i++) {
22587117f1b4Smrg         struct gl_renderbuffer_attachment *att =
22597117f1b4Smrg            ctx->DrawBuffer->Attachment + i;
22607117f1b4Smrg         if (att->Type == GL_TEXTURE &&
22617117f1b4Smrg             att->Texture == texObj &&
22627117f1b4Smrg             att->TextureLevel == level &&
22637117f1b4Smrg             att->CubeMapFace == face) {
22647117f1b4Smrg            ASSERT(att->Texture->Image[att->CubeMapFace][att->TextureLevel]);
22657117f1b4Smrg            /* Tell driver about the new renderbuffer texture */
22667117f1b4Smrg            ctx->Driver.RenderTexture(ctx, ctx->DrawBuffer, att);
22677117f1b4Smrg         }
22687117f1b4Smrg      }
22697117f1b4Smrg   }
22707117f1b4Smrg}
22717117f1b4Smrg
22727117f1b4Smrg
22737117f1b4Smrg
22747117f1b4Smrg/*
22757117f1b4Smrg * Called from the API.  Note that width includes the border.
22767117f1b4Smrg */
22777117f1b4Smrgvoid GLAPIENTRY
22787117f1b4Smrg_mesa_TexImage1D( GLenum target, GLint level, GLint internalFormat,
22797117f1b4Smrg                  GLsizei width, GLint border, GLenum format,
22807117f1b4Smrg                  GLenum type, const GLvoid *pixels )
22817117f1b4Smrg{
22827117f1b4Smrg   GLsizei postConvWidth = width;
22837117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
22847117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
22857117f1b4Smrg
22867117f1b4Smrg   if (is_color_format(internalFormat)) {
22877117f1b4Smrg      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
22887117f1b4Smrg   }
22897117f1b4Smrg
22907117f1b4Smrg   if (target == GL_TEXTURE_1D) {
22917117f1b4Smrg      /* non-proxy target */
22927117f1b4Smrg      struct gl_texture_unit *texUnit;
22937117f1b4Smrg      struct gl_texture_object *texObj;
22947117f1b4Smrg      struct gl_texture_image *texImage;
22957117f1b4Smrg      const GLuint face = texture_face(target);
22967117f1b4Smrg
22977117f1b4Smrg      if (texture_error_check(ctx, target, level, internalFormat,
22987117f1b4Smrg                              format, type, 1, postConvWidth, 1, 1, border)) {
22997117f1b4Smrg         return;   /* error was recorded */
23007117f1b4Smrg      }
23017117f1b4Smrg
23027117f1b4Smrg      if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
23037117f1b4Smrg	 _mesa_update_state(ctx);
23047117f1b4Smrg
23057117f1b4Smrg      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
23067117f1b4Smrg      texObj = _mesa_select_tex_object(ctx, texUnit, target);
23077117f1b4Smrg      _mesa_lock_texture(ctx, texObj);
23087117f1b4Smrg      {
23097117f1b4Smrg	 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
23107117f1b4Smrg	 if (!texImage) {
23117117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D");
23127117f1b4Smrg	    goto out;
23137117f1b4Smrg	 }
23147117f1b4Smrg
23157117f1b4Smrg	 if (texImage->Data) {
23167117f1b4Smrg	    ctx->Driver.FreeTexImageData( ctx, texImage );
23177117f1b4Smrg	 }
23187117f1b4Smrg
23197117f1b4Smrg	 ASSERT(texImage->Data == NULL);
23207117f1b4Smrg
23217117f1b4Smrg	 clear_teximage_fields(texImage); /* not really needed, but helpful */
23227117f1b4Smrg	 _mesa_init_teximage_fields(ctx, target, texImage,
23237117f1b4Smrg				    postConvWidth, 1, 1,
23247117f1b4Smrg				    border, internalFormat);
23257117f1b4Smrg
23267117f1b4Smrg	 ASSERT(ctx->Driver.TexImage1D);
23277117f1b4Smrg
23287117f1b4Smrg	 /* Give the texture to the driver!  <pixels> may be null! */
23297117f1b4Smrg	 (*ctx->Driver.TexImage1D)(ctx, target, level, internalFormat,
23307117f1b4Smrg				   width, border, format, type, pixels,
23317117f1b4Smrg				   &ctx->Unpack, texObj, texImage);
23327117f1b4Smrg
23337117f1b4Smrg	 ASSERT(texImage->TexFormat);
23347117f1b4Smrg
23357117f1b4Smrg	 update_fbo_texture(ctx, texObj, face, level);
23367117f1b4Smrg
23377117f1b4Smrg	 /* state update */
23387117f1b4Smrg	 texObj->Complete = GL_FALSE;
23397117f1b4Smrg	 ctx->NewState |= _NEW_TEXTURE;
23407117f1b4Smrg      }
23417117f1b4Smrg   out:
23427117f1b4Smrg      _mesa_unlock_texture(ctx, texObj);
23437117f1b4Smrg   }
23447117f1b4Smrg   else if (target == GL_PROXY_TEXTURE_1D) {
23457117f1b4Smrg      /* Proxy texture: check for errors and update proxy state */
23467117f1b4Smrg      struct gl_texture_image *texImage;
23477117f1b4Smrg      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
23487117f1b4Smrg      if (texture_error_check(ctx, target, level, internalFormat,
23497117f1b4Smrg                              format, type, 1, postConvWidth, 1, 1, border)) {
23507117f1b4Smrg         /* when error, clear all proxy texture image parameters */
23517117f1b4Smrg         if (texImage)
23527117f1b4Smrg            clear_teximage_fields(texImage);
23537117f1b4Smrg      }
23547117f1b4Smrg      else {
23557117f1b4Smrg         /* no error, set the tex image parameters */
23567117f1b4Smrg         ASSERT(texImage);
23577117f1b4Smrg         _mesa_init_teximage_fields(ctx, target, texImage,
23587117f1b4Smrg                                    postConvWidth, 1, 1,
23597117f1b4Smrg                                    border, internalFormat);
23607117f1b4Smrg         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
23617117f1b4Smrg                                          internalFormat, format, type);
23627117f1b4Smrg      }
23637117f1b4Smrg   }
23647117f1b4Smrg   else {
23657117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage1D(target)" );
23667117f1b4Smrg      return;
23677117f1b4Smrg   }
23687117f1b4Smrg}
23697117f1b4Smrg
23707117f1b4Smrg
23717117f1b4Smrgvoid GLAPIENTRY
23727117f1b4Smrg_mesa_TexImage2D( GLenum target, GLint level, GLint internalFormat,
23737117f1b4Smrg                  GLsizei width, GLsizei height, GLint border,
23747117f1b4Smrg                  GLenum format, GLenum type,
23757117f1b4Smrg                  const GLvoid *pixels )
23767117f1b4Smrg{
23777117f1b4Smrg   GLsizei postConvWidth = width, postConvHeight = height;
23787117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
23797117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
23807117f1b4Smrg
23817117f1b4Smrg   if (is_color_format(internalFormat)) {
23827117f1b4Smrg      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
23837117f1b4Smrg					 &postConvHeight);
23847117f1b4Smrg   }
23857117f1b4Smrg
23867117f1b4Smrg   if (target == GL_TEXTURE_2D ||
23877117f1b4Smrg       (ctx->Extensions.ARB_texture_cube_map &&
23887117f1b4Smrg        target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
23897117f1b4Smrg        target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) ||
23907117f1b4Smrg       (ctx->Extensions.NV_texture_rectangle &&
23917117f1b4Smrg        target == GL_TEXTURE_RECTANGLE_NV)) {
23927117f1b4Smrg      /* non-proxy target */
23937117f1b4Smrg      struct gl_texture_unit *texUnit;
23947117f1b4Smrg      struct gl_texture_object *texObj;
23957117f1b4Smrg      struct gl_texture_image *texImage;
23967117f1b4Smrg      const GLuint face = texture_face(target);
23977117f1b4Smrg
23987117f1b4Smrg      if (texture_error_check(ctx, target, level, internalFormat,
23997117f1b4Smrg                              format, type, 2, postConvWidth, postConvHeight,
24007117f1b4Smrg                              1, border)) {
24017117f1b4Smrg         return;   /* error was recorded */
24027117f1b4Smrg      }
24037117f1b4Smrg
24047117f1b4Smrg      if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
24057117f1b4Smrg	 _mesa_update_state(ctx);
24067117f1b4Smrg
24077117f1b4Smrg      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
24087117f1b4Smrg      texObj = _mesa_select_tex_object(ctx, texUnit, target);
24097117f1b4Smrg      _mesa_lock_texture(ctx, texObj);
24107117f1b4Smrg      {
24117117f1b4Smrg	 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
24127117f1b4Smrg	 if (!texImage) {
24137117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D");
24147117f1b4Smrg	    goto out;
24157117f1b4Smrg	 }
24167117f1b4Smrg
24177117f1b4Smrg	 if (texImage->Data) {
24187117f1b4Smrg	    ctx->Driver.FreeTexImageData( ctx, texImage );
24197117f1b4Smrg	 }
24207117f1b4Smrg
24217117f1b4Smrg	 ASSERT(texImage->Data == NULL);
24227117f1b4Smrg	 clear_teximage_fields(texImage); /* not really needed, but helpful */
24237117f1b4Smrg	 _mesa_init_teximage_fields(ctx, target, texImage,
24247117f1b4Smrg				    postConvWidth, postConvHeight, 1,
24257117f1b4Smrg				    border, internalFormat);
24267117f1b4Smrg
24277117f1b4Smrg	 ASSERT(ctx->Driver.TexImage2D);
24287117f1b4Smrg
24297117f1b4Smrg	 /* Give the texture to the driver!  <pixels> may be null! */
24307117f1b4Smrg	 (*ctx->Driver.TexImage2D)(ctx, target, level, internalFormat,
24317117f1b4Smrg				   width, height, border, format, type, pixels,
24327117f1b4Smrg				   &ctx->Unpack, texObj, texImage);
24337117f1b4Smrg
24347117f1b4Smrg	 ASSERT(texImage->TexFormat);
24357117f1b4Smrg
24367117f1b4Smrg	 update_fbo_texture(ctx, texObj, face, level);
24377117f1b4Smrg
24387117f1b4Smrg	 /* state update */
24397117f1b4Smrg	 texObj->Complete = GL_FALSE;
24407117f1b4Smrg	 ctx->NewState |= _NEW_TEXTURE;
24417117f1b4Smrg      }
24427117f1b4Smrg   out:
24437117f1b4Smrg      _mesa_unlock_texture(ctx, texObj);
24447117f1b4Smrg   }
24457117f1b4Smrg   else if (target == GL_PROXY_TEXTURE_2D ||
24467117f1b4Smrg            (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB &&
24477117f1b4Smrg             ctx->Extensions.ARB_texture_cube_map) ||
24487117f1b4Smrg            (target == GL_PROXY_TEXTURE_RECTANGLE_NV &&
24497117f1b4Smrg             ctx->Extensions.NV_texture_rectangle)) {
24507117f1b4Smrg      /* Proxy texture: check for errors and update proxy state */
24517117f1b4Smrg      struct gl_texture_image *texImage;
24527117f1b4Smrg      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
24537117f1b4Smrg      if (texture_error_check(ctx, target, level, internalFormat,
24547117f1b4Smrg                              format, type, 2, postConvWidth, postConvHeight,
24557117f1b4Smrg                              1, border)) {
24567117f1b4Smrg         /* when error, clear all proxy texture image parameters */
24577117f1b4Smrg         if (texImage)
24587117f1b4Smrg            clear_teximage_fields(ctx->Texture.Proxy2D->Image[0][level]);
24597117f1b4Smrg      }
24607117f1b4Smrg      else {
24617117f1b4Smrg         /* no error, set the tex image parameters */
24627117f1b4Smrg         _mesa_init_teximage_fields(ctx, target, texImage,
24637117f1b4Smrg                                    postConvWidth, postConvHeight, 1,
24647117f1b4Smrg                                    border, internalFormat);
24657117f1b4Smrg         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
24667117f1b4Smrg                                          internalFormat, format, type);
24677117f1b4Smrg      }
24687117f1b4Smrg   }
24697117f1b4Smrg   else {
24707117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage2D(target)" );
24717117f1b4Smrg      return;
24727117f1b4Smrg   }
24737117f1b4Smrg}
24747117f1b4Smrg
24757117f1b4Smrg
24767117f1b4Smrg/*
24777117f1b4Smrg * Called by the API or display list executor.
24787117f1b4Smrg * Note that width and height include the border.
24797117f1b4Smrg */
24807117f1b4Smrgvoid GLAPIENTRY
24817117f1b4Smrg_mesa_TexImage3D( GLenum target, GLint level, GLint internalFormat,
24827117f1b4Smrg                  GLsizei width, GLsizei height, GLsizei depth,
24837117f1b4Smrg                  GLint border, GLenum format, GLenum type,
24847117f1b4Smrg                  const GLvoid *pixels )
24857117f1b4Smrg{
24867117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
24877117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
24887117f1b4Smrg
24897117f1b4Smrg   if (target == GL_TEXTURE_3D) {
24907117f1b4Smrg      /* non-proxy target */
24917117f1b4Smrg      struct gl_texture_unit *texUnit;
24927117f1b4Smrg      struct gl_texture_object *texObj;
24937117f1b4Smrg      struct gl_texture_image *texImage;
24947117f1b4Smrg      const GLuint face = texture_face(target);
24957117f1b4Smrg
24967117f1b4Smrg      if (texture_error_check(ctx, target, level, (GLint) internalFormat,
24977117f1b4Smrg                              format, type, 3, width, height, depth, border)) {
24987117f1b4Smrg         return;   /* error was recorded */
24997117f1b4Smrg      }
25007117f1b4Smrg
25017117f1b4Smrg      if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
25027117f1b4Smrg	 _mesa_update_state(ctx);
25037117f1b4Smrg
25047117f1b4Smrg      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
25057117f1b4Smrg      texObj = _mesa_select_tex_object(ctx, texUnit, target);
25067117f1b4Smrg      _mesa_lock_texture(ctx, texObj);
25077117f1b4Smrg      {
25087117f1b4Smrg	 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
25097117f1b4Smrg	 if (!texImage) {
25107117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage3D");
25117117f1b4Smrg	    goto out;
25127117f1b4Smrg	 }
25137117f1b4Smrg
25147117f1b4Smrg	 if (texImage->Data) {
25157117f1b4Smrg	    ctx->Driver.FreeTexImageData( ctx, texImage );
25167117f1b4Smrg	 }
25177117f1b4Smrg
25187117f1b4Smrg	 ASSERT(texImage->Data == NULL);
25197117f1b4Smrg	 clear_teximage_fields(texImage); /* not really needed, but helpful */
25207117f1b4Smrg	 _mesa_init_teximage_fields(ctx, target, texImage,
25217117f1b4Smrg				    width, height, depth,
25227117f1b4Smrg				    border, internalFormat);
25237117f1b4Smrg
25247117f1b4Smrg	 ASSERT(ctx->Driver.TexImage3D);
25257117f1b4Smrg
25267117f1b4Smrg	 /* Give the texture to the driver!  <pixels> may be null! */
25277117f1b4Smrg	 (*ctx->Driver.TexImage3D)(ctx, target, level, internalFormat,
25287117f1b4Smrg				   width, height, depth, border, format, type,
25297117f1b4Smrg				   pixels, &ctx->Unpack, texObj, texImage);
25307117f1b4Smrg
25317117f1b4Smrg	 ASSERT(texImage->TexFormat);
25327117f1b4Smrg
25337117f1b4Smrg	 update_fbo_texture(ctx, texObj, face, level);
25347117f1b4Smrg
25357117f1b4Smrg	 /* state update */
25367117f1b4Smrg	 texObj->Complete = GL_FALSE;
25377117f1b4Smrg	 ctx->NewState |= _NEW_TEXTURE;
25387117f1b4Smrg      }
25397117f1b4Smrg   out:
25407117f1b4Smrg      _mesa_unlock_texture(ctx, texObj);
25417117f1b4Smrg   }
25427117f1b4Smrg   else if (target == GL_PROXY_TEXTURE_3D) {
25437117f1b4Smrg      /* Proxy texture: check for errors and update proxy state */
25447117f1b4Smrg      struct gl_texture_image *texImage;
25457117f1b4Smrg      texImage = _mesa_get_proxy_tex_image(ctx, target, level);
25467117f1b4Smrg      if (texture_error_check(ctx, target, level, internalFormat,
25477117f1b4Smrg                              format, type, 3, width, height, depth, border)) {
25487117f1b4Smrg         /* when error, clear all proxy texture image parameters */
25497117f1b4Smrg         if (texImage)
25507117f1b4Smrg            clear_teximage_fields(texImage);
25517117f1b4Smrg      }
25527117f1b4Smrg      else {
25537117f1b4Smrg         /* no error, set the tex image parameters */
25547117f1b4Smrg         _mesa_init_teximage_fields(ctx, target, texImage, width, height,
25557117f1b4Smrg                                    depth, border, internalFormat);
25567117f1b4Smrg         texImage->TexFormat = (*ctx->Driver.ChooseTextureFormat)(ctx,
25577117f1b4Smrg                                          internalFormat, format, type);
25587117f1b4Smrg      }
25597117f1b4Smrg   }
25607117f1b4Smrg   else {
25617117f1b4Smrg      _mesa_error( ctx, GL_INVALID_ENUM, "glTexImage3D(target)" );
25627117f1b4Smrg      return;
25637117f1b4Smrg   }
25647117f1b4Smrg}
25657117f1b4Smrg
25667117f1b4Smrg
25677117f1b4Smrgvoid GLAPIENTRY
25687117f1b4Smrg_mesa_TexImage3DEXT( GLenum target, GLint level, GLenum internalFormat,
25697117f1b4Smrg                     GLsizei width, GLsizei height, GLsizei depth,
25707117f1b4Smrg                     GLint border, GLenum format, GLenum type,
25717117f1b4Smrg                     const GLvoid *pixels )
25727117f1b4Smrg{
25737117f1b4Smrg   _mesa_TexImage3D(target, level, (GLint) internalFormat, width, height,
25747117f1b4Smrg                    depth, border, format, type, pixels);
25757117f1b4Smrg}
25767117f1b4Smrg
25777117f1b4Smrg
25787117f1b4Smrg
25797117f1b4Smrgvoid GLAPIENTRY
25807117f1b4Smrg_mesa_TexSubImage1D( GLenum target, GLint level,
25817117f1b4Smrg                     GLint xoffset, GLsizei width,
25827117f1b4Smrg                     GLenum format, GLenum type,
25837117f1b4Smrg                     const GLvoid *pixels )
25847117f1b4Smrg{
25857117f1b4Smrg   GLsizei postConvWidth = width;
25867117f1b4Smrg   struct gl_texture_unit *texUnit;
25877117f1b4Smrg   struct gl_texture_object *texObj;
25887117f1b4Smrg   struct gl_texture_image *texImage = NULL;
25897117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
25907117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
25917117f1b4Smrg
25927117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
25937117f1b4Smrg      _mesa_update_state(ctx);
25947117f1b4Smrg
25957117f1b4Smrg   /* XXX should test internal format */
25967117f1b4Smrg   if (is_color_format(format)) {
25977117f1b4Smrg      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
25987117f1b4Smrg   }
25997117f1b4Smrg
26007117f1b4Smrg   if (subtexture_error_check(ctx, 1, target, level, xoffset, 0, 0,
26017117f1b4Smrg			       postConvWidth, 1, 1, format, type)) {
26027117f1b4Smrg      return;   /* error was detected */
26037117f1b4Smrg   }
26047117f1b4Smrg
26057117f1b4Smrg
26067117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
26077117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
26087117f1b4Smrg   assert(texObj);
26097117f1b4Smrg
26107117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
26117117f1b4Smrg   {
26127117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
26137117f1b4Smrg
26147117f1b4Smrg      if (subtexture_error_check2(ctx, 1, target, level, xoffset, 0, 0,
26157117f1b4Smrg				  postConvWidth, 1, 1, format, type, texImage)) {
26167117f1b4Smrg	 goto out;   /* error was detected */
26177117f1b4Smrg      }
26187117f1b4Smrg
26197117f1b4Smrg      if (width == 0)
26207117f1b4Smrg	 goto out;  /* no-op, not an error */
26217117f1b4Smrg
26227117f1b4Smrg      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
26237117f1b4Smrg      xoffset += texImage->Border;
26247117f1b4Smrg
26257117f1b4Smrg      ASSERT(ctx->Driver.TexSubImage1D);
26267117f1b4Smrg      (*ctx->Driver.TexSubImage1D)(ctx, target, level, xoffset, width,
26277117f1b4Smrg				   format, type, pixels, &ctx->Unpack,
26287117f1b4Smrg				   texObj, texImage);
26297117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
26307117f1b4Smrg   }
26317117f1b4Smrg out:
26327117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
26337117f1b4Smrg}
26347117f1b4Smrg
26357117f1b4Smrg
26367117f1b4Smrgvoid GLAPIENTRY
26377117f1b4Smrg_mesa_TexSubImage2D( GLenum target, GLint level,
26387117f1b4Smrg                     GLint xoffset, GLint yoffset,
26397117f1b4Smrg                     GLsizei width, GLsizei height,
26407117f1b4Smrg                     GLenum format, GLenum type,
26417117f1b4Smrg                     const GLvoid *pixels )
26427117f1b4Smrg{
26437117f1b4Smrg   GLsizei postConvWidth = width, postConvHeight = height;
26447117f1b4Smrg   struct gl_texture_unit *texUnit;
26457117f1b4Smrg   struct gl_texture_object *texObj;
26467117f1b4Smrg   struct gl_texture_image *texImage;
26477117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
26487117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
26497117f1b4Smrg
26507117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
26517117f1b4Smrg      _mesa_update_state(ctx);
26527117f1b4Smrg
26537117f1b4Smrg   /* XXX should test internal format */
26547117f1b4Smrg   if (is_color_format(format)) {
26557117f1b4Smrg      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
26567117f1b4Smrg                                         &postConvHeight);
26577117f1b4Smrg   }
26587117f1b4Smrg
26597117f1b4Smrg   if (subtexture_error_check(ctx, 2, target, level, xoffset, yoffset, 0,
26607117f1b4Smrg			      postConvWidth, postConvHeight, 1, format, type)) {
26617117f1b4Smrg      return;   /* error was detected */
26627117f1b4Smrg   }
26637117f1b4Smrg
26647117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
26657117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
26667117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
26677117f1b4Smrg   {
26687117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
26697117f1b4Smrg
26707117f1b4Smrg      if (subtexture_error_check2(ctx, 2, target, level, xoffset, yoffset, 0,
26717117f1b4Smrg				  postConvWidth, postConvHeight, 1, format, type,
26727117f1b4Smrg				  texImage)) {
26737117f1b4Smrg	 goto out;   /* error was detected */
26747117f1b4Smrg      }
26757117f1b4Smrg
26767117f1b4Smrg      if (width == 0 || height == 0)
26777117f1b4Smrg	 goto out;  /* no-op, not an error */
26787117f1b4Smrg
26797117f1b4Smrg      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
26807117f1b4Smrg      xoffset += texImage->Border;
26817117f1b4Smrg      yoffset += texImage->Border;
26827117f1b4Smrg
26837117f1b4Smrg      ASSERT(ctx->Driver.TexSubImage2D);
26847117f1b4Smrg      (*ctx->Driver.TexSubImage2D)(ctx, target, level, xoffset, yoffset,
26857117f1b4Smrg				   width, height, format, type, pixels,
26867117f1b4Smrg				   &ctx->Unpack, texObj, texImage);
26877117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
26887117f1b4Smrg   }
26897117f1b4Smrg out:
26907117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
26917117f1b4Smrg}
26927117f1b4Smrg
26937117f1b4Smrg
26947117f1b4Smrg
26957117f1b4Smrgvoid GLAPIENTRY
26967117f1b4Smrg_mesa_TexSubImage3D( GLenum target, GLint level,
26977117f1b4Smrg                     GLint xoffset, GLint yoffset, GLint zoffset,
26987117f1b4Smrg                     GLsizei width, GLsizei height, GLsizei depth,
26997117f1b4Smrg                     GLenum format, GLenum type,
27007117f1b4Smrg                     const GLvoid *pixels )
27017117f1b4Smrg{
27027117f1b4Smrg   struct gl_texture_unit *texUnit;
27037117f1b4Smrg   struct gl_texture_object *texObj;
27047117f1b4Smrg   struct gl_texture_image *texImage;
27057117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
27067117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
27077117f1b4Smrg
27087117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
27097117f1b4Smrg      _mesa_update_state(ctx);
27107117f1b4Smrg
27117117f1b4Smrg   if (subtexture_error_check(ctx, 3, target, level, xoffset, yoffset, zoffset,
27127117f1b4Smrg                              width, height, depth, format, type)) {
27137117f1b4Smrg      return;   /* error was detected */
27147117f1b4Smrg   }
27157117f1b4Smrg
27167117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
27177117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
27187117f1b4Smrg
27197117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
27207117f1b4Smrg   {
27217117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
27227117f1b4Smrg
27237117f1b4Smrg      if (subtexture_error_check2(ctx, 3, target, level, xoffset, yoffset, zoffset,
27247117f1b4Smrg				  width, height, depth, format, type, texImage)) {
27257117f1b4Smrg	 goto out;   /* error was detected */
27267117f1b4Smrg      }
27277117f1b4Smrg
27287117f1b4Smrg      if (width == 0 || height == 0 || height == 0)
27297117f1b4Smrg	 goto out;  /* no-op, not an error */
27307117f1b4Smrg
27317117f1b4Smrg      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
27327117f1b4Smrg      xoffset += texImage->Border;
27337117f1b4Smrg      yoffset += texImage->Border;
27347117f1b4Smrg      zoffset += texImage->Border;
27357117f1b4Smrg
27367117f1b4Smrg      ASSERT(ctx->Driver.TexSubImage3D);
27377117f1b4Smrg      (*ctx->Driver.TexSubImage3D)(ctx, target, level,
27387117f1b4Smrg				   xoffset, yoffset, zoffset,
27397117f1b4Smrg				   width, height, depth,
27407117f1b4Smrg				   format, type, pixels,
27417117f1b4Smrg				   &ctx->Unpack, texObj, texImage );
27427117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
27437117f1b4Smrg   }
27447117f1b4Smrg out:
27457117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
27467117f1b4Smrg}
27477117f1b4Smrg
27487117f1b4Smrg
27497117f1b4Smrg
27507117f1b4Smrgvoid GLAPIENTRY
27517117f1b4Smrg_mesa_CopyTexImage1D( GLenum target, GLint level,
27527117f1b4Smrg                      GLenum internalFormat,
27537117f1b4Smrg                      GLint x, GLint y,
27547117f1b4Smrg                      GLsizei width, GLint border )
27557117f1b4Smrg{
27567117f1b4Smrg   struct gl_texture_unit *texUnit;
27577117f1b4Smrg   struct gl_texture_object *texObj;
27587117f1b4Smrg   struct gl_texture_image *texImage;
27597117f1b4Smrg   GLsizei postConvWidth = width;
27607117f1b4Smrg   const GLuint face = texture_face(target);
27617117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
27627117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
27637117f1b4Smrg
27647117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
27657117f1b4Smrg      _mesa_update_state(ctx);
27667117f1b4Smrg
27677117f1b4Smrg   if (is_color_format(internalFormat)) {
27687117f1b4Smrg      _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
27697117f1b4Smrg   }
27707117f1b4Smrg
27717117f1b4Smrg   if (copytexture_error_check(ctx, 1, target, level, internalFormat,
27727117f1b4Smrg                               postConvWidth, 1, border))
27737117f1b4Smrg      return;
27747117f1b4Smrg
27757117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
27767117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
27777117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
27787117f1b4Smrg   {
27797117f1b4Smrg      texImage = _mesa_get_tex_image(ctx, texObj, target, level);
27807117f1b4Smrg      if (!texImage) {
27817117f1b4Smrg	 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage1D");
27827117f1b4Smrg	 goto out;
27837117f1b4Smrg      }
27847117f1b4Smrg
27857117f1b4Smrg      if (texImage->Data) {
27867117f1b4Smrg	 ctx->Driver.FreeTexImageData( ctx, texImage );
27877117f1b4Smrg      }
27887117f1b4Smrg
27897117f1b4Smrg      ASSERT(texImage->Data == NULL);
27907117f1b4Smrg
27917117f1b4Smrg      clear_teximage_fields(texImage); /* not really needed, but helpful */
27927117f1b4Smrg      _mesa_init_teximage_fields(ctx, target, texImage, postConvWidth, 1, 1,
27937117f1b4Smrg				 border, internalFormat);
27947117f1b4Smrg
27957117f1b4Smrg
27967117f1b4Smrg      ASSERT(ctx->Driver.CopyTexImage1D);
27977117f1b4Smrg      (*ctx->Driver.CopyTexImage1D)(ctx, target, level, internalFormat,
27987117f1b4Smrg				    x, y, width, border);
27997117f1b4Smrg
28007117f1b4Smrg      ASSERT(texImage->TexFormat);
28017117f1b4Smrg
28027117f1b4Smrg      update_fbo_texture(ctx, texObj, face, level);
28037117f1b4Smrg
28047117f1b4Smrg      /* state update */
28057117f1b4Smrg      texObj->Complete = GL_FALSE;
28067117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
28077117f1b4Smrg   }
28087117f1b4Smrg out:
28097117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
28107117f1b4Smrg}
28117117f1b4Smrg
28127117f1b4Smrg
28137117f1b4Smrg
28147117f1b4Smrgvoid GLAPIENTRY
28157117f1b4Smrg_mesa_CopyTexImage2D( GLenum target, GLint level, GLenum internalFormat,
28167117f1b4Smrg                      GLint x, GLint y, GLsizei width, GLsizei height,
28177117f1b4Smrg                      GLint border )
28187117f1b4Smrg{
28197117f1b4Smrg   struct gl_texture_unit *texUnit;
28207117f1b4Smrg   struct gl_texture_object *texObj;
28217117f1b4Smrg   struct gl_texture_image *texImage;
28227117f1b4Smrg   GLsizei postConvWidth = width, postConvHeight = height;
28237117f1b4Smrg   const GLuint face = texture_face(target);
28247117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
28257117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
28267117f1b4Smrg
28277117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
28287117f1b4Smrg      _mesa_update_state(ctx);
28297117f1b4Smrg
28307117f1b4Smrg   if (is_color_format(internalFormat)) {
28317117f1b4Smrg      _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth,
28327117f1b4Smrg                                         &postConvHeight);
28337117f1b4Smrg   }
28347117f1b4Smrg
28357117f1b4Smrg   if (copytexture_error_check(ctx, 2, target, level, internalFormat,
28367117f1b4Smrg                               postConvWidth, postConvHeight, border))
28377117f1b4Smrg      return;
28387117f1b4Smrg
28397117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
28407117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
28417117f1b4Smrg
28427117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
28437117f1b4Smrg   {
28447117f1b4Smrg      texImage = _mesa_get_tex_image(ctx, texObj, target, level);
28457117f1b4Smrg
28467117f1b4Smrg      if (!texImage) {
28477117f1b4Smrg	 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyTexImage2D");
28487117f1b4Smrg	 goto out;
28497117f1b4Smrg      }
28507117f1b4Smrg
28517117f1b4Smrg      if (texImage->Data) {
28527117f1b4Smrg	 ctx->Driver.FreeTexImageData( ctx, texImage );
28537117f1b4Smrg      }
28547117f1b4Smrg
28557117f1b4Smrg      ASSERT(texImage->Data == NULL);
28567117f1b4Smrg
28577117f1b4Smrg      clear_teximage_fields(texImage); /* not really needed, but helpful */
28587117f1b4Smrg      _mesa_init_teximage_fields(ctx, target, texImage,
28597117f1b4Smrg				 postConvWidth, postConvHeight, 1,
28607117f1b4Smrg				 border, internalFormat);
28617117f1b4Smrg
28627117f1b4Smrg      ASSERT(ctx->Driver.CopyTexImage2D);
28637117f1b4Smrg      (*ctx->Driver.CopyTexImage2D)(ctx, target, level, internalFormat,
28647117f1b4Smrg				    x, y, width, height, border);
28657117f1b4Smrg
28667117f1b4Smrg      ASSERT(texImage->TexFormat);
28677117f1b4Smrg
28687117f1b4Smrg      update_fbo_texture(ctx, texObj, face, level);
28697117f1b4Smrg
28707117f1b4Smrg      /* state update */
28717117f1b4Smrg      texObj->Complete = GL_FALSE;
28727117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
28737117f1b4Smrg   }
28747117f1b4Smrg out:
28757117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
28767117f1b4Smrg}
28777117f1b4Smrg
28787117f1b4Smrg
28797117f1b4Smrgvoid GLAPIENTRY
28807117f1b4Smrg_mesa_CopyTexSubImage1D( GLenum target, GLint level,
28817117f1b4Smrg                         GLint xoffset, GLint x, GLint y, GLsizei width )
28827117f1b4Smrg{
28837117f1b4Smrg   struct gl_texture_unit *texUnit;
28847117f1b4Smrg   struct gl_texture_object *texObj;
28857117f1b4Smrg   struct gl_texture_image *texImage;
28867117f1b4Smrg   GLsizei postConvWidth = width;
28877117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
28887117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
28897117f1b4Smrg
28907117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
28917117f1b4Smrg      _mesa_update_state(ctx);
28927117f1b4Smrg
28937117f1b4Smrg   /* XXX should test internal format */
28947117f1b4Smrg   _mesa_adjust_image_for_convolution(ctx, 1, &postConvWidth, NULL);
28957117f1b4Smrg
28967117f1b4Smrg   if (copytexsubimage_error_check(ctx, 1, target, level,
28977117f1b4Smrg                                   xoffset, 0, 0, postConvWidth, 1))
28987117f1b4Smrg      return;
28997117f1b4Smrg
29007117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
29017117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
29027117f1b4Smrg
29037117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
29047117f1b4Smrg   {
29057117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
29067117f1b4Smrg
29077117f1b4Smrg      if (copytexsubimage_error_check2(ctx, 1, target, level,
29087117f1b4Smrg				       xoffset, 0, 0, postConvWidth, 1,
29097117f1b4Smrg				       texImage))
29107117f1b4Smrg	 goto out;
29117117f1b4Smrg
29127117f1b4Smrg
29137117f1b4Smrg      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
29147117f1b4Smrg      xoffset += texImage->Border;
29157117f1b4Smrg
29167117f1b4Smrg      ASSERT(ctx->Driver.CopyTexSubImage1D);
29177117f1b4Smrg      (*ctx->Driver.CopyTexSubImage1D)(ctx, target, level, xoffset, x, y, width);
29187117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
29197117f1b4Smrg   }
29207117f1b4Smrg out:
29217117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
29227117f1b4Smrg}
29237117f1b4Smrg
29247117f1b4Smrg
29257117f1b4Smrg
29267117f1b4Smrgvoid GLAPIENTRY
29277117f1b4Smrg_mesa_CopyTexSubImage2D( GLenum target, GLint level,
29287117f1b4Smrg                         GLint xoffset, GLint yoffset,
29297117f1b4Smrg                         GLint x, GLint y, GLsizei width, GLsizei height )
29307117f1b4Smrg{
29317117f1b4Smrg   struct gl_texture_unit *texUnit;
29327117f1b4Smrg   struct gl_texture_object *texObj;
29337117f1b4Smrg   struct gl_texture_image *texImage;
29347117f1b4Smrg   GLsizei postConvWidth = width, postConvHeight = height;
29357117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
29367117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
29377117f1b4Smrg
29387117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
29397117f1b4Smrg      _mesa_update_state(ctx);
29407117f1b4Smrg
29417117f1b4Smrg   /* XXX should test internal format */
29427117f1b4Smrg   _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth, &postConvHeight);
29437117f1b4Smrg
29447117f1b4Smrg   if (copytexsubimage_error_check(ctx, 2, target, level, xoffset, yoffset, 0,
29457117f1b4Smrg                                   postConvWidth, postConvHeight))
29467117f1b4Smrg      return;
29477117f1b4Smrg
29487117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
29497117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
29507117f1b4Smrg
29517117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
29527117f1b4Smrg   {
29537117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
29547117f1b4Smrg
29557117f1b4Smrg      if (copytexsubimage_error_check2(ctx, 2, target, level, xoffset, yoffset, 0,
29567117f1b4Smrg				       postConvWidth, postConvHeight, texImage))
29577117f1b4Smrg	 goto out;
29587117f1b4Smrg
29597117f1b4Smrg      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
29607117f1b4Smrg      xoffset += texImage->Border;
29617117f1b4Smrg      yoffset += texImage->Border;
29627117f1b4Smrg
29637117f1b4Smrg      ASSERT(ctx->Driver.CopyTexSubImage2D);
29647117f1b4Smrg      (*ctx->Driver.CopyTexSubImage2D)(ctx, target, level,
29657117f1b4Smrg				       xoffset, yoffset, x, y, width, height);
29667117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
29677117f1b4Smrg   }
29687117f1b4Smrg out:
29697117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
29707117f1b4Smrg}
29717117f1b4Smrg
29727117f1b4Smrg
29737117f1b4Smrg
29747117f1b4Smrgvoid GLAPIENTRY
29757117f1b4Smrg_mesa_CopyTexSubImage3D( GLenum target, GLint level,
29767117f1b4Smrg                         GLint xoffset, GLint yoffset, GLint zoffset,
29777117f1b4Smrg                         GLint x, GLint y, GLsizei width, GLsizei height )
29787117f1b4Smrg{
29797117f1b4Smrg   struct gl_texture_unit *texUnit;
29807117f1b4Smrg   struct gl_texture_object *texObj;
29817117f1b4Smrg   struct gl_texture_image *texImage;
29827117f1b4Smrg   GLsizei postConvWidth = width, postConvHeight = height;
29837117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
29847117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
29857117f1b4Smrg
29867117f1b4Smrg   if (ctx->NewState & _IMAGE_NEW_TRANSFER_STATE)
29877117f1b4Smrg      _mesa_update_state(ctx);
29887117f1b4Smrg
29897117f1b4Smrg   /* XXX should test internal format */
29907117f1b4Smrg   _mesa_adjust_image_for_convolution(ctx, 2, &postConvWidth, &postConvHeight);
29917117f1b4Smrg
29927117f1b4Smrg   if (copytexsubimage_error_check(ctx, 3, target, level, xoffset, yoffset,
29937117f1b4Smrg                                   zoffset, postConvWidth, postConvHeight))
29947117f1b4Smrg      return;
29957117f1b4Smrg
29967117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
29977117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
29987117f1b4Smrg
29997117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
30007117f1b4Smrg   {
30017117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
30027117f1b4Smrg
30037117f1b4Smrg      if (copytexsubimage_error_check2(ctx, 3, target, level, xoffset, yoffset,
30047117f1b4Smrg				       zoffset, postConvWidth, postConvHeight,
30057117f1b4Smrg				       texImage))
30067117f1b4Smrg	 goto out;
30077117f1b4Smrg
30087117f1b4Smrg      /* If we have a border, xoffset=-1 is legal.  Bias by border width */
30097117f1b4Smrg      xoffset += texImage->Border;
30107117f1b4Smrg      yoffset += texImage->Border;
30117117f1b4Smrg      zoffset += texImage->Border;
30127117f1b4Smrg
30137117f1b4Smrg      ASSERT(ctx->Driver.CopyTexSubImage3D);
30147117f1b4Smrg      (*ctx->Driver.CopyTexSubImage3D)(ctx, target, level,
30157117f1b4Smrg				       xoffset, yoffset, zoffset,
30167117f1b4Smrg				       x, y, width, height);
30177117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
30187117f1b4Smrg   }
30197117f1b4Smrg out:
30207117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
30217117f1b4Smrg}
30227117f1b4Smrg
30237117f1b4Smrg
30247117f1b4Smrg
30257117f1b4Smrg
30267117f1b4Smrg/**********************************************************************/
30277117f1b4Smrg/******                   Compressed Textures                    ******/
30287117f1b4Smrg/**********************************************************************/
30297117f1b4Smrg
30307117f1b4Smrg
30317117f1b4Smrg/**
30327117f1b4Smrg * Error checking for glCompressedTexImage[123]D().
30337117f1b4Smrg * \return error code or GL_NO_ERROR.
30347117f1b4Smrg */
30357117f1b4Smrgstatic GLenum
30367117f1b4Smrgcompressed_texture_error_check(GLcontext *ctx, GLint dimensions,
30377117f1b4Smrg                               GLenum target, GLint level,
30387117f1b4Smrg                               GLenum internalFormat, GLsizei width,
30397117f1b4Smrg                               GLsizei height, GLsizei depth, GLint border,
30407117f1b4Smrg                               GLsizei imageSize)
30417117f1b4Smrg{
30427117f1b4Smrg   GLint expectedSize, maxLevels = 0, maxTextureSize;
30437117f1b4Smrg
30447117f1b4Smrg   if (dimensions == 1) {
30457117f1b4Smrg      /* 1D compressed textures not allowed */
30467117f1b4Smrg      return GL_INVALID_ENUM;
30477117f1b4Smrg   }
30487117f1b4Smrg   else if (dimensions == 2) {
30497117f1b4Smrg      if (target == GL_PROXY_TEXTURE_2D) {
30507117f1b4Smrg         maxLevels = ctx->Const.MaxTextureLevels;
30517117f1b4Smrg      }
30527117f1b4Smrg      else if (target == GL_TEXTURE_2D) {
30537117f1b4Smrg         maxLevels = ctx->Const.MaxTextureLevels;
30547117f1b4Smrg      }
30557117f1b4Smrg      else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
30567117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map)
30577117f1b4Smrg            return GL_INVALID_ENUM; /*target*/
30587117f1b4Smrg         maxLevels = ctx->Const.MaxCubeTextureLevels;
30597117f1b4Smrg      }
30607117f1b4Smrg      else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
30617117f1b4Smrg               target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
30627117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map)
30637117f1b4Smrg            return GL_INVALID_ENUM; /*target*/
30647117f1b4Smrg         maxLevels = ctx->Const.MaxCubeTextureLevels;
30657117f1b4Smrg      }
30667117f1b4Smrg      else {
30677117f1b4Smrg         return GL_INVALID_ENUM; /*target*/
30687117f1b4Smrg      }
30697117f1b4Smrg   }
30707117f1b4Smrg   else if (dimensions == 3) {
30717117f1b4Smrg      /* 3D compressed textures not allowed */
30727117f1b4Smrg      return GL_INVALID_ENUM;
30737117f1b4Smrg   }
30747117f1b4Smrg
30757117f1b4Smrg   maxTextureSize = 1 << (maxLevels - 1);
30767117f1b4Smrg
30777117f1b4Smrg   /* This will detect any invalid internalFormat value */
30787117f1b4Smrg   if (!is_compressed_format(ctx, internalFormat))
30797117f1b4Smrg      return GL_INVALID_ENUM;
30807117f1b4Smrg
30817117f1b4Smrg   /* This should really never fail */
30827117f1b4Smrg   if (_mesa_base_tex_format(ctx, internalFormat) < 0)
30837117f1b4Smrg      return GL_INVALID_ENUM;
30847117f1b4Smrg
30857117f1b4Smrg   if (border != 0)
30867117f1b4Smrg      return GL_INVALID_VALUE;
30877117f1b4Smrg
30887117f1b4Smrg   /*
30897117f1b4Smrg    * XXX We should probably use the proxy texture error check function here.
30907117f1b4Smrg    */
30917117f1b4Smrg   if (width < 1 || width > maxTextureSize ||
30927117f1b4Smrg       (!ctx->Extensions.ARB_texture_non_power_of_two && _mesa_bitcount(width) != 1))
30937117f1b4Smrg      return GL_INVALID_VALUE;
30947117f1b4Smrg
30957117f1b4Smrg   if ((height < 1 || height > maxTextureSize ||
30967117f1b4Smrg       (!ctx->Extensions.ARB_texture_non_power_of_two && _mesa_bitcount(height) != 1))
30977117f1b4Smrg       && dimensions > 1)
30987117f1b4Smrg      return GL_INVALID_VALUE;
30997117f1b4Smrg
31007117f1b4Smrg   if ((depth < 1 || depth > maxTextureSize ||
31017117f1b4Smrg       (!ctx->Extensions.ARB_texture_non_power_of_two && _mesa_bitcount(depth) != 1))
31027117f1b4Smrg       && dimensions > 2)
31037117f1b4Smrg      return GL_INVALID_VALUE;
31047117f1b4Smrg
31057117f1b4Smrg   /* For cube map, width must equal height */
31067117f1b4Smrg   if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
31077117f1b4Smrg       target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height)
31087117f1b4Smrg      return GL_INVALID_VALUE;
31097117f1b4Smrg
31107117f1b4Smrg   if (level < 0 || level >= maxLevels)
31117117f1b4Smrg      return GL_INVALID_VALUE;
31127117f1b4Smrg
31137117f1b4Smrg   expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height,
31147117f1b4Smrg                                                       depth, internalFormat);
31157117f1b4Smrg   if (expectedSize != imageSize)
31167117f1b4Smrg      return GL_INVALID_VALUE;
31177117f1b4Smrg
31187117f1b4Smrg#if FEATURE_EXT_texture_sRGB
31197117f1b4Smrg   if ((internalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT ||
31207117f1b4Smrg        internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT ||
31217117f1b4Smrg        internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT ||
31227117f1b4Smrg        internalFormat == GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT)
31237117f1b4Smrg       && border != 0) {
31247117f1b4Smrg      return GL_INVALID_OPERATION;
31257117f1b4Smrg   }
31267117f1b4Smrg#endif
31277117f1b4Smrg
31287117f1b4Smrg   return GL_NO_ERROR;
31297117f1b4Smrg}
31307117f1b4Smrg
31317117f1b4Smrg
31327117f1b4Smrg/**
31337117f1b4Smrg * Error checking for glCompressedTexSubImage[123]D().
31347117f1b4Smrg * \warning  There are some bad assumptions here about the size of compressed
31357117f1b4Smrg *           texture tiles (multiple of 4) used to test the validity of the
31367117f1b4Smrg *           offset and size parameters.
31377117f1b4Smrg * \return error code or GL_NO_ERROR.
31387117f1b4Smrg */
31397117f1b4Smrgstatic GLenum
31407117f1b4Smrgcompressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
31417117f1b4Smrg                                  GLenum target, GLint level,
31427117f1b4Smrg                                  GLint xoffset, GLint yoffset, GLint zoffset,
31437117f1b4Smrg                                  GLsizei width, GLsizei height, GLsizei depth,
31447117f1b4Smrg                                  GLenum format, GLsizei imageSize)
31457117f1b4Smrg{
31467117f1b4Smrg   GLint expectedSize, maxLevels = 0, maxTextureSize;
31477117f1b4Smrg   (void) zoffset;
31487117f1b4Smrg
31497117f1b4Smrg   if (dimensions == 1) {
31507117f1b4Smrg      /* 1D compressed textures not allowed */
31517117f1b4Smrg      return GL_INVALID_ENUM;
31527117f1b4Smrg   }
31537117f1b4Smrg   else if (dimensions == 2) {
31547117f1b4Smrg      if (target == GL_PROXY_TEXTURE_2D) {
31557117f1b4Smrg         maxLevels = ctx->Const.MaxTextureLevels;
31567117f1b4Smrg      }
31577117f1b4Smrg      else if (target == GL_TEXTURE_2D) {
31587117f1b4Smrg         maxLevels = ctx->Const.MaxTextureLevels;
31597117f1b4Smrg      }
31607117f1b4Smrg      else if (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB) {
31617117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map)
31627117f1b4Smrg            return GL_INVALID_ENUM; /*target*/
31637117f1b4Smrg         maxLevels = ctx->Const.MaxCubeTextureLevels;
31647117f1b4Smrg      }
31657117f1b4Smrg      else if (target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
31667117f1b4Smrg               target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
31677117f1b4Smrg         if (!ctx->Extensions.ARB_texture_cube_map)
31687117f1b4Smrg            return GL_INVALID_ENUM; /*target*/
31697117f1b4Smrg         maxLevels = ctx->Const.MaxCubeTextureLevels;
31707117f1b4Smrg      }
31717117f1b4Smrg      else {
31727117f1b4Smrg         return GL_INVALID_ENUM; /*target*/
31737117f1b4Smrg      }
31747117f1b4Smrg   }
31757117f1b4Smrg   else if (dimensions == 3) {
31767117f1b4Smrg      /* 3D compressed textures not allowed */
31777117f1b4Smrg      return GL_INVALID_ENUM;
31787117f1b4Smrg   }
31797117f1b4Smrg
31807117f1b4Smrg   maxTextureSize = 1 << (maxLevels - 1);
31817117f1b4Smrg
31827117f1b4Smrg   /* this will catch any invalid compressed format token */
31837117f1b4Smrg   if (!is_compressed_format(ctx, format))
31847117f1b4Smrg      return GL_INVALID_ENUM;
31857117f1b4Smrg
31867117f1b4Smrg   if (width < 1 || width > maxTextureSize)
31877117f1b4Smrg      return GL_INVALID_VALUE;
31887117f1b4Smrg
31897117f1b4Smrg   if ((height < 1 || height > maxTextureSize)
31907117f1b4Smrg       && dimensions > 1)
31917117f1b4Smrg      return GL_INVALID_VALUE;
31927117f1b4Smrg
31937117f1b4Smrg   if (level < 0 || level >= maxLevels)
31947117f1b4Smrg      return GL_INVALID_VALUE;
31957117f1b4Smrg
31967117f1b4Smrg   /* XXX these tests are specific to the compressed format.
31977117f1b4Smrg    * this code should be generalized in some way.
31987117f1b4Smrg    */
31997117f1b4Smrg   if ((xoffset & 3) != 0 || (yoffset & 3) != 0)
32007117f1b4Smrg      return GL_INVALID_VALUE;
32017117f1b4Smrg
32027117f1b4Smrg   if ((width & 3) != 0 && width != 2 && width != 1)
32037117f1b4Smrg      return GL_INVALID_VALUE;
32047117f1b4Smrg
32057117f1b4Smrg   if ((height & 3) != 0 && height != 2 && height != 1)
32067117f1b4Smrg      return GL_INVALID_VALUE;
32077117f1b4Smrg
32087117f1b4Smrg   expectedSize = _mesa_compressed_texture_size_glenum(ctx, width, height,
32097117f1b4Smrg                                                       depth, format);
32107117f1b4Smrg   if (expectedSize != imageSize)
32117117f1b4Smrg      return GL_INVALID_VALUE;
32127117f1b4Smrg
32137117f1b4Smrg   return GL_NO_ERROR;
32147117f1b4Smrg}
32157117f1b4Smrg
32167117f1b4Smrg
32177117f1b4Smrg
32187117f1b4Smrgvoid GLAPIENTRY
32197117f1b4Smrg_mesa_CompressedTexImage1DARB(GLenum target, GLint level,
32207117f1b4Smrg                              GLenum internalFormat, GLsizei width,
32217117f1b4Smrg                              GLint border, GLsizei imageSize,
32227117f1b4Smrg                              const GLvoid *data)
32237117f1b4Smrg{
32247117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
32257117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
32267117f1b4Smrg
32277117f1b4Smrg   if (target == GL_TEXTURE_1D) {
32287117f1b4Smrg      /* non-proxy target */
32297117f1b4Smrg      struct gl_texture_unit *texUnit;
32307117f1b4Smrg      struct gl_texture_object *texObj;
32317117f1b4Smrg      struct gl_texture_image *texImage;
32327117f1b4Smrg      GLenum error = compressed_texture_error_check(ctx, 1, target, level,
32337117f1b4Smrg                               internalFormat, width, 1, 1, border, imageSize);
32347117f1b4Smrg      if (error) {
32357117f1b4Smrg         _mesa_error(ctx, error, "glCompressedTexImage1D");
32367117f1b4Smrg         return;
32377117f1b4Smrg      }
32387117f1b4Smrg
32397117f1b4Smrg      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
32407117f1b4Smrg      texObj = _mesa_select_tex_object(ctx, texUnit, target);
32417117f1b4Smrg
32427117f1b4Smrg      _mesa_lock_texture(ctx, texObj);
32437117f1b4Smrg      {
32447117f1b4Smrg	 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
32457117f1b4Smrg	 if (!texImage) {
32467117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage1D");
32477117f1b4Smrg	    goto out;
32487117f1b4Smrg	 }
32497117f1b4Smrg
32507117f1b4Smrg	 if (texImage->Data) {
32517117f1b4Smrg	    ctx->Driver.FreeTexImageData( ctx, texImage );
32527117f1b4Smrg	 }
32537117f1b4Smrg	 ASSERT(texImage->Data == NULL);
32547117f1b4Smrg
32557117f1b4Smrg	 _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
32567117f1b4Smrg				    border, internalFormat);
32577117f1b4Smrg
32587117f1b4Smrg	 ASSERT(ctx->Driver.CompressedTexImage1D);
32597117f1b4Smrg	 (*ctx->Driver.CompressedTexImage1D)(ctx, target, level,
32607117f1b4Smrg					     internalFormat, width, border,
32617117f1b4Smrg					     imageSize, data,
32627117f1b4Smrg					     texObj, texImage);
32637117f1b4Smrg
32647117f1b4Smrg	 /* state update */
32657117f1b4Smrg	 texObj->Complete = GL_FALSE;
32667117f1b4Smrg	 ctx->NewState |= _NEW_TEXTURE;
32677117f1b4Smrg      }
32687117f1b4Smrg   out:
32697117f1b4Smrg      _mesa_unlock_texture(ctx, texObj);
32707117f1b4Smrg   }
32717117f1b4Smrg   else if (target == GL_PROXY_TEXTURE_1D) {
32727117f1b4Smrg      /* Proxy texture: check for errors and update proxy state */
32737117f1b4Smrg      GLenum error = compressed_texture_error_check(ctx, 1, target, level,
32747117f1b4Smrg                               internalFormat, width, 1, 1, border, imageSize);
32757117f1b4Smrg      if (!error) {
32767117f1b4Smrg         ASSERT(ctx->Driver.TestProxyTexImage);
32777117f1b4Smrg         error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level,
32787117f1b4Smrg                                             internalFormat, GL_NONE, GL_NONE,
32797117f1b4Smrg                                             width, 1, 1, border);
32807117f1b4Smrg      }
32817117f1b4Smrg      if (error) {
32827117f1b4Smrg         /* if error, clear all proxy texture image parameters */
32837117f1b4Smrg         struct gl_texture_image *texImage;
32847117f1b4Smrg         texImage = _mesa_get_proxy_tex_image(ctx, target, level);
32857117f1b4Smrg         if (texImage)
32867117f1b4Smrg            clear_teximage_fields(texImage);
32877117f1b4Smrg      }
32887117f1b4Smrg      else {
32897117f1b4Smrg         /* store the teximage parameters */
32907117f1b4Smrg         struct gl_texture_unit *texUnit;
32917117f1b4Smrg         struct gl_texture_object *texObj;
32927117f1b4Smrg         struct gl_texture_image *texImage;
32937117f1b4Smrg         texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
32947117f1b4Smrg	 texObj = _mesa_select_tex_object(ctx, texUnit, target);
32957117f1b4Smrg
32967117f1b4Smrg	 _mesa_lock_texture(ctx, texObj);
32977117f1b4Smrg	 {
32987117f1b4Smrg	    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
32997117f1b4Smrg	    _mesa_init_teximage_fields(ctx, target, texImage, width, 1, 1,
33007117f1b4Smrg				       border, internalFormat);
33017117f1b4Smrg	 }
33027117f1b4Smrg	 _mesa_unlock_texture(ctx, texObj);
33037117f1b4Smrg      }
33047117f1b4Smrg   }
33057117f1b4Smrg   else {
33067117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage1D(target)");
33077117f1b4Smrg      return;
33087117f1b4Smrg   }
33097117f1b4Smrg}
33107117f1b4Smrg
33117117f1b4Smrg
33127117f1b4Smrgvoid GLAPIENTRY
33137117f1b4Smrg_mesa_CompressedTexImage2DARB(GLenum target, GLint level,
33147117f1b4Smrg                              GLenum internalFormat, GLsizei width,
33157117f1b4Smrg                              GLsizei height, GLint border, GLsizei imageSize,
33167117f1b4Smrg                              const GLvoid *data)
33177117f1b4Smrg{
33187117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
33197117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
33207117f1b4Smrg
33217117f1b4Smrg   if (target == GL_TEXTURE_2D ||
33227117f1b4Smrg       (ctx->Extensions.ARB_texture_cube_map &&
33237117f1b4Smrg        target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
33247117f1b4Smrg        target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB)) {
33257117f1b4Smrg      /* non-proxy target */
33267117f1b4Smrg      struct gl_texture_unit *texUnit;
33277117f1b4Smrg      struct gl_texture_object *texObj;
33287117f1b4Smrg      struct gl_texture_image *texImage;
33297117f1b4Smrg      GLenum error = compressed_texture_error_check(ctx, 2, target, level,
33307117f1b4Smrg                          internalFormat, width, height, 1, border, imageSize);
33317117f1b4Smrg      if (error) {
33327117f1b4Smrg         _mesa_error(ctx, error, "glCompressedTexImage2D");
33337117f1b4Smrg         return;
33347117f1b4Smrg      }
33357117f1b4Smrg
33367117f1b4Smrg      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
33377117f1b4Smrg      texObj = _mesa_select_tex_object(ctx, texUnit, target);
33387117f1b4Smrg
33397117f1b4Smrg      _mesa_lock_texture(ctx, texObj);
33407117f1b4Smrg      {
33417117f1b4Smrg	 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
33427117f1b4Smrg	 if (!texImage) {
33437117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage2D");
33447117f1b4Smrg	    goto out;
33457117f1b4Smrg	 }
33467117f1b4Smrg
33477117f1b4Smrg	 if (texImage->Data) {
33487117f1b4Smrg	    ctx->Driver.FreeTexImageData( ctx, texImage );
33497117f1b4Smrg	 }
33507117f1b4Smrg	 ASSERT(texImage->Data == NULL);
33517117f1b4Smrg
33527117f1b4Smrg	 _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
33537117f1b4Smrg				    border, internalFormat);
33547117f1b4Smrg
33557117f1b4Smrg	 ASSERT(ctx->Driver.CompressedTexImage2D);
33567117f1b4Smrg	 (*ctx->Driver.CompressedTexImage2D)(ctx, target, level,
33577117f1b4Smrg					     internalFormat, width, height,
33587117f1b4Smrg					     border, imageSize, data,
33597117f1b4Smrg					     texObj, texImage);
33607117f1b4Smrg
33617117f1b4Smrg	 /* state update */
33627117f1b4Smrg	 texObj->Complete = GL_FALSE;
33637117f1b4Smrg	 ctx->NewState |= _NEW_TEXTURE;
33647117f1b4Smrg      }
33657117f1b4Smrg   out:
33667117f1b4Smrg      _mesa_unlock_texture(ctx, texObj);
33677117f1b4Smrg   }
33687117f1b4Smrg   else if (target == GL_PROXY_TEXTURE_2D ||
33697117f1b4Smrg            (target == GL_PROXY_TEXTURE_CUBE_MAP_ARB &&
33707117f1b4Smrg             ctx->Extensions.ARB_texture_cube_map)) {
33717117f1b4Smrg      /* Proxy texture: check for errors and update proxy state */
33727117f1b4Smrg      GLenum error = compressed_texture_error_check(ctx, 2, target, level,
33737117f1b4Smrg                          internalFormat, width, height, 1, border, imageSize);
33747117f1b4Smrg      if (!error) {
33757117f1b4Smrg         ASSERT(ctx->Driver.TestProxyTexImage);
33767117f1b4Smrg         error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level,
33777117f1b4Smrg                                              internalFormat, GL_NONE, GL_NONE,
33787117f1b4Smrg                                              width, height, 1, border);
33797117f1b4Smrg      }
33807117f1b4Smrg      if (error) {
33817117f1b4Smrg         /* if error, clear all proxy texture image parameters */
33827117f1b4Smrg         struct gl_texture_image *texImage;
33837117f1b4Smrg         texImage = _mesa_get_proxy_tex_image(ctx, target, level);
33847117f1b4Smrg         if (texImage)
33857117f1b4Smrg            clear_teximage_fields(texImage);
33867117f1b4Smrg      }
33877117f1b4Smrg      else {
33887117f1b4Smrg         /* store the teximage parameters */
33897117f1b4Smrg         struct gl_texture_unit *texUnit;
33907117f1b4Smrg         struct gl_texture_object *texObj;
33917117f1b4Smrg         struct gl_texture_image *texImage;
33927117f1b4Smrg         texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
33937117f1b4Smrg	 texObj = _mesa_select_tex_object(ctx, texUnit, target);
33947117f1b4Smrg
33957117f1b4Smrg	 _mesa_lock_texture(ctx, texObj);
33967117f1b4Smrg	 {
33977117f1b4Smrg	    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
33987117f1b4Smrg	    _mesa_init_teximage_fields(ctx, target, texImage, width, height, 1,
33997117f1b4Smrg				       border, internalFormat);
34007117f1b4Smrg	 }
34017117f1b4Smrg	 _mesa_unlock_texture(ctx, texObj);
34027117f1b4Smrg      }
34037117f1b4Smrg   }
34047117f1b4Smrg   else {
34057117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage2D(target)");
34067117f1b4Smrg      return;
34077117f1b4Smrg   }
34087117f1b4Smrg}
34097117f1b4Smrg
34107117f1b4Smrg
34117117f1b4Smrgvoid GLAPIENTRY
34127117f1b4Smrg_mesa_CompressedTexImage3DARB(GLenum target, GLint level,
34137117f1b4Smrg                              GLenum internalFormat, GLsizei width,
34147117f1b4Smrg                              GLsizei height, GLsizei depth, GLint border,
34157117f1b4Smrg                              GLsizei imageSize, const GLvoid *data)
34167117f1b4Smrg{
34177117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
34187117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
34197117f1b4Smrg
34207117f1b4Smrg   if (target == GL_TEXTURE_3D) {
34217117f1b4Smrg      /* non-proxy target */
34227117f1b4Smrg      struct gl_texture_unit *texUnit;
34237117f1b4Smrg      struct gl_texture_object *texObj;
34247117f1b4Smrg      struct gl_texture_image *texImage;
34257117f1b4Smrg      GLenum error = compressed_texture_error_check(ctx, 3, target, level,
34267117f1b4Smrg                      internalFormat, width, height, depth, border, imageSize);
34277117f1b4Smrg      if (error) {
34287117f1b4Smrg         _mesa_error(ctx, error, "glCompressedTexImage3D");
34297117f1b4Smrg         return;
34307117f1b4Smrg      }
34317117f1b4Smrg
34327117f1b4Smrg      texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
34337117f1b4Smrg      texObj = _mesa_select_tex_object(ctx, texUnit, target);
34347117f1b4Smrg      _mesa_lock_texture(ctx, texObj);
34357117f1b4Smrg      {
34367117f1b4Smrg	 texImage = _mesa_get_tex_image(ctx, texObj, target, level);
34377117f1b4Smrg	 if (!texImage) {
34387117f1b4Smrg	    _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCompressedTexImage3D");
34397117f1b4Smrg	    goto out;
34407117f1b4Smrg	 }
34417117f1b4Smrg
34427117f1b4Smrg	 if (texImage->Data) {
34437117f1b4Smrg	    ctx->Driver.FreeTexImageData( ctx, texImage );
34447117f1b4Smrg	 }
34457117f1b4Smrg	 ASSERT(texImage->Data == NULL);
34467117f1b4Smrg
34477117f1b4Smrg	 _mesa_init_teximage_fields(ctx, target, texImage, width, height, depth,
34487117f1b4Smrg				    border, internalFormat);
34497117f1b4Smrg
34507117f1b4Smrg	 ASSERT(ctx->Driver.CompressedTexImage3D);
34517117f1b4Smrg	 (*ctx->Driver.CompressedTexImage3D)(ctx, target, level,
34527117f1b4Smrg					     internalFormat,
34537117f1b4Smrg					     width, height, depth,
34547117f1b4Smrg					     border, imageSize, data,
34557117f1b4Smrg					     texObj, texImage);
34567117f1b4Smrg
34577117f1b4Smrg	 /* state update */
34587117f1b4Smrg	 texObj->Complete = GL_FALSE;
34597117f1b4Smrg	 ctx->NewState |= _NEW_TEXTURE;
34607117f1b4Smrg      }
34617117f1b4Smrg   out:
34627117f1b4Smrg      _mesa_unlock_texture(ctx, texObj);
34637117f1b4Smrg   }
34647117f1b4Smrg   else if (target == GL_PROXY_TEXTURE_3D) {
34657117f1b4Smrg      /* Proxy texture: check for errors and update proxy state */
34667117f1b4Smrg      GLenum error = compressed_texture_error_check(ctx, 3, target, level,
34677117f1b4Smrg                      internalFormat, width, height, depth, border, imageSize);
34687117f1b4Smrg      if (!error) {
34697117f1b4Smrg         ASSERT(ctx->Driver.TestProxyTexImage);
34707117f1b4Smrg         error = !(*ctx->Driver.TestProxyTexImage)(ctx, target, level,
34717117f1b4Smrg                                             internalFormat, GL_NONE, GL_NONE,
34727117f1b4Smrg                                             width, height, depth, border);
34737117f1b4Smrg      }
34747117f1b4Smrg      if (error) {
34757117f1b4Smrg         /* if error, clear all proxy texture image parameters */
34767117f1b4Smrg         struct gl_texture_image *texImage;
34777117f1b4Smrg         texImage = _mesa_get_proxy_tex_image(ctx, target, level);
34787117f1b4Smrg         if (texImage)
34797117f1b4Smrg            clear_teximage_fields(texImage);
34807117f1b4Smrg      }
34817117f1b4Smrg      else {
34827117f1b4Smrg         /* store the teximage parameters */
34837117f1b4Smrg         struct gl_texture_unit *texUnit;
34847117f1b4Smrg         struct gl_texture_object *texObj;
34857117f1b4Smrg         struct gl_texture_image *texImage;
34867117f1b4Smrg         texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
34877117f1b4Smrg	 texObj = _mesa_select_tex_object(ctx, texUnit, target);
34887117f1b4Smrg	 _mesa_lock_texture(ctx, texObj);
34897117f1b4Smrg	 {
34907117f1b4Smrg	    texImage = _mesa_select_tex_image(ctx, texObj, target, level);
34917117f1b4Smrg	    _mesa_init_teximage_fields(ctx, target, texImage, width, height,
34927117f1b4Smrg				       depth, border, internalFormat);
34937117f1b4Smrg	 }
34947117f1b4Smrg	 _mesa_unlock_texture(ctx, texObj);
34957117f1b4Smrg      }
34967117f1b4Smrg   }
34977117f1b4Smrg   else {
34987117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage3D(target)");
34997117f1b4Smrg      return;
35007117f1b4Smrg   }
35017117f1b4Smrg}
35027117f1b4Smrg
35037117f1b4Smrg
35047117f1b4Smrgvoid GLAPIENTRY
35057117f1b4Smrg_mesa_CompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset,
35067117f1b4Smrg                                 GLsizei width, GLenum format,
35077117f1b4Smrg                                 GLsizei imageSize, const GLvoid *data)
35087117f1b4Smrg{
35097117f1b4Smrg   struct gl_texture_unit *texUnit;
35107117f1b4Smrg   struct gl_texture_object *texObj;
35117117f1b4Smrg   struct gl_texture_image *texImage;
35127117f1b4Smrg   GLenum error;
35137117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
35147117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
35157117f1b4Smrg
35167117f1b4Smrg   error = compressed_subtexture_error_check(ctx, 1, target, level,
35177117f1b4Smrg                                             xoffset, 0, 0, /* pos */
35187117f1b4Smrg                                             width, 1, 1,   /* size */
35197117f1b4Smrg                                             format, imageSize);
35207117f1b4Smrg   if (error) {
35217117f1b4Smrg      _mesa_error(ctx, error, "glCompressedTexSubImage1D");
35227117f1b4Smrg      return;
35237117f1b4Smrg   }
35247117f1b4Smrg
35257117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
35267117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
35277117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
35287117f1b4Smrg   {
35297117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
35307117f1b4Smrg      assert(texImage);
35317117f1b4Smrg
35327117f1b4Smrg      if ((GLint) format != texImage->InternalFormat) {
35337117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
35347117f1b4Smrg		     "glCompressedTexSubImage1D(format)");
35357117f1b4Smrg	 goto out;
35367117f1b4Smrg      }
35377117f1b4Smrg
35387117f1b4Smrg      if ((width == 1 || width == 2) && (GLuint) width != texImage->Width) {
35397117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage1D(width)");
35407117f1b4Smrg	 goto out;
35417117f1b4Smrg      }
35427117f1b4Smrg
35437117f1b4Smrg      if (width == 0)
35447117f1b4Smrg	 goto out;  /* no-op, not an error */
35457117f1b4Smrg
35467117f1b4Smrg      if (ctx->Driver.CompressedTexSubImage1D) {
35477117f1b4Smrg	 (*ctx->Driver.CompressedTexSubImage1D)(ctx, target, level,
35487117f1b4Smrg						xoffset, width,
35497117f1b4Smrg						format, imageSize, data,
35507117f1b4Smrg						texObj, texImage);
35517117f1b4Smrg      }
35527117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
35537117f1b4Smrg   }
35547117f1b4Smrg out:
35557117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
35567117f1b4Smrg}
35577117f1b4Smrg
35587117f1b4Smrg
35597117f1b4Smrgvoid GLAPIENTRY
35607117f1b4Smrg_mesa_CompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset,
35617117f1b4Smrg                                 GLint yoffset, GLsizei width, GLsizei height,
35627117f1b4Smrg                                 GLenum format, GLsizei imageSize,
35637117f1b4Smrg                                 const GLvoid *data)
35647117f1b4Smrg{
35657117f1b4Smrg   struct gl_texture_unit *texUnit;
35667117f1b4Smrg   struct gl_texture_object *texObj;
35677117f1b4Smrg   struct gl_texture_image *texImage;
35687117f1b4Smrg   GLenum error;
35697117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
35707117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
35717117f1b4Smrg
35727117f1b4Smrg   error = compressed_subtexture_error_check(ctx, 2, target, level,
35737117f1b4Smrg                                             xoffset, yoffset, 0, /* pos */
35747117f1b4Smrg                                             width, height, 1,    /* size */
35757117f1b4Smrg                                             format, imageSize);
35767117f1b4Smrg   if (error) {
35777117f1b4Smrg      /* XXX proxy target? */
35787117f1b4Smrg      _mesa_error(ctx, error, "glCompressedTexSubImage2D");
35797117f1b4Smrg      return;
35807117f1b4Smrg   }
35817117f1b4Smrg
35827117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
35837117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
35847117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
35857117f1b4Smrg   {
35867117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
35877117f1b4Smrg      assert(texImage);
35887117f1b4Smrg
35897117f1b4Smrg      if ((GLint) format != texImage->InternalFormat) {
35907117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
35917117f1b4Smrg		     "glCompressedTexSubImage2D(format)");
35927117f1b4Smrg	 goto out;
35937117f1b4Smrg      }
35947117f1b4Smrg
35957117f1b4Smrg      if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) ||
35967117f1b4Smrg	  ((height == 1 || height == 2) && (GLuint) height != texImage->Height)) {
35977117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage2D(size)");
35987117f1b4Smrg	 goto out;
35997117f1b4Smrg      }
36007117f1b4Smrg
36017117f1b4Smrg      if (width == 0 || height == 0)
36027117f1b4Smrg	 goto out;  /* no-op, not an error */
36037117f1b4Smrg
36047117f1b4Smrg      if (ctx->Driver.CompressedTexSubImage2D) {
36057117f1b4Smrg	 (*ctx->Driver.CompressedTexSubImage2D)(ctx, target, level,
36067117f1b4Smrg						xoffset, yoffset, width, height,
36077117f1b4Smrg						format, imageSize, data,
36087117f1b4Smrg						texObj, texImage);
36097117f1b4Smrg      }
36107117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
36117117f1b4Smrg   }
36127117f1b4Smrg out:
36137117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
36147117f1b4Smrg}
36157117f1b4Smrg
36167117f1b4Smrg
36177117f1b4Smrgvoid GLAPIENTRY
36187117f1b4Smrg_mesa_CompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset,
36197117f1b4Smrg                                 GLint yoffset, GLint zoffset, GLsizei width,
36207117f1b4Smrg                                 GLsizei height, GLsizei depth, GLenum format,
36217117f1b4Smrg                                 GLsizei imageSize, const GLvoid *data)
36227117f1b4Smrg{
36237117f1b4Smrg   struct gl_texture_unit *texUnit;
36247117f1b4Smrg   struct gl_texture_object *texObj;
36257117f1b4Smrg   struct gl_texture_image *texImage;
36267117f1b4Smrg   GLenum error;
36277117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
36287117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
36297117f1b4Smrg
36307117f1b4Smrg   error = compressed_subtexture_error_check(ctx, 3, target, level,
36317117f1b4Smrg                                             xoffset, yoffset, zoffset,/*pos*/
36327117f1b4Smrg                                             width, height, depth, /*size*/
36337117f1b4Smrg                                             format, imageSize);
36347117f1b4Smrg   if (error) {
36357117f1b4Smrg      _mesa_error(ctx, error, "glCompressedTexSubImage2D");
36367117f1b4Smrg      return;
36377117f1b4Smrg   }
36387117f1b4Smrg
36397117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
36407117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
36417117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
36427117f1b4Smrg   {
36437117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
36447117f1b4Smrg      assert(texImage);
36457117f1b4Smrg
36467117f1b4Smrg      if ((GLint) format != texImage->InternalFormat) {
36477117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION,
36487117f1b4Smrg		     "glCompressedTexSubImage3D(format)");
36497117f1b4Smrg	 goto out;
36507117f1b4Smrg      }
36517117f1b4Smrg
36527117f1b4Smrg      if (((width == 1 || width == 2) && (GLuint) width != texImage->Width) ||
36537117f1b4Smrg	  ((height == 1 || height == 2) && (GLuint) height != texImage->Height) ||
36547117f1b4Smrg	  ((depth == 1 || depth == 2) && (GLuint) depth != texImage->Depth)) {
36557117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage3D(size)");
36567117f1b4Smrg	 goto out;
36577117f1b4Smrg      }
36587117f1b4Smrg
36597117f1b4Smrg      if (width == 0 || height == 0 || depth == 0)
36607117f1b4Smrg	 goto out;  /* no-op, not an error */
36617117f1b4Smrg
36627117f1b4Smrg      if (ctx->Driver.CompressedTexSubImage3D) {
36637117f1b4Smrg	 (*ctx->Driver.CompressedTexSubImage3D)(ctx, target, level,
36647117f1b4Smrg						xoffset, yoffset, zoffset,
36657117f1b4Smrg						width, height, depth,
36667117f1b4Smrg						format, imageSize, data,
36677117f1b4Smrg						texObj, texImage);
36687117f1b4Smrg      }
36697117f1b4Smrg      ctx->NewState |= _NEW_TEXTURE;
36707117f1b4Smrg   }
36717117f1b4Smrg out:
36727117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
36737117f1b4Smrg}
36747117f1b4Smrg
36757117f1b4Smrg
36767117f1b4Smrgvoid GLAPIENTRY
36777117f1b4Smrg_mesa_GetCompressedTexImageARB(GLenum target, GLint level, GLvoid *img)
36787117f1b4Smrg{
36797117f1b4Smrg   const struct gl_texture_unit *texUnit;
36807117f1b4Smrg   struct gl_texture_object *texObj;
36817117f1b4Smrg   struct gl_texture_image *texImage;
36827117f1b4Smrg   GLint maxLevels;
36837117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
36847117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
36857117f1b4Smrg
36867117f1b4Smrg
36877117f1b4Smrg   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
36887117f1b4Smrg   texObj = _mesa_select_tex_object(ctx, texUnit, target);
36897117f1b4Smrg   if (!texObj) {
36907117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB");
36917117f1b4Smrg      return;
36927117f1b4Smrg   }
36937117f1b4Smrg
36947117f1b4Smrg   maxLevels = _mesa_max_texture_levels(ctx, target);
36957117f1b4Smrg   ASSERT(maxLevels > 0); /* 0 indicates bad target, caught above */
36967117f1b4Smrg
36977117f1b4Smrg   if (level < 0 || level >= maxLevels) {
36987117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)");
36997117f1b4Smrg      return;
37007117f1b4Smrg   }
37017117f1b4Smrg
37027117f1b4Smrg   if (_mesa_is_proxy_texture(target)) {
37037117f1b4Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetCompressedTexImageARB(target)");
37047117f1b4Smrg      return;
37057117f1b4Smrg   }
37067117f1b4Smrg
37077117f1b4Smrg
37087117f1b4Smrg   _mesa_lock_texture(ctx, texObj);
37097117f1b4Smrg   {
37107117f1b4Smrg      texImage = _mesa_select_tex_image(ctx, texObj, target, level);
37117117f1b4Smrg      if (!texImage) {
37127117f1b4Smrg	 /* probably invalid mipmap level */
37137117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_VALUE, "glGetCompressedTexImageARB(level)");
37147117f1b4Smrg	 goto out;
37157117f1b4Smrg      }
37167117f1b4Smrg
37177117f1b4Smrg      if (!texImage->IsCompressed) {
37187117f1b4Smrg	 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetCompressedTexImageARB");
37197117f1b4Smrg	 goto out;
37207117f1b4Smrg      }
37217117f1b4Smrg
37227117f1b4Smrg      /* this typically calls _mesa_get_compressed_teximage() */
37237117f1b4Smrg      ctx->Driver.GetCompressedTexImage(ctx, target, level, img, texObj,texImage);
37247117f1b4Smrg   }
37257117f1b4Smrg out:
37267117f1b4Smrg   _mesa_unlock_texture(ctx, texObj);
37277117f1b4Smrg}
3728