etnaviv: implement resource creation with modifier
[mesa.git] / src / gallium / drivers / etnaviv / etnaviv_transfer.c
index 269bd498f89f1975a6996ff07156e85bb26f9bde..6c1edd483541d5417e03b0f13e4cc1947842ae3f 100644 (file)
@@ -39,6 +39,8 @@
 #include "util/u_surface.h"
 #include "util/u_transfer.h"
 
+#include <drm_fourcc.h>
+
 /* Compute offset into a 1D/2D/3D buffer of a certain box.
  * This box must be aligned to the block width and height of the
  * underlying format. */
@@ -70,6 +72,10 @@ etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
    if (rsc->texture && !etna_resource_newer(rsc, etna_resource(rsc->texture)))
       rsc = etna_resource(rsc->texture); /* switch to using the texture resource */
 
+   /*
+    * Temporary resources are always pulled into the CPU domain, must push them
+    * back into GPU domain before the RS execs the blit to the base resource.
+    */
    if (trans->rsc)
       etna_bo_cpu_fini(etna_resource(trans->rsc)->bo);
 
@@ -85,21 +91,19 @@ etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
          struct etna_resource_level *res_level = &rsc->levels[ptrans->level];
          void *mapped = etna_bo_map(rsc->bo) + res_level->offset;
 
-         if (rsc->layout == ETNA_LAYOUT_LINEAR || rsc->layout == ETNA_LAYOUT_TILED) {
-            if (rsc->layout == ETNA_LAYOUT_TILED && !util_format_is_compressed(rsc->base.format)) {
-               etna_texture_tile(
-                  mapped + ptrans->box.z * res_level->layer_stride,
-                  trans->staging, ptrans->box.x, ptrans->box.y,
-                  res_level->stride, ptrans->box.width, ptrans->box.height,
-                  ptrans->stride, util_format_get_blocksize(rsc->base.format));
-            } else { /* non-tiled or compressed format */
-               util_copy_box(mapped, rsc->base.format, res_level->stride,
-                             res_level->layer_stride, ptrans->box.x,
-                             ptrans->box.y, ptrans->box.z, ptrans->box.width,
-                             ptrans->box.height, ptrans->box.depth,
-                             trans->staging, ptrans->stride,
-                             ptrans->layer_stride, 0, 0, 0 /* src x,y,z */);
-            }
+         if (rsc->layout == ETNA_LAYOUT_TILED) {
+            etna_texture_tile(
+               mapped + ptrans->box.z * res_level->layer_stride,
+               trans->staging, ptrans->box.x, ptrans->box.y,
+               res_level->stride, ptrans->box.width, ptrans->box.height,
+               ptrans->stride, util_format_get_blocksize(rsc->base.format));
+         } else if (rsc->layout == ETNA_LAYOUT_LINEAR) {
+            util_copy_box(mapped, rsc->base.format, res_level->stride,
+                          res_level->layer_stride, ptrans->box.x,
+                          ptrans->box.y, ptrans->box.z, ptrans->box.width,
+                          ptrans->box.height, ptrans->box.depth,
+                          trans->staging, ptrans->stride,
+                          ptrans->layer_stride, 0, 0, 0 /* src x,y,z */);
          } else {
             BUG("unsupported tiling %i", rsc->layout);
          }
@@ -114,7 +118,12 @@ etna_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans)
       }
    }
 
-   if (!trans->rsc)
+   /*
+    * Transfers without a temporary are only pulled into the CPU domain if they
+    * are not mapped unsynchronized. If they are, must push them back into GPU
+    * domain after CPU access is finished.
+    */
+   if (!trans->rsc && !(ptrans->usage & PIPE_TRANSFER_UNSYNCHRONIZED))
       etna_bo_cpu_fini(rsc->bo);
 
    pipe_resource_reference(&trans->rsc, NULL);
@@ -150,6 +159,20 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
 
    assert(level <= prsc->last_level);
 
