mesa: fix num_draw_buffers==0 in fixed-function fragment program generation
[mesa.git] / src / mesa / main / teximage.c
index e5f23dd18fe08e3cd95f6da89e37fd98d59fbdd4..47d509396a788857a4e2a4d3416b4053cb4229fb 100644 (file)
@@ -40,6 +40,7 @@
 #include "image.h"
 #include "imports.h"
 #include "macros.h"
+#include "mfeatures.h"
 #include "state.h"
 #include "texcompress.h"
 #include "texfetch.h"
@@ -340,11 +341,11 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat )
          return GL_RGBA;
       case GL_SLUMINANCE_ALPHA_EXT:
       case GL_SLUMINANCE8_ALPHA8_EXT:
-      case GL_COMPRESSED_SLUMINANCE_EXT:
       case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT:
          return GL_LUMINANCE_ALPHA;
       case GL_SLUMINANCE_EXT:
       case GL_SLUMINANCE8_EXT:
+      case GL_COMPRESSED_SLUMINANCE_EXT:
          return GL_LUMINANCE;
       default:
          ; /* fallthrough */
@@ -931,8 +932,8 @@ _mesa_max_texture_levels(struct gl_context *ctx, GLenum target)
 /**
  * Return number of dimensions per mipmap level for the given texture target.
  */
