gallium/util: implement layered framebuffer clear in u_blitter
authorMarek Olšák <marek.olsak@amd.com>
Thu, 21 Nov 2013 14:41:36 +0000 (15:41 +0100)
committerMarek Olšák <marek.olsak@amd.com>
Tue, 3 Dec 2013 18:39:13 +0000 (19:39 +0100)
All bound layers (from first_layer to last_layer) should be cleared.

This uses a vertex shader which outputs gl_Layer = gl_InstanceID, so each
instance goes to a different layer. By rendering a quad and setting
the instance count to the number of layers, it will trivially clear all
layers.

This requires AMD_vertex_shader_layer (or PIPE_CAP_TGSI_VS_LAYER), which only
radeonsi supports at the moment. r600 could do this too. Standard DX11
hardware will have to use a geometry shader though, which has higher overhead.

src/gallium/auxiliary/util/u_blitter.c
src/gallium/auxiliary/util/u_blitter.h
src/gallium/auxiliary/util/u_framebuffer.c
src/gallium/auxiliary/util/u_framebuffer.h
src/gallium/auxiliary/util/u_simple_shaders.c
src/gallium/auxiliary/util/u_simple_shaders.h
src/gallium/drivers/ilo/ilo_blitter_pipe.c
src/gallium/drivers/r300/r300_blit.c
src/gallium/drivers/r600/r600_blit.c
src/gallium/drivers/radeonsi/r600_blit.c

index b95cbab126f06151b8e6bf8dfc59d4a6868733e7..bb1920a47844964e01f5c33e0fca34c06b4e145b 100644 (file)
@@ -65,6 +65,7 @@ struct blitter_context_priv
    /* Vertex shaders. */
    void *vs; /**< Vertex shader which passes {pos, generic} to the output.*/
    void *vs_pos_only; /**< Vertex shader which passes pos to the output.*/
+   void *vs_layered; /**< Vertex shader which sets LAYER = INSTANCEID. */
 
    /* Fragment shaders. */
    void *fs_empty;
@@ -295,6 +296,7 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
          util_make_vertex_passthrough_shader(pipe, 2, semantic_names,
                                              semantic_indices);
    }
+
    if (ctx->has_stream_out) {
       struct pipe_stream_output_info so;
       const uint semantic_names[] = { TGSI_SEMANTIC_POSITION };
@@ -310,6 +312,11 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
                                                      semantic_indices, &so);
    }
 
+   if (pipe->screen->get_param(pipe->screen, PIPE_CAP_TGSI_INSTANCEID) &&
+       pipe->screen->get_param(pipe->screen, PIPE_CAP_TGSI_VS_LAYER)) {
+      ctx->vs_layered = util_make_layered_clear_vertex_shader(pipe);
+   }
+
    /* set invariant vertex coordinates */
    for (i = 0; i < 4; i++)
       ctx->vertices[i][0][3] = 1; /*v.w*/
@@ -901,13 +908,14 @@ void util_blitter_cache_all_shaders(struct blitter_context *blitter)
 }
 
 static void blitter_set_common_draw_rect_state(struct blitter_context_priv *ctx,
-                                               boolean scissor)
+                                               boolean scissor,
+                                               boolean vs_layered)
 {
    struct pipe_context *pipe = ctx->base.pipe;
 
    pipe->bind_rasterizer_state(pipe, scissor ? ctx->rs_state_scissor
                                              : ctx->rs_state);
-   pipe->bind_vs_state(pipe, ctx->vs);
+   pipe->bind_vs_state(pipe, vs_layered ? ctx->vs_layered : ctx->vs);
    if (ctx->has_geometry_shader)
       pipe->bind_gs_state(pipe, NULL);
    if (ctx->has_stream_out)
@@ -915,19 +923,24 @@ static void blitter_set_common_draw_rect_state(struct blitter_context_priv *ctx,
 }
 
 static void blitter_draw(struct blitter_context_priv *ctx,
-                         int x1, int y1, int x2, int y2, float depth)
+                         int x1, int y1, int x2, int y2, float depth,
+                         unsigned num_instances)
 {
-   struct pipe_resource *buf = NULL;
-   unsigned offset = 0;
+   struct pipe_context *pipe = ctx->base.pipe;
+   struct pipe_vertex_buffer vb = {0};
 
    blitter_set_rectangle(ctx, x1, y1, x2, y2, depth);
 
+   vb.stride = 8 * sizeof(float);
+
    u_upload_data(ctx->upload, 0, sizeof(ctx->vertices), ctx->vertices,
-                 &offset, &buf);
+                 &vb.buffer_offset, &vb.buffer);
    u_upload_unmap(ctx->upload);
