shaders.cc (7123B)
1 /* Copyright 2013 Brian Swetland <swetland@frotz.net> 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include <stdio.h> 17 #include <stdlib.h> 18 19 #include "app.h" 20 #include "util.h" 21 #include "matrix.h" 22 23 #define INCLUDE_SHADER_GLOBALS 1 24 #include "shared.h" 25 26 #define ENABLE_SHADER_CACHE 0 27 28 static void dump_compile_error(unsigned id) { 29 int len; 30 char *buf; 31 glGetShaderiv(id, GL_INFO_LOG_LENGTH, &len); 32 buf = (char*) malloc(len + 1); 33 if (buf != 0) { 34 memset(buf, 0, len); 35 glGetShaderInfoLog(id, len, &len, buf); 36 buf[len] = 0; 37 printx("-- shader compiler error --\n%s\n", buf); 38 free(buf); 39 } 40 } 41 42 static void dump_link_error(unsigned id) { 43 int len; 44 char *buf; 45 glGetProgramiv(id, GL_INFO_LOG_LENGTH, &len); 46 buf = (char*) malloc(len + 1); 47 if (buf != 0) { 48 memset(buf, 0, len); 49 glGetProgramInfoLog(id, len, &len, buf); 50 buf[len] = 0; 51 printx("-- shader link error --\n%s\n", buf); 52 free(buf); 53 } 54 } 55 56 int Program::link(VertexShader *vs, PixelShader *ps) { 57 return link(vs, NULL, ps); 58 } 59 60 static const char *_blocknames[] = { 61 "block0", "block1", "block2", "block3", 62 }; 63 static const char *_samplernames[] = { 64 "sampler0", "sampler1", "sampler2", "sampler3", 65 }; 66 67 int Program::link(VertexShader *vs, GeometryShader *gs, PixelShader *ps) { 68 unsigned n; 69 int r; 70 n = glCreateProgram(); 71 glAttachShader(n, vs->id); 72 if (gs) 73 glAttachShader(n, gs->id); 74 glAttachShader(n, ps->id); 75 glLinkProgram(n); 76 glGetProgramiv(n, GL_LINK_STATUS, &r); 77 if (!r) { 78 dump_link_error(n); 79 glDeleteProgram(n); 80 return error("shader program link error"); 81 } 82 if (id) 83 glDeleteProgram(id); 84 id = n; 85 86 /* bind uniform block indices to bindpoints based on their name */ 87 for (n = 0; n < sizeof(_blocknames) / sizeof(_blocknames[0]); n++) { 88 unsigned idx = glGetUniformBlockIndex(id, _blocknames[n]); 89 if (idx != GL_INVALID_INDEX) { 90 printx("found %s @ %d\n", _blocknames[n], idx); 91 glUniformBlockBinding(id, idx, n); 92 } 93 } 94 95 return 0; 96 } 97 98 /* defer final link steps until the first time glUseProgram() is called, */ 99 void Program::bind() { 100 unsigned n; 101 int r; 102 for (n = 0; n < sizeof(_samplernames) / sizeof(_samplernames[0]); n++) { 103 r = glGetUniformLocation(id, _samplernames[n]); 104 if (r != -1) { 105 printx("found %s @ %d\n", _samplernames[n], r); 106 glUniform1i(r, n); 107 } 108 } 109 bound = 1; 110 } 111 112 int Program::load(const char *vsfn, const char *gsfn, const char *psfn) { 113 VertexShader vs; 114 GeometryShader gs; 115 PixelShader ps; 116 if (vs.load(vsfn)) 117 return -1; 118 if (gs.load(gsfn)) 119 return -1; 120 if (ps.load(psfn)) 121 return -1; 122 return link(&vs, &gs, &ps); 123 } 124 125 int Program::load(const char *vsfn, const char *psfn) { 126 VertexShader vs; 127 PixelShader ps; 128 if (vs.load(vsfn)) 129 return -1; 130 if (ps.load(psfn)) 131 return -1; 132 return link(&vs, &ps); 133 } 134 135 struct section { 136 section *next; 137 unsigned lineno; 138 const char *name; 139 const char *str; 140 unsigned len; 141 }; 142 143 struct source { 144 source *next; 145 const char *name; 146 section *sections; 147 section common; 148 const char *str; 149 unsigned len; 150 }; 151 152 #if ENABLE_SHADER_CACHE 153 static source *source_cache = NULL; 154 #endif 155 156 static struct source *load_shader_source(const char *fn) { 157 source *src; 158 section *part; 159 unsigned lineno = 1; 160 unsigned len; 161 char *x, *end, *tmp; 162 char buf[1024]; 163 164 x = (char*) strchr(fn, '.'); 165 if (x) { 166 memcpy(buf, fn, x-fn); 167 strcpy(buf + (x - fn), ".glsl"); 168 } else { 169 sprintf(buf, "%s.glsl", fn); 170 } 171 172 #if ENABLE_SHADER_CACHE 173 for (src = source_cache; src; src = src->next) 174 if (!strcmp(buf, src->name)) 175 return src; 176 #endif 177 178 src = new source; 179 src->sections = NULL; 180 part = &src->common; 181 part->name = "$common$"; 182 183 x = (char*) load_file(buf, &len); 184 if (!x) { 185 delete src; 186 return NULL; 187 } 188 src->str = x; 189 src->len = len; 190 191 part->str = x; 192 part->lineno = lineno; 193 194 end = x + len; 195 while (x < end) { 196 if (*x++ != '\n') 197 continue; 198 lineno++; 199 if ((end - x) < 3) 200 continue; 201 if ((x[0] != '-') || (x[1] != '-')) 202 continue; 203 part->len = x - part->str; 204 part->next = src->sections; 205 src->sections = part; 206 *x = 0; 207 x += 2; 208 209 part = new section; 210 part->next = NULL; 211 part->name = ""; 212 213 tmp = x; 214 while (x < end) { 215 if (*x == '\n') { 216 *x = 0; 217 while ((tmp < x) && (*tmp <= ' ')) 218 tmp++; 219 part->name = tmp; 220 while (tmp < x) { 221 if (*tmp <= ' ') 222 *tmp = 0; 223 tmp++; 224 } 225 x++; 226 break; 227 } 228 x++; 229 } 230 231 lineno++; 232 part->str = x; 233 part->lineno = lineno; 234 } 235 236 part->len = x - part->str; 237 part->next = src->sections; 238 src->sections = part; 239 240 #if 0 241 printx("[ source '%s' %d lines ]\n", buf, lineno); 242 for (part = src->sections; part; part = part->next) 243 printx(" [ section '%s' %d bytes @ %d]\n", 244 part->name, part->len, part->lineno); 245 #endif 246 247 src->name = strdup(buf); 248 249 #if ENABLE_SHADER_CACHE 250 src->next = source_cache; 251 source_cache = src; 252 #endif 253 return src; 254 } 255 256 static int compile_shader_source(source *src, const char *name, const char *defines, unsigned id) { 257 char misc[128]; 258 const char *data[5]; 259 int size[5]; 260 section *part; 261 262 for (part = src->sections; part; part = part->next) { 263 if (!strcmp(name, part->name)) { 264 printx("Loaded shader section '%s' from '%s'\n", 265 part->name, src->name); 266 sprintf(misc, "#line %d\n", part->lineno - 1); 267 data[0] = src->common.str; 268 size[0] = src->common.len; 269 data[1] = shader_globals; 270 size[1] = strlen(shader_globals); 271 data[2] = defines; 272 size[2] = strlen(defines); 273 data[3] = misc; 274 size[3] = strlen(misc); 275 data[4] = part->str; 276 size[4] = part->len; 277 glShaderSource(id, 5, data, size); 278 return 0; 279 } 280 } 281 return error("cannot find section '%s'", name); 282 } 283 284 static int _load_shader(unsigned *out, const char *fn, const char *defines, unsigned type) { 285 unsigned id; 286 source *src; 287 const char *x; 288 int r; 289 290 x = strchr(fn, '.'); 291 if (x == 0) 292 return error("shader source '%s' has no section", fn); 293 x++; 294 295 src = load_shader_source(fn); 296 if (src == NULL) 297 return error("cannot load shader source '%s'", fn); 298 299 id = glCreateShader(type); 300 if (compile_shader_source(src, x, defines, id)) { 301 glDeleteShader(id); 302 return -1; 303 } 304 glCompileShader(id); 305 glGetShaderiv(id, GL_COMPILE_STATUS, &r); 306 if (!r) { 307 dump_compile_error(id); 308 glDeleteShader(id); 309 return error("shader '%s' compile error", fn); 310 } 311 if (*out) 312 glDeleteShader(*out); 313 *out = id; 314 return 0; 315 } 316 317 int VertexShader::load(const char *fn, const char *defines) { 318 return _load_shader(&id, fn, defines, GL_VERTEX_SHADER); 319 } 320 321 int PixelShader::load(const char *fn, const char *defines) { 322 return _load_shader(&id, fn, defines, GL_FRAGMENT_SHADER); 323 } 324 325 int GeometryShader::load(const char *fn, const char *defines) { 326 return _load_shader(&id, fn, defines, GL_GEOMETRY_SHADER); 327 } 328