-static GLint
-get_texture_dimensions(GLenum target)
+GLint
+_mesa_get_texture_dimensions(GLenum target)
 {
    switch (target) {
    case GL_TEXTURE_1D:
@@ -1157,7 +1158,7 @@ _mesa_init_teximage_fields(struct gl_context *ctx, GLenum target,
 
    img->TexFormat = format;
 
-   dims = get_texture_dimensions(target);
+   dims = _mesa_get_texture_dimensions(target);
 
    _mesa_set_fetch_functions(img, dims);
 }
@@ -1219,94 +1220,110 @@ _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level,
    switch (target) {
    case GL_PROXY_TEXTURE_1D:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width >0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or level */
+      if (width < 2 * border || width > 2 + maxSize)
          return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
+         return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_2D:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or height or level */
+      if (width < 2 * border || width > 2 + maxSize)
          return GL_FALSE;
+      if (height < 2 * border || height > 2 + maxSize)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
+         return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_3D:
       maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          depth < 2 * border || depth > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           depth > 0 && !_mesa_is_pow_two(depth - 2 * border)) ||
-          level >= ctx->Const.Max3DTextureLevels) {
-         /* bad width or height or depth or level */
+      if (width < 2 * border || width > 2 + maxSize)
+         return GL_FALSE;
+      if (height < 2 * border || height > 2 + maxSize)
+         return GL_FALSE;
+      if (depth < 2 * border || depth > 2 + maxSize)
          return GL_FALSE;
+      if (level >= ctx->Const.Max3DTextureLevels)
+         return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
+         if (depth > 0 && !_mesa_is_pow_two(depth - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_RECTANGLE_NV:
-      if (width < 0 || width > ctx->Const.MaxTextureRectSize ||
-          height < 0 || height > ctx->Const.MaxTextureRectSize ||
-          level != 0) {
-         /* bad width or height or level */
+      maxSize = ctx->Const.MaxTextureRectSize;
+      if (width < 0 || width > maxSize)
+         return GL_FALSE;
+      if (height < 0 || height > maxSize)
+         return GL_FALSE;
+      if (level != 0)
          return GL_FALSE;
-      }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
       maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          level >= ctx->Const.MaxCubeTextureLevels) {
-         /* bad width or height */
+      if (width < 2 * border || width > 2 + maxSize)
+         return GL_FALSE;
+      if (height < 2 * border || height > 2 + maxSize)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxCubeTextureLevels)
          return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or level */
+      if (width < 2 * border || width > 2 + maxSize)
          return GL_FALSE;
-      }
-
-      if (height < 1 || height > ctx->Const.MaxArrayTextureLayers) {
+      if (height < 1 || height > ctx->Const.MaxArrayTextureLayers)
+         return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
          return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    case GL_PROXY_TEXTURE_2D_ARRAY_EXT:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
-      if (width < 2 * border || width > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           width > 0 && !_mesa_is_pow_two(width - 2 * border)) ||
-          height < 2 * border || height > 2 + maxSize ||
-          (!ctx->Extensions.ARB_texture_non_power_of_two &&
-           height > 0 && !_mesa_is_pow_two(height - 2 * border)) ||
-          level >= ctx->Const.MaxTextureLevels) {
-         /* bad width or height or level */
+      if (width < 2 * border || width > 2 + maxSize)
          return GL_FALSE;
-      }
-      if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) {
+      if (height < 2 * border || height > 2 + maxSize)
+         return GL_FALSE;
+      if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers)
          return GL_FALSE;
+      if (level >= ctx->Const.MaxTextureLevels)
+         return GL_FALSE;
+      if (!ctx->Extensions.ARB_texture_non_power_of_two) {
+         if (width > 0 && !_mesa_is_pow_two(width - 2 * border))
+            return GL_FALSE;
+         if (height > 0 && !_mesa_is_pow_two(height - 2 * border))
+            return GL_FALSE;
       }
       return GL_TRUE;
+
    default:
       _mesa_problem(ctx, "Invalid target in _mesa_test_proxy_teximage");
       return GL_FALSE;
@@ -1333,15 +1350,19 @@ legal_texture_size(struct gl_context *ctx, gl_format format,
 
 
 /**
- * Helper function to determine whether a target supports compressed textures
+ * Helper function to determine whether a target and specific compression
+ * format are supported.
  */
 static GLboolean
-target_can_be_compressed(struct gl_context *ctx, GLenum target)
+target_can_be_compressed(const struct gl_context *ctx, GLenum target,
+                         GLenum intFormat)
 {
+   (void) intFormat;  /* not used yet */
+
    switch (target) {
    case GL_TEXTURE_2D:
    case GL_PROXY_TEXTURE_2D:
-      return GL_TRUE;
+      return GL_TRUE; /* true for any compressed format so far */
    case GL_PROXY_TEXTURE_CUBE_MAP:
    case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
    case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
@@ -1417,10 +1438,12 @@ legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target)
 
 /**
  * Check if the given texture target value is legal for a
- * glCopyTexImage1/2D call.
+ * glTexSubImage, glCopyTexSubImage or glCopyTexImage call.
+ * The difference compared to legal_teximage_target() above is that
+ * proxy targets are not supported.
  */
 static GLboolean
-legal_copyteximage_target(struct gl_context *ctx, GLuint dims, GLenum target)
+legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target)
 {
    switch (dims) {
    case 1:
@@ -1443,58 +1466,23 @@ legal_copyteximage_target(struct gl_context *ctx, GLuint dims, GLenum target)
       default:
          return GL_FALSE;
       }
-   default:
-      _mesa_problem(ctx, "invalid dims=%u in legal_copyteximage_target()", dims);
-      return GL_FALSE;
-   }
-}
-
-
-/**
- * Check if the given texture target value is legal for a
- * glCompressedTexImage1/2/3D call.
- */
-static GLboolean
-legal_compressed_teximage_target(struct gl_context *ctx, GLuint dims,
-                                 GLenum target)
-{
-   switch (dims) {
-   case 1:
-      return GL_FALSE;  /* No 1D compresssed textures yet */
-   case 2:
+   case 3:
       switch (target) {
-      case GL_TEXTURE_2D:
-      case GL_PROXY_TEXTURE_2D:
+      case GL_TEXTURE_3D:
          return GL_TRUE;
-      case GL_PROXY_TEXTURE_CUBE_MAP:
-      case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-      case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-      case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-      case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-         return ctx->Extensions.ARB_texture_cube_map;
-      case GL_TEXTURE_RECTANGLE_NV:
-      case GL_PROXY_TEXTURE_RECTANGLE_NV:
-         return GL_FALSE; /* not supported yet */
-      case GL_TEXTURE_1D_ARRAY_EXT:
-      case GL_PROXY_TEXTURE_1D_ARRAY_EXT:
-         return GL_FALSE; /* not supported yet */
+      case GL_TEXTURE_2D_ARRAY_EXT:
+         return ctx->Extensions.MESA_texture_array;
       default:
          return GL_FALSE;
       }
-   case 3:
-      return GL_FALSE;  /* No 3D compressed textures yet */
    default:
-      _mesa_problem(ctx,
-                    "invalid dims=%u in legal_compressed_teximage_target()",
+      _mesa_problem(ctx, "invalid dims=%u in legal_texsubimage_target()",
                     dims);
       return GL_FALSE;
    }
 }
 
 
-
 /**
  * Test the glTexImage[123]D() parameters for errors.
  * 
@@ -1671,9 +1659,10 @@ texture_error_check( struct gl_context *ctx,
 
    /* additional checks for compressed textures */
    if (_mesa_is_compressed_format(ctx, internalFormat)) {
-      if (!target_can_be_compressed(ctx, target) && !isProxy) {
-         _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glTexImage%dD(target)", dimensions);
+      if (!target_can_be_compressed(ctx, target, internalFormat)) {
+         if (!isProxy)
+            _mesa_error(ctx, GL_INVALID_ENUM,
+                        "glTexImage%dD(target)", dimensions);
          return GL_TRUE;
       }
       if (border != 0) {
@@ -1824,13 +1813,6 @@ subtexture_error_check2( struct gl_context *ctx, GLuint dimensions,
    if (_mesa_is_format_compressed(destTex->TexFormat)) {
       GLuint bw, bh;
 
-      if (!target_can_be_compressed(ctx, target)) {
-         _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glTexSubImage%dD(target=%s)", dimensions,
-                     _mesa_lookup_enum_by_nr(target));
-         return GL_TRUE;
-      }
-
       /* do tests which depend on compression block size */
       _mesa_get_format_block_size(destTex->TexFormat, &bw, &bh);
 
@@ -1887,7 +1869,7 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
    GLint format;
 
    /* check target */
-   if (!legal_copyteximage_target(ctx, dimensions, target)) {
+   if (!legal_texsubimage_target(ctx, dimensions, target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexImage%uD(target=%s)",
                   dimensions, _mesa_lookup_enum_by_nr(target));
       return GL_TRUE;
@@ -1953,7 +1935,7 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions,
    }
 
    if (_mesa_is_compressed_format(ctx, internalFormat)) {
-      if (!target_can_be_compressed(ctx, target)) {
+      if (!target_can_be_compressed(ctx, target, internalFormat)) {
          _mesa_error(ctx, GL_INVALID_ENUM,
                      "glCopyTexImage%dD(target)", dimensions);
          return GL_TRUE;
@@ -2013,8 +1995,7 @@ copytexsubimage_error_check1( struct gl_context *ctx, GLuint dimensions,
    }
 
    /* check target (proxies not allowed) */
-   if (!legal_teximage_target(ctx, dimensions, target) ||
-       _mesa_is_proxy_texture(target)) {
+   if (!legal_texsubimage_target(ctx, dimensions, target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glCopyTexSubImage%uD(target=%s)",
                   dimensions, _mesa_lookup_enum_by_nr(target));
       return GL_TRUE;
@@ -2106,11 +2087,6 @@ copytexsubimage_error_check2( struct gl_context *ctx, GLuint dimensions,
    }
 
    if (_mesa_is_format_compressed(teximage->TexFormat)) {
-      if (!target_can_be_compressed(ctx, target)) {
-         _mesa_error(ctx, GL_INVALID_ENUM,
-                     "glCopyTexSubImage%dD(target)", dimensions);
-         return GL_TRUE;
-      }
       /* offset must be multiple of 4 */
       if ((xoffset & 3) || (yoffset & 3)) {
          _mesa_error(ctx, GL_INVALID_VALUE,
@@ -2615,8 +2591,7 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level,
                   _mesa_lookup_enum_by_nr(type), pixels);
 
    /* check target (proxies not allowed) */
-   if (!legal_teximage_target(ctx, dims, target) ||
-       _mesa_is_proxy_texture(target)) {
+   if (!legal_texsubimage_target(ctx, dims, target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glTexSubImage%uD(target=%s)",
                   dims, _mesa_lookup_enum_by_nr(target));
       return;
@@ -2999,6 +2974,10 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
    if (level < 0 || level >= maxLevels)
       return GL_INVALID_VALUE;
 
+   if (!target_can_be_compressed(ctx, target, internalFormat)) {
+      return GL_INVALID_ENUM;
+   }
+
    /* This will detect any invalid internalFormat value */
    if (!_mesa_is_compressed_format(ctx, internalFormat))
       return GL_INVALID_ENUM;
@@ -3016,17 +2995,42 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions,
        target <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB && width != height)
       return GL_INVALID_VALUE;
 
+   /* check image size against compression block size */
+   {
+      gl_format texFormat =
+         ctx->Driver.ChooseTextureFormat(ctx, internalFormat,
+                                         GL_NONE, GL_NONE);
+      GLuint bw, bh;
+
+      _mesa_get_format_block_size(texFormat, &bw, &bh);
+      if ((width > bw && width % bw > 0) ||
+          (height > bh && height % bh > 0)) {
+         /*
+          * Per GL_ARB_texture_compression:  GL_INVALID_OPERATION is
+          * generated [...] if any parameter combinations are not
+          * supported by the specific compressed internal format. 
+          */
+         return GL_INVALID_OPERATION;
+      }
+   }
+
    /* check image sizes */
    if (!ctx->Driver.TestProxyTexImage(ctx, proxyTarget, level,
                                       internalFormat, GL_NONE, GL_NONE,
                                       width, height, depth, border)) {
-      return GL_INVALID_VALUE;
+      /* See error comment above */
+      return GL_INVALID_OPERATION;
    }
 
    /* check image size in bytes */
    expectedSize = compressed_tex_size(width, height, depth, internalFormat);
-   if (expectedSize != imageSize)
+   if (expectedSize != imageSize) {
+      /* Per GL_ARB_texture_compression:  GL_INVALID_VALUE is generated [...]
+       * if <imageSize> is not consistent with the format, dimensions, and
+       * contents of the specified image.
+       */
       return GL_INVALID_VALUE;
+   }
 
    return GL_NO_ERROR;
 }
@@ -3191,7 +3195,7 @@ compressedteximage(struct gl_context *ctx, GLuint dims,
                   width, height, depth, border, imageSize, data);
 
    /* check target */
-   if (!legal_compressed_teximage_target(ctx, dims, target)) {
+   if (!legal_teximage_target(ctx, dims, target)) {
       _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target=%s)",
                   dims, _mesa_lookup_enum_by_nr(target));
       return;