-   util_draw_vertex_buffer(ctx->base.pipe, NULL, buf, ctx->base.vb_slot,
-                           offset, PIPE_PRIM_TRIANGLE_FAN, 4, 2);
-   pipe_resource_reference(&buf, NULL);
+
+   pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1, &vb);
+   util_draw_arrays_instanced(pipe, PIPE_PRIM_TRIANGLE_FAN, 0, 4,
+                              0, num_instances);
+   pipe_resource_reference(&vb.buffer, NULL);
 }
 
 void util_blitter_draw_rectangle(struct blitter_context *blitter,
@@ -949,11 +962,12 @@ void util_blitter_draw_rectangle(struct blitter_context *blitter,
       default:;
    }
 
-   blitter_draw(ctx, x1, y1, x2, y2, depth);
+   blitter_draw(ctx, x1, y1, x2, y2, depth, 1);
 }
 
 static void util_blitter_clear_custom(struct blitter_context *blitter,
                                       unsigned width, unsigned height,
+                                      unsigned num_layers,
                                       unsigned clear_buffers,
                                       const union pipe_color_union *color,
                                       double depth, unsigned stencil,
@@ -963,6 +977,8 @@ static void util_blitter_clear_custom(struct blitter_context *blitter,
    struct pipe_context *pipe = ctx->base.pipe;
    struct pipe_stencil_ref sr = { { 0 } };
 
+   assert(ctx->vs_layered || num_layers <= 1);
+
    blitter_set_running_flag(ctx);
    blitter_check_saved_vertex_states(ctx);
    blitter_check_saved_fragment_states(ctx);
@@ -996,10 +1012,18 @@ static void util_blitter_clear_custom(struct blitter_context *blitter,
    ctx->bind_fs_state(pipe, ctx->fs_write_all_cbufs);
    pipe->set_sample_mask(pipe, ~0);
 
-   blitter_set_common_draw_rect_state(ctx, FALSE);
    blitter_set_dst_dimensions(ctx, width, height);
-   blitter->draw_rectangle(blitter, 0, 0, width, height, (float) depth,
-                           UTIL_BLITTER_ATTRIB_COLOR, color);
+
+   if (num_layers > 1 && ctx->vs_layered) {
+      blitter_set_common_draw_rect_state(ctx, FALSE, TRUE);
+      blitter_set_clear_color(ctx, color);
+      blitter_draw(ctx, 0, 0, width, height, depth, num_layers);
+   }
+   else {
+      blitter_set_common_draw_rect_state(ctx, FALSE, FALSE);
+      blitter->draw_rectangle(blitter, 0, 0, width, height, (float) depth,
+                              UTIL_BLITTER_ATTRIB_COLOR, color);
+   }
 
    blitter_restore_vertex_states(ctx);
    blitter_restore_fragment_states(ctx);
@@ -1008,12 +1032,12 @@ static void util_blitter_clear_custom(struct blitter_context *blitter,
 }
 
 void util_blitter_clear(struct blitter_context *blitter,
-                        unsigned width, unsigned height,
+                        unsigned width, unsigned height, unsigned num_layers,
                         unsigned clear_buffers,
                         const union pipe_color_union *color,
                         double depth, unsigned stencil)
 {
-   util_blitter_clear_custom(blitter, width, height,
+   util_blitter_clear_custom(blitter, width, height, num_layers,
                              clear_buffers, color, depth, stencil,
                              NULL, NULL);
 }
@@ -1023,7 +1047,7 @@ void util_blitter_custom_clear_depth(struct blitter_context *blitter,
                                      double depth, void *custom_dsa)
 {
     static const union pipe_color_union color;
-    util_blitter_clear_custom(blitter, width, height, 0, &color, depth, 0,
+    util_blitter_clear_custom(blitter, width, height, 0, 0, &color, depth, 0,
                               NULL, custom_dsa);
 }
 
@@ -1341,7 +1365,7 @@ void util_blitter_blit_generic(struct blitter_context *blitter,
       pipe->set_scissor_states(pipe, 0, 1, scissor);
    }
 
-   blitter_set_common_draw_rect_state(ctx, scissor != NULL);
+   blitter_set_common_draw_rect_state(ctx, scissor != NULL, FALSE);
    blitter_set_dst_dimensions(ctx, dst->width, dst->height);
 
    if ((src_target == PIPE_TEXTURE_1D ||
@@ -1402,7 +1426,7 @@ void util_blitter_blit_generic(struct blitter_context *blitter,
                                      srcbox->y + srcbox->height);
                blitter_draw(ctx, dstbox->x, dstbox->y,
                             dstbox->x + dstbox->width,
-                            dstbox->y + dstbox->height, 0);
+                            dstbox->y + dstbox->height, 0, 1);
             }
          } else {
             pipe->set_sample_mask(pipe, ~0);
@@ -1413,7 +1437,7 @@ void util_blitter_blit_generic(struct blitter_context *blitter,
                                   srcbox->y + srcbox->height);
             blitter_draw(ctx, dstbox->x, dstbox->y,
                          dstbox->x + dstbox->width,
-                         dstbox->y + dstbox->height, 0);
+                         dstbox->y + dstbox->height, 0, 1);
          }
 
          /* Get the next surface or (if this is the last iteration)
@@ -1508,7 +1532,7 @@ void util_blitter_clear_render_target(struct blitter_context *blitter,
    pipe->set_framebuffer_state(pipe, &fb_state);
    pipe->set_sample_mask(pipe, ~0);
 
-   blitter_set_common_draw_rect_state(ctx, FALSE);
+   blitter_set_common_draw_rect_state(ctx, FALSE, FALSE);
    blitter_set_dst_dimensions(ctx, dstsurf->width, dstsurf->height);
    blitter->draw_rectangle(blitter, dstx, dsty, dstx+width, dsty+height, 0,
                            UTIL_BLITTER_ATTRIB_COLOR, color);
@@ -1576,7 +1600,7 @@ void util_blitter_clear_depth_stencil(struct blitter_context *blitter,
    pipe->set_framebuffer_state(pipe, &fb_state);
    pipe->set_sample_mask(pipe, ~0);
 
-   blitter_set_common_draw_rect_state(ctx, FALSE);
+   blitter_set_common_draw_rect_state(ctx, FALSE, FALSE);
    blitter_set_dst_dimensions(ctx, dstsurf->width, dstsurf->height);
    blitter->draw_rectangle(blitter, dstx, dsty, dstx+width, dsty+height,
                            (float) depth,
@@ -1633,7 +1657,7 @@ void util_blitter_custom_depth_stencil(struct blitter_context *blitter,
    pipe->set_framebuffer_state(pipe, &fb_state);
    pipe->set_sample_mask(pipe, sample_mask);
 
-   blitter_set_common_draw_rect_state(ctx, FALSE);
+   blitter_set_common_draw_rect_state(ctx, FALSE, FALSE);
    blitter_set_dst_dimensions(ctx, zsurf->width, zsurf->height);
    blitter->draw_rectangle(blitter, 0, 0, zsurf->width, zsurf->height, depth,
                            UTIL_BLITTER_ATTRIB_NONE, NULL);
@@ -1818,7 +1842,7 @@ void util_blitter_custom_resolve_color(struct blitter_context *blitter,
    fb_state.zsbuf = NULL;
    pipe->set_framebuffer_state(pipe, &fb_state);
 
-   blitter_set_common_draw_rect_state(ctx, FALSE);
+   blitter_set_common_draw_rect_state(ctx, FALSE, FALSE);
    blitter_set_dst_dimensions(ctx, src->width0, src->height0);
    blitter->draw_rectangle(blitter, 0, 0, src->width0, src->height0,
                            0, 0, NULL);
@@ -1868,7 +1892,7 @@ void util_blitter_custom_color(struct blitter_context *blitter,
    pipe->set_framebuffer_state(pipe, &fb_state);
    pipe->set_sample_mask(pipe, ~0);
 
-   blitter_set_common_draw_rect_state(ctx, FALSE);
+   blitter_set_common_draw_rect_state(ctx, FALSE, FALSE);
    blitter_set_dst_dimensions(ctx, dstsurf->width, dstsurf->height);
    blitter->draw_rectangle(blitter, 0, 0, dstsurf->width, dstsurf->height,
                            0, 0, NULL);
index d9cefde500a6efb40161b784c2cbbe105b597002..24c11115573a071b0bfd8e0ca023c43ba3db77a8 100644 (file)
@@ -183,7 +183,7 @@ void util_blitter_draw_rectangle(struct blitter_context *blitter,
  * - blend state
  */
 void util_blitter_clear(struct blitter_context *blitter,
-                        unsigned width, unsigned height,
+                        unsigned width, unsigned height, unsigned num_layers,
                         unsigned clear_buffers,
                         const union pipe_color_union *color,
                         double depth, unsigned stencil);
index f84485d1f1c66a20cafa83dc7fe4d4f33b542371..683967237e91df9563a3b20c953a893fceb60caf 100644 (file)
@@ -147,3 +147,27 @@ util_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
       return TRUE;
    }
 }
+
+
+/**
+ * Return the number of layers set in the framebuffer state.
+ */
+unsigned
+util_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
+{
+       unsigned i, num_layers = 0;
+
+       for (i = 0; i < fb->nr_cbufs; i++) {
+               if (fb->cbufs[i]) {
+                       unsigned num = fb->cbufs[i]->u.tex.last_layer -
+                                      fb->cbufs[i]->u.tex.first_layer + 1;
+                       num_layers = MAX2(num_layers, num);
+               }
+       }
+       if (fb->zsbuf) {
+               unsigned num = fb->zsbuf->u.tex.last_layer -
+                              fb->zsbuf->u.tex.first_layer + 1;
+               num_layers = MAX2(num_layers, num);
+       }
+       return num_layers;
+}
index a8906623042f24ce7bf124002d43b7a3076240ad..0e6c98363a86376a7f137d90030481cc39df6afd 100644 (file)
@@ -55,6 +55,11 @@ util_framebuffer_min_size(const struct pipe_framebuffer_state *fb,
                           unsigned *width,
                           unsigned *height);
 
+
+extern unsigned
+util_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb);
+
+
 #ifdef __cplusplus
 }
 #endif
