1 module gfx.gl3.error;
2 
3 import gfx.bindings.opengl.gl : Gl;
4 import gfx.graal.pipeline : ShaderStage;
5 import gfx.graal.error : GfxException;
6 
7 string prependLineNumbers(string code) {
8     import std..string : splitLines, strip, KeepTerminator;
9     import std.format : format;
10     import std.algorithm : joiner, map;
11     import std.conv : to;
12     import std.math : log10;
13 
14     auto lines = code.splitLines(KeepTerminator.yes);
15     immutable width = 1 + cast(int)log10(lines.length);
16     string res;
17     foreach(i, l; lines) {
18         res ~= format("%*s. %s", width, i+1, l);
19     }
20     return res;
21 }
22 
23 unittest {
24     string code =
25         "#version 120\n" ~
26         "\n" ~
27         "attribute vec2 a_Pos;\n" ~
28         "attribute vec3 a_Color;\n" ~
29         "varying vec4 v_Color;\n" ~
30         "\n" ~
31         "void main() {\n" ~
32         "    v_Color = vec4(a_Color, 1.0);\n" ~
33         "    gl_Position = vec4(a_Pos, 0.0, 1.0);\n" ~
34         "}";
35 
36     string expected =
37         " 1. #version 120\n" ~
38         " 2. \n" ~
39         " 3. attribute vec2 a_Pos;\n" ~
40         " 4. attribute vec3 a_Color;\n" ~
41         " 5. varying vec4 v_Color;\n" ~
42         " 6. \n" ~
43         " 7. void main() {\n" ~
44         " 8.     v_Color = vec4(a_Color, 1.0);\n" ~
45         " 9.     gl_Position = vec4(a_Pos, 0.0, 1.0);\n" ~
46         "10. }";
47 
48     assert(prependLineNumbers(code) == expected);
49 }
50 
51 
52 class Gl3ShaderCompileException : GfxException {
53     ShaderStage stage;
54     string code;
55     string errorMsg;
56 
57     this(ShaderStage stage, string code, string errorMsg) {
58         import std.format : format;
59         import std.conv : to;
60         super(format("%s shader compilation error", stage.to!string),
61                 format("\n%s\nshader code:\n%s\n", errorMsg, prependLineNumbers(code)));
62 
63         this.stage = stage;
64         this.code = code;
65         this.errorMsg = errorMsg;
66     }
67 }
68 
69 class Gl3ProgramLinkException : Exception {
70     string errorMsg;
71 
72     this(string errorMsg) {
73         import std.format : format;
74         super(format("Shading program link error"), errorMsg);
75 
76         this.errorMsg = errorMsg;
77     }
78 }
79 
80 void glCheck(Gl gl, in string operation)
81 {
82     import gfx.bindings.opengl.gl : GL_NO_ERROR, GL_INVALID_ENUM,
83                                     GL_INVALID_VALUE, GL_INVALID_OPERATION,
84                                     GL_STACK_OVERFLOW, GL_STACK_UNDERFLOW,
85                                     GL_OUT_OF_MEMORY,
86                                     GL_INVALID_FRAMEBUFFER_OPERATION,
87                                     GL_CONTEXT_LOST;
88     const code = gl.GetError();
89     if (code != GL_NO_ERROR) {
90         string glErr;
91         switch (code) {
92         case GL_INVALID_ENUM:
93             glErr = "GL_INVALID_ENUM";
94             break;
95         case GL_INVALID_VALUE:
96             glErr = "GL_INVALID_VALUE";
97             break;
98         case GL_INVALID_OPERATION:
99             glErr = "GL_INVALID_OPERATION";
100             break;
101         case GL_STACK_OVERFLOW:
102             glErr = "GL_STACK_OVERFLOW";
103             break;
104         case GL_STACK_UNDERFLOW:
105             glErr = "GL_STACK_UNDERFLOW";
106             break;
107         case GL_OUT_OF_MEMORY:
108             glErr = "GL_OUT_OF_MEMORY";
109             break;
110         case GL_INVALID_FRAMEBUFFER_OPERATION:
111             glErr = "GL_INVALID_FRAMEBUFFER_OPERATION";
112             break;
113         case GL_CONTEXT_LOST:
114             glErr = "GL_CONTEXT_LOST";
115             break;
116         default:
117             glErr = "(unknown error)";
118             break;
119         }
120 
121         import gfx.gl3 : gfxGlLog;
122 
123         gfxGlLog.errorf("OpenGL error %s during %s", glErr, operation);
124     }
125 }