lima: track write submits of context (v3)
[mesa.git] / src / gallium / drivers / lima / lima_resource.c
index 4e215e9e08f6a4a27ab5447e097882ca7d51d69f..6c207f19d9186f58de1c33e61cd034231fa50974 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "util/u_memory.h"
 #include "util/u_blitter.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
 #include "util/u_inlines.h"
 #include "util/u_math.h"
 #include "util/u_debug.h"
@@ -44,7 +44,7 @@
 #include "lima_resource.h"
 #include "lima_bo.h"
 #include "lima_util.h"
-#include "lima_tiling.h"
+#include "pan_tiling.h"
 
 static struct pipe_resource *
 lima_resource_create_scanout(struct pipe_screen *pscreen,
@@ -116,6 +116,7 @@ setup_miptree(struct lima_resource *res,
       res->levels[level].width = aligned_width;
       res->levels[level].stride = stride;
       res->levels[level].offset = size;
+      res->levels[level].layer_stride = util_format_get_stride(pres->format, align(width, 16)) * align(height, 16);
 
       /* The start address of each level <= 10 must be 64-aligned
        * in order to be able to pass the addresses
@@ -177,9 +178,13 @@ _lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
                                      int count)
 {
    struct lima_screen *screen = lima_screen(pscreen);
-   bool should_tile = false;
+   bool should_tile = lima_debug & LIMA_DEBUG_NO_TILING ? false : true;
    unsigned width, height;
    bool should_align_dimensions;
+   bool has_user_modifiers = true;
+
+   if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)
+      has_user_modifiers = false;
 
    /* VBOs/PBOs are untiled (and 1 height). */
    if (templat->target == PIPE_BUFFER)
@@ -188,9 +193,17 @@ _lima_resource_create_with_modifiers(struct pipe_screen *pscreen,
    if (templat->bind & (PIPE_BIND_LINEAR | PIPE_BIND_SCANOUT))
       should_tile = false;
 
-   /* if linear buffer is not allowed, alloc fail */
-   if (!should_tile && !drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
-      return NULL;
+   /* If there's no user modifiers and buffer is shared we use linear */
+   if (!has_user_modifiers && (templat->bind & PIPE_BIND_SHARED))
+      should_tile = false;
+
+   if (drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
+      should_tile = false;
+
+   if (has_user_modifiers &&
+      !drm_find_modifier(DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED,
+                         modifiers, count))
+      should_tile = false;
 
    if (should_tile || (templat->bind & PIPE_BIND_RENDER_TARGET) ||
        (templat->bind & PIPE_BIND_DEPTH_STENCIL)) {
@@ -227,10 +240,9 @@ static struct pipe_resource *
 lima_resource_create(struct pipe_screen *pscreen,
                      const struct pipe_resource *templat)
 {
-   static const uint64_t modifiers[] = {
-      DRM_FORMAT_MOD_LINEAR,
-   };
-   return _lima_resource_create_with_modifiers(pscreen, templat, modifiers, ARRAY_SIZE(modifiers));
+   const uint64_t mod = DRM_FORMAT_MOD_INVALID;
+
+   return _lima_resource_create_with_modifiers(pscreen, templat, &mod, 1);
 }
 
 static struct pipe_resource *
@@ -259,11 +271,14 @@ lima_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pres)
    struct lima_resource *res = lima_resource(pres);
 
    if (res->bo)
-      lima_bo_free(res->bo);
+      lima_bo_unreference(res->bo);
 
    if (res->scanout)
       renderonly_scanout_destroy(res->scanout, screen->ro);
 
+   if (res->damage.region)
+      FREE(res->damage.region);
+
    FREE(res);
 }
 
@@ -311,8 +326,24 @@ lima_resource_from_handle(struct pipe_screen *pscreen,
    else
       res->levels[0].width = pres->width0;
 
-   handle->modifier = DRM_FORMAT_MOD_LINEAR;
-   res->tiled = false;
+   switch (handle->modifier) {
+   case DRM_FORMAT_MOD_LINEAR:
+      res->tiled = false;
+      break;
+   case DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED:
+      res->tiled = true;
+      break;
+   case DRM_FORMAT_MOD_INVALID:
+      /* Modifier wasn't specified and it's shared buffer. We create these
+       * as linear, so disable tiling.
+       */
+      res->tiled = false;
+      break;
+   default:
+      fprintf(stderr, "Attempted to import unsupported modifier 0x%llx\n",
+                  (long long)handle->modifier);
+      goto err_out;
+   }
 
    return pres;
 
@@ -321,7 +352,7 @@ err_out:
    return NULL;
 }
 
-static boolean
+static bool
 lima_resource_get_handle(struct pipe_screen *pscreen,
                          struct pipe_context *pctx,
                          struct pipe_resource *pres,
@@ -330,17 +361,107 @@ lima_resource_get_handle(struct pipe_screen *pscreen,
    struct lima_screen *screen = lima_screen(pscreen);
    struct lima_resource *res = lima_resource(pres);
 
-   handle->modifier = DRM_FORMAT_MOD_LINEAR;
+   if (res->tiled)
+      handle->modifier = DRM_FORMAT_MOD_ARM_16X16_BLOCK_U_INTERLEAVED;
+   else
+      handle->modifier = DRM_FORMAT_MOD_LINEAR;
 
    if (handle->type == WINSYS_HANDLE_TYPE_KMS && screen->ro &&
        renderonly_get_handle(res->scanout, handle))
-      return TRUE;
+      return true;
 
    if (!lima_bo_export(res->bo, handle))
-      return FALSE;
+      return false;
 
    handle->stride = res->levels[0].stride;
-   return TRUE;
+   return true;
+}
+
+static void
+get_scissor_from_box(struct pipe_scissor_state *s,
+                     const struct pipe_box *b, int h)
+{
+   int y = h - (b->y + b->height);
+   /* region in tile unit */
+   s->minx = b->x >> 4;
+   s->miny = y >> 4;
+   s->maxx = (b->x + b->width + 0xf) >> 4;
+   s->maxy = (y + b->height + 0xf) >> 4;
+}
+
+static void
+get_damage_bound_box(struct pipe_resource *pres,
+                     const struct pipe_box *rects,
+                     unsigned int nrects,
+                     struct pipe_scissor_state *bound)
+{
+   struct pipe_box b = rects[0];
+
+   for (int i = 1; i < nrects; i++)
+      u_box_union_2d(&b, &b, rects + i);
+
+   int ret = u_box_clip_2d(&b, &b, pres->width0, pres->height0);
+   if (ret < 0)
+      memset(bound, 0, sizeof(*bound));
+   else
+      get_scissor_from_box(bound, &b, pres->height0);
+}
+
+static void
+lima_resource_set_damage_region(struct pipe_screen *pscreen,
+                                struct pipe_resource *pres,
+                                unsigned int nrects,
+                                const struct pipe_box *rects)
+{
+   struct lima_resource *res = lima_resource(pres);
+   struct lima_damage_region *damage = &res->damage;
+   int i;
+
+   if (damage->region) {
+      FREE(damage->region);
+      damage->region = NULL;
+      damage->num_region = 0;
+   }
+
+   if (!nrects)
+      return;
+
+   /* check full damage
+    *
+    * TODO: currently only check if there is any single damage
+    * region that can cover the full render target; there may
+    * be some accurate way, but a single window size damage
+    * region is most of the case from weston
+    */
+   for (i = 0; i < nrects; i++) {
+      if (rects[i].x <= 0 && rects[i].y <= 0 &&
+          rects[i].x + rects[i].width >= pres->width0 &&
+          rects[i].y + rects[i].height >= pres->height0)
+         return;
+   }
+
+   struct pipe_scissor_state *bound = &damage->bound;
+   get_damage_bound_box(pres, rects, nrects, bound);
+
+   damage->region = CALLOC(nrects, sizeof(*damage->region));
+   if (!damage->region)
+      return;
+
+   for (i = 0; i < nrects; i++)
+      get_scissor_from_box(damage->region + i, rects + i,
+                           pres->height0);
+
+   /* is region aligned to tiles? */
+   damage->aligned = true;
+   for (i = 0; i < nrects; i++) {
+      if (rects[i].x & 0xf || rects[i].y & 0xf ||
+          rects[i].width & 0xf || rects[i].height & 0xf) {
+         damage->aligned = false;
+         break;
+      }
+   }
+
+   damage->num_region = nrects;
 }
 
 void
@@ -351,6 +472,7 @@ lima_resource_screen_init(struct lima_screen *screen)
    screen->base.resource_from_handle = lima_resource_from_handle;
    screen->base.resource_destroy = lima_resource_destroy;
    screen->base.resource_get_handle = lima_resource_get_handle;
+   screen->base.set_damage_region = lima_resource_set_damage_region;
 }
 
 static struct pipe_surface *
@@ -382,6 +504,8 @@ lima_surface_create(struct pipe_context *pctx,
    surf->tiled_w = align(psurf->width, 16) >> 4;
    surf->tiled_h = align(psurf->height, 16) >> 4;
 
+   surf->reload = true;
+
    struct lima_context *ctx = lima_context(pctx);
    if (ctx->plb_pp_stream) {
       struct lima_ctx_plb_pp_stream_key key = {
@@ -435,7 +559,7 @@ lima_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurf)
          struct lima_ctx_plb_pp_stream *s = entry->data;
          if (--s->refcnt == 0) {
             if (s->bo)
-               lima_bo_free(s->bo);
+               lima_bo_unreference(s->bo);
             _mesa_hash_table_remove(ctx->plb_pp_stream, entry);
             ralloc_free(s);
          }
@@ -470,8 +594,7 @@ lima_transfer_map(struct pipe_context *pctx,
     * range, so no need to sync */
    if (pres->usage != PIPE_USAGE_STREAM) {
       if (usage & PIPE_TRANSFER_READ_WRITE) {
-         if (lima_need_flush(ctx, bo, usage & PIPE_TRANSFER_WRITE))
-            lima_flush(ctx);
+         lima_flush_submit_accessing_bo(ctx, bo, usage & PIPE_TRANSFER_WRITE);
 
          unsigned op = usage & PIPE_TRANSFER_WRITE ?
             LIMA_GEM_WAIT_WRITE : LIMA_GEM_WAIT_READ;
@@ -502,20 +625,26 @@ lima_transfer_map(struct pipe_context *pctx,
 
       trans->staging = malloc(ptrans->stride * ptrans->box.height * ptrans->box.depth);
 
-      if (usage & PIPE_TRANSFER_READ)
-         lima_load_tiled_image(trans->staging, bo->map + res->levels[level].offset,
-                              &ptrans->box,
-                              ptrans->stride,
-                              res->levels[level].stride,
-                              util_format_get_blocksize(pres->format));
+      if (usage & PIPE_TRANSFER_READ) {
+         unsigned i;
+         for (i = 0; i < ptrans->box.depth; i++)
+            panfrost_load_tiled_image(
+               trans->staging + i * ptrans->stride * ptrans->box.height,
+               bo->map + res->levels[level].offset + (i + box->z) * res->levels[level].layer_stride,
+               ptrans->box.x, ptrans->box.y,
+               ptrans->box.width, ptrans->box.height,
+               ptrans->stride,
+               res->levels[level].stride,
+               pres->format);
+      }
 
       return trans->staging;
    } else {
       ptrans->stride = res->levels[level].stride;
-      ptrans->layer_stride = ptrans->stride * box->height;
+      ptrans->layer_stride = res->levels[level].layer_stride;
 
       return bo->map + res->levels[level].offset +
-         box->z * ptrans->layer_stride +
+         box->z * res->levels[level].layer_stride +
          box->y / util_format_get_blockheight(pres->format) * ptrans->stride +
          box->x / util_format_get_blockwidth(pres->format) *
          util_format_get_blocksize(pres->format);
@@ -542,12 +671,18 @@ lima_transfer_unmap(struct pipe_context *pctx,
 
    if (trans->staging) {
       pres = &res->base;
-      if (ptrans->usage & PIPE_TRANSFER_WRITE)
-         lima_store_tiled_image(bo->map + res->levels[ptrans->level].offset, trans->staging,
-                              &ptrans->box,
-                              res->levels[ptrans->level].stride,
-                              ptrans->stride,
-                              util_format_get_blocksize(pres->format));
+      if (ptrans->usage & PIPE_TRANSFER_WRITE) {
+         unsigned i;
+         for (i = 0; i < ptrans->box.depth; i++)
+            panfrost_store_tiled_image(
+               bo->map + res->levels[ptrans->level].offset + (i + ptrans->box.z) * res->levels[ptrans->level].layer_stride,
+               trans->staging + i * ptrans->stride * ptrans->box.height,
+               ptrans->box.x, ptrans->box.y,
+               ptrans->box.width, ptrans->box.height,
+               res->levels[ptrans->level].stride,
+               ptrans->stride,
+               pres->format);
+      }
       free(trans->staging);
    }