a4xx: add noperspective interpolation support
[mesa.git] / src / gallium / drivers / freedreno / freedreno_resource.c
index 0f846c7b2555b565d65b68acb0d9d38a06d41f56..faafd6fe82db09d42b3ae51c7f79e76251df7bd7 100644 (file)
@@ -48,7 +48,7 @@
 #include <errno.h>
 
 /* XXX this should go away, needed for 'struct winsys_handle' */
-#include "state_tracker/drm_driver.h"
+#include "frontend/drm_driver.h"
 
 /* A private modifier for now, so we have a way to request tiled but not
  * compressed.  It would perhaps be good to get real modifiers for the
@@ -69,6 +69,9 @@ rebind_resource_in_ctx(struct fd_context *ctx, struct fd_resource *rsc)
 {
        struct pipe_resource *prsc = &rsc->base;
 
+       if (ctx->rebind_resource)
+               ctx->rebind_resource(ctx, rsc);
+
        /* VBOs */
        if (rsc->dirty & FD_DIRTY_VTXBUF) {
                struct fd_vertexbuf_stateobj *vb = &ctx->vtx.vertexbuf;
@@ -146,11 +149,19 @@ rebind_resource_in_ctx(struct fd_context *ctx, struct fd_resource *rsc)
 }
 
 static void
-rebind_resource(struct fd_context *ctx, struct fd_resource *rsc)
+rebind_resource(struct fd_resource *rsc)
 {
+       struct fd_screen *screen = fd_screen(rsc->base.screen);
+
+       fd_screen_lock(screen);
        fd_resource_lock(rsc);
-       rebind_resource_in_ctx(ctx, rsc);
+
+       if (rsc->dirty)
+               list_for_each_entry (struct fd_context, ctx, &screen->context_list, node)
+                       rebind_resource_in_ctx(ctx, rsc);
+
        fd_resource_unlock(rsc);
+       fd_screen_unlock(screen);
 }
 
 static void
@@ -256,8 +267,9 @@ fd_try_shadow_resource(struct fd_context *ctx, struct fd_resource *rsc,
         * should empty/destroy rsc->batches hashset)
         */
        fd_bc_invalidate_resource(rsc, false);
+       rebind_resource(rsc);
 
-       mtx_lock(&ctx->screen->lock);
+       fd_screen_lock(ctx->screen);
 
        /* Swap the backing bo's, so shadow becomes the old buffer,
         * blit from shadow to new buffer.  From here on out, we
@@ -291,7 +303,7 @@ fd_try_shadow_resource(struct fd_context *ctx, struct fd_resource *rsc,
        }
        swap(rsc->batch_mask, shadow->batch_mask);
 
-       mtx_unlock(&ctx->screen->lock);
+       fd_screen_unlock(ctx->screen);
 
        struct pipe_blit_info blit = {};
        blit.dst.resource = prsc;
@@ -368,7 +380,7 @@ fd_try_shadow_resource(struct fd_context *ctx, struct fd_resource *rsc,
  * Uncompress an UBWC compressed buffer "in place".  This works basically
  * like resource shadowing, creating a new resource, and doing an uncompress
  * blit, and swapping the state between shadow and original resource so it
- * appears to the state tracker as if nothing changed.
+ * appears to the gallium frontends as if nothing changed.
  */
 void
 fd_resource_uncompress(struct fd_context *ctx, struct fd_resource *rsc)
@@ -378,18 +390,6 @@ fd_resource_uncompress(struct fd_context *ctx, struct fd_resource *rsc)
 
        /* shadow should not fail in any cases where we need to uncompress: */
        debug_assert(success);
-
-       /*
-        * TODO what if rsc is used in other contexts, we don't currently
-        * have a good way to rebind_resource() in other contexts.  And an
-        * app that is reading one resource in multiple contexts, isn't
-        * going to expect that the resource is modified.
-        *
-        * Hopefully the edge cases where we need to uncompress are rare
-        * enough that they mostly only show up in deqp.
-        */
-
-       rebind_resource(ctx, rsc);
 }
 
 static struct fd_resource *
