Implemented GL_ARB_texture_non_power_of_two (except for auto mipmap generation).
authorBrian Paul <brian.paul@tungstengraphics.com>
Thu, 3 Jul 2003 03:05:48 +0000 (03:05 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Thu, 3 Jul 2003 03:05:48 +0000 (03:05 +0000)
src/mesa/drivers/x11/xm_dd.c
src/mesa/main/extensions.c
src/mesa/main/mtypes.h
src/mesa/main/teximage.c
src/mesa/main/texobj.c
src/mesa/swrast/s_texture.c
src/mesa/swrast/s_triangle.c

index 30a8b51723f97d8b3f5bf5f69f11f04b433a7161..3a3375f34c4e7520fa2cf94ab561416b993fcf38 100644 (file)
@@ -937,9 +937,15 @@ test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
    if (target == GL_PROXY_TEXTURE_3D) {
       /* special case for 3D textures */
       if (width * height * depth > 512 * 512 * 64 ||
-          width  < 2 * border || _mesa_bitcount(width  - 2 * border) != 1 ||
-          height < 2 * border || _mesa_bitcount(height - 2 * border) != 1 ||
-          depth  < 2 * border || _mesa_bitcount(depth  - 2 * border) != 1) {
+          width  < 2 * border ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(width  - 2 * border) != 1) ||
+          height < 2 * border ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(height - 2 * border) != 1) ||
+          depth  < 2 * border ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(depth  - 2 * border) != 1)) {
          /* Bad size, or too many texels */
          return GL_FALSE;
       }
