radeon: Fix memory leak in radeonCreateScreen2.
[mesa.git] / src / mesa / swrast / s_texture.c
index 14ee0ebc600304f946f2d311e9f8ee375862d4b4..8ae3d5bd0e6c8b285a76219a45502011dac7fdf8 100644 (file)
@@ -29,6 +29,7 @@
 #include "main/context.h"
 #include "main/fbobject.h"
 #include "main/teximage.h"
+#include "main/texobj.h"
 #include "swrast/swrast.h"
 #include "swrast/s_context.h"
 
@@ -63,29 +64,70 @@ _swrast_delete_texture_image(struct gl_context *ctx,
  */
 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 bytes = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
+                                          texImage->Height, texImage->Depth);
+   GLuint i;
 
-   /* This _should_ be true (revisit if these ever fail) */
-   assert(texImage->Width == width);
-   assert(texImage->Height == height);
-   assert(texImage->Depth == depth);
+   assert(!swImg->Buffer);
+   swImg->Buffer = _mesa_align_malloc(bytes, 512);
+   if (!swImg->Buffer)
+      return GL_FALSE;
 
-   assert(!texImage->Data);
-   texImage->Data = _mesa_align_malloc(bytes, 512);
+   /* RowStride and ImageOffsets[] describe how to address texels in 'Data' */
+   swImg->RowStride = texImage->Width;
 
-   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)))
+   /* 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 = malloc(texImage->Depth * sizeof(GLuint));
+   if (!swImg->ImageOffsets)
+      return GL_FALSE;
+
+   for (i = 0; i < texImage->Depth; i++) {
+      swImg->ImageOffsets[i] = i * texImage->Width * texImage->Height;
+   }
+
+   _swrast_init_texture_image(texImage);
+
+   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 ImageOffsets or RowStride.
+ *
+ * Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
+ */
+void
+_swrast_init_texture_image(struct gl_texture_image *texImage)
+{
+   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
+
+   if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) &&
+       (texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) &&
+       (texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2)))
       swImg->_IsPowerOfTwo = GL_TRUE;
    else
       swImg->_IsPowerOfTwo = GL_FALSE;
 
-   return texImage->Data != NULL;
+   /* Compute Width/Height/DepthScale for mipmap lod computation */
+   if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
+      /* scale = 1.0 since texture coords directly map to texels */
+      swImg->WidthScale = 1.0;
+      swImg->HeightScale = 1.0;
+      swImg->DepthScale = 1.0;
+   }
+   else {
+      swImg->WidthScale = (GLfloat) texImage->Width;
+      swImg->HeightScale = (GLfloat) texImage->Height;
+      swImg->DepthScale = (GLfloat) texImage->Depth;
+   }
 }
 
 
@@ -96,11 +138,14 @@ void
 _swrast_free_texture_image_buffer(struct gl_context *ctx,
                                   struct gl_texture_image *texImage)
 {
-   if (texImage->Data && !texImage->IsClientData) {
-      _mesa_align_free(texImage->Data);
+   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
+   if (swImage->Buffer) {
+      _mesa_align_free(swImage->Buffer);
+      swImage->Buffer = NULL;
    }
 
-   texImage->Data = NULL;
+   free(swImage->ImageOffsets);
+   swImage->ImageOffsets = NULL;
 }
 
 
@@ -142,6 +187,7 @@ _swrast_map_teximage(struct gl_context *ctx,
                      GLubyte **mapOut,
                      GLint *rowStrideOut)
 {
+   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
    GLubyte *map;
    GLint stride, texelSize;
    GLuint bw, bh;
@@ -152,9 +198,16 @@ _swrast_map_teximage(struct gl_context *ctx,
    stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
    _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
 
-   assert(texImage->Data);
+   assert(x % bw == 0);
+   assert(y % bh == 0);
 
-   map = texImage->Data;
+   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) {
@@ -164,6 +217,13 @@ _swrast_map_teximage(struct gl_context *ctx,
                                                  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;
    }
 
    /* apply x/y offset to map address */
@@ -180,3 +240,112 @@ _swrast_unmap_teximage(struct gl_context *ctx,
 {
    /* nop */
 }
+
+
+void
+_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
+{
+   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);
+
+            /* XXX we'll eventually call _swrast_map_teximage() here */
+            swImage->Map = swImage->Buffer;
+         }
+      }
+   }
+}
+
+
+void
+_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
+{
+   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);
+
+            /* XXX we'll eventually call _swrast_unmap_teximage() here */
+            swImage->Map = NULL;
+         }
+      }
+   }
+}
+
+
+/**
+ * Map all textures for reading prior to software rendering.
+ */
+void
+_swrast_map_textures(struct gl_context *ctx)
+{
+   GLbitfield enabledUnits = ctx->Texture._EnabledUnits;
+
+   /* loop over enabled texture units */
+   while (enabledUnits) {
+      GLuint unit = ffs(enabledUnits) - 1;
+      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
+      
+      _swrast_map_texture(ctx, texObj);
+
+      enabledUnits &= ~(1 << unit);
+   }
+}
+
+
+/**
+ * Unmap all textures for reading prior to software rendering.
+ */
+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;
+      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
+      
+      _swrast_unmap_texture(ctx, texObj);
+
+      enabledUnits &= ~(1 << unit);
+   }
+}
+
+
+/**
+ * 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)) {
+            return GL_FALSE;
+         }
+      }
+   }
+
+   return GL_TRUE;
+}
+