Difference between revisions of "Selecting a Shading Language"

From OpenGL Wiki
Jump to: navigation, search
(Offline Compiler, Binary Format)
(Added SPIR-V to this page.)
 
(12 intermediate revisions by 4 users not shown)
Line 1: Line 1:
== Overview ==
+
The various extensions and core revisions of the OpenGL API have led to the availability of a number of different potential shading languages that you may use. This page will deal with what they are, their pros and cons, and hardware.
  
Before we address this question, it's worthwhile to enumerate the choices you have:
+
== Main options ==
  
* [[GLSL]] - aka OpenGL Shading Language (aka GLSlang); a high-level shading language
+
While there are other possibilities, these are the three primary competitors in the OpenGL space:
* [[Cg]] - another high-level shading language, but by NVidia
 
* ARB/EXT or vendor-specific assembly profiles - low-level "assembly" shading languages
 
  
The OpenGL purist would of course state that you should ''always'' use [[GLSL]].  However, there are specific needs that might favor any one of these approaches.  So it's up to you to chose, but in the absence of any specific needs do favor [[GLSL]].
+
* [[OpenGL Shading Language]] (GLSL)
[[GLSL]] has been supported in the OpenGL core since OpenGL 2.0.
+
* [[SPIR-V]]
 +
* [[Cg|C for Graphics]] (Cg)
 +
* ARB assembly: assembly-like languages that are accessed through a set of ARB extensions.
 +
* NVIDIA assembly: NVIDIA-specific extensions to the ARB assembly language.
  
This page will (eventually) be expanded to provide you with all the information you need to make your choice based on your application's needs.
+
== OpenGL shading language ==
 +
{{main|OpenGL Shading Language}}
  
== Shading Language Considerations ==
+
The OpenGL Shading Language (GLSL) is a "high-level" language. This means high-level compared to assembly, not high-level the way a language like C# is compared to C. GLSL is structurally very similar to C.
  
Here are some of the points you need to consider when choosing a shading language:
+
=== Advantages ===
  
