1 /******************************************************************************
2 Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18 #include <assert.h>
19
20 #include "../util/base.h"
21 #include "../util/bmem.h"
22 #include "../util/platform.h"
23 #include "graphics-internal.h"
24 #include "vec2.h"
25 #include "vec3.h"
26 #include "quat.h"
27 #include "axisang.h"
28 #include "effect-parser.h"
29 #include "effect.h"
30
31 #ifdef _MSC_VER
32 #undef near
33 #undef far
34 #endif
35
36 static THREAD_LOCAL graphics_t *thread_graphics = NULL;
37
gs_obj_valid(const void * obj,const char * f,const char * name)38 static inline bool gs_obj_valid(const void *obj, const char *f,
39 const char *name)
40 {
41 if (!obj) {
42 blog(LOG_DEBUG, "%s: Null '%s' parameter", f, name);
43 return false;
44 }
45
46 return true;
47 }
48
gs_valid(const char * f)49 static inline bool gs_valid(const char *f)
50 {
51 if (!thread_graphics) {
52 blog(LOG_DEBUG, "%s: called while not in a graphics context",
53 f);
54 return false;
55 }
56
57 return true;
58 }
59
60 #define ptr_valid(ptr, func) gs_obj_valid(ptr, func, #ptr)
61
62 #define gs_valid_p(func, param1) (gs_valid(func) && ptr_valid(param1, func))
63
64 #define gs_valid_p2(func, param1, param2) \
65 (gs_valid(func) && ptr_valid(param1, func) && ptr_valid(param2, func))
66
67 #define gs_valid_p3(func, param1, param2, param3) \
68 (gs_valid(func) && ptr_valid(param1, func) && \
69 ptr_valid(param2, func) && ptr_valid(param3, func))
70
71 #define IMMEDIATE_COUNT 512
72
gs_enum_adapters(bool (* callback)(void * param,const char * name,uint32_t id),void * param)73 void gs_enum_adapters(bool (*callback)(void *param, const char *name,
74 uint32_t id),
75 void *param)
76 {
77 graphics_t *graphics = thread_graphics;
78
79 if (!gs_valid_p("gs_enum_adapters", callback))
80 return;
81
82 if (graphics->exports.device_enum_adapters) {
83 if (graphics->exports.device_enum_adapters(callback, param)) {
84 return;
85 }
86 }
87
88 /* If the subsystem does not currently support device enumeration of
89 * adapters or fails to enumerate adapters, just set it to one adapter
90 * named "Default" */
91 callback(param, "Default", 0);
92 }
93
94 extern void gs_init_image_deps(void);
95 extern void gs_free_image_deps(void);
96
97 bool load_graphics_imports(struct gs_exports *exports, void *module,
98 const char *module_name);
99
graphics_init_immediate_vb(struct graphics_subsystem * graphics)100 static bool graphics_init_immediate_vb(struct graphics_subsystem *graphics)
101 {
102 struct gs_vb_data *vbd;
103
104 vbd = gs_vbdata_create();
105 vbd->num = IMMEDIATE_COUNT;
106 vbd->points = bmalloc(sizeof(struct vec3) * IMMEDIATE_COUNT);
107 vbd->normals = bmalloc(sizeof(struct vec3) * IMMEDIATE_COUNT);
108 vbd->colors = bmalloc(sizeof(uint32_t) * IMMEDIATE_COUNT);
109 vbd->num_tex = 1;
110 vbd->tvarray = bmalloc(sizeof(struct gs_tvertarray));
111 vbd->tvarray[0].width = 2;
112 vbd->tvarray[0].array = bmalloc(sizeof(struct vec2) * IMMEDIATE_COUNT);
113
114 graphics->immediate_vertbuffer =
115 graphics->exports.device_vertexbuffer_create(graphics->device,
116 vbd, GS_DYNAMIC);
117 if (!graphics->immediate_vertbuffer)
118 return false;
119
120 return true;
121 }
122
graphics_init_sprite_vb(struct graphics_subsystem * graphics)123 static bool graphics_init_sprite_vb(struct graphics_subsystem *graphics)
124 {
125 struct gs_vb_data *vbd;
126
127 vbd = gs_vbdata_create();
128 vbd->num = 4;
129 vbd->points = bmalloc(sizeof(struct vec3) * 4);
130 vbd->num_tex = 1;
131 vbd->tvarray = bmalloc(sizeof(struct gs_tvertarray));
132 vbd->tvarray[0].width = 2;
133 vbd->tvarray[0].array = bmalloc(sizeof(struct vec2) * 4);
134
135 memset(vbd->points, 0, sizeof(struct vec3) * 4);
136 memset(vbd->tvarray[0].array, 0, sizeof(struct vec2) * 4);
137
138 graphics->sprite_buffer = graphics->exports.device_vertexbuffer_create(
139 graphics->device, vbd, GS_DYNAMIC);
140 if (!graphics->sprite_buffer)
141 return false;
142
143 return true;
144 }
145
graphics_init(struct graphics_subsystem * graphics)146 static bool graphics_init(struct graphics_subsystem *graphics)
147 {
148 struct matrix4 top_mat;
149
150 matrix4_identity(&top_mat);
151 da_push_back(graphics->matrix_stack, &top_mat);
152
153 graphics->exports.device_enter_context(graphics->device);
154
155 if (!graphics_init_immediate_vb(graphics))
156 return false;
157 if (!graphics_init_sprite_vb(graphics))
158 return false;
159 if (pthread_mutex_init(&graphics->mutex, NULL) != 0)
160 return false;
161 if (pthread_mutex_init(&graphics->effect_mutex, NULL) != 0)
162 return false;
163
164 graphics->exports.device_blend_function_separate(
165 graphics->device, GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA,
166 GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
167 graphics->cur_blend_state.enabled = true;
168 graphics->cur_blend_state.src_c = GS_BLEND_SRCALPHA;
169 graphics->cur_blend_state.dest_c = GS_BLEND_INVSRCALPHA;
170 graphics->cur_blend_state.src_a = GS_BLEND_ONE;
171 graphics->cur_blend_state.dest_a = GS_BLEND_INVSRCALPHA;
172
173 graphics->exports.device_leave_context(graphics->device);
174
175 gs_init_image_deps();
176 return true;
177 }
178
gs_create(graphics_t ** pgraphics,const char * module,uint32_t adapter)179 int gs_create(graphics_t **pgraphics, const char *module, uint32_t adapter)
180 {
181 int errcode = GS_ERROR_FAIL;
182
183 graphics_t *graphics = bzalloc(sizeof(struct graphics_subsystem));
184 pthread_mutex_init_value(&graphics->mutex);
185 pthread_mutex_init_value(&graphics->effect_mutex);
186
187 graphics->module = os_dlopen(module);
188 if (!graphics->module) {
189 errcode = GS_ERROR_MODULE_NOT_FOUND;
190 goto error;
191 }
192
193 if (!load_graphics_imports(&graphics->exports, graphics->module,
194 module))
195 goto error;
196
197 errcode = graphics->exports.device_create(&graphics->device, adapter);
198 if (errcode != GS_SUCCESS)
199 goto error;
200
201 if (!graphics_init(graphics)) {
202 errcode = GS_ERROR_FAIL;
203 goto error;
204 }
205
206 *pgraphics = graphics;
207 return errcode;
208
209 error:
210 gs_destroy(graphics);
211 return errcode;
212 }
213
214 extern void gs_effect_actually_destroy(gs_effect_t *effect);
215
gs_destroy(graphics_t * graphics)216 void gs_destroy(graphics_t *graphics)
217 {
218 if (!ptr_valid(graphics, "gs_destroy"))
219 return;
220
221 while (thread_graphics)
222 gs_leave_context();
223
224 if (graphics->device) {
225 struct gs_effect *effect = graphics->first_effect;
226
227 thread_graphics = graphics;
228 graphics->exports.device_enter_context(graphics->device);
229
230 while (effect) {
231 struct gs_effect *next = effect->next;
232 gs_effect_actually_destroy(effect);
233 effect = next;
234 }
235
236 graphics->exports.gs_vertexbuffer_destroy(
237 graphics->sprite_buffer);
238 graphics->exports.gs_vertexbuffer_destroy(
239 graphics->immediate_vertbuffer);
240 graphics->exports.device_destroy(graphics->device);
241
242 thread_graphics = NULL;
243 }
244
245 pthread_mutex_destroy(&graphics->mutex);
246 pthread_mutex_destroy(&graphics->effect_mutex);
247 da_free(graphics->matrix_stack);
248 da_free(graphics->viewport_stack);
249 da_free(graphics->blend_state_stack);
250 if (graphics->module)
251 os_dlclose(graphics->module);
252 bfree(graphics);
253
254 gs_free_image_deps();
255 }
256
gs_enter_context(graphics_t * graphics)257 void gs_enter_context(graphics_t *graphics)
258 {
259 if (!ptr_valid(graphics, "gs_enter_context"))
260 return;
261
262 bool is_current = thread_graphics == graphics;
263 if (thread_graphics && !is_current) {
264 while (thread_graphics)
265 gs_leave_context();
266 }
267
268 if (!is_current) {
269 pthread_mutex_lock(&graphics->mutex);
270 graphics->exports.device_enter_context(graphics->device);
271 thread_graphics = graphics;
272 }
273
274 os_atomic_inc_long(&graphics->ref);
275 }
276
gs_leave_context(void)277 void gs_leave_context(void)
278 {
279 if (gs_valid("gs_leave_context")) {
280 if (!os_atomic_dec_long(&thread_graphics->ref)) {
281 graphics_t *graphics = thread_graphics;
282
283 graphics->exports.device_leave_context(
284 graphics->device);
285 pthread_mutex_unlock(&graphics->mutex);
286 thread_graphics = NULL;
287 }
288 }
289 }
290
gs_get_context(void)291 graphics_t *gs_get_context(void)
292 {
293 return thread_graphics;
294 }
295
gs_get_device_obj(void)296 void *gs_get_device_obj(void)
297 {
298 if (!gs_valid("gs_get_device_obj"))
299 return NULL;
300
301 return thread_graphics->exports.device_get_device_obj(
302 thread_graphics->device);
303 }
304
gs_get_device_name(void)305 const char *gs_get_device_name(void)
306 {
307 return gs_valid("gs_get_device_name")
308 ? thread_graphics->exports.device_get_name()
309 : NULL;
310 }
311
gs_get_device_type(void)312 int gs_get_device_type(void)
313 {
314 return gs_valid("gs_get_device_type")
315 ? thread_graphics->exports.device_get_type()
316 : -1;
317 }
318
top_matrix(graphics_t * graphics)319 static inline struct matrix4 *top_matrix(graphics_t *graphics)
320 {
321 return graphics->matrix_stack.array + graphics->cur_matrix;
322 }
323
gs_matrix_push(void)324 void gs_matrix_push(void)
325 {
326 graphics_t *graphics = thread_graphics;
327
328 if (!gs_valid("gs_matrix_push"))
329 return;
330
331 struct matrix4 mat, *top_mat = top_matrix(graphics);
332
333 memcpy(&mat, top_mat, sizeof(struct matrix4));
334 da_push_back(graphics->matrix_stack, &mat);
335 graphics->cur_matrix++;
336 }
337
gs_matrix_pop(void)338 void gs_matrix_pop(void)
339 {
340 graphics_t *graphics = thread_graphics;
341
342 if (!gs_valid("gs_matrix_pop"))
343 return;
344
345 if (graphics->cur_matrix == 0) {
346 blog(LOG_ERROR, "Tried to pop last matrix on stack");
347 return;
348 }
349
350 da_erase(graphics->matrix_stack, graphics->cur_matrix);
351 graphics->cur_matrix--;
352 }
353
gs_matrix_identity(void)354 void gs_matrix_identity(void)
355 {
356 struct matrix4 *top_mat;
357
358 if (!gs_valid("gs_matrix_identity"))
359 return;
360
361 top_mat = top_matrix(thread_graphics);
362 if (top_mat)
363 matrix4_identity(top_mat);
364 }
365
gs_matrix_transpose(void)366 void gs_matrix_transpose(void)
367 {
368 struct matrix4 *top_mat;
369
370 if (!gs_valid("gs_matrix_transpose"))
371 return;
372
373 top_mat = top_matrix(thread_graphics);
374 if (top_mat)
375 matrix4_transpose(top_mat, top_mat);
376 }
377
gs_matrix_set(const struct matrix4 * matrix)378 void gs_matrix_set(const struct matrix4 *matrix)
379 {
380 struct matrix4 *top_mat;
381
382 if (!gs_valid("gs_matrix_set"))
383 return;
384
385 top_mat = top_matrix(thread_graphics);
386 if (top_mat)
387 matrix4_copy(top_mat, matrix);
388 }
389
gs_matrix_get(struct matrix4 * dst)390 void gs_matrix_get(struct matrix4 *dst)
391 {
392 struct matrix4 *top_mat;
393
394 if (!gs_valid("gs_matrix_get"))
395 return;
396
397 top_mat = top_matrix(thread_graphics);
398 if (top_mat)
399 matrix4_copy(dst, top_mat);
400 }
401
gs_matrix_mul(const struct matrix4 * matrix)402 void gs_matrix_mul(const struct matrix4 *matrix)
403 {
404 struct matrix4 *top_mat;
405
406 if (!gs_valid("gs_matrix_mul"))
407 return;
408
409 top_mat = top_matrix(thread_graphics);
410 if (top_mat)
411 matrix4_mul(top_mat, matrix, top_mat);
412 }
413
gs_matrix_rotquat(const struct quat * rot)414 void gs_matrix_rotquat(const struct quat *rot)
415 {
416 struct matrix4 *top_mat;
417
418 if (!gs_valid("gs_matrix_rotquat"))
419 return;
420
421 top_mat = top_matrix(thread_graphics);
422 if (top_mat)
423 matrix4_rotate_i(top_mat, rot, top_mat);
424 }
425
gs_matrix_rotaa(const struct axisang * rot)426 void gs_matrix_rotaa(const struct axisang *rot)
427 {
428 struct matrix4 *top_mat;
429
430 if (!gs_valid("gs_matrix_rotaa"))
431 return;
432
433 top_mat = top_matrix(thread_graphics);
434 if (top_mat)
435 matrix4_rotate_aa_i(top_mat, rot, top_mat);
436 }
437
gs_matrix_translate(const struct vec3 * pos)438 void gs_matrix_translate(const struct vec3 *pos)
439 {
440 struct matrix4 *top_mat;
441
442 if (!gs_valid("gs_matrix_translate"))
443 return;
444
445 top_mat = top_matrix(thread_graphics);
446 if (top_mat)
447 matrix4_translate3v_i(top_mat, pos, top_mat);
448 }
449
gs_matrix_scale(const struct vec3 * scale)450 void gs_matrix_scale(const struct vec3 *scale)
451 {
452 struct matrix4 *top_mat;
453
454 if (!gs_valid("gs_matrix_scale"))
455 return;
456
457 top_mat = top_matrix(thread_graphics);
458 if (top_mat)
459 matrix4_scale_i(top_mat, scale, top_mat);
460 }
461
gs_matrix_rotaa4f(float x,float y,float z,float angle)462 void gs_matrix_rotaa4f(float x, float y, float z, float angle)
463 {
464 struct matrix4 *top_mat;
465 struct axisang aa;
466
467 if (!gs_valid("gs_matrix_rotaa4f"))
468 return;
469
470 top_mat = top_matrix(thread_graphics);
471 if (top_mat) {
472 axisang_set(&aa, x, y, z, angle);
473 matrix4_rotate_aa_i(top_mat, &aa, top_mat);
474 }
475 }
476
gs_matrix_translate3f(float x,float y,float z)477 void gs_matrix_translate3f(float x, float y, float z)
478 {
479 struct matrix4 *top_mat;
480 struct vec3 p;
481
482 if (!gs_valid("gs_matrix_translate3f"))
483 return;
484
485 top_mat = top_matrix(thread_graphics);
486 if (top_mat) {
487 vec3_set(&p, x, y, z);
488 matrix4_translate3v_i(top_mat, &p, top_mat);
489 }
490 }
491
gs_matrix_scale3f(float x,float y,float z)492 void gs_matrix_scale3f(float x, float y, float z)
493 {
494 struct matrix4 *top_mat = top_matrix(thread_graphics);
495 struct vec3 p;
496
497 if (top_mat) {
498 vec3_set(&p, x, y, z);
499 matrix4_scale_i(top_mat, &p, top_mat);
500 }
501 }
502
reset_immediate_arrays(graphics_t * graphics)503 static inline void reset_immediate_arrays(graphics_t *graphics)
504 {
505 da_init(graphics->verts);
506 da_init(graphics->norms);
507 da_init(graphics->colors);
508 for (size_t i = 0; i < 16; i++)
509 da_init(graphics->texverts[i]);
510 }
511
gs_render_start(bool b_new)512 void gs_render_start(bool b_new)
513 {
514 graphics_t *graphics = thread_graphics;
515
516 if (!gs_valid("gs_render_start"))
517 return;
518
519 graphics->using_immediate = !b_new;
520 reset_immediate_arrays(graphics);
521
522 if (b_new) {
523 graphics->vbd = gs_vbdata_create();
524 } else {
525 graphics->vbd = gs_vertexbuffer_get_data(
526 graphics->immediate_vertbuffer);
527 memset(graphics->vbd->colors, 0xFF,
528 sizeof(uint32_t) * IMMEDIATE_COUNT);
529
530 graphics->verts.array = graphics->vbd->points;
531 graphics->norms.array = graphics->vbd->normals;
532 graphics->colors.array = graphics->vbd->colors;
533 graphics->texverts[0].array = graphics->vbd->tvarray[0].array;
534
535 graphics->verts.capacity = IMMEDIATE_COUNT;
536 graphics->norms.capacity = IMMEDIATE_COUNT;
537 graphics->colors.capacity = IMMEDIATE_COUNT;
538 graphics->texverts[0].capacity = IMMEDIATE_COUNT;
539 }
540 }
541
min_size(const size_t a,const size_t b)542 static inline size_t min_size(const size_t a, const size_t b)
543 {
544 return (a < b) ? a : b;
545 }
546
gs_render_stop(enum gs_draw_mode mode)547 void gs_render_stop(enum gs_draw_mode mode)
548 {
549 graphics_t *graphics = thread_graphics;
550 size_t i, num;
551
552 if (!gs_valid("gs_render_stop"))
553 return;
554
555 num = graphics->verts.num;
556 if (!num) {
557 if (!graphics->using_immediate) {
558 da_free(graphics->verts);
559 da_free(graphics->norms);
560 da_free(graphics->colors);
561 for (i = 0; i < 16; i++)
562 da_free(graphics->texverts[i]);
563 gs_vbdata_destroy(graphics->vbd);
564 }
565
566 return;
567 }
568
569 if (graphics->norms.num &&
570 (graphics->norms.num != graphics->verts.num)) {
571 blog(LOG_ERROR, "gs_render_stop: normal count does "
572 "not match vertex count");
573 num = min_size(num, graphics->norms.num);
574 }
575
576 if (graphics->colors.num &&
577 (graphics->colors.num != graphics->verts.num)) {
578 blog(LOG_ERROR, "gs_render_stop: color count does "
579 "not match vertex count");
580 num = min_size(num, graphics->colors.num);
581 }
582
583 if (graphics->texverts[0].num &&
584 (graphics->texverts[0].num != graphics->verts.num)) {
585 blog(LOG_ERROR, "gs_render_stop: texture vertex count does "
586 "not match vertex count");
587 num = min_size(num, graphics->texverts[0].num);
588 }
589
590 if (graphics->using_immediate) {
591 gs_vertexbuffer_flush(graphics->immediate_vertbuffer);
592
593 gs_load_vertexbuffer(graphics->immediate_vertbuffer);
594 gs_load_indexbuffer(NULL);
595 gs_draw(mode, 0, (uint32_t)num);
596
597 reset_immediate_arrays(graphics);
598 } else {
599 gs_vertbuffer_t *vb = gs_render_save();
600
601 gs_load_vertexbuffer(vb);
602 gs_load_indexbuffer(NULL);
603 gs_draw(mode, 0, 0);
604
605 gs_vertexbuffer_destroy(vb);
606 }
607
608 graphics->vbd = NULL;
609 }
610
gs_render_save(void)611 gs_vertbuffer_t *gs_render_save(void)
612 {
613 graphics_t *graphics = thread_graphics;
614 size_t num_tex, i;
615
616 if (!gs_valid("gs_render_save"))
617 return NULL;
618 if (graphics->using_immediate)
619 return NULL;
620
621 if (!graphics->verts.num) {
622 gs_vbdata_destroy(graphics->vbd);
623 return NULL;
624 }
625
626 for (num_tex = 0; num_tex < 16; num_tex++)
627 if (!graphics->texverts[num_tex].num)
628 break;
629
630 graphics->vbd->points = graphics->verts.array;
631 graphics->vbd->normals = graphics->norms.array;
632 graphics->vbd->colors = graphics->colors.array;
633 graphics->vbd->num = graphics->verts.num;
634 graphics->vbd->num_tex = num_tex;
635
636 if (graphics->vbd->num_tex) {
637 graphics->vbd->tvarray =
638 bmalloc(sizeof(struct gs_tvertarray) * num_tex);
639
640 for (i = 0; i < num_tex; i++) {
641 graphics->vbd->tvarray[i].width = 2;
642 graphics->vbd->tvarray[i].array =
643 graphics->texverts[i].array;
644 }
645 }
646
647 reset_immediate_arrays(graphics);
648
649 return gs_vertexbuffer_create(graphics->vbd, 0);
650 }
651
gs_vertex2f(float x,float y)652 void gs_vertex2f(float x, float y)
653 {
654 struct vec3 v3;
655
656 if (!gs_valid("gs_verte"))
657 return;
658
659 vec3_set(&v3, x, y, 0.0f);
660 gs_vertex3v(&v3);
661 }
662
gs_vertex3f(float x,float y,float z)663 void gs_vertex3f(float x, float y, float z)
664 {
665 struct vec3 v3;
666
667 if (!gs_valid("gs_vertex3f"))
668 return;
669
670 vec3_set(&v3, x, y, z);
671 gs_vertex3v(&v3);
672 }
673
gs_normal3f(float x,float y,float z)674 void gs_normal3f(float x, float y, float z)
675 {
676 struct vec3 v3;
677
678 if (!gs_valid("gs_normal3f"))
679 return;
680
681 vec3_set(&v3, x, y, z);
682 gs_normal3v(&v3);
683 }
684
validvertsize(graphics_t * graphics,size_t num,const char * name)685 static inline bool validvertsize(graphics_t *graphics, size_t num,
686 const char *name)
687 {
688 if (graphics->using_immediate && num == IMMEDIATE_COUNT) {
689 blog(LOG_ERROR,
690 "%s: tried to use over %u "
691 "for immediate rendering",
692 name, IMMEDIATE_COUNT);
693 return false;
694 }
695
696 return true;
697 }
698
gs_color(uint32_t color)699 void gs_color(uint32_t color)
700 {
701 graphics_t *graphics = thread_graphics;
702
703 if (!gs_valid("gs_color"))
704 return;
705 if (!validvertsize(graphics, graphics->colors.num, "gs_color"))
706 return;
707
708 da_push_back(graphics->colors, &color);
709 }
710
gs_texcoord(float x,float y,int unit)711 void gs_texcoord(float x, float y, int unit)
712 {
713 struct vec2 v2;
714
715 if (!gs_valid("gs_texcoord"))
716 return;
717
718 vec2_set(&v2, x, y);
719 gs_texcoord2v(&v2, unit);
720 }
721
gs_vertex2v(const struct vec2 * v)722 void gs_vertex2v(const struct vec2 *v)
723 {
724 struct vec3 v3;
725
726 if (!gs_valid("gs_vertex2v"))
727 return;
728
729 vec3_set(&v3, v->x, v->y, 0.0f);
730 gs_vertex3v(&v3);
731 }
732
gs_vertex3v(const struct vec3 * v)733 void gs_vertex3v(const struct vec3 *v)
734 {
735 graphics_t *graphics = thread_graphics;
736
737 if (!gs_valid("gs_vertex3v"))
738 return;
739 if (!validvertsize(graphics, graphics->verts.num, "gs_vertex"))
740 return;
741
742 da_push_back(graphics->verts, v);
743 }
744
gs_normal3v(const struct vec3 * v)745 void gs_normal3v(const struct vec3 *v)
746 {
747 graphics_t *graphics = thread_graphics;
748
749 if (!gs_valid("gs_normal3v"))
750 return;
751 if (!validvertsize(graphics, graphics->norms.num, "gs_normal"))
752 return;
753
754 da_push_back(graphics->norms, v);
755 }
756
gs_color4v(const struct vec4 * v)757 void gs_color4v(const struct vec4 *v)
758 {
759 /* TODO */
760 UNUSED_PARAMETER(v);
761 }
762
gs_texcoord2v(const struct vec2 * v,int unit)763 void gs_texcoord2v(const struct vec2 *v, int unit)
764 {
765 graphics_t *graphics = thread_graphics;
766
767 if (!gs_valid("gs_texcoord2v"))
768 return;
769 if (!validvertsize(graphics, graphics->texverts[unit].num,
770 "gs_texcoord"))
771 return;
772
773 da_push_back(graphics->texverts[unit], v);
774 }
775
gs_get_input(void)776 input_t *gs_get_input(void)
777 {
778 /* TODO */
779 return NULL;
780 }
781
gs_get_effect(void)782 gs_effect_t *gs_get_effect(void)
783 {
784 if (!gs_valid("gs_get_effect"))
785 return NULL;
786
787 return thread_graphics ? thread_graphics->cur_effect : NULL;
788 }
789
find_cached_effect(const char * filename)790 static inline struct gs_effect *find_cached_effect(const char *filename)
791 {
792 struct gs_effect *effect = thread_graphics->first_effect;
793
794 while (effect) {
795 if (strcmp(effect->effect_path, filename) == 0)
796 break;
797 effect = effect->next;
798 }
799
800 return effect;
801 }
802
gs_effect_create_from_file(const char * file,char ** error_string)803 gs_effect_t *gs_effect_create_from_file(const char *file, char **error_string)
804 {
805 char *file_string;
806 gs_effect_t *effect = NULL;
807
808 if (!gs_valid_p("gs_effect_create_from_file", file))
809 return NULL;
810
811 effect = find_cached_effect(file);
812 if (effect)
813 return effect;
814
815 file_string = os_quick_read_utf8_file(file);
816 if (!file_string) {
817 blog(LOG_ERROR, "Could not load effect file '%s'", file);
818 return NULL;
819 }
820
821 effect = gs_effect_create(file_string, file, error_string);
822 bfree(file_string);
823
824 return effect;
825 }
826
gs_effect_create(const char * effect_string,const char * filename,char ** error_string)827 gs_effect_t *gs_effect_create(const char *effect_string, const char *filename,
828 char **error_string)
829 {
830 if (!gs_valid_p("gs_effect_create", effect_string))
831 return NULL;
832
833 struct gs_effect *effect = bzalloc(sizeof(struct gs_effect));
834 struct effect_parser parser;
835 bool success;
836
837 effect->graphics = thread_graphics;
838 effect->effect_path = bstrdup(filename);
839
840 ep_init(&parser);
841 success = ep_parse(&parser, effect, effect_string, filename);
842 if (!success) {
843 if (error_string)
844 *error_string =
845 error_data_buildstring(&parser.cfp.error_list);
846 gs_effect_destroy(effect);
847 effect = NULL;
848 }
849
850 if (effect) {
851 pthread_mutex_lock(&thread_graphics->effect_mutex);
852
853 if (effect->effect_path) {
854 effect->cached = true;
855 effect->next = thread_graphics->first_effect;
856 thread_graphics->first_effect = effect;
857 }
858
859 pthread_mutex_unlock(&thread_graphics->effect_mutex);
860 }
861
862 ep_free(&parser);
863 return effect;
864 }
865
gs_vertexshader_create_from_file(const char * file,char ** error_string)866 gs_shader_t *gs_vertexshader_create_from_file(const char *file,
867 char **error_string)
868 {
869 if (!gs_valid_p("gs_vertexshader_create_from_file", file))
870 return NULL;
871
872 char *file_string;
873 gs_shader_t *shader = NULL;
874
875 file_string = os_quick_read_utf8_file(file);
876 if (!file_string) {
877 blog(LOG_ERROR, "Could not load vertex shader file '%s'", file);
878 return NULL;
879 }
880
881 shader = gs_vertexshader_create(file_string, file, error_string);
882 bfree(file_string);
883
884 return shader;
885 }
886
gs_pixelshader_create_from_file(const char * file,char ** error_string)887 gs_shader_t *gs_pixelshader_create_from_file(const char *file,
888 char **error_string)
889 {
890 char *file_string;
891 gs_shader_t *shader = NULL;
892
893 if (!gs_valid_p("gs_pixelshader_create_from_file", file))
894 return NULL;
895
896 file_string = os_quick_read_utf8_file(file);
897 if (!file_string) {
898 blog(LOG_ERROR, "Could not load pixel shader file '%s'", file);
899 return NULL;
900 }
901
902 shader = gs_pixelshader_create(file_string, file, error_string);
903 bfree(file_string);
904
905 return shader;
906 }
907
gs_texture_create_from_file(const char * file)908 gs_texture_t *gs_texture_create_from_file(const char *file)
909 {
910 enum gs_color_format format;
911 uint32_t cx;
912 uint32_t cy;
913 uint8_t *data = gs_create_texture_file_data(file, &format, &cx, &cy);
914 gs_texture_t *tex = NULL;
915
916 if (data) {
917 tex = gs_texture_create(cx, cy, format, 1,
918 (const uint8_t **)&data, 0);
919 bfree(data);
920 }
921
922 return tex;
923 }
924
assign_sprite_rect(float * start,float * end,float size,bool flip)925 static inline void assign_sprite_rect(float *start, float *end, float size,
926 bool flip)
927 {
928 if (!flip) {
929 *start = 0.0f;
930 *end = size;
931 } else {
932 *start = size;
933 *end = 0.0f;
934 }
935 }
936
assign_sprite_uv(float * start,float * end,bool flip)937 static inline void assign_sprite_uv(float *start, float *end, bool flip)
938 {
939 if (!flip) {
940 *start = 0.0f;
941 *end = 1.0f;
942 } else {
943 *start = 1.0f;
944 *end = 0.0f;
945 }
946 }
947
build_sprite(struct gs_vb_data * data,float fcx,float fcy,float start_u,float end_u,float start_v,float end_v)948 static void build_sprite(struct gs_vb_data *data, float fcx, float fcy,
949 float start_u, float end_u, float start_v, float end_v)
950 {
951 struct vec2 *tvarray = data->tvarray[0].array;
952
953 vec3_zero(data->points);
954 vec3_set(data->points + 1, fcx, 0.0f, 0.0f);
955 vec3_set(data->points + 2, 0.0f, fcy, 0.0f);
956 vec3_set(data->points + 3, fcx, fcy, 0.0f);
957 vec2_set(tvarray, start_u, start_v);
958 vec2_set(tvarray + 1, end_u, start_v);
959 vec2_set(tvarray + 2, start_u, end_v);
960 vec2_set(tvarray + 3, end_u, end_v);
961 }
962
build_sprite_norm(struct gs_vb_data * data,float fcx,float fcy,uint32_t flip)963 static inline void build_sprite_norm(struct gs_vb_data *data, float fcx,
964 float fcy, uint32_t flip)
965 {
966 float start_u, end_u;
967 float start_v, end_v;
968
969 assign_sprite_uv(&start_u, &end_u, (flip & GS_FLIP_U) != 0);
970 assign_sprite_uv(&start_v, &end_v, (flip & GS_FLIP_V) != 0);
971 build_sprite(data, fcx, fcy, start_u, end_u, start_v, end_v);
972 }
973
build_subsprite_norm(struct gs_vb_data * data,float fsub_x,float fsub_y,float fsub_cx,float fsub_cy,float fcx,float fcy,uint32_t flip)974 static inline void build_subsprite_norm(struct gs_vb_data *data, float fsub_x,
975 float fsub_y, float fsub_cx,
976 float fsub_cy, float fcx, float fcy,
977 uint32_t flip)
978 {
979 float start_u, end_u;
980 float start_v, end_v;
981
982 if ((flip & GS_FLIP_U) == 0) {
983 start_u = fsub_x / fcx;
984 end_u = (fsub_x + fsub_cx) / fcx;
985 } else {
986 start_u = (fsub_x + fsub_cx) / fcx;
987 end_u = fsub_x / fcx;
988 }
989
990 if ((flip & GS_FLIP_V) == 0) {
991 start_v = fsub_y / fcy;
992 end_v = (fsub_y + fsub_cy) / fcy;
993 } else {
994 start_v = (fsub_y + fsub_cy) / fcy;
995 end_v = fsub_y / fcy;
996 }
997
998 build_sprite(data, fsub_cx, fsub_cy, start_u, end_u, start_v, end_v);
999 }
1000
build_sprite_rect(struct gs_vb_data * data,gs_texture_t * tex,float fcx,float fcy,uint32_t flip)1001 static inline void build_sprite_rect(struct gs_vb_data *data, gs_texture_t *tex,
1002 float fcx, float fcy, uint32_t flip)
1003 {
1004 float start_u, end_u;
1005 float start_v, end_v;
1006 float width = (float)gs_texture_get_width(tex);
1007 float height = (float)gs_texture_get_height(tex);
1008
1009 assign_sprite_rect(&start_u, &end_u, width, (flip & GS_FLIP_U) != 0);
1010 assign_sprite_rect(&start_v, &end_v, height, (flip & GS_FLIP_V) != 0);
1011 build_sprite(data, fcx, fcy, start_u, end_u, start_v, end_v);
1012 }
1013
gs_draw_sprite(gs_texture_t * tex,uint32_t flip,uint32_t width,uint32_t height)1014 void gs_draw_sprite(gs_texture_t *tex, uint32_t flip, uint32_t width,
1015 uint32_t height)
1016 {
1017 graphics_t *graphics = thread_graphics;
1018 float fcx, fcy;
1019 struct gs_vb_data *data;
1020
1021 if (tex) {
1022 if (gs_get_texture_type(tex) != GS_TEXTURE_2D) {
1023 blog(LOG_ERROR, "A sprite must be a 2D texture");
1024 return;
1025 }
1026 } else {
1027 if (!width || !height) {
1028 blog(LOG_ERROR, "A sprite cannot be drawn without "
1029 "a width/height");
1030 return;
1031 }
1032 }
1033
1034 fcx = width ? (float)width : (float)gs_texture_get_width(tex);
1035 fcy = height ? (float)height : (float)gs_texture_get_height(tex);
1036
1037 data = gs_vertexbuffer_get_data(graphics->sprite_buffer);
1038 if (tex && gs_texture_is_rect(tex))
1039 build_sprite_rect(data, tex, fcx, fcy, flip);
1040 else
1041 build_sprite_norm(data, fcx, fcy, flip);
1042
1043 gs_vertexbuffer_flush(graphics->sprite_buffer);
1044 gs_load_vertexbuffer(graphics->sprite_buffer);
1045 gs_load_indexbuffer(NULL);
1046
1047 gs_draw(GS_TRISTRIP, 0, 0);
1048 }
1049
gs_draw_sprite_subregion(gs_texture_t * tex,uint32_t flip,uint32_t sub_x,uint32_t sub_y,uint32_t sub_cx,uint32_t sub_cy)1050 void gs_draw_sprite_subregion(gs_texture_t *tex, uint32_t flip, uint32_t sub_x,
1051 uint32_t sub_y, uint32_t sub_cx, uint32_t sub_cy)
1052 {
1053 graphics_t *graphics = thread_graphics;
1054 float fcx, fcy;
1055 struct gs_vb_data *data;
1056
1057 if (tex) {
1058 if (gs_get_texture_type(tex) != GS_TEXTURE_2D) {
1059 blog(LOG_ERROR, "A sprite must be a 2D texture");
1060 return;
1061 }
1062 }
1063
1064 fcx = (float)gs_texture_get_width(tex);
1065 fcy = (float)gs_texture_get_height(tex);
1066
1067 data = gs_vertexbuffer_get_data(graphics->sprite_buffer);
1068 build_subsprite_norm(data, (float)sub_x, (float)sub_y, (float)sub_cx,
1069 (float)sub_cy, fcx, fcy, flip);
1070
1071 gs_vertexbuffer_flush(graphics->sprite_buffer);
1072 gs_load_vertexbuffer(graphics->sprite_buffer);
1073 gs_load_indexbuffer(NULL);
1074
1075 gs_draw(GS_TRISTRIP, 0, 0);
1076 }
1077
gs_draw_cube_backdrop(gs_texture_t * cubetex,const struct quat * rot,float left,float right,float top,float bottom,float znear)1078 void gs_draw_cube_backdrop(gs_texture_t *cubetex, const struct quat *rot,
1079 float left, float right, float top, float bottom,
1080 float znear)
1081 {
1082 /* TODO */
1083 UNUSED_PARAMETER(cubetex);
1084 UNUSED_PARAMETER(rot);
1085 UNUSED_PARAMETER(left);
1086 UNUSED_PARAMETER(right);
1087 UNUSED_PARAMETER(top);
1088 UNUSED_PARAMETER(bottom);
1089 UNUSED_PARAMETER(znear);
1090 }
1091
gs_reset_viewport(void)1092 void gs_reset_viewport(void)
1093 {
1094 uint32_t cx, cy;
1095
1096 if (!gs_valid("gs_reset_viewport"))
1097 return;
1098
1099 gs_get_size(&cx, &cy);
1100 gs_set_viewport(0, 0, (int)cx, (int)cy);
1101 }
1102
gs_set_2d_mode(void)1103 void gs_set_2d_mode(void)
1104 {
1105 uint32_t cx, cy;
1106
1107 if (!gs_valid("gs_set_2d_mode"))
1108 return;
1109
1110 gs_get_size(&cx, &cy);
1111 gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -1.0, -1024.0f);
1112 }
1113
gs_set_3d_mode(double fovy,double znear,double zvar)1114 void gs_set_3d_mode(double fovy, double znear, double zvar)
1115 {
1116 /* TODO */
1117 UNUSED_PARAMETER(fovy);
1118 UNUSED_PARAMETER(znear);
1119 UNUSED_PARAMETER(zvar);
1120 }
1121
gs_viewport_push(void)1122 void gs_viewport_push(void)
1123 {
1124 if (!gs_valid("gs_viewport_push"))
1125 return;
1126
1127 struct gs_rect *rect =
1128 da_push_back_new(thread_graphics->viewport_stack);
1129 gs_get_viewport(rect);
1130 }
1131
gs_viewport_pop(void)1132 void gs_viewport_pop(void)
1133 {
1134 struct gs_rect *rect;
1135
1136 if (!gs_valid("gs_viewport_pop"))
1137 return;
1138 if (!thread_graphics->viewport_stack.num)
1139 return;
1140
1141 rect = da_end(thread_graphics->viewport_stack);
1142 gs_set_viewport(rect->x, rect->y, rect->cx, rect->cy);
1143 da_pop_back(thread_graphics->viewport_stack);
1144 }
1145
gs_texture_set_image(gs_texture_t * tex,const uint8_t * data,uint32_t linesize,bool flip)1146 void gs_texture_set_image(gs_texture_t *tex, const uint8_t *data,
1147 uint32_t linesize, bool flip)
1148 {
1149 uint8_t *ptr;
1150 uint32_t linesize_out;
1151 size_t row_copy;
1152 size_t height;
1153
1154 if (!gs_valid_p2("gs_texture_set_image", tex, data))
1155 return;
1156
1157 if (!gs_texture_map(tex, &ptr, &linesize_out))
1158 return;
1159
1160 row_copy = (linesize < linesize_out) ? linesize : linesize_out;
1161
1162 height = gs_texture_get_height(tex);
1163
1164 if (flip) {
1165 uint8_t *const end = ptr + height * linesize_out;
1166 data += (height - 1) * linesize;
1167 while (ptr < end) {
1168 memcpy(ptr, data, row_copy);
1169 ptr += linesize_out;
1170 data -= linesize;
1171 }
1172
1173 } else if (linesize == linesize_out) {
1174 memcpy(ptr, data, row_copy * height);
1175
1176 } else {
1177 uint8_t *const end = ptr + height * linesize_out;
1178 while (ptr < end) {
1179 memcpy(ptr, data, row_copy);
1180 ptr += linesize_out;
1181 data += linesize;
1182 }
1183 }
1184
1185 gs_texture_unmap(tex);
1186 }
1187
gs_cubetexture_set_image(gs_texture_t * cubetex,uint32_t side,const void * data,uint32_t linesize,bool invert)1188 void gs_cubetexture_set_image(gs_texture_t *cubetex, uint32_t side,
1189 const void *data, uint32_t linesize, bool invert)
1190 {
1191 /* TODO */
1192 UNUSED_PARAMETER(cubetex);
1193 UNUSED_PARAMETER(side);
1194 UNUSED_PARAMETER(data);
1195 UNUSED_PARAMETER(linesize);
1196 UNUSED_PARAMETER(invert);
1197 }
1198
gs_perspective(float angle,float aspect,float near,float far)1199 void gs_perspective(float angle, float aspect, float near, float far)
1200 {
1201 graphics_t *graphics = thread_graphics;
1202 float xmin, xmax, ymin, ymax;
1203
1204 if (!gs_valid("gs_perspective"))
1205 return;
1206
1207 ymax = near * tanf(RAD(angle) * 0.5f);
1208 ymin = -ymax;
1209
1210 xmin = ymin * aspect;
1211 xmax = ymax * aspect;
1212
1213 graphics->exports.device_frustum(graphics->device, xmin, xmax, ymin,
1214 ymax, near, far);
1215 }
1216
gs_blend_state_push(void)1217 void gs_blend_state_push(void)
1218 {
1219 graphics_t *graphics = thread_graphics;
1220
1221 if (!gs_valid("gs_blend_state_push"))
1222 return;
1223
1224 da_push_back(graphics->blend_state_stack, &graphics->cur_blend_state);
1225 }
1226
gs_blend_state_pop(void)1227 void gs_blend_state_pop(void)
1228 {
1229 graphics_t *graphics = thread_graphics;
1230 struct blend_state *state;
1231
1232 if (!gs_valid("gs_blend_state_pop"))
1233 return;
1234
1235 state = da_end(graphics->blend_state_stack);
1236 if (!state)
1237 return;
1238
1239 gs_enable_blending(state->enabled);
1240 gs_blend_function_separate(state->src_c, state->dest_c, state->src_a,
1241 state->dest_a);
1242
1243 da_pop_back(graphics->blend_state_stack);
1244 }
1245
gs_reset_blend_state(void)1246 void gs_reset_blend_state(void)
1247 {
1248 graphics_t *graphics = thread_graphics;
1249
1250 if (!gs_valid("gs_preprocessor_name"))
1251 return;
1252
1253 if (!graphics->cur_blend_state.enabled)
1254 gs_enable_blending(true);
1255
1256 if (graphics->cur_blend_state.src_c != GS_BLEND_SRCALPHA ||
1257 graphics->cur_blend_state.dest_c != GS_BLEND_INVSRCALPHA ||
1258 graphics->cur_blend_state.src_a != GS_BLEND_ONE ||
1259 graphics->cur_blend_state.dest_a != GS_BLEND_INVSRCALPHA)
1260 gs_blend_function_separate(GS_BLEND_SRCALPHA,
1261 GS_BLEND_INVSRCALPHA, GS_BLEND_ONE,
1262 GS_BLEND_INVSRCALPHA);
1263 }
1264
1265 /* ------------------------------------------------------------------------- */
1266
gs_preprocessor_name(void)1267 const char *gs_preprocessor_name(void)
1268 {
1269 graphics_t *graphics = thread_graphics;
1270
1271 if (!gs_valid("gs_preprocessor_name"))
1272 return NULL;
1273
1274 return graphics->exports.device_preprocessor_name();
1275 }
1276
gs_swapchain_create(const struct gs_init_data * data)1277 gs_swapchain_t *gs_swapchain_create(const struct gs_init_data *data)
1278 {
1279 struct gs_init_data new_data = *data;
1280 graphics_t *graphics = thread_graphics;
1281
1282 if (!gs_valid_p("gs_swapchain_create", data))
1283 return NULL;
1284
1285 if (new_data.num_backbuffers == 0)
1286 new_data.num_backbuffers = 1;
1287
1288 return graphics->exports.device_swapchain_create(graphics->device,
1289 &new_data);
1290 }
1291
gs_resize(uint32_t x,uint32_t y)1292 void gs_resize(uint32_t x, uint32_t y)
1293 {
1294 graphics_t *graphics = thread_graphics;
1295
1296 if (!gs_valid("gs_resize"))
1297 return;
1298
1299 graphics->exports.device_resize(graphics->device, x, y);
1300 }
1301
gs_get_size(uint32_t * x,uint32_t * y)1302 void gs_get_size(uint32_t *x, uint32_t *y)
1303 {
1304 graphics_t *graphics = thread_graphics;
1305
1306 if (!gs_valid("gs_get_size"))
1307 return;
1308
1309 graphics->exports.device_get_size(graphics->device, x, y);
1310 }
1311
gs_get_width(void)1312 uint32_t gs_get_width(void)
1313 {
1314 graphics_t *graphics = thread_graphics;
1315
1316 if (!gs_valid("gs_get_width"))
1317 return 0;
1318
1319 return graphics->exports.device_get_width(graphics->device);
1320 }
1321
gs_get_height(void)1322 uint32_t gs_get_height(void)
1323 {
1324 graphics_t *graphics = thread_graphics;
1325
1326 if (!gs_valid("gs_get_height"))
1327 return 0;
1328
1329 return graphics->exports.device_get_height(graphics->device);
1330 }
1331
is_pow2(uint32_t size)1332 static inline bool is_pow2(uint32_t size)
1333 {
1334 return size >= 2 && (size & (size - 1)) == 0;
1335 }
1336
gs_texture_create(uint32_t width,uint32_t height,enum gs_color_format color_format,uint32_t levels,const uint8_t ** data,uint32_t flags)1337 gs_texture_t *gs_texture_create(uint32_t width, uint32_t height,
1338 enum gs_color_format color_format,
1339 uint32_t levels, const uint8_t **data,
1340 uint32_t flags)
1341 {
1342 graphics_t *graphics = thread_graphics;
1343 bool pow2tex = is_pow2(width) && is_pow2(height);
1344 bool uses_mipmaps = (flags & GS_BUILD_MIPMAPS || levels != 1);
1345
1346 if (!gs_valid("gs_texture_create"))
1347 return NULL;
1348
1349 if (uses_mipmaps && !pow2tex) {
1350 blog(LOG_WARNING, "Cannot use mipmaps with a "
1351 "non-power-of-two texture. Disabling "
1352 "mipmaps for this texture.");
1353
1354 uses_mipmaps = false;
1355 flags &= ~GS_BUILD_MIPMAPS;
1356 levels = 1;
1357 }
1358
1359 if (uses_mipmaps && flags & GS_RENDER_TARGET) {
1360 blog(LOG_WARNING, "Cannot use mipmaps with render targets. "
1361 "Disabling mipmaps for this texture.");
1362 flags &= ~GS_BUILD_MIPMAPS;
1363 levels = 1;
1364 }
1365
1366 return graphics->exports.device_texture_create(graphics->device, width,
1367 height, color_format,
1368 levels, data, flags);
1369 }
1370
1371 #if __linux__
1372
gs_texture_create_from_dmabuf(unsigned int width,unsigned int height,uint32_t drm_format,enum gs_color_format color_format,uint32_t n_planes,const int * fds,const uint32_t * strides,const uint32_t * offsets,const uint64_t * modifiers)1373 gs_texture_t *gs_texture_create_from_dmabuf(
1374 unsigned int width, unsigned int height, uint32_t drm_format,
1375 enum gs_color_format color_format, uint32_t n_planes, const int *fds,
1376 const uint32_t *strides, const uint32_t *offsets,
1377 const uint64_t *modifiers)
1378 {
1379 graphics_t *graphics = thread_graphics;
1380
1381 return graphics->exports.device_texture_create_from_dmabuf(
1382 graphics->device, width, height, drm_format, color_format,
1383 n_planes, fds, strides, offsets, modifiers);
1384 }
1385
1386 #endif
1387
gs_cubetexture_create(uint32_t size,enum gs_color_format color_format,uint32_t levels,const uint8_t ** data,uint32_t flags)1388 gs_texture_t *gs_cubetexture_create(uint32_t size,
1389 enum gs_color_format color_format,
1390 uint32_t levels, const uint8_t **data,
1391 uint32_t flags)
1392 {
1393 graphics_t *graphics = thread_graphics;
1394 bool pow2tex = is_pow2(size);
1395 bool uses_mipmaps = (flags & GS_BUILD_MIPMAPS || levels != 1);
1396
1397 if (!gs_valid("gs_cubetexture_create"))
1398 return NULL;
1399
1400 if (uses_mipmaps && !pow2tex) {
1401 blog(LOG_WARNING, "Cannot use mipmaps with a "
1402 "non-power-of-two texture. Disabling "
1403 "mipmaps for this texture.");
1404
1405 uses_mipmaps = false;
1406 flags &= ~GS_BUILD_MIPMAPS;
1407 levels = 1;
1408 }
1409
1410 if (uses_mipmaps && flags & GS_RENDER_TARGET) {
1411 blog(LOG_WARNING, "Cannot use mipmaps with render targets. "
1412 "Disabling mipmaps for this texture.");
1413 flags &= ~GS_BUILD_MIPMAPS;
1414 levels = 1;
1415 data = NULL;
1416 }
1417
1418 return graphics->exports.device_cubetexture_create(
1419 graphics->device, size, color_format, levels, data, flags);
1420 }
1421
gs_voltexture_create(uint32_t width,uint32_t height,uint32_t depth,enum gs_color_format color_format,uint32_t levels,const uint8_t ** data,uint32_t flags)1422 gs_texture_t *gs_voltexture_create(uint32_t width, uint32_t height,
1423 uint32_t depth,
1424 enum gs_color_format color_format,
1425 uint32_t levels, const uint8_t **data,
1426 uint32_t flags)
1427 {
1428 graphics_t *graphics = thread_graphics;
1429
1430 if (!gs_valid("gs_voltexture_create"))
1431 return NULL;
1432
1433 return graphics->exports.device_voltexture_create(graphics->device,
1434 width, height, depth,
1435 color_format, levels,
1436 data, flags);
1437 }
1438
gs_zstencil_create(uint32_t width,uint32_t height,enum gs_zstencil_format format)1439 gs_zstencil_t *gs_zstencil_create(uint32_t width, uint32_t height,
1440 enum gs_zstencil_format format)
1441 {
1442 graphics_t *graphics = thread_graphics;
1443
1444 if (!gs_valid("gs_zstencil_create"))
1445 return NULL;
1446
1447 return graphics->exports.device_zstencil_create(graphics->device, width,
1448 height, format);
1449 }
1450
gs_stagesurface_create(uint32_t width,uint32_t height,enum gs_color_format color_format)1451 gs_stagesurf_t *gs_stagesurface_create(uint32_t width, uint32_t height,
1452 enum gs_color_format color_format)
1453 {
1454 graphics_t *graphics = thread_graphics;
1455
1456 if (!gs_valid("gs_stagesurface_create"))
1457 return NULL;
1458
1459 return graphics->exports.device_stagesurface_create(
1460 graphics->device, width, height, color_format);
1461 }
1462
gs_samplerstate_create(const struct gs_sampler_info * info)1463 gs_samplerstate_t *gs_samplerstate_create(const struct gs_sampler_info *info)
1464 {
1465 graphics_t *graphics = thread_graphics;
1466
1467 if (!gs_valid_p("gs_samplerstate_create", info))
1468 return NULL;
1469
1470 return graphics->exports.device_samplerstate_create(graphics->device,
1471 info);
1472 }
1473
gs_vertexshader_create(const char * shader,const char * file,char ** error_string)1474 gs_shader_t *gs_vertexshader_create(const char *shader, const char *file,
1475 char **error_string)
1476 {
1477 graphics_t *graphics = thread_graphics;
1478
1479 if (!gs_valid_p("gs_vertexshader_create", shader))
1480 return NULL;
1481
1482 return graphics->exports.device_vertexshader_create(
1483 graphics->device, shader, file, error_string);
1484 }
1485
gs_pixelshader_create(const char * shader,const char * file,char ** error_string)1486 gs_shader_t *gs_pixelshader_create(const char *shader, const char *file,
1487 char **error_string)
1488 {
1489 graphics_t *graphics = thread_graphics;
1490
1491 if (!gs_valid_p("gs_pixelshader_create", shader))
1492 return NULL;
1493
1494 return graphics->exports.device_pixelshader_create(
1495 graphics->device, shader, file, error_string);
1496 }
1497
gs_vertexbuffer_create(struct gs_vb_data * data,uint32_t flags)1498 gs_vertbuffer_t *gs_vertexbuffer_create(struct gs_vb_data *data, uint32_t flags)
1499 {
1500 graphics_t *graphics = thread_graphics;
1501
1502 if (!gs_valid("gs_vertexbuffer_create"))
1503 return NULL;
1504
1505 if (data && data->num && (flags & GS_DUP_BUFFER) != 0) {
1506 struct gs_vb_data *new_data = gs_vbdata_create();
1507
1508 new_data->num = data->num;
1509
1510 #define DUP_VAL(val) \
1511 do { \
1512 if (data->val) \
1513 new_data->val = bmemdup( \
1514 data->val, sizeof(*data->val) * data->num); \
1515 } while (false)
1516
1517 DUP_VAL(points);
1518 DUP_VAL(normals);
1519 DUP_VAL(tangents);
1520 DUP_VAL(colors);
1521 #undef DUP_VAL
1522
1523 if (data->tvarray && data->num_tex) {
1524 new_data->num_tex = data->num_tex;
1525 new_data->tvarray = bzalloc(
1526 sizeof(struct gs_tvertarray) * data->num_tex);
1527
1528 for (size_t i = 0; i < data->num_tex; i++) {
1529 struct gs_tvertarray *tv = &data->tvarray[i];
1530 struct gs_tvertarray *new_tv =
1531 &new_data->tvarray[i];
1532 size_t size = tv->width * sizeof(float);
1533
1534 new_tv->width = tv->width;
1535 new_tv->array =
1536 bmemdup(tv->array, size * data->num);
1537 }
1538 }
1539
1540 data = new_data;
1541 }
1542
1543 return graphics->exports.device_vertexbuffer_create(graphics->device,
1544 data, flags);
1545 }
1546
gs_indexbuffer_create(enum gs_index_type type,void * indices,size_t num,uint32_t flags)1547 gs_indexbuffer_t *gs_indexbuffer_create(enum gs_index_type type, void *indices,
1548 size_t num, uint32_t flags)
1549 {
1550 graphics_t *graphics = thread_graphics;
1551
1552 if (!gs_valid("gs_indexbuffer_create"))
1553 return NULL;
1554
1555 if (indices && num && (flags & GS_DUP_BUFFER) != 0) {
1556 size_t size = type == GS_UNSIGNED_SHORT ? 2 : 4;
1557 indices = bmemdup(indices, size * num);
1558 }
1559
1560 return graphics->exports.device_indexbuffer_create(
1561 graphics->device, type, indices, num, flags);
1562 }
1563
gs_timer_create()1564 gs_timer_t *gs_timer_create()
1565 {
1566 graphics_t *graphics = thread_graphics;
1567
1568 if (!gs_valid("gs_timer_create"))
1569 return NULL;
1570
1571 return graphics->exports.device_timer_create(graphics->device);
1572 }
1573
gs_timer_range_create()1574 gs_timer_range_t *gs_timer_range_create()
1575 {
1576 graphics_t *graphics = thread_graphics;
1577
1578 if (!gs_valid("gs_timer_range_create"))
1579 return NULL;
1580
1581 return graphics->exports.device_timer_range_create(graphics->device);
1582 }
1583
gs_get_texture_type(const gs_texture_t * texture)1584 enum gs_texture_type gs_get_texture_type(const gs_texture_t *texture)
1585 {
1586 graphics_t *graphics = thread_graphics;
1587
1588 if (!gs_valid_p("gs_get_texture_type", texture))
1589 return GS_TEXTURE_2D;
1590
1591 return graphics->exports.device_get_texture_type(texture);
1592 }
1593
gs_load_vertexbuffer(gs_vertbuffer_t * vertbuffer)1594 void gs_load_vertexbuffer(gs_vertbuffer_t *vertbuffer)
1595 {
1596 graphics_t *graphics = thread_graphics;
1597
1598 if (!gs_valid("gs_load_vertexbuffer"))
1599 return;
1600
1601 graphics->exports.device_load_vertexbuffer(graphics->device,
1602 vertbuffer);
1603 }
1604
gs_load_indexbuffer(gs_indexbuffer_t * indexbuffer)1605 void gs_load_indexbuffer(gs_indexbuffer_t *indexbuffer)
1606 {
1607 graphics_t *graphics = thread_graphics;
1608
1609 if (!gs_valid("gs_load_indexbuffer"))
1610 return;
1611
1612 graphics->exports.device_load_indexbuffer(graphics->device,
1613 indexbuffer);
1614 }
1615
gs_load_texture(gs_texture_t * tex,int unit)1616 void gs_load_texture(gs_texture_t *tex, int unit)
1617 {
1618 graphics_t *graphics = thread_graphics;
1619
1620 if (!gs_valid("gs_load_texture"))
1621 return;
1622
1623 graphics->exports.device_load_texture(graphics->device, tex, unit);
1624 }
1625
gs_load_samplerstate(gs_samplerstate_t * samplerstate,int unit)1626 void gs_load_samplerstate(gs_samplerstate_t *samplerstate, int unit)
1627 {
1628 graphics_t *graphics = thread_graphics;
1629
1630 if (!gs_valid("gs_load_samplerstate"))
1631 return;
1632
1633 graphics->exports.device_load_samplerstate(graphics->device,
1634 samplerstate, unit);
1635 }
1636
gs_load_vertexshader(gs_shader_t * vertshader)1637 void gs_load_vertexshader(gs_shader_t *vertshader)
1638 {
1639 graphics_t *graphics = thread_graphics;
1640
1641 if (!gs_valid("gs_load_vertexshader"))
1642 return;
1643
1644 graphics->exports.device_load_vertexshader(graphics->device,
1645 vertshader);
1646 }
1647
gs_load_pixelshader(gs_shader_t * pixelshader)1648 void gs_load_pixelshader(gs_shader_t *pixelshader)
1649 {
1650 graphics_t *graphics = thread_graphics;
1651
1652 if (!gs_valid("gs_load_pixelshader"))
1653 return;
1654
1655 graphics->exports.device_load_pixelshader(graphics->device,
1656 pixelshader);
1657 }
1658
gs_load_default_samplerstate(bool b_3d,int unit)1659 void gs_load_default_samplerstate(bool b_3d, int unit)
1660 {
1661 graphics_t *graphics = thread_graphics;
1662
1663 if (!gs_valid("gs_load_default_samplerstate"))
1664 return;
1665
1666 graphics->exports.device_load_default_samplerstate(graphics->device,
1667 b_3d, unit);
1668 }
1669
gs_get_vertex_shader(void)1670 gs_shader_t *gs_get_vertex_shader(void)
1671 {
1672 graphics_t *graphics = thread_graphics;
1673
1674 if (!gs_valid("gs_get_vertex_shader"))
1675 return NULL;
1676
1677 return graphics->exports.device_get_vertex_shader(graphics->device);
1678 }
1679
gs_get_pixel_shader(void)1680 gs_shader_t *gs_get_pixel_shader(void)
1681 {
1682 graphics_t *graphics = thread_graphics;
1683
1684 if (!gs_valid("gs_get_pixel_shader"))
1685 return NULL;
1686
1687 return graphics->exports.device_get_pixel_shader(graphics->device);
1688 }
1689
gs_get_render_target(void)1690 gs_texture_t *gs_get_render_target(void)
1691 {
1692 graphics_t *graphics = thread_graphics;
1693
1694 if (!gs_valid("gs_get_render_target"))
1695 return NULL;
1696
1697 return graphics->exports.device_get_render_target(graphics->device);
1698 }
1699
gs_get_zstencil_target(void)1700 gs_zstencil_t *gs_get_zstencil_target(void)
1701 {
1702 graphics_t *graphics = thread_graphics;
1703
1704 if (!gs_valid("gs_get_zstencil_target"))
1705 return NULL;
1706
1707 return graphics->exports.device_get_zstencil_target(graphics->device);
1708 }
1709
gs_set_render_target(gs_texture_t * tex,gs_zstencil_t * zstencil)1710 void gs_set_render_target(gs_texture_t *tex, gs_zstencil_t *zstencil)
1711 {
1712 graphics_t *graphics = thread_graphics;
1713
1714 if (!gs_valid("gs_set_render_target"))
1715 return;
1716
1717 graphics->exports.device_set_render_target(graphics->device, tex,
1718 zstencil);
1719 }
1720
gs_set_cube_render_target(gs_texture_t * cubetex,int side,gs_zstencil_t * zstencil)1721 void gs_set_cube_render_target(gs_texture_t *cubetex, int side,
1722 gs_zstencil_t *zstencil)
1723 {
1724 graphics_t *graphics = thread_graphics;
1725
1726 if (!gs_valid("gs_set_cube_render_target"))
1727 return;
1728
1729 graphics->exports.device_set_cube_render_target(
1730 graphics->device, cubetex, side, zstencil);
1731 }
1732
gs_enable_framebuffer_srgb(bool enable)1733 void gs_enable_framebuffer_srgb(bool enable)
1734 {
1735 graphics_t *graphics = thread_graphics;
1736
1737 if (!gs_valid("gs_enable_framebuffer_srgb"))
1738 return;
1739
1740 graphics->exports.device_enable_framebuffer_srgb(graphics->device,
1741 enable);
1742 }
1743
gs_framebuffer_srgb_enabled(void)1744 bool gs_framebuffer_srgb_enabled(void)
1745 {
1746 graphics_t *graphics = thread_graphics;
1747
1748 if (!gs_valid("gs_framebuffer_srgb_enabled"))
1749 return false;
1750
1751 return graphics->exports.device_framebuffer_srgb_enabled(
1752 graphics->device);
1753 }
1754
gs_get_linear_srgb(void)1755 bool gs_get_linear_srgb(void)
1756 {
1757 graphics_t *graphics = thread_graphics;
1758
1759 if (!gs_valid("gs_get_linear_srgb"))
1760 return false;
1761
1762 return graphics->linear_srgb;
1763 }
1764
gs_set_linear_srgb(bool linear_srgb)1765 bool gs_set_linear_srgb(bool linear_srgb)
1766 {
1767 graphics_t *graphics = thread_graphics;
1768
1769 if (!gs_valid("gs_set_linear_srgb"))
1770 return false;
1771
1772 const bool previous = graphics->linear_srgb;
1773 graphics->linear_srgb = linear_srgb;
1774 return previous;
1775 }
1776
gs_copy_texture(gs_texture_t * dst,gs_texture_t * src)1777 void gs_copy_texture(gs_texture_t *dst, gs_texture_t *src)
1778 {
1779 graphics_t *graphics = thread_graphics;
1780
1781 if (!gs_valid_p2("gs_copy_texture", dst, src))
1782 return;
1783
1784 graphics->exports.device_copy_texture(graphics->device, dst, src);
1785 }
1786
gs_copy_texture_region(gs_texture_t * dst,uint32_t dst_x,uint32_t dst_y,gs_texture_t * src,uint32_t src_x,uint32_t src_y,uint32_t src_w,uint32_t src_h)1787 void gs_copy_texture_region(gs_texture_t *dst, uint32_t dst_x, uint32_t dst_y,
1788 gs_texture_t *src, uint32_t src_x, uint32_t src_y,
1789 uint32_t src_w, uint32_t src_h)
1790 {
1791 graphics_t *graphics = thread_graphics;
1792
1793 if (!gs_valid_p("gs_copy_texture_region", dst))
1794 return;
1795
1796 graphics->exports.device_copy_texture_region(graphics->device, dst,
1797 dst_x, dst_y, src, src_x,
1798 src_y, src_w, src_h);
1799 }
1800
gs_stage_texture(gs_stagesurf_t * dst,gs_texture_t * src)1801 void gs_stage_texture(gs_stagesurf_t *dst, gs_texture_t *src)
1802 {
1803 graphics_t *graphics = thread_graphics;
1804
1805 if (!gs_valid("gs_stage_texture"))
1806 return;
1807
1808 graphics->exports.device_stage_texture(graphics->device, dst, src);
1809 }
1810
gs_begin_frame(void)1811 void gs_begin_frame(void)
1812 {
1813 graphics_t *graphics = thread_graphics;
1814
1815 if (!gs_valid("gs_begin_frame"))
1816 return;
1817
1818 graphics->exports.device_begin_frame(graphics->device);
1819 }
1820
gs_begin_scene(void)1821 void gs_begin_scene(void)
1822 {
1823 graphics_t *graphics = thread_graphics;
1824
1825 if (!gs_valid("gs_begin_scene"))
1826 return;
1827
1828 graphics->exports.device_begin_scene(graphics->device);
1829 }
1830
gs_draw(enum gs_draw_mode draw_mode,uint32_t start_vert,uint32_t num_verts)1831 void gs_draw(enum gs_draw_mode draw_mode, uint32_t start_vert,
1832 uint32_t num_verts)
1833 {
1834 graphics_t *graphics = thread_graphics;
1835
1836 if (!gs_valid("gs_draw"))
1837 return;
1838
1839 graphics->exports.device_draw(graphics->device, draw_mode, start_vert,
1840 num_verts);
1841 }
1842
gs_end_scene(void)1843 void gs_end_scene(void)
1844 {
1845 graphics_t *graphics = thread_graphics;
1846
1847 if (!gs_valid("gs_end_scene"))
1848 return;
1849
1850 graphics->exports.device_end_scene(graphics->device);
1851 }
1852
gs_load_swapchain(gs_swapchain_t * swapchain)1853 void gs_load_swapchain(gs_swapchain_t *swapchain)
1854 {
1855 graphics_t *graphics = thread_graphics;
1856
1857 if (!gs_valid("gs_load_swapchain"))
1858 return;
1859
1860 graphics->exports.device_load_swapchain(graphics->device, swapchain);
1861 }
1862
gs_clear(uint32_t clear_flags,const struct vec4 * color,float depth,uint8_t stencil)1863 void gs_clear(uint32_t clear_flags, const struct vec4 *color, float depth,
1864 uint8_t stencil)
1865 {
1866 graphics_t *graphics = thread_graphics;
1867
1868 if (!gs_valid("gs_clear"))
1869 return;
1870
1871 graphics->exports.device_clear(graphics->device, clear_flags, color,
1872 depth, stencil);
1873 }
1874
gs_present(void)1875 void gs_present(void)
1876 {
1877 graphics_t *graphics = thread_graphics;
1878
1879 if (!gs_valid("gs_present"))
1880 return;
1881
1882 graphics->exports.device_present(graphics->device);
1883 }
1884
gs_flush(void)1885 void gs_flush(void)
1886 {
1887 graphics_t *graphics = thread_graphics;
1888
1889 if (!gs_valid("gs_flush"))
1890 return;
1891
1892 graphics->exports.device_flush(graphics->device);
1893 }
1894
gs_set_cull_mode(enum gs_cull_mode mode)1895 void gs_set_cull_mode(enum gs_cull_mode mode)
1896 {
1897 graphics_t *graphics = thread_graphics;
1898
1899 if (!gs_valid("gs_set_cull_mode"))
1900 return;
1901
1902 graphics->exports.device_set_cull_mode(graphics->device, mode);
1903 }
1904
gs_get_cull_mode(void)1905 enum gs_cull_mode gs_get_cull_mode(void)
1906 {
1907 graphics_t *graphics = thread_graphics;
1908
1909 if (!gs_valid("gs_get_cull_mode"))
1910 return GS_NEITHER;
1911
1912 return graphics->exports.device_get_cull_mode(graphics->device);
1913 }
1914
gs_enable_blending(bool enable)1915 void gs_enable_blending(bool enable)
1916 {
1917 graphics_t *graphics = thread_graphics;
1918
1919 if (!gs_valid("gs_enable_blending"))
1920 return;
1921
1922 graphics->cur_blend_state.enabled = enable;
1923 graphics->exports.device_enable_blending(graphics->device, enable);
1924 }
1925
gs_enable_depth_test(bool enable)1926 void gs_enable_depth_test(bool enable)
1927 {
1928 graphics_t *graphics = thread_graphics;
1929
1930 if (!gs_valid("gs_enable_depth_test"))
1931 return;
1932
1933 graphics->exports.device_enable_depth_test(graphics->device, enable);
1934 }
1935
gs_enable_stencil_test(bool enable)1936 void gs_enable_stencil_test(bool enable)
1937 {
1938 graphics_t *graphics = thread_graphics;
1939
1940 if (!gs_valid("gs_enable_stencil_test"))
1941 return;
1942
1943 graphics->exports.device_enable_stencil_test(graphics->device, enable);
1944 }
1945
gs_enable_stencil_write(bool enable)1946 void gs_enable_stencil_write(bool enable)
1947 {
1948 graphics_t *graphics = thread_graphics;
1949
1950 if (!gs_valid("gs_enable_stencil_write"))
1951 return;
1952
1953 graphics->exports.device_enable_stencil_write(graphics->device, enable);
1954 }
1955
gs_enable_color(bool red,bool green,bool blue,bool alpha)1956 void gs_enable_color(bool red, bool green, bool blue, bool alpha)
1957 {
1958 graphics_t *graphics = thread_graphics;
1959
1960 if (!gs_valid("gs_enable_color"))
1961 return;
1962
1963 graphics->exports.device_enable_color(graphics->device, red, green,
1964 blue, alpha);
1965 }
1966
gs_blend_function(enum gs_blend_type src,enum gs_blend_type dest)1967 void gs_blend_function(enum gs_blend_type src, enum gs_blend_type dest)
1968 {
1969 graphics_t *graphics = thread_graphics;
1970
1971 if (!gs_valid("gs_blend_function"))
1972 return;
1973
1974 graphics->cur_blend_state.src_c = src;
1975 graphics->cur_blend_state.dest_c = dest;
1976 graphics->cur_blend_state.src_a = src;
1977 graphics->cur_blend_state.dest_a = dest;
1978 graphics->exports.device_blend_function(graphics->device, src, dest);
1979 }
1980
gs_blend_function_separate(enum gs_blend_type src_c,enum gs_blend_type dest_c,enum gs_blend_type src_a,enum gs_blend_type dest_a)1981 void gs_blend_function_separate(enum gs_blend_type src_c,
1982 enum gs_blend_type dest_c,
1983 enum gs_blend_type src_a,
1984 enum gs_blend_type dest_a)
1985 {
1986 graphics_t *graphics = thread_graphics;
1987
1988 if (!gs_valid("gs_blend_function_separate"))
1989 return;
1990
1991 graphics->cur_blend_state.src_c = src_c;
1992 graphics->cur_blend_state.dest_c = dest_c;
1993 graphics->cur_blend_state.src_a = src_a;
1994 graphics->cur_blend_state.dest_a = dest_a;
1995 graphics->exports.device_blend_function_separate(
1996 graphics->device, src_c, dest_c, src_a, dest_a);
1997 }
1998
gs_depth_function(enum gs_depth_test test)1999 void gs_depth_function(enum gs_depth_test test)
2000 {
2001 graphics_t *graphics = thread_graphics;
2002
2003 if (!gs_valid("gs_depth_function"))
2004 return;
2005
2006 graphics->exports.device_depth_function(graphics->device, test);
2007 }
2008
gs_stencil_function(enum gs_stencil_side side,enum gs_depth_test test)2009 void gs_stencil_function(enum gs_stencil_side side, enum gs_depth_test test)
2010 {
2011 graphics_t *graphics = thread_graphics;
2012
2013 if (!gs_valid("gs_stencil_function"))
2014 return;
2015
2016 graphics->exports.device_stencil_function(graphics->device, side, test);
2017 }
2018
gs_stencil_op(enum gs_stencil_side side,enum gs_stencil_op_type fail,enum gs_stencil_op_type zfail,enum gs_stencil_op_type zpass)2019 void gs_stencil_op(enum gs_stencil_side side, enum gs_stencil_op_type fail,
2020 enum gs_stencil_op_type zfail, enum gs_stencil_op_type zpass)
2021 {
2022 graphics_t *graphics = thread_graphics;
2023
2024 if (!gs_valid("gs_stencil_op"))
2025 return;
2026
2027 graphics->exports.device_stencil_op(graphics->device, side, fail, zfail,
2028 zpass);
2029 }
2030
gs_set_viewport(int x,int y,int width,int height)2031 void gs_set_viewport(int x, int y, int width, int height)
2032 {
2033 graphics_t *graphics = thread_graphics;
2034
2035 if (!gs_valid("gs_set_viewport"))
2036 return;
2037
2038 graphics->exports.device_set_viewport(graphics->device, x, y, width,
2039 height);
2040 }
2041
gs_get_viewport(struct gs_rect * rect)2042 void gs_get_viewport(struct gs_rect *rect)
2043 {
2044 graphics_t *graphics = thread_graphics;
2045
2046 if (!gs_valid_p("gs_get_viewport", rect))
2047 return;
2048
2049 graphics->exports.device_get_viewport(graphics->device, rect);
2050 }
2051
gs_set_scissor_rect(const struct gs_rect * rect)2052 void gs_set_scissor_rect(const struct gs_rect *rect)
2053 {
2054 graphics_t *graphics = thread_graphics;
2055
2056 if (!gs_valid("gs_set_scissor_rect"))
2057 return;
2058
2059 graphics->exports.device_set_scissor_rect(graphics->device, rect);
2060 }
2061
gs_ortho(float left,float right,float top,float bottom,float znear,float zfar)2062 void gs_ortho(float left, float right, float top, float bottom, float znear,
2063 float zfar)
2064 {
2065 graphics_t *graphics = thread_graphics;
2066
2067 if (!gs_valid("gs_ortho"))
2068 return;
2069
2070 graphics->exports.device_ortho(graphics->device, left, right, top,
2071 bottom, znear, zfar);
2072 }
2073
gs_frustum(float left,float right,float top,float bottom,float znear,float zfar)2074 void gs_frustum(float left, float right, float top, float bottom, float znear,
2075 float zfar)
2076 {
2077 graphics_t *graphics = thread_graphics;
2078
2079 if (!gs_valid("gs_frustum"))
2080 return;
2081
2082 graphics->exports.device_frustum(graphics->device, left, right, top,
2083 bottom, znear, zfar);
2084 }
2085
gs_projection_push(void)2086 void gs_projection_push(void)
2087 {
2088 graphics_t *graphics = thread_graphics;
2089
2090 if (!gs_valid("gs_projection_push"))
2091 return;
2092
2093 graphics->exports.device_projection_push(graphics->device);
2094 }
2095
gs_projection_pop(void)2096 void gs_projection_pop(void)
2097 {
2098 graphics_t *graphics = thread_graphics;
2099
2100 if (!gs_valid("gs_projection_pop"))
2101 return;
2102
2103 graphics->exports.device_projection_pop(graphics->device);
2104 }
2105
gs_swapchain_destroy(gs_swapchain_t * swapchain)2106 void gs_swapchain_destroy(gs_swapchain_t *swapchain)
2107 {
2108 graphics_t *graphics = thread_graphics;
2109
2110 if (!gs_valid("gs_swapchain_destroy"))
2111 return;
2112 if (!swapchain)
2113 return;
2114
2115 graphics->exports.gs_swapchain_destroy(swapchain);
2116 }
2117
gs_shader_destroy(gs_shader_t * shader)2118 void gs_shader_destroy(gs_shader_t *shader)
2119 {
2120 graphics_t *graphics = thread_graphics;
2121
2122 if (!gs_valid("gs_shader_destroy"))
2123 return;
2124 if (!shader)
2125 return;
2126
2127 graphics->exports.gs_shader_destroy(shader);
2128 }
2129
gs_shader_get_num_params(const gs_shader_t * shader)2130 int gs_shader_get_num_params(const gs_shader_t *shader)
2131 {
2132 graphics_t *graphics = thread_graphics;
2133
2134 if (!gs_valid_p("gs_shader_get_num_params", shader))
2135 return 0;
2136
2137 return graphics->exports.gs_shader_get_num_params(shader);
2138 }
2139
gs_shader_get_param_by_idx(gs_shader_t * shader,uint32_t param)2140 gs_sparam_t *gs_shader_get_param_by_idx(gs_shader_t *shader, uint32_t param)
2141 {
2142 graphics_t *graphics = thread_graphics;
2143
2144 if (!gs_valid_p("gs_shader_get_param_by_idx", shader))
2145 return NULL;
2146
2147 return graphics->exports.gs_shader_get_param_by_idx(shader, param);
2148 }
2149
gs_shader_get_param_by_name(gs_shader_t * shader,const char * name)2150 gs_sparam_t *gs_shader_get_param_by_name(gs_shader_t *shader, const char *name)
2151 {
2152 graphics_t *graphics = thread_graphics;
2153
2154 if (!gs_valid_p2("gs_shader_get_param_by_name", shader, name))
2155 return NULL;
2156
2157 return graphics->exports.gs_shader_get_param_by_name(shader, name);
2158 }
2159
gs_shader_get_viewproj_matrix(const gs_shader_t * shader)2160 gs_sparam_t *gs_shader_get_viewproj_matrix(const gs_shader_t *shader)
2161 {
2162 graphics_t *graphics = thread_graphics;
2163
2164 if (!gs_valid_p("gs_shader_get_viewproj_matrix", shader))
2165 return NULL;
2166
2167 return graphics->exports.gs_shader_get_viewproj_matrix(shader);
2168 }
2169
gs_shader_get_world_matrix(const gs_shader_t * shader)2170 gs_sparam_t *gs_shader_get_world_matrix(const gs_shader_t *shader)
2171 {
2172 graphics_t *graphics = thread_graphics;
2173
2174 if (!gs_valid_p("gs_shader_get_world_matrix", shader))
2175 return NULL;
2176
2177 return graphics->exports.gs_shader_get_world_matrix(shader);
2178 }
2179
gs_shader_get_param_info(const gs_sparam_t * param,struct gs_shader_param_info * info)2180 void gs_shader_get_param_info(const gs_sparam_t *param,
2181 struct gs_shader_param_info *info)
2182 {
2183 graphics_t *graphics = thread_graphics;
2184
2185 if (!gs_valid_p2("gs_shader_get_param_info", param, info))
2186 return;
2187
2188 graphics->exports.gs_shader_get_param_info(param, info);
2189 }
2190
gs_shader_set_bool(gs_sparam_t * param,bool val)2191 void gs_shader_set_bool(gs_sparam_t *param, bool val)
2192 {
2193 graphics_t *graphics = thread_graphics;
2194
2195 if (!gs_valid_p("gs_shader_set_bool", param))
2196 return;
2197
2198 graphics->exports.gs_shader_set_bool(param, val);
2199 }
2200
gs_shader_set_float(gs_sparam_t * param,float val)2201 void gs_shader_set_float(gs_sparam_t *param, float val)
2202 {
2203 graphics_t *graphics = thread_graphics;
2204
2205 if (!gs_valid_p("gs_shader_set_float", param))
2206 return;
2207
2208 graphics->exports.gs_shader_set_float(param, val);
2209 }
2210
gs_shader_set_int(gs_sparam_t * param,int val)2211 void gs_shader_set_int(gs_sparam_t *param, int val)
2212 {
2213 graphics_t *graphics = thread_graphics;
2214
2215 if (!gs_valid_p("gs_shader_set_int", param))
2216 return;
2217
2218 graphics->exports.gs_shader_set_int(param, val);
2219 }
2220
gs_shader_set_matrix3(gs_sparam_t * param,const struct matrix3 * val)2221 void gs_shader_set_matrix3(gs_sparam_t *param, const struct matrix3 *val)
2222 {
2223 graphics_t *graphics = thread_graphics;
2224
2225 if (!gs_valid_p2("gs_shader_set_matrix3", param, val))
2226 return;
2227
2228 graphics->exports.gs_shader_set_matrix3(param, val);
2229 }
2230
gs_shader_set_matrix4(gs_sparam_t * param,const struct matrix4 * val)2231 void gs_shader_set_matrix4(gs_sparam_t *param, const struct matrix4 *val)
2232 {
2233 graphics_t *graphics = thread_graphics;
2234
2235 if (!gs_valid_p2("gs_shader_set_matrix4", param, val))
2236 return;
2237
2238 graphics->exports.gs_shader_set_matrix4(param, val);
2239 }
2240
gs_shader_set_vec2(gs_sparam_t * param,const struct vec2 * val)2241 void gs_shader_set_vec2(gs_sparam_t *param, const struct vec2 *val)
2242 {
2243 graphics_t *graphics = thread_graphics;
2244
2245 if (!gs_valid_p2("gs_shader_set_vec2", param, val))
2246 return;
2247
2248 graphics->exports.gs_shader_set_vec2(param, val);
2249 }
2250
gs_shader_set_vec3(gs_sparam_t * param,const struct vec3 * val)2251 void gs_shader_set_vec3(gs_sparam_t *param, const struct vec3 *val)
2252 {
2253 graphics_t *graphics = thread_graphics;
2254
2255 if (!gs_valid_p2("gs_shader_set_vec3", param, val))
2256 return;
2257
2258 graphics->exports.gs_shader_set_vec3(param, val);
2259 }
2260
gs_shader_set_vec4(gs_sparam_t * param,const struct vec4 * val)2261 void gs_shader_set_vec4(gs_sparam_t *param, const struct vec4 *val)
2262 {
2263 graphics_t *graphics = thread_graphics;
2264
2265 if (!gs_valid_p2("gs_shader_set_vec4", param, val))
2266 return;
2267
2268 graphics->exports.gs_shader_set_vec4(param, val);
2269 }
2270
gs_shader_set_texture(gs_sparam_t * param,gs_texture_t * val)2271 void gs_shader_set_texture(gs_sparam_t *param, gs_texture_t *val)
2272 {
2273 graphics_t *graphics = thread_graphics;
2274
2275 if (!gs_valid_p("gs_shader_set_texture", param))
2276 return;
2277
2278 graphics->exports.gs_shader_set_texture(param, val);
2279 }
2280
gs_shader_set_val(gs_sparam_t * param,const void * val,size_t size)2281 void gs_shader_set_val(gs_sparam_t *param, const void *val, size_t size)
2282 {
2283 graphics_t *graphics = thread_graphics;
2284
2285 if (!gs_valid_p2("gs_shader_set_val", param, val))
2286 return;
2287
2288 graphics->exports.gs_shader_set_val(param, val, size);
2289 }
2290
gs_shader_set_default(gs_sparam_t * param)2291 void gs_shader_set_default(gs_sparam_t *param)
2292 {
2293 graphics_t *graphics = thread_graphics;
2294
2295 if (!gs_valid_p("gs_shader_set_default", param))
2296 return;
2297
2298 graphics->exports.gs_shader_set_default(param);
2299 }
2300
gs_shader_set_next_sampler(gs_sparam_t * param,gs_samplerstate_t * sampler)2301 void gs_shader_set_next_sampler(gs_sparam_t *param, gs_samplerstate_t *sampler)
2302 {
2303 graphics_t *graphics = thread_graphics;
2304
2305 if (!gs_valid_p("gs_shader_set_next_sampler", param))
2306 return;
2307
2308 graphics->exports.gs_shader_set_next_sampler(param, sampler);
2309 }
2310
gs_texture_destroy(gs_texture_t * tex)2311 void gs_texture_destroy(gs_texture_t *tex)
2312 {
2313 graphics_t *graphics = thread_graphics;
2314
2315 if (!gs_valid("gs_texture_destroy"))
2316 return;
2317 if (!tex)
2318 return;
2319
2320 graphics->exports.gs_texture_destroy(tex);
2321 }
2322
gs_texture_get_width(const gs_texture_t * tex)2323 uint32_t gs_texture_get_width(const gs_texture_t *tex)
2324 {
2325 graphics_t *graphics = thread_graphics;
2326
2327 if (!gs_valid_p("gs_texture_get_width", tex))
2328 return 0;
2329
2330 return graphics->exports.gs_texture_get_width(tex);
2331 }
2332
gs_texture_get_height(const gs_texture_t * tex)2333 uint32_t gs_texture_get_height(const gs_texture_t *tex)
2334 {
2335 graphics_t *graphics = thread_graphics;
2336
2337 if (!gs_valid_p("gs_texture_get_height", tex))
2338 return 0;
2339
2340 return graphics->exports.gs_texture_get_height(tex);
2341 }
2342
gs_texture_get_color_format(const gs_texture_t * tex)2343 enum gs_color_format gs_texture_get_color_format(const gs_texture_t *tex)
2344 {
2345 graphics_t *graphics = thread_graphics;
2346
2347 if (!gs_valid_p("gs_texture_get_color_format", tex))
2348 return GS_UNKNOWN;
2349
2350 return graphics->exports.gs_texture_get_color_format(tex);
2351 }
2352
gs_texture_map(gs_texture_t * tex,uint8_t ** ptr,uint32_t * linesize)2353 bool gs_texture_map(gs_texture_t *tex, uint8_t **ptr, uint32_t *linesize)
2354 {
2355 graphics_t *graphics = thread_graphics;
2356
2357 if (!gs_valid_p3("gs_texture_map", tex, ptr, linesize))
2358 return false;
2359
2360 return graphics->exports.gs_texture_map(tex, ptr, linesize);
2361 }
2362
gs_texture_unmap(gs_texture_t * tex)2363 void gs_texture_unmap(gs_texture_t *tex)
2364 {
2365 graphics_t *graphics = thread_graphics;
2366
2367 if (!gs_valid_p("gs_texture_unmap", tex))
2368 return;
2369
2370 graphics->exports.gs_texture_unmap(tex);
2371 }
2372
gs_texture_is_rect(const gs_texture_t * tex)2373 bool gs_texture_is_rect(const gs_texture_t *tex)
2374 {
2375 graphics_t *graphics = thread_graphics;
2376
2377 if (!gs_valid_p("gs_texture_is_rect", tex))
2378 return false;
2379
2380 if (graphics->exports.gs_texture_is_rect)
2381 return graphics->exports.gs_texture_is_rect(tex);
2382 else
2383 return false;
2384 }
2385
gs_texture_get_obj(gs_texture_t * tex)2386 void *gs_texture_get_obj(gs_texture_t *tex)
2387 {
2388 graphics_t *graphics = thread_graphics;
2389
2390 if (!gs_valid_p("gs_texture_get_obj", tex))
2391 return NULL;
2392
2393 return graphics->exports.gs_texture_get_obj(tex);
2394 }
2395
gs_cubetexture_destroy(gs_texture_t * cubetex)2396 void gs_cubetexture_destroy(gs_texture_t *cubetex)
2397 {
2398 graphics_t *graphics = thread_graphics;
2399
2400 if (!gs_valid("gs_cubetexture_destroy"))
2401 return;
2402 if (!cubetex)
2403 return;
2404
2405 graphics->exports.gs_cubetexture_destroy(cubetex);
2406 }
2407
gs_cubetexture_get_size(const gs_texture_t * cubetex)2408 uint32_t gs_cubetexture_get_size(const gs_texture_t *cubetex)
2409 {
2410 graphics_t *graphics = thread_graphics;
2411
2412 if (!gs_valid_p("gs_cubetexture_get_size", cubetex))
2413 return 0;
2414
2415 return graphics->exports.gs_cubetexture_get_size(cubetex);
2416 }
2417
2418 enum gs_color_format
gs_cubetexture_get_color_format(const gs_texture_t * cubetex)2419 gs_cubetexture_get_color_format(const gs_texture_t *cubetex)
2420 {
2421 graphics_t *graphics = thread_graphics;
2422
2423 if (!gs_valid_p("gs_cubetexture_get_color_format", cubetex))
2424 return GS_UNKNOWN;
2425
2426 return graphics->exports.gs_cubetexture_get_color_format(cubetex);
2427 }
2428
gs_voltexture_destroy(gs_texture_t * voltex)2429 void gs_voltexture_destroy(gs_texture_t *voltex)
2430 {
2431 graphics_t *graphics = thread_graphics;
2432
2433 if (!gs_valid("gs_voltexture_destroy"))
2434 return;
2435 if (!voltex)
2436 return;
2437
2438 graphics->exports.gs_voltexture_destroy(voltex);
2439 }
2440
gs_voltexture_get_width(const gs_texture_t * voltex)2441 uint32_t gs_voltexture_get_width(const gs_texture_t *voltex)
2442 {
2443 graphics_t *graphics = thread_graphics;
2444
2445 if (!gs_valid_p("gs_voltexture_get_width", voltex))
2446 return 0;
2447
2448 return graphics->exports.gs_voltexture_get_width(voltex);
2449 }
2450
gs_voltexture_get_height(const gs_texture_t * voltex)2451 uint32_t gs_voltexture_get_height(const gs_texture_t *voltex)
2452 {
2453 graphics_t *graphics = thread_graphics;
2454
2455 if (!gs_valid_p("gs_voltexture_get_height", voltex))
2456 return 0;
2457
2458 return graphics->exports.gs_voltexture_get_height(voltex);
2459 }
2460
gs_voltexture_get_depth(const gs_texture_t * voltex)2461 uint32_t gs_voltexture_get_depth(const gs_texture_t *voltex)
2462 {
2463 graphics_t *graphics = thread_graphics;
2464
2465 if (!gs_valid_p("gs_voltexture_get_depth", voltex))
2466 return 0;
2467
2468 return graphics->exports.gs_voltexture_get_depth(voltex);
2469 }
2470
gs_voltexture_get_color_format(const gs_texture_t * voltex)2471 enum gs_color_format gs_voltexture_get_color_format(const gs_texture_t *voltex)
2472 {
2473 graphics_t *graphics = thread_graphics;
2474
2475 if (!gs_valid_p("gs_voltexture_get_color_format", voltex))
2476 return GS_UNKNOWN;
2477
2478 return graphics->exports.gs_voltexture_get_color_format(voltex);
2479 }
2480
gs_stagesurface_destroy(gs_stagesurf_t * stagesurf)2481 void gs_stagesurface_destroy(gs_stagesurf_t *stagesurf)
2482 {
2483 graphics_t *graphics = thread_graphics;
2484
2485 if (!gs_valid("gs_stagesurface_destroy"))
2486 return;
2487 if (!stagesurf)
2488 return;
2489
2490 graphics->exports.gs_stagesurface_destroy(stagesurf);
2491 }
2492
gs_stagesurface_get_width(const gs_stagesurf_t * stagesurf)2493 uint32_t gs_stagesurface_get_width(const gs_stagesurf_t *stagesurf)
2494 {
2495 graphics_t *graphics = thread_graphics;
2496
2497 if (!gs_valid_p("gs_stagesurface_get_width", stagesurf))
2498 return 0;
2499
2500 return graphics->exports.gs_stagesurface_get_width(stagesurf);
2501 }
2502
gs_stagesurface_get_height(const gs_stagesurf_t * stagesurf)2503 uint32_t gs_stagesurface_get_height(const gs_stagesurf_t *stagesurf)
2504 {
2505 graphics_t *graphics = thread_graphics;
2506
2507 if (!gs_valid_p("gs_stagesurface_get_height", stagesurf))
2508 return 0;
2509
2510 return graphics->exports.gs_stagesurface_get_height(stagesurf);
2511 }
2512
2513 enum gs_color_format
gs_stagesurface_get_color_format(const gs_stagesurf_t * stagesurf)2514 gs_stagesurface_get_color_format(const gs_stagesurf_t *stagesurf)
2515 {
2516 graphics_t *graphics = thread_graphics;
2517
2518 if (!gs_valid_p("gs_stagesurface_get_color_format", stagesurf))
2519 return GS_UNKNOWN;
2520
2521 return graphics->exports.gs_stagesurface_get_color_format(stagesurf);
2522 }
2523
gs_stagesurface_map(gs_stagesurf_t * stagesurf,uint8_t ** data,uint32_t * linesize)2524 bool gs_stagesurface_map(gs_stagesurf_t *stagesurf, uint8_t **data,
2525 uint32_t *linesize)
2526 {
2527 graphics_t *graphics = thread_graphics;
2528
2529 if (!gs_valid_p3("gs_stagesurface_map", stagesurf, data, linesize))
2530 return 0;
2531
2532 return graphics->exports.gs_stagesurface_map(stagesurf, data, linesize);
2533 }
2534
gs_stagesurface_unmap(gs_stagesurf_t * stagesurf)2535 void gs_stagesurface_unmap(gs_stagesurf_t *stagesurf)
2536 {
2537 graphics_t *graphics = thread_graphics;
2538
2539 if (!gs_valid_p("gs_stagesurface_unmap", stagesurf))
2540 return;
2541
2542 graphics->exports.gs_stagesurface_unmap(stagesurf);
2543 }
2544
gs_zstencil_destroy(gs_zstencil_t * zstencil)2545 void gs_zstencil_destroy(gs_zstencil_t *zstencil)
2546 {
2547 if (!gs_valid("gs_zstencil_destroy"))
2548 return;
2549 if (!zstencil)
2550 return;
2551
2552 thread_graphics->exports.gs_zstencil_destroy(zstencil);
2553 }
2554
gs_samplerstate_destroy(gs_samplerstate_t * samplerstate)2555 void gs_samplerstate_destroy(gs_samplerstate_t *samplerstate)
2556 {
2557 if (!gs_valid("gs_samplerstate_destroy"))
2558 return;
2559 if (!samplerstate)
2560 return;
2561
2562 thread_graphics->exports.gs_samplerstate_destroy(samplerstate);
2563 }
2564
gs_vertexbuffer_destroy(gs_vertbuffer_t * vertbuffer)2565 void gs_vertexbuffer_destroy(gs_vertbuffer_t *vertbuffer)
2566 {
2567 graphics_t *graphics = thread_graphics;
2568
2569 if (!gs_valid("gs_vertexbuffer_destroy"))
2570 return;
2571 if (!vertbuffer)
2572 return;
2573
2574 graphics->exports.gs_vertexbuffer_destroy(vertbuffer);
2575 }
2576
gs_vertexbuffer_flush(gs_vertbuffer_t * vertbuffer)2577 void gs_vertexbuffer_flush(gs_vertbuffer_t *vertbuffer)
2578 {
2579 if (!gs_valid_p("gs_vertexbuffer_flush", vertbuffer))
2580 return;
2581
2582 thread_graphics->exports.gs_vertexbuffer_flush(vertbuffer);
2583 }
2584
gs_vertexbuffer_flush_direct(gs_vertbuffer_t * vertbuffer,const struct gs_vb_data * data)2585 void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vertbuffer,
2586 const struct gs_vb_data *data)
2587 {
2588 if (!gs_valid_p2("gs_vertexbuffer_flush_direct", vertbuffer, data))
2589 return;
2590
2591 thread_graphics->exports.gs_vertexbuffer_flush_direct(vertbuffer, data);
2592 }
2593
gs_vertexbuffer_get_data(const gs_vertbuffer_t * vertbuffer)2594 struct gs_vb_data *gs_vertexbuffer_get_data(const gs_vertbuffer_t *vertbuffer)
2595 {
2596 if (!gs_valid_p("gs_vertexbuffer_get_data", vertbuffer))
2597 return NULL;
2598
2599 return thread_graphics->exports.gs_vertexbuffer_get_data(vertbuffer);
2600 }
2601
gs_indexbuffer_destroy(gs_indexbuffer_t * indexbuffer)2602 void gs_indexbuffer_destroy(gs_indexbuffer_t *indexbuffer)
2603 {
2604 graphics_t *graphics = thread_graphics;
2605
2606 if (!gs_valid("gs_indexbuffer_destroy"))
2607 return;
2608 if (!indexbuffer)
2609 return;
2610
2611 graphics->exports.gs_indexbuffer_destroy(indexbuffer);
2612 }
2613
gs_indexbuffer_flush(gs_indexbuffer_t * indexbuffer)2614 void gs_indexbuffer_flush(gs_indexbuffer_t *indexbuffer)
2615 {
2616 if (!gs_valid_p("gs_indexbuffer_flush", indexbuffer))
2617 return;
2618
2619 thread_graphics->exports.gs_indexbuffer_flush(indexbuffer);
2620 }
2621
gs_indexbuffer_flush_direct(gs_indexbuffer_t * indexbuffer,const void * data)2622 void gs_indexbuffer_flush_direct(gs_indexbuffer_t *indexbuffer,
2623 const void *data)
2624 {
2625 if (!gs_valid_p2("gs_indexbuffer_flush_direct", indexbuffer, data))
2626 return;
2627
2628 thread_graphics->exports.gs_indexbuffer_flush_direct(indexbuffer, data);
2629 }
2630
gs_indexbuffer_get_data(const gs_indexbuffer_t * indexbuffer)2631 void *gs_indexbuffer_get_data(const gs_indexbuffer_t *indexbuffer)
2632 {
2633 if (!gs_valid_p("gs_indexbuffer_get_data", indexbuffer))
2634 return NULL;
2635
2636 return thread_graphics->exports.gs_indexbuffer_get_data(indexbuffer);
2637 }
2638
gs_indexbuffer_get_num_indices(const gs_indexbuffer_t * indexbuffer)2639 size_t gs_indexbuffer_get_num_indices(const gs_indexbuffer_t *indexbuffer)
2640 {
2641 if (!gs_valid_p("gs_indexbuffer_get_num_indices", indexbuffer))
2642 return 0;
2643
2644 return thread_graphics->exports.gs_indexbuffer_get_num_indices(
2645 indexbuffer);
2646 }
2647
gs_indexbuffer_get_type(const gs_indexbuffer_t * indexbuffer)2648 enum gs_index_type gs_indexbuffer_get_type(const gs_indexbuffer_t *indexbuffer)
2649 {
2650 if (!gs_valid_p("gs_indexbuffer_get_type", indexbuffer))
2651 return (enum gs_index_type)0;
2652
2653 return thread_graphics->exports.gs_indexbuffer_get_type(indexbuffer);
2654 }
2655
gs_timer_destroy(gs_timer_t * timer)2656 void gs_timer_destroy(gs_timer_t *timer)
2657 {
2658 graphics_t *graphics = thread_graphics;
2659
2660 if (!gs_valid("gs_timer_destroy"))
2661 return;
2662 if (!timer)
2663 return;
2664
2665 graphics->exports.gs_timer_destroy(timer);
2666 }
2667
gs_timer_begin(gs_timer_t * timer)2668 void gs_timer_begin(gs_timer_t *timer)
2669 {
2670 graphics_t *graphics = thread_graphics;
2671
2672 if (!gs_valid("gs_timer_begin"))
2673 return;
2674 if (!timer)
2675 return;
2676
2677 graphics->exports.gs_timer_begin(timer);
2678 }
2679
gs_timer_end(gs_timer_t * timer)2680 void gs_timer_end(gs_timer_t *timer)
2681 {
2682 graphics_t *graphics = thread_graphics;
2683
2684 if (!gs_valid("gs_timer_end"))
2685 return;
2686 if (!timer)
2687 return;
2688
2689 graphics->exports.gs_timer_end(timer);
2690 }
2691
gs_timer_get_data(gs_timer_t * timer,uint64_t * ticks)2692 bool gs_timer_get_data(gs_timer_t *timer, uint64_t *ticks)
2693 {
2694 if (!gs_valid_p2("gs_timer_get_data", timer, ticks))
2695 return false;
2696
2697 return thread_graphics->exports.gs_timer_get_data(timer, ticks);
2698 }
2699
gs_timer_range_destroy(gs_timer_range_t * range)2700 void gs_timer_range_destroy(gs_timer_range_t *range)
2701 {
2702 graphics_t *graphics = thread_graphics;
2703
2704 if (!gs_valid("gs_timer_range_destroy"))
2705 return;
2706 if (!range)
2707 return;
2708
2709 graphics->exports.gs_timer_range_destroy(range);
2710 }
2711
gs_timer_range_begin(gs_timer_range_t * range)2712 void gs_timer_range_begin(gs_timer_range_t *range)
2713 {
2714 graphics_t *graphics = thread_graphics;
2715
2716 if (!gs_valid("gs_timer_range_begin"))
2717 return;
2718 if (!range)
2719 return;
2720
2721 graphics->exports.gs_timer_range_begin(range);
2722 }
2723
gs_timer_range_end(gs_timer_range_t * range)2724 void gs_timer_range_end(gs_timer_range_t *range)
2725 {
2726 graphics_t *graphics = thread_graphics;
2727
2728 if (!gs_valid("gs_timer_range_end"))
2729 return;
2730 if (!range)
2731 return;
2732
2733 graphics->exports.gs_timer_range_end(range);
2734 }
2735
gs_timer_range_get_data(gs_timer_range_t * range,bool * disjoint,uint64_t * frequency)2736 bool gs_timer_range_get_data(gs_timer_range_t *range, bool *disjoint,
2737 uint64_t *frequency)
2738 {
2739 if (!gs_valid_p2("gs_timer_range_get_data", disjoint, frequency))
2740 return false;
2741
2742 return thread_graphics->exports.gs_timer_range_get_data(range, disjoint,
2743 frequency);
2744 }
2745
gs_nv12_available(void)2746 bool gs_nv12_available(void)
2747 {
2748 if (!gs_valid("gs_nv12_available"))
2749 return false;
2750
2751 if (!thread_graphics->exports.device_nv12_available)
2752 return false;
2753
2754 return thread_graphics->exports.device_nv12_available(
2755 thread_graphics->device);
2756 }
2757
gs_debug_marker_begin(const float color[4],const char * markername)2758 void gs_debug_marker_begin(const float color[4], const char *markername)
2759 {
2760 if (!gs_valid("gs_debug_marker_begin"))
2761 return;
2762
2763 if (!markername)
2764 markername = "(null)";
2765
2766 thread_graphics->exports.device_debug_marker_begin(
2767 thread_graphics->device, markername, color);
2768 }
2769
gs_debug_marker_begin_format(const float color[4],const char * format,...)2770 void gs_debug_marker_begin_format(const float color[4], const char *format, ...)
2771 {
2772 if (!gs_valid("gs_debug_marker_begin"))
2773 return;
2774
2775 if (format) {
2776 char markername[64];
2777 va_list args;
2778 va_start(args, format);
2779 vsnprintf(markername, sizeof(markername), format, args);
2780 va_end(args);
2781 thread_graphics->exports.device_debug_marker_begin(
2782 thread_graphics->device, markername, color);
2783 } else {
2784 gs_debug_marker_begin(color, NULL);
2785 }
2786 }
2787
gs_debug_marker_end(void)2788 void gs_debug_marker_end(void)
2789 {
2790 if (!gs_valid("gs_debug_marker_end"))
2791 return;
2792
2793 thread_graphics->exports.device_debug_marker_end(
2794 thread_graphics->device);
2795 }
2796
2797 #ifdef __APPLE__
2798
2799 /** Platform specific functions */
gs_texture_create_from_iosurface(void * iosurf)2800 gs_texture_t *gs_texture_create_from_iosurface(void *iosurf)
2801 {
2802 graphics_t *graphics = thread_graphics;
2803
2804 if (!gs_valid_p("gs_texture_create_from_iosurface", iosurf))
2805 return NULL;
2806 if (!graphics->exports.device_texture_create_from_iosurface)
2807 return NULL;
2808
2809 return graphics->exports.device_texture_create_from_iosurface(
2810 graphics->device, iosurf);
2811 }
2812
gs_texture_rebind_iosurface(gs_texture_t * texture,void * iosurf)2813 bool gs_texture_rebind_iosurface(gs_texture_t *texture, void *iosurf)
2814 {
2815 graphics_t *graphics = thread_graphics;
2816
2817 if (!gs_valid_p("gs_texture_rebind_iosurface", texture))
2818 return false;
2819 if (!graphics->exports.gs_texture_rebind_iosurface)
2820 return false;
2821
2822 return graphics->exports.gs_texture_rebind_iosurface(texture, iosurf);
2823 }
2824
gs_shared_texture_available(void)2825 bool gs_shared_texture_available(void)
2826 {
2827 if (!gs_valid("gs_shared_texture_available"))
2828 return false;
2829
2830 return thread_graphics->exports.device_shared_texture_available();
2831 }
2832
gs_texture_open_shared(uint32_t handle)2833 gs_texture_t *gs_texture_open_shared(uint32_t handle)
2834 {
2835 graphics_t *graphics = thread_graphics;
2836 if (!gs_valid("gs_texture_open_shared"))
2837 return NULL;
2838
2839 if (graphics->exports.device_texture_open_shared)
2840 return graphics->exports.device_texture_open_shared(
2841 graphics->device, handle);
2842 return NULL;
2843 }
2844
2845 #elif _WIN32
2846
gs_gdi_texture_available(void)2847 bool gs_gdi_texture_available(void)
2848 {
2849 if (!gs_valid("gs_gdi_texture_available"))
2850 return false;
2851
2852 return thread_graphics->exports.device_gdi_texture_available();
2853 }
2854
gs_shared_texture_available(void)2855 bool gs_shared_texture_available(void)
2856 {
2857 if (!gs_valid("gs_shared_texture_available"))
2858 return false;
2859
2860 return thread_graphics->exports.device_shared_texture_available();
2861 }
2862
gs_get_duplicator_monitor_info(int monitor_idx,struct gs_monitor_info * monitor_info)2863 bool gs_get_duplicator_monitor_info(int monitor_idx,
2864 struct gs_monitor_info *monitor_info)
2865 {
2866 if (!gs_valid_p("gs_get_duplicator_monitor_info", monitor_info))
2867 return false;
2868 if (!thread_graphics->exports.device_get_duplicator_monitor_info)
2869 return false;
2870
2871 return thread_graphics->exports.device_get_duplicator_monitor_info(
2872 thread_graphics->device, monitor_idx, monitor_info);
2873 }
2874
gs_duplicator_get_monitor_index(void * monitor)2875 int gs_duplicator_get_monitor_index(void *monitor)
2876 {
2877 if (!gs_valid("gs_duplicator_get_monitor_index"))
2878 return false;
2879 if (!thread_graphics->exports.device_duplicator_get_monitor_index)
2880 return false;
2881
2882 return thread_graphics->exports.device_duplicator_get_monitor_index(
2883 thread_graphics->device, monitor);
2884 }
2885
gs_duplicator_create(int monitor_idx)2886 gs_duplicator_t *gs_duplicator_create(int monitor_idx)
2887 {
2888 if (!gs_valid("gs_duplicator_create"))
2889 return NULL;
2890 if (!thread_graphics->exports.device_duplicator_create)
2891 return NULL;
2892
2893 return thread_graphics->exports.device_duplicator_create(
2894 thread_graphics->device, monitor_idx);
2895 }
2896
gs_duplicator_destroy(gs_duplicator_t * duplicator)2897 void gs_duplicator_destroy(gs_duplicator_t *duplicator)
2898 {
2899 if (!gs_valid("gs_duplicator_destroy"))
2900 return;
2901 if (!duplicator)
2902 return;
2903 if (!thread_graphics->exports.gs_duplicator_destroy)
2904 return;
2905
2906 thread_graphics->exports.gs_duplicator_destroy(duplicator);
2907 }
2908
gs_duplicator_update_frame(gs_duplicator_t * duplicator)2909 bool gs_duplicator_update_frame(gs_duplicator_t *duplicator)
2910 {
2911 if (!gs_valid_p("gs_duplicator_update_frame", duplicator))
2912 return false;
2913 if (!thread_graphics->exports.gs_duplicator_update_frame)
2914 return false;
2915
2916 return thread_graphics->exports.gs_duplicator_update_frame(duplicator);
2917 }
2918
gs_get_adapter_count(void)2919 uint32_t gs_get_adapter_count(void)
2920 {
2921 if (!gs_valid("gs_get_adapter_count"))
2922 return 0;
2923 if (!thread_graphics->exports.gs_get_adapter_count)
2924 return 0;
2925
2926 return thread_graphics->exports.gs_get_adapter_count();
2927 }
2928
gs_duplicator_get_texture(gs_duplicator_t * duplicator)2929 gs_texture_t *gs_duplicator_get_texture(gs_duplicator_t *duplicator)
2930 {
2931 if (!gs_valid_p("gs_duplicator_get_texture", duplicator))
2932 return NULL;
2933 if (!thread_graphics->exports.gs_duplicator_get_texture)
2934 return NULL;
2935
2936 return thread_graphics->exports.gs_duplicator_get_texture(duplicator);
2937 }
2938
2939 /** creates a windows GDI-lockable texture */
gs_texture_create_gdi(uint32_t width,uint32_t height)2940 gs_texture_t *gs_texture_create_gdi(uint32_t width, uint32_t height)
2941 {
2942 graphics_t *graphics = thread_graphics;
2943
2944 if (!gs_valid("gs_texture_create_gdi"))
2945 return NULL;
2946
2947 if (graphics->exports.device_texture_create_gdi)
2948 return graphics->exports.device_texture_create_gdi(
2949 graphics->device, width, height);
2950 return NULL;
2951 }
2952
gs_texture_get_dc(gs_texture_t * gdi_tex)2953 void *gs_texture_get_dc(gs_texture_t *gdi_tex)
2954 {
2955 if (!gs_valid_p("gs_texture_release_dc", gdi_tex))
2956 return NULL;
2957
2958 if (thread_graphics->exports.gs_texture_get_dc)
2959 return thread_graphics->exports.gs_texture_get_dc(gdi_tex);
2960 return NULL;
2961 }
2962
gs_texture_release_dc(gs_texture_t * gdi_tex)2963 void gs_texture_release_dc(gs_texture_t *gdi_tex)
2964 {
2965 if (!gs_valid_p("gs_texture_release_dc", gdi_tex))
2966 return;
2967
2968 if (thread_graphics->exports.gs_texture_release_dc)
2969 thread_graphics->exports.gs_texture_release_dc(gdi_tex);
2970 }
2971
gs_texture_open_shared(uint32_t handle)2972 gs_texture_t *gs_texture_open_shared(uint32_t handle)
2973 {
2974 graphics_t *graphics = thread_graphics;
2975 if (!gs_valid("gs_texture_open_shared"))
2976 return NULL;
2977
2978 if (graphics->exports.device_texture_open_shared)
2979 return graphics->exports.device_texture_open_shared(
2980 graphics->device, handle);
2981 return NULL;
2982 }
2983
gs_texture_get_shared_handle(gs_texture_t * tex)2984 uint32_t gs_texture_get_shared_handle(gs_texture_t *tex)
2985 {
2986 graphics_t *graphics = thread_graphics;
2987 if (!gs_valid("gs_texture_get_shared_handle"))
2988 return GS_INVALID_HANDLE;
2989
2990 if (graphics->exports.device_texture_get_shared_handle)
2991 return graphics->exports.device_texture_get_shared_handle(tex);
2992 return GS_INVALID_HANDLE;
2993 }
2994
gs_texture_wrap_obj(void * obj)2995 gs_texture_t *gs_texture_wrap_obj(void *obj)
2996 {
2997 graphics_t *graphics = thread_graphics;
2998 if (!gs_valid("gs_texture_wrap_obj"))
2999 return NULL;
3000
3001 if (graphics->exports.device_texture_wrap_obj)
3002 return graphics->exports.device_texture_wrap_obj(
3003 graphics->device, obj);
3004 return NULL;
3005 }
3006
gs_texture_acquire_sync(gs_texture_t * tex,uint64_t key,uint32_t ms)3007 int gs_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms)
3008 {
3009 graphics_t *graphics = thread_graphics;
3010 if (!gs_valid("gs_texture_acquire_sync"))
3011 return -1;
3012
3013 if (graphics->exports.device_texture_acquire_sync)
3014 return graphics->exports.device_texture_acquire_sync(tex, key,
3015 ms);
3016 return -1;
3017 }
3018
gs_texture_release_sync(gs_texture_t * tex,uint64_t key)3019 int gs_texture_release_sync(gs_texture_t *tex, uint64_t key)
3020 {
3021 graphics_t *graphics = thread_graphics;
3022 if (!gs_valid("gs_texture_release_sync"))
3023 return -1;
3024
3025 if (graphics->exports.device_texture_release_sync)
3026 return graphics->exports.device_texture_release_sync(tex, key);
3027 return -1;
3028 }
3029
gs_texture_create_nv12(gs_texture_t ** tex_y,gs_texture_t ** tex_uv,uint32_t width,uint32_t height,uint32_t flags)3030 bool gs_texture_create_nv12(gs_texture_t **tex_y, gs_texture_t **tex_uv,
3031 uint32_t width, uint32_t height, uint32_t flags)
3032 {
3033 graphics_t *graphics = thread_graphics;
3034 bool success = false;
3035
3036 if (!gs_valid("gs_texture_create_nv12"))
3037 return false;
3038
3039 if ((width & 1) == 1 || (height & 1) == 1) {
3040 blog(LOG_ERROR, "NV12 textures must have dimensions "
3041 "divisible by 2.");
3042 return false;
3043 }
3044
3045 if (graphics->exports.device_texture_create_nv12) {
3046 success = graphics->exports.device_texture_create_nv12(
3047 graphics->device, tex_y, tex_uv, width, height, flags);
3048 if (success)
3049 return true;
3050 }
3051
3052 *tex_y = gs_texture_create(width, height, GS_R8, 1, NULL, flags);
3053 *tex_uv = gs_texture_create(width / 2, height / 2, GS_R8G8, 1, NULL,
3054 flags);
3055
3056 if (!*tex_y || !*tex_uv) {
3057 if (*tex_y)
3058 gs_texture_destroy(*tex_y);
3059 if (*tex_uv)
3060 gs_texture_destroy(*tex_uv);
3061 *tex_y = NULL;
3062 *tex_uv = NULL;
3063 return false;
3064 }
3065
3066 return true;
3067 }
3068
gs_stagesurface_create_nv12(uint32_t width,uint32_t height)3069 gs_stagesurf_t *gs_stagesurface_create_nv12(uint32_t width, uint32_t height)
3070 {
3071 graphics_t *graphics = thread_graphics;
3072
3073 if (!gs_valid("gs_stagesurface_create_nv12"))
3074 return NULL;
3075
3076 if ((width & 1) == 1 || (height & 1) == 1) {
3077 blog(LOG_ERROR, "NV12 textures must have dimensions "
3078 "divisible by 2.");
3079 return NULL;
3080 }
3081
3082 if (graphics->exports.device_stagesurface_create_nv12)
3083 return graphics->exports.device_stagesurface_create_nv12(
3084 graphics->device, width, height);
3085
3086 return NULL;
3087 }
3088
gs_register_loss_callbacks(const struct gs_device_loss * callbacks)3089 void gs_register_loss_callbacks(const struct gs_device_loss *callbacks)
3090 {
3091 graphics_t *graphics = thread_graphics;
3092
3093 if (!gs_valid("gs_register_loss_callbacks"))
3094 return;
3095
3096 if (graphics->exports.device_register_loss_callbacks)
3097 graphics->exports.device_register_loss_callbacks(
3098 graphics->device, callbacks);
3099 }
3100
gs_unregister_loss_callbacks(void * data)3101 void gs_unregister_loss_callbacks(void *data)
3102 {
3103 graphics_t *graphics = thread_graphics;
3104
3105 if (!gs_valid("gs_unregister_loss_callbacks"))
3106 return;
3107
3108 if (graphics->exports.device_unregister_loss_callbacks)
3109 graphics->exports.device_unregister_loss_callbacks(
3110 graphics->device, data);
3111 }
3112
3113 #endif
3114