[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