[Mesa-dev] [RFC] ARB_gl_spirv and NIR backend for radeonsi

Jason Ekstrand jason at jlekstrand.net
Mon May 22 21:09:46 UTC 2017


Taking the "just reply to Nicolai" approach like everyeone else...

Nicolai,

First off, thanks for working on this!  I've given it a bit of thought in
the context of i965, so I've got a few ideas about how you could overcome
some of the issues.

On Sun, May 21, 2017 at 3:48 AM, Nicolai Hähnle <nhaehnle at gmail.com> wrote:

> Hi all,
>
> I've been looking into ARB_gl_spirv for radeonsi. I don't fancy
> re-inventing the ~8k LOC of src/compiler/spirv, and there's already a
> perfectly fine SPIR-V -> NIR -> LLVM compiler pipeline in radv, so I looked
> into re-using that.
>
> It's not entirely straightforward because radeonsi and radv use different
> "ABIs" for their shaders, i.e. prolog/epilog shader parts, different user
> SGPR allocations, descriptor loads work differently (obviously), and so on.
>

We have this same problem with NIR coming into our back-end compiler from
Vulkan, BLORP, and GLSL where they all speak very slightly different
variants.  The approach we've taken for most of this is to add
front-end-specific lowering passes that turn it into a common "ABI" that is
consumed by our two back-ends.  You could also do some switching in NIR ->
LLVM and that should work fine for small things.  If you want to see what
we've done, look for any anv_nir_*.c or brw_nir_*.c in src/intel/vulkan or
src/mesa/drivers/dri/i965.


> Still, it's possible to separate the ABI from the meat of the NIR -> LLVM
> translation. So here goes...
>
>
> The Step-by-Step Plan
> =====================
>
> 1. Add an optional GLSL-to-NIR path (controlled by R600_DEBUG=nir) for
> very simple VS-PS pipelines.
>

This sounds like both a good step and something that I think would be neat
to see.  There have been a variety of different discussions over the last
few years about compiler design choices but we've lacked the ability to get
any good apples-to-apples comparisons.  This may provide some opportunities
to do so.


> 2. Add GL_ARB_gl_spirv support to Mesa and test it on simple VS-PS
> pipelines.
>
> 3. Fill in all the rest:
> 3a. GL 4.x shader extensions (SSBOs, images, atomics, ...)
> 3b. Geometry and tessellation shaders
> 3c. Compute shaders
> 3d. Tests
>

spirv_to_nir should handle almost everything here (with the possible
exception of stand-alone atomic counters).


> I've started with step 1 and got basic GLSL 1.30-level vertex shaders
> working via NIR. The code is here: https://cgit.freedesktop.org/~
> nh/mesa/log/?h=nir
>
> The basic approach is to introduce `struct ac_shader_abi' to capture the
> differences between radeonsi and radv. In the end, the entry point for NIR
> -> LLVM translation will simply be:
>
>    void ac_nir_translate(struct ac_llvm_context *ac,
>                          struct ac_shader_abi *abi,
>                          struct nir_shader *nir);
>
> Setting up the LLVM function with its parameters is still considered part
> of the driver.
>
>
> Questions
> =========
>
> 1. How do we get good test coverage?
> ------------------------------------
> A natural candidate would be to add a SPIR-V execution mode for the piglit
> shader_runner. That is, use build scripts to extract shaders from
> shader_test files and feed them through glslang to get spv files, and then
> load those from shader_runner if a `-spirv' flag is passed on the command
> line.
>
> This immediately runs into the difficulty that GL_ARB_gl_spirv wants SSO
> linking semantics, and I'm pretty sure the majority of shader_test files
> don't support that -- if only because they don't set a location on the
> fragment shader color output.
>
> Some ideas:
> 1. Add a GL_MESA_spirv_link_by_name extension
> 2. Have glslang add the locations for us (probably difficult because
> glslang seems to be focused on one shader stage at a time.)
> 3. Hack something together in the shader_test-to-spv build scripts via
> regular expressions (and now we have two problems? :-) )
> 4. Other ideas?
>

Another thing I've considered when thinking about doing this myself would
be to add a SPIR-V back-end to either NIR or GLSL IR.  Then you can hook it
up as GLSL -> SPIR-V -> NIR and run some tests.  If you did this
post-linking, then you could just use the locations assigned by the linker
and all of the tests should basically work.  I'm not sure about whether
doing NIR -> SPIR-V or GLSL -> SPIR-V would be better.  Being able to
serialize NIR has its uses but, if one wanted to make the stand-alone
compiler into a GLSLang competitor, I think going directly from GLSL IR
would be better.