+   /* Upgrade DISCARD_RANGE to WHOLE_RESOURCE if the whole resource is
+    * being mapped. If we add buffer reallocation to avoid CPU/GPU sync this
+    * check needs to be extended to coherent mappings and shared resources.
+    */
+   if ((usage & PIPE_TRANSFER_DISCARD_RANGE) &&
+       !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
+       prsc->last_level == 0 &&
+       prsc->width0 == box->width &&
+       prsc->height0 == box->height &&
+       prsc->depth0 == box->depth &&
+       prsc->array_size == 1) {
+      usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
+   }
+
    if (rsc->texture && !etna_resource_newer(rsc, etna_resource(rsc->texture))) {
       /* We have a texture resource which is the same age or newer than the
        * render resource. Use the texture resource, which avoids bouncing
@@ -182,13 +205,16 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
       templ.nr_samples = 0;
       templ.bind = PIPE_BIND_RENDER_TARGET;
 
-      trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR, &templ);
+      trans->rsc = etna_resource_alloc(pctx->screen, ETNA_LAYOUT_LINEAR,
+                                       DRM_FORMAT_MOD_LINEAR, &templ);
       if (!trans->rsc) {
          slab_free(&ctx->transfer_pool, trans);
          return NULL;
       }
 
-      etna_copy_resource(pctx, trans->rsc, prsc, level, trans->rsc->last_level);
+      if (!(usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE))
+         etna_copy_resource(pctx, trans->rsc, prsc, level,
+                            trans->rsc->last_level);
 
       /* Switch to using the temporary resource instead */
       rsc = etna_resource(trans->rsc);
@@ -253,26 +279,21 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
       PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE is set.
     */
 
-   /* No need to allocate a buffer for copying if the resource is not in use,
-    * and no tiling is needed, can just return a direct pointer.
+   /*
+    * Pull resources into the CPU domain. Only skipped for unsynchronized
+    * transfers without a temporary resource.
     */
-   bool in_place = rsc->layout == ETNA_LAYOUT_LINEAR ||
-                   (rsc->layout == ETNA_LAYOUT_TILED &&
-                    util_format_is_compressed(prsc->format));
-
-   /* Ignore PIPE_TRANSFER_UNSYNCHRONIZED and PIPE_TRANSFER_DONTBLOCK here.
-    * It appears that Gallium operates the index/vertex buffers in a
-    * circular fashion, and the CPU can catch up with the GPU and starts
-    * overwriting yet-to-be-processed entries, causing rendering corruption. */
-   uint32_t prep_flags = 0;
+   if (trans->rsc || !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
+      uint32_t prep_flags = 0;
 
-   if (usage & PIPE_TRANSFER_READ)
-      prep_flags |= DRM_ETNA_PREP_READ;
-   if (usage & PIPE_TRANSFER_WRITE)
-      prep_flags |= DRM_ETNA_PREP_WRITE;
+      if (usage & PIPE_TRANSFER_READ)
+         prep_flags |= DRM_ETNA_PREP_READ;
+      if (usage & PIPE_TRANSFER_WRITE)
+         prep_flags |= DRM_ETNA_PREP_WRITE;
 
-   if (etna_bo_cpu_prep(rsc->bo, prep_flags))
-      goto fail_prep;
+      if (etna_bo_cpu_prep(rsc->bo, prep_flags))
+         goto fail_prep;
+   }
 
    /* map buffer object */
    void *mapped = etna_bo_map(rsc->bo);
@@ -281,7 +302,7 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
 
    *out_transfer = ptrans;
 
-   if (in_place) {
+   if (rsc->layout == ETNA_LAYOUT_LINEAR) {
       ptrans->stride = res_level->stride;
       ptrans->layer_stride = res_level->layer_stride;
 
@@ -308,24 +329,21 @@ etna_transfer_map(struct pipe_context *pctx, struct pipe_resource *prsc,
          goto fail;
 
       if (usage & PIPE_TRANSFER_READ) {
-         /* untile or copy resource for reading */
-         if (rsc->layout == ETNA_LAYOUT_LINEAR || rsc->layout == ETNA_LAYOUT_TILED) {
-            if (rsc->layout == ETNA_LAYOUT_TILED && !util_format_is_compressed(rsc->base.format)) {
-               etna_texture_untile(trans->staging,
-                                   mapped + ptrans->box.z * res_level->layer_stride,
-                                   ptrans->box.x, ptrans->box.y, res_level->stride,
-                                   ptrans->box.width, ptrans->box.height, ptrans->stride,
-                                   util_format_get_blocksize(rsc->base.format));
-            } else { /* non-tiled or compressed format */
-               util_copy_box(trans->staging, rsc->base.format, ptrans->stride,
-                             ptrans->layer_stride, 0, 0, 0, /* dst x,y,z */
-                             ptrans->box.width, ptrans->box.height,
-                             ptrans->box.depth, mapped, res_level->stride,
-                             res_level->layer_stride, ptrans->box.x,
-                             ptrans->box.y, ptrans->box.z);
-            }
-         } else /* TODO supertiling */
-         {
+         if (rsc->layout == ETNA_LAYOUT_TILED) {
+            etna_texture_untile(trans->staging,
+                                mapped + ptrans->box.z * res_level->layer_stride,
+                                ptrans->box.x, ptrans->box.y, res_level->stride,
+                                ptrans->box.width, ptrans->box.height, ptrans->stride,
+                                util_format_get_blocksize(rsc->base.format));
+         } else if (rsc->layout == ETNA_LAYOUT_LINEAR) {
+            util_copy_box(trans->staging, rsc->base.format, ptrans->stride,
+                          ptrans->layer_stride, 0, 0, 0, /* dst x,y,z */
+                          ptrans->box.width, ptrans->box.height,
+                          ptrans->box.depth, mapped, res_level->stride,
+                          res_level->layer_stride, ptrans->box.x,
+                          ptrans->box.y, ptrans->box.z);
+         } else {
+            /* TODO supertiling */
             BUG("unsupported tiling %i for reading", rsc->layout);
          }
       }