<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Mon, Oct 15, 2018 at 7:06 AM Lionel Landwerlin <<a href="mailto:lionel.g.landwerlin@intel.com">lionel.g.landwerlin@intel.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 13/10/2018 14:09, Jason Ekstrand wrote:<br>
> Annoyingly, this requires that we implement integer division on the<br>
> command streamer.  Fortunately, we're only ever dividing by constants so<br>
> we can use the mulh+add+shift trick and it's not as bad as it sounds.<br>
> ---<br>
>   src/intel/vulkan/anv_device.c      |   2 +-<br>
>   src/intel/vulkan/genX_cmd_buffer.c | 150 +++++++++++++++++++++++++++++<br>
>   2 files changed, 151 insertions(+), 1 deletion(-)<br>
><br>
> diff --git a/src/intel/vulkan/anv_device.c b/src/intel/vulkan/anv_device.c<br>
> index 6395656dfd0..acca97b53d1 100644<br>
> --- a/src/intel/vulkan/anv_device.c<br>
> +++ b/src/intel/vulkan/anv_device.c<br>
> @@ -1226,7 +1226,7 @@ void anv_GetPhysicalDeviceProperties2(<br>
>            props->transformFeedbackQueries = VK_FALSE;<br>
>            props->transformFeedbackStreamsLinesTriangles = VK_FALSE;<br>
>            props->transformFeedbackRasterizationStreamSelect = VK_TRUE;<br>
> -         props->transformFeedbackDraw = VK_FALSE;<br>
> +         props->transformFeedbackDraw = VK_TRUE;<br>
>            break;<br>
>         }<br>
>   <br>
> diff --git a/src/intel/vulkan/genX_cmd_buffer.c b/src/intel/vulkan/genX_cmd_buffer.c<br>
> index 90469abbf21..1fbcfaf4264 100644<br>
> --- a/src/intel/vulkan/genX_cmd_buffer.c<br>
> +++ b/src/intel/vulkan/genX_cmd_buffer.c<br>
> @@ -27,6 +27,7 @@<br>
>   #include "anv_private.h"<br>
>   #include "vk_format_info.h"<br>
>   #include "vk_util.h"<br>
> +#include "util/fast_idiv_by_const.h"<br>
>   <br>
>   #include "common/gen_l3_config.h"<br>
>   #include "genxml/gen_macros.h"<br>
> @@ -2880,7 +2881,156 @@ emit_mul_gpr0(struct anv_batch *batch, uint32_t N)<br>
>      build_alu_multiply_gpr0(dw + 1, &num_dwords, N);<br>
>   }<br>
>   <br>
> +static void<br>
> +emit_alu_add(struct anv_batch *batch, unsigned dst_reg,<br>
> +             unsigned reg_a, unsigned reg_b)<br>
> +{<br>
> +   uint32_t *dw = anv_batch_emitn(batch, 1 + 4, GENX(MI_MATH));<br>
> +   dw[1] = mi_alu(MI_ALU_LOAD, MI_ALU_SRCA, reg_a);<br>
> +   dw[2] = mi_alu(MI_ALU_LOAD, MI_ALU_SRCB, reg_b);<br>
> +   dw[3] = mi_alu(MI_ALU_ADD, 0, 0);<br>
> +   dw[4] = mi_alu(MI_ALU_STORE, dst_reg, MI_ALU_ACCU);<br>
> +}<br>
> +<br>
> +static void<br>
> +emit_add32_gpr0(struct anv_batch *batch, uint32_t N)<br>
> +{<br>
> +   emit_lri(batch, CS_GPR(1), N);<br>
> +   emit_alu_add(batch, MI_ALU_REG0, MI_ALU_REG0, MI_ALU_REG1);<br>
> +}<br>
> +<br>
> +static void<br>
> +emit_alu_shl(struct anv_batch *batch, unsigned dst_reg,<br>
> +             unsigned src_reg, unsigned shift)<br>
> +{<br>
> +   assert(shift > 0);<br>
> +<br>
> +   uint32_t *dw = anv_batch_emitn(batch, 1 + 4 * shift, GENX(MI_MATH));<br>
> +   for (unsigned i = 0; i < shift; i++) {<br>
> +      unsigned add_src = (i == 0) ? src_reg : dst_reg;<br>
> +      dw[1 + (i * 4) + 0] = mi_alu(MI_ALU_LOAD, MI_ALU_SRCA, add_src);<br>
> +      dw[1 + (i * 4) + 1] = mi_alu(MI_ALU_LOAD, MI_ALU_SRCB, add_src);<br>
> +      dw[1 + (i * 4) + 2] = mi_alu(MI_ALU_ADD, 0, 0);<br>
> +      dw[1 + (i * 4) + 3] = mi_alu(MI_ALU_STORE, dst_reg, MI_ALU_ACCU);<br>
> +   }<br>
> +}<br>
> +<br>
> +static void<br>
> +emit_div32_gpr0(struct anv_batch *batch, uint32_t D)<br>
> +{<br>
> +   /* Zero out the top of GPR0 */<br>
> +   emit_lri(batch, CS_GPR(0) + 4, 0);<br>
> +<br>
> +   if (D == 0) {<br>
> +      /* This invalid, but we should do something so we set GPR0 to 0. */<br>
> +      emit_lri(batch, CS_GPR(0), 0);<br>
> +   } else if (util_is_power_of_two_or_zero(D)) {<br>
> +      unsigned log2_D = util_logbase2(D);<br>
> +      assert(log2_D < 32);<br>
> +      /* We right-shift by log2(D) by left-shifting by 32 - log2(D) and taking<br>
> +       * the top 32 bits of the result.<br>
> +       */<br>
> +      emit_alu_shl(batch, MI_ALU_REG0, MI_ALU_REG0, 32 - log2_D);<br>
> +      emit_lrr(batch, CS_GPR(0) + 0, CS_GPR(0) + 4);<br>
> +      emit_lri(batch, CS_GPR(0) + 4, 0);<br>
> +   } else {<br>
> +      struct util_fast_udiv_info m = util_compute_fast_udiv_info(D, 32, 32);<br>
> +      assert(m.multiplier <= UINT32_MAX);<br>
> +<br>
> +      if (m.pre_shift) {<br>
> +         /* We right-shift by L by left-shifting by 32 - l and taking the top<br>
> +          * 32 bits of the result.<br>
> +          */<br>
> +         if (m.pre_shift < 32)<br>
> +            emit_alu_shl(batch, MI_ALU_REG0, MI_ALU_REG0, 32 - m.pre_shift);<br>
> +         emit_lrr(batch, CS_GPR(0) + 0, CS_GPR(0) + 4);<br>
> +         emit_lri(batch, CS_GPR(0) + 4, 0);<br>
> +      }<br>
> +<br>
> +      /* Do the 32x32 multiply  into gpr0 */<br>
> +      emit_mul_gpr0(batch, m.multiplier);<br>
> +<br>
> +      if (m.increment) {<br>
> +         /* If we need to increment, save off a copy of GPR0 */<br>
> +         emit_lri(batch, CS_GPR(1) + 0, m.multiplier);<br>
> +         emit_lri(batch, CS_GPR(1) + 4, 0);<br>
> +         emit_alu_add(batch, MI_ALU_REG0, MI_ALU_REG0, MI_ALU_REG1);<br>
> +      }<br>
> +<br>
> +      /* Shift by 32 */<br>
> +      emit_lrr(batch, CS_GPR(0) + 0, CS_GPR(0) + 4);<br>
> +      emit_lri(batch, CS_GPR(0) + 4, 0);<br>
> +<br>
> +      if (m.post_shift) {<br>
> +         /* We right-shift by L by left-shifting by 32 - l and taking the top<br>
> +          * 32 bits of the result.<br>
> +          */<br>
> +         if (m.post_shift < 32)<br>
> +            emit_alu_shl(batch, MI_ALU_REG0, MI_ALU_REG0, 32 - m.post_shift);<br>
> +         emit_lrr(batch, CS_GPR(0) + 0, CS_GPR(0) + 4);<br>
> +         emit_lri(batch, CS_GPR(0) + 4, 0);<br>
> +      }<br>
> +   }<br>
> +}<br>
> +<br>
> +#endif /* GEN_IS_HASWELL || GEN_GEN >= 8 */<br>
> +<br>
> +void genX(CmdDrawIndirectByteCountEXT)(<br>
> +    VkCommandBuffer                             commandBuffer,<br>
> +    uint32_t                                    instanceCount,<br>
> +    uint32_t                                    firstInstance,<br>
> +    VkBuffer                                    counterBuffer,<br>
> +    VkDeviceSize                                counterBufferOffset,<br>
> +    uint32_t                                    counterOffset,<br>
> +    uint32_t                                    vertexStride)<br>
> +{<br>
> +#if GEN_IS_HASWELL || GEN_GEN >= 8<br>
> +   ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, commandBuffer);<br>
> +   ANV_FROM_HANDLE(anv_buffer, counter_buffer, counterBuffer);<br>
> +   struct anv_pipeline *pipeline = cmd_buffer->state.gfx.base.pipeline;<br>
> +   const struct brw_vs_prog_data *vs_prog_data = get_vs_prog_data(pipeline);<br>
> +<br>
> +   /* firstVertex is always zero for this draw function */<br>
> +   const uint32_t firstVertex = 0;<br>
> +<br>
> +   if (GEN_GEN == 7 && !GEN_IS_HASWELL)<br>
> +      return;<br>
<br>
<br>
I think this isn't needed as you've got the right #if above.<br></blockquote><div><br></div><div>Right.  I'll get rid of it.</div><div><br></div><div>--Jason</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> +<br>
> +   if (anv_batch_has_error(&cmd_buffer->batch))<br>
> +      return;<br>
> +<br>
> +   genX(cmd_buffer_flush_state)(cmd_buffer);<br>
> +<br>
> +   if (vs_prog_data->uses_firstvertex ||<br>
> +       vs_prog_data->uses_baseinstance)<br>
> +      emit_base_vertex_instance(cmd_buffer, firstVertex, firstInstance);<br>
> +   if (vs_prog_data->uses_drawid)<br>
> +      emit_draw_index(cmd_buffer, 0);<br>
> +<br>
> +   /* Our implementation of VK_KHR_multiview uses instancing to draw the<br>
> +    * different views.  We need to multiply instanceCount by the view count.<br>
> +    */<br>
> +   instanceCount *= anv_subpass_view_count(cmd_buffer->state.subpass);<br>
> +<br>
> +   emit_lrm(&cmd_buffer->batch, CS_GPR(0),<br>
> +            anv_address_add(counter_buffer->address, counterBufferOffset));<br>
> +   if (counterOffset)<br>
> +      emit_add32_gpr0(&cmd_buffer->batch, -counterOffset);<br>
> +   emit_div32_gpr0(&cmd_buffer->batch, vertexStride);<br>
> +   emit_lrr(&cmd_buffer->batch, GEN7_3DPRIM_VERTEX_COUNT, CS_GPR(0));<br>
> +<br>
> +   emit_lri(&cmd_buffer->batch, GEN7_3DPRIM_START_VERTEX, firstVertex);<br>
> +   emit_lri(&cmd_buffer->batch, GEN7_3DPRIM_INSTANCE_COUNT, instanceCount);<br>
> +   emit_lri(&cmd_buffer->batch, GEN7_3DPRIM_START_INSTANCE, firstInstance);<br>
> +   emit_lri(&cmd_buffer->batch, GEN7_3DPRIM_BASE_VERTEX, 0);<br>
> +<br>
> +   anv_batch_emit(&cmd_buffer->batch, GENX(3DPRIMITIVE), prim) {<br>
> +      prim.IndirectParameterEnable  = true;<br>
> +      prim.VertexAccessType         = SEQUENTIAL;<br>
> +      prim.PrimitiveTopologyType    = pipeline->topology;<br>
> +   }<br>
>   #endif /* GEN_IS_HASWELL || GEN_GEN >= 8 */<br>
> +}<br>
>   <br>
>   static void<br>
>   load_indirect_parameters(struct anv_cmd_buffer *cmd_buffer,<br>
<br>
<br>
</blockquote></div></div>