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

Jason Ekstrand jason at jlekstrand.net
Tue May 30 23:46:38 UTC 2017


On Tue, May 30, 2017 at 4:32 PM, Ian Romanick <idr at freedesktop.org> wrote:

> 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.
>

Yes and no.  GLSL IR will always have some of those optimizations if for
nothing other than enforcing GLSL rules about varyings etc.  Even if all
they get is basic copy propagation, constant folding, and dead-code, that
should be enough to cut the SPIR-V file size in half in a lot of cases.


> >  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.
>

Yes.  Fortunately, the Vulkan CTS has a medium sized set of hand-written
SPIR-V tests.  Most of the interesting ones target control flow which is by
far the trickiest bit.


> >  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.
>

Fair enough. :-)


> > 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.
>

I don't think that's practical.  You can't know the size of the sections
without basically doing a full walk of the shader and pretending to
generate SPIR-V.  I think glslang has 3 or 4 instances of
std::vector<uint32_t>.  I think you need at least 3: decorations,
types+constants, code.  It's a bit unfortunate and I'm not convinced that
splitting things into sections actually helps parsers, but it is what it is.


> > 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20170530/3dd6f6a9/attachment-0001.html>


More information about the mesa-dev mailing list