iris: Enable ARB_shader_draw_parameters support
authorJose Maria Casanova Crespo <jmcasanova@igalia.com>
Tue, 26 Feb 2019 13:37:23 +0000 (14:37 +0100)
committerKenneth Graunke <kenneth@whitecape.org>
Tue, 26 Feb 2019 21:28:38 +0000 (13:28 -0800)
Additional VERTEX_ELEMENT_STATE are used to store basevertex and
baseinstance and drawid updating the DWordLength of the
3DSTATE_VERTEX_ELEMENTS command.

This passes all piglit tests for spec.*draw_parameters.* tests
and VK-GL-CTS KHR-GL45.shader_draw_parameters_tests.* tests.

Now we only mark a dirty_update when parameters are changed or
when we have an indirect draw.

We enable PIPE_CAP_DRAW_PARAMETERS on Iris.

There is no edge flag support in the Vertex Elements setup.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/gallium/drivers/iris/iris_context.h
src/gallium/drivers/iris/iris_draw.c
src/gallium/drivers/iris/iris_program.c
src/gallium/drivers/iris/iris_screen.c
src/gallium/drivers/iris/iris_state.c

index 8453e8c8d9e7a0dfccdeca3c813203f75fd99dc4..fe06fd935af41706decf2488f9801a37a355c72d 100644 (file)
@@ -448,6 +448,49 @@ struct iris_context {
 
    struct u_upload_mgr *query_buffer_uploader;
 
+   struct {
+      struct {
+         /**
+          * Either the value of BaseVertex for indexed draw calls or the value
+          * of the argument <first> for non-indexed draw calls.
+          */
+         int firstvertex;
+         int baseinstance;
+      } params;
+
+      /**
+       * Resource and offset that stores draw_parameters from the indirect
+       * buffer or to the buffer that stures the previous values for non
+       * indirect draws.
+       */
+      struct pipe_resource *draw_params_res;
+      uint32_t draw_params_offset;
+
+      struct {
+         /**
+          * The value of DrawID. This always comes in from it's own vertex
+          * buffer since it's not part of the indirect draw parameters.
+          */
+         int drawid;
+
+         /**
+          * Stores if an indexed or non-indexed draw (~0/0). Useful to
+          * calculate BaseVertex as an AND of firstvertex and is_indexed_draw.
+          */
+         int is_indexed_draw;
+      } derived_params;
+
+      /**
+       * Resource and offset used for GL_ARB_shader_draw_parameters which
+       * contains parameters that are not present in the indirect buffer as
+       * drawid and is_indexed_draw. They will go in their own vertex element.
+       */
+      struct pipe_resource *derived_draw_params_res;
+      uint32_t derived_draw_params_offset;
+
+      bool is_indirect;
+   } draw;
+
    struct {
       struct iris_uncompiled_shader *uncompiled[MESA_SHADER_STAGES];
       struct iris_compiled_shader *prog[MESA_SHADER_STAGES];
@@ -523,6 +566,11 @@ struct iris_context {
 
       struct iris_shader_state shaders[MESA_SHADER_STAGES];
 
+      /** Do vertex shader uses shader draw parameters ? */
+      bool vs_uses_draw_params;
+      bool vs_uses_derived_draw_params;
+      bool vs_needs_sgvs_element;
+
       /** Do any samplers (for any stage) need border color? */
       bool need_border_colors;
 
index 9dc102d2b70912135ec1d532421c230bd4423c97..e30f12974fb2d089f80e965ad158ce615fc04c72 100644 (file)
@@ -73,6 +73,40 @@ iris_update_draw_info(struct iris_context *ice,
       ice->state.primitive_restart = info->primitive_restart;
       ice->state.cut_index = info->restart_index;
    }
+
+   if (info->indirect) {
+      pipe_resource_reference(&ice->draw.draw_params_res,
+                              info->indirect->buffer);
+      ice->draw.draw_params_offset = info->indirect->offset +
+                                     (info->index_size ? 12 : 8);
+      ice->draw.params.firstvertex = 0;
+      ice->draw.params.baseinstance = 0;
+      ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
+                          IRIS_DIRTY_VERTEX_ELEMENTS |
+                          IRIS_DIRTY_VF_SGVS;
+   } else if (ice->draw.is_indirect ||
+              ice->draw.params.firstvertex !=
+              (info->index_size ? info->index_bias : info->start) ||
+              (ice->draw.params.baseinstance != info->start_instance)) {
+      pipe_resource_reference(&ice->draw.draw_params_res, NULL);
+      ice->draw.draw_params_offset = 0;
+      ice->draw.params.firstvertex =
+         info->index_size ? info->index_bias : info->start;
+      ice->draw.params.baseinstance = info->start_instance;
+      ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
+                          IRIS_DIRTY_VERTEX_ELEMENTS |
+                          IRIS_DIRTY_VF_SGVS;
+   }
+   ice->draw.is_indirect = info->indirect;
+
+   if (ice->draw.derived_params.drawid != info->drawid ||
+       ice->draw.derived_params.is_indexed_draw != (info->index_size ? ~0 : 0)) {
+      ice->draw.derived_params.drawid = info->drawid;
+      ice->draw.derived_params.is_indexed_draw = info->index_size ? ~0 : 0;
+      ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
+                          IRIS_DIRTY_VERTEX_ELEMENTS |
+                          IRIS_DIRTY_VF_SGVS;
+   }
 }
 
 /**
index 7f92c4a7998f030067edcb7b55d9331933cd8775..28864c4f0163bd416ac084c3795e8f9bb9aff90e 100644 (file)
@@ -617,6 +617,24 @@ iris_update_compiled_vs(struct iris_context *ice)
                           IRIS_DIRTY_BINDINGS_VS |
                           IRIS_DIRTY_CONSTANTS_VS |
                           IRIS_DIRTY_VF_SGVS;
+      const struct brw_vs_prog_data *vs_prog_data =
+            (void *) shader->prog_data;
+      const bool uses_draw_params = vs_prog_data->uses_firstvertex ||
+                                    vs_prog_data->uses_baseinstance;
+      const bool uses_derived_draw_params = vs_prog_data->uses_drawid ||
+                                            vs_prog_data->uses_is_indexed_draw;
+      const bool needs_sgvs_element = uses_draw_params ||
+                                      vs_prog_data->uses_instanceid ||
+                                      vs_prog_data->uses_vertexid;
+
+      if (ice->state.vs_uses_draw_params != uses_draw_params ||
+          ice->state.vs_uses_derived_draw_params != uses_derived_draw_params) {
+         ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS |
+                             IRIS_DIRTY_VERTEX_ELEMENTS;
+      }
+      ice->state.vs_uses_draw_params = uses_draw_params;
+      ice->state.vs_uses_derived_draw_params = uses_derived_draw_params;
+      ice->state.vs_needs_sgvs_element = needs_sgvs_element;
    }
 }
 
index d831ffbc0a27e919cc666ecfc075cdc98f399cfd..54c395c759f97f3e269358df68d2d26e7ea32fac 100644 (file)
@@ -172,6 +172,7 @@ iris_get_param(struct pipe_screen *pscreen, enum pipe_cap param)
    case PIPE_CAP_GLSL_TESS_LEVELS_AS_INPUTS:
    case PIPE_CAP_LOAD_CONSTBUF:
    case PIPE_CAP_NIR_COMPACT_ARRAYS:
+   case PIPE_CAP_DRAW_PARAMETERS:
       return true;
    case PIPE_CAP_TGSI_FS_FBFETCH:
    case PIPE_CAP_POST_DEPTH_COVERAGE:
index 578a61292e50f8afe8d9938c5980c5b6cdbfba06..464f81f17bf38103fd4bb9ec46e6b97e96c9deaf 100644 (file)
@@ -4651,6 +4651,62 @@ iris_upload_dirty_render_state(struct iris_context *ice,
 
    if (dirty & IRIS_DIRTY_VERTEX_BUFFERS) {
       int count = util_bitcount64(ice->state.bound_vertex_buffers);
+      int dynamic_bound = ice->state.bound_vertex_buffers;
+
+      if (ice->state.vs_uses_draw_params) {
+         if (ice->draw.draw_params_offset == 0) {
+            u_upload_data(ice->state.dynamic_uploader, 0, sizeof(ice->draw.params),
+                          4, &ice->draw.params, &ice->draw.draw_params_offset,
+                          &ice->draw.draw_params_res);
+         }
+         assert(ice->draw.draw_params_res);
+
+         struct iris_vertex_buffer_state *state =
+            &(ice->state.genx->vertex_buffers[count]);
+         pipe_resource_reference(&state->resource, ice->draw.draw_params_res);
+         struct iris_resource *res = (void *) state->resource;
+
+         iris_pack_state(GENX(VERTEX_BUFFER_STATE), state->state, vb) {
+            vb.VertexBufferIndex = count;
+            vb.AddressModifyEnable = true;
+            vb.BufferPitch = 0;
+            vb.BufferSize = res->bo->size - ice->draw.draw_params_offset;
+            vb.BufferStartingAddress =
+               ro_bo(NULL, res->bo->gtt_offset +
+                           (int) ice->draw.draw_params_offset);
+            vb.MOCS = mocs(res->bo);
+         }
+         dynamic_bound |= 1ull << count;
+         count++;
+      }
+
+      if (ice->state.vs_uses_derived_draw_params) {
+         u_upload_data(ice->state.dynamic_uploader, 0,
+                       sizeof(ice->draw.derived_params), 4,
+                       &ice->draw.derived_params,
+                       &ice->draw.derived_draw_params_offset,
+                       &ice->draw.derived_draw_params_res);
+
+         struct iris_vertex_buffer_state *state =
+            &(ice->state.genx->vertex_buffers[count]);
+         pipe_resource_reference(&state->resource,
+                                 ice->draw.derived_draw_params_res);
+         struct iris_resource *res = (void *) ice->draw.derived_draw_params_res;
+
+         iris_pack_state(GENX(VERTEX_BUFFER_STATE), state->state, vb) {
+             vb.VertexBufferIndex = count;
+            vb.AddressModifyEnable = true;
+            vb.BufferPitch = 0;
+            vb.BufferSize =
+               res->bo->size - ice->draw.derived_draw_params_offset;
+            vb.BufferStartingAddress =
+               ro_bo(NULL, res->bo->gtt_offset +
+                           (int) ice->draw.derived_draw_params_offset);
+            vb.MOCS = mocs(res->bo);
+         }
+         dynamic_bound |= 1ull << count;
+         count++;
+      }
 
       if (count) {
          /* The VF cache designers cut corners, and made the cache key's
@@ -4664,7 +4720,7 @@ iris_upload_dirty_render_state(struct iris_context *ice,
           */
          unsigned flush_flags = 0;
 
-         uint64_t bound = ice->state.bound_vertex_buffers;
+         uint64_t bound = dynamic_bound;
          while (bound) {
             const int i = u_bit_scan64(&bound);
             uint16_t high_bits = 0;
@@ -4704,7 +4760,7 @@ iris_upload_dirty_render_state(struct iris_context *ice,
          }
          map += 1;
 
-         bound = ice->state.bound_vertex_buffers;
+         bound = dynamic_bound;
          while (bound) {
             const int i = u_bit_scan64(&bound);
             memcpy(map, genx->vertex_buffers[i].state,
@@ -4717,8 +4773,59 @@ iris_upload_dirty_render_state(struct iris_context *ice,
    if (dirty & IRIS_DIRTY_VERTEX_ELEMENTS) {
       struct iris_vertex_element_state *cso = ice->state.cso_vertex_elements;
       const unsigned entries = MAX2(cso->count, 1);
-      iris_batch_emit(batch, cso->vertex_elements, sizeof(uint32_t) *
-                      (1 + entries * GENX(VERTEX_ELEMENT_STATE_length)));
+      if (!(ice->state.vs_needs_sgvs_element ||
+            ice->state.vs_uses_derived_draw_params)) {
+         iris_batch_emit(batch, cso->vertex_elements, sizeof(uint32_t) *
+                         (1 + entries * GENX(VERTEX_ELEMENT_STATE_length)));
+      } else {
+         uint32_t dynamic_ves[1 + 33 * GENX(VERTEX_ELEMENT_STATE_length)];
+         const int dyn_count = cso->count +
+            ice->state.vs_needs_sgvs_element +
+            ice->state.vs_uses_derived_draw_params;
+
+         iris_pack_command(GENX(3DSTATE_VERTEX_ELEMENTS),
+                           &dynamic_ves, ve) {
+            ve.DWordLength =
+               1 + GENX(VERTEX_ELEMENT_STATE_length) * dyn_count - 2;
+         }
+         memcpy(&dynamic_ves[1], &cso->vertex_elements[1], cso->count *
+                GENX(VERTEX_ELEMENT_STATE_length) * sizeof(uint32_t));
+         uint32_t *ve_pack_dest =
+            &dynamic_ves[1 + cso->count * GENX(VERTEX_ELEMENT_STATE_length)];
+
+         if (ice->state.vs_needs_sgvs_element) {
+            uint32_t base_ctrl = ice->state.vs_uses_draw_params ?
+                                 VFCOMP_STORE_SRC : VFCOMP_STORE_0;
+            iris_pack_state(GENX(VERTEX_ELEMENT_STATE), ve_pack_dest, ve) {
+               ve.Valid = true;
+               ve.VertexBufferIndex =
+                  util_bitcount64(ice->state.bound_vertex_buffers);
+               ve.SourceElementFormat = ISL_FORMAT_R32G32_UINT;
+               ve.Component0Control = base_ctrl;
+               ve.Component1Control = base_ctrl;
+               ve.Component2Control = VFCOMP_STORE_0;
+               ve.Component3Control = VFCOMP_STORE_0;
+            }
+            ve_pack_dest += GENX(VERTEX_ELEMENT_STATE_length);
+         }
+         if (ice->state.vs_uses_derived_draw_params) {
+            iris_pack_state(GENX(VERTEX_ELEMENT_STATE), ve_pack_dest, ve) {
+               ve.Valid = true;
+               ve.VertexBufferIndex =
+                  util_bitcount64(ice->state.bound_vertex_buffers) +
+                  ice->state.vs_uses_draw_params;
+               ve.SourceElementFormat = ISL_FORMAT_R32G32_UINT;
+               ve.Component0Control = VFCOMP_STORE_SRC;
+               ve.Component1Control = VFCOMP_STORE_SRC;
+               ve.Component2Control = VFCOMP_STORE_0;
+               ve.Component3Control = VFCOMP_STORE_0;
+            }
+            ve_pack_dest += GENX(VERTEX_ELEMENT_STATE_length);
+         }
+         iris_batch_emit(batch, &dynamic_ves, sizeof(uint32_t) *
+                         (1 + dyn_count * GENX(VERTEX_ELEMENT_STATE_length)));
+      }
+
       iris_batch_emit(batch, cso->vf_instancing, sizeof(uint32_t) *
                       entries * GENX(3DSTATE_VF_INSTANCING_length));
    }