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

<p>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).</p>

<p>First of all, there's <strong><a href="https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_get_program_binary.txt" rel="nofollow noreferrer">GL_ARB_get_program_binary</a> (core since 4.1), which let's you retrieve a platform-dependent binary</strong> 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 <code>GL_NV_gpu_programX</code> 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 <em>might</em> offer similar listings inside their binaries.</p>

<p>Then there's also external programs that might compile your shader into some <strong>intermediate form, the most platform-independent of those being <a href="https://www.khronos.org/opengl/wiki/SPIR-V" rel="nofollow noreferrer">SPIR-V</a></strong>, for which Khronos-approved external compilers exist. Being an <em>intermediate</em> 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).</p>

<p>With the <a href="https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gl_spirv.txt" rel="nofollow noreferrer">GL_ARB_spirv</a> 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 <em>driver</em> compile GLSL into SPIR-V and then retrieve that. Otherwise some external SPIR-V module created from a reference compiler would <strong><em>not</em> necessarily be equal to the machine code that your driver's actual GLSL compiler produces</strong>. It might also be that such an intermediate representation might already be <strong>too high-level</strong> for analysing micro-optimizations anyway.</p>

<p>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 <code>glGetProgramBinary</code> 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.</p>

<p>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 <strong>shouldn't let micro-optimizations like this guide your practice too much, let alone rely on any of that guidance being remotely portable</strong> (let alone assume that the assembly listed in the binary is <em>actually</em> what's uses as machine code). But if you want to know what your driver <em>might</em> 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".</p>

CC BY-SA 4.0
2018-05-09T06:12:53.440Z
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
CC BY-SA 4.0
2018-05-09T08:26:44.673Z
@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
CC BY-SA 4.0
2018-05-08T15:52:48.687Z
2018-05-08T15:52:48.687Z
Christian Rau
<p>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. </p>

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

<p>Therefore my question: How would I get to seeing assembly code of my shaders?</p>

CC BY-SA 4.0
2018-05-08T16:49:52.223Z
"*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
CC BY-SA 4.0
2018-05-08T18:19:11.433Z
`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
<glsl><assembly><optimization>
How to get assembly code from GLSL Shader
Tare
# How to get assembly code from GLSL Shader

(Asked by: username_0 on 2018-05-08)

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?

**Tags:** glsl, assembly, optimization

> **Comments:**
> **username_1**: "*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.  
> **username_0**: `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.  

---

## 1 answers

### Answer by username_2 on 2018-05-08. Score: 4 | Accepted answer

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](https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_get_program_binary.txt) (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](https://www.khronos.org/opengl/wiki/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](https://www.khronos.org/registry/OpenGL/extensions/ARB/ARB_gl_spirv.txt) 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".

> **Comments:**
> **username_0**: 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.  
> **username_2**: @username_0 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.  

---