> 2. What's the Gallium interface?
> --------------------------------
> Specifically, does it pass SPIR-V or NIR?
>
> I'm leaning towards NIR, because then specialization, mapping of uniform
> locations, atomics, etc. can be done entirely in st/mesa.
>
> On the other hand, Pierre Moreau's work passes SPIR-V directly. On the
> third hand, it wouldn't be the first time that clover does things
> differently.
>
>
> 3. NIR vs. TGSI
> ---------------
> It is *not* a goal for this project to use NIR for normal GLSL shaders.
> We'll keep the TGSI backend at least for now. But it makes sense to think
> ahead.
>
> A minor disadvantage of NIR is that the GLSL-to-NIR path is not as solid
> as the GLSL-to-TGSI path yet, but this shouldn't be too difficult to
> overcome.
>
> The major disadvantage of NIR is that it doesn't have serialization.
> radeonsi uses the fact that TGSI *is* a serialization format for two things:
>
> - The internal shader cache, which avoids re-compiling the same shader
> over and over again when it's linked into different programs. (This part
> only needs a strong hash.)
>
> - The (disk) shader cache stores the TGSI so that it's available in case
> additional shader variants need to be compiled on the fly.
>
> Some ideas:
>
> 1. Add a serialization format for NIR. This is the most straight-forward
> solution, but it's a lot of work for a comparatively small feature.
>

This shouldn't be hard to do.  Some instruction types like texture
instructions will be a bit of work (not bad) but most of the instructions
are ALU instructions or intrinsics and those have a very nice introspection
mechanism that would let you write a fairly small piece of code that can
handle anthing.  All told, I doubt a well-written NIR [de]serialization
pass would take much more than around 1k LOC.


> 1b. Use SPIR-V as a serialization format for NIR. This is more work for
> serialization than a custom format due to the ceremony involved in SPIR-V,
> but we already have deserialization. Also, it'd implicitly give us an
> alternative GLSL-to-SPIR-V compiler, which is kind of neat.
>

Giving it a fairly small quantity of thought, I think this would probably
work out ok.  The biggest problem would be that NIR is typeless so you
would have to detect type changes and insert bitcast instructions at
various places.  There are some other mismatches but those are mostly
things that NIR expects to be lowered so they only show up in SPIR-V -> NIR.


> 2. Don't store TGSI/NIR in the (disk) shader cache. The reason we have to
> do that right now is that radeonsi does multi-threaded compilation, and so
> we cannot fallback all the way back to GLSL compilation if we need to
> compile a new shader variant. However, once we properly implement
> ARB_parallel_shader_compile, this issue will go away.
>
> This doesn't address the internal shader cache, though.
>
> 3. Have st/mesa recognize when the same shader is linked into multiple
> programs and avoid generating duplicate shader CSOs where possible. This is
> non-trivial mostly because linking can map shader I/O into different
> places, but I imagine that it would cover the majority of the cases caught
> by radeonsi's internal shader cache.
>
> 4. Something else for the internal shader cache?
>
> 5. Use TGSI after all. TGSI really isn't such a bad format. It does have
> some warts, like pretending that everything is a vec4, which means that f64
> support is already annoying, f16 support is going to be annoying, the way
> we do UBOs should probably be re-written (since it cannot support std430
> packing, which would be nice to have), and real (non-inline) function
> support will be nasty if we ever get there. But TGSI works, it's patient
> and straightforward.
>
> That said, NIR is nicer in several ways. Not using it just because it
> can't do serialization would be sad, not to mention those ~8k LOCs of
> SPIRV-to-NIR. We could go SPIRV-to-NIR-to-TGSI, of course, but that's not
> exactly great for compiler performance.
>
> All of this doesn't necessarily block the project of adding
> GL_ARB_gl_spirv, but it'd be nice to think a bit ahead.
>
> So, what does everybody think? I'm particularly interested in the nouveau
> folks' take on the whole NIR vs. TGSI thing, and any ideas on how to
> address the above questions.
>
> Cheers,
> Nicolai
> --
> Lerne, wie die Welt wirklich ist,
> Aber vergiss niemals, wie sie sein sollte.
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170522/db5c0f55/attachment-0001.html>


More information about the mesa-dev mailing list