a4xx: add noperspective interpolation support
[mesa.git] / src / gallium / drivers / freedreno / freedreno_draw.c
index a4724221b12522e458c8ef8f8aeb526c48c4e2a5..a5dae976607af1c3137a957582b19ac2db14f2d8 100644 (file)
@@ -47,7 +47,7 @@ resource_read(struct fd_batch *batch, struct pipe_resource *prsc)
 {
        if (!prsc)
                return;
-       fd_batch_resource_used(batch, fd_resource(prsc), false);
+       fd_batch_resource_read(batch, fd_resource(prsc));
 }
 
 static void
@@ -55,70 +55,15 @@ resource_written(struct fd_batch *batch, struct pipe_resource *prsc)
 {
        if (!prsc)
                return;
-       fd_batch_resource_used(batch, fd_resource(prsc), true);
+       fd_batch_resource_write(batch, fd_resource(prsc));
 }
 
 static void
-fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
+batch_draw_tracking(struct fd_batch *batch, const struct pipe_draw_info *info)
 {
-       struct fd_context *ctx = fd_context(pctx);
-       struct fd_batch *batch = fd_context_batch(ctx);
+       struct fd_context *ctx = batch->ctx;
        struct pipe_framebuffer_state *pfb = &batch->framebuffer;
-       unsigned i, prims, buffers = 0, restore_buffers = 0;
-
-       /* for debugging problems with indirect draw, it is convenient
-        * to be able to emulate it, to determine if game is feeding us
-        * bogus data:
-        */
-       if (info->indirect && (fd_mesa_debug & FD_DBG_NOINDR)) {
-               util_draw_indirect(pctx, info);
-               return;
-       }
-
-       if (!info->count_from_stream_output && !info->indirect &&
-           !info->primitive_restart &&
-           !u_trim_pipe_prim(info->mode, (unsigned*)&info->count))
-               return;
-
-       /* TODO: push down the region versions into the tiles */
-       if (!fd_render_condition_check(pctx))
-               return;
-
-       /* emulate unsupported primitives: */
-       if (!fd_supported_prim(ctx, info->mode)) {
-               if (ctx->streamout.num_targets > 0)
-                       debug_error("stream-out with emulated prims");
-               util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);
-               util_primconvert_draw_vbo(ctx->primconvert, info);
-               return;
-       }
-
-       fd_fence_ref(&ctx->last_fence, NULL);
-
-       /* Upload a user index buffer. */
-       struct pipe_resource *indexbuf = NULL;
-       unsigned index_offset = 0;
-       struct pipe_draw_info new_info;
-       if (info->index_size) {
-               if (info->has_user_indices) {
-                       if (!util_upload_index_buffer(pctx, info, &indexbuf, &index_offset, 4))
-                               return;
-                       new_info = *info;
-                       new_info.index.resource = indexbuf;
-                       new_info.has_user_indices = false;
-                       info = &new_info;
-               } else {
-                       indexbuf = info->index.resource;
-               }
-       }
-
-       if (ctx->in_blit) {
-               fd_batch_reset(batch);
-               fd_context_all_dirty(ctx);
-       }
-
-       batch->blit = ctx->in_blit;
-       batch->back_blit = ctx->in_shadow;
+       unsigned buffers = 0, restore_buffers = 0;
 
        /* NOTE: needs to be before resource_written(batch->query_buf), otherwise
         * query_buf may not be created yet.
@@ -129,7 +74,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
         * Figure out the buffers/features we need:
         */
 