@@ -481,9 +481,9 @@ flush_resource(struct fd_context *ctx, struct fd_resource *rsc, unsigned usage)
 {
        struct fd_batch *write_batch = NULL;
 
-       mtx_lock(&ctx->screen->lock);
+       fd_screen_lock(ctx->screen);
        fd_batch_reference_locked(&write_batch, rsc->write_batch);
-       mtx_unlock(&ctx->screen->lock);
+       fd_screen_unlock(ctx->screen);
 
        if (usage & PIPE_TRANSFER_WRITE) {
                struct fd_batch *batch, *batches[32] = {};
@@ -494,11 +494,11 @@ flush_resource(struct fd_context *ctx, struct fd_resource *rsc, unsigned usage)
                 * to iterate the batches which reference this resource.  So
                 * we must first grab references under a lock, then flush.
                 */
-               mtx_lock(&ctx->screen->lock);
+               fd_screen_lock(ctx->screen);
                batch_mask = rsc->batch_mask;
                foreach_batch(batch, &ctx->screen->batch_cache, batch_mask)
                        fd_batch_reference_locked(&batches[batch->idx], batch);
-               mtx_unlock(&ctx->screen->lock);
+               fd_screen_unlock(ctx->screen);
 
                foreach_batch(batch, &ctx->screen->batch_cache, batch_mask)
                        fd_batch_flush(batch);
@@ -569,6 +569,11 @@ fd_resource_transfer_map(struct pipe_context *pctx,
        DBG("prsc=%p, level=%u, usage=%x, box=%dx%d+%d,%d", prsc, level, usage,
                box->width, box->height, box->x, box->y);
 
+       if ((usage & PIPE_TRANSFER_MAP_DIRECTLY) && rsc->layout.tile_mode) {
+               DBG("CANNOT MAP DIRECTLY!\n");
+               return NULL;
+       }
+
        ptrans = slab_alloc(&ctx->transfer_pool);
        if (!ptrans)
                return NULL;
@@ -637,8 +642,8 @@ fd_resource_transfer_map(struct pipe_context *pctx,
 
        if (usage & PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE) {
                if (needs_flush || fd_resource_busy(rsc, op)) {
+                       rebind_resource(rsc);
                        realloc_bo(rsc, fd_bo_size(rsc->bo));
-                       rebind_resource(ctx, rsc);
                }
        } else if ((usage & PIPE_TRANSFER_WRITE) &&
                           prsc->target == PIPE_BUFFER &&
@@ -681,7 +686,6 @@ fd_resource_transfer_map(struct pipe_context *pctx,
                        if (needs_flush && fd_try_shadow_resource(ctx, rsc, level,
                                                        box, DRM_FORMAT_MOD_LINEAR)) {
                                needs_flush = busy = false;
-                               rebind_resource(ctx, rsc);
                                ctx->stats.shadow_uploads++;
                        } else {
                                struct fd_resource *staging_rsc;
@@ -802,104 +806,6 @@ fd_resource_get_handle(struct pipe_screen *pscreen,
                        fd_resource_slice(rsc, 0)->pitch, handle);
 }
 
-static uint32_t
-setup_slices(struct fd_resource *rsc, uint32_t alignment, enum pipe_format format)
-{
-       struct pipe_resource *prsc = &rsc->base;
-       struct fd_screen *screen = fd_screen(prsc->screen);
-       enum util_format_layout layout = util_format_description(format)->layout;
-       uint32_t pitchalign = screen->gmem_alignw;
-       uint32_t level, size = 0;
-       uint32_t width = prsc->width0;
-       uint32_t height = prsc->height0;
-       uint32_t depth = prsc->depth0;
-       /* in layer_first layout, the level (slice) contains just one
-        * layer (since in fact the layer contains the slices)
-        */
-       uint32_t layers_in_level = rsc->layout.layer_first ? 1 : prsc->array_size;
-
-       for (level = 0; level <= prsc->last_level; level++) {
-               struct fdl_slice *slice = fd_resource_slice(rsc, level);
-               uint32_t blocks;
-
-               if (layout == UTIL_FORMAT_LAYOUT_ASTC)
-                       width = util_align_npot(width, pitchalign * util_format_get_blockwidth(format));
-               else
-                       width = align(width, pitchalign);
-               slice->pitch = util_format_get_nblocksx(format, width) * rsc->layout.cpp;
-               slice->offset = size;
-               blocks = util_format_get_nblocks(format, width, height);
-               /* 1d array and 2d array textures must all have the same layer size
-                * for each miplevel on a3xx. 3d textures can have different layer
-                * sizes for high levels, but the hw auto-sizer is buggy (or at least
-                * different than what this code does), so as soon as the layer size
-                * range gets into range, we stop reducing it.
-                */
-               if (prsc->target == PIPE_TEXTURE_3D && (
-                                       level == 1 ||
-                                       (level > 1 && fd_resource_slice(rsc, level - 1)->size0 > 0xf000)))
-                       slice->size0 = align(blocks * rsc->layout.cpp, alignment);
-               else if (level == 0 || rsc->layout.layer_first || alignment == 1)
-                       slice->size0 = align(blocks * rsc->layout.cpp, alignment);
-               else
-                       slice->size0 = fd_resource_slice(rsc, level - 1)->size0;
-
-               size += slice->size0 * depth * layers_in_level;
-
-               width = u_minify(width, 1);
-               height = u_minify(height, 1);
-               depth = u_minify(depth, 1);
-       }
-
-       return size;
-}
-
-static uint32_t
-slice_alignment(enum pipe_texture_target target)
-{
-       /* on a3xx, 2d array and 3d textures seem to want their
-        * layers aligned to page boundaries:
-        */
-       switch (target) {
-       case PIPE_TEXTURE_3D:
-       case PIPE_TEXTURE_1D_ARRAY:
-       case PIPE_TEXTURE_2D_ARRAY:
-               return 4096;
-       default:
-               return 1;
-       }
-}
-
-/* cross generation texture layout to plug in to screen->setup_slices()..
- * replace with generation specific one as-needed.
- *
- * TODO for a4xx probably can extract out the a4xx specific logic int
- * a small fd4_setup_slices() wrapper that sets up layer_first, and then
- * calls this.
- */
-uint32_t
-fd_setup_slices(struct fd_resource *rsc)
-{
-       uint32_t alignment;
-
-       alignment = slice_alignment(rsc->base.target);
-
-       struct fd_screen *screen = fd_screen(rsc->base.screen);
-       if (is_a4xx(screen)) {
-               switch (rsc->base.target) {
-               case PIPE_TEXTURE_3D:
-                       rsc->layout.layer_first = false;
-                       break;
-               default:
-                       rsc->layout.layer_first = true;
-                       alignment = 1;
-                       break;
-               }
-       }
-
-       return setup_slices(rsc, alignment, rsc->base.format);
-}
-
 /* special case to resize query buf after allocated.. */
 void
 fd_resource_resize(struct pipe_resource *prsc, uint32_t sz)
@@ -954,7 +860,7 @@ fd_resource_create_with_modifiers(struct pipe_screen *pscreen,
                struct renderonly_scanout *scanout;
                struct winsys_handle handle;
 
-               /* apply freedreno alignment requirement */
+               /* note: alignment is wrong for a6xx */
                scanout_templat.width0 = align(tmpl->width0, screen->gmem_alignw);
 
                scanout = renderonly_scanout_for_resource(&scanout_templat,
@@ -1093,7 +999,6 @@ fd_resource_from_handle(struct pipe_screen *pscreen,
        struct fd_resource *rsc = CALLOC_STRUCT(fd_resource);
        struct fdl_slice *slice = fd_resource_slice(rsc, 0);
        struct pipe_resource *prsc = &rsc->base;
-       uint32_t pitchalign = fd_screen(pscreen)->gmem_alignw * rsc->layout.cpp;
 
        DBG("target=%d, format=%s, %ux%ux%u, array_size=%u, last_level=%u, "
                        "nr_samples=%u, usage=%u, bind=%x, flags=%x",
@@ -1125,6 +1030,14 @@ fd_resource_from_handle(struct pipe_screen *pscreen,
        slice->offset = handle->offset;
        slice->size0 = handle->stride * prsc->height0;
 
+       uint32_t pitchalign = fd_screen(pscreen)->gmem_alignw * rsc->layout.cpp;
+
+       /* pitchalign is 64-bytes for linear formats on a6xx
+        * layout_resource_for_modifier will validate tiled pitch
+        */
+       if (is_a6xx(screen))
+               pitchalign = 64;
+
        if ((slice->pitch < align(prsc->width0 * rsc->layout.cpp, pitchalign)) ||
                        (slice->pitch & (pitchalign - 1)))
                goto fail;
@@ -1244,6 +1157,12 @@ fd_layout_resource_for_modifier(struct fd_resource *rsc, uint64_t modifier)
 {
        switch (modifier) {
        case DRM_FORMAT_MOD_LINEAR:
+               /* The dri gallium frontend will pass DRM_FORMAT_MOD_INVALID to us
+                * when it's called through any of the non-modifier BO create entry
+                * points.  Other drivers will determine tiling from the kernel or
+                * other legacy backchannels, but for freedreno it just means
+                * LINEAR. */
+       case DRM_FORMAT_MOD_INVALID:
                return 0;
        default:
                return -1;
@@ -1268,8 +1187,6 @@ fd_resource_screen_init(struct pipe_screen *pscreen)
        pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl,
                        true, false, fake_rgtc, true);
 
-       if (!screen->setup_slices)
-               screen->setup_slices = fd_setup_slices;
        if (!screen->layout_resource_for_modifier)
                screen->layout_resource_for_modifier = fd_layout_resource_for_modifier;
        if (!screen->supported_modifiers) {