Keith Becker
Keith Becker

Reputation: 566

In graphics applications, why do shaders get loaded into the application on runtime?

Shaders written in for example GLSL are typically loaded into a graphics application at runtime. I am wondering why not just compile the application with the shaders so they will not have to be loaded later. Like this:

#define glsl(version, glsl) "#version " #version "\n" #glsl

namespace glsl { namespace vs {
//VERTEX SHADERS
//=========================
// simple VS
//=========================
constexpr GLchar * const simple = glsl(450 core, 
    layout(location = 0) in vec3 position;

    void main() {
        gl_Position = vec4(position, 1.0f);
    }
    );

} namespace fs {
//FRAGMENT SHADERS
//=========================
// simple FS
//=========================
constexpr GLchar * const simple = glsl(450 core,
    out vec4 color;

    void main() {
        color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
    }       
    );

} }

I don't think this would result in too large of an exe file and it would speed up loading times; unless I'm mistaken about how many shaders are used for a typical graphics application. I realize you may want to update shaders after compile time, but does that really happen?

Is there any reason that I should not want to do this?

Upvotes: 7

Views: 2230

Answers (3)

datenwolf
datenwolf

Reputation: 162164

How do you figure it would speed up load times? It doesn't!

It doesn't matter if you read data from a regular file that you opened with fopen (or std::ifstream or CreateFile or whatever) and read from that, or if you're accessing some part of the process image. Heck, in most cases accessing some large-ish hunk of pages in the process image may perform worse, because most OSs are lazily populating pages in the segments that hold nonexecutable, readonly data; mmaped read access on unpopulated pages is actually slower than just a plain read, because it involves faulting the page table and a subsequent I/O read to populate the page with data.

Mandatory read: http://lkml.iu.edu/hypermail/linux/kernel/0004.0/0728.html

The OpenGL API specifices GLSL source code being the only way to actually load shaders. There's a caching API (glShaderBinary, glProgramBinary) but the binaries loaded through that are in an unspecified format, that may change at any time, and it's a valid error condition that the driver rejects a binary for whatever reason to enforce loading the original GLSL source. To actually obtain such a shader binary you first load a regular GLSL shader source, compile it and then retrieve a binary blob from OpenGL.

Upvotes: 1

mattnewport
mattnewport

Reputation: 14057

A few reasons:

  • During development it's very convenient to 'hotload' shaders without restarting the application so you can make changes while debugging or performance tuning and instantly see the results. This is simpler when shaders are stored as separate files.
  • As mentioned in the comments, depending on your platform it is common to precompile shaders from a high level shading language to an intermediate byte code representation or to actual final GPU code (e.g. in the case of consoles where the GPU hardware is a fixed target). Shader compilation can be quite time consuming so it is better to do it offline rather than at runtime when possible.
  • The approach you take is actually not uncommon in small / simple applications, it becomes more painful the bigger your app gets and the more shaders you have to manage. Personally I like to be able to hotload shaders even on small personal projects.
  • This is actually a more general question than just for shaders. In any project you have a choice of when to embed resources in the executable (either directly in source code or through a separate build step like Windows Resources) or store them as separate files. There are pros and cons to both approaches but the main advantage of embedding is that all the resources an app might need are embedded right in the executable so you don't have to worry about / deal with potentially missing resources. The downside is that if you cram everything into the executable (especially for a project with many large assets like a game) then you increase build times, make hotloading difficult and can make the problem of asset organization more difficult.

Upvotes: 5

Omar Martinez
Omar Martinez

Reputation: 708

The shader compilation process is part of OpenGL's glsl compiler, while you can hardcore the shaders into memory as a string, it would require recompilation everytime you make ANY edit to the shaders.

In game programming you generally do not want to recompile the whole project when you are making small tweaks to hundreds of parts of the code, shaders, libraries, etc. This is one of the main reasons why all large game engines have scripting engines, it is often better to write extra boilerplate code to integrate scripting into your engine than have to compile a program 10 times just to get the color/shininess/position of your object just right. Try hardcoding all your shaders so they compile at runtime in memory and you'll see just how tedious it becomes after a day!

Upvotes: 0

Related Questions