-       mtx_lock(&ctx->screen->lock);
+       fd_screen_lock(ctx->screen);
 
        if (ctx->dirty & (FD_DIRTY_FRAMEBUFFER | FD_DIRTY_ZSA)) {
                if (fd_depth_enabled(ctx)) {
@@ -162,7 +107,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
        if (fd_logicop_enabled(ctx))
                batch->gmem_reason |= FD_GMEM_LOGICOP_ENABLED;
 
-       for (i = 0; i < pfb->nr_cbufs; i++) {
+       for (unsigned i = 0; i < pfb->nr_cbufs; i++) {
                struct pipe_resource *surf;
 
                if (!pfb->cbufs[i])
@@ -185,16 +130,19 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
                        resource_written(batch, pfb->cbufs[i]->texture);
        }
 
-       /* Mark SSBOs as being written.. we don't actually know which ones are
-        * read vs written, so just assume the worst
-        */
+       /* Mark SSBOs */
        if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_SSBO) {
-               foreach_bit(i, ctx->shaderbuf[PIPE_SHADER_FRAGMENT].enabled_mask)
-                               resource_written(batch, ctx->shaderbuf[PIPE_SHADER_FRAGMENT].sb[i].buffer);
+               const struct fd_shaderbuf_stateobj *so = &ctx->shaderbuf[PIPE_SHADER_FRAGMENT];
+
+               foreach_bit (i, so->enabled_mask & so->writable_mask)
+                       resource_written(batch, so->sb[i].buffer);
+
+               foreach_bit (i, so->enabled_mask & ~so->writable_mask)
+                       resource_read(batch, so->sb[i].buffer);
        }
 
        if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_IMAGE) {
-               foreach_bit(i, ctx->shaderimg[PIPE_SHADER_FRAGMENT].enabled_mask) {
+               foreach_bit (i, ctx->shaderimg[PIPE_SHADER_FRAGMENT].enabled_mask) {
                        struct pipe_image_view *img =
                                        &ctx->shaderimg[PIPE_SHADER_FRAGMENT].si[i];
                        if (img->access & PIPE_IMAGE_ACCESS_WRITE)
@@ -205,25 +153,26 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
        }
 
        if (ctx->dirty_shader[PIPE_SHADER_VERTEX] & FD_DIRTY_SHADER_CONST) {
-               foreach_bit(i, ctx->constbuf[PIPE_SHADER_VERTEX].enabled_mask)
+               foreach_bit (i, ctx->constbuf[PIPE_SHADER_VERTEX].enabled_mask)
                        resource_read(batch, ctx->constbuf[PIPE_SHADER_VERTEX].cb[i].buffer);
        }
 
        if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_CONST) {
-               foreach_bit(i, ctx->constbuf[PIPE_SHADER_FRAGMENT].enabled_mask)
+               foreach_bit (i, ctx->constbuf[PIPE_SHADER_FRAGMENT].enabled_mask)
                        resource_read(batch, ctx->constbuf[PIPE_SHADER_FRAGMENT].cb[i].buffer);
        }
 
        /* Mark VBOs as being read */
        if (ctx->dirty & FD_DIRTY_VTXBUF) {
-               foreach_bit(i, ctx->vtx.vertexbuf.enabled_mask) {
+               foreach_bit (i, ctx->vtx.vertexbuf.enabled_mask) {
                        assert(!ctx->vtx.vertexbuf.vb[i].is_user_buffer);
                        resource_read(batch, ctx->vtx.vertexbuf.vb[i].buffer.resource);
                }
        }
 
        /* Mark index buffer as being read */
-       resource_read(batch, indexbuf);
+       if (info->index_size)
+               resource_read(batch, info->index.resource);
 
        /* Mark indirect draw buffer as being read */
        if (info->indirect)
@@ -231,18 +180,18 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 
        /* Mark textures as being read */
        if (ctx->dirty_shader[PIPE_SHADER_VERTEX] & FD_DIRTY_SHADER_TEX) {
-               foreach_bit(i, ctx->tex[PIPE_SHADER_VERTEX].valid_textures)
+               foreach_bit (i, ctx->tex[PIPE_SHADER_VERTEX].valid_textures)
                        resource_read(batch, ctx->tex[PIPE_SHADER_VERTEX].textures[i]->texture);
        }
 
        if (ctx->dirty_shader[PIPE_SHADER_FRAGMENT] & FD_DIRTY_SHADER_TEX) {
-               foreach_bit(i, ctx->tex[PIPE_SHADER_FRAGMENT].valid_textures)
+               foreach_bit (i, ctx->tex[PIPE_SHADER_FRAGMENT].valid_textures)
                        resource_read(batch, ctx->tex[PIPE_SHADER_FRAGMENT].textures[i]->texture);
        }
 
        /* Mark streamout buffers as being written.. */
        if (ctx->dirty & FD_DIRTY_STREAMOUT) {
-               for (i = 0; i < ctx->streamout.num_targets; i++)
+               for (unsigned i = 0; i < ctx->streamout.num_targets; i++)
                        if (ctx->streamout.targets[i])
                                resource_written(batch, ctx->streamout.targets[i]->buffer);
        }
@@ -252,14 +201,92 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
        list_for_each_entry(struct fd_acc_query, aq, &ctx->acc_active_queries, node)
                resource_written(batch, aq->prsc);
 
-       mtx_unlock(&ctx->screen->lock);
+       fd_screen_unlock(ctx->screen);
+
+       /* any buffers that haven't been cleared yet, we need to restore: */
+       batch->restore |= restore_buffers & (FD_BUFFER_ALL & ~batch->invalidated);
+       /* and any buffers used, need to be resolved: */
+       batch->resolve |= buffers;
+}
+
+static void
+fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
+{
+       struct fd_context *ctx = fd_context(pctx);
+
+       /* for debugging problems with indirect draw, it is convenient
+        * to be able to emulate it, to determine if game is feeding us
+        * bogus data:
+        */
+       if (info->indirect && (fd_mesa_debug & FD_DBG_NOINDR)) {
+               util_draw_indirect(pctx, info);
+               return;
+       }
+
+       if (!info->count_from_stream_output && !info->indirect &&
+           !info->primitive_restart &&
+           !u_trim_pipe_prim(info->mode, (unsigned*)&info->count))
+               return;
+
+       /* TODO: push down the region versions into the tiles */
+       if (!fd_render_condition_check(pctx))
+               return;
+
+       /* emulate unsupported primitives: */
+       if (!fd_supported_prim(ctx, info->mode)) {
+               if (ctx->streamout.num_targets > 0)
+                       debug_error("stream-out with emulated prims");
+               util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);
+               util_primconvert_draw_vbo(ctx->primconvert, info);
+               return;
+       }
+
+       /* Upload a user index buffer. */
+       struct pipe_resource *indexbuf = NULL;
+       unsigned index_offset = 0;
+       struct pipe_draw_info new_info;
+       if (info->index_size) {
+               if (info->has_user_indices) {
+                       if (!util_upload_index_buffer(pctx, info, &indexbuf, &index_offset, 4))
+                               return;
+                       new_info = *info;
+                       new_info.index.resource = indexbuf;
+                       new_info.has_user_indices = false;
+                       info = &new_info;
+               } else {
+                       indexbuf = info->index.resource;
+               }
+       }
+
+       struct fd_batch *batch = NULL;
+       fd_batch_reference(&batch, fd_context_batch(ctx));
 
+       if (ctx->in_discard_blit) {
+               fd_batch_reset(batch);
+               fd_context_all_dirty(ctx);
+       }
+
+       batch_draw_tracking(batch, info);
+
+       if (unlikely(ctx->batch != batch)) {
+               /* The current batch was flushed in batch_draw_tracking()
+                * so start anew.  We know this won't happen a second time
+                * since we are dealing with a fresh batch:
+                */
+               fd_batch_reference(&batch, fd_context_batch(ctx));
+               batch_draw_tracking(batch, info);
+               assert(ctx->batch == batch);
+       }
+
+       batch->blit = ctx->in_discard_blit;
+       batch->back_blit = ctx->in_shadow;
        batch->num_draws++;
 
        /* Counting prims in sw doesn't work for GS and tesselation. For older
         * gens we don't have those stages and don't have the hw counters enabled,
         * so keep the count accurate for non-patch geometry.
         */
+       unsigned prims;
        if (info->mode != PIPE_PRIM_PATCHES)
                prims = u_reduced_prims_for_vertices(info->mode, info->count);
        else
@@ -277,12 +304,14 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
                ctx->stats.prims_emitted += prims;
        ctx->stats.prims_generated += prims;
 
-       /* any buffers that haven't been cleared yet, we need to restore: */
-       batch->restore |= restore_buffers & (FD_BUFFER_ALL & ~batch->invalidated);
-       /* and any buffers used, need to be resolved: */
-       batch->resolve |= buffers;
+       /* Clearing last_fence must come after the batch dependency tracking
+        * (resource_read()/resource_written()), as that can trigger a flush,
+        * re-populating last_fence
+        */
+       fd_fence_ref(&ctx->last_fence, NULL);
 
-       DBG("%p: %x %ux%u num_draws=%u (%s/%s)", batch, buffers,
+       struct pipe_framebuffer_state *pfb = &batch->framebuffer;
+       DBG("%p: %ux%u num_draws=%u (%s/%s)", batch,
                pfb->width, pfb->height, batch->num_draws,
                util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
                util_format_short_name(pipe_surface_format(pfb->zsbuf)));
@@ -292,38 +321,25 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 
        batch->num_vertices += info->count * info->instance_count;
 
-       for (i = 0; i < ctx->streamout.num_targets; i++)
+       for (unsigned i = 0; i < ctx->streamout.num_targets; i++)
                ctx->streamout.offsets[i] += info->count;
 
        if (fd_mesa_debug & FD_DBG_DDRAW)
                fd_context_all_dirty(ctx);
 
        fd_batch_check_size(batch);
+       fd_batch_reference(&batch, NULL);
 
        if (info == &new_info)
                pipe_resource_reference(&indexbuf, NULL);
 }
 
 static void
-fd_clear(struct pipe_context *pctx, unsigned buffers,
-               const union pipe_color_union *color, double depth, unsigned stencil)
+batch_clear_tracking(struct fd_batch *batch, unsigned buffers)
 {
-       struct fd_context *ctx = fd_context(pctx);
-       struct fd_batch *batch = fd_context_batch(ctx);
+       struct fd_context *ctx = batch->ctx;
        struct pipe_framebuffer_state *pfb = &batch->framebuffer;
        unsigned cleared_buffers;
-       int i;
-
-       /* TODO: push down the region versions into the tiles */
-       if (!fd_render_condition_check(pctx))
-               return;
-
-       fd_fence_ref(&ctx->last_fence, NULL);
-
-       if (ctx->in_blit) {
-               fd_batch_reset(batch);
-               fd_context_all_dirty(ctx);
-       }
 
        /* pctx->clear() is only for full-surface clears, so scissor is
         * equivalent to having GL_SCISSOR_TEST disabled:
@@ -347,10 +363,10 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
        batch->resolve |= buffers;
        batch->needs_flush = true;
 
-       mtx_lock(&ctx->screen->lock);
+       fd_screen_lock(ctx->screen);
 
        if (buffers & PIPE_CLEAR_COLOR)
-               for (i = 0; i < pfb->nr_cbufs; i++)
+               for (unsigned i = 0; i < pfb->nr_cbufs; i++)
                        if (buffers & (PIPE_CLEAR_COLOR0 << i))
                                resource_written(batch, pfb->cbufs[i]->texture);
 
@@ -364,8 +380,48 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
        list_for_each_entry(struct fd_acc_query, aq, &ctx->acc_active_queries, node)
                resource_written(batch, aq->prsc);
 
-       mtx_unlock(&ctx->screen->lock);
+       fd_screen_unlock(ctx->screen);
+}
 
+static void
+fd_clear(struct pipe_context *pctx, unsigned buffers,
+               const struct pipe_scissor_state *scissor_state,
+               const union pipe_color_union *color, double depth,
+               unsigned stencil)
+{
+       struct fd_context *ctx = fd_context(pctx);
+
+       /* TODO: push down the region versions into the tiles */
+       if (!fd_render_condition_check(pctx))
+               return;
+
+       struct fd_batch *batch = NULL;
+       fd_batch_reference(&batch, fd_context_batch(ctx));
+
+       if (ctx->in_discard_blit) {
+               fd_batch_reset(batch);
+               fd_context_all_dirty(ctx);
+       }
+
+       batch_clear_tracking(batch, buffers);
+
+       if (unlikely(ctx->batch != batch)) {
+               /* The current batch was flushed in batch_clear_tracking()
+                * so start anew.  We know this won't happen a second time
+                * since we are dealing with a fresh batch:
+                */
+               fd_batch_reference(&batch, fd_context_batch(ctx));
+               batch_clear_tracking(batch, buffers);
+               assert(ctx->batch == batch);
+       }
+
+       /* Clearing last_fence must come after the batch dependency tracking
+        * (resource_read()/resource_written()), as that can trigger a flush,
+        * re-populating last_fence
+        */
+       fd_fence_ref(&ctx->last_fence, NULL);
+
+       struct pipe_framebuffer_state *pfb = &batch->framebuffer;
        DBG("%p: %x %ux%u depth=%f, stencil=%u (%s/%s)", batch, buffers,
                pfb->width, pfb->height, depth, stencil,
                util_format_short_name(pipe_surface_format(pfb->cbufs[0])),
@@ -392,6 +448,7 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
        }
 
        fd_batch_check_size(batch);
+       fd_batch_reference(&batch, NULL);
 }
 
 static void
@@ -417,21 +474,22 @@ static void
 fd_launch_grid(struct pipe_context *pctx, const struct pipe_grid_info *info)
 {
        struct fd_context *ctx = fd_context(pctx);
+       const struct fd_shaderbuf_stateobj *so = &ctx->shaderbuf[PIPE_SHADER_COMPUTE];
        struct fd_batch *batch, *save_batch = NULL;
-       unsigned i;
 
        batch = fd_bc_alloc_batch(&ctx->screen->batch_cache, ctx, true);
        fd_batch_reference(&save_batch, ctx->batch);
        fd_batch_reference(&ctx->batch, batch);
        fd_context_all_dirty(ctx);
 
-       mtx_lock(&ctx->screen->lock);
+       fd_screen_lock(ctx->screen);
 
-       /* Mark SSBOs as being written.. we don't actually know which ones are
-        * read vs written, so just assume the worst
-        */
-       foreach_bit(i, ctx->shaderbuf[PIPE_SHADER_COMPUTE].enabled_mask)
-               resource_written(batch, ctx->shaderbuf[PIPE_SHADER_COMPUTE].sb[i].buffer);
+       /* Mark SSBOs */
+       foreach_bit (i, so->enabled_mask & so->writable_mask)
+               resource_written(batch, so->sb[i].buffer);
+
+       foreach_bit (i, so->enabled_mask & ~so->writable_mask)
+               resource_read(batch, so->sb[i].buffer);
 
        foreach_bit(i, ctx->shaderimg[PIPE_SHADER_COMPUTE].enabled_mask) {
                struct pipe_image_view *img =
@@ -459,12 +517,12 @@ fd_launch_grid(struct pipe_context *pctx, const struct pipe_grid_info *info)
        if (info->indirect)
                resource_read(batch, info->indirect);
 
-       mtx_unlock(&ctx->screen->lock);
+       fd_screen_unlock(ctx->screen);
 
        batch->needs_flush = true;
        ctx->launch_grid(ctx, info);
 
-       fd_batch_flush(batch, false);
+       fd_batch_flush(batch);
 
        fd_batch_reference(&ctx->batch, save_batch);
        fd_context_all_dirty(ctx);