* Ease of use
+
This is the current standard, as far as OpenGL is concerned. It is one of only two shading languages ([[#SPIR-V|SPIR-V]] being the other) that is a part of the OpenGL specification.
* Cross-vendor Y/N
 
* Cross-platform Y/N
 
* Run-time efficiency
 
* Compilation time
 
* Feature differences
 
  
For now, this section will be brief, but eventually we'll try to beef this up with more specifics on each of these and how they relate to each shading language.
+
Because of this, it is kept up-to-date with current OpenGL features. Each new version of the base standard usually means a new version number of GLSL as well.
  
* '''Ease of use'''
+
=== Disadvantages ===
*: Choose a high-level language ([[GLSL]] or [[Cg]]).  You really don't want to be coding assembly unless you're trying to wring out every last microsecond of performance on a specific card by a specific vendor.
 
  
* '''Cross-vendor Y/N'''
+
The complexity of having a full C-style language in a graphics driver causes quite a few driver bugs to show themselves, particularly in ATI compilers.
*: [[GLSL]] and ARB/EXT assembly profiles are explicitly cross-vendor.  However, check whether stable support for these languages/extensions has been provided by each vendor you are considering.  [[Cg]] is also cross-vendor, but for non-[[nVidia]] [[GPU]]s, you drop down to SM2.0 capability.
 
  
* '''Cross-platform'''
+
NVIDIA's GLSL compiler is really a slight modification of the Cg compiler. Because of that, some of the differences between GLSL and Cg will occasionally show their heads. Cg is more permissive syntactically than GLSL, so a GLSL program that compiles on an NVIDIA driver may not compile on an ATI driver. It can also give unusual error messages, with references to a "profile" (a concept that exists in Cg but not GLSL).
*: See previous point.
 
  
* '''Run-time Efficiency'''
+
== SPIR-V ==
*: This is one of those things you're just going have to try as it's going to depend on how you use the API.
+
{{main|SPIR-V}}
  
* '''Compilation time'''
+
SPIR-V is an intermediate shading language developed by the Khronos Group (the organization also responsible for OpenGL and other standards). Though initially developed for Vulkan and OpenCL, the ability to give OpenGL a SPIR-V shader was also added to OpenGL in 4.6.
*: Obviously compiling high-level shading languages isn't going to be instantaneous.  If you're going to compile all the shaders you'll ''ever'' need during a run at startup, you probably don't care much about this time (as long as the user doesn't wait too long at startup). But if you want to build/compile shaders at run-time, you might prefer an option such as loading pre-compiled shaders or background shader compilation, and not all these shading languages support that (see [[#Offline Compiler, Binary Format]] below for more on this).
 
  
* '''Feature differences'''
+
=== Advantages ===
*: Hopefully we'll eventually have a good pick-list here.  Things like having an effects framework, switchable compile-time or run-time shader "decision" points, support for bit-packing/unpacking statements, predetermined varying slots, etc.
 
  
Now for a brief history of shading support in OpenGL to give you some context:
+
SPIR-V is an intermediate language, so it lacks some of the higher-level constructs that often challenge GLSL compilers. As an intermediate language, many shading languages can compile directly to it. The [https://github.com/KhronosGroup/glslang glslang project] provides an off-line compiler tool that can convert GLSL into SPIR-V compatible with OpenGL.
  
== History ==
+
SPIR-V also has a developing ecosystem around supporting it. Glslang itself even provides HLSL support (though it's not clear if HLSL-to-SPIR-V for OpenGL is effective). There are tools to perform introspection over SPIR-V shader files, to manipulate and combine them, and so forth.
  
In the beginning ...
+
=== Disadvantages ===
  
Many years ago, nVidia designed the register combiners ([[NV_register_combiners]]) and implemented the technology in their TNT but I'm not sure if they became popular. Later came the TNT and then, Geforce 256. During the Geforce 256 era, nVidia wanted everyone to do bump mapping and various effects possible with RC. This wasn't strictly a shader language but it allowed programmers to setup the fragment end of the graphics pipe. You needed to make API calls to setup the GPU. nVidia later released their nvasm. Programmers wrote in a assembly language and compiled this.
+
Though SPIR-V as a language is compatible with several backends, it is not possible to write a single shader (without {{code|#defines}}) which can be consumed by both Vulkan and OpenGL. Their resource binding models are too dissimilar, so you will generally need to keep at least the resource definitions in different files.
  
ATI came up with their fragment shader (ATI_fragment_shader). This was also a powerful API to setup the GPU. ATI_fragment_shader_text (?) was available on Macs, if I'm not mistaken, which allowed programmers to write a shader. This was for the fragment pipe as well.
+
SPIR-V also requires a lot more explicit specification than GLSL, which often means that if you use GLSL as your initial source that gets compiled to SPIR-V, you will be required to provide similar explicit specifications as well. For example, you need to use {{code|location}} qualifiers on all inter-stage inputs and outputs.
  
NV also invented [[NV_register_combiners2]], [[NV_texture_shader]], [[NV_texture_shader2]], [[NV_texture_shader3]].
+
== C for graphics ==
 +
{{main|Cg}}
  
All gave great access to the GPUs features. All these are for setting up the fragment pipe.
+
Cg is NVIDIA's shading language. It was originally intended for OpenGL, but the ARB rejected it in favor of GLSL. It is at this point defunct (NVIDIA no longer supports it), and you should probably ignore it.
  
[[ARB_texture_env_combine]] and fellow extensions also made a appearance, but since this was to be available across GPUs, it was severely limited. All these are for setting up the fragment pipe.
+
=== Advantages ===
  
[[EXT_vertex_weighting]] was another way to setup the GPU. Finally, an extension for the vertex pipe. Never was popular.
+
The syntax is almost identical to Direct3D's HLSL. As such, Cg shaders can be ported without changes to HLSL, if one is doing cross-API development.
  
[[EXT_vertex_shader]] came along. Never was popular.
+
The Cg compiler is a library that is external to the driver. As such, the user can pre-compile shaders into their target form.
  
NV came up with [[NV_vertex_program]]. The Geforce 3 was out and people needed a way to program this VS 1.1 part.
+
=== Disadvantages ===
They also released [[NV_register_combiners2]] and [[NV_texture_shader]].
 
  
NV came up with [[NV_fragment_program]].
+
The Cg compiler is really a cross-compiler. The source code is compiled into an output based on a profile. To use Cg in OpenGL, your output profile must be something that OpenGL can accept. Therefore, Cg's disadvantages depend entirely on what profile you are using.
  
[[ARB_vertex_program]] approved by ARB on June 18, 2002
+
The GLSL profile causes the use of Cg to gain the disadvantages of GLSL, but also the advantages of it. The same goes for the ARB assembly and NVIDIA assembly profiles.
  
An official shading language for the vertex pipe for all IHVs!
+
Without precompiling, you also gain a increased compile time. First the Cg compiler must generate the output for the profile, then the GLSL or ARB assembly compiler must operate to create the actual shader.
  
This is suitable for VS 1.1 GPUs.
+
Additionally, you lose some of the flexibility of using GLSL directly. For example, you can use [[OpenGL Extensions|extensions to GLSL]], but only if you're using it directly. You can't use extensions through Cg.
  
[[ARB_fragment_program]] approved by ARB on September 18, 2002
+
Another problem, particularly when using GLSL profiles, is that the code generated may not be the best for all platforms. NVIDIA writes the profiles, after all. As such, they can optimize for things their hardware does well, but would be less optimal for other hardware. What you get out of the GLSL profile is not necessarily what you would have written yourself, though it may be close to it.
  
An official shading language for the fragment pipe for all IHVs!
+
== ARB assembly ==
  
This is suitable for PS 2.0 GPUs.
+
The ARB_vertex_program and ARB_fragment_program extensions expose a assembly-like shading language. It is not pure assembly, and implementations of it do not have to resemble the language. But it is something close.
  
ATI releases the Radeon 9700 and soon ships drivers supporting [[ARB_vertex_program|ARB_vp]] and [[ARB_fragment_program|ARB_fp]], the first IHV to support them.
+
=== Advantages ===
  
NV releases [[NV_vertex_program1_1]] and [[NV_vertex_program2]].
+
Faster compile times.
  
[[NV_vertex_program2]] is for VS 3.0
+
Intel supports these.
  
NV releases [[NV_fragment_program2]], which is for PS 3.0
+
=== Disadvantages ===
  
In 2001, 3DLabs considers the future of GL. Calling it GL 2.0, they decide on new features and a fresh API. Older parts of the API was to be removed. GLSL was part of the proposal.
+
ARB assembly predates GLSL version 1.0. As such, ARB assembly is very old. It was designed to work with hardware around the time of the Radeon 9xxx and the GeForce FX 5xxx series. This means, in Direct3D terms, that ARB assembly only provides shader model 2.0-level functionality. It has no support for many common features.
  
The proposal is not accepted.
+
Being an assembly-like language, it is more difficult to program in as your programs become more complex.
  
There was GL 1.4 at the time. GL 1.5 came out.
+
== NVIDIA assembly ==
  
During GL 1.5, GLSL becomes accepted. The first high level shading language for GL with a C like syntax.
+
NVIDIA assembly refers to a number of NVIDIA-specific extensions to the ARB assembly language. They make the language congruent with modern GL 3.x features (geometry shaders, etc).
  
ARB_shading_language_100, ARB_shader_objects, ARB_vertex_shader, ARB_fragment_shader define GLSL.
+
=== Advantages ===
  
Approved by the ARB on June 11, 2003.
+
Compilation speed similar to that of ARB assembly.
  
This is GLSL 1.00
+
=== Disadvantages ===
  
September 7, 2004. GL 2.0 spec released and GLSL 1.10 becomes core
+
NVIDIA-only.
  
In memory of fixed pipeline. May you rest in peace. I mean, pieces.
+
== Special considerations ==
  
Note: The above is not necessarily in chronological order.
+
=== Intel support ===
  
== How to know if GLSL is supported? ==
+
Intel is the sales leader in dedicated graphics hardware for PCs. This hardware is not standalone graphics boards, but low-end graphics chips integrated in Intel's motherboards.
  
If the the GL version is 2.0, then GLSL is supported.
+
Put simply, Intel's driver support is terrible (note: this is true for both Direct3D and OpenGL, though GL gets it worse). They refuse to implement GLSL on any of their D3D9 chips. They have implemented GLSL on their D3D10 parts, but even then, they only implement OpenGL version 2.0 (D3D10 is the functional equivalent of version 3.2 of OpenGL).
  
glhlib can help you with finding the version, it is open source
+
If you are interested in your shader-based programs working on older Intel hardware, the ARB assembly is your best bet, as Intel's OpenGL drivers do support that.
  
http://www.geocities.com/vmelkon/glhlibrary.html
+
[[Category:Shading Languages]]
 
 
  int values[2];  //Major and minor version
 
  glhGetIntegerv(GLH_OPENGL_VERSION, values);
 
  if(values[0] >= 2)
 
  {
 
    cout<<"yes, it is supported";
 
  }
 
 
 
and if you want the GLSL version
 
  glhGetIntegerv(GLH_GLSL_VERSION, values);
 
 
 
There is also
 
  glhGetIntegerv(GLH_GPU_SHADERMODEL, values);
 
  glhGetIntegerv(GLH_VENDOR, values);
 
  if(values[0] == VENDOR_ATI)
 
  {
 
    cout<<"this is a ATI/AMD";
 
  }
 
 
 
== Additional Info ==
 
 
 
3DLabs implemented a compiler for GLSL. After all, they were the one who invented GLSL.
 
 
 
ATI/AMD used the 3DLabs compiler to implement their own. That is one reason why if you make errors in your GLSL code, you get error messages that is identical to the 3DLabs compiler.
 
 
 
nVidia had their [[Cg]] compiler. They preferred that people write [[Cg]] shaders and thus would be available for GL and D3D.
 
 
 
nVidia later on added a GLSL compiler or should we say tokenizer to their [[Cg]] compiler thus a GLSL compiler was quickly available on nVidia and it was pretty stable.
 
 
 
The unfortunate side effect is that error messages are different from the 3DLabs compiler.
 
 
 
== Implementation ==
 
 
 
The GLSL compiler is implemented in the driver. 3DLabs has their own, ATI/AMD has their own. nVidia has their own. This was why on one of them you will find bugs but you won't find it on the other.
 
 
 
== Offline Compiler, Binary Format ==
 
 
 
This is ''currently'' not available in [[GLSL]], but is supported in [[Cg]] (well, the format isn't binary, but is rather ARB/EXT or NV assembly language shaders which load fast).
 
 
 
Some had suggested that this new addition be made available by ARB/Khronos for [[GLSL]].  That is, compile your GLSL shader and create a sort of binary blob that would work on all drivers/GPUs.
 
 
 
Advantages :
 
 
 
# A single compiler, less risks of bugs
 
# The compiler can be open source so that anyone can fix it
 
# Compiling lots of GLSL shaders (200 and more) takes a lot of time. In the order of a few seconds to 1 minute. An offline compiler would do all this heavy CPU operation. Your program can quickly load the binary blob.
 
 
 
Disadvantages :
 
 
 
# The binary blob needs to be of some generic format that the compiler in the driver itself might want to optimize for the GPU.
 
# nVidia has created [[Cg]] which can convert [[GLSL]] to ARB and NV assembly shading languages. Why not make just use this since it is available?
 
# These aren't disadvantages. Just road blocks and uncertainties as to what is the best thing to do.
 
 
 
== Intel, S3 ==
 
 
 
For Windows, Intel just refuses to implement GLSL on some of their GPUs like the GMA 900, 950 and others
 
 
 
The GL version is at GL 1.5
 
 
 
http://en.wikipedia.org/wiki/Intel_GMA
 
 
 
It is not clear if their more advanced GPUs like the X3000 has support.
 
 
 
Also, keep in mind these aren't gaming GPUs. They are ok for doing Aero effects on Windows Vista.
 
 
 
However, Intel does provide [[ARB_vertex_program]], [[ARB_fragment_program]]. These are the older interfaces which are an ASM like language.
 
 
 
What you can do is code in GLSL, then use the [[Cg]] offline compiler from nVidia to compile it to [[ARB_vertex_program]], [[ARB_fragment_program]] form.
 
 
 
On Mac, Apple implements OpenGL and it is not clear if GLSL support is hw accelerated on Intel. Need confirmation.
 
 
 
On Linux, the open source drivers implemented GLSL and it works.
 
 
 
Then there is S3. Little is known about their GL support.
 
 
 
http://en.wikipedia.org/wiki/S3_Graphics
 
 
 
We need to people to report what they support.
 

Latest revision as of 15:10, 8 September 2019

The various extensions and core revisions of the OpenGL API have led to the availability of a number of different potential shading languages that you may use. This page will deal with what they are, their pros and cons, and hardware.

Main options

While there are other possibilities, these are the three primary competitors in the OpenGL space:

  • OpenGL Shading Language (GLSL)
  • SPIR-V
  • C for Graphics (Cg)
  • ARB assembly: assembly-like languages that are accessed through a set of ARB extensions.
  • NVIDIA assembly: NVIDIA-specific extensions to the ARB assembly language.

OpenGL shading language

The OpenGL Shading Language (GLSL) is a "high-level" language. This means high-level compared to assembly, not high-level the way a language like C# is compared to C. GLSL is structurally very similar to C.

Advantages

This is the current standard, as far as OpenGL is concerned. It is one of only two shading languages (SPIR-V being the other) that is a part of the OpenGL specification.

Because of this, it is kept up-to-date with current OpenGL features. Each new version of the base standard usually means a new version number of GLSL as well.

Disadvantages

The complexity of having a full C-style language in a graphics driver causes quite a few driver bugs to show themselves, particularly in ATI compilers.

NVIDIA's GLSL compiler is really a slight modification of the Cg compiler. Because of that, some of the differences between GLSL and Cg will occasionally show their heads. Cg is more permissive syntactically than GLSL, so a GLSL program that compiles on an NVIDIA driver may not compile on an ATI driver. It can also give unusual error messages, with references to a "profile" (a concept that exists in Cg but not GLSL).

SPIR-V

SPIR-V is an intermediate shading language developed by the Khronos Group (the organization also responsible for OpenGL and other standards). Though initially developed for Vulkan and OpenCL, the ability to give OpenGL a SPIR-V shader was also added to OpenGL in 4.6.

Advantages

SPIR-V is an intermediate language, so it lacks some of the higher-level constructs that often challenge GLSL compilers. As an intermediate language, many shading languages can compile directly to it. The glslang project provides an off-line compiler tool that can convert GLSL into SPIR-V compatible with OpenGL.

SPIR-V also has a developing ecosystem around supporting it. Glslang itself even provides HLSL support (though it's not clear if HLSL-to-SPIR-V for OpenGL is effective). There are tools to perform introspection over SPIR-V shader files, to manipulate and combine them, and so forth.

Disadvantages

Though SPIR-V as a language is compatible with several backends, it is not possible to write a single shader (without #defines) which can be consumed by both Vulkan and OpenGL. Their resource binding models are too dissimilar, so you will generally need to keep at least the resource definitions in different files.

SPIR-V also requires a lot more explicit specification than GLSL, which often means that if you use GLSL as your initial source that gets compiled to SPIR-V, you will be required to provide similar explicit specifications as well. For example, you need to use location qualifiers on all inter-stage inputs and outputs.

C for graphics

Cg is NVIDIA's shading language. It was originally intended for OpenGL, but the ARB rejected it in favor of GLSL. It is at this point defunct (NVIDIA no longer supports it), and you should probably ignore it.

Advantages

The syntax is almost identical to Direct3D's HLSL. As such, Cg shaders can be ported without changes to HLSL, if one is doing cross-API development.

The Cg compiler is a library that is external to the driver. As such, the user can pre-compile shaders into their target form.

Disadvantages

The Cg compiler is really a cross-compiler. The source code is compiled into an output based on a profile. To use Cg in OpenGL, your output profile must be something that OpenGL can accept. Therefore, Cg's disadvantages depend entirely on what profile you are using.

The GLSL profile causes the use of Cg to gain the disadvantages of GLSL, but also the advantages of it. The same goes for the ARB assembly and NVIDIA assembly profiles.

Without precompiling, you also gain a increased compile time. First the Cg compiler must generate the output for the profile, then the GLSL or ARB assembly compiler must operate to create the actual shader.

Additionally, you lose some of the flexibility of using GLSL directly. For example, you can use extensions to GLSL, but only if you're using it directly. You can't use extensions through Cg.

Another problem, particularly when using GLSL profiles, is that the code generated may not be the best for all platforms. NVIDIA writes the profiles, after all. As such, they can optimize for things their hardware does well, but would be less optimal for other hardware. What you get out of the GLSL profile is not necessarily what you would have written yourself, though it may be close to it.

ARB assembly

The ARB_vertex_program and ARB_fragment_program extensions expose a assembly-like shading language. It is not pure assembly, and implementations of it do not have to resemble the language. But it is something close.

Advantages

Faster compile times.

Intel supports these.

Disadvantages

ARB assembly predates GLSL version 1.0. As such, ARB assembly is very old. It was designed to work with hardware around the time of the Radeon 9xxx and the GeForce FX 5xxx series. This means, in Direct3D terms, that ARB assembly only provides shader model 2.0-level functionality. It has no support for many common features.

Being an assembly-like language, it is more difficult to program in as your programs become more complex.

NVIDIA assembly

NVIDIA assembly refers to a number of NVIDIA-specific extensions to the ARB assembly language. They make the language congruent with modern GL 3.x features (geometry shaders, etc).

Advantages

Compilation speed similar to that of ARB assembly.

Disadvantages

NVIDIA-only.

Special considerations

Intel support

Intel is the sales leader in dedicated graphics hardware for PCs. This hardware is not standalone graphics boards, but low-end graphics chips integrated in Intel's motherboards.

Put simply, Intel's driver support is terrible (note: this is true for both Direct3D and OpenGL, though GL gets it worse). They refuse to implement GLSL on any of their D3D9 chips. They have implemented GLSL on their D3D10 parts, but even then, they only implement OpenGL version 2.0 (D3D10 is the functional equivalent of version 3.2 of OpenGL).

If you are interested in your shader-based programs working on older Intel hardware, the ARB assembly is your best bet, as Intel's OpenGL drivers do support that.