[Mesa-dev] Adding a SPIR-V back-end to the GLSL compiler

Ian Romanick idr at freedesktop.org
Tue May 30 23:32:15 UTC 2017


On 05/26/2017 08:57 AM, Jason Ekstrand wrote:
> This is something that I have considered doing on multiple occasions and
> have given a significant amount of thought.  Unfortunately, it has never
> made it particularly high on my priority list so no code has been
> written.  However, there have been a number of people who have brought
> this up lately so I thought I would do a brain-dump on the topic in the
> hopes of saving someone some effort.

I've thought about this a lot too.  I agree, to at least some extent,
with everything you say below.

> Why?
> 
> That's as good a place to start as any.  I think there a re a number of
> reasons why this may be a useful thing to do:
> 
>  1) Provide another GLSL -> SPIR-V compiler.  Right now, the only thing
> in that space is GLSLang and, while it seems to be servicing the need
> ok, it also means that drivers tend not to implement SPIR-V support so
> much as GLSLang support.  SPIR-V provides a decent amount of freedom in
> how you do things and GLSLang tends to only do them one way.  This means
> that the other 10 ways are untested in most drivers.  Having another
> SPIR-V producer out there would help the ecosystem.
> 
>  2) Optimizations.  One thing that I've heard developers asking for is
> some basic platform-agnostic optimizations specifically to reduce SPIR-V
> code size.  Our compiler stack already has quite a few optimizations
> that developers may want such as copy propagation, dead code
> elimination, constant folding, loop unrolling, CSE, etc.  In a GLSL ->
> SPIR-V translator, we would probably want these to be optional, but it
> wouldn't be hard to provide them as flags.

So... isn't that going to be a problem?  Pretty much all of our
optimization infrastructure is now in NIR, and we're working towards
removing at least some of the existing GLSL IR passes.

>  3) Bootstrapping GL_ARB_spirv.  The biggest barrier here is going to be
> testing and convincing ourselves that we've done everything right. 
> However, if we did GLSL -> SPIR-V -> NIR -> back-end, then we would be
> able to exercise both the GLSL -> SPIR-V path and the SPIR-V -> NIR path
> with the full piglit suite.  Some people have suggested modifying
> shader_runner.  However,  I think that if we simply did the SPIR-V
> translation inside the driver, it would be much easier to test things
> like non-SSO because we could go into SPIR-V after linking.
> 
>  4) Better testing spirv_to_nir.  See above.

This would augment the existing testing for spriv_to_nir (and
not-yet-existing testing for GL_ARB_spriv), but we will probably need to
start using a SPIR-V assembler to really hit all the corners.

>  5) Better spec compliance.  I don't know the glslang code base well
> enough to speak particularly strongly about it's correctness.  What I do
> know, however, is that the GLSL compiler in mesa is used in
> production-grade drivers that pass piglit, the Open GL 4.5 CTS, the Open
> GL ES 3.2 CTS, and the Android CTS.  That's not something you can say
> about GLSLang.  I think we should make that available to game devs
> wishing to target Vulkan.
> 
> Where?
> 
> This is a question that I have internally debated for some time.  When
> we first started working on Vulkan, we boot-strapped it by adding some
> hacks to the GLSL compiler to provide the descriptor set bindings and
> just used GLSL.  When it came time for SPIR-V support, I chose to go
> directly into NIR.  At the time, I thought that SPIR-V was going to end
> up being a fairly low-level IR and that NIR would be a better match. 
> However, as things turned out, SPIR-V (at least for graphics) is more of
> a binary form of GLSL than anything else.  In retrospect, there are a
> number of things (dealing with built-ins comes to mind) which would have
> been easier had we gone SPIR-V -> GLSL.  However, I still stand by my
> original decision for two reasons:
> 
>  1) As we try to add some of these "advanced compute" features that
> people keep talking about, I think NIR will be a better and better fit. 
> Trying to retrofit some of those things into GLSL may be more trouble
> than it's worth.
> 
>  2) Going directly into NIR meant that we didn't have to pull in
> mtypes.h.  NIR is a fairly stand-alone chunk of the mesa tree and we
> have pulled our i965 back-end compiler out so it only depends on NIR. 
> This makes the Vulkan driver much smaller and keeps it separate from the
> GL state tracker.
> 
> When considering a GLSL -> SPIR-V path there is some question about
> whether it should be GLSL -> NIR -> SPIR-V or GLSL -> SPIR-V directly. 
> There are pros and cons to both:
> 
>  1) SPIR-V would actually make a reasonable serialization format for
> NIR.  It's maybe not as compact as we could do if we made our own, but
> it's not bad.

Yeah, I think I suggested that to Nicolai in the SPIR-V for Radeon thread.

>  2) NIR is, in some ways simpler than GLSL IR so it may be a bit
> easier.  Unfortunately, that's not always a help...
> 
>  3) Because NIR is simpler, it requires a lot of lowering.  There are
> several things such as block variables (for UBOs and SSBOs) that NIR
> doesn't know how to handle.  It assumes that it just gets
> load_ubo(index, offset).  NIR also doesn't handle GLSL built-ins.  For
> SPIR-V -> NIR, those things are lowered a way on-the-fly.  This means
> that we would have to add some things to NIR and the SPIR-V code you get
> out would necessarily be lower-level than what glslang produces.
> 
>  4) As I pointed out above, GLSL is a bit better fit than NIR in a lot
> of ways.
> 
>  5) If we did NIR -> SPIR-V, we could also compile ARB programs to
> SPIR-V.  Maybe that's a downside?

I'm somewhat ambivalent about that.  I think an interesting standalone
project would be a compiler that could take some of the "advanced" NV
assembly shaders to SPRI-V.  I don't really want to see any of that
support come back into Mesa.

> All in all, my recommendation would be to do GLSL -> SPIR-V directly.  I
> think there's less of an impedance mismatch there and I think it would
> be easier to handle some of the higher-level things such as built-ins
> and block variables.
> 
> How?
> 
> This is something that I've also given quite a bit of thought. :-)  You
> could even say that I've written a decent chunk of it in my head.  Too
> bad I haven't typed it into a computer yet. :-(
> 
> The first thing I would do would be to write some sort of SPIR-V builder
> and put it in src/compiler/spirv.  It have multiple dword streams going
> at a time (SPIR-V has multiple sections) to handle things such as types,
> constants, etc. as well as function bodies.  Then you would have

An alternative would be to do it in two passes:  the first pass figures
out the sizes of the sections, and the second pass fills in the data.
Or perhaps I'm misunderstanding.

> functions which would generate SPIR-V opcodes similar to nir_builder.h. 
> For Types, you would have a single spv_type function that turned a
> glsl_type pointer into a SPIR-V ID.  You would want to have this backed
> by a hash map so that they aren't re-emitted all the time.  For the rest
> of the opcodes, SPIRV-Headers project on the Khronos github project has
> a JSON representation of SPIR-V so it shouldn't be hard to write a
> little python code that generates most of the "build an opcode"
> functions similar to what we do for nir_builder_opcodes.h.
> 
> Finally, you would write the GLSL -> SPIR-V (or NIR -> SPIR-V) pass on
> top of that.  If you did GLSL -> SPIR-V, you could probably look at
> glsl_to_nir for inspiration.
> 
> Ok, there's my brain-dump.  It's on the list now so anyone who wants to
> pick up the project has it.  I'm happy to chat further via e-mail or IRC
> about different approaches but I think I've given a fairly complete
> picture of my thoughts at the moment.  Happy Hacking!
> 
> --Jason



More information about the mesa-dev mailing list