replace malloc macros in imports.h with u_memory.h versions
[mesa.git] / src / mesa / swrast / s_texture.c
index a50018dfd4bf04716a89e1fe6fa1b80b53d59ecd..88b4e87c62af3b2f88f524d00700cb897612cba9 100644 (file)
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
  */
 
 /**
@@ -29,6 +30,8 @@
 #include "main/context.h"
 #include "main/fbobject.h"
 #include "main/teximage.h"
+#include "main/texobj.h"
+#include "util/u_memory.h"
 #include "swrast/swrast.h"
 #include "swrast/s_context.h"
 
@@ -57,48 +60,77 @@ _swrast_delete_texture_image(struct gl_context *ctx,
    _mesa_delete_texture_image(ctx, texImage);
 }
 
+static unsigned int
+texture_slices(const struct gl_texture_image *texImage)
+{
+   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
+      return texImage->Height;
+   else
+      return texImage->Depth;
+}
+
+unsigned int
+_swrast_teximage_slice_height(struct gl_texture_image *texImage)
+{
+   /* For 1D array textures, the slices are all 1 pixel high, and Height is
+    * the number of slices.
+    */
+   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
+      return 1;
+   else
+      return texImage->Height;
+}
 
 /**
  * Called via ctx->Driver.AllocTextureImageBuffer()
  */
 GLboolean
 _swrast_alloc_texture_image_buffer(struct gl_context *ctx,
-                                   struct gl_texture_image *texImage,
-                                   gl_format format, GLsizei width,
-                                   GLsizei height, GLsizei depth)
+                                   struct gl_texture_image *texImage)
 {
    struct swrast_texture_image *swImg = swrast_texture_image(texImage);
-   GLuint bytes = _mesa_format_image_size(format, width, height, depth);
+   GLuint bytesPerSlice;
+   GLuint slices = texture_slices(texImage);
    GLuint i;
 
-   /* This _should_ be true (revisit if these ever fail) */
-   assert(texImage->Width == width);
-   assert(texImage->Height == height);
-   assert(texImage->Depth == depth);
+   if (!_swrast_init_texture_image(texImage))
+      return GL_FALSE;
+
+   bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
+                                           _swrast_teximage_slice_height(texImage), 1);
 
    assert(!swImg->Buffer);
-   swImg->Buffer = _mesa_align_malloc(bytes, 512);
+   swImg->Buffer = _mesa_align_malloc(bytesPerSlice * slices, 512);
    if (!swImg->Buffer)
       return GL_FALSE;
 
-   /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
-   swImg->RowStride = width;
+   /* RowStride and ImageSlices[] describe how to address texels in 'Data' */
+   swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat,
+                                              texImage->Width);
 
-   /* Allocate the ImageOffsets array and initialize to typical values.
-    * We allocate the array for 1D/2D textures too in order to avoid special-
-    * case code in the texstore routines.
-    */
-   swImg->ImageOffsets = (GLuint *) malloc(depth * sizeof(GLuint));
-   if (!swImg->ImageOffsets)
-      return GL_FALSE;
-
-   for (i = 0; i < depth; i++) {
-      swImg->ImageOffsets[i] = i * width * height;
+   for (i = 0; i < slices; i++) {
+      swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i;
    }
 
-   if ((width == 1 || _mesa_is_pow_two(texImage->Width2)) &&
-       (height == 1 || _mesa_is_pow_two(texImage->Height2)) &&
-       (depth == 1 || _mesa_is_pow_two(texImage->Depth2)))
+   return GL_TRUE;
+}
+
+
+/**
+ * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to
+ * initialize the fields of swrast_texture_image without allocating the image
+ * buffer or initializing RowStride or the contents of ImageSlices.
+ *
+ * Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
+ */
+GLboolean
+_swrast_init_texture_image(struct gl_texture_image *texImage)
+{
+   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
+
+   if ((texImage->Width == 1 || util_is_power_of_two_or_zero(texImage->Width2)) &&
+       (texImage->Height == 1 || util_is_power_of_two_or_zero(texImage->Height2)) &&
+       (texImage->Depth == 1 || util_is_power_of_two_or_zero(texImage->Depth2)))
       swImg->_IsPowerOfTwo = GL_TRUE;
    else
       swImg->_IsPowerOfTwo = GL_FALSE;
@@ -116,6 +148,11 @@ _swrast_alloc_texture_image_buffer(struct gl_context *ctx,
       swImg->DepthScale = (GLfloat) texImage->Depth;
    }
 
+   assert(!swImg->ImageSlices);
+   swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *));
+   if (!swImg->ImageSlices)
+      return GL_FALSE;
+
    return GL_TRUE;
 }
 
