freedreno: add support for conditional rendering, required for GL3.0
[mesa.git] / src / gallium / drivers / freedreno / freedreno_draw.c
index fed3e64f202404ab3b69ed90b6e99e13c12b6f03..bf803cc77bc6137ec109530a8fcadc2ef2285a0c 100644 (file)
@@ -40,7 +40,8 @@
 #include "freedreno_util.h"
 
 static void
-resource_reading(struct fd_context *ctx, struct pipe_resource *prsc)
+resource_used(struct fd_context *ctx, struct pipe_resource *prsc,
+               enum fd_resource_status status)
 {
        struct fd_resource *rsc;
 
@@ -48,9 +49,29 @@ resource_reading(struct fd_context *ctx, struct pipe_resource *prsc)
                return;
 
        rsc = fd_resource(prsc);
-       rsc->reading = true;
+       rsc->status |= status;
+       if (rsc->stencil)
+               rsc->stencil->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;
+}
+
+static void
+resource_read(struct fd_context *ctx, struct pipe_resource *prsc)
+{
+       resource_used(ctx, prsc, FD_PENDING_READ);
+}
+
+static void
+resource_written(struct fd_context *ctx, struct pipe_resource *prsc)
+{
+       resource_used(ctx, prsc, FD_PENDING_WRITE);
 }
 
 static void
@@ -59,7 +80,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
        struct fd_context *ctx = fd_context(pctx);
        struct pipe_framebuffer_state *pfb = &ctx->framebuffer;
        struct pipe_scissor_state *scissor = fd_context_get_scissor(ctx);
