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 }