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