Handmade Hero » Forums » Code » OpenGL Runtime Recompile Of Shaders
Mebourne
Scott Hunt
27 posts

Father, Thinker, Mechanical Engineer @NASA, and C/C++ Hobby Enthusiast / @TexxStudio

#10757 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago

Good evening, running into a bit of a snag the last few hours in attempting to setup an OpenGL shader live recompile for the first time. The code so far successfully recognizes a newer FILETIME on any previous compiled shader source files and recompiles. The problem when it re-compiles is that the OpenGL context just seems to shut down. The code is still running, but the swap buffer doesn't display anything different and I lose all key and mouse input to the window.

Debugging, I've checked that the recompile itself works with no errors passed through OpenGL and the same OpenGL program Id persists so that it continues carrying on to the Render Commands.

Any thoughts on what to look for next would be greatly appreciated.

Some related code is below.

Thanks in advance for any thoughts, ideas, help.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
for(uint32 ShaderId = 0;
          ShaderId < GActiveShaderCount;
          ++ShaderId)
      {
          FActiveShader Shader = GActiveShaders[ShaderId];
          FILETIME VertexWriteTime = Win32GetLastWriteTime(Shader.VertexFilename);
          FILETIME FragmentWriteTime = Win32GetLastWriteTime(Shader.FragmentFilename);
                    
          bool32 VertexDirty = CompareFileTime(&VertexWriteTime, &Shader.VertexLastWriteTime);
          bool32 FragmentDirty = CompareFileTime(&FragmentWriteTime, &Shader.FragmentLastWriteTime);
          if(VertexDirty || FragmentDirty)
          {
               RecompileShader(&Shader, ShaderId, VertexWriteTime, FragmentWriteTime);
          }
      }


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
InternalFunc void RecompileShader(FActiveShader* Shader, uint32 ShaderId, FILETIME VertexWrite, FILETIME FragmentWrite)
{
    char* VertexShaderSource = (char*)DEBUGPlatformReadEntireFile(Shader->VertexFilename).Contents;
    char* FragmentShaderSource = (char*)DEBUGPlatformReadEntireFile(Shader->FragmentFilename).Contents;
    
    uint32 VertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(VertexShader, 1, &VertexShaderSource, 0);
    glCompileShader(VertexShader);
    int32 Success;
    uint8 InfoLog[1024];
    glGetShaderiv(VertexShader, GL_COMPILE_STATUS, &Success);
    if(!Success)
    {
        glGetShaderInfoLog(VertexShader, 1024, NULL, InfoLog);
        printf("Compile Error");
    }
    
    uint32 FragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(FragmentShader, 1, &FragmentShaderSource, NULL);
    glCompileShader(FragmentShader);
    glGetShaderiv(FragmentShader, GL_COMPILE_STATUS, &Success);
    if(!Success)
    {
        glGetShaderInfoLog(FragmentShader, 1024, NULL, InfoLog);
        printf("Compile Error");
    }
    
    glAttachShader(Shader->ShaderId, VertexShader);
    glAttachShader(Shader->ShaderId, FragmentShader);
    glLinkProgram(Shader->ShaderId);
    glDeleteShader(VertexShader);
    glDeleteShader(FragmentShader);
    
    GActiveShaders[ShaderId].VertexLastWriteTime = Win32GetLastWriteTime(Shader->VertexFilename);
    GActiveShaders[ShaderId].FragmentLastWriteTime = Win32GetLastWriteTime(Shader->FragmentFilename);
}


None
mmozeiko
Mārtiņš Možeiko
1349 posts
1 project
#10759 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago Edited by Mārtiņš Možeiko on Feb. 6, 2017, 7:02 a.m.

Please check GL_LINK_STATUS (and glGetProgramInfoLog if its GL_FALSE) after linking program. Similar to how you check GL_COMPILE_STATUS after compiling shaders.

My guess would be on one these situations:

1) you are not creating new program - you are reusing previous Shader->ShaderId program, which is already linked, and are attaching new shader objects. I don't remember if this is allowed (need to lookup this in specs), but it may be valid operation.

2) if nr1 is allowed, then it may be because you are attaching new shader objects to existing program, but you are not detaching previous objects. So when glLinkProgram is called the program will contain two entry points for fragment shader and two for vertex shader, which probably is an error. Check GL_LINK_STATUS!

3) something else, like not querying new locations of uniforms, or new attribute locations. Which is not visible in this code fragment.

And please, please use glGetError after EVERY call to OpenGL function. I'm not joking or exaggerating. Stick it everywhere. Or use GL_ARB_debug_output extension. It will make catching mistakes with GL so much easier and faster. Trust me, it will. Here's how you use both of them: https://git.handmade.network/snippets/17
Mebourne
Scott Hunt
27 posts

Father, Thinker, Mechanical Engineer @NASA, and C/C++ Hobby Enthusiast / @TexxStudio

#10763 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago Edited by Scott Hunt on Feb. 6, 2017, 7:33 a.m.

EDIT: Also reviewed the snippet you posted, I'll will definitely be taking your advice on logging all GL calls.

Martins, thank you! I completely missed the GL_LINK_STATUS call and that was indeed the issue. I didn't realize you couldn't re-link to an existing Shader program and I wasn't catching this error as you pointed out.

I've abstracted a bit down one layer now with an enum list of ShaderTypes, ie ShaderTypeTerrain, ShaderTypeStaticModel, etc. This maps to a OpenGL program Id that now gets updated after deleting the OpenGL program and recreating a new ProgramId on recompile. The RenderCommands don't store the Program Id any longer they store the ShaderType. Working as intended, phew.

Thanks again for the help and very quick follow-up.

Regards,
Scott

None
CaptainKraft
Jeremiah
140 posts
2 projects

Father, husband, C programmer, and Linux apologist. Think before you code.

#10779 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago

How is it that Martins seems to know *everything*

Build a man a fire, he'll be warm for a day.
Set a man on fire, he'll be warm for the rest of his life.
mmozeiko
Mārtiņš Možeiko
1349 posts
1 project
#10782 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago

Hah. I don't really know everything. I'm just really good with figuring out technical stuff. Especially if there is a code (or math). Simplified view on how I do it is - you just go line by line and pretend to be CPU. Simulate execution and enumerate as much as possible edge cases that can happen. With time your intuition gets good and you start finding errors really fast and easy.
abnercoimbre
Abner Coimbre
191 posts
2 projects

Community Builder

#10785 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago

mmozeiko:
Simplified view on how I do it is - you just go line by line and pretend to be CPU.

This is so handmade I can't even...

Programmer for a certain space agency
CaptainKraft
Jeremiah
140 posts
2 projects

Father, husband, C programmer, and Linux apologist. Think before you code.

#10792 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago

abnercoimbre:
mmozeiko:
Simplified view on how I do it is - you just go line by line and pretend to be CPU.

This is so handmade I can't even...


Where's the upvote button?

Build a man a fire, he'll be warm for a day.
Set a man on fire, he'll be warm for the rest of his life.
Jesse
34 posts
#10799 OpenGL Runtime Recompile Of Shaders
4 months, 2 weeks ago

abnercoimbre:
mmozeiko:
Simplified view on how I do it is - you just go line by line and pretend to be CPU.

This is so handmade I can't even...


Become One with the CPU. Oooooooommmmm.