Merge remote-tracking branch 'mesa-public/master' into vulkan
[mesa.git] / src / gallium / drivers / llvmpipe / lp_texture.c
index c07bd21bf12b284bb1314f0c9a57fa8ce96fc929..828688145812fdca42ab04fd30bc4d967d22dd1a 100644 (file)
@@ -40,7 +40,7 @@
 #include "util/u_format.h"
 #include "util/u_math.h"
 #include "util/u_memory.h"
-#include "util/u_simple_list.h"
+#include "util/simple_list.h"
 #include "util/u_transfer.h"
 
 #include "lp_context.h"
@@ -59,16 +59,15 @@ static struct llvmpipe_resource resource_list;
 #endif
 static unsigned id_counter = 0;
 
-static void
-alloc_image_data(struct llvmpipe_resource *lpr);
 
 /**
  * Conventional allocation path for non-display textures:
- * Just compute row strides here.  Storage is allocated on demand later.
+ * Compute strides and allocate data (unless asked not to).
  */
 static boolean
 llvmpipe_texture_layout(struct llvmpipe_screen *screen,
-                        struct llvmpipe_resource *lpr)
+                        struct llvmpipe_resource *lpr,
+                        boolean allocate)
 {
    struct pipe_resource *pt = &lpr->base;
    unsigned level;
@@ -77,80 +76,86 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
    unsigned depth = pt->depth0;
    uint64_t total_size = 0;
    unsigned layers = pt->array_size;
+   /* XXX:
+    * This alignment here (same for displaytarget) was added for the purpose of
+    * ARB_map_buffer_alignment. I am not convinced it's needed for non-buffer
+    * resources. Otherwise we'd want the max of cacheline size and 16 (max size
+    * of a block for all formats) though this should not be strictly necessary
+    * neither. In any case it can only affect compressed or 1d textures.
+    */
+   unsigned mip_align = MAX2(64, util_cpu_caps.cacheline);
 
    assert(LP_MAX_TEXTURE_2D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
    assert(LP_MAX_TEXTURE_3D_LEVELS <= LP_MAX_TEXTURE_LEVELS);
 
    for (level = 0; level <= pt->last_level; level++) {
+      uint64_t mipsize;
+      unsigned align_x, align_y, nblocksx, nblocksy, block_size, num_slices;
 
       /* Row stride and image stride */
-      {
-         unsigned align_x, align_y, nblocksx, nblocksy, block_size;
-
-         /* For non-compressed formats we need 4x4 pixel alignment
-          * so we can read/write LP_RASTER_BLOCK_SIZE when rendering to them.
-          * We also want cache line size in x direction,
-          * otherwise same cache line could end up in multiple threads.
-          * For explicit 1d resources however we reduce this to 4x1 and
-          * handle specially in render output code (as we need to do special
-          * handling there for buffers in any case).
-          */
-         if (util_format_is_compressed(pt->format))
-            align_x = align_y = 1;
-         else {
-            align_x = LP_RASTER_BLOCK_SIZE;
-            if (llvmpipe_resource_is_1d(&lpr->base))
-               align_y = 1;
-            else
-               align_y = LP_RASTER_BLOCK_SIZE;
-         }
-
-         nblocksx = util_format_get_nblocksx(pt->format,
-                                             align(width, align_x));
-         nblocksy = util_format_get_nblocksy(pt->format,
-                                             align(height, align_y));
-         block_size = util_format_get_blocksize(pt->format);
 
-         if (util_format_is_compressed(pt->format))
-            lpr->row_stride[level] = nblocksx * block_size;
+      /* For non-compressed formats we need 4x4 pixel alignment
+       * so we can read/write LP_RASTER_BLOCK_SIZE when rendering to them.
+       * We also want cache line size in x direction,
+       * otherwise same cache line could end up in multiple threads.
+       * For explicit 1d resources however we reduce this to 4x1 and
+       * handle specially in render output code (as we need to do special
+       * handling there for buffers in any case).
+       */
+      if (util_format_is_compressed(pt->format))
+         align_x = align_y = 1;
+      else {
+         align_x = LP_RASTER_BLOCK_SIZE;
+         if (llvmpipe_resource_is_1d(&lpr->base))
+            align_y = 1;
          else
-            lpr->row_stride[level] = align(nblocksx * block_size, util_cpu_caps.cacheline);
+            align_y = LP_RASTER_BLOCK_SIZE;
+      }
 
-         /* if row_stride * height > LP_MAX_TEXTURE_SIZE */
-         if ((uint64_t)lpr->row_stride[level] * nblocksy > LP_MAX_TEXTURE_SIZE) {
-            /* image too large */
-            goto fail;
-         }
+      nblocksx = util_format_get_nblocksx(pt->format,
+                                          align(width, align_x));
+      nblocksy = util_format_get_nblocksy(pt->format,
+                                          align(height, align_y));
+      block_size = util_format_get_blocksize(pt->format);
+
+      if (util_format_is_compressed(pt->format))
+         lpr->row_stride[level] = nblocksx * block_size;
+      else
+         lpr->row_stride[level] = align(nblocksx * block_size, util_cpu_caps.cacheline);
 
-         lpr->img_stride[level] = lpr->row_stride[level] * nblocksy;
+      /* if row_stride * height > LP_MAX_TEXTURE_SIZE */
+      if ((uint64_t)lpr->row_stride[level] * nblocksy > LP_MAX_TEXTURE_SIZE) {
+         /* image too large */
+         goto fail;
       }
 
-      /* Number of 3D image slices, cube faces or texture array layers */
-      {
-         unsigned num_slices;
-
-         if (lpr->base.target == PIPE_TEXTURE_CUBE)
-            num_slices = 6;
-         else if (lpr->base.target == PIPE_TEXTURE_3D)
-            num_slices = depth;
-         else if (lpr->base.target == PIPE_TEXTURE_1D_ARRAY ||
-                  lpr->base.target == PIPE_TEXTURE_2D_ARRAY)
-            num_slices = layers;
-         else
-            num_slices = 1;
+      lpr->img_stride[level] = lpr->row_stride[level] * nblocksy;
 
-         lpr->num_slices_faces[level] = num_slices;
+      /* Number of 3D image slices, cube faces or texture array layers */
+      if (lpr->base.target == PIPE_TEXTURE_CUBE) {
+         assert(layers == 6);
       }
 
+      if (lpr->base.target == PIPE_TEXTURE_3D)
+         num_slices = depth;
+      else if (lpr->base.target == PIPE_TEXTURE_1D_ARRAY ||
+               lpr->base.target == PIPE_TEXTURE_2D_ARRAY ||
+               lpr->base.target == PIPE_TEXTURE_CUBE ||
+               lpr->base.target == PIPE_TEXTURE_CUBE_ARRAY)
+         num_slices = layers;
+      else
+         num_slices = 1;
+
       /* if img_stride * num_slices_faces > LP_MAX_TEXTURE_SIZE */
-      if (lpr->img_stride[level] >
-          LP_MAX_TEXTURE_SIZE / lpr->num_slices_faces[level]) {
+      mipsize = (uint64_t)lpr->img_stride[level] * num_slices;
+      if (mipsize > LP_MAX_TEXTURE_SIZE) {
          /* volume too large */
          goto fail;
       }
 
-      total_size += (uint64_t) lpr->num_slices_faces[level]
-                  * (uint64_t) lpr->img_stride[level];
+      lpr->mip_offsets[level] = total_size;
+
+      total_size += align((unsigned)mipsize, mip_align);
       if (total_size > LP_MAX_TEXTURE_SIZE) {
          goto fail;
       }
@@ -161,6 +166,16 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
       depth = u_minify(depth, 1);
    }
 
+   if (allocate) {
+      lpr->tex_data = align_malloc(total_size, mip_align);
+      if (!lpr->tex_data) {
+         return FALSE;
+      }
+      else {
+         memset(lpr->tex_data, 0, total_size);
+      }
+   }
+
    return TRUE;
 
 fail:
@@ -179,13 +194,14 @@ llvmpipe_can_create_resource(struct pipe_screen *screen,
    struct llvmpipe_resource lpr;
    memset(&lpr, 0, sizeof(lpr));
    lpr.base = *res;
-   return llvmpipe_texture_layout(llvmpipe_screen(screen), &lpr);
+   return llvmpipe_texture_layout(llvmpipe_screen(screen), &lpr, false);
 }
 
 
 static boolean
 llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
-                              struct llvmpipe_resource *lpr)
+                              struct llvmpipe_resource *lpr,
+                              const void *map_front_private)
 {
    struct sw_winsys *winsys = screen->winsys;
 
@@ -195,20 +211,18 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
    const unsigned width = MAX2(1, align(lpr->base.width0, TILE_SIZE));
    const unsigned height = MAX2(1, align(lpr->base.height0, TILE_SIZE));
 
-   lpr->num_slices_faces[0] = 1;
-   lpr->img_stride[0] = 0;
-
    lpr->dt = winsys->displaytarget_create(winsys,
                                           lpr->base.bind,
                                           lpr->base.format,
                                           width, height,
                                           64,
+                                          map_front_private,
                                           &lpr->row_stride[0] );
 
    if (lpr->dt == NULL)
       return FALSE;
 
-   {
+   if (!map_front_private) {
       void *map = winsys->displaytarget_map(winsys, lpr->dt,
                                             PIPE_TRANSFER_WRITE);
 
@@ -223,8 +237,9 @@ llvmpipe_displaytarget_layout(struct llvmpipe_screen *screen,
 
 
 static struct pipe_resource *
-llvmpipe_resource_create(struct pipe_screen *_screen,
-                         const struct pipe_resource *templat)
+llvmpipe_resource_create_front(struct pipe_screen *_screen,
+                               const struct pipe_resource *templat,
+                               const void *map_front_private)
 {
    struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
    struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
@@ -242,18 +257,13 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
                             PIPE_BIND_SCANOUT |
                             PIPE_BIND_SHARED)) {
          /* displayable surface */
-         if (!llvmpipe_displaytarget_layout(screen, lpr))
+         if (!llvmpipe_displaytarget_layout(screen, lpr, map_front_private))
             goto fail;
       }
       else {
          /* texture map */
-         if (!llvmpipe_texture_layout(screen, lpr))
+         if (!llvmpipe_texture_layout(screen, lpr, true))
             goto fail;
-
-         alloc_image_data(lpr);
-         if (!lpr->tex_data) {
-            goto fail;
-         }
       }
    }
    else {
@@ -269,6 +279,7 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
        * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE.
        */
       lpr->data = align_malloc(bytes + (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float), 64);
+
       /*
        * buffers don't really have stride but it's probably safer
        * (for code doing same calculations for buffers and textures)
@@ -292,7 +303,12 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
    FREE(lpr);
    return NULL;
 }
-
+static struct pipe_resource *
+llvmpipe_resource_create(struct pipe_screen *_screen,
+                         const struct pipe_resource *templat)
+{
+   return llvmpipe_resource_create_front(_screen, templat, NULL);
+}
 
 static void
 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
@@ -443,9 +459,6 @@ llvmpipe_resource_from_handle(struct pipe_screen *screen,
    assert(lpr->base.height0 == height);
 #endif
 
-   lpr->num_slices_faces[0] = 1;
-   lpr->img_stride[0] = 0;
-
    lpr->dt = winsys->displaytarget_from_handle(winsys,
                                                template,
                                                whandle,
@@ -677,7 +690,7 @@ struct pipe_resource *
 llvmpipe_user_buffer_create(struct pipe_screen *screen,
                             void *ptr,
                             unsigned bytes,
-                           unsigned bind_flags)
+                            unsigned bind_flags)
 {
    struct llvmpipe_resource *buffer;
 
@@ -713,18 +726,6 @@ tex_image_face_size(const struct llvmpipe_resource *lpr, unsigned level)
 }
 
 
-/**
- * Compute size (in bytes) need to store a texture image / mipmap level,
- * including all cube faces or 3D image slices
- */
-static unsigned
-tex_image_size(const struct llvmpipe_resource *lpr, unsigned level)
-{
-   const unsigned buf_size = tex_image_face_size(lpr, level);
-   return buf_size * lpr->num_slices_faces[level];
-}
-
-
 /**
  * Return pointer to a 2D texture image/face/slice.
  * No tiled/linear conversion is done.
@@ -746,49 +747,6 @@ llvmpipe_get_texture_image_address(struct llvmpipe_resource *lpr,
 }
 
 
-/**
- * Allocate storage for a linear image
- * (all cube faces and all 3D slices, all levels).
- */
-static void
-alloc_image_data(struct llvmpipe_resource *lpr)
-{
-   uint alignment = MAX2(64, util_cpu_caps.cacheline);
-   uint level;
-   uint offset = 0;
-
-   if (lpr->dt) {
-      /* we get the linear memory from the winsys, and it has
-       * already been zeroed
-       */
-      struct llvmpipe_screen *screen = llvmpipe_screen(lpr->base.screen);
-      struct sw_winsys *winsys = screen->winsys;
-
-      assert(lpr->base.last_level == 0);
-
-      lpr->tex_data =
-         winsys->displaytarget_map(winsys, lpr->dt,
-                                   PIPE_TRANSFER_READ_WRITE);
-   }
-   else {
-      /* not a display target - allocate regular memory */
-      /*
-       * Offset calculation for start of a specific mip/layer is always
-       * offset = lpr->linear_mip_offsets[level] + lpr->img_stride[level] * layer
-       */
-      for (level = 0; level <= lpr->base.last_level; level++) {
-         uint buffer_size = tex_image_size(lpr, level);
-         lpr->mip_offsets[level] = offset;
-         offset += align(buffer_size, alignment);
-      }
-      lpr->tex_data = align_malloc(offset, alignment);
-      if (lpr->tex_data) {
-         memset(lpr->tex_data, 0, offset);
-      }
-   }
-}
-
-
 /**
  * Return size of resource in bytes
  */
@@ -796,18 +754,15 @@ unsigned
 llvmpipe_resource_size(const struct pipe_resource *resource)
 {
    const struct llvmpipe_resource *lpr = llvmpipe_resource_const(resource);
-   unsigned lvl, size = 0;
+   unsigned size = 0;
 
    if (llvmpipe_resource_is_texture(resource)) {
-      for (lvl = 0; lvl <= lpr->base.last_level; lvl++) {
-         if (lpr->tex_data)
-            size += tex_image_size(lpr, lvl);
-      }
+      /* Note this will always return 0 for displaytarget resources */
+      size = lpr->total_alloc_size;
    }
    else {
       size = resource->width0;
    }
-
    return size;
 }
 
@@ -850,6 +805,7 @@ llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
 #endif
 
    screen->resource_create = llvmpipe_resource_create;
+/*   screen->resource_create_front = llvmpipe_resource_create_front; */
    screen->resource_destroy = llvmpipe_resource_destroy;
    screen->resource_from_handle = llvmpipe_resource_from_handle;
    screen->resource_get_handle = llvmpipe_resource_get_handle;