1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Shader API.
12 *
13 * See LICENSE.txt for copyright information.
14 */
15
16 #include "allegro5/allegro.h"
17 #include "allegro5/internal/aintern_bitmap.h"
18 #include "allegro5/internal/aintern_display.h"
19 #include "allegro5/internal/aintern_dtor.h"
20 #include "allegro5/internal/aintern_shader.h"
21 #include "allegro5/internal/aintern_system.h"
22
23 #ifdef ALLEGRO_CFG_SHADER_GLSL
24 #include "allegro5/allegro_opengl.h"
25 #endif
26
27 ALLEGRO_DEBUG_CHANNEL("shader")
28
29 #include "shader_source.inc"
30
31
resolve_platform(ALLEGRO_SHADER_PLATFORM platform)32 static ALLEGRO_SHADER_PLATFORM resolve_platform(ALLEGRO_SHADER_PLATFORM platform)
33 {
34 if (platform == ALLEGRO_SHADER_AUTO) {
35 ALLEGRO_DISPLAY *display = al_get_current_display();
36 ASSERT(display);
37 if (al_get_display_flags(display) & ALLEGRO_OPENGL) {
38 platform = ALLEGRO_SHADER_GLSL;
39 }
40 else {
41 platform = ALLEGRO_SHADER_HLSL;
42 }
43 }
44
45 return platform;
46 }
47
48 /* Function: al_create_shader
49 */
al_create_shader(ALLEGRO_SHADER_PLATFORM platform)50 ALLEGRO_SHADER *al_create_shader(ALLEGRO_SHADER_PLATFORM platform)
51 {
52 ALLEGRO_SHADER *shader = NULL;
53
54 platform = resolve_platform(platform);
55
56 if (false) {
57 }
58 #ifdef ALLEGRO_CFG_SHADER_GLSL
59 else if (platform == ALLEGRO_SHADER_GLSL) {
60 shader = _al_create_shader_glsl(platform);
61 }
62 #endif
63 #ifdef ALLEGRO_CFG_SHADER_HLSL
64 else if (platform == ALLEGRO_SHADER_HLSL) {
65 shader = _al_create_shader_hlsl(platform);
66 }
67 #endif
68
69 if (shader) {
70 ASSERT(shader->platform);
71 ASSERT(shader->vt);
72 shader->dtor_item = _al_register_destructor(_al_dtor_list, "shader", shader,
73 (void (*)(void *))al_destroy_shader);
74 }
75 else {
76 ALLEGRO_WARN("Failed to create shader\n");
77 }
78 return shader;
79 }
80
81 /* Function: al_attach_shader_source
82 */
al_attach_shader_source(ALLEGRO_SHADER * shader,ALLEGRO_SHADER_TYPE type,const char * source)83 bool al_attach_shader_source(ALLEGRO_SHADER *shader, ALLEGRO_SHADER_TYPE type,
84 const char *source)
85 {
86 ASSERT(shader);
87 return shader->vt->attach_shader_source(shader, type, source);
88 }
89
90 /* Function: al_attach_shader_source_file
91 */
al_attach_shader_source_file(ALLEGRO_SHADER * shader,ALLEGRO_SHADER_TYPE type,const char * filename)92 bool al_attach_shader_source_file(ALLEGRO_SHADER *shader,
93 ALLEGRO_SHADER_TYPE type, const char *filename)
94 {
95 ALLEGRO_FILE *fp;
96 ALLEGRO_USTR *str;
97 bool ret;
98
99 fp = al_fopen(filename, "r");
100 if (!fp) {
101 ALLEGRO_WARN("Failed to open %s\n", filename);
102 al_ustr_free(shader->log);
103 shader->log = al_ustr_newf("Failed to open %s", filename);
104 return false;
105 }
106 str = al_ustr_new("");
107 for (;;) {
108 char buf[512];
109 size_t n;
110 ALLEGRO_USTR_INFO info;
111
112 n = al_fread(fp, buf, sizeof(buf));
113 if (n <= 0)
114 break;
115 al_ustr_append(str, al_ref_buffer(&info, buf, n));
116 }
117 al_fclose(fp);
118 ret = al_attach_shader_source(shader, type, al_cstr(str));
119 al_ustr_free(str);
120 return ret;
121 }
122
123 /* Function: al_build_shader
124 */
al_build_shader(ALLEGRO_SHADER * shader)125 bool al_build_shader(ALLEGRO_SHADER *shader)
126 {
127 ASSERT(shader);
128 return shader->vt->build_shader(shader);
129 }
130
131 /* Function: al_get_shader_log
132 */
al_get_shader_log(ALLEGRO_SHADER * shader)133 const char *al_get_shader_log(ALLEGRO_SHADER *shader)
134 {
135 ASSERT(shader);
136
137 return (shader->log) ? al_cstr(shader->log) : "";
138 }
139
140 /* Function: al_get_shader_platform
141 */
al_get_shader_platform(ALLEGRO_SHADER * shader)142 ALLEGRO_SHADER_PLATFORM al_get_shader_platform(ALLEGRO_SHADER *shader)
143 {
144 ASSERT(shader);
145 return shader->platform;
146 }
147
148 /* Function: al_use_shader
149 */
al_use_shader(ALLEGRO_SHADER * shader)150 bool al_use_shader(ALLEGRO_SHADER *shader)
151 {
152 ALLEGRO_BITMAP *bmp = al_get_target_bitmap();
153 ALLEGRO_DISPLAY *disp;
154
155 if (!bmp) {
156 ALLEGRO_WARN("No current target bitmap.\n");
157 return false;
158 }
159 if (al_get_bitmap_flags(bmp) & ALLEGRO_MEMORY_BITMAP) {
160 ALLEGRO_WARN("Target bitmap is memory bitmap.\n");
161 return false;
162 }
163 disp = _al_get_bitmap_display(bmp);
164 ASSERT(disp);
165
166 if (shader) {
167 if (shader->vt->use_shader(shader, disp, true)) {
168 _al_set_bitmap_shader_field(bmp, shader);
169 ALLEGRO_DEBUG("use_shader succeeded\n");
170 return true;
171 }
172 else {
173 _al_set_bitmap_shader_field(bmp, NULL);
174 ALLEGRO_ERROR("use_shader failed\n");
175 if (disp->default_shader) {
176 disp->default_shader->vt->use_shader(
177 disp->default_shader, disp, true);
178 }
179 return false;
180 }
181 }
182 else {
183 if (bmp->shader) {
184 bmp->shader->vt->unuse_shader(bmp->shader, disp);
185 _al_set_bitmap_shader_field(bmp, NULL);
186 }
187 if (disp->default_shader) {
188 disp->default_shader->vt->use_shader(
189 disp->default_shader, disp, true);
190 }
191 return true;
192 }
193 }
194
195 /* Function: al_destroy_shader
196 */
al_destroy_shader(ALLEGRO_SHADER * shader)197 void al_destroy_shader(ALLEGRO_SHADER *shader)
198 {
199 ALLEGRO_BITMAP *bmp;
200 unsigned i;
201
202 if (!shader)
203 return;
204
205 /* As a convenience, implicitly unuse the shader on the target bitmap
206 * if currently used.
207 */
208 bmp = al_get_target_bitmap();
209 if (bmp && _al_vector_contains(&shader->bitmaps, &bmp)) {
210 ALLEGRO_DEBUG("implicitly unusing shader on target bitmap\n");
211 al_use_shader(NULL);
212 }
213
214 _al_unregister_destructor(_al_dtor_list, shader->dtor_item);
215
216 al_ustr_free(shader->vertex_copy);
217 shader->vertex_copy = NULL;
218 al_ustr_free(shader->pixel_copy);
219 shader->pixel_copy = NULL;
220 al_ustr_free(shader->log);
221 shader->log = NULL;
222
223 /* Clear references to this shader from all bitmaps. */
224 for (i = 0; i < _al_vector_size(&shader->bitmaps); i++) {
225 ALLEGRO_BITMAP **slot = _al_vector_ref(&shader->bitmaps, i);
226 ALLEGRO_BITMAP *bitmap = *slot;
227 ASSERT(bitmap->shader == shader);
228 bitmap->shader = NULL;
229 }
230 _al_vector_free(&shader->bitmaps);
231
232 shader->vt->destroy_shader(shader);
233 }
234
235 /* Function: al_set_shader_sampler
236 */
al_set_shader_sampler(const char * name,ALLEGRO_BITMAP * bitmap,int unit)237 bool al_set_shader_sampler(const char *name,
238 ALLEGRO_BITMAP *bitmap, int unit)
239 {
240 ALLEGRO_BITMAP *bmp;
241 ALLEGRO_SHADER *shader;
242
243 if ((bmp = al_get_target_bitmap()) != NULL) {
244 if ((shader = bmp->shader) != NULL) {
245 return shader->vt->set_shader_sampler(shader, name, bitmap, unit);
246 }
247 else {
248 return false;
249 }
250 }
251 else {
252 return false;
253 }
254 }
255
256 /* Function: al_set_shader_matrix
257 */
al_set_shader_matrix(const char * name,const ALLEGRO_TRANSFORM * matrix)258 bool al_set_shader_matrix(const char *name,
259 const ALLEGRO_TRANSFORM *matrix)
260 {
261 ALLEGRO_BITMAP *bmp;
262 ALLEGRO_SHADER *shader;
263
264 if ((bmp = al_get_target_bitmap()) != NULL) {
265 if ((shader = bmp->shader) != NULL) {
266 return shader->vt->set_shader_matrix(shader, name, matrix);
267 }
268 else {
269 return false;
270 }
271 }
272 else {
273 return false;
274 }
275 }
276
277 /* Function: al_set_shader_int
278 */
al_set_shader_int(const char * name,int i)279 bool al_set_shader_int(const char *name, int i)
280 {
281 ALLEGRO_BITMAP *bmp;
282 ALLEGRO_SHADER *shader;
283
284 if ((bmp = al_get_target_bitmap()) != NULL) {
285 if ((shader = bmp->shader) != NULL) {
286 return shader->vt->set_shader_int(shader, name, i);
287 }
288 else {
289 return false;
290 }
291 }
292 else {
293 return false;
294 }
295 }
296
297 /* Function: al_set_shader_float
298 */
al_set_shader_float(const char * name,float f)299 bool al_set_shader_float(const char *name, float f)
300 {
301 ALLEGRO_BITMAP *bmp;
302 ALLEGRO_SHADER *shader;
303
304 if ((bmp = al_get_target_bitmap()) != NULL) {
305 if ((shader = bmp->shader) != NULL) {
306 return shader->vt->set_shader_float(shader, name, f);
307 }
308 else {
309 return false;
310 }
311 }
312 else {
313 return false;
314 }
315 }
316
317 /* Function: al_set_shader_int_vector
318 */
al_set_shader_int_vector(const char * name,int num_components,const int * i,int num_elems)319 bool al_set_shader_int_vector(const char *name,
320 int num_components, const int *i, int num_elems)
321 {
322 ALLEGRO_BITMAP *bmp;
323 ALLEGRO_SHADER *shader;
324
325 if ((bmp = al_get_target_bitmap()) != NULL) {
326 if ((shader = bmp->shader) != NULL) {
327 return shader->vt->set_shader_int_vector(shader, name, num_components, i, num_elems);
328 }
329 else {
330 return false;
331 }
332 }
333 else {
334 return false;
335 }
336 }
337
338 /* Function: al_set_shader_float_vector
339 */
al_set_shader_float_vector(const char * name,int num_components,const float * f,int num_elems)340 bool al_set_shader_float_vector(const char *name,
341 int num_components, const float *f, int num_elems)
342 {
343 ALLEGRO_BITMAP *bmp;
344 ALLEGRO_SHADER *shader;
345
346 if ((bmp = al_get_target_bitmap()) != NULL) {
347 if ((shader = bmp->shader) != NULL) {
348 return shader->vt->set_shader_float_vector(shader, name, num_components, f, num_elems);
349 }
350 else {
351 return false;
352 }
353 }
354 else {
355 return false;
356 }
357 }
358
359 /* Function: al_set_shader_bool
360 */
al_set_shader_bool(const char * name,bool b)361 bool al_set_shader_bool(const char *name, bool b)
362 {
363 ALLEGRO_BITMAP *bmp;
364 ALLEGRO_SHADER *shader;
365
366 if ((bmp = al_get_target_bitmap()) != NULL) {
367 if ((shader = bmp->shader) != NULL) {
368 return shader->vt->set_shader_bool(shader, name, b);
369 }
370 else {
371 return false;
372 }
373 }
374 else {
375 return false;
376 }
377 }
378
379 /* Function: al_get_default_shader_source
380 */
al_get_default_shader_source(ALLEGRO_SHADER_PLATFORM platform,ALLEGRO_SHADER_TYPE type)381 char const *al_get_default_shader_source(ALLEGRO_SHADER_PLATFORM platform,
382 ALLEGRO_SHADER_TYPE type)
383 {
384 (void)type;
385 switch (resolve_platform(platform)) {
386 case ALLEGRO_SHADER_GLSL:
387 #ifdef ALLEGRO_CFG_SHADER_GLSL
388 switch (type) {
389 case ALLEGRO_VERTEX_SHADER:
390 return default_glsl_vertex_source;
391 case ALLEGRO_PIXEL_SHADER:
392 return default_glsl_pixel_source;
393 }
394 #endif
395 break;
396
397 case ALLEGRO_SHADER_HLSL:
398 #ifdef ALLEGRO_CFG_SHADER_HLSL
399 switch (type) {
400 case ALLEGRO_VERTEX_SHADER:
401 return default_hlsl_vertex_source;
402 case ALLEGRO_PIXEL_SHADER:
403 return default_hlsl_pixel_source;
404 }
405 #endif
406 break;
407
408 case ALLEGRO_SHADER_AUTO:
409 ASSERT(0);
410 }
411 return NULL;
412 }
413
_al_set_bitmap_shader_field(ALLEGRO_BITMAP * bmp,ALLEGRO_SHADER * shader)414 void _al_set_bitmap_shader_field(ALLEGRO_BITMAP *bmp, ALLEGRO_SHADER *shader)
415 {
416 ASSERT(bmp);
417
418 if (bmp->shader != shader) {
419 if (bmp->shader) {
420 _al_unregister_shader_bitmap(bmp->shader, bmp);
421 }
422 bmp->shader = shader;
423 if (bmp->shader) {
424 _al_register_shader_bitmap(bmp->shader, bmp);
425 }
426 }
427 }
428
_al_register_shader_bitmap(ALLEGRO_SHADER * shader,ALLEGRO_BITMAP * bmp)429 void _al_register_shader_bitmap(ALLEGRO_SHADER *shader, ALLEGRO_BITMAP *bmp)
430 {
431 ALLEGRO_BITMAP **slot;
432 ASSERT(shader);
433 ASSERT(bmp);
434
435 slot = _al_vector_alloc_back(&shader->bitmaps);
436 *slot = bmp;
437 }
438
_al_unregister_shader_bitmap(ALLEGRO_SHADER * shader,ALLEGRO_BITMAP * bmp)439 void _al_unregister_shader_bitmap(ALLEGRO_SHADER *shader, ALLEGRO_BITMAP *bmp)
440 {
441 bool deleted;
442 ASSERT(shader);
443 ASSERT(bmp);
444
445 deleted = _al_vector_find_and_delete(&shader->bitmaps, &bmp);
446 ASSERT(deleted);
447 }
448
_al_create_default_shader(int display_flags)449 ALLEGRO_SHADER *_al_create_default_shader(int display_flags)
450 {
451 ALLEGRO_SHADER_PLATFORM platform = ALLEGRO_SHADER_AUTO;
452 ALLEGRO_SHADER *shader;
453 (void)display_flags;
454
455 if (false) {
456 }
457 #ifdef ALLEGRO_CFG_SHADER_GLSL
458 else if (display_flags & ALLEGRO_OPENGL) {
459 platform = ALLEGRO_SHADER_GLSL;
460 }
461 #endif
462 #ifdef ALLEGRO_CFG_SHADER_HLSL
463 else if (display_flags & ALLEGRO_DIRECT3D_INTERNAL) {
464 platform = ALLEGRO_SHADER_HLSL;
465 }
466 #endif
467
468 if (platform == ALLEGRO_SHADER_AUTO) {
469 ALLEGRO_ERROR("No suitable shader platform found for creating the default shader.\n");
470 return false;
471 }
472
473 _al_push_destructor_owner();
474 shader = al_create_shader(platform);
475 _al_pop_destructor_owner();
476
477 if (!shader) {
478 ALLEGRO_ERROR("Error creating default shader.\n");
479 return false;
480 }
481 if (!al_attach_shader_source(shader, ALLEGRO_VERTEX_SHADER,
482 al_get_default_shader_source(platform, ALLEGRO_VERTEX_SHADER))) {
483 ALLEGRO_ERROR("al_attach_shader_source for vertex shader failed: %s\n",
484 al_get_shader_log(shader));
485 goto fail;
486 }
487 if (!al_attach_shader_source(shader, ALLEGRO_PIXEL_SHADER,
488 al_get_default_shader_source(platform, ALLEGRO_PIXEL_SHADER))) {
489 ALLEGRO_ERROR("al_attach_shader_source for pixel shader failed: %s\n",
490 al_get_shader_log(shader));
491 goto fail;
492 }
493 if (!al_build_shader(shader)) {
494 ALLEGRO_ERROR("al_build_shader failed: %s\n", al_get_shader_log(shader));
495 goto fail;
496 }
497 return shader;
498
499 fail:
500 al_destroy_shader(shader);
501 return NULL;
502 }
503
504 /* vim: set sts=3 sw=3 et: */
505