/
mojoshader_opengl.c
1490 lines (1236 loc) · 48.8 KB
1
2
3
4
5
6
7
8
9
/**
* MojoShader; generate shader programs from bytecode of compiled
* Direct3D shaders.
*
* Please see the file LICENSE.txt in the source's root directory.
*
* This file written by Ryan C. Gordon.
*/
10
11
12
13
14
15
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>
16
17
18
19
20
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h> // GL headers need this for WINGDIAPI definition.
#endif
21
#include "mojoshader.h"
22
#define GL_GLEXT_LEGACY 1
23
24
#include "GL/gl.h"
#include "GL/glext.h"
25
26
27
28
// Get basic wankery out of the way here...
typedef unsigned int uint; // this is a printf() helper. don't use for code.
29
30
31
32
33
34
#ifdef _MSC_VER
#define snprintf _snprintf
typedef unsigned __int8 uint8;
typedef unsigned __int32 uint32;
typedef unsigned __int32 int32;
35
36
37
// Warning Level 4 considered harmful. :)
#pragma warning(disable: 4100) // "unreferenced formal parameter"
#pragma warning(disable: 4389) // "signed/unsigned mismatch"
38
39
#else
#include <stdint.h>
40
41
42
typedef uint8_t uint8;
typedef uint32_t uint32;
typedef int32_t int32;
43
44
45
#endif
#define STATICARRAYLEN(x) ( (sizeof ((x))) / (sizeof ((x)[0])) )
46
47
48
49
50
#ifndef SUPPORT_PROFILE_GLSL
#define SUPPORT_PROFILE_GLSL 1
#endif
51
52
53
54
#ifndef SUPPORT_PROFILE_ARB1
#define SUPPORT_PROFILE_ARB1 1
#endif
55
56
57
58
59
60
61
62
63
64
#ifndef SUPPORT_PROFILE_NV2
#define SUPPORT_PROFILE_NV2 1
#endif
#if SUPPORT_PROFILE_NV2 && !SUPPORT_PROFILE_ARB1
#error nv2 profile requires arb1 profile.
#endif
65
66
67
struct MOJOSHADER_glShader
{
const MOJOSHADER_parseData *parseData;
68
GLuint handle;
69
70
71
uint32 refcount;
};
72
73
typedef struct
{
74
MOJOSHADER_shaderType shader_type;
75
const MOJOSHADER_uniform *uniform;
76
GLuint location;
77
78
} UniformMap;
79
80
81
82
83
84
85
typedef struct
{
MOJOSHADER_shaderType shader_type;
const MOJOSHADER_sampler *sampler;
GLuint location;
} SamplerMap;
86
87
typedef struct
{
88
const MOJOSHADER_attribute *attribute;
89
GLuint location;
90
91
} AttributeMap;
92
93
struct MOJOSHADER_glProgram
{
94
95
MOJOSHADER_glShader *vertex;
MOJOSHADER_glShader *fragment;
96
GLuint handle;
97
98
uint32 constant_count; // !!! FIXME: misnamed.
GLfloat *constants; // !!! FIXME: misnamed.
99
uint32 uniform_count;
100
UniformMap *uniforms;
101
102
uint32 sampler_count;
SamplerMap *samplers;
103
uint32 attribute_count;
104
AttributeMap *attributes;
105
106
107
uint32 refcount;
};
108
109
110
111
#ifndef WINGDIAPI
#define WINGDIAPI
#endif
112
// Entry points in base OpenGL that lack function pointer prototypes...
113
114
typedef WINGDIAPI void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params);
typedef WINGDIAPI const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
115
typedef WINGDIAPI GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
116
117
typedef WINGDIAPI void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
typedef WINGDIAPI void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
118
119
120
121
122
123
124
125
126
127
struct MOJOSHADER_glContext
{
// Allocators...
MOJOSHADER_malloc malloc_fn;
MOJOSHADER_free free_fn;
void *malloc_data;
// The constant register files...
// Man, it kills me how much memory this takes...
128
129
130
131
132
133
GLfloat vs_reg_file_f[8192 * 4];
GLint vs_reg_file_i[2047 * 4];
GLint vs_reg_file_b[2047];
GLfloat ps_reg_file_f[8192 * 4];
GLint ps_reg_file_i[2047 * 4];
GLint ps_reg_file_b[2047];
134
GLuint sampler_reg_file[16];
135
136
137
138
139
// GL stuff...
int opengl_major;
int opengl_minor;
MOJOSHADER_glProgram *bound_program;
140
char profile[16];
141
142
// Extensions...
143
144
145
146
147
148
149
150
151
152
int have_base_opengl:1;
int have_GL_ARB_vertex_program:1;
int have_GL_ARB_fragment_program:1;
int have_GL_NV_vertex_program2_option:1;
int have_GL_NV_fragment_program2:1;
int have_GL_ARB_shader_objects:1;
int have_GL_ARB_vertex_shader:1;
int have_GL_ARB_fragment_shader:1;
int have_GL_ARB_shading_language_100:1;
int have_GL_NV_half_float:1;
153
154
155
// Entry points...
PFNGLGETSTRINGPROC glGetString;
156
PFNGLGETERRORPROC glGetError;
157
PFNGLGETINTEGERVPROC glGetIntegerv;
158
159
PFNGLENABLEPROC glEnable;
PFNGLDISABLEPROC glDisable;
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
PFNGLDELETEOBJECTARBPROC glDeleteObject;
PFNGLATTACHOBJECTARBPROC glAttachObject;
PFNGLCOMPILESHADERARBPROC glCompileShader;
PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObject;
PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObject;
PFNGLDISABLEVERTEXATTRIBARRAYARBPROC glDisableVertexAttribArray;
PFNGLENABLEVERTEXATTRIBARRAYARBPROC glEnableVertexAttribArray;
PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocation;
PFNGLGETINFOLOGARBPROC glGetInfoLog;
PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameteriv;
PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocation;
PFNGLLINKPROGRAMARBPROC glLinkProgram;
PFNGLSHADERSOURCEARBPROC glShaderSource;
PFNGLUNIFORM1IARBPROC glUniform1i;
PFNGLUNIFORM4FVARBPROC glUniform4fv;
PFNGLUNIFORM4IVARBPROC glUniform4iv;
PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObject;
PFNGLVERTEXATTRIBPOINTERARBPROC glVertexAttribPointer;
178
179
180
181
182
183
184
PFNGLGETPROGRAMIVARBPROC glGetProgramivARB;
PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB;
PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB;
PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB;
PFNGLGENPROGRAMSARBPROC glGenProgramsARB;
PFNGLBINDPROGRAMARBPROC glBindProgramARB;
PFNGLPROGRAMSTRINGARBPROC glProgramStringARB;
185
186
187
// interface for profile-specific things.
int (*profileMaxUniforms)(MOJOSHADER_shaderType shader_type);
188
int (*profileCompileShader)(const MOJOSHADER_parseData *pd, GLuint *s);
189
190
void (*profileDeleteShader)(const GLuint shader);
void (*profileDeleteProgram)(const GLuint program);
191
192
193
GLint (*profileGetAttribLocation)(MOJOSHADER_glProgram *program, int idx);
GLint (*profileGetUniformLocation)(MOJOSHADER_glProgram *, MOJOSHADER_glShader *, int);
GLint (*profileGetSamplerLocation)(MOJOSHADER_glProgram *, MOJOSHADER_glShader *, int);
194
195
GLuint (*profileLinkProgram)(MOJOSHADER_glShader *, MOJOSHADER_glShader *);
void (*profileUseProgramObject)(MOJOSHADER_glProgram *program);
196
197
198
void (*profileUniform4fv)(const MOJOSHADER_parseData *, GLint, GLsizei, GLfloat *);
void (*profileUniform4iv)(const MOJOSHADER_parseData *, GLint, GLsizei, GLint *);
void (*profileUniform1i)(const MOJOSHADER_parseData *, GLint, GLint);
199
void (*profileSetSampler)(GLint loc, GLuint sampler);
200
201
};
202
203
// predeclare some profile implementation stuff...
static int impl_GLSL_MaxUniforms(MOJOSHADER_shaderType shader_type);
204
205
206
static int impl_GLSL_CompileShader(const MOJOSHADER_parseData *pd, GLuint *s);
static void impl_GLSL_DeleteShader(const GLuint shader);
static void impl_GLSL_DeleteProgram(const GLuint program);
207
208
209
static GLint impl_GLSL_GetAttribLocation(MOJOSHADER_glProgram *, int);
static GLint impl_GLSL_GetUniformLocation(MOJOSHADER_glProgram *, MOJOSHADER_glShader *, int);
static GLint impl_GLSL_GetSamplerLocation(MOJOSHADER_glProgram *, MOJOSHADER_glShader *, int);
210
211
static GLuint impl_GLSL_LinkProgram(MOJOSHADER_glShader *, MOJOSHADER_glShader *);
static void impl_GLSL_UseProgramObject(MOJOSHADER_glProgram *program);
212
213
214
static void impl_GLSL_Uniform4fv(const MOJOSHADER_parseData *pd, GLint loc, GLsizei siz, GLfloat *v);
static void impl_GLSL_Uniform4iv(const MOJOSHADER_parseData *pd, GLint loc, GLsizei siz, GLint *v);
static void impl_GLSL_Uniform1i(const MOJOSHADER_parseData *pd, GLint loc, GLint v);
215
216
static void impl_GLSL_SetSampler(GLint loc, GLuint sampler);
217
static int impl_ARB1_MaxUniforms(MOJOSHADER_shaderType shader_type);
218
219
220
static int impl_ARB1_CompileShader(const MOJOSHADER_parseData *pd, GLuint *s);
static void impl_ARB1_DeleteShader(const GLuint shader);
static void impl_ARB1_DeleteProgram(const GLuint program);
221
222
223
static GLint impl_ARB1_GetAttribLocation(MOJOSHADER_glProgram *, int);
static GLint impl_ARB1_GetUniformLocation(MOJOSHADER_glProgram *, MOJOSHADER_glShader *, int);
static GLint impl_ARB1_GetSamplerLocation(MOJOSHADER_glProgram *, MOJOSHADER_glShader *, int);
224
225
static GLuint impl_ARB1_LinkProgram(MOJOSHADER_glShader *, MOJOSHADER_glShader *);
static void impl_ARB1_UseProgramObject(MOJOSHADER_glProgram *program);
226
227
228
static void impl_ARB1_Uniform4fv(const MOJOSHADER_parseData *pd, GLint loc, GLsizei siz, GLfloat *v);
static void impl_ARB1_Uniform4iv(const MOJOSHADER_parseData *pd, GLint loc, GLsizei siz, GLint *v);
static void impl_ARB1_Uniform1i(const MOJOSHADER_parseData *pd, GLint loc, GLint v);
229
static void impl_ARB1_SetSampler(GLint loc, GLuint sampler);
230
231
232
static MOJOSHADER_glContext *ctx = NULL;
233
234
235
236
237
238
239
240
241
// Error state...
static char error_buffer[1024] = { '\0' };
static void set_error(const char *str)
{
snprintf(error_buffer, sizeof (error_buffer), "%s", str);
} // set_error
242
243
244
245
246
247
248
249
250
251
252
253
254
// #define this to force app to supply an allocator, so there's no reference
// to the C runtime's malloc() and free()...
#if MOJOSHADER_FORCE_ALLOCATOR
#define internal_malloc NULL
#define internal_free NULL
#else
static void *internal_malloc(int bytes, void *d) { return malloc(bytes); }
static void internal_free(void *ptr, void *d) { free(ptr); }
#endif
static inline void *Malloc(const size_t len)
{
255
void *retval = ctx->malloc_fn((int) len, ctx->malloc_data);
256
257
258
if (retval == NULL)
set_error("out of memory");
return retval;
259
260
261
262
} // Malloc
static inline void Free(void *ptr)
{
263
if (ptr != NULL)
264
ctx->free_fn(ptr, ctx->malloc_data);
265
266
267
} // Free
268
269
270
271
272
273
const char *MOJOSHADER_glGetError(void)
{
return error_buffer;
} // MOJOSHADER_glGetError
274
275
276
277
278
279
280
281
282
static inline void toggle_gl_state(GLenum state, int val)
{
if (val)
ctx->glEnable(state);
else
ctx->glDisable(state);
} // toggle_gl_state
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
static void *loadsym(void *(*lookup)(const char *fn), const char *fn, int *ext)
{
void *retval = NULL;
if (lookup != NULL)
{
retval = lookup(fn);
if (retval == NULL)
{
char arbfn[64];
snprintf(arbfn, sizeof (arbfn), "%sARB", fn);
retval = lookup(arbfn);
} // if
} // if
if (retval == NULL)
*ext = 0;
return retval;
} // loadsym
static void lookup_entry_points(void *(*lookup)(const char *fnname))
{
305
306
307
308
309
310
#define DO_LOOKUP(ext, typ, fn) { \
int exist = ctx->have_##ext; \
ctx->fn = (typ) loadsym(lookup, #fn, &exist); \
ctx->have_##ext = exist; \
}
311
DO_LOOKUP(base_opengl, PFNGLGETSTRINGPROC, glGetString);
312
DO_LOOKUP(base_opengl, PFNGLGETERRORPROC, glGetError);
313
DO_LOOKUP(base_opengl, PFNGLGETINTEGERVPROC, glGetIntegerv);
314
315
DO_LOOKUP(base_opengl, PFNGLENABLEPROC, glEnable);
DO_LOOKUP(base_opengl, PFNGLDISABLEPROC, glDisable);
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
DO_LOOKUP(GL_ARB_shader_objects, PFNGLDELETEOBJECTARBPROC, glDeleteObject);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLATTACHOBJECTARBPROC, glAttachObject);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLCOMPILESHADERARBPROC, glCompileShader);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLCREATEPROGRAMOBJECTARBPROC, glCreateProgramObject);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLCREATESHADEROBJECTARBPROC, glCreateShaderObject);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLGETINFOLOGARBPROC, glGetInfoLog);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLGETOBJECTPARAMETERIVARBPROC, glGetObjectParameteriv);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLGETUNIFORMLOCATIONARBPROC, glGetUniformLocation);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLLINKPROGRAMARBPROC, glLinkProgram);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLSHADERSOURCEARBPROC, glShaderSource);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLUNIFORM1IARBPROC, glUniform1i);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLUNIFORM4FVARBPROC, glUniform4fv);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLUNIFORM4IVARBPROC, glUniform4iv);
DO_LOOKUP(GL_ARB_shader_objects, PFNGLUSEPROGRAMOBJECTARBPROC, glUseProgramObject);
DO_LOOKUP(GL_ARB_vertex_shader, PFNGLDISABLEVERTEXATTRIBARRAYARBPROC, glDisableVertexAttribArray);
DO_LOOKUP(GL_ARB_vertex_shader, PFNGLENABLEVERTEXATTRIBARRAYARBPROC, glEnableVertexAttribArray);
DO_LOOKUP(GL_ARB_vertex_shader, PFNGLGETATTRIBLOCATIONARBPROC, glGetAttribLocation);
DO_LOOKUP(GL_ARB_vertex_shader, PFNGLVERTEXATTRIBPOINTERARBPROC, glVertexAttribPointer);
334
335
336
337
338
339
340
341
342
343
DO_LOOKUP(GL_ARB_vertex_program, PFNGLUSEPROGRAMOBJECTARBPROC, glUseProgramObject);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLVERTEXATTRIBPOINTERARBPROC, glVertexAttribPointer);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLGETPROGRAMIVARBPROC, glGetProgramivARB);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLGETPROGRAMSTRINGARBPROC, glGetProgramStringARB);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLPROGRAMENVPARAMETER4FVARBPROC, glProgramEnvParameter4fvARB);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLDELETEPROGRAMSARBPROC, glDeleteProgramsARB);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLGENPROGRAMSARBPROC, glGenProgramsARB);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLBINDPROGRAMARBPROC, glBindProgramARB);
DO_LOOKUP(GL_ARB_vertex_program, PFNGLPROGRAMSTRINGARBPROC, glProgramStringARB);
344
345
346
347
348
349
350
351
352
353
#undef DO_LOOKUP
} // lookup_entry_points
static int verify_extension(const char *ext, int have, const char *extlist,
int major, int minor)
{
if (have == 0)
return 0; // don't bother checking, we're missing an entry point.
354
355
356
else if (!ctx->have_base_opengl)
return 0; // don't bother checking, we're missing basic functionality.
357
// See if it's in the spec for this GL implementation's version.
358
359
if (major >= 0)
{
360
if ( ((ctx->opengl_major << 16) | (ctx->opengl_minor & 0xFFFF)) >=
361
362
363
((major << 16) | (minor & 0xFFFF)) )
return 1;
} // if
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
// Not available in the GL version, check the extension list.
const char *ptr = strstr(extlist, ext);
if (ptr == NULL)
return 0;
const char endchar = ptr[strlen(ext)];
if ((endchar == '\0') || (endchar == ' '))
return 1; // extension is in the list.
return 0; // just not supported, fail.
} // verify_extension
static void parse_opengl_version(const char *verstr)
{
if (verstr == NULL)
381
ctx->opengl_major = ctx->opengl_minor = 0;
382
else
383
sscanf(verstr, "%d.%d", &ctx->opengl_major, &ctx->opengl_minor);
384
385
386
} // parse_opengl_version
387
static void load_extensions(void *(*lookup)(const char *fnname))
388
{
389
390
const char *extlist = NULL;
391
ctx->have_base_opengl = 1;
392
393
ctx->have_GL_ARB_vertex_program = 1;
ctx->have_GL_ARB_fragment_program = 1;
394
395
396
397
398
ctx->have_GL_ARB_shader_objects = 1;
ctx->have_GL_ARB_vertex_shader = 1;
ctx->have_GL_ARB_fragment_shader = 1;
ctx->have_GL_ARB_shading_language_100 = 1;
ctx->have_GL_NV_half_float = 1;
399
400
401
lookup_entry_points(lookup);
402
if (!ctx->have_base_opengl)
403
set_error("missing basic OpenGL entry points");
404
405
406
407
408
else
{
parse_opengl_version((const char *) ctx->glGetString(GL_VERSION));
extlist = (const char *) ctx->glGetString(GL_EXTENSIONS);
} // else
409
410
411
412
413
if (extlist == NULL)
extlist = ""; // just in case.
#define VERIFY_EXT(ext, major, minor) \
414
ctx->have_##ext = verify_extension(#ext, ctx->have_##ext, extlist, major, minor)
415
416
417
VERIFY_EXT(GL_ARB_vertex_program, -1, -1);
VERIFY_EXT(GL_ARB_fragment_program, -1, -1);
418
419
420
421
VERIFY_EXT(GL_ARB_shader_objects, 2, 0);
VERIFY_EXT(GL_ARB_vertex_shader, 2, 0);
VERIFY_EXT(GL_ARB_fragment_shader, 2, 0);
VERIFY_EXT(GL_ARB_shading_language_100, 2, 0);
422
VERIFY_EXT(GL_NV_half_float, -1, -1);
423
424
#undef VERIFY_EXT
425
426
427
428
429
430
431
} // load_extensions
static int valid_profile(const char *profile)
{
if (!ctx->have_base_opengl)
return 0;
432
433
434
#define MUST_HAVE(p, x) \
if (!ctx->have_##x) { set_error(#p " profile needs " #x); return 0; }
435
436
437
438
439
440
if (profile == NULL)
{
set_error("NULL profile");
return 0;
} // if
441
442
443
444
445
446
447
448
449
#if SUPPORT_PROFILE_ARB1
else if (strcmp(profile, MOJOSHADER_PROFILE_ARB1) == 0)
{
MUST_HAVE(MOJOSHADER_PROFILE_ARB1, GL_ARB_vertex_program);
MUST_HAVE(MOJOSHADER_PROFILE_ARB1, GL_ARB_fragment_program);
} // else if
#endif
450
451
452
453
454
455
456
457
458
459
#if SUPPORT_PROFILE_NV2
else if (strcmp(profile, MOJOSHADER_PROFILE_NV2) == 0)
{
MUST_HAVE(MOJOSHADER_PROFILE_NV2, GL_ARB_vertex_program);
MUST_HAVE(MOJOSHADER_PROFILE_NV2, GL_ARB_fragment_program);
MUST_HAVE(MOJOSHADER_PROFILE_NV2, GL_NV_vertex_program2_option);
MUST_HAVE(MOJOSHADER_PROFILE_NV2, GL_NV_fragment_program2);
} // else if
#endif
460
461
#if SUPPORT_PROFILE_GLSL
else if (strcmp(profile, MOJOSHADER_PROFILE_GLSL) == 0)
462
{
463
464
465
466
467
468
MUST_HAVE(MOJOSHADER_PROFILE_GLSL, GL_ARB_shader_objects);
MUST_HAVE(MOJOSHADER_PROFILE_GLSL, GL_ARB_vertex_shader);
MUST_HAVE(MOJOSHADER_PROFILE_GLSL, GL_ARB_fragment_shader);
MUST_HAVE(MOJOSHADER_PROFILE_GLSL, GL_ARB_shading_language_100);
} // else if
#endif
469
470
471
else
{
472
set_error("unknown or unsupported profile");
473
474
475
return 0;
} // else
476
#undef MUST_HAVE
477
478
return 1;
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
} // valid_profile
const char *MOJOSHADER_glBestProfile(void *(*lookup)(const char *fnname))
{
const char *retval = NULL;
MOJOSHADER_glContext _ctx;
MOJOSHADER_glContext *current_ctx = ctx;
ctx = &_ctx;
memset(ctx, '\0', sizeof (MOJOSHADER_glContext));
load_extensions(lookup);
if (ctx->have_base_opengl)
{
static const char *priority[] = {
MOJOSHADER_PROFILE_GLSL,
496
MOJOSHADER_PROFILE_NV2,
497
MOJOSHADER_PROFILE_ARB1,
498
499
500
501
502
};
int i;
for (i = 0; i < STATICARRAYLEN(priority); i++)
{
503
504
// !!! FIXME: if Mac OS X <= 10.4, don't ever pick GLSL, even if
// !!! FIXME: the system claims it is available.
505
506
507
508
509
510
if (valid_profile(priority[i]))
{
retval = priority[i];
break;
} // if
} // for
511
512
513
514
if (retval == NULL)
set_error("no profiles available");
} // if
515
516
517
518
519
520
521
ctx = current_ctx;
return retval;
} // MOJOSHADER_glBestProfile
MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile,
522
523
524
void *(*lookup)(const char *fnname),
MOJOSHADER_malloc m, MOJOSHADER_free f,
void *d)
525
{
526
MOJOSHADER_glContext *retval = NULL;
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
MOJOSHADER_glContext *current_ctx = ctx;
ctx = NULL;
if (m == NULL) m = internal_malloc;
if (f == NULL) f = internal_free;
ctx = (MOJOSHADER_glContext *) m(sizeof (MOJOSHADER_glContext), d);
if (ctx == NULL)
{
set_error("out of memory");
goto init_fail;
} // if
memset(ctx, '\0', sizeof (MOJOSHADER_glContext));
ctx->malloc_fn = m;
ctx->free_fn = f;
ctx->malloc_data = d;
544
snprintf(ctx->profile, sizeof (ctx->profile), "%s", profile);
545
546
547
load_extensions(lookup);
if (!valid_profile(profile))
548
goto init_fail;
549
550
551
MOJOSHADER_glBindProgram(NULL);
552
553
554
555
556
557
558
559
560
561
// !!! FIXME: generalize this part.
if (profile == NULL) {}
#if SUPPORT_PROFILE_GLSL
else if (strcmp(profile, MOJOSHADER_PROFILE_GLSL) == 0)
{
ctx->profileMaxUniforms = impl_GLSL_MaxUniforms;
ctx->profileCompileShader = impl_GLSL_CompileShader;
ctx->profileDeleteShader = impl_GLSL_DeleteShader;
ctx->profileDeleteProgram = impl_GLSL_DeleteProgram;
562
ctx->profileGetAttribLocation = impl_GLSL_GetAttribLocation;
563
ctx->profileGetUniformLocation = impl_GLSL_GetUniformLocation;
564
ctx->profileGetSamplerLocation = impl_GLSL_GetSamplerLocation;
565
566
567
568
569
570
ctx->profileLinkProgram = impl_GLSL_LinkProgram;
ctx->profileUseProgramObject = impl_GLSL_UseProgramObject;
ctx->profileUniform4fv = impl_GLSL_Uniform4fv;
ctx->profileUniform4iv = impl_GLSL_Uniform4iv;
ctx->profileUniform1i = impl_GLSL_Uniform1i;
ctx->profileSetSampler = impl_GLSL_SetSampler;
571
572
573
574
} // if
#endif
#if SUPPORT_PROFILE_ARB1
575
576
else if ( (strcmp(profile, MOJOSHADER_PROFILE_ARB1) == 0) ||
(strcmp(profile, MOJOSHADER_PROFILE_NV2) == 0) )
577
578
579
580
581
{
ctx->profileMaxUniforms = impl_ARB1_MaxUniforms;
ctx->profileCompileShader = impl_ARB1_CompileShader;
ctx->profileDeleteShader = impl_ARB1_DeleteShader;
ctx->profileDeleteProgram = impl_ARB1_DeleteProgram;
582
ctx->profileGetAttribLocation = impl_ARB1_GetAttribLocation;
583
ctx->profileGetUniformLocation = impl_ARB1_GetUniformLocation;
584
ctx->profileGetSamplerLocation = impl_ARB1_GetSamplerLocation;
585
586
587
588
589
590
ctx->profileLinkProgram = impl_ARB1_LinkProgram;
ctx->profileUseProgramObject = impl_ARB1_UseProgramObject;
ctx->profileUniform4fv = impl_ARB1_Uniform4fv;
ctx->profileUniform4iv = impl_ARB1_Uniform4iv;
ctx->profileUniform1i = impl_ARB1_Uniform1i;
ctx->profileSetSampler = impl_ARB1_SetSampler;
591
592
593
594
595
596
597
} // if
#endif
assert(ctx->profileMaxUniforms != NULL);
assert(ctx->profileCompileShader != NULL);
assert(ctx->profileDeleteShader != NULL);
assert(ctx->profileDeleteProgram != NULL);
598
assert(ctx->profileMaxUniforms != NULL);
599
assert(ctx->profileGetAttribLocation != NULL);
600
assert(ctx->profileGetUniformLocation != NULL);
601
assert(ctx->profileGetSamplerLocation != NULL);
602
603
604
605
606
607
assert(ctx->profileLinkProgram != NULL);
assert(ctx->profileUseProgramObject != NULL);
assert(ctx->profileUniform4fv != NULL);
assert(ctx->profileUniform4iv != NULL);
assert(ctx->profileUniform1i != NULL);
assert(ctx->profileSetSampler != NULL);
608
609
retval = ctx;
610
611
ctx = current_ctx;
return retval;
612
613
init_fail:
614
615
616
617
if (ctx != NULL)
f(ctx, d);
ctx = current_ctx;
return NULL;
618
} // MOJOSHADER_glCreateContext
619
620
621
622
623
624
625
626
void MOJOSHADER_glMakeContextCurrent(MOJOSHADER_glContext *_ctx)
{
ctx = _ctx;
} // MOJOSHADER_glMakeContextCurrent
627
static int impl_GLSL_MaxUniforms(MOJOSHADER_shaderType shader_type)
628
629
630
631
632
633
634
635
636
637
638
639
{
GLenum pname = GL_NONE;
GLint val = 0;
if (shader_type == MOJOSHADER_TYPE_VERTEX)
pname = GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB;
else if (shader_type == MOJOSHADER_TYPE_PIXEL)
pname = GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB;
else
return -1;
ctx->glGetIntegerv(pname, &val);
return (int) val;
640
641
642
} // impl_GLSL_MaxUniforms
643
644
645
646
647
648
649
650
651
652
653
654
static int impl_ARB1_MaxUniforms(MOJOSHADER_shaderType shader_type)
{
GLint retval = 0;
GLenum program_type = GL_NONE;
if (shader_type == MOJOSHADER_TYPE_VERTEX)
program_type = GL_VERTEX_PROGRAM_ARB;
else if (shader_type == MOJOSHADER_TYPE_PIXEL)
program_type = GL_FRAGMENT_PROGRAM_ARB;
else
return -1;
ctx->glGetProgramivARB(program_type, GL_MAX_PROGRAM_PARAMETERS_ARB, &retval);
655
return (int) retval; // !!! FIXME: times four?
656
657
658
} // impl_ARB1_MaxUniforms
659
660
661
int MOJOSHADER_glMaxUniforms(MOJOSHADER_shaderType shader_type)
{
return ctx->profileMaxUniforms(shader_type);
662
663
664
} // MOJOSHADER_glMaxUniforms
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
static int impl_GLSL_CompileShader(const MOJOSHADER_parseData *pd, GLuint *s)
{
GLint ok = 0;
GLint shaderlen = (GLint) pd->output_len;
const GLenum shader_type = (pd->shader_type == MOJOSHADER_TYPE_PIXEL) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER;
GLuint shader = ctx->glCreateShaderObject(shader_type);
ctx->glShaderSource(shader, 1, (const GLchar **) &pd->output, &shaderlen);
ctx->glCompileShader(shader);
ctx->glGetObjectParameteriv(shader, GL_OBJECT_COMPILE_STATUS_ARB, &ok);
if (!ok)
{
GLsizei len = 0;
ctx->glGetInfoLog(shader, sizeof (error_buffer), &len,
(GLchar *) error_buffer);
*s = 0;
return 0;
} // if
*s = shader;
return 1;
} // impl_GLSL_CompileShader
690
691
692
693
694
695
696
697
698
static int impl_ARB1_CompileShader(const MOJOSHADER_parseData *pd, GLuint *s)
{
GLint shaderlen = (GLint) pd->output_len;
const GLenum shader_type = (pd->shader_type == MOJOSHADER_TYPE_PIXEL) ? GL_FRAGMENT_PROGRAM_ARB : GL_VERTEX_PROGRAM_ARB;
GLuint shader = 0;
ctx->glGenProgramsARB(1, &shader);
ctx->glGetError(); // flush any existing error state.
ctx->glBindProgramARB(shader_type, shader);
699
ctx->glProgramStringARB(shader_type, GL_PROGRAM_FORMAT_ASCII_ARB,
700
shaderlen, pd->output);
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
if (ctx->glGetError() == GL_INVALID_OPERATION)
{
GLint pos = 0;
ctx->glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &pos);
const GLubyte *errstr = ctx->glGetString(GL_PROGRAM_ERROR_STRING_ARB);
snprintf(error_buffer, sizeof (error_buffer),
"ARB1 compile error at position %d: %s",
(int) pos, (const char *) errstr);
ctx->glBindProgramARB(shader_type, 0);
ctx->glDeleteProgramsARB(1, &shader);
*s = 0;
return 0;
} // if
*s = shader;
return 1;
} // impl_ARB1_CompileShader
721
722
723
724
725
726
static void impl_GLSL_DeleteShader(const GLuint shader)
{
ctx->glDeleteObject(shader);
} // impl_GLSL_DeleteShader
727
728
729
730
731
732
733
static void impl_ARB1_DeleteShader(const GLuint _shader)
{
GLuint shader = _shader; // const removal.
ctx->glDeleteProgramsARB(1, &shader);
} // impl_ARB1_DeleteShader
734
735
736
737
738
739
static void impl_GLSL_DeleteProgram(const GLuint program)
{
ctx->glDeleteObject(program);
} // impl_GLSL_DeleteProgram
740
741
742
743
744
745
static void impl_ARB1_DeleteProgram(const GLuint program)
{
// no-op. ARB1 doesn't have real linked programs.
} // impl_GLSL_DeleteProgram
746
747
748
749
MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf,
const unsigned int bufsize)
{
MOJOSHADER_glShader *retval = NULL;
750
GLuint shader = 0;
751
752
753
754
const MOJOSHADER_parseData *pd = MOJOSHADER_parse(ctx->profile, tokenbuf,
bufsize, ctx->malloc_fn,
ctx->free_fn,
ctx->malloc_data);
755
if (pd->error != NULL)
756
757
{
set_error(pd->error);
758
goto compile_shader_fail;
759
} // if
760
761
762
retval = (MOJOSHADER_glShader *) Malloc(sizeof (MOJOSHADER_glShader));
if (retval == NULL)
763
764
goto compile_shader_fail;
765
if (!ctx->profileCompileShader(pd, &shader))
766
goto compile_shader_fail;
767
768
769
770
771
retval->parseData = pd;
retval->handle = shader;
retval->refcount = 1;
return retval;
772
773
774
775
776
compile_shader_fail:
MOJOSHADER_freeParseData(pd);
Free(retval);
if (shader != 0)
777
ctx->profileDeleteShader(shader);
778
return NULL;
779
780
781
} // MOJOSHADER_glCompileShader
782
783
784
785
786
787
788
const MOJOSHADER_parseData *MOJOSHADER_glGetShaderParseData(
MOJOSHADER_glShader *shader)
{
return (shader != NULL) ? shader->parseData : NULL;
} // MOJOSHADER_glGetShaderParseData
789
790
791
792
static void shader_unref(MOJOSHADER_glShader *shader)
{
if (shader != NULL)
{
793
const uint32 refcount = shader->refcount;
794
if (refcount > 1)
795
shader->refcount--;
796
797
else
{
798
ctx->profileDeleteShader(shader->handle);
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
MOJOSHADER_freeParseData(shader->parseData);
Free(shader);
} // else
} // if
} // shader_unref
static void program_unref(MOJOSHADER_glProgram *program)
{
if (program != NULL)
{
const uint32 refcount = program->refcount;
if (refcount > 1)
program->refcount--;
else
{
815
ctx->profileDeleteProgram(program->handle);
816
817
shader_unref(program->vertex);
shader_unref(program->fragment);
818
Free(program->constants);
819
820
821
Free(program->samplers);
Free(program->uniforms);
Free(program->attributes);
822
823
824
825
826
827
Free(program);
} // else
} // if
} // program_unref
828
829
static GLint impl_GLSL_GetUniformLocation(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader, int idx)
830
{
831
832
return ctx->glGetUniformLocation(program->handle,
shader->parseData->uniforms[idx].name);
833
834
} // impl_GLSL_GetUniformLocation
835
836
837
static GLint impl_ARB1_GetUniformLocation(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader, int idx)
838
{
839
840
assert(shader->parseData->uniforms[idx].type == MOJOSHADER_UNIFORM_FLOAT);
return shader->parseData->uniforms[idx].index; // !!! FIXME: doesn't work if there are int or bool uniforms!
841
842
843
} // impl_ARB1_GetUniformLocation
844
845
846
847
static void lookup_uniforms(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader)
{
const MOJOSHADER_parseData *pd = shader->parseData;
848
const MOJOSHADER_uniform *u = pd->uniforms;
849
const MOJOSHADER_shaderType shader_type = pd->shader_type;
850
int i;
851
852
853
for (i = 0; i < pd->uniform_count; i++)
{
854
const GLint loc = ctx->profileGetUniformLocation(program, shader, i);
855
856
857
if (loc != -1) // maybe the Uniform was optimized out?
{
UniformMap *map = &program->uniforms[program->uniform_count];
858
map->shader_type = shader_type;
859
map->uniform = &u[i];
860
map->location = (GLuint) loc;
861
862
863
864
865
866
program->uniform_count++;
} // if
} // for
} // lookup_uniforms
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
static GLint impl_GLSL_GetSamplerLocation(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader, int idx)
{
return ctx->glGetUniformLocation(program->handle,
shader->parseData->samplers[idx].name);
} // impl_GLSL_GetSamplerLocation
static GLint impl_ARB1_GetSamplerLocation(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader, int idx)
{
return shader->parseData->samplers[idx].index;
} // impl_ARB1_GetSamplerLocation
882
883
884
885
886
887
888
889
890
891
static void lookup_samplers(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader)
{
int i;
const MOJOSHADER_parseData *pd = shader->parseData;
const MOJOSHADER_sampler *s = pd->samplers;
const MOJOSHADER_shaderType shader_type = pd->shader_type;
for (i = 0; i < pd->sampler_count; i++)
{
892
const GLint loc = ctx->profileGetSamplerLocation(program, shader, i);
893
894
895
896
897
898
899
900
901
902
903
904
if (loc != -1) // maybe the Sampler was optimized out?
{
SamplerMap *map = &program->samplers[program->sampler_count];
map->shader_type = shader_type;
map->sampler = &s[i];
map->location = (GLuint) loc;
program->sampler_count++;
} // if
} // for
} // lookup_samplers
905
906
907
908
909
910
911
912
913
914
915
916
917
static GLint impl_GLSL_GetAttribLocation(MOJOSHADER_glProgram *program, int idx)
{
const MOJOSHADER_parseData *pd = program->vertex->parseData;
const MOJOSHADER_attribute *a = pd->attributes;
return ctx->glGetAttribLocation(program->handle, a[idx].name);
} // impl_GLSL_GetAttribLocation
static GLint impl_ARB1_GetAttribLocation(MOJOSHADER_glProgram *program, int idx)
{
return idx; // map to vertex arrays in the same order as the parseData.
} // impl_ARB1_GetAttribLocation
918
919
920
921
static void lookup_attributes(MOJOSHADER_glProgram *program)
{
int i;
const MOJOSHADER_parseData *pd = program->vertex->parseData;
922
const MOJOSHADER_attribute *a = pd->attributes;
923
924
925
for (i = 0; i < pd->attribute_count; i++)
{
926
const GLint loc = ctx->profileGetAttribLocation(program, i);
927
928
929
930
if (loc != -1) // maybe the Attribute was optimized out?
{
AttributeMap *map = &program->attributes[program->attribute_count];
map->attribute = &a[i];
931
map->location = (GLuint) loc;
932
933
934
935
936
937
program->attribute_count++;
} // if
} // for
} // lookup_attributes
938
939
static GLuint impl_GLSL_LinkProgram(MOJOSHADER_glShader *vshader,
MOJOSHADER_glShader *pshader)
940
{
941
const GLuint program = ctx->glCreateProgramObject();
942
943
944
if (vshader != NULL) ctx->glAttachObject(program, vshader->handle);
if (pshader != NULL) ctx->glAttachObject(program, pshader->handle);
945
946
ctx->glLinkProgram(program);
947
948
GLint ok = 0;
949
ctx->glGetObjectParameteriv(program, GL_OBJECT_LINK_STATUS_ARB, &ok);
950
951
952
if (!ok)
{
GLsizei len = 0;
953
ctx->glGetInfoLog(program, sizeof (error_buffer), &len, (GLchar *) error_buffer);
954
955
ctx->glDeleteObject(program);
return 0;
956
} // if
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
return program;
} // impl_GLSL_LinkProgram
static GLuint impl_ARB1_LinkProgram(MOJOSHADER_glShader *vshader,
MOJOSHADER_glShader *pshader)
{
// there is no formal linking in ARB1...just return a unique value.
static GLuint retval = 1;
return retval++;
} // impl_ARB1_LinkProgram
MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader,
MOJOSHADER_glShader *pshader)
{
if ((vshader == NULL) && (pshader == NULL))
return NULL;
int numregs = 0;
int consts = 0;
MOJOSHADER_glProgram *retval = NULL;
const GLuint program = ctx->profileLinkProgram(vshader, pshader);
if (program == 0)
goto link_program_fail;
984
985
retval = (MOJOSHADER_glProgram *) Malloc(sizeof (MOJOSHADER_glProgram));
if (retval == NULL)
986
987
goto link_program_fail;
memset(retval, '\0', sizeof (MOJOSHADER_glProgram));
988
989
numregs = 0;
990
991
if (vshader != NULL) numregs += vshader->parseData->uniform_count;
if (pshader != NULL) numregs += pshader->parseData->uniform_count;
992
993
994
995
996
997
998
999
if (numregs > 0)
{
const size_t len = sizeof (UniformMap) * numregs;
retval->uniforms = (UniformMap *) Malloc(len);
if (retval->uniforms == NULL)
goto link_program_fail;
memset(retval->uniforms, '\0', len);
} // if
1000