/
mojoshader_opengl.c
799 lines (654 loc) · 24.6 KB
1
2
3
4
5
6
7
8
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <assert.h>
#include "mojoshader.h"
9
10
11
#define GL_GLEXT_LEGACY 1
#include "gl.h"
#include "glext.h"
12
13
14
// Get basic wankery out of the way here...
15
16
#define STATICARRAYLEN(x) ( (sizeof ((x))) / (sizeof ((x)[0])) )
17
18
19
20
21
22
23
24
typedef unsigned int uint; // this is a printf() helper. don't use for code.
typedef uint8_t uint8;
typedef uint32_t uint32;
typedef int32_t int32;
struct MOJOSHADER_glShader
{
const MOJOSHADER_parseData *parseData;
25
GLhandleARB handle;
26
27
28
uint32 refcount;
};
29
30
typedef struct
{
31
MOJOSHADER_shaderType shader_type;
32
const MOJOSHADER_uniform *uniform;
33
GLuint location;
34
35
} UniformMap;
36
37
typedef struct
{
38
const MOJOSHADER_attribute *attribute;
39
GLuint location;
40
41
} AttributeMap;
42
43
struct MOJOSHADER_glProgram
{
44
45
MOJOSHADER_glShader *vertex;
MOJOSHADER_glShader *fragment;
46
GLhandleARB handle;
47
uint32 uniform_count;
48
UniformMap *uniforms;
49
uint32 attribute_count;
50
AttributeMap *attributes;
51
52
53
uint32 refcount;
};
54
// Entry points in base OpenGL that lack function pointer prototypes...
55
56
typedef WINGDIAPI const GLubyte * (APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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...
float vs_reg_file_f[8192 * 4];
int vs_reg_file_i[2047 * 4];
uint8 vs_reg_file_b[2047];
float ps_reg_file_f[8192 * 4];
int ps_reg_file_i[2047 * 4];
uint8 ps_reg_file_b[2047];
// GL stuff...
int opengl_major;
int opengl_minor;
MOJOSHADER_glProgram *bound_program;
const char *profile;
// 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;
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;
110
111
112
113
114
115
116
117
118
119
// 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
120
121
122
123
124
125
126
127
128
129
130
131
132
// #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)
{
133
void *retval = ctx->malloc_fn(len, ctx->malloc_data);
134
135
136
if (retval == NULL)
set_error("out of memory");
return retval;
137
138
139
140
} // Malloc
static inline void Free(void *ptr)
{
141
if (ptr != NULL)
142
ctx->free_fn(ptr, ctx->malloc_data);
143
144
145
} // Free
146
147
148
149
150
151
const char *MOJOSHADER_glGetError(void)
{
return error_buffer;
} // MOJOSHADER_glGetError
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
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))
{
174
#define DO_LOOKUP(ext, typ, fn) ctx->fn = (typ) loadsym(lookup, #fn, &ctx->have_##ext)
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
DO_LOOKUP(base_opengl, PFNGLGETSTRINGPROC, glGetString);
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.
// See if it's in the spec for this GL implementation's version.
205
206
if (major >= 0)
{
207
if ( ((ctx->opengl_major << 16) | (ctx->opengl_minor & 0xFFFF)) >=
208
209
210
((major << 16) | (minor & 0xFFFF)) )
return 1;
} // if
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
// 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)
228
ctx->opengl_major = ctx->opengl_minor = 0;
229
else
230
sscanf(verstr, "%d.%d", &ctx->opengl_major, &ctx->opengl_minor);
231
232
233
234
235
} // parse_opengl_version
static int check_extensions(void *(*lookup)(const char *fnname))
{
236
237
238
239
240
241
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;
242
243
244
lookup_entry_points(lookup);
245
if (!ctx->have_base_opengl) // a func we should definitely have is MIA?
246
247
248
249
250
{
set_error("missing basic OpenGL entry points");
return 0;
} // if
251
parse_opengl_version((const char *) ctx->glGetString(GL_VERSION));
252
253
const char *extlist = (const char *) ctx->glGetString(GL_EXTENSIONS);
254
255
256
257
if (extlist == NULL)
extlist = ""; // just in case.
#define VERIFY_EXT(ext, major, minor) \
258
ctx->have_##ext = verify_extension(#ext, ctx->have_##ext, extlist, major, minor)
259
260
261
262
263
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);
264
VERIFY_EXT(GL_NV_half_float, -1, -1);
265
266
267
268
#undef VERIFY_EXT
#define REQUIRE_GL_EXTENSION(x) \
269
if (!ctx->have_##x) { set_error("profile requires " #x); return 0; }
270
271
if (strcmp(ctx->profile, MOJOSHADER_PROFILE_GLSL) == 0)
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
{
REQUIRE_GL_EXTENSION(GL_ARB_shader_objects);
REQUIRE_GL_EXTENSION(GL_ARB_vertex_shader);
REQUIRE_GL_EXTENSION(GL_ARB_fragment_shader);
REQUIRE_GL_EXTENSION(GL_ARB_shading_language_100);
} // if
else
{
set_error("unknown profile");
return 0;
} // else
#undef REQUIRE_GL_EXTENSION
return 1;
} // check_extensions
291
MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *_profile,
292
293
294
void *(*lookup)(const char *fnname),
MOJOSHADER_malloc m, MOJOSHADER_free f,
void *d)
295
{
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
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
MOJOSHADER_glContext *retval = ctx;
memset(ctx, '\0', sizeof (MOJOSHADER_glContext));
ctx->malloc_fn = m;
ctx->free_fn = f;
ctx->malloc_data = d;
315
316
if (strcmp(_profile, MOJOSHADER_PROFILE_GLSL) == 0)
317
ctx->profile = MOJOSHADER_PROFILE_GLSL;
318
else
319
320
{
set_error("unknown profile");
321
goto init_fail;
322
} // else
323
324
325
if (!check_extensions(lookup))
goto init_fail;
326
327
328
MOJOSHADER_glBindProgram(NULL);
329
330
ctx = current_ctx;
return retval;
331
332
init_fail:
333
334
335
336
if (ctx != NULL)
f(ctx, d);
ctx = current_ctx;
return NULL;
337
} // MOJOSHADER_glCreateContext
338
339
340
341
342
343
344
345
void MOJOSHADER_glMakeContextCurrent(MOJOSHADER_glContext *_ctx)
{
ctx = _ctx;
} // MOJOSHADER_glMakeContextCurrent
346
347
348
349
MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf,
const unsigned int bufsize)
{
MOJOSHADER_glShader *retval = NULL;
350
GLhandleARB shader = 0;
351
352
353
354
const MOJOSHADER_parseData *pd = MOJOSHADER_parse(ctx->profile, tokenbuf,
bufsize, ctx->malloc_fn,
ctx->free_fn,
ctx->malloc_data);
355
if (pd->error != NULL)
356
357
{
set_error(pd->error);
358
goto compile_shader_fail;
359
} // if
360
361
362
retval = (MOJOSHADER_glShader *) Malloc(sizeof (MOJOSHADER_glShader));
if (retval == NULL)
363
364
goto compile_shader_fail;
365
GLint ok = 0;
366
const GLenum shader_type = (pd->shader_type == MOJOSHADER_TYPE_PIXEL) ? GL_FRAGMENT_SHADER : GL_VERTEX_SHADER;
367
GLint shaderlen = (GLint) pd->output_len;
368
shader = ctx->glCreateShaderObject(shader_type);
369
370
371
372
ctx->glShaderSource(shader, 1, (const GLchar **) &pd->output, &shaderlen);
ctx->glCompileShader(shader);
ctx->glGetObjectParameteriv(shader, GL_OBJECT_COMPILE_STATUS_ARB, &ok);
373
374
375
376
if (!ok)
{
GLsizei len = 0;
377
ctx->glGetInfoLog(shader, sizeof (error_buffer), &len, (GLchar *) error_buffer);
378
goto compile_shader_fail;
379
380
381
382
383
384
} // if
retval->parseData = pd;
retval->handle = shader;
retval->refcount = 1;
return retval;
385
386
387
388
389
compile_shader_fail:
MOJOSHADER_freeParseData(pd);
Free(retval);
if (shader != 0)
390
ctx->glDeleteObject(shader);
391
return NULL;
392
393
394
395
396
397
398
} // MOJOSHADER_glCompileShader
static void shader_unref(MOJOSHADER_glShader *shader)
{
if (shader != NULL)
{
399
const uint32 refcount = shader->refcount;
400
if (refcount > 1)
401
shader->refcount--;
402
403
else
{
404
ctx->glDeleteObject(shader->handle);
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
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
{
421
ctx->glDeleteObject(program->handle);
422
423
shader_unref(program->vertex);
shader_unref(program->fragment);
424
Free(program->attributes);
425
Free(program->uniforms);
426
427
428
429
430
431
Free(program);
} // else
} // if
} // program_unref
432
433
434
435
436
static void lookup_uniforms(MOJOSHADER_glProgram *program,
MOJOSHADER_glShader *shader)
{
int i;
const MOJOSHADER_parseData *pd = shader->parseData;
437
const MOJOSHADER_uniform *u = pd->uniforms;
438
const MOJOSHADER_shaderType shader_type = pd->shader_type;
439
440
441
for (i = 0; i < pd->uniform_count; i++)
{
442
const GLint loc = ctx->glGetUniformLocation(program->handle, u[i].name);
443
444
445
if (loc != -1) // maybe the Uniform was optimized out?
{
UniformMap *map = &program->uniforms[program->uniform_count];
446
map->shader_type = shader_type;
447
map->uniform = &u[i];
448
map->location = (GLuint) loc;
449
450
451
452
453
454
program->uniform_count++;
} // if
} // for
} // lookup_uniforms
455
456
457
458
static void lookup_attributes(MOJOSHADER_glProgram *program)
{
int i;
const MOJOSHADER_parseData *pd = program->vertex->parseData;
459
const MOJOSHADER_attribute *a = pd->attributes;
460
461
462
for (i = 0; i < pd->attribute_count; i++)
{
463
const GLint loc = ctx->glGetAttribLocation(program->handle, a->name);
464
465
466
467
if (loc != -1) // maybe the Attribute was optimized out?
{
AttributeMap *map = &program->attributes[program->attribute_count];
map->attribute = &a[i];
468
map->location = (GLuint) loc;
469
470
471
472
473
474
program->attribute_count++;
} // if
} // for
} // lookup_attributes
475
476
477
MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader,
MOJOSHADER_glShader *pshader)
{
478
479
480
if ((vshader == NULL) && (pshader == NULL))
return NULL;
481
MOJOSHADER_glProgram *retval = NULL;
482
const GLhandleARB program = ctx->glCreateProgramObject();
483
484
485
if (vshader != NULL) ctx->glAttachObject(program, vshader->handle);
if (pshader != NULL) ctx->glAttachObject(program, pshader->handle);
486
487
ctx->glLinkProgram(program);
488
489
GLint ok = 0;
490
ctx->glGetObjectParameteriv(program, GL_OBJECT_LINK_STATUS_ARB, &ok);
491
492
493
if (!ok)
{
GLsizei len = 0;
494
ctx->glGetInfoLog(program, sizeof (error_buffer), &len, (GLchar *) error_buffer);
495
496
goto link_program_fail;
} // if
497
498
499
retval = (MOJOSHADER_glProgram *) Malloc(sizeof (MOJOSHADER_glProgram));
if (retval == NULL)
500
501
goto link_program_fail;
memset(retval, '\0', sizeof (MOJOSHADER_glProgram));
502
503
504
505
int numregs = 0;
if (vshader != NULL) numregs += vshader->parseData->uniform_count;
if (pshader != NULL) numregs += pshader->parseData->uniform_count;
506
507
508
retval->uniforms = (UniformMap *) Malloc(sizeof (UniformMap) * numregs);
if (retval->uniforms == NULL)
goto link_program_fail;
509
memset(retval->uniforms, '\0', sizeof (UniformMap) * numregs);
510
511
512
513
514
retval->handle = program;
retval->vertex = vshader;
retval->fragment = pshader;
retval->refcount = 1;
515
516
if (vshader != NULL)
517
{
518
519
520
521
522
523
retval->attributes = (AttributeMap *) Malloc(sizeof (AttributeMap) *
vshader->parseData->attribute_count);
if (retval->attributes == NULL)
goto link_program_fail;
lookup_attributes(retval);
524
lookup_uniforms(retval, vshader);
525
vshader->refcount++;
526
527
} // if
528
if (pshader != NULL)
529
530
{
lookup_uniforms(retval, pshader);
531
pshader->refcount++;
532
} // if
533
534
return retval;
535
536
537
538
link_program_fail:
if (retval != NULL)
{
539
540
Free(retval->uniforms);
Free(retval->attributes);
541
542
543
Free(retval);
} // if
544
ctx->glDeleteObject(program);
545
return NULL;
546
547
548
549
550
} // MOJOSHADER_glLinkProgram
void MOJOSHADER_glBindProgram(MOJOSHADER_glProgram *program)
{
551
GLhandleARB handle = 0;
552
int i;
553
554
if (program == ctx->bound_program)
555
556
557
return; // nothing to do.
// Disable any client-side arrays the current program could have used.
558
559
// !!! FIXME: don't disable yet...see which ones get reused, and disable
// !!! FIXME: only what we don't need in MOJOSHADER_glProgramReady().
560
if (ctx->bound_program != NULL)
561
{
562
563
const int count = ctx->bound_program->attribute_count;
for (i = 0; i < count; i++)
564
{
565
566
const AttributeMap *map = &ctx->bound_program->attributes[i];
ctx->glDisableVertexAttribArray(map->location);
567
568
569
} // if
} // for
570
571
572
573
574
575
if (program != NULL)
{
handle = program->handle;
program->refcount++;
} // if
576
577
578
ctx->glUseProgramObject(handle);
program_unref(ctx->bound_program);
ctx->bound_program = program;
579
580
581
} // MOJOSHADER_glBindProgram
582
583
584
585
586
587
static inline uint maxuint(const uint a, const uint b)
{
return ((a > b) ? a : b);
} // maxuint
588
void MOJOSHADER_glSetVertexShaderUniformF(unsigned int idx, const float *data,
589
unsigned int vec4n)
590
{
591
const uint maxregs = STATICARRAYLEN(ctx->vs_reg_file_f) / 4;
592
593
if (idx < maxregs)
{
594
const uint cpy = (maxuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
595
memcpy(ctx->vs_reg_file_f + (idx * 4), data, cpy);
596
} // if
597
598
599
600
} // MOJOSHADER_glSetVertexShaderUniformF
void MOJOSHADER_glSetVertexShaderUniformI(unsigned int idx, const int *data,
601
unsigned int ivec4n)
602
{
603
const uint maxregs = STATICARRAYLEN(ctx->vs_reg_file_i) / 4;
604
605
if (idx < maxregs)
{
606
const uint cpy = (maxuint(maxregs - idx, ivec4n) * sizeof (*data)) * 4;
607
memcpy(ctx->vs_reg_file_i + (idx * 4), data, cpy);
608
} // if
609
610
611
612
613
614
} // MOJOSHADER_glSetVertexShaderUniformI
void MOJOSHADER_glSetVertexShaderUniformB(unsigned int idx, const int *data,
unsigned int bcount)
{
615
const uint maxregs = STATICARRAYLEN(ctx->vs_reg_file_f) / 4;
616
617
if (idx < maxregs)
{
618
uint8 *wptr = ctx->vs_reg_file_b + idx;
619
620
621
622
uint8 *endptr = wptr + maxuint(maxregs - idx, bcount);
while (wptr != endptr)
*(wptr++) = *(data++) ? 1 : 0;
} // if
623
624
625
626
} // MOJOSHADER_glSetVertexShaderUniformB
void MOJOSHADER_glSetPixelShaderUniformF(unsigned int idx, const float *data,
627
unsigned int vec4n)
628
{
629
const uint maxregs = STATICARRAYLEN(ctx->ps_reg_file_f) / 4;
630
631
if (idx < maxregs)
{
632
const uint cpy = (maxuint(maxregs - idx, vec4n) * sizeof (*data)) * 4;
633
memcpy(ctx->ps_reg_file_f + (idx * 4), data, cpy);
634
} // if
635
636
637
638
} // MOJOSHADER_glSetPixelShaderUniformF
void MOJOSHADER_glSetPixelShaderUniformI(unsigned int idx, const int *data,
639
unsigned int ivec4n)
640
{
641
const uint maxregs = STATICARRAYLEN(ctx->ps_reg_file_i) / 4;
642
643
if (idx < maxregs)
{
644
const uint cpy = (maxuint(maxregs - idx, ivec4n) * sizeof (*data)) * 4;
645
memcpy(ctx->ps_reg_file_i + (idx * 4), data, cpy);
646
} // if
647
648
649
650
} // MOJOSHADER_glSetPixelShaderUniformI
void MOJOSHADER_glSetPixelShaderUniformB(unsigned int idx, const int *data,
651
unsigned int bcount)
652
{
653
const uint maxregs = STATICARRAYLEN(ctx->ps_reg_file_f) / 4;
654
655
if (idx < maxregs)
{
656
uint8 *wptr = ctx->ps_reg_file_b + idx;
657
658
659
660
uint8 *endptr = wptr + maxuint(maxregs - idx, bcount);
while (wptr != endptr)
*(wptr++) = *(data++) ? 1 : 0;
} // if
661
662
663
} // MOJOSHADER_glSetPixelShaderUniformB
664
665
666
667
static inline GLenum opengl_attr_type(const MOJOSHADER_attributeType type)
{
switch (type)
{
668
case MOJOSHADER_ATTRIBUTE_UNKNOWN: return GL_NONE; // oh well.
669
670
671
case MOJOSHADER_ATTRIBUTE_BYTE: return GL_BYTE;
case MOJOSHADER_ATTRIBUTE_UBYTE: return GL_UNSIGNED_BYTE;
case MOJOSHADER_ATTRIBUTE_SHORT: return GL_SHORT;
672
case MOJOSHADER_ATTRIBUTE_USHORT: return GL_UNSIGNED_SHORT;
673
674
675
676
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;
677
678
case MOJOSHADER_ATTRIBUTE_HALF_FLOAT:
679
if (ctx->have_GL_NV_half_float)
680
681
return GL_HALF_FLOAT_NV;
break;
682
683
684
685
686
687
} // switch
return GL_NONE; // oh well. Raises a GL error later.
} // opengl_attr_type
688
689
690
691
692
693
void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage,
int index, unsigned int size,
MOJOSHADER_attributeType type,
int normalized, unsigned int stride,
const void *ptr)
{
694
if ((ctx->bound_program == NULL) || (ctx->bound_program->vertex == NULL))
695
696
return;
697
698
699
const GLenum gl_type = opengl_attr_type(type);
const GLboolean norm = (normalized) ? GL_TRUE : GL_FALSE;
GLuint gl_index = 0;
700
701
702
703
// 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.
704
705
if ((usage != MOJOSHADER_USAGE_POSITION) || (index != 0))
706
{
707
708
709
710
711
712
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;
713
714
715
// !!! FIXME: is this array guaranteed to be sorted by usage?
// !!! FIXME: if so, we can break if a->usage > usage.
716
717
718
719
720
721
722
if ((a->usage == usage) && (a->index == index))
{
gl_index = map->location;
break;
} // if
} // for
723
724
725
if (gl_index == 0)
return; // nothing to do, this shader doesn't use this stream.
726
} // if
727
728
729
ctx->glVertexAttribPointer(gl_index, size, gl_type, norm, stride, ptr);
ctx->glEnableVertexAttribArray(gl_index);
730
731
732
733
734
} // MOJOSHADER_glSetVertexAttribute
void MOJOSHADER_glProgramReady(void)
{
735
736
int i;
737
if (ctx->bound_program == NULL)
738
739
740
741
742
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...
743
744
const int count = ctx->bound_program->uniform_count;
for (i = 0; i < count; i++)
745
{
746
const UniformMap *map = &ctx->bound_program->uniforms[i];
747
748
749
750
751
752
753
754
755
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)
756
ctx->glUniform4fv(location, 1, &ctx->vs_reg_file_f[index * 4]);
757
else if (type == MOJOSHADER_UNIFORM_INT)
758
ctx->glUniform4iv(location, 1, &ctx->vs_reg_file_i[index * 4]);
759
else if (type == MOJOSHADER_UNIFORM_BOOL)
760
ctx->glUniform1i(location, ctx->vs_reg_file_b[index]);
761
762
763
764
765
} // if
else if (shader_type == MOJOSHADER_TYPE_PIXEL)
{
if (type == MOJOSHADER_UNIFORM_FLOAT)
766
ctx->glUniform4fv(location, 1, &ctx->ps_reg_file_f[index * 4]);
767
else if (type == MOJOSHADER_UNIFORM_INT)
768
ctx->glUniform4iv(location, 1, &ctx->ps_reg_file_i[index * 4]);
769
else if (type == MOJOSHADER_UNIFORM_BOOL)
770
ctx->glUniform1i(location, ctx->ps_reg_file_b[index]);
771
772
} // else if
} // for
773
774
775
} // MOJOSHADER_glProgramReady
776
void MOJOSHADER_glDeleteProgram(MOJOSHADER_glProgram *program)
777
{
778
program_unref(program);
779
780
781
} // MOJOSHADER_glDeleteProgram
782
void MOJOSHADER_glDeleteShader(MOJOSHADER_glShader *shader)
783
784
785
786
787
{
shader_unref(shader);
} // MOJOSHADER_glDeleteShader
788
void MOJOSHADER_glDestroyContext(MOJOSHADER_glContext *_ctx)
789
{
790
791
MOJOSHADER_glContext *current_ctx = ctx;
ctx = _ctx;
792
MOJOSHADER_glBindProgram(NULL);
793
lookup_entry_points(NULL);
794
795
Free(ctx);
ctx = ((current_ctx == _ctx) ? NULL : current_ctx);
796
} // MOJOSHADER_glDestroyContext
797
798
// end of mojoshader_opengl.c ...