st/mesa: fix texture array dimensions
authorBrian Paul <brianp@vmware.com>
Sat, 29 Jan 2011 03:25:27 +0000 (20:25 -0700)
committerBrian Paul <brianp@vmware.com>
Sat, 29 Jan 2011 03:25:27 +0000 (20:25 -0700)
For 1D/2D texture arrays use the pipe_resource::array_size field.
In OpenGL 1D arrays texture use the height dimension as the array
size and 2D array textures use the depth dimension as the array size.
Gallium uses a special array_size field instead.  When setting up
gallium textures or comparing Mesa textures to gallium textures we
need to be extra careful that we're comparing the right fields.

The new st_gl_texture_dims_to_pipe_dims() function maps OpenGL
texture dimensions to gallium texture dimensions and simplifies
this quite a bit.

src/mesa/state_tracker/st_cb_texture.c
src/mesa/state_tracker/st_texture.c
src/mesa/state_tracker/st_texture.h

index acddef6c749664df4cdc936b8908caa29f825e5a..ce6516929beb90705e0afc2bf3734273edcfc7b0 100644 (file)
@@ -275,6 +275,7 @@ guess_and_alloc_texture(struct st_context *st,
    const GLuint dims = get_texture_dims(stObj->base.Target);
    GLuint level, lastLevel, width, height, depth;
    GLuint bindings;
+   GLuint ptWidth, ptHeight, ptDepth, ptLayers;
    enum pipe_format fmt;
 
    DBG("%s\n", __FUNCTION__);
@@ -352,14 +353,18 @@ guess_and_alloc_texture(struct st_context *st,
 
    bindings = default_bindings(st, fmt);
 
+   st_gl_texture_dims_to_pipe_dims(stObj->base.Target,
+                                   width, height, depth,
+                                   &ptWidth, &ptHeight, &ptDepth, &ptLayers);
+
    stObj->pt = st_texture_create(st,
                                  gl_target_to_pipe(stObj->base.Target),
                                  fmt,
                                  lastLevel,
-                                 width,
-                                 height,
-                                 depth,
-                                 1,
+                                 ptWidth,
+                                 ptHeight,
+                                 ptDepth,
+                                 ptLayers,
                                  bindings);
 
    DBG("%s returning %d\n", __FUNCTION__, (stObj->pt != NULL));
@@ -1838,6 +1843,7 @@ st_finalize_texture(struct gl_context *ctx,
    GLuint face;
    struct st_texture_image *firstImage;
    enum pipe_format firstImageFormat;
+   GLuint ptWidth, ptHeight, ptDepth, ptLayers;
 
    if (stObj->base._Complete) {
       /* The texture is complete and we know exactly how many mipmap levels
@@ -1870,6 +1876,9 @@ st_finalize_texture(struct gl_context *ctx,
 
    /* Find gallium format for the Mesa texture */
    firstImageFormat = st_mesa_format_to_pipe_format(firstImage->base.TexFormat);
+   st_gl_texture_dims_to_pipe_dims(stObj->base.Target, stObj->width0,
+                                   stObj->height0, stObj->depth0,
+                                   &ptWidth, &ptHeight, &ptDepth, &ptLayers);
 
    /* If we already have a gallium texture, check that it matches the texture
     * object's format, target, size, num_levels, etc.
@@ -1878,9 +1887,10 @@ st_finalize_texture(struct gl_context *ctx,
       if (stObj->pt->target != gl_target_to_pipe(stObj->base.Target) ||
           !st_sampler_compat_formats(stObj->pt->format, firstImageFormat) ||
           stObj->pt->last_level < stObj->lastLevel ||
-          stObj->pt->width0 != stObj->width0 ||
-          stObj->pt->height0 != stObj->height0 ||
-          stObj->pt->depth0 != stObj->depth0)
+          stObj->pt->width0 != ptWidth ||
+          stObj->pt->height0 != ptHeight ||
+          stObj->pt->depth0 != ptDepth ||
+          stObj->pt->array_size != ptLayers)
       {
          /* The gallium texture does not match the Mesa texture so delete the
           * gallium texture now.  We'll make a new one below.
@@ -1900,10 +1910,10 @@ st_finalize_texture(struct gl_context *ctx,
                                     gl_target_to_pipe(stObj->base.Target),
                                     firstImageFormat,
                                     stObj->lastLevel,
-                                    stObj->width0,
-                                    stObj->height0,
-                                    stObj->depth0,
-                                    1,
+                                    ptWidth,
+                                    ptHeight,
+                                    ptDepth,
+                                    ptLayers,
                                     bindings);
 
       if (!stObj->pt) {
index c5d541007be1127fd24e89d3b215cb1d4fb820b9..1e0a8323ab830cd5d9c2bc427f6dd2fa3dc6793c 100644 (file)
@@ -69,6 +69,8 @@ st_texture_create(struct st_context *st,
    assert(width0 > 0);
    assert(height0 > 0);
    assert(depth0 > 0);
+   if (target == PIPE_TEXTURE_CUBE)
+      assert(layers == 6);
 
    DBG("%s target %s format %s last_level %d\n", __FUNCTION__,
        _mesa_lookup_enum_by_nr(target),
@@ -85,7 +87,7 @@ st_texture_create(struct st_context *st,
    pt.width0 = width0;
    pt.height0 = height0;
    pt.depth0 = depth0;
-   pt.array_size = (target == PIPE_TEXTURE_CUBE ? 6 : 1);
+   pt.array_size = (target == PIPE_TEXTURE_CUBE ? 6 : layers);
    pt.usage = PIPE_USAGE_DEFAULT;
    pt.bind = bind;
    pt.flags = 0;
@@ -98,6 +100,72 @@ st_texture_create(struct st_context *st,
 }
 
 
+/**
+ * In OpenGL the number of 1D array texture layers is the "height" and
+ * the number of 2D array texture layers is the "depth".  In Gallium the
+ * number of layers in an array texture is a separate 'array_size' field.
+ * This function converts dimensions from the former to the later.
+ */
+void
+st_gl_texture_dims_to_pipe_dims(GLenum texture,
+                                GLuint widthIn,
+                                GLuint heightIn,
+                                GLuint depthIn,
+                                GLuint *widthOut,
+                                GLuint *heightOut,
+                                GLuint *depthOut,
+                                GLuint *layersOut)
+{
+   switch (texture) {
+   case GL_TEXTURE_1D:
+      assert(heightIn == 1);
+      assert(depthIn == 1);
+      *widthOut = widthIn;
+      *heightOut = 1;
+      *depthOut = 1;
+      *layersOut = 1;
+      break;
+   case GL_TEXTURE_1D_ARRAY:
+      assert(depthIn == 1);
+      *widthOut = widthIn;
+      *heightOut = 1;
+      *depthOut = 1;
+      *layersOut = heightIn;
+      break;
+   case GL_TEXTURE_2D:
+   case GL_TEXTURE_RECTANGLE:
+      assert(depthIn == 1);
+      *widthOut = widthIn;
+      *heightOut = heightIn;
+      *depthOut = 1;
+      *layersOut = 1;
+      break;
+   case GL_TEXTURE_CUBE_MAP:
+      assert(depthIn == 1);
+      *widthOut = widthIn;
+      *heightOut = heightIn;
+      *depthOut = 1;
+      *layersOut = 6;
+      break;
+   case GL_TEXTURE_2D_ARRAY:
+      *widthOut = widthIn;
+      *heightOut = heightIn;
+      *depthOut = 1;
+      *layersOut = depthIn;
+      break;
+   default:
+      assert(0 && "Unexpected texture in st_gl_texture_dims_to_pipe_dims()");
+      /* fall-through */
+   case GL_TEXTURE_3D:
+      *widthOut = widthIn;
+      *heightOut = heightIn;
+      *depthOut = depthIn;
+      *layersOut = 1;
+      break;
+   }
+}
+
+
 /**
  * Check if a texture image can be pulled into a unified mipmap texture.
  */
@@ -106,6 +174,8 @@ st_texture_match_image(const struct pipe_resource *pt,
                        const struct gl_texture_image *image,
                        GLuint face, GLuint level)
 {
+   GLuint ptWidth, ptHeight, ptDepth, ptLayers;
+
    /* Images with borders are never pulled into mipmap textures. 
     */
    if (image->Border) 
@@ -116,12 +186,17 @@ st_texture_match_image(const struct pipe_resource *pt,
    if (st_mesa_format_to_pipe_format(image->TexFormat) != pt->format)
       return GL_FALSE;
 
+   st_gl_texture_dims_to_pipe_dims(image->TexObject->Target,
+                                   image->Width, image->Height, image->Depth,
+                                   &ptWidth, &ptHeight, &ptDepth, &ptLayers);
+
    /* Test if this image's size matches what's expected in the
     * established texture.
     */
-   if (image->Width != u_minify(pt->width0, level) ||
-       image->Height != u_minify(pt->height0, level) ||
-       image->Depth != u_minify(pt->depth0, level))
+   if (ptWidth != u_minify(pt->width0, level) ||
+       ptHeight != u_minify(pt->height0, level) ||
+       ptDepth != u_minify(pt->depth0, level) ||
+       ptLayers != pt->array_size)
       return GL_FALSE;
 
    return GL_TRUE;
@@ -213,14 +288,20 @@ st_texture_image_data(struct st_context *st,
                       GLuint src_row_stride, GLuint src_image_stride)
 {
    struct pipe_context *pipe = st->pipe;
-   GLuint depth = u_minify(dst->depth0, level);
    GLuint i;
    const GLubyte *srcUB = src;
    struct pipe_transfer *dst_transfer;
+   GLuint layers;
+
+   if (dst->target == PIPE_TEXTURE_1D_ARRAY ||
+       dst->target == PIPE_TEXTURE_2D_ARRAY)
+      layers = dst->array_size;
+   else
+      layers = u_minify(dst->depth0, level);
 
    DBG("%s\n", __FUNCTION__);
 
-   for (i = 0; i < depth; i++) {
+   for (i = 0; i < layers; i++) {
       dst_transfer = pipe_get_transfer(st->pipe, dst, level, face + i,
                                        PIPE_TRANSFER_WRITE, 0, 0,
                                        u_minify(dst->width0, level),
index 5eae7ab72987621e7369ea348e5f973b8dc519ef..d50c3c9af79a01b743d0f109b1afa58b548bd5d8 100644 (file)
@@ -71,7 +71,10 @@ struct st_texture_object
     */
    GLuint lastLevel;
 
-   /** The size of the level=0 mipmap image */
+   /** The size of the level=0 mipmap image.
+    * Note that the number of 1D array layers will be in height0 and the
+    * number of 2D array layers will be in depth0, as in GL.
+    */
    GLuint width0, height0, depth0;
 
    /* On validation any active images held in main memory or in other
@@ -172,6 +175,16 @@ st_texture_create(struct st_context *st,
                   GLuint tex_usage );
 
 
+extern void
+st_gl_texture_dims_to_pipe_dims(GLenum texture,
+                                GLuint widthIn,
+                                GLuint heightIn,
+                                GLuint depthIn,
+                                GLuint *widthOut,
+                                GLuint *heightOut,
+                                GLuint *depthOut,
+                                GLuint *layersOut);
+
 /* Check if an image fits into an existing texture object.
  */
 extern GLboolean