index c93d754696980f9dd36d3683d1f9771a166d9ff8..26fa476a6d046b8f182e5ece7a877884d140cd98 100644 (file)
@@ -99,6 +99,32 @@ util_make_vertex_passthrough_shader_with_so(struct pipe_context *pipe,
 }
 
 
+void *util_make_layered_clear_vertex_shader(struct pipe_context *pipe)
+{
+   static const char text[] =
+         "VERT\n"
+         "DCL IN[0]\n"
+         "DCL IN[1]\n"
+         "DCL SV[0], INSTANCEID\n"
+         "DCL OUT[0], POSITION\n"
+         "DCL OUT[1], GENERIC[0]\n"
+         "DCL OUT[2], LAYER\n"
+
+         "MOV OUT[0], IN[0]\n"
+         "MOV OUT[1], IN[1]\n"
+         "MOV OUT[2], SV[0]\n"
+         "END\n";
+   struct tgsi_token tokens[1000];
+   struct pipe_shader_state state = {tokens};
+
+   if (!tgsi_text_translate(text, tokens, Elements(tokens))) {
+      assert(0);
+      return NULL;
+   }
+   return pipe->create_vs_state(pipe, &state);
+}
+
+
 /**
  * Make simple fragment texture shader:
  *  IMM {0,0,0,1}                         // (if writemask != 0xf)
index 016664d1b56299c95fbce63529625d2ef598c172..9be76e9bf1215d1394a72c6b6cda5405b564a7ac 100644 (file)
@@ -56,6 +56,8 @@ util_make_vertex_passthrough_shader_with_so(struct pipe_context *pipe,
                                     const uint *semantic_indexes,
                                     const struct pipe_stream_output_info *so);
 
+extern void *
+util_make_layered_clear_vertex_shader(struct pipe_context *pipe);
 
 extern void *
 util_make_fragment_tex_shader_writemask(struct pipe_context *pipe, 
index b4dd3ad91c5196fae2d883488612fcf8981de153..fa4f1582b7f710491390fa92bb6adec300624aee 100644 (file)
@@ -220,7 +220,7 @@ ilo_blitter_pipe_clear_fb(struct ilo_blitter *blitter,
    ilo_blitter_pipe_begin(blitter, ILO_BLITTER_PIPE_CLEAR_FB, false);
 
    util_blitter_clear(blitter->pipe_blitter,
-         blitter->ilo->fb.state.width, blitter->ilo->fb.state.height,
+         blitter->ilo->fb.state.width, blitter->ilo->fb.state.height, 1,
          buffers, color, depth, stencil);
 
    ilo_blitter_pipe_end(blitter);
index 4ec68ae6e1c1256210cb05a5fa39a625f1bd2683..42410fe7daefcd5ce72b96ec514492b4300db711 100644 (file)
@@ -365,9 +365,7 @@ static void r300_clear(struct pipe_context* pipe,
     if (buffers) {
         /* Clear using the blitter. */
         r300_blitter_begin(r300, R300_CLEAR);
