# How to get assembly code from GLSL Shader

I am new to optimizing shader code. Now that I have written an "optimzation", I want to make sure that it really speeds things up and is not just an unreadable version of what I intend to do. For this, I wanted to look into the assembly version of my shader, but I couldn't really find out how to do that.

I use CodeXL and APITrace, but the former doesn't have any Assembly view as far as I could see and the latter didn't work for my program for some reason. Most other debugging tools don't work (properly) because I program using OpenSceneGraph, meaning there is some Legacy OpenGL Code.

Therefore my question: How would I get to seeing assembly code of my shaders?

• "For this, I wanted to look into the assembly version of my shader" Unless you're getting the platform-specific machine code, anything you see will be essentially useless for telling if your optimization was successful. The most effective way to tell if you gained something from an optimization is to benchmark it. Oh, and OSG is not exactly known for being performance-friendly. – Nicol Bolas May 8 '18 at 16:49
• OSG is not exactly known for being perfomance-friendly that decision is not in my hands, I have to work with it. My optimization is branching elimination - while I wasn't aware how hardware dependend optimizations are, I was under the assumption that branch elimination is generally preferable. However I now have three sign calls, which is why I wanted to do this in the first place. Nevertheless, thank you for the input. – Tare May 8 '18 at 18:19

In unextended OpenGL that's indeed a little difficult, if possible at all. There is really no actual notion of "GLSL assembly code", or not one that's remotely vendor-independent, let alone a way to retrieve that.

There are a few extensions that might help you get that information, though, albeit in a not entirely intuitive or even platform-dependent way (but well, you're talking about micro-optimizations, so we're firmly in platform-dependent territory anyway).

First of all, there's GL_ARB_get_program_binary (core since 4.1), which let's you retrieve a platform-dependent binary version of the program (after linking). At least on NVidia hardware (maybe others, too, but I wouldn't know) this binary blob also contains ASCII assembly listings of all the contained shaders in NVidia-extended ARB syntax (continuously refined in the GL_NV_gpu_programX extensions). Those listings are quite easy to find in the binary when opening it with a normal text editor and the syntax is quite straight forward if you know your way around shaders and general assembly programming principles. As said, other vendors might offer similar listings inside their binaries.

Then there's also external programs that might compile your shader into some intermediate form, the most platform-independent of those being SPIR-V, for which Khronos-approved external compilers exist. Being an intermediate language this is somewhat of a "high-level assembly language" with an "assembly-like" structure but with many high-level abstractions that builds a bit of a compromise between the easy interpretability of assembly and the easy programability and platform-independence of a high-level language (think of Java bytecode).

With the GL_ARB_spirv extension (core since 4.6) you can directly use (externally precompiled) SPIR-V programs in OpenGL in place of GLSL shaders. I don't know if there is currently a way to let your driver compile GLSL into SPIR-V and then retrieve that. Otherwise some external SPIR-V module created from a reference compiler would not necessarily be equal to the machine code that your driver's actual GLSL compiler produces. It might also be that such an intermediate representation might already be too high-level for analysing micro-optimizations anyway.

All in all, and especially if you just want to use it for debugging/analyzing purposes on a dedicated machine, trying to look for a whatever-natured assembly listing in your driver's binary blob retrieved with glGetProgramBinary might be the easiest and most "close-to-the metal" way to get some insight into the compiled product. I use it occasionally just out of interest.

But of course no answer to this question would be complete without a warning that you shouldn't make too much out of it either. As on the CPU, generally trusting your compiler is a good default approach and you shouldn't let micro-optimizations like this guide your practice too much, let alone rely on any of that guidance being remotely portable (let alone assume that the assembly listed in the binary is actually what's uses as machine code). But if you want to know what your driver might make of it, it can be quite interesting and helpful, especially when deciding between two equally meaningful ways to write some function that might have unexpected differences in the "assembly".

• As I already mentioned in the code above, I wanted to take out branching and came up with a solution that uses sign three times. I wasn't aware, just how hardware dependent this is, I assumed for example that NVidia graphics cards would turn up more or less the same results. Also, one often reads to get rid of branching to optimize code, which I took to be a general advice, rather than it being firmly in platform-dependent territory. I guess from your answer though, that the SPIR-V route is probably the best for me at this point, because of OSG. In any case, thanks for the thorough answer. – Tare May 9 '18 at 6:12
• @Tare Well, yes, that is indeed pretty general advice. There are definitely some clear optimization advices that pertain to how GPUs and shaders generally work and the principles of how they're programmed. However, that is also rather high-level stuff that doesn't usually require looking into specific assembly too much. I was more thinking of real micro-optimization stuff. I didn't mean to say looking at the assembly can't give you a general idea how your code maps to GPUs, just that you shouldn't rely too much on the specific instructions being all too accurate guidance for every machine. – Christian Rau May 9 '18 at 8:26