index 4c0faf3a18dd1d64572914ac088ef157852fef9c..75972c755934c6e20a15725749c32a58ea1e2158 100644 (file)
@@ -57,6 +57,7 @@ static const struct {
    { OFF, "GL_ARB_texture_env_crossbar",       F(ARB_texture_env_crossbar) },
    { OFF, "GL_ARB_texture_env_dot3",           F(ARB_texture_env_dot3) },
    { OFF, "GL_ARB_texture_mirrored_repeat",    F(ARB_texture_mirrored_repeat)},
+   { OFF, "GL_ARB_texture_non_power_of_two",   F(ARB_texture_non_power_of_two)},
    { ON,  "GL_ARB_transpose_matrix",           0 },
    { OFF, "GL_ARB_vertex_buffer_object",       F(ARB_vertex_buffer_object) },
    { OFF, "GL_ARB_vertex_program",             F(ARB_vertex_program) },
@@ -163,6 +164,7 @@ _mesa_enable_sw_extensions(GLcontext *ctx)
    ctx->Extensions.ARB_texture_env_crossbar = GL_TRUE;
    ctx->Extensions.ARB_texture_env_dot3 = GL_TRUE;
    ctx->Extensions.ARB_texture_mirrored_repeat = GL_TRUE;
+   ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
 #if FEATURE_ARB_vertex_program
    /*ctx->Extensions.ARB_vertex_program = GL_TRUE;*/
 #endif
@@ -291,6 +293,7 @@ _mesa_enable_1_5_extensions(GLcontext *ctx)
 {
    ctx->Extensions.ARB_occlusion_query = GL_TRUE;
    ctx->Extensions.ARB_vertex_buffer_object = GL_TRUE;
+   ctx->Extensions.ARB_texture_non_power_of_two = GL_TRUE;
 }
 
 
index 2c73d989627499b1fb6b046ad36deca3a06eeaa0..c116228bf8501c3e7dc1f415c767d8fa7eb664f2 100644 (file)
@@ -1469,6 +1469,7 @@ struct gl_extensions {
    GLboolean ARB_texture_env_crossbar;
    GLboolean ARB_texture_env_dot3;
    GLboolean ARB_texture_mirrored_repeat;
+   GLboolean ARB_texture_non_power_of_two;
    GLboolean ARB_vertex_buffer_object;
    GLboolean ARB_vertex_program;
    GLboolean ARB_window_pos;
index 1c10aaea016500fa377739784a6e9a3d17def351..d731e12ad3bfeba14c433b6a124d7db7540c1fb6 100644 (file)
@@ -103,9 +103,8 @@ static void PrintTexture(GLcontext *ctx, const struct gl_texture_image *img)
 
 
 /*
- * Compute log base 2 of n.
- * If n isn't an exact power of two return -1.
- * If n < 0 return -1.
+ * Compute floor(log_base_2(n)).
+ * If n <= 0 return -1.
  */
 static int
 logbase2( int n )
@@ -113,7 +112,7 @@ logbase2( int n )
    GLint i = 1;
    GLint log2 = 0;
 
-   if (n < 0) {
+   if (n <= 0) {
       return -1;
    }
 
@@ -122,7 +121,7 @@ logbase2( int n )
       log2++;
    }
    if (i != n) {
-      return -1;
+      return log2 - 1;
    }
    else {
       return log2;
@@ -820,6 +819,7 @@ clear_teximage_fields(struct gl_texture_image *img)
 
 /*
  * Initialize basic fields of the gl_texture_image struct.
+ * Note: width, height and depth include the border.
  */
 void
 _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
@@ -845,9 +845,9 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
       img->DepthLog2 = 0;
    else
       img->DepthLog2 = logbase2(depth - 2 * border);
-   img->Width2 = 1 << img->WidthLog2;
-   img->Height2 = 1 << img->HeightLog2;
-   img->Depth2 = 1 << img->DepthLog2;
+   img->Width2 = width - 2 * border; /*1 << img->WidthLog2;*/
+   img->Height2 = height - 2 * border; /*1 << img->HeightLog2;*/
+   img->Depth2 = depth - 2 * border; /*1 << img->DepthLog2;*/
    img->MaxLog2 = MAX2(img->WidthLog2, img->HeightLog2);
    img->IsCompressed = is_compressed_format(internalFormat);
    if (img->IsCompressed)
@@ -856,6 +856,13 @@ _mesa_init_teximage_fields(GLcontext *ctx, GLenum target,
    else
       img->CompressedSize = 0;
 
+   if ((width == 1 || _mesa_bitcount(width - 2 * border) == 1) &&
+       (height == 1 || _mesa_bitcount(height - 2 * border) == 1) &&
+       (depth == 1 || _mesa_bitcount(depth - 2 * border) == 1))
+      img->_IsPowerOfTwo = GL_TRUE;
+   else
+      img->_IsPowerOfTwo = GL_FALSE;
+
    /* Compute Width/Height/DepthScale for mipmap lod computation */
    if (target == GL_TEXTURE_RECTANGLE_NV) {
       /* scale = 1.0 since texture coords directly map to texels */
@@ -906,7 +913,8 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
    case GL_PROXY_TEXTURE_1D:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
-          _mesa_bitcount(width - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(width - 2 * border) != 1) ||
           level >= ctx->Const.MaxTextureLevels) {
          /* bad width or level */
          return GL_FALSE;
@@ -915,9 +923,11 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
    case GL_PROXY_TEXTURE_2D:
       maxSize = 1 << (ctx->Const.MaxTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
-          _mesa_bitcount(width - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
-          _mesa_bitcount(height - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(height - 2 * border) != 1) ||
           level >= ctx->Const.MaxTextureLevels) {
          /* bad width or height or level */
          return GL_FALSE;
@@ -926,11 +936,14 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
    case GL_PROXY_TEXTURE_3D:
       maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
-          _mesa_bitcount(width - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
-          _mesa_bitcount(height - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(height - 2 * border) != 1) ||
           depth < 2 * border || depth > 2 + maxSize ||
-          _mesa_bitcount(depth - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(depth - 2 * border) != 1) ||
           level >= ctx->Const.Max3DTextureLevels) {
          /* bad width or height or depth or level */
          return GL_FALSE;
@@ -947,9 +960,11 @@ _mesa_test_proxy_teximage(GLcontext *ctx, GLenum target, GLint level,
    case GL_PROXY_TEXTURE_CUBE_MAP_ARB:
       maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1);
       if (width < 2 * border || width > 2 + maxSize ||
-          _mesa_bitcount(width - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(width - 2 * border) != 1) ||
           height < 2 * border || height > 2 + maxSize ||
-          _mesa_bitcount(height - 2 * border) != 1 ||
+          (!ctx->Extensions.ARB_texture_non_power_of_two &&
+           _mesa_bitcount(height - 2 * border) != 1) ||
           level >= ctx->Const.MaxCubeTextureLevels) {
          /* bad width or height */
          return GL_FALSE;
@@ -2458,14 +2473,20 @@ compressed_texture_error_check(GLcontext *ctx, GLint dimensions,
    if (border != 0)
       return GL_INVALID_VALUE;
 
-   if (width < 1 || width > maxTextureSize || logbase2(width) < 0)
+   /*
+    * XXX We should probably use the proxy texture error check function here.
+    */
+   if (width < 1 || width > maxTextureSize ||
+       (!ctx->Extensions.ARB_texture_non_power_of_two && logbase2(width) < 0))
       return GL_INVALID_VALUE;
 
-   if ((height < 1 || height > maxTextureSize || logbase2(height) < 0)
+   if ((height < 1 || height > maxTextureSize ||
+        (!ctx->Extensions.ARB_texture_non_power_of_two && logbase2(height) < 0))
        && dimensions > 1)
       return GL_INVALID_VALUE;
 
-   if ((depth < 1 || depth > maxTextureSize || logbase2(depth) < 0)
+   if ((depth < 1 || depth > maxTextureSize ||
+        (!ctx->Extensions.ARB_texture_non_power_of_two && logbase2(depth) < 0))
        && dimensions > 2)
       return GL_INVALID_VALUE;
 
@@ -2538,10 +2559,10 @@ compressed_subtexture_error_check(GLcontext *ctx, GLint dimensions,
    if (!is_compressed_format(format))
       return GL_INVALID_ENUM;
 
-   if (width < 1 || width > maxTextureSize || logbase2(width) < 0)
+   if (width < 1 || width > maxTextureSize)
       return GL_INVALID_VALUE;
 
-   if ((height < 1 || height > maxTextureSize || logbase2(height) < 0)
+   if ((height < 1 || height > maxTextureSize)
        && dimensions > 1)
       return GL_INVALID_VALUE;
 
index 3d5d256240de9dcb27a1a1c66c3d1f0dd06c602d..19b2b3f8e4acd97a5d754fdedba1255ba6e9eb6e 100644 (file)
@@ -228,6 +228,7 @@ _mesa_copy_texture_object( struct gl_texture_object *dest,
    dest->GenerateMipmap = src->GenerateMipmap;
    dest->Palette = src->Palette;
    dest->Complete = src->Complete;
+   dest->_IsPowerOfTwo = src->_IsPowerOfTwo;
 }
 
 
@@ -257,6 +258,7 @@ _mesa_test_texobj_completeness( const GLcontext *ctx,
    GLint maxLog2 = 0, maxLevels = 0;
 
    t->Complete = GL_TRUE;  /* be optimistic */
+   t->_IsPowerOfTwo = GL_TRUE;  /* may be set FALSE below */
 
    /* Always need the base level image */
    if (!t->Image[baseLevel]) {
@@ -329,6 +331,12 @@ _mesa_test_texobj_completeness( const GLcontext *ctx,
       }
    }
 
+   /* check for non power of two */
+   if (!t->Image[baseLevel]->_IsPowerOfTwo) {
+      t->_IsPowerOfTwo = GL_FALSE;
+   }
+
+   /* extra checking for mipmaps */
    if (t->MinFilter != GL_NEAREST && t->MinFilter != GL_LINEAR) {
       /*
        * Mipmapping: determine if we have a complete set of mipmaps
index a47e6a72ae853848a74bba8ec3682d86216cf8a0..1343b289fbd013eb3e80a5f6134368399bf580cf 100644 (file)
 #define WEIGHT_SHIFT 16
 
 
+/*
+ * Compute the remainder of a divided by b, but be careful with
+ * negative values so that GL_REPEAT mode works right.
+ */
+static INLINE GLint
+repeat_remainder(GLint a, GLint b)
+{
+   if (a >= 0)
+      return a % b;
+   else
+      return (a + 1) % b + b - 1;
+}
+
+
 /*
  * Used to compute texel locations for linear sampling.
  * Input:
 {                                                                      \
    if (wrapMode == GL_REPEAT) {                                                \
       U = S * SIZE - 0.5F;                                             \
-      I0 = IFLOOR(U) & (SIZE - 1);                                     \
-      I1 = (I0 + 1) & (SIZE - 1);                                      \
+      if (tObj->_IsPowerOfTwo) {                                       \
+         I0 = IFLOOR(U) & (SIZE - 1);                                  \
+         I1 = (I0 + 1) & (SIZE - 1);                                   \
+      }                                                                        \
+      else {                                                           \
+         I0 = repeat_remainder(IFLOOR(U), SIZE);                       \
+         I1 = repeat_remainder(I0 + 1, SIZE);                          \
+      }                                                                        \
    }                                                                   \
    else if (wrapMode == GL_CLAMP_TO_EDGE) {                            \
       if (S <= 0.0F)                                                   \
@@ -75,7 +95,7 @@
       if (I1 >= (GLint) SIZE)                                          \
          I1 = SIZE - 1;                                                        \
    }                                                                   \
-   else  if (wrapMode == GL_CLAMP_TO_BORDER) {                 \
+   else if (wrapMode == GL_CLAMP_TO_BORDER) {                          \
       const GLfloat min = -1.0F / (2.0F * SIZE);                       \
       const GLfloat max = 1.0F - min;                                  \
       if (S <= min)                                                    \
       I0 = IFLOOR(U);                                                  \
       I1 = I0 + 1;                                                     \
    }                                                                   \
-   else if (wrapMode == GL_MIRRORED_REPEAT) {                  \
+   else if (wrapMode == GL_MIRRORED_REPEAT) {                          \
       const GLint flr = IFLOOR(S);                                     \
       if (flr & 1)                                                     \
          U = 1.0F - (S - (GLfloat) flr);       /* flr is odd */        \
       /* s limited to [0,1) */                                         \
       /* i limited to [0,size-1] */                                    \
       I = IFLOOR(S * SIZE);                                            \
-      I &= (SIZE - 1);                                                 \
+      if (tObj->_IsPowerOfTwo)                                         \
+         I &= (SIZE - 1);                                              \
+      else                                                             \
+         I = repeat_remainder(I, SIZE);                                        \
    }                                                                   \
    else if (wrapMode == GL_CLAMP_TO_EDGE) {                            \
       /* s limited to [min,max] */                                     \
       else                                                             \
          I = IFLOOR(S * SIZE);                                         \
    }                                                                   \
-   else if (wrapMode == GL_CLAMP_TO_BORDER) {                  \
+   else if (wrapMode == GL_CLAMP_TO_BORDER) {                          \
       /* s limited to [min,max] */                                     \
       /* i limited to [-1, size] */                                    \
       const GLfloat min = -1.0F / (2.0F * SIZE);                       \
       else                                                             \
          I = IFLOOR(S * SIZE);                                         \
    }                                                                   \
-   else if (wrapMode == GL_MIRRORED_REPEAT) {                  \
+   else if (wrapMode == GL_MIRRORED_REPEAT) {                          \
       const GLfloat min = 1.0F / (2.0F * SIZE);                                \
       const GLfloat max = 1.0F - min;                                  \
       const GLint flr = IFLOOR(S);                                     \
 }
 
 
+/* Power of two image sizes only */
 #define COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(S, U, SIZE, I0, I1)       \
 {                                                                      \
    U = S * SIZE - 0.5F;                                                        \
@@ -1215,6 +1239,7 @@ sample_2d_linear_repeat(GLcontext *ctx,
    ASSERT(tObj->WrapT == GL_REPEAT);
    ASSERT(img->Border == 0);
    ASSERT(img->Format != GL_COLOR_INDEX);
+   ASSERT(img->_IsPowerOfTwo);
 
    COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord[0], u, width,  i0, i1);
    COMPUTE_LINEAR_REPEAT_TEXEL_LOCATION(texcoord[1], v, height, j0, j1);
@@ -1379,6 +1404,7 @@ sample_2d_linear_mipmap_linear_repeat( GLcontext *ctx,
    ASSERT(lambda != NULL);
    ASSERT(tObj->WrapS == GL_REPEAT);
    ASSERT(tObj->WrapT == GL_REPEAT);
+   ASSERT(tObj->_IsPowerOfTwo);
    for (i = 0; i < n; i++) {
       GLint level;
       COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
@@ -1457,6 +1483,7 @@ opt_sample_rgb_2d( GLcontext *ctx, GLuint texUnit,
    ASSERT(tObj->WrapT==GL_REPEAT);
    ASSERT(img->Border==0);
    ASSERT(img->Format==GL_RGB);
+   ASSERT(img->_IsPowerOfTwo);
 
    for (k=0; k<n; k++) {
       GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
@@ -1496,6 +1523,7 @@ opt_sample_rgba_2d( GLcontext *ctx, GLuint texUnit,
    ASSERT(tObj->WrapT==GL_REPEAT);
    ASSERT(img->Border==0);
    ASSERT(img->Format==GL_RGBA);
+   ASSERT(img->_IsPowerOfTwo);
 
    for (i = 0; i < n; i++) {
       const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
@@ -1521,10 +1549,11 @@ sample_lambda_2d( GLcontext *ctx, GLuint texUnit,
    GLuint minStart, minEnd;  /* texels with minification */
    GLuint magStart, magEnd;  /* texels with magnification */
 
-   const GLboolean repeatNoBorder = (tObj->WrapS == GL_REPEAT)
+   const GLboolean repeatNoBorderPOT = (tObj->WrapS == GL_REPEAT)
       && (tObj->WrapT == GL_REPEAT)
       && (tImg->Border == 0 && (tImg->Width == tImg->RowStride))
-      && (tImg->Format != GL_COLOR_INDEX);
+      && (tImg->Format != GL_COLOR_INDEX)
+      && tImg->_IsPowerOfTwo;
 
    ASSERT(lambda != NULL);
    compute_min_mag_ranges(SWRAST_CONTEXT(ctx)->_MinMagThresh[texUnit],
@@ -1535,7 +1564,7 @@ sample_lambda_2d( GLcontext *ctx, GLuint texUnit,
       const GLuint m = minEnd - minStart;
       switch (tObj->MinFilter) {
       case GL_NEAREST:
-         if (repeatNoBorder) {
+         if (repeatNoBorderPOT) {
             switch (tImg->Format) {
             case GL_RGB:
                opt_sample_rgb_2d(ctx, texUnit, tObj, m, texcoords + minStart,
@@ -1573,7 +1602,7 @@ sample_lambda_2d( GLcontext *ctx, GLuint texUnit,
                                          lambda + minStart, rgba + minStart);
          break;
       case GL_LINEAR_MIPMAP_LINEAR:
-         if (repeatNoBorder)
+         if (repeatNoBorderPOT)
             sample_2d_linear_mipmap_linear_repeat(ctx, tObj, m,
                   texcoords + minStart, lambda + minStart, rgba + minStart);
          else
@@ -1592,7 +1621,7 @@ sample_lambda_2d( GLcontext *ctx, GLuint texUnit,
 
       switch (tObj->MagFilter) {
       case GL_NEAREST:
-         if (repeatNoBorder) {
+         if (repeatNoBorderPOT) {
             switch (tImg->Format) {
             case GL_RGB:
                opt_sample_rgb_2d(ctx, texUnit, tObj, m, texcoords + magStart,
@@ -2977,12 +3006,14 @@ _swrast_choose_texture_sample_func( GLcontext *ctx,
          ASSERT(t->MinFilter == GL_NEAREST);
          if (t->WrapS == GL_REPEAT &&
              t->WrapT == GL_REPEAT &&
+             t->_IsPowerOfTwo &&
              t->Image[baseLevel]->Border == 0 &&
              t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
             return &opt_sample_rgb_2d;
          }
          else if (t->WrapS == GL_REPEAT &&
                   t->WrapT == GL_REPEAT &&
+                  t->_IsPowerOfTwo &&
                   t->Image[baseLevel]->Border == 0 &&
                   t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
             return &opt_sample_rgba_2d;
@@ -4188,6 +4219,7 @@ _swrast_texture_span( GLcontext *ctx, struct sw_span *span )
          swrast->TextureSample[unit]( ctx, unit, texUnit->_Current, span->end,
                          (const GLfloat (*)[4]) span->array->texcoords[unit],
                          lambda, texels );
+
          /* GL_SGI_texture_color_table */
          if (texUnit->ColorTableEnabled) {
             _swrast_texture_table_lookup(&texUnit->ColorTable, span->end, texels);
index 0ce3459d544019b665daed19eb0123d8c4297142..86fe4dc1fdc3938978393bcdb32bb3248699ccb7 100644 (file)
@@ -1074,6 +1074,7 @@ _swrast_choose_triangle( GLcontext *ctx )
              && ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT
              && texObj2D->WrapS==GL_REPEAT
             && texObj2D->WrapT==GL_REPEAT
+             && texObj2D->_IsPowerOfTwo
              && texImg->Border==0
              && texImg->Width == texImg->RowStride
              && (format == MESA_FORMAT_RGB || format == MESA_FORMAT_RGBA)