lima/ppir: add ppir_node to ppir_src
[mesa.git] / src / gallium / drivers / etnaviv / etnaviv_resource.c
index 7fd374ae23d5ee781d13caa878c705744fada499..b03681cc5c0c7d0881b55e80ee4b5b1203246d29 100644 (file)
 #include "etnaviv_screen.h"
 #include "etnaviv_translate.h"
 
+#include "util/hash_table.h"
 #include "util/u_inlines.h"
 #include "util/u_memory.h"
 
-#include <drm_fourcc.h>
-
-#ifndef DRM_FORMAT_MOD_INVALID
-#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
-#endif
+#include "drm-uapi/drm_fourcc.h"
 
 static enum etna_surface_layout modifier_to_layout(uint64_t modifier)
 {
@@ -87,13 +84,36 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
                               struct etna_resource *rsc)
 {
    struct etna_screen *screen = etna_screen(pscreen);
-   size_t rt_ts_size, ts_layer_stride, pixels;
+   size_t rt_ts_size, ts_layer_stride;
+   size_t ts_bits_per_tile, bytes_per_tile;
+   uint8_t ts_mode = TS_MODE_128B; /* only used by halti5 */
+   int8_t ts_compress_fmt;
 
    assert(!rsc->ts_bo);
 
-   /* TS only for level 0 -- XXX is this formula correct? */
-   pixels = rsc->levels[0].layer_stride / util_format_get_blocksize(rsc->base.format);
-   ts_layer_stride = align(pixels * screen->specs.bits_per_tile / 0x80,
+   /* pre-v4 compression is largely useless, so disable it when not wanted for MSAA
+    * v4 compression can be enabled everywhere without any known drawback,
+    * except that in-place resolve must go through a slower path
+    */
+   ts_compress_fmt = (screen->specs.v4_compression || rsc->base.nr_samples > 1) ?
+                      translate_ts_format(rsc->base.format) : -1;
+
+   if (screen->specs.halti >= 5) {
+      /* enable 256B ts mode with compression, as it improves performance
+       * the size of the resource might also determine if we want to use it or not
+       */
+      if (ts_compress_fmt >= 0)
+         ts_mode = TS_MODE_256B;
+
+      ts_bits_per_tile = 4;
+      bytes_per_tile = ts_mode == TS_MODE_256B ? 256 : 128;
+   } else {
+      ts_bits_per_tile = screen->specs.bits_per_tile;
+      bytes_per_tile = 64;
+   }
+
+   ts_layer_stride = align(DIV_ROUND_UP(rsc->levels[0].layer_stride,
+                                        bytes_per_tile * 8 / ts_bits_per_tile),
                            0x100 * screen->specs.pixel_pipes);
    rt_ts_size = ts_layer_stride * rsc->base.array_size;
    if (rt_ts_size == 0)
@@ -114,18 +134,13 @@ etna_screen_resource_alloc_ts(struct pipe_screen *pscreen,
    rsc->levels[0].ts_offset = 0;
    rsc->levels[0].ts_layer_stride = ts_layer_stride;
    rsc->levels[0].ts_size = rt_ts_size;
-
-   /* It is important to initialize the TS, as random pattern
-    * can result in crashes. Do this on the CPU as this only happens once
-    * per surface anyway and it's a small area, so it may not be worth
-    * queuing this to the GPU. */
-   void *ts_map = etna_bo_map(rt_ts);
-   memset(ts_map, screen->specs.ts_clear_value, rt_ts_size);
+   rsc->levels[0].ts_mode = ts_mode;
+   rsc->levels[0].ts_compress_fmt = ts_compress_fmt;
 
    return true;
 }
 
-static boolean
+static bool
 etna_screen_can_create_resource(struct pipe_screen *pscreen,
                                 const struct pipe_resource *templat)
 {
@@ -158,6 +173,7 @@ setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY,
 
       mip->width = width;
       mip->height = height;
+      mip->depth = depth;
       mip->padded_width = align(width * msaa_xscale, paddingX);
       mip->padded_height = align(height * msaa_yscale, paddingY);
       mip->stride = util_format_get_stride(prsc->format, mip->padded_width);
@@ -176,10 +192,20 @@ setup_miptree(struct etna_resource *rsc, unsigned paddingX, unsigned paddingY,
    return size;
 }
 
+/* Is rs alignment needed? */
+static bool is_rs_align(struct etna_screen *screen,
+                        const struct pipe_resource *tmpl)
+{
+   return screen->specs.use_blt ? false : (
+      VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN) ||
+      !etna_resource_sampler_only(tmpl));
+}
+
 /* Create a new resource object, using the given template info */
 struct pipe_resource *
 etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
-                    uint64_t modifier, const struct pipe_resource *templat)
+                    enum etna_resource_addressing_mode mode, uint64_t modifier,
+                    const struct pipe_resource *templat)
 {
    struct etna_screen *screen = etna_screen(pscreen);
    struct etna_resource *rsc;
@@ -217,11 +243,9 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
        * resolve engine's width.  If not, we must not align resources used
        * only for textures. If this GPU uses the BLT engine, never do RS align.
        */
-      bool rs_align = screen->specs.use_blt ? false : (
-                         VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN) ||
-                         !etna_resource_sampler_only(templat));
-      etna_layout_multiple(layout, screen->specs.pixel_pipes, rs_align, &paddingX,
-                           &paddingY, &halign);
+      etna_layout_multiple(layout, screen->specs.pixel_pipes,
+                           is_rs_align (screen, templat),
+                           &paddingX, &paddingY, &halign);
       assert(paddingX && paddingY);
    } else {
       /* Compressed textures are padded to their block size, but we don't have
@@ -230,17 +254,19 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
       paddingY = 1;
    }
 
-   if (!screen->specs.use_blt && templat->target != PIPE_BUFFER)
-      etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
+   if (!screen->specs.use_blt && templat->target != PIPE_BUFFER && layout == ETNA_LAYOUT_LINEAR)
+      paddingY = align(paddingY, ETNA_RS_HEIGHT_MASK + 1);
 
-   if (templat->bind & PIPE_BIND_SCANOUT) {
+   if (templat->bind & PIPE_BIND_SCANOUT && screen->ro->kms_fd >= 0) {
       struct pipe_resource scanout_templat = *templat;
       struct renderonly_scanout *scanout;
       struct winsys_handle handle;
 
       /* pad scanout buffer size to be compatible with the RS */
-      if (!screen->specs.use_blt && modifier == DRM_FORMAT_MOD_LINEAR)
-         etna_adjust_rs_align(screen->specs.pixel_pipes, &paddingX, &paddingY);
+      if (!screen->specs.use_blt && modifier == DRM_FORMAT_MOD_LINEAR) {
+         paddingX = align(paddingX, ETNA_RS_WIDTH_MASK + 1);
+         paddingY = align(paddingY, ETNA_RS_HEIGHT_MASK + 1);
+      }
 
       scanout_templat.width0 = align(scanout_templat.width0, paddingX);
       scanout_templat.height0 = align(scanout_templat.height0, paddingY);
@@ -254,7 +280,7 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
       handle.modifier = modifier;
       rsc = etna_resource(pscreen->resource_from_handle(pscreen, templat,
                                                         &handle,
-                                                        PIPE_HANDLE_USAGE_WRITE));
+                                                        PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE));
       close(handle.handle);
       if (!rsc)
          return NULL;
