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