@@ -128,15 +165,12 @@ _swrast_free_texture_image_buffer(struct gl_context *ctx,
                                   struct gl_texture_image *texImage)
 {
    struct swrast_texture_image *swImage = swrast_texture_image(texImage);
-   if (swImage->Buffer) {
-      _mesa_align_free(swImage->Buffer);
-      swImage->Buffer = NULL;
-   }
 
-   if (swImage->ImageOffsets) {
-      free(swImage->ImageOffsets);
-      swImage->ImageOffsets = NULL;
-   }
+   _mesa_align_free(swImage->Buffer);
+   swImage->Buffer = NULL;
+
+   free(swImage->ImageSlices);
+   swImage->ImageSlices = NULL;
 }
 
 
@@ -144,8 +178,8 @@ _swrast_free_texture_image_buffer(struct gl_context *ctx,
  * Error checking for debugging only.
  */
 static void
-_mesa_check_map_teximage(struct gl_texture_image *texImage,
-                         GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
+check_map_teximage(const struct gl_texture_image *texImage,
+                   GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
 {
 
    if (texImage->TexObject->Target == GL_TEXTURE_1D)
@@ -155,6 +189,7 @@ _mesa_check_map_teximage(struct gl_texture_image *texImage,
    assert(y < texImage->Height || texImage->Height == 0);
    assert(x + w <= texImage->Width);
    assert(y + h <= texImage->Height);
+   assert(slice < texture_slices(texImage));
 }
 
 /**
@@ -183,7 +218,16 @@ _swrast_map_teximage(struct gl_context *ctx,
    GLint stride, texelSize;
    GLuint bw, bh;
 
-   _mesa_check_map_teximage(texImage, slice, x, y, w, h);
+   check_map_teximage(texImage, slice, x, y, w, h);
+
+   if (!swImage->Buffer) {
+      /* Either glTexImage was called with a NULL <pixels> argument or
+       * we ran out of memory when allocating texture memory,
+       */
+      *mapOut = NULL;
+      *rowStrideOut = 0;
+      return;
+   }
 
    texelSize = _mesa_get_format_bytes(texImage->TexFormat);
    stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
@@ -192,30 +236,13 @@ _swrast_map_teximage(struct gl_context *ctx,
    assert(x % bw == 0);
    assert(y % bh == 0);
 
-   if (!swImage->Buffer) {
-      /* probably ran out of memory when allocating tex mem */
-      *mapOut = NULL;
-      return;
-   }
-      
-   map = swImage->Buffer;
-
-   if (texImage->TexObject->Target == GL_TEXTURE_3D ||
-       texImage->TexObject->Target == GL_TEXTURE_2D_ARRAY) {
-      GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
-                                                 texImage->Width,
-                                                 texImage->Height,
-                                                 1);
-      assert(slice < texImage->Depth);
-      map += slice * sliceSize;
-   } else if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) {
-      GLuint sliceSize = _mesa_format_image_size(texImage->TexFormat,
-                                                 texImage->Width,
-                                                 1,
-                                                 1);
-      assert(slice < texImage->Height);
-      map += slice * sliceSize;
-   }
+   /* This function can only be used with a swrast-allocated buffer, in which
+    * case ImageSlices is populated with pointers into Buffer.
+    */
+   assert(swImage->Buffer);
+   assert(swImage->Buffer == swImage->ImageSlices[0]);
+
+   map = swImage->ImageSlices[slice];
 
    /* apply x/y offset to map address */
    map += stride * (y / bh) + texelSize * (x / bw);
@@ -236,18 +263,57 @@ _swrast_unmap_teximage(struct gl_context *ctx,
 void
 _swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
 {
-   const GLuint faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
+   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
    GLuint face, level;
 
    for (face = 0; face < faces; face++) {
       for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
          struct gl_texture_image *texImage = texObj->Image[face][level];
-         if (texImage) {
-            struct swrast_texture_image *swImage =
-               swrast_texture_image(texImage);
+         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
+         unsigned int i, slices;
+
+         if (!texImage)
+            continue;
+
+         /* In the case of a swrast-allocated texture buffer, the ImageSlices
+          * and RowStride are always available.
+          */
+         if (swImage->Buffer) {
+            assert(swImage->ImageSlices[0] == swImage->Buffer);
+            continue;
+         }
+
+         if (!swImage->ImageSlices) {
+            swImage->ImageSlices =
+               calloc(texture_slices(texImage), sizeof(void *));
+            if (!swImage->ImageSlices)
+               continue;
+         }
 
-            /* XXX we'll eventually call _swrast_map_teximage() here */
-            swImage->Map = swImage->Buffer;
+         slices = texture_slices(texImage);
+
+         for (i = 0; i < slices; i++) {
+            GLubyte *map;
+            GLint rowStride;
+
+            if (swImage->ImageSlices[i])
+               continue;
+
+            ctx->Driver.MapTextureImage(ctx, texImage, i,
+                                        0, 0,
+                                        texImage->Width, texImage->Height,
+                                        GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
+                                        &map, &rowStride);
+
+            swImage->ImageSlices[i] = map;
+            /* A swrast-using driver has to return the same rowstride for
+             * every slice of the same texture, since we don't track them
+             * separately.
+             */
+            if (i == 0)
+               swImage->RowStride = rowStride;
+            else
+               assert(swImage->RowStride == rowStride);
          }
       }
    }
@@ -257,18 +323,31 @@ _swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
 void
 _swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
 {
-   const GLuint faces = texObj->Target == GL_TEXTURE_CUBE_MAP ? 6 : 1;
+   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
    GLuint face, level;
 
    for (face = 0; face < faces; face++) {
       for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
          struct gl_texture_image *texImage = texObj->Image[face][level];
-         if (texImage) {
-            struct swrast_texture_image *swImage
-               = swrast_texture_image(texImage);
+         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
+         unsigned int i, slices;
+
+         if (!texImage)
+            continue;
+
+         if (swImage->Buffer)
+            return;
 
-            /* XXX we'll eventually call _swrast_unmap_teximage() here */
-            swImage->Map = NULL;
+         if (!swImage->ImageSlices)
+            continue;
+
+         slices = texture_slices(texImage);
+
+         for (i = 0; i < slices; i++) {
+            if (swImage->ImageSlices[i]) {
+               ctx->Driver.UnmapTextureImage(ctx, texImage, i);
+               swImage->ImageSlices[i] = NULL;
+            }
          }
       }
    }
@@ -281,16 +360,13 @@ _swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
 void
 _swrast_map_textures(struct gl_context *ctx)
 {
-   GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
+   int unit;
 
-   /* loop over enabled texture units */
-   while (enabledUnits) {
-      GLuint unit = ffs(enabledUnits) - 1;
+   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
       struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
-      
-      _swrast_map_texture(ctx, texObj);
 
-      enabledUnits &= ~(1 << unit);
+      if (texObj)
+         _swrast_map_texture(ctx, texObj);
    }
 }
 
@@ -301,99 +377,11 @@ _swrast_map_textures(struct gl_context *ctx)
 void
 _swrast_unmap_textures(struct gl_context *ctx)
 {
-   GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
-
-   /* loop over enabled texture units */
-   while (enabledUnits) {
-      GLuint unit = ffs(enabledUnits) - 1;
+   int unit;
+   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
       struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
-      
-      _swrast_unmap_texture(ctx, texObj);
-
-      enabledUnits &= ~(1 << unit);
-   }
-}
-
-
-/**
- * Map or unmap any textures that we may be rendering to as renderbuffers.
- */
-static void
-map_unmap_renderbuffers(struct gl_context *ctx,
-                        struct gl_framebuffer *fb,
-                        GLboolean map)
-{
-   GLuint i;
-
-   for (i = 0; i < Elements(fb->Attachment); i++) {
-      struct gl_texture_object *texObj = fb->Attachment[i].Texture;
-      if (texObj) {
-         const GLuint level = fb->Attachment[i].TextureLevel;
-         const GLuint face = fb->Attachment[i].CubeMapFace;
-         struct gl_texture_image *texImage = texObj->Image[face][level];
-         if (texImage) {
-            struct swrast_texture_image *swImage
-               = swrast_texture_image(texImage);
-
-            if (map) {
-               /* XXX we'll eventually call _swrast_map_teximage() here */
-               swImage->Map = swImage->Buffer;
-            }
-            else {
-               /* XXX we'll eventually call _swrast_unmap_teximage() here */
-               swImage->Map = NULL;
-            }
-         }
-      }
-   }
-}
 
-
-void
-_swrast_map_renderbuffers(struct gl_context *ctx)
-{
-   map_unmap_renderbuffers(ctx, ctx->DrawBuffer, GL_TRUE);
-   if (ctx->ReadBuffer != ctx->DrawBuffer)
-      map_unmap_renderbuffers(ctx, ctx->ReadBuffer, GL_TRUE);
-}
-
-
-void
-_swrast_unmap_renderbuffers(struct gl_context *ctx)
-{
-   map_unmap_renderbuffers(ctx, ctx->DrawBuffer, GL_FALSE);
-   if (ctx->ReadBuffer != ctx->DrawBuffer)
-      map_unmap_renderbuffers(ctx, ctx->ReadBuffer, GL_FALSE);
-}
-
-
-
-/**
- * Called via ctx->Driver.AllocTextureStorage()
- * Just have to allocate memory for the texture images.
- */
-GLboolean
-_swrast_AllocTextureStorage(struct gl_context *ctx,
-                            struct gl_texture_object *texObj,
-                            GLsizei levels, GLsizei width,
-                            GLsizei height, GLsizei depth)
-{
-   const GLint numFaces = (texObj->Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
-   GLint face, level;
-
-   for (face = 0; face < numFaces; face++) {
-      for (level = 0; level < levels; level++) {
-         struct gl_texture_image *texImage = texObj->Image[face][level];
-         if (!_swrast_alloc_texture_image_buffer(ctx, texImage,
-                                                 texImage->TexFormat,
-                                                 texImage->Width,
-                                                 texImage->Height,
-                                                 texImage->Depth)) {
-            return GL_FALSE;
-         }
-      }
+      if (texObj)
+         _swrast_unmap_texture(ctx, texObj);
    }
-
-   return GL_TRUE;
 }
-