@@ -273,9 +299,9 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
    rsc->base.nr_samples = nr_samples;
    rsc->layout = layout;
    rsc->halign = halign;
+   rsc->addressing_mode = mode;
 
    pipe_reference_init(&rsc->base.reference, 1);
-   list_inithead(&rsc->list);
 
    size = setup_miptree(rsc, paddingX, paddingY, msaa_xscale, msaa_yscale);
 
@@ -296,6 +322,11 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout,
       memset(map, 0, size);
    }
 
+   rsc->pending_ctx = _mesa_set_create(NULL, _mesa_hash_pointer,
+                                       _mesa_key_pointer_equal);
+   if (!rsc->pending_ctx)
+      goto free_rsc;
+
    return &rsc->base;
 
 free_rsc:
@@ -309,12 +340,14 @@ etna_resource_create(struct pipe_screen *pscreen,
 {
    struct etna_screen *screen = etna_screen(pscreen);
 
-   /* Figure out what tiling to use -- for now, assume that texture cannot be linear.
-    * there is a capability LINEAR_TEXTURE_SUPPORT (supported on gc880 and
-    * gc2000 at least), but not sure how it works.
+   /* Figure out what tiling and address mode to use -- for now, assume that
+    * texture cannot be linear. there is a capability LINEAR_TEXTURE_SUPPORT
+    * (supported on gc880 and gc2000 at least), but not sure how it works.
     * Buffers always have LINEAR layout.
     */
    unsigned layout = ETNA_LAYOUT_LINEAR;
+   enum etna_resource_addressing_mode mode = ETNA_ADDRESSING_MODE_TILED;
+
    if (etna_resource_sampler_only(templat)) {
       /* The buffer is only used for texturing, so create something
        * directly compatible with the sampler.  Such a buffer can
@@ -357,7 +390,7 @@ etna_resource_create(struct pipe_screen *pscreen,
       layout = ETNA_LAYOUT_LINEAR;
 
    /* modifier is only used for scanout surfaces, so safe to use LINEAR here */
-   return etna_resource_alloc(pscreen, layout, DRM_FORMAT_MOD_LINEAR, templat);
+   return etna_resource_alloc(pscreen, layout, mode, DRM_FORMAT_MOD_LINEAR, templat);
 }
 
 enum modifier_priority {
@@ -438,7 +471,7 @@ etna_resource_create_modifiers(struct pipe_screen *pscreen,
    tmpl.bind |= PIPE_BIND_SCANOUT;
 
    return etna_resource_alloc(pscreen, modifier_to_layout(modifier),
-                              modifier, &tmpl);
+                              ETNA_ADDRESSING_MODE_TILED, modifier, &tmpl);
 }
 
 static void
@@ -455,8 +488,14 @@ etna_resource_changed(struct pipe_screen *pscreen, struct pipe_resource *prsc)
 static void
 etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
 {
+   struct etna_screen *screen = etna_screen(pscreen);
    struct etna_resource *rsc = etna_resource(prsc);
 
+   mtx_lock(&screen->lock);
+   _mesa_set_remove_key(screen->used_resources, rsc);
+   _mesa_set_destroy(rsc->pending_ctx, NULL);
+   mtx_unlock(&screen->lock);
+
    if (rsc->bo)
       etna_bo_del(rsc->bo);
 
@@ -466,11 +505,12 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc)
    if (rsc->scanout)
       renderonly_scanout_destroy(rsc->scanout, etna_screen(pscreen)->ro);
 
-   list_delinit(&rsc->list);
-
    pipe_resource_reference(&rsc->texture, NULL);
    pipe_resource_reference(&rsc->external, NULL);
 
+   for (unsigned i = 0; i < ETNA_NUM_LOD; i++)
+      FREE(rsc->levels[i].patch_offsets);
+
    FREE(rsc);
 }
 
@@ -501,7 +541,6 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
    *prsc = *tmpl;
 
    pipe_reference_init(&prsc->reference, 1);
-   list_inithead(&rsc->list);
    prsc->screen = pscreen;
 
    rsc->bo = etna_screen_bo_from_handle(pscreen, handle, &level->stride);
@@ -511,19 +550,22 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
    rsc->seqno = 1;
    rsc->layout = modifier_to_layout(handle->modifier);
    rsc->halign = TEXTURE_HALIGN_FOUR;
+   rsc->addressing_mode = ETNA_ADDRESSING_MODE_TILED;
 
 
    level->width = tmpl->width0;
    level->height = tmpl->height0;
+   level->depth = tmpl->depth0;
+   level->offset = handle->offset;
 
    /* Determine padding of the imported resource. */
    unsigned paddingX = 0, paddingY = 0;
    etna_layout_multiple(rsc->layout, screen->specs.pixel_pipes,
-                        VIV_FEATURE(screen, chipMinorFeatures1, TEXTURE_HALIGN),
+                        is_rs_align(screen, tmpl),
                         &paddingX, &paddingY, &rsc->halign);
 
-   if (!screen->specs.use_blt)
-      etna_adjust_rs_align(screen->specs.pixel_pipes, NULL, &paddingY);
+   if (!screen->specs.use_blt && rsc->layout == ETNA_LAYOUT_LINEAR)
+      paddingY = align(paddingY, ETNA_RS_HEIGHT_MASK + 1);
    level->padded_width = align(level->width, paddingX);
    level->padded_height = align(level->height, paddingY);
 
@@ -547,6 +589,11 @@ etna_resource_from_handle(struct pipe_screen *pscreen,
       goto fail;
    }
 
+   rsc->pending_ctx = _mesa_set_create(NULL, _mesa_hash_pointer,
+                                       _mesa_key_pointer_equal);
+   if (!rsc->pending_ctx)
+      goto fail;
+
    if (rsc->layout == ETNA_LAYOUT_LINEAR) {
       /*
        * Both sampler and pixel pipes can't handle linear, create a compatible
@@ -580,7 +627,7 @@ fail:
    return NULL;
 }
 
-static boolean
+static bool
 etna_resource_get_handle(struct pipe_screen *pscreen,
                          struct pipe_context *pctx,
                          struct pipe_resource *prsc,
@@ -598,22 +645,23 @@ etna_resource_get_handle(struct pipe_screen *pscreen,
       rsc = etna_resource(rsc->external);
 
    handle->stride = rsc->levels[0].stride;
+   handle->offset = rsc->levels[0].offset;
    handle->modifier = layout_to_modifier(rsc->layout);
 
    if (handle->type == WINSYS_HANDLE_TYPE_SHARED) {
       return etna_bo_get_name(rsc->bo, &handle->handle) == 0;
    } else if (handle->type == WINSYS_HANDLE_TYPE_KMS) {
       if (renderonly_get_handle(scanout, handle)) {
-         return TRUE;
+         return true;
       } else {
          handle->handle = etna_bo_handle(rsc->bo);
-         return TRUE;
+         return true;
       }
    } else if (handle->type == WINSYS_HANDLE_TYPE_FD) {
       handle->handle = etna_bo_dmabuf(rsc->bo);
-      return TRUE;
+      return true;
    } else {
-      return FALSE;
+      return false;
    }
 }
 
@@ -621,20 +669,47 @@ void
 etna_resource_used(struct etna_context *ctx, struct pipe_resource *prsc,
                    enum etna_resource_status status)
 {
+   struct etna_screen *screen = ctx->screen;
    struct etna_resource *rsc;
 
    if (!prsc)
       return;
 
    rsc = etna_resource(prsc);
+
+   mtx_lock(&screen->lock);
+
+   /*
+    * if we are pending read or write by any other context or
+    * if reading a resource pending a write, then
+    * flush all the contexts to maintain coherency
+    */
+   if (((status & ETNA_PENDING_WRITE) && rsc->status) ||
+       ((status & ETNA_PENDING_READ) && (rsc->status & ETNA_PENDING_WRITE))) {
+      set_foreach(rsc->pending_ctx, entry) {
+         struct etna_context *extctx = (struct etna_context *)entry->key;
+         struct pipe_context *pctx = &extctx->base;
+
+         if (extctx == ctx)
+            continue;
+
+         pctx->flush(pctx, NULL, 0);
+         /* It's safe to clear the status here. If we need to flush it means
+          * either another context had the resource in exclusive (write) use,
+          * or we transition the resource to exclusive use in our context.
+          * In both cases the new status accurately reflects the resource use
+          * after the flush.
+          */
+         rsc->status = 0;
+      }
+   }
+
    rsc->status |= status;
 
-   /* TODO resources can actually be shared across contexts,
-    * so I'm not sure a single list-head will do the trick? */
-   debug_assert((rsc->pending_ctx == ctx) || !rsc->pending_ctx);
-   list_delinit(&rsc->list);
-   list_addtail(&rsc->list, &ctx->used_resources);
-   rsc->pending_ctx = ctx;
+   _mesa_set_add(screen->used_resources, rsc);
+   _mesa_set_add(rsc->pending_ctx, ctx);
+
+   mtx_unlock(&screen->lock);
 }
 
 bool