llvmpipe: fixup multisample coverage masks for covered tiles
[mesa.git] / src / gallium / drivers / llvmpipe / lp_texture.c
index 40e5815ab33f746412065a7ca56f62548c32e002..fa7a1ff1129c065f7971ed91e3b050e229a25059 100644 (file)
 
 #include "util/u_inlines.h"
 #include "util/u_cpu_detect.h"
-#include "util/u_format.h"
+#include "util/format/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,88 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
    unsigned depth = pt->depth0;
    uint64_t total_size = 0;
    unsigned layers = pt->array_size;
+   unsigned num_samples = util_res_sample_count(pt);
+
+   /* 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 +168,19 @@ llvmpipe_texture_layout(struct llvmpipe_screen *screen,
       depth = u_minify(depth, 1);
    }
 
+   lpr->sample_stride = total_size;
+   total_size *= num_samples;
+
+   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:
@@ -172,20 +192,21 @@ fail:
  * Check the size of the texture specified by 'res'.
  * \return TRUE if OK, FALSE if too large.
  */
-static boolean
+static bool
 llvmpipe_can_create_resource(struct pipe_screen *screen,
                              const struct pipe_resource *res)
 {
    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 +216,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 +242,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 +262,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 +284,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)
@@ -294,6 +310,14 @@ llvmpipe_resource_create(struct pipe_screen *_screen,
 }
 
 
+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,
                           struct pipe_resource *pt)
@@ -418,7 +442,8 @@ llvmpipe_resource_data(struct pipe_resource *resource)
 static struct pipe_resource *
 llvmpipe_resource_from_handle(struct pipe_screen *screen,
                               const struct pipe_resource *template,
-                              struct winsys_handle *whandle)
+                              struct winsys_handle *whandle,
+                              unsigned usage)
 {
    struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
    struct llvmpipe_resource *lpr;
@@ -443,9 +468,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,
@@ -469,29 +491,32 @@ no_lpr:
 }
 
 
-static boolean
+static bool
 llvmpipe_resource_get_handle(struct pipe_screen *screen,
+                             struct pipe_context *ctx,
                             struct pipe_resource *pt,
-                            struct winsys_handle *whandle)
+                            struct winsys_handle *whandle,
+                             unsigned usage)
 {
    struct sw_winsys *winsys = llvmpipe_screen(screen)->winsys;
    struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
 
    assert(lpr->dt);
    if (!lpr->dt)
-      return FALSE;
+      return false;
 
    return winsys->displaytarget_get_handle(winsys, lpr->dt, whandle);
 }
 
 
-static void *
-llvmpipe_transfer_map( struct pipe_context *pipe,
-                       struct pipe_resource *resource,
-                       unsigned level,
-                       unsigned usage,
-                       const struct pipe_box *box,
-                       struct pipe_transfer **transfer )
+void *
+llvmpipe_transfer_map_ms( struct pipe_context *pipe,
+                          struct pipe_resource *resource,
+                          unsigned level,
+                          unsigned usage,
+                          unsigned sample,
+                          const struct pipe_box *box,
+                          struct pipe_transfer **transfer )
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
    struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
@@ -527,14 +552,14 @@ llvmpipe_transfer_map( struct pipe_context *pipe,
       }
    }
 
-   /* Check if we're mapping the current constant buffer */
+   /* Check if we're mapping a current constant buffer */
    if ((usage & PIPE_TRANSFER_WRITE) &&
        (resource->bind & PIPE_BIND_CONSTANT_BUFFER)) {
       unsigned i;
-      for (i = 0; i < Elements(llvmpipe->constants[PIPE_SHADER_FRAGMENT]); ++i) {
+      for (i = 0; i < ARRAY_SIZE(llvmpipe->constants[PIPE_SHADER_FRAGMENT]); ++i) {
          if (resource == llvmpipe->constants[PIPE_SHADER_FRAGMENT][i].buffer) {
             /* constants may have changed */
-            llvmpipe->dirty |= LP_NEW_CONSTANTS;
+            llvmpipe->dirty |= LP_NEW_FS_CONSTANTS;
             break;
          }
       }
@@ -596,9 +621,20 @@ llvmpipe_transfer_map( struct pipe_context *pipe,
       box->y / util_format_get_blockheight(format) * pt->stride +
       box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format);
 
+   map += sample * lpr->sample_stride;
    return map;
 }
 
+static void *
+llvmpipe_transfer_map( struct pipe_context *pipe,
+                       struct pipe_resource *resource,
+                       unsigned level,
+                       unsigned usage,
+                       const struct pipe_box *box,
+                       struct pipe_transfer **transfer )
+{
+   return llvmpipe_transfer_map_ms(pipe, resource, level, usage, 0, box, transfer);
+}
 
 static void
 llvmpipe_transfer_unmap(struct pipe_context *pipe,
@@ -625,16 +661,11 @@ llvmpipe_is_resource_referenced( struct pipe_context *pipe,
                                  unsigned level)
 {
    struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
-
-   /*
-    * XXX checking only resources with the right bind flags
-    * is unsafe since with opengl state tracker we can end up
-    * with resources bound to places they weren't supposed to be
-    * (buffers bound as sampler views is one possibility here).
-    */
    if (!(presource->bind & (PIPE_BIND_DEPTH_STENCIL |
                             PIPE_BIND_RENDER_TARGET |
-                            PIPE_BIND_SAMPLER_VIEW)))
+                            PIPE_BIND_SAMPLER_VIEW |
+                            PIPE_BIND_SHADER_BUFFER |
+                            PIPE_BIND_SHADER_IMAGE)))
       return LP_UNREFERENCED;
 
    return lp_setup_is_resource_referenced(llvmpipe->setup, presource);
@@ -658,7 +689,7 @@ llvmpipe_get_format_alignment( enum pipe_format format )
 
    bytes = size / 8;
 
-   if (!util_is_power_of_two(bytes)) {
+   if (!util_is_power_of_two_or_zero(bytes)) {
       bytes /= desc->nr_channels;
    }
 
@@ -672,17 +703,18 @@ llvmpipe_get_format_alignment( enum pipe_format format )
 
 /**
  * Create buffer which wraps user-space data.
+ * XXX unreachable.
  */
 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;
 
    buffer = CALLOC_STRUCT(llvmpipe_resource);
-   if(!buffer)
+   if (!buffer)
       return NULL;
 
    pipe_reference_init(&buffer->base.reference, 1);
@@ -713,18 +745,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,36 +766,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;
-
-   assert(!lpr->dt);
-
-   /* 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
  */
@@ -783,21 +773,25 @@ 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;
 }
 
+static void
+llvmpipe_memory_barrier(struct pipe_context *pipe,
+                       unsigned flags)
+{
+   /* this may be an overly large hammer for this nut. */
+   llvmpipe_finish(pipe, "barrier");
+}
 
 #ifdef DEBUG
 void
@@ -837,6 +831,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;
@@ -851,5 +846,8 @@ llvmpipe_init_context_resource_funcs(struct pipe_context *pipe)
    pipe->transfer_unmap = llvmpipe_transfer_unmap;
 
    pipe->transfer_flush_region = u_default_transfer_flush_region;
-   pipe->transfer_inline_write = u_default_transfer_inline_write;
+   pipe->buffer_subdata = u_default_buffer_subdata;
+   pipe->texture_subdata = u_default_texture_subdata;
+
+   pipe->memory_barrier = llvmpipe_memory_barrier;
 }