-        util_blitter_clear(r300->blitter,
-                           width,
-                           height,
+        util_blitter_clear(r300->blitter, width, height, 1,
                            buffers, color, depth, stencil);
         r300_blitter_end(r300);
     } else if (r300->zmask_clear.dirty ||
index fea33bccaa8ebcbd021a987ca3beaf3e7104d761..f33bb43b8c632bbf644e841c30b23d136d5164dc 100644 (file)
@@ -558,7 +558,7 @@ static void r600_clear(struct pipe_context *ctx, unsigned buffers,
        }
 
        r600_blitter_begin(ctx, R600_CLEAR);
-       util_blitter_clear(rctx->blitter, fb->width, fb->height,
+       util_blitter_clear(rctx->blitter, fb->width, fb->height, 1,
                           buffers, color, depth, stencil);
        r600_blitter_end(ctx);
 
index 851b80c5484fc007244493959a6ec9970d88548b..e525f7950b0a158657b576d71084bf36e86cc228 100644 (file)
@@ -332,6 +332,7 @@ static void r600_clear(struct pipe_context *ctx, unsigned buffers,
 
        r600_blitter_begin(ctx, R600_CLEAR);
        util_blitter_clear(rctx->blitter, fb->width, fb->height,
+                          util_framebuffer_get_num_layers(fb),
                           buffers, color, depth, stencil);
        r600_blitter_end(ctx);
 }