-       unsigned i, buffers = 0;
+       unsigned i, prims, buffers = 0;
 
        /* if we supported transform feedback, we'd have to disable this: */
        if (((scissor->maxx - scissor->minx) *
@@ -67,8 +88,14 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
                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_index_buffer(ctx->primconvert, &ctx->indexbuf);
                util_primconvert_save_rasterizer_state(ctx->primconvert, ctx->rasterizer);
                util_primconvert_draw_vbo(ctx->primconvert, info);
@@ -83,13 +110,13 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 
        if (fd_depth_enabled(ctx)) {
                buffers |= FD_BUFFER_DEPTH;
-               fd_resource(pfb->zsbuf->texture)->dirty = true;
+               resource_written(ctx, pfb->zsbuf->texture);
                ctx->gmem_reason |= FD_GMEM_DEPTH_ENABLED;
        }
 
        if (fd_stencil_enabled(ctx)) {
                buffers |= FD_BUFFER_STENCIL;
-               fd_resource(pfb->zsbuf->texture)->dirty = true;
+               resource_written(ctx, pfb->zsbuf->texture);
                ctx->gmem_reason |= FD_GMEM_STENCIL_ENABLED;
        }
 
@@ -104,7 +131,7 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 
                surf = pfb->cbufs[i]->texture;
 
-               fd_resource(surf)->dirty = true;
+               resource_written(ctx, surf);
                buffers |= PIPE_CLEAR_COLOR0 << i;
 
                if (surf->nr_samples > 1)
@@ -116,32 +143,38 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
 
        /* Skip over buffer 0, that is sent along with the command stream */
        for (i = 1; i < PIPE_MAX_CONSTANT_BUFFERS; i++) {
-               resource_reading(ctx, ctx->constbuf[PIPE_SHADER_VERTEX].cb[i].buffer);
-               resource_reading(ctx, ctx->constbuf[PIPE_SHADER_FRAGMENT].cb[i].buffer);
+               resource_read(ctx, ctx->constbuf[PIPE_SHADER_VERTEX].cb[i].buffer);
+               resource_read(ctx, ctx->constbuf[PIPE_SHADER_FRAGMENT].cb[i].buffer);
        }
 
        /* Mark VBOs as being read */
        for (i = 0; i < ctx->vtx.vertexbuf.count; i++) {
                assert(!ctx->vtx.vertexbuf.vb[i].user_buffer);
-               resource_reading(ctx, ctx->vtx.vertexbuf.vb[i].buffer);
+               resource_read(ctx, ctx->vtx.vertexbuf.vb[i].buffer);
        }
 
        /* Mark index buffer as being read */
-       resource_reading(ctx, ctx->indexbuf.buffer);
+       resource_read(ctx, ctx->indexbuf.buffer);
 
        /* Mark textures as being read */
        for (i = 0; i < ctx->verttex.num_textures; i++)
                if (ctx->verttex.textures[i])
-                       resource_reading(ctx, ctx->verttex.textures[i]->texture);
+                       resource_read(ctx, ctx->verttex.textures[i]->texture);
        for (i = 0; i < ctx->fragtex.num_textures; i++)
                if (ctx->fragtex.textures[i])
-                       resource_reading(ctx, ctx->fragtex.textures[i]->texture);
+                       resource_read(ctx, ctx->fragtex.textures[i]->texture);
+
+       /* Mark streamout buffers as being written.. */
+       for (i = 0; i < ctx->streamout.num_targets; i++)
+               if (ctx->streamout.targets[i])
+                       resource_written(ctx, ctx->streamout.targets[i]->buffer);
 
        ctx->num_draws++;
 
+       prims = u_reduced_prims_for_vertices(info->mode, info->count);
+
        ctx->stats.draw_calls++;
-       ctx->stats.prims_emitted +=
-               u_reduced_prims_for_vertices(info->mode, info->count);
+       ctx->stats.prims_emitted += prims;
 
        /* any buffers that haven't been cleared yet, we need to restore: */
        ctx->restore |= buffers & (FD_BUFFER_ALL & ~ctx->cleared);
@@ -155,6 +188,12 @@ fd_draw_vbo(struct pipe_context *pctx, const struct pipe_draw_info *info)
        fd_hw_query_set_stage(ctx, ctx->ring, FD_STAGE_DRAW);
        ctx->draw_vbo(ctx, info);
 
+       for (i = 0; i < ctx->streamout.num_targets; i++)
+               ctx->streamout.offsets[i] += prims;
+
+       if (fd_mesa_debug & FD_DBG_DDRAW)
+               ctx->dirty = 0xffffffff;
+
        /* if an app (or, well, piglit test) does many thousands of draws
         * without flush (or anything which implicitly flushes, like
         * changing render targets), we can exceed the ringbuffer size.
@@ -185,6 +224,10 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
        unsigned cleared_buffers;
        int i;
 
+       /* TODO: push down the region versions into the tiles */
+       if (!fd_render_condition_check(pctx))
+               return;
+
        /* for bookkeeping about which buffers have been cleared (and thus
         * can fully or partially skip mem2gmem) we need to ignore buffers
         * that have already had a draw, in case apps do silly things like
@@ -212,10 +255,10 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
        if (buffers & PIPE_CLEAR_COLOR)
                for (i = 0; i < pfb->nr_cbufs; i++)
                        if (buffers & (PIPE_CLEAR_COLOR0 << i))
-                               fd_resource(pfb->cbufs[i]->texture)->dirty = true;
+                               resource_written(ctx, pfb->cbufs[i]->texture);
 
        if (buffers & (PIPE_CLEAR_DEPTH | PIPE_CLEAR_STENCIL)) {
-               fd_resource(pfb->zsbuf->texture)->dirty = true;
+               resource_written(ctx, pfb->zsbuf->texture);
                ctx->gmem_reason |= FD_GMEM_CLEARS_DEPTH_STENCIL;
        }
 
@@ -233,7 +276,8 @@ fd_clear(struct pipe_context *pctx, unsigned buffers,
                        FD_DIRTY_SAMPLE_MASK |
                        FD_DIRTY_PROG |
                        FD_DIRTY_CONSTBUF |
-                       FD_DIRTY_BLEND;
+                       FD_DIRTY_BLEND |
+                       FD_DIRTY_FRAMEBUFFER;
 
        if (fd_mesa_debug & FD_DBG_DCLEAR)
                ctx->dirty = 0xffffffff;