/
mojoshader_opengl.c
1009 lines (826 loc) · 31.2 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
35
36
#ifdef _MSC_VER
#define snprintf _snprintf
typedef unsigned __int8 uint8;
typedef unsigned __int32 uint32;
typedef unsigned __int32 int32;
#else
#include <stdint.h>
37
38
39
typedef uint8_t uint8;
typedef uint32_t uint32;
typedef int32_t int32;
40
41
42
#endif
#define STATICARRAYLEN(x) ( (sizeof ((x))) / (sizeof ((x)[0])) )
43
44
45
46
47
#ifndef SUPPORT_PROFILE_GLSL
#define SUPPORT_PROFILE_GLSL 1
#endif
48
49
50
struct MOJOSHADER_glShader
{
const MOJOSHADER_parseData *parseData;
51
GLhandleARB handle;
52
53
54
uint32 refcount;
};
55
56
typedef struct
{
57
MOJOSHADER_shaderType shader_type;
58
const MOJOSHADER_uniform *uniform;
59
GLuint location;
60
61
} UniformMap;
62
63
typedef struct
{
64
const MOJOSHADER_attribute *attribute;
65
GLuint location;
66
67
} AttributeMap;
68
69
struct MOJOSHADER_glProgram
{
70
71
MOJOSHADER_glShader *vertex;
MOJOSHADER_glShader *fragment;
72
GLhandleARB handle;
73
74
uint32 constant_count; // !!! FIXME: misnamed.
GLfloat *constants; // !!! FIXME: misnamed.
75
uint32 uniform_count;
76
UniformMap *uniforms;
77
uint32 attribute_count;
78
AttributeMap *attributes;
79
80
81
uint32 refcount;
};
82
83
84
85
#ifndef WINGDIAPI
#define WINGDIAPI
#endif
86
// Entry points in base OpenGL that lack function pointer prototypes...
87
88
typedef WINGDIAPI void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params);
typedef WINGDIAPI const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
89
90
91
92
93
94
95
96
97
98
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...
99
100
101
102
103
104
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];
105
106
107
108
109
// GL stuff...
int opengl_major;
int opengl_minor;
MOJOSHADER_glProgram *bound_program;
110
char profile[16];
111
112
113
114
115
116
117
118
119
120
121
// Extensions...
int have_base_opengl;
int have_GL_ARB_shader_objects;
int have_GL_ARB_vertex_shader;
int have_GL_ARB_fragment_shader;
int have_GL_ARB_shading_language_100;
int have_GL_NV_half_float;
// Entry points...
PFNGLGETSTRINGPROC glGetString;
122
PFNGLGETINTEGERVPROC glGetIntegerv;
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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;
};
static MOJOSHADER_glContext *ctx = NULL;
144
145
146
147
148
149
150
151
152
153
// 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
154
155
156
157
158
159
160
161
162
163
164
165
166
// #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)
{
167
void *retval = ctx->malloc_fn(len, ctx->malloc_data);
168
169
170
if (retval == NULL)
set_error("out of memory");
return retval;
171
172
173
174
} // Malloc
static inline void Free(void *ptr)
{
175
if (ptr != NULL)
176
ctx->free_fn(ptr, ctx->malloc_data);
177
178
179
} // Free
180
181
182
183
184
185
const char *MOJOSHADER_glGetError(void)
{
return error_buffer;
} // MOJOSHADER_glGetError
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
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))
{
208
#define DO_LOOKUP(ext, typ, fn) ctx->fn = (typ) loadsym(lookup, #fn, &ctx->have_##ext)
209
DO_LOOKUP(base_opengl, PFNGLGETSTRINGPROC, glGetString);
210
DO_LOOKUP(base_opengl, PFNGLGETINTEGERVPROC, glGetIntegerv);
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
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);
#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.
239
240
241
else if (!ctx->have_base_opengl)
return 0; // don't bother checking, we're missing basic functionality.
242
// See if it's in the spec for this GL implementation's version.
243
244
if (major >= 0)
{
245
if ( ((ctx->opengl_major << 16) | (ctx->opengl_minor & 0xFFFF)) >=
246
247
248
((major << 16) | (minor & 0xFFFF)) )
return 1;
} // if
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// 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)
266
ctx->opengl_major = ctx->opengl_minor = 0;
267
else
268
sscanf(verstr, "%d.%d", &ctx->opengl_major, &ctx->opengl_minor);
269
270
271
} // parse_opengl_version
272
static void load_extensions(void *(*lookup)(const char *fnname))
273
{
274
275
const char *extlist = NULL;
276
277
278
279
280
281
ctx->have_base_opengl = 1;
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;
282
283
284
lookup_entry_points(lookup);
285
if (!ctx->have_base_opengl)
286
set_error("missing basic OpenGL entry points");
287
288
289
290
291
else
{
parse_opengl_version((const char *) ctx->glGetString(GL_VERSION));
extlist = (const char *) ctx->glGetString(GL_EXTENSIONS);
} // else
292
293
294
295
296
if (extlist == NULL)
extlist = ""; // just in case.
#define VERIFY_EXT(ext, major, minor) \
297
ctx->have_##ext = verify_extension(#ext, ctx->have_##ext, extlist, major, minor)
298
299
300
301
302
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);
303
VERIFY_EXT(GL_NV_half_float, -1, -1);
304
305
#undef VERIFY_EXT
306
307
308
309
310
311
312
} // load_extensions
static int valid_profile(const char *profile)
{
if (!ctx->have_base_opengl)
return 0;
313
314
315
#define MUST_HAVE(p, x) \
if (!ctx->have_##x) { set_error(#p " profile needs " #x); return 0; }
316
317
318
319
320
if (0) {}
#if SUPPORT_PROFILE_GLSL
else if (strcmp(profile, MOJOSHADER_PROFILE_GLSL) == 0)
321
{
322
323
324
325
326
327
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
328
329
330
else
{
331
set_error("unknown or unsupported profile");
332
333
334
return 0;
} // else
335
#undef MUST_HAVE
336
337
return 1;
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
} // 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,
};
int i;
for (i = 0; i < STATICARRAYLEN(priority); i++)
{
if (valid_profile(priority[i]))
{
retval = priority[i];
break;
} // if
} // for
366
367
368
369
if (retval == NULL)
set_error("no profiles available");
} // if
370
371
372
373
374
375
376
ctx = current_ctx;
return retval;
} // MOJOSHADER_glBestProfile
MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile,
377
378
379
void *(*lookup)(const char *fnname),
MOJOSHADER_malloc m, MOJOSHADER_free f,
void *d)
380
{
381
MOJOSHADER_glContext *retval = NULL;
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
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;
399
snprintf(ctx->profile, sizeof (ctx->profile), "%s", profile);
400
401
402
load_extensions(lookup);
if (!valid_profile(profile))
403
goto init_fail;
404
405
406
MOJOSHADER_glBindProgram(NULL);
407
retval = ctx;
408
409
ctx = current_ctx;
return retval;
410
411
init_fail:
412
413
414
415
if (ctx != NULL)
f(ctx, d);
ctx = current_ctx;
return NULL;
416
} // MOJOSHADER_glCreateContext
417
418
419
420
421
422
423
424
void MOJOSHADER_glMakeContextCurrent(MOJOSHADER_glContext *_ctx)
{
ctx = _ctx;
} // MOJOSHADER_glMakeContextCurrent
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
int MOJOSHADER_glMaxUniforms(MOJOSHADER_shaderType shader_type)
{
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;
} // MOJOSHADER_glMaxUniforms
441
442
443
444
MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf,
const unsigned int bufsize)
{
MOJOSHADER_glShader *retval = NULL;
445
GLhandleARB shader = 0;
446
447
448
449
const MOJOSHADER_parseData *pd = MOJOSHADER_parse(ctx->profile, tokenbuf,
bufsize, ctx->malloc_fn,
ctx->free_fn,
ctx->malloc_data);
450
451
452
453
GLint ok = 0;
const GLenum shader_type = (pd->shader_type == MOJOSHADER_TYPE_PIXEL) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER;
GLint shaderlen = (GLint) pd->output_len;
454
if (pd->error != NULL)
455
456
{
set_error(pd->error);
457
goto compile_shader_fail;
458
} // if
459
460
461
retval = (MOJOSHADER_glShader *) Malloc(sizeof (MOJOSHADER_glShader));
if (retval == NULL)
462
463
goto compile_shader_fail;
464
shader = ctx->glCreateShaderObject(shader_type);
465
466
467
468
ctx->glShaderSource(shader, 1, (const GLchar **) &pd->output, &shaderlen);
ctx->glCompileShader(shader);
ctx->glGetObjectParameteriv(shader, GL_OBJECT_COMPILE_STATUS_ARB, &ok);
469
470
471
472
if (!ok)
{
GLsizei len = 0;
473
ctx->glGetInfoLog(shader, sizeof (error_buffer), &len, (GLchar *) error_buffer);
474
goto compile_shader_fail;
475
476
477
478
479
480
} // if
retval->parseData = pd;
retval->handle = shader;
retval->refcount = 1;
return retval;
481
482
483
484
485
compile_shader_fail:
MOJOSHADER_freeParseData(pd);
Free(retval);
if (shader != 0)
486
ctx->glDeleteObject(shader);
487
return NULL;
488
489
490
} // MOJOSHADER_glCompileShader
491
492
493
494
495
496
497
const MOJOSHADER_parseData *MOJOSHADER_glGetShaderParseData(
MOJOSHADER_glShader *shader)
{
return (shader != NULL) ? shader->parseData : NULL;
} // MOJOSHADER_glGetShaderParseData
498
499
500
501
static void shader_unref(MOJOSHADER_glShader *shader)
{
if (shader != NULL)
{
502
const uint32 refcount = shader->refcount;
503
if (refcount > 1)
504
shader->refcount--;
505
506
else
{
507
ctx->glDeleteObject(shader->handle);
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
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
{
524
ctx->glDeleteObject(program->handle);
525
526
shader_unref(program->vertex);
shader_unref(program->fragment);
527
Free(program->attributes);
528
Free(program->uniforms);
529
Free(program->constants);
530
531
532
533
534
535
Free(program);
} // else
} // if
} // program_unref
536
537
538
539
540
static void lookup_uniforms(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader)
{
int i;
const MOJOSHADER_parseData *pd = shader->parseData;
541
const MOJOSHADER_uniform *u = pd->uniforms;
542
const MOJOSHADER_shaderType shader_type = pd->shader_type;
543
544
545
for (i = 0; i < pd->uniform_count; i++)
{
546
const GLint loc = ctx->glGetUniformLocation(program->handle, u[i].name);
547
548
549
if (loc != -1) // maybe the Uniform was optimized out?
{
UniformMap *map = &program->uniforms[program->uniform_count];
550
map->shader_type = shader_type;
551
map->uniform = &u[i];
552
map->location = (GLuint) loc;
553
554
555
556
557
558
program->uniform_count++;
} // if
} // for
} // lookup_uniforms
559
560
561
562
static void lookup_attributes(MOJOSHADER_glProgram *program)
{
int i;
const MOJOSHADER_parseData *pd = program->vertex->parseData;
563
const MOJOSHADER_attribute *a = pd->attributes;
564
565
566
for (i = 0; i < pd->attribute_count; i++)
{
567
const GLint loc = ctx->glGetAttribLocation(program->handle, a->name);
568
569
570
571
if (loc != -1) // maybe the Attribute was optimized out?
{
AttributeMap *map = &program->attributes[program->attribute_count];
map->attribute = &a[i];
572
map->location = (GLuint) loc;
573
574
575
576
577
578
program->attribute_count++;
} // if
} // for
} // lookup_attributes
579
580
581
MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader,
MOJOSHADER_glShader *pshader)
{
582
583
584
if ((vshader == NULL) && (pshader == NULL))
return NULL;
585
MOJOSHADER_glProgram *retval = NULL;
586
const GLhandleARB program = ctx->glCreateProgramObject();
587
int numregs = 0;
588
589
590
if (vshader != NULL) ctx->glAttachObject(program, vshader->handle);
if (pshader != NULL) ctx->glAttachObject(program, pshader->handle);
591
592
ctx->glLinkProgram(program);
593
594
GLint ok = 0;
595
ctx->glGetObjectParameteriv(program, GL_OBJECT_LINK_STATUS_ARB, &ok);
596
597
598
if (!ok)
{
GLsizei len = 0;
599
ctx->glGetInfoLog(program, sizeof (error_buffer), &len, (GLchar *) error_buffer);
600
601
goto link_program_fail;
} // if
602
603
604
retval = (MOJOSHADER_glProgram *) Malloc(sizeof (MOJOSHADER_glProgram));
if (retval == NULL)
605
606
goto link_program_fail;
memset(retval, '\0', sizeof (MOJOSHADER_glProgram));
607
608
609
if (vshader != NULL) numregs += vshader->parseData->uniform_count;
if (pshader != NULL) numregs += pshader->parseData->uniform_count;
610
611
612
retval->uniforms = (UniformMap *) Malloc(sizeof (UniformMap) * numregs);
if (retval->uniforms == NULL)
goto link_program_fail;
613
memset(retval->uniforms, '\0', sizeof (UniformMap) * numregs);
614
615
616
617
618
retval->handle = program;
retval->vertex = vshader;
retval->fragment = pshader;
retval->refcount = 1;
619
620
621
uint32 const_count = 0;
622
if (vshader != NULL)
623
{
624
625
if (const_count < vshader->parseData->constant_count)
const_count = vshader->parseData->constant_count;
626
627
628
629
630
631
retval->attributes = (AttributeMap *) Malloc(sizeof (AttributeMap) *
vshader->parseData->attribute_count);
if (retval->attributes == NULL)
goto link_program_fail;
lookup_attributes(retval);
632
lookup_uniforms(retval, vshader);
633
vshader->refcount++;
634
635
} // if
636
if (pshader != NULL)
637
{
638
639
640
if (const_count < pshader->parseData->constant_count)
const_count = pshader->parseData->constant_count;
641
lookup_uniforms(retval, pshader);
642
pshader->refcount++;
643
} // if
644
645
646
647
648
649
650
651
652
if (const_count > 0)
{
retval->constants = (GLfloat *) Malloc(sizeof (GLfloat) * const_count);
if (retval->constants == NULL)
goto link_program_fail;
retval->constant_count = const_count;
} // if
653
return retval;
654
655
656
657
link_program_fail:
if (retval != NULL)
{
658
659
Free(retval->uniforms);
Free(retval->attributes);
660
Free(retval->constants);
661
662
663
Free(retval);
} // if
664
ctx->glDeleteObject(program);
665
return NULL;
666
667
668
669
670
} // MOJOSHADER_glLinkProgram
void MOJOSHADER_glBindProgram(MOJOSHADER_glProgram *program)
{
671
GLhandleARB handle = 0;
672
int i;
673
674
if (program == ctx->bound_program)
675
676
677
return; // nothing to do.
// Disable any client-side arrays the current program could have used.
678
679
// !!! FIXME: don't disable yet...see which ones get reused, and disable
// !!! FIXME: only what we don't need in MOJOSHADER_glProgramReady().
680
if (ctx->bound_program != NULL)
681
{
682
683
const int count = ctx->bound_program->attribute_count;
for (i = 0; i < count; i++)
684
{
685
686
const AttributeMap *map = &ctx->bound_program->attributes[i];
ctx->glDisableVertexAttribArray(map->location);
687
688
689
} // if
} // for
690
691
692
693
694
695
if (program != NULL)
{
handle = program->handle;
program->refcount++;
} // if
696
697
698
ctx->glUseProgramObject(handle);
program_unref(ctx->bound_program);
ctx->bound_program = program;
699
700
701
} // MOJOSHADER_glBindProgram
702
static inline uint minuint(const uint a, const uint b)
703
{
704
705
return ((a < b) ? a : b);
} // minuint
706
707
708
void MOJOSHADER_glSetVertexShaderUniformF(unsigned int idx, const float *data,
709
unsigned int vec4n)
710
{
711
const uint maxregs = STATICARRAYLEN(ctx->vs_reg_file_f) / 4;
712
713
if (idx < maxregs)
{
714
assert(sizeof (GLfloat) == sizeof (float));
715
const uint cpy = (minuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
716
memcpy(ctx->vs_reg_file_f + (idx * 4), data, cpy);
717
} // if
718
719
720
721
} // MOJOSHADER_glSetVertexShaderUniformF
void MOJOSHADER_glSetVertexShaderUniformI(unsigned int idx, const int *data,
722
unsigned int ivec4n)
723
{
724
const uint maxregs = STATICARRAYLEN(ctx->vs_reg_file_i) / 4;
725
726
if (idx < maxregs)
{
727
assert(sizeof (GLint) == sizeof (int));
728
const uint cpy = (minuint(maxregs - idx, ivec4n) * sizeof (*data)) * 4;
729
memcpy(ctx->vs_reg_file_i + (idx * 4), data, cpy);
730
} // if
731
732
733
734
735
736
} // MOJOSHADER_glSetVertexShaderUniformI
void MOJOSHADER_glSetVertexShaderUniformB(unsigned int idx, const int *data,
unsigned int bcount)
{
737
const uint maxregs = STATICARRAYLEN(ctx->vs_reg_file_f) / 4;
738
739
if (idx < maxregs)
{
740
GLint *wptr = ctx->vs_reg_file_b + idx;
741
GLint *endptr = wptr + minuint(maxregs - idx, bcount);
742
743
744
while (wptr != endptr)
*(wptr++) = *(data++) ? 1 : 0;
} // if
745
746
747
748
} // MOJOSHADER_glSetVertexShaderUniformB
void MOJOSHADER_glSetPixelShaderUniformF(unsigned int idx, const float *data,
749
unsigned int vec4n)
750
{
751
const uint maxregs = STATICARRAYLEN(ctx->ps_reg_file_f) / 4;
752
753
if (idx < maxregs)
{
754
assert(sizeof (GLfloat) == sizeof (float));
755
const uint cpy = (minuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
756
memcpy(ctx->ps_reg_file_f + (idx * 4), data, cpy);
757
} // if
758
759
760
761
} // MOJOSHADER_glSetPixelShaderUniformF
void MOJOSHADER_glSetPixelShaderUniformI(unsigned int idx, const int *data,
762
unsigned int ivec4n)
763
{
764
const uint maxregs = STATICARRAYLEN(ctx->ps_reg_file_i) / 4;
765
766
if (idx < maxregs)
{
767
assert(sizeof (GLint) == sizeof (int));
768
const uint cpy = (minuint(maxregs - idx, ivec4n) * sizeof (*data)) * 4;
769
memcpy(ctx->ps_reg_file_i + (idx * 4), data, cpy);
770
} // if
771
772
773
774
} // MOJOSHADER_glSetPixelShaderUniformI
void MOJOSHADER_glSetPixelShaderUniformB(unsigned int idx, const int *data,
775
unsigned int bcount)
776
{
777
const uint maxregs = STATICARRAYLEN(ctx->ps_reg_file_f) / 4;
778
779
if (idx < maxregs)
{
780
GLint *wptr = ctx->ps_reg_file_b + idx;
781
GLint *endptr = wptr + minuint(maxregs - idx, bcount);
782
783
784
while (wptr != endptr)
*(wptr++) = *(data++) ? 1 : 0;
} // if
785
786
787
} // MOJOSHADER_glSetPixelShaderUniformB
788
789
790
791
static inline GLenum opengl_attr_type(const MOJOSHADER_attributeType type)
{
switch (type)
{
792
case MOJOSHADER_ATTRIBUTE_UNKNOWN: return GL_NONE; // oh well.
793
794
795
case MOJOSHADER_ATTRIBUTE_BYTE: return GL_BYTE;
case MOJOSHADER_ATTRIBUTE_UBYTE: return GL_UNSIGNED_BYTE;
case MOJOSHADER_ATTRIBUTE_SHORT: return GL_SHORT;
796
case MOJOSHADER_ATTRIBUTE_USHORT: return GL_UNSIGNED_SHORT;
797
798
799
800
case MOJOSHADER_ATTRIBUTE_INT: return GL_INT;
case MOJOSHADER_ATTRIBUTE_UINT: return GL_UNSIGNED_INT;
case MOJOSHADER_ATTRIBUTE_FLOAT: return GL_FLOAT;
case MOJOSHADER_ATTRIBUTE_DOUBLE: return GL_DOUBLE;
801
802
case MOJOSHADER_ATTRIBUTE_HALF_FLOAT:
803
if (ctx->have_GL_NV_half_float)
804
805
return GL_HALF_FLOAT_NV;
break;
806
807
808
809
810
811
} // switch
return GL_NONE; // oh well. Raises a GL error later.
} // opengl_attr_type
812
813
814
815
816
817
void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage,
int index, unsigned int size,
MOJOSHADER_attributeType type,
int normalized, unsigned int stride,
const void *ptr)
{
818
if ((ctx->bound_program == NULL) || (ctx->bound_program->vertex == NULL))
819
820
return;
821
822
823
const GLenum gl_type = opengl_attr_type(type);
const GLboolean norm = (normalized) ? GL_TRUE : GL_FALSE;
GLuint gl_index = 0;
824
825
826
827
// We have to map POSITION0 to generic vertex attribute 0; the
// GL_ARB_vertex_shader spec says this is equivalent to using
// glVertexPointer(), but without the limitations of that entry point.
828
829
if ((usage != MOJOSHADER_USAGE_POSITION) || (index != 0))
830
{
831
832
833
834
835
836
int i;
const int count = ctx->bound_program->attribute_count;
for (i = 0; i < count; i++)
{
const AttributeMap *map = &ctx->bound_program->attributes[i];
const MOJOSHADER_attribute *a = map->attribute;
837
838
839
// !!! FIXME: is this array guaranteed to be sorted by usage?
// !!! FIXME: if so, we can break if a->usage > usage.
840
841
842
843
844
845
846
if ((a->usage == usage) && (a->index == index))
{
gl_index = map->location;
break;
} // if
} // for
847
848
849
if (gl_index == 0)
return; // nothing to do, this shader doesn't use this stream.
850
} // if
851
852
853
ctx->glVertexAttribPointer(gl_index, size, gl_type, norm, stride, ptr);
ctx->glEnableVertexAttribArray(gl_index);
854
855
856
857
858
} // MOJOSHADER_glSetVertexAttribute
void MOJOSHADER_glProgramReady(void)
{
859
860
int i;
861
if (ctx->bound_program == NULL)
862
863
864
865
866
return; // nothing to do.
// !!! FIXME: don't push Uniforms if we know they haven't changed.
// push Uniforms to the program from our register files...
867
868
const int count = ctx->bound_program->uniform_count;
for (i = 0; i < count; i++)
869
{
870
const UniformMap *map = &ctx->bound_program->uniforms[i];
871
872
873
874
const MOJOSHADER_uniform *u = map->uniform;
const MOJOSHADER_uniformType type = u->type;
const MOJOSHADER_shaderType shader_type = map->shader_type;
const int index = u->index;
875
const int size = u->array_count;
876
877
const GLint location = map->location;
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
// only use arrays for 'c' registers.
assert((size == 0) || (type == MOJOSHADER_UNIFORM_FLOAT));
if (size != 0) // !!! FIXME: this code sucks.
{
// !!! FIXME: calculate this all at link time.
if (shader_type == MOJOSHADER_TYPE_VERTEX)
{
const MOJOSHADER_constant *c = ctx->bound_program->vertex->parseData->constants;
int hi = ctx->bound_program->vertex->parseData->constant_count;
int j;
GLfloat *ptr = ctx->bound_program->constants;
for (j = 0; j < hi; j++)
{
if (c[j].type != MOJOSHADER_UNIFORM_FLOAT)
continue;
const int idx = c[j].index;
if ( (idx >= index) && (idx < (index + size)) )
{
memcpy(ptr, &ctx->vs_reg_file_f[idx * 4], 16); // !!! FIXME: 16
memcpy(&ctx->vs_reg_file_f[idx * 4], &c->value.f, 16); // !!! FIXME: 16
ptr += 4;
} // if
} // for
ctx->glUniform4fv(location, size, &ctx->vs_reg_file_f[index * 4]);
ptr = ctx->bound_program->constants;
for (j = 0; j < hi; j++)
{
if (c[j].type != MOJOSHADER_UNIFORM_FLOAT)
continue;
const int idx = c[j].index;
if ( (idx >= index) && (idx < (index + size)) )
{
memcpy(&ctx->vs_reg_file_f[idx * 4], ptr, 16); // !!! FIXME: 16
ptr += 4;
} // if
} // for
} // if
else if (shader_type == MOJOSHADER_TYPE_PIXEL)
{
const MOJOSHADER_constant *c = ctx->bound_program->fragment->parseData->constants;
int hi = ctx->bound_program->fragment->parseData->constant_count;
int j;
GLfloat *ptr = ctx->bound_program->constants;
for (j = 0; j < hi; j++)
{
if (c[j].type != MOJOSHADER_UNIFORM_FLOAT)
continue;
const int idx = c[j].index;
if ( (idx >= index) && (idx < (index + size)) )
{
memcpy(ptr, &ctx->ps_reg_file_f[idx * 4], 16); // !!! FIXME: 16
memcpy(&ctx->ps_reg_file_f[idx * 4], &c->value.f, 16); // !!! FIXME: 16
ptr += 4;
} // if
} // for
ctx->glUniform4fv(location, size, &ctx->ps_reg_file_f[index * 4]);
ptr = ctx->bound_program->constants;
for (j = 0; j < hi; j++)
{
if (c[j].type != MOJOSHADER_UNIFORM_FLOAT)
continue;
const int idx = c[j].index;
if ( (idx >= index) && (idx < (index + size)) )
{
memcpy(&ctx->ps_reg_file_f[idx * 4], ptr, 16); // !!! FIXME: 16
ptr += 4;
} // if
} // for
} // else if
} // if
else if (shader_type == MOJOSHADER_TYPE_VERTEX)
964
965
{
if (type == MOJOSHADER_UNIFORM_FLOAT)
966
ctx->glUniform4fv(location, 1, &ctx->vs_reg_file_f[index * 4]);
967
else if (type == MOJOSHADER_UNIFORM_INT)
968
ctx->glUniform4iv(location, 1, &ctx->vs_reg_file_i[index * 4]);
969
else if (type == MOJOSHADER_UNIFORM_BOOL)
970
ctx->glUniform1i(location, ctx->vs_reg_file_b[index]);
971
972
973
974
975
} // if
else if (shader_type == MOJOSHADER_TYPE_PIXEL)
{
if (type == MOJOSHADER_UNIFORM_FLOAT)
976
ctx->glUniform4fv(location, 1, &ctx->ps_reg_file_f[index * 4]);
977
else if (type == MOJOSHADER_UNIFORM_INT)
978
ctx->glUniform4iv(location, 1, &ctx->ps_reg_file_i[index * 4]);
979
else if (type == MOJOSHADER_UNIFORM_BOOL)
980
ctx->glUniform1i(location, ctx->ps_reg_file_b[index]);
981
982
} // else if
} // for
983
984
985
} // MOJOSHADER_glProgramReady
986
void MOJOSHADER_glDeleteProgram(MOJOSHADER_glProgram *program)
987
{
988
program_unref(program);
989
990
991
} // MOJOSHADER_glDeleteProgram
992
void MOJOSHADER_glDeleteShader(MOJOSHADER_glShader *shader)
993
994
995
996
997
{
shader_unref(shader);
} // MOJOSHADER_glDeleteShader
998
void MOJOSHADER_glDestroyContext(MOJOSHADER_glContext *_ctx)
999
{
1000
MOJOSHADER_glContext *current_ctx = ctx;