[Mesa-dev] Implementation of VK_KHR_draw_indirect_count extension for anv

Jason Ekstrand jason at jlekstrand.net
Tue Sep 18 10:08:24 UTC 2018

On Tue, Sep 18, 2018 at 4:08 AM Danylo Piliaiev <danylo.piliaiev at gmail.com>

> On 9/17/18 7:03 PM, Jason Ekstrand wrote:
> On Mon, Sep 17, 2018 at 10:08 AM Danylo Piliaiev <
> danylo.piliaiev at gmail.com> wrote:
>> On 9/17/18 5:34 PM, Jason Ekstrand wrote:
>> On Mon, Sep 17, 2018 at 8:34 AM Danylo Piliaiev <
>> danylo.piliaiev at gmail.com> wrote:
>>> Hi Jason,
>>> I have implemented the extension and it works, however before sending
>>> the patch I decided to see how it can interact with other extension -
>>> VK_EXT_conditional_render
>>> and got confused:
>>> From the spec it is not disallowed to call functions of
>>> VK_KHR_draw_indirect_count in conditional rendering block. So let's say
>>> that predicate of conditional rendering
>>> will result in FALSE, we call vkCmdDrawIndirectCountKHR which sees that
>>> there is already a predicate emitted and it should be taken into account,
>>> since it will be FALSE
>>> all next predicates should result in FALSE. The issue is that I don't
>>> see an easy way to do this.
>>> My current implementation uses the next predicate (it is same as in GL
>>> implementation):
>>>        /* While draw_index < maxDrawCount the predicate's result will be
>>>         *  (draw_index == maxDrawCount) ^ TRUE = TRUE
>>>         * When draw_index == maxDrawCount the result is
>>>         *  (TRUE) ^ TRUE = FALSE
>>>         * After this all results will be:
>>>         *  (FALSE) ^ FALSE = FALSE
>>>         */
>>>        anv_batch_emit(&cmd_buffer->batch, GENX(MI_PREDICATE), mip) {
>>>           mip.LoadOperation    = LOAD_LOAD;
>>>           mip.CombineOperation = COMBINE_XOR;
>>>           mip.CompareOperation = COMPARE_SRCS_EQUAL;
>>>        }
>>> But if the initial predicate state is FALSE then when draw_index equals
>>> maxDrawCount the result will be
>>>   (FALSE) ^ TRUE = TRUE
>>> Which isn't something we want. But without "not equal" operation or
>>> without MI_MATH I don't see how to fix this.
>> First off, thanks for looking into the combination of these two
>> features.  Getting them to work together nicely is half of the difficulty
>> of these two extensions.
>> On platforms which support MI_MATH, I think we're probably better off
>> just using it.  For Ivy Bridge, the only thing I could think to do when
>> both are in use would be to do two MI_PREDICATEs for every draw call.  The
>> first would be what you describe above and the second would be the
>> MI_PREDICATE for the conditional render with COMBINE_AND.  When the
>> condition is true, the AND would have no effect and you would get the
>> behavior above.  If the condition is false, the above logic for
>> implementing draw_indirect_count wouldn't matter because it would get ANDed
>> with false.  On Haswell and later, it's likely more efficient to just use
>> MI_MATH and avoid re-loading the draw count and condition on every draw
>> call.  (We could just leave the draw count in CS_GPR0, for instance.)  Does
>> that work?
>> Looks like a plan. I'll try to go this path.
>> Also there is another interaction which wasn't thought of before:
>> Several vkCmdDrawIndirectCountKHR in conditional render block but using
>> MI_MATH should solve it.
> In that case, we'll have to basically re-do the conditional bit for every
> draw call.  There may be some interesting interactions here with secondary
> command buffers as well.  I don't remember what we decided about inheriting
> conditions in secondaries.  Again, if we decide we need MI_MATH, then we'll
> just drop support for one or both extensions on Ivy Bridge.
> About the secondary command buffers:
> If inherited conditional rendering
> <https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#features-features-inheritedConditionalRendering>
> is supported it means that secondary buffers can be executed inside
> conditional rendering block and commands which can be affected by
> conditional rendering are affected by it in secondary buffer and also in
> primary, is it right?
> However at this point the secondary buffer is already composed without
> commands for conditions and since our implementation depends on commands
> emitted to the buffer making its commands to depend on condition either
> highly tricky to do (secondary buffer needs to have certain points where to
> inject conditions?) or just impossible.
> And this secondary buffer may have been formed inside conditional render
> block so they could be affected by two conditions if I understand correctly.
> Is is doable to implement?

I think it is.  The obvious way to implement it would be to have a boolean
in the command buffer somewhere that tells you whether or not conditional
rendering is enabled and use that to set the PredicateEnable bit on
3DPRIMITIVE commands.  For secondary command buffers, however, we would
have to assume that predication is enabled and set the predicate to true in
vkCmdExecuteCommands if conditional rendering is disabled.

The second issue is in communicating the predicate value.  If we don't have
secondaries, we can just hang on to the condition buffer and re-read it
whenever needed.  If we're going to use secondaries, we won't have it
available in the secondary.  One obvious option would be to simply reserve
one of the CS_GPR registers, say CS_GPR15, for storing the predicate
value.  On Ivy Bridge, the CS_GPRs don't exist and we'd have to pick some
other RW register.  Digging through the docs, I found the MI_PREDICATE_DATA
which seems to exist for just this sort of thing. :-)  Exactly what
register we use will have to depend on how we want to compute predicate
values; I could see CS_GPR15 being more convenient if we use MI_MATH, for

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20180918/ffcd8495/attachment.html>

More information about the mesa-dev mailing list