1 /*
2  * This software is licensed under the terms of the MIT License.
3  * See COPYING for further information.
4  * ---
5  * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6  * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7  */
8 
9 #include "taisei.h"
10 
11 #include "gl33.h"
12 #include "../api.h"
13 #include "../common/matstack.h"
14 #include "../common/backend.h"
15 #include "../common/sprite_batch.h"
16 #include "texture.h"
17 #include "shader_object.h"
18 #include "shader_program.h"
19 #include "framebuffer.h"
20 #include "common_buffer.h"
21 #include "vertex_buffer.h"
22 #include "index_buffer.h"
23 #include "vertex_array.h"
24 #include "../glcommon/debug.h"
25 #include "../glcommon/vtable.h"
26 #include "resource/resource.h"
27 #include "resource/model.h"
28 #include "util/glm.h"
29 #include "util/env.h"
30 
31 // #define GL33_DEBUG_TEXUNITS
32 
33 typedef struct TextureUnit {
34 	LIST_INTERFACE(struct TextureUnit);
35 
36 	struct {
37 		GLuint gl_handle;
38 		Texture *active;
39 		Texture *pending;
40 		bool locked;
41 	} tex2d;
42 } TextureUnit;
43 
44 #define TU_INDEX(unit) ((ptrdiff_t)((unit) - R.texunits.array))
45 
46 static struct {
47 	struct {
48 		TextureUnit *array;
49 		LIST_ANCHOR(TextureUnit) list;
50 		TextureUnit *active;
51 		TextureUnit *pending;
52 		GLint limit;
53 	} texunits;
54 
55 	struct {
56 		Framebuffer *active;
57 		Framebuffer *pending;
58 	} framebuffer;
59 
60 	struct {
61 		GLuint active;
62 		GLuint pending;
63 	} buffer_objects[GL33_NUM_BUFFER_BINDINGS];
64 
65 	struct {
66 		GLuint active;
67 		GLuint pending;
68 	} vao;
69 
70 	struct {
71 		GLuint gl_prog;
72 		ShaderProgram *active;
73 		ShaderProgram *pending;
74 	} progs;
75 
76 	struct {
77 		struct {
78 			BlendMode active;
79 			BlendMode pending;
80 		} mode;
81 		bool enabled;
82 	} blend;
83 
84 	struct {
85 		struct {
86 			CullFaceMode active;
87 			CullFaceMode pending;
88 		} mode;
89 	} cull_face;
90 
91 	struct {
92 		struct {
93 			DepthTestFunc active;
94 			DepthTestFunc pending;
95 		} func;
96 	} depth_test;
97 
98 	struct {
99 		r_capability_bits_t active;
100 		r_capability_bits_t pending;
101 	} capabilities;
102 
103 	struct {
104 		FloatRect active;
105 		FloatRect default_framebuffer;
106 	} viewport;
107 
108 	Color color;
109 	Color clear_color;
110 	float clear_depth;
111 	r_feature_bits_t features;
112 
113 	SDL_GLContext *gl_context;
114 	SDL_Window *window;
115 
116 	#ifdef GL33_DRAW_STATS
117 	struct {
118 		hrtime_t last_draw;
119 		hrtime_t draw_time;
120 		uint draw_calls;
121 	} stats;
122 	#endif
123 } R;
124 
125 /*
126  * Internal functions
127  */
128 
blendop_to_gl_blendop(BlendOp op)129 static GLenum blendop_to_gl_blendop(BlendOp op) {
130 	switch(op) {
131 		case BLENDOP_ADD:     return GL_FUNC_ADD;
132 		case BLENDOP_SUB:     return GL_FUNC_SUBTRACT;
133 		case BLENDOP_REV_SUB: return GL_FUNC_REVERSE_SUBTRACT;
134 		case BLENDOP_MAX:     return GL_MAX;
135 		case BLENDOP_MIN:     return GL_MIN;
136 	}
137 
138 	UNREACHABLE;
139 }
140 
blendfactor_to_gl_blendfactor(BlendFactor factor)141 static GLenum blendfactor_to_gl_blendfactor(BlendFactor factor) {
142 	switch(factor) {
143 		case BLENDFACTOR_DST_ALPHA:     return GL_DST_ALPHA;
144 		case BLENDFACTOR_INV_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
145 		case BLENDFACTOR_DST_COLOR:     return GL_DST_COLOR;
146 		case BLENDFACTOR_INV_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
147 		case BLENDFACTOR_INV_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
148 		case BLENDFACTOR_INV_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
149 		case BLENDFACTOR_ONE:           return GL_ONE;
150 		case BLENDFACTOR_SRC_ALPHA:     return GL_SRC_ALPHA;
151 		case BLENDFACTOR_SRC_COLOR:     return GL_SRC_COLOR;
152 		case BLENDFACTOR_ZERO:          return GL_ZERO;
153 	}
154 
155 	UNREACHABLE;
156 }
157 
r_cull_to_gl_cull(CullFaceMode mode)158 static inline GLenum r_cull_to_gl_cull(CullFaceMode mode) {
159 	switch(mode) {
160 		case CULL_BACK:
161 			return GL_BACK;
162 
163 		case CULL_FRONT:
164 			return GL_FRONT;
165 
166 		case CULL_BOTH:
167 			return GL_FRONT_AND_BACK;
168 
169 		default: UNREACHABLE;
170 	}
171 }
172 
gl33_stats_pre_draw(void)173 static inline void gl33_stats_pre_draw(void) {
174 	#ifdef GL33_DRAW_STATS
175 	R.stats.last_draw = time_get();
176 	R.stats.draw_calls++;
177 	#endif
178 }
179 
gl33_stats_post_draw(void)180 static inline void gl33_stats_post_draw(void) {
181 	#ifdef GL33_DRAW_STATS
182 	R.stats.draw_time += (time_get() - R.stats.last_draw);
183 	#endif
184 }
185 
gl33_stats_post_frame(void)186 static inline void gl33_stats_post_frame(void) {
187 	#ifdef GL33_DRAW_STATS
188 	log_debug("%.20gs spent in %u draw calls", (double)R.stats.draw_time, R.stats.draw_calls);
189 	memset(&R.stats, 0, sizeof(R.stats));
190 	#endif
191 }
192 
gl33_init_texunits(void)193 static void gl33_init_texunits(void) {
194 	GLint texunits_available, texunits_capped, texunits_max, texunits_min = 4;
195 	glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &texunits_available);
196 
197 	if(texunits_available < texunits_min) {
198 		log_fatal("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is %i; at least %i is expected.", texunits_available, texunits_min);
199 	}
200 
201 	texunits_max = env_get_int("GL33_MAX_NUM_TEXUNITS", 32);
202 
203 	if(texunits_max == 0) {
204 		texunits_max = texunits_available;
205 	} else {
206 		texunits_max = iclamp(texunits_max, texunits_min, texunits_available);
207 	}
208 
209 	texunits_capped = imin(texunits_max, texunits_available);
210 	R.texunits.limit = env_get_int("GL33_NUM_TEXUNITS", texunits_capped);
211 
212 	if(R.texunits.limit == 0) {
213 		R.texunits.limit = texunits_available;
214 	} else {
215 		R.texunits.limit = iclamp(R.texunits.limit, texunits_min, texunits_available);
216 	}
217 
218 	R.texunits.array = calloc(R.texunits.limit, sizeof(TextureUnit));
219 	R.texunits.active = R.texunits.array;
220 
221 	for(int i = 0; i < R.texunits.limit; ++i) {
222 		TextureUnit *u = R.texunits.array + i;
223 		alist_append(&R.texunits.list, u);
224 	}
225 
226 	log_info("Using %i texturing units (%i available)", R.texunits.limit, texunits_available);
227 }
228 
gl33_get_viewport(FloatRect * vp)229 static void gl33_get_viewport(FloatRect *vp) {
230 	IntRect vp_int;
231 	glGetIntegerv(GL_VIEWPORT, &vp_int.x);
232 	vp->x = vp_int.x;
233 	vp->y = vp_int.y;
234 	vp->w = vp_int.w;
235 	vp->h = vp_int.h;
236 }
237 
gl33_set_viewport(const FloatRect * vp)238 static void gl33_set_viewport(const FloatRect *vp) {
239 	glViewport(vp->x, vp->y, vp->w, vp->h);
240 }
241 
242 #ifndef STATIC_GLES3
gl41_get_viewport(FloatRect * vp)243 static void gl41_get_viewport(FloatRect *vp) {
244 	glGetFloati_v(GL_VIEWPORT, 0, &vp->x);
245 }
246 
gl41_set_viewport(const FloatRect * vp)247 static void gl41_set_viewport(const FloatRect *vp) {
248 	glViewportIndexedfv(0, &vp->x);
249 }
250 #endif
251 
gl33_init_context(SDL_Window * window)252 static void gl33_init_context(SDL_Window *window) {
253 	R.gl_context = SDL_GL_CreateContext(window);
254 
255 	if(!R.gl_context) {
256 		log_fatal("Could not create the OpenGL context: %s", SDL_GetError());
257 	}
258 
259 	glcommon_load_functions();
260 	glcommon_check_capabilities();
261 
262 	if(glcommon_debug_requested()) {
263 		glcommon_debug_enable();
264 	}
265 
266 	gl33_init_texunits();
267 	gl33_set_clear_depth(1);
268 	gl33_set_clear_color(RGBA(0, 0, 0, 0));
269 
270 #ifdef STATIC_GLES3
271 	GLVT.get_viewport = gl33_get_viewport;
272 	GLVT.set_viewport = gl33_set_viewport;
273 #else
274 	if(glext.viewport_array) {
275 		GLVT.get_viewport = gl41_get_viewport;
276 		GLVT.set_viewport = gl41_set_viewport;
277 	} else {
278 		GLVT.get_viewport = gl33_get_viewport;
279 		GLVT.set_viewport = gl33_set_viewport;
280 	}
281 #endif
282 
283 	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
284 	glPixelStorei(GL_PACK_ALIGNMENT, 1);
285 	GLVT.get_viewport(&R.viewport.default_framebuffer);
286 
287 	if(HAVE_GL_FUNC(glReadBuffer)) {
288 		glReadBuffer(GL_BACK);
289 	}
290 
291 	R.viewport.active = R.viewport.default_framebuffer;
292 
293 	if(glext.instanced_arrays) {
294 		R.features |= r_feature_bit(RFEAT_DRAW_INSTANCED);
295 	}
296 
297 	if(glext.depth_texture) {
298 		R.features |= r_feature_bit(RFEAT_DEPTH_TEXTURE);
299 	}
300 
301 	if(glext.draw_buffers) {
302 		R.features |= r_feature_bit(RFEAT_FRAMEBUFFER_MULTIPLE_OUTPUTS);
303 	}
304 
305 	R.features |= r_feature_bit(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN);
306 
307 	if(glext.clear_texture) {
308 		_r_backend.funcs.texture_clear = gl44_texture_clear;
309 	}
310 }
311 
gl33_apply_capability(RendererCapability cap,bool value)312 static void gl33_apply_capability(RendererCapability cap, bool value) {
313 	switch(cap) {
314 		case RCAP_DEPTH_TEST:
315 			(value ? glEnable : glDisable)(GL_DEPTH_TEST);
316 			break;
317 
318 		case RCAP_DEPTH_WRITE:
319 			glDepthMask(value);
320 			break;
321 
322 		case RCAP_CULL_FACE:
323 			(value ? glEnable : glDisable)(GL_CULL_FACE);
324 			break;
325 
326 		default: UNREACHABLE;
327 	}
328 }
329 
transform_viewport_origin(Framebuffer * fb,FloatRect * vp)330 static void transform_viewport_origin(Framebuffer *fb, FloatRect *vp) {
331 	int fb_height = 0;
332 
333 	if(fb == NULL) {
334 		SDL_Window *win = SDL_GL_GetCurrentWindow();
335 		assume(win != NULL);
336 		SDL_GL_GetDrawableSize(win, NULL, &fb_height);
337 	} else {
338 		for(FramebufferAttachment a = FRAMEBUFFER_ATTACH_COLOR0; a < FRAMEBUFFER_MAX_ATTACHMENTS; ++a) {
339 			if(fb->attachments[a] != NULL) {
340 				fb_height = fb->attachments[a]->params.height;
341 				break;
342 			}
343 		}
344 	}
345 
346 	assert(fb_height > 0);
347 	vp->y = fb_height - vp->y - vp->h;
348 }
349 
get_framebuffer_viewport(Framebuffer * fb)350 static inline FloatRect* get_framebuffer_viewport(Framebuffer *fb) {
351 	if(fb == NULL) {
352 		return &R.viewport.default_framebuffer;
353 	}
354 
355 	return &fb->viewport;
356 }
357 
gl33_sync_viewport(void)358 static void gl33_sync_viewport(void) {
359 	FloatRect *vp = get_framebuffer_viewport(R.framebuffer.pending);
360 
361 	if(memcmp(&R.viewport.active, vp, sizeof(R.viewport.active))) {
362 		R.viewport.active = *vp;
363 		GLVT.set_viewport(vp);
364 	}
365 }
366 
gl33_sync_state(void)367 static void gl33_sync_state(void) {
368 	gl33_sync_capabilities();
369 	gl33_sync_shader();
370 	r_uniform_mat4("r_modelViewMatrix", *_r_matrices.modelview.head);
371 	r_uniform_mat4("r_projectionMatrix", *_r_matrices.projection.head);
372 	r_uniform_mat4("r_textureMatrix", *_r_matrices.texture.head);
373 	r_uniform_vec4_rgba("r_color", &R.color);
374 	gl33_sync_uniforms(R.progs.active);
375 	gl33_sync_texunits(true);
376 	gl33_sync_framebuffer();
377 	gl33_sync_viewport();
378 	gl33_sync_vao();
379 	gl33_sync_blend_mode();
380 
381 	if(R.capabilities.active & r_capability_bit(RCAP_CULL_FACE)) {
382 		gl33_sync_cull_face_mode();
383 	}
384 
385 	if(R.capabilities.active & r_capability_bit(RCAP_DEPTH_TEST)) {
386 		gl33_sync_depth_test_func();
387 	}
388 }
389 
390 /*
391  * Exported functions
392  */
393 
gl33_prim_to_gl_prim(Primitive prim)394 GLenum gl33_prim_to_gl_prim(Primitive prim) {
395 	static GLenum map[] = {
396 		[PRIM_POINTS]         = GL_POINTS,
397 		[PRIM_LINE_STRIP]     = GL_LINE_STRIP,
398 		[PRIM_LINE_LOOP]      = GL_LINE_LOOP,
399 		[PRIM_LINES]          = GL_LINES,
400 		[PRIM_TRIANGLE_STRIP] = GL_TRIANGLE_STRIP,
401 		[PRIM_TRIANGLES]      = GL_TRIANGLES,
402 	};
403 
404 	assert((uint)prim < sizeof(map)/sizeof(*map));
405 	return map[prim];
406 }
407 
gl33_sync_capabilities(void)408 void gl33_sync_capabilities(void) {
409 	if(R.capabilities.active == R.capabilities.pending) {
410 		return;
411 	}
412 
413 	for(RendererCapability cap = 0; cap < NUM_RCAPS; ++cap) {
414 		r_capability_bits_t flag = r_capability_bit(cap);
415 		bool pending = R.capabilities.pending & flag;
416 		bool active = R.capabilities.active & flag;
417 
418 		if(pending != active) {
419 			gl33_apply_capability(cap, pending);
420 		}
421 	}
422 
423 	R.capabilities.active = R.capabilities.pending;
424 }
425 
426 attr_nonnull(1)
gl33_activate_texunit(TextureUnit * unit)427 static void gl33_activate_texunit(TextureUnit *unit) {
428 	assert(unit >= R.texunits.array && unit < R.texunits.array + R.texunits.limit);
429 
430 	if(R.texunits.active != unit) {
431 		glActiveTexture(GL_TEXTURE0 + TU_INDEX(unit));
432 		R.texunits.active = unit;
433 #ifdef GL33_DEBUG_TEXUNITS
434 		log_debug("Activated unit %i", (uint)TU_INDEX(unit));
435 #endif
436 	}
437 }
438 
gl33_texunit_priority(TextureUnit * u)439 static int gl33_texunit_priority(TextureUnit *u) {
440 	if(u->tex2d.locked) {
441 		assert(u->tex2d.pending);
442 		return 3;
443 	}
444 
445 	if(u->tex2d.pending) {
446 		return 2;
447 	}
448 
449 	if(u->tex2d.active) {
450 		return 1;
451 	}
452 
453 	return 0;
454 }
455 
gl33_texunit_priority_callback(List * elem)456 static int gl33_texunit_priority_callback(List *elem) {
457 	TextureUnit *u = (TextureUnit*)elem;
458 	return gl33_texunit_priority(u);
459 }
460 
texture_str(Texture * tex,char * buf,size_t bufsize)461 attr_unused static void texture_str(Texture *tex, char *buf, size_t bufsize) {
462 	if(tex == NULL) {
463 		snprintf(buf, bufsize, "None");
464 	} else {
465 		snprintf(buf, bufsize, "\"%s\" (#%i; at %p)", tex->debug_label, tex->gl_handle, (void*)tex);
466 	}
467 }
468 
gl33_dump_texunits(void)469 attr_unused static void gl33_dump_texunits(void) {
470 	log_debug("=== BEGIN DUMP ===");
471 
472 	for(TextureUnit *u = R.texunits.list.first; u; u = u->next) {
473 		char buf1[128], buf2[128];
474 		texture_str(u->tex2d.active, buf1, sizeof(buf1));
475 		texture_str(u->tex2d.pending, buf2, sizeof(buf2));
476 		log_debug("[Unit %u | %i] bound: %s; pending: %s", (uint)TU_INDEX(u), gl33_texunit_priority(u), buf1, buf2);
477 	}
478 
479 	log_debug("=== END DUMP ===");
480 }
481 
gl33_relocate_texuint(TextureUnit * unit)482 static void gl33_relocate_texuint(TextureUnit *unit) {
483 	int prio = gl33_texunit_priority(unit);
484 
485 	alist_unlink(&R.texunits.list, unit);
486 
487 	if(prio > 1) {
488 		alist_insert_at_priority_tail(&R.texunits.list, unit, prio, gl33_texunit_priority_callback);
489 	} else {
490 		alist_insert_at_priority_head(&R.texunits.list, unit, prio, gl33_texunit_priority_callback);
491 	}
492 
493 #ifdef GL33_DEBUG_TEXUNITS
494 	// gl33_dump_texunits();
495 	// log_debug("Relocated unit %u", (uint)TU_INDEX(unit));
496 #endif
497 }
498 
499 attr_nonnull(1)
gl33_set_texunit_binding(TextureUnit * unit,Texture * tex,bool lock)500 static void gl33_set_texunit_binding(TextureUnit *unit, Texture *tex, bool lock) {
501 	assert(!unit->tex2d.locked);
502 
503 	if(unit->tex2d.pending == tex) {
504 		if(tex) {
505 			tex->binding_unit = unit;
506 		}
507 
508 		if(lock) {
509 			unit->tex2d.locked = true;
510 		}
511 
512 		// gl33_relocate_texuint(unit);
513 		return;
514 	}
515 
516 	if(unit->tex2d.pending != NULL) {
517 		// assert(unit->tex2d.pending->binding_unit == unit);
518 
519 		if(unit->tex2d.pending->binding_unit == unit) {
520 			// FIXME: should we search through the units for a matching binding,
521 			// just in case another unit had the same texture bound?
522 			unit->tex2d.pending->binding_unit = NULL;
523 		}
524 	}
525 
526 	unit->tex2d.pending = tex;
527 
528 	if(tex) {
529 		tex->binding_unit = unit;
530 	}
531 
532 	if(lock) {
533 		unit->tex2d.locked = true;
534 	}
535 
536 	gl33_relocate_texuint(unit);
537 }
538 
gl33_sync_texunit(TextureUnit * unit,bool prepare_rendering,bool ensure_active)539 void gl33_sync_texunit(TextureUnit *unit, bool prepare_rendering, bool ensure_active) {
540 	Texture *tex = unit->tex2d.pending;
541 
542 #ifdef GL33_DEBUG_TEXUNITS
543 	if(unit->tex2d.pending != unit->tex2d.active) {
544 		attr_unused char buf1[128], buf2[128];
545 		texture_str(unit->tex2d.active, buf1, sizeof(buf1));
546 		texture_str(unit->tex2d.pending, buf2, sizeof(buf2));
547 		log_debug("[Unit %u] %s ===> %s", (uint)TU_INDEX(unit), buf1, buf2);
548 	}
549 #endif
550 
551 	if(tex == NULL) {
552 		if(unit->tex2d.gl_handle != 0) {
553 			gl33_activate_texunit(unit);
554 			glBindTexture(GL_TEXTURE_2D, 0);
555 			unit->tex2d.gl_handle = 0;
556 			unit->tex2d.active = NULL;
557 			gl33_relocate_texuint(unit);
558 		}
559 	} else if(unit->tex2d.gl_handle != tex->gl_handle) {
560 		gl33_activate_texunit(unit);
561 		glBindTexture(GL_TEXTURE_2D, tex->gl_handle);
562 		unit->tex2d.gl_handle = tex->gl_handle;
563 
564 		if(unit->tex2d.active == NULL) {
565 			unit->tex2d.active = tex;
566 			gl33_relocate_texuint(unit);
567 		} else {
568 			unit->tex2d.active = tex;
569 		}
570 	} else if(ensure_active) {
571 		gl33_activate_texunit(unit);
572 	}
573 
574 	if(prepare_rendering && unit->tex2d.active != NULL) {
575 		gl33_texture_prepare(unit->tex2d.active);
576 		unit->tex2d.locked = false;
577 	}
578 }
579 
gl33_sync_texunits(bool prepare_rendering)580 void gl33_sync_texunits(bool prepare_rendering) {
581 	for(TextureUnit *u = R.texunits.array; u < R.texunits.array + R.texunits.limit; ++u) {
582 		gl33_sync_texunit(u, prepare_rendering, false);
583 	}
584 }
585 
gl33_sync_vao(void)586 void gl33_sync_vao(void) {
587 	if(R.vao.active != R.vao.pending) {
588 		R.vao.active = R.vao.pending;
589 		glBindVertexArray(R.vao.active);
590 	}
591 }
592 
gl33_bindidx_to_glenum(BufferBindingIndex bindidx)593 GLenum gl33_bindidx_to_glenum(BufferBindingIndex bindidx) {
594 	if(bindidx == GL33_BUFFER_BINDING_ELEMENT_ARRAY) {
595 		return GL_ELEMENT_ARRAY_BUFFER;
596 	}
597 
598 	static GLenum map[] = {
599 		[GL33_BUFFER_BINDING_ARRAY] = GL_ARRAY_BUFFER,
600 		[GL33_BUFFER_BINDING_COPY_WRITE] = GL_COPY_WRITE_BUFFER,
601 		[GL33_BUFFER_BINDING_PIXEL_UNPACK] = GL_PIXEL_UNPACK_BUFFER,
602 	};
603 
604 	static_assert(sizeof(map) == sizeof(GLenum) * GL33_NUM_BUFFER_BINDINGS, "Fix the lookup table");
605 	assert((uint)bindidx < GL33_NUM_BUFFER_BINDINGS);
606 	return map[bindidx];
607 }
608 
gl33_sync_buffer(BufferBindingIndex bindidx)609 void gl33_sync_buffer(BufferBindingIndex bindidx) {
610 	assert((uint)bindidx < GL33_NUM_BUFFER_BINDINGS);
611 
612 	if(R.buffer_objects[bindidx].active != R.buffer_objects[bindidx].pending) {
613 		R.buffer_objects[bindidx].active = R.buffer_objects[bindidx].pending;
614 		glBindBuffer(gl33_bindidx_to_glenum(bindidx), R.buffer_objects[bindidx].active);
615 	}
616 }
617 
gl33_sync_cull_face_mode(void)618 void gl33_sync_cull_face_mode(void) {
619 	if(R.cull_face.mode.pending != R.cull_face.mode.active) {
620 		GLenum glcull = r_cull_to_gl_cull(R.cull_face.mode.pending);
621 		glCullFace(glcull);
622 		R.cull_face.mode.active = R.cull_face.mode.pending;
623 	}
624 }
625 
gl33_sync_depth_test_func(void)626 void gl33_sync_depth_test_func(void) {
627 	DepthTestFunc func = R.depth_test.func.pending;
628 
629 	static GLenum func_to_glfunc[] = {
630 		[DEPTH_NEVER]     = GL_NEVER,
631 		[DEPTH_ALWAYS]    = GL_ALWAYS,
632 		[DEPTH_EQUAL]     = GL_EQUAL,
633 		[DEPTH_NOTEQUAL]  = GL_NOTEQUAL,
634 		[DEPTH_LESS]      = GL_LESS,
635 		[DEPTH_LEQUAL]    = GL_LEQUAL,
636 		[DEPTH_GREATER]   = GL_GREATER,
637 		[DEPTH_GEQUAL]    = GL_GEQUAL,
638 	};
639 
640 	uint32_t idx = func;
641 	assert(idx < sizeof(func_to_glfunc)/sizeof(GLenum));
642 
643 	if(R.depth_test.func.active != func) {
644 		glDepthFunc(func_to_glfunc[idx]);
645 		R.depth_test.func.active = func;
646 	}
647 }
648 
fbo_num(Framebuffer * fb)649 static inline GLuint fbo_num(Framebuffer *fb) {
650 	if(fb == NULL) {
651 		return 0;
652 	}
653 
654 	assert(fb->gl_fbo != 0);
655 	return fb->gl_fbo;
656 }
657 
gl33_sync_framebuffer(void)658 void gl33_sync_framebuffer(void) {
659 	if(fbo_num(R.framebuffer.active) != fbo_num(R.framebuffer.pending)) {
660 		glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_num(R.framebuffer.pending));
661 		R.framebuffer.active = R.framebuffer.pending;
662 	}
663 
664 	if(R.framebuffer.active) {
665 		gl33_framebuffer_prepare(R.framebuffer.active);
666 	}
667 }
668 
gl33_sync_shader(void)669 void gl33_sync_shader(void) {
670 	if(R.progs.pending && R.progs.gl_prog != R.progs.pending->gl_handle) {
671 		glUseProgram(R.progs.pending->gl_handle);
672 		R.progs.gl_prog = R.progs.pending->gl_handle;
673 		R.progs.active = R.progs.pending;
674 	}
675 }
676 
gl33_sync_blend_mode(void)677 void gl33_sync_blend_mode(void) {
678 	BlendMode mode = R.blend.mode.pending;
679 
680 	if(mode == BLEND_NONE) {
681 		if(R.blend.enabled) {
682 			glDisable(GL_BLEND);
683 			R.blend.enabled = false;
684 		}
685 
686 		return;
687 	}
688 
689 	if(!R.blend.enabled) {
690 		R.blend.enabled = true;
691 		glEnable(GL_BLEND);
692 	}
693 
694 	if(mode != R.blend.mode.active) {
695 		static UnpackedBlendMode umode;
696 		r_blend_unpack(mode, &umode);
697 		R.blend.mode.active = mode;
698 
699 		// TODO: maybe cache the funcs and factors separately,
700 		// because the blend funcs change a lot less frequently.
701 
702 		glBlendEquationSeparate(
703 			blendop_to_gl_blendop(umode.color.op),
704 			blendop_to_gl_blendop(umode.alpha.op)
705 		);
706 
707 		glBlendFuncSeparate(
708 			blendfactor_to_gl_blendfactor(umode.color.src),
709 			blendfactor_to_gl_blendfactor(umode.color.dst),
710 			blendfactor_to_gl_blendfactor(umode.alpha.src),
711 			blendfactor_to_gl_blendfactor(umode.alpha.dst)
712 		);
713 	}
714 }
715 
gl33_bind_texture(Texture * texture,bool for_rendering,int preferred_unit)716 uint gl33_bind_texture(Texture *texture, bool for_rendering, int preferred_unit) {
717 	if(glext.issues.avoid_sampler_uniform_updates && preferred_unit >= 0) {
718 		assert(preferred_unit < R.texunits.limit);
719 		TextureUnit *u = &R.texunits.array[preferred_unit];
720 
721 		if(u->tex2d.pending == texture) {
722 			u->tex2d.locked |= for_rendering;
723 		} else {
724 			gl33_set_texunit_binding(u, texture, for_rendering);
725 		}
726 
727 		// In this case the texture may be bound to more than one unit.
728 		// This is fine though, and we just always update binding_unit to the
729 		// most recent binding.
730 		texture->binding_unit = u;
731 	} else if(!texture->binding_unit) {
732 		// assert(R.texunits.list.first->tex2d.pending != texture);
733 
734 		if(
735 			R.texunits.list.first->tex2d.pending &&
736 			R.texunits.list.first->tex2d.pending != R.texunits.list.first->tex2d.active
737 		) {
738 			log_warn("Ran out of texturing units, expect rendering errors!");
739 		}
740 
741 		gl33_set_texunit_binding(R.texunits.list.first, texture, for_rendering);
742 	} else /* if(for_rendering) */ {
743 		texture->binding_unit->tex2d.locked |= for_rendering;
744 		gl33_relocate_texuint(texture->binding_unit);
745 	}
746 
747 	assert(texture->binding_unit->tex2d.pending == texture);
748 	return TU_INDEX(texture->binding_unit);
749 }
750 
gl33_bind_buffer(BufferBindingIndex bindidx,GLuint gl_handle)751 void gl33_bind_buffer(BufferBindingIndex bindidx, GLuint gl_handle) {
752 	R.buffer_objects[bindidx].pending = gl_handle;
753 }
754 
gl33_bind_vao(GLuint vao)755 void gl33_bind_vao(GLuint vao) {
756 	R.vao.pending = vao;
757 }
758 
gl33_buffer_current(BufferBindingIndex bindidx)759 GLuint gl33_buffer_current(BufferBindingIndex bindidx) {
760 	return R.buffer_objects[bindidx].pending;
761 }
762 
gl33_vao_current(void)763 GLuint gl33_vao_current(void) {
764 	return R.vao.pending;
765 }
766 
gl33_texture_deleted(Texture * tex)767 void gl33_texture_deleted(Texture *tex) {
768 	_r_sprite_batch_texture_deleted(tex);
769 	gl33_unref_texture_from_samplers(tex);
770 
771 	for(TextureUnit *unit = R.texunits.array; unit < R.texunits.array + R.texunits.limit; ++unit) {
772 		bool bump = false;
773 
774 		if(unit->tex2d.pending == tex) {
775 			unit->tex2d.pending = NULL;
776 			unit->tex2d.locked = false;
777 			bump = true;
778 		}
779 
780 		if(unit->tex2d.active == tex) {
781 			assert(unit->tex2d.gl_handle == tex->gl_handle);
782 			unit->tex2d.active = NULL;
783 			unit->tex2d.gl_handle = 0;
784 			bump = true;
785 		} else {
786 			assert(unit->tex2d.gl_handle != tex->gl_handle);
787 		}
788 
789 		if(bump) {
790 			gl33_relocate_texuint(unit);
791 		}
792 	}
793 
794 	if(R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].pending == tex->pbo) {
795 		R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].pending = 0;
796 	}
797 
798 	if(R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].active == tex->pbo) {
799 		R.buffer_objects[GL33_BUFFER_BINDING_PIXEL_UNPACK].active = 0;
800 	}
801 }
802 
gl33_framebuffer_deleted(Framebuffer * fb)803 void gl33_framebuffer_deleted(Framebuffer *fb) {
804 	if(R.framebuffer.pending == fb) {
805 		R.framebuffer.pending = NULL;
806 	}
807 
808 	if(R.framebuffer.active == fb) {
809 		R.framebuffer.active = NULL;
810 	}
811 }
812 
gl33_shader_deleted(ShaderProgram * prog)813 void gl33_shader_deleted(ShaderProgram *prog) {
814 	if(R.progs.active == NULL) {
815 		R.progs.active = NULL;
816 	}
817 
818 	if(R.progs.pending == prog) {
819 		R.progs.pending = NULL;
820 		r_shader_standard();
821 	}
822 
823 	if(R.progs.gl_prog == prog->gl_handle) {
824 		R.progs.gl_prog = 0;
825 	}
826 }
827 
gl33_buffer_deleted(CommonBuffer * cbuf)828 void gl33_buffer_deleted(CommonBuffer *cbuf) {
829 	if(R.buffer_objects[cbuf->bindidx].active == cbuf->gl_handle) {
830 		R.buffer_objects[cbuf->bindidx].active = 0;
831 	}
832 
833 	if(R.buffer_objects[cbuf->bindidx].pending == cbuf->gl_handle) {
834 		R.buffer_objects[cbuf->bindidx].pending = 0;
835 	}
836 }
837 
gl33_vertex_buffer_deleted(VertexBuffer * vbuf)838 void gl33_vertex_buffer_deleted(VertexBuffer *vbuf) {
839 	if(R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].active == vbuf->cbuf.gl_handle) {
840 		R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].active = 0;
841 	}
842 
843 	if(R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].pending == vbuf->cbuf.gl_handle) {
844 		R.buffer_objects[GL33_BUFFER_BINDING_ARRAY].pending = 0;
845 	}
846 }
847 
gl33_vertex_array_deleted(VertexArray * varr)848 void gl33_vertex_array_deleted(VertexArray *varr) {
849 	if(R.vao.active == varr->gl_handle) {
850 		R.vao.active = 0;
851 	}
852 
853 	if(R.vao.pending == varr->gl_handle) {
854 		R.vao.pending = 0;
855 	}
856 }
857 
858 /*
859  * Renderer interface implementation
860  */
861 
gl33_init(void)862 static void gl33_init(void) {
863 	SDL_GLprofile profile;
864 	SDL_GLcontextFlag flags = 0;
865 
866 	if(env_get("TAISEI_GL33_CORE_PROFILE", true)) {
867 		profile = SDL_GL_CONTEXT_PROFILE_CORE;
868 	} else {
869 		profile = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
870 	}
871 
872 	if(env_get("TAISEI_GL33_FORWARD_COMPATIBLE", true)) {
873 		flags |= SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG;
874 	}
875 
876 	int major = env_get("TAISEI_GL33_VERSION_MAJOR", 3);
877 	int minor = env_get("TAISEI_GL33_VERSION_MINOR", 3);
878 
879 	glcommon_setup_attributes(profile, major, minor, flags);
880 	glcommon_load_library();
881 }
882 
gl33_post_init(void)883 static void gl33_post_init(void) {
884 
885 }
886 
gl33_shutdown(void)887 static void gl33_shutdown(void) {
888 	glcommon_unload_library();
889 	SDL_GL_DeleteContext(R.gl_context);
890 }
891 
gl33_create_window(const char * title,int x,int y,int w,int h,uint32_t flags)892 static SDL_Window* gl33_create_window(const char *title, int x, int y, int w, int h, uint32_t flags) {
893 	SDL_Window *window = SDL_CreateWindow(title, x, y, w, h, flags | SDL_WINDOW_OPENGL);
894 
895 	if(R.gl_context) {
896 		SDL_GL_MakeCurrent(window, R.gl_context);
897 	} else {
898 		GLVT.init_context(window);
899 	}
900 
901 	R.window = window;
902 	return window;
903 }
904 
gl33_features(void)905 static r_feature_bits_t gl33_features(void) {
906 	return R.features;
907 }
908 
gl33_capabilities(r_capability_bits_t capbits)909 static void gl33_capabilities(r_capability_bits_t capbits) {
910 	R.capabilities.pending = capbits;
911 }
912 
gl33_capabilities_current(void)913 static r_capability_bits_t gl33_capabilities_current(void) {
914 	return R.capabilities.pending;
915 }
916 
gl33_vsync(VsyncMode mode)917 static void gl33_vsync(VsyncMode mode) {
918 	int interval = 0, result;
919 
920 	switch(mode) {
921 		case VSYNC_NONE:     interval =  0; break;
922 		case VSYNC_NORMAL:   interval =  1; break;
923 		case VSYNC_ADAPTIVE: interval = -1; break;
924 		default:
925 			log_fatal("Unknown mode 0x%x", mode);
926 	}
927 
928 set_interval:
929 	result = SDL_GL_SetSwapInterval(interval);
930 
931 	if(result < 0) {
932 		log_warn("SDL_GL_SetSwapInterval(%i) failed: %s", interval, SDL_GetError());
933 
934 		// if adaptive vsync failed, try normal vsync
935 		if(interval < 0) {
936 			interval = 1;
937 			goto set_interval;
938 		}
939 	}
940 }
941 
gl33_vsync_current(void)942 static VsyncMode gl33_vsync_current(void) {
943 	int interval = SDL_GL_GetSwapInterval();
944 
945 	if(interval == 0) {
946 		return VSYNC_NONE;
947 	}
948 
949 	return interval > 0 ? VSYNC_NORMAL : VSYNC_ADAPTIVE;
950 }
951 
gl33_color4(float r,float g,float b,float a)952 static void gl33_color4(float r, float g, float b, float a) {
953 	R.color.r = r;
954 	R.color.g = g;
955 	R.color.b = b;
956 	R.color.a = a;
957 }
958 
gl33_color_current(void)959 static const Color* gl33_color_current(void) {
960 	return &R.color;
961 }
962 
gl33_begin_draw(VertexArray * varr,void ** state)963 void gl33_begin_draw(VertexArray *varr, void **state) {
964 	gl33_stats_pre_draw();
965 	r_flush_sprites();
966 	GLuint prev_vao = gl33_vao_current();
967 	gl33_bind_vao(varr->gl_handle);
968 	gl33_sync_state();
969 	gl33_vertex_array_flush_buffers(varr);
970 	*state = (void*)(uintptr_t)prev_vao;
971 }
972 
gl33_end_draw(void * state)973 void gl33_end_draw(void *state) {
974 	if(R.framebuffer.active) {
975 		gl33_framebuffer_taint(R.framebuffer.active);
976 	}
977 
978 	gl33_bind_vao((uintptr_t)state);
979 	gl33_stats_post_draw();
980 }
981 
gl33_draw(VertexArray * varr,Primitive prim,uint firstvert,uint count,uint instances,uint base_instance)982 static void gl33_draw(VertexArray *varr, Primitive prim, uint firstvert, uint count, uint instances, uint base_instance) {
983 	assert(count > 0);
984 	assert(base_instance == 0);
985 	GLuint gl_prim = gl33_prim_to_gl_prim(prim);
986 
987 	void *state;
988 	gl33_begin_draw(varr, &state);
989 
990 	if(instances) {
991 		glDrawArraysInstanced(gl_prim, firstvert, count, instances);
992 	} else {
993 		glDrawArrays(gl_prim, firstvert, count);
994 	}
995 
996 	gl33_end_draw(state);
997 }
998 
gl33_draw_indexed(VertexArray * varr,Primitive prim,uint firstidx,uint count,uint instances,uint base_instance)999 static void gl33_draw_indexed(VertexArray *varr, Primitive prim, uint firstidx, uint count, uint instances, uint base_instance) {
1000 	assert(count > 0);
1001 	assert(base_instance == 0);
1002 	assert(varr->index_attachment != NULL);
1003 	GLuint gl_prim = gl33_prim_to_gl_prim(prim);
1004 
1005 	void *state;
1006 	gl33_begin_draw(varr, &state);
1007 
1008 	uintptr_t iofs = firstidx * sizeof(gl33_ibo_index_t);
1009 
1010 	if(instances) {
1011 		glDrawElementsInstanced(gl_prim, count, GL33_IBO_GL_DATATYPE, (void*)iofs, instances);
1012 	} else {
1013 		glDrawElements(gl_prim, count, GL33_IBO_GL_DATATYPE, (void*)iofs);
1014 	}
1015 
1016 	gl33_end_draw(state);
1017 }
1018 
gl33_framebuffer(Framebuffer * fb)1019 static void gl33_framebuffer(Framebuffer *fb) {
1020 	R.framebuffer.pending = fb;
1021 }
1022 
gl33_framebuffer_current(void)1023 static Framebuffer *gl33_framebuffer_current(void) {
1024 	return R.framebuffer.pending;
1025 }
1026 
gl33_framebuffer_viewport(Framebuffer * fb,FloatRect vp)1027 static void gl33_framebuffer_viewport(Framebuffer *fb, FloatRect vp) {
1028 	transform_viewport_origin(fb, &vp);
1029 	memcpy(get_framebuffer_viewport(fb), &vp, sizeof(vp));
1030 }
1031 
gl33_framebuffer_viewport_current(Framebuffer * fb,FloatRect * out_rect)1032 static void gl33_framebuffer_viewport_current(Framebuffer *fb, FloatRect *out_rect) {
1033 	*out_rect = *get_framebuffer_viewport(fb);
1034 	transform_viewport_origin(fb, out_rect);
1035 }
1036 
gl33_framebuffer_get_size(Framebuffer * fb)1037 static IntExtent gl33_framebuffer_get_size(Framebuffer *fb) {
1038 	IntExtent fb_size;
1039 
1040 	if(fb == NULL) {
1041 		// TODO: cache this at window creation time and refresh on resize events?
1042 		SDL_GL_GetDrawableSize(R.window, &fb_size.w, &fb_size.h);
1043 	} else {
1044 		fb_size = gl33_framebuffer_get_effective_size(fb);
1045 	}
1046 
1047 	return fb_size;
1048 }
1049 
gl33_shader(ShaderProgram * prog)1050 static void gl33_shader(ShaderProgram *prog) {
1051 	assert(prog->gl_handle != 0);
1052 
1053 	R.progs.pending = prog;
1054 }
1055 
gl33_shader_current(void)1056 static ShaderProgram *gl33_shader_current(void) {
1057 	return R.progs.pending;
1058 }
1059 
gl33_set_clear_color(const Color * color)1060 void gl33_set_clear_color(const Color *color) {
1061 	if(memcmp(&R.clear_color, color, sizeof(*color))) {
1062 		memcpy(&R.clear_color, color, sizeof(*color));
1063 		glClearColor(color->r, color->g, color->b, color->a);
1064 	}
1065 }
1066 
gl33_set_clear_depth(float depth)1067 void gl33_set_clear_depth(float depth) {
1068 	if(R.clear_depth != depth) {
1069 		R.clear_depth = depth;
1070 		glClearDepth(depth);
1071 	}
1072 }
1073 
gl33_swap(SDL_Window * window)1074 static void gl33_swap(SDL_Window *window) {
1075 	r_flush_sprites();
1076 
1077 	Framebuffer *prev_fb = r_framebuffer_current();
1078 	r_framebuffer(NULL);
1079 	gl33_sync_framebuffer();
1080 #ifndef __EMSCRIPTEN__
1081 	SDL_GL_SwapWindow(window);
1082 #endif
1083 	r_framebuffer(prev_fb);
1084 
1085 	gl33_stats_post_frame();
1086 
1087 	// We can't rely on viewport being preserved across frames,
1088 	// so force the next frame to set one on the first draw call.
1089 	// The viewport might get updated externally when e.g. going
1090 	// fullscreen, and we can't catch that in the resize event.
1091 	memset(&R.viewport.active, 0, sizeof(R.viewport.active));
1092 }
1093 
gl33_blend(BlendMode mode)1094 static void gl33_blend(BlendMode mode) {
1095 	R.blend.mode.pending = mode;
1096 }
1097 
gl33_blend_current(void)1098 static BlendMode gl33_blend_current(void) {
1099 	return R.blend.mode.pending;
1100 }
1101 
gl33_cull(CullFaceMode mode)1102 static void gl33_cull(CullFaceMode mode) {
1103 	R.cull_face.mode.pending = mode;
1104 }
1105 
gl33_cull_current(void)1106 static CullFaceMode gl33_cull_current(void) {
1107 	return R.cull_face.mode.pending;
1108 }
1109 
gl33_depth_func(DepthTestFunc func)1110 static void gl33_depth_func(DepthTestFunc func) {
1111 	R.depth_test.func.pending = func;
1112 }
1113 
gl33_depth_func_current(void)1114 static DepthTestFunc gl33_depth_func_current(void) {
1115 	return R.depth_test.func.pending;
1116 }
1117 
gl33_screenshot(Pixmap * out)1118 static bool gl33_screenshot(Pixmap *out) {
1119 	FloatRect *vp = &R.viewport.default_framebuffer;
1120 	out->width = vp->w;
1121 	out->height = vp->h;
1122 	out->format = PIXMAP_FORMAT_RGB8;
1123 	out->origin = PIXMAP_ORIGIN_BOTTOMLEFT;
1124 	out->data.untyped = pixmap_alloc_buffer_for_copy(out);
1125 	glReadPixels(vp->x, vp->y, vp->w, vp->h, GL_RGB, GL_UNSIGNED_BYTE, out->data.untyped);
1126 	return true;
1127 }
1128 
1129 RendererBackend _r_backend_gl33 = {
1130 	.name = "gl33",
1131 	.funcs = {
1132 		.init = gl33_init,
1133 		.post_init = gl33_post_init,
1134 		.shutdown = gl33_shutdown,
1135 		.create_window = gl33_create_window,
1136 		.features = gl33_features,
1137 		.capabilities = gl33_capabilities,
1138 		.capabilities_current = gl33_capabilities_current,
1139 		.draw = gl33_draw,
1140 		.draw_indexed = gl33_draw_indexed,
1141 		.color4 = gl33_color4,
1142 		.color_current = gl33_color_current,
1143 		.blend = gl33_blend,
1144 		.blend_current = gl33_blend_current,
1145 		.cull = gl33_cull,
1146 		.cull_current = gl33_cull_current,
1147 		.depth_func = gl33_depth_func,
1148 		.depth_func_current = gl33_depth_func_current,
1149 		.shader_language_supported = gl33_shader_language_supported,
1150 		.shader_object_compile = gl33_shader_object_compile,
1151 		.shader_object_destroy = gl33_shader_object_destroy,
1152 		.shader_object_set_debug_label = gl33_shader_object_set_debug_label,
1153 		.shader_object_get_debug_label = gl33_shader_object_get_debug_label,
1154 		.shader_program_link = gl33_shader_program_link,
1155 		.shader_program_destroy = gl33_shader_program_destroy,
1156 		.shader_program_set_debug_label = gl33_shader_program_set_debug_label,
1157 		.shader_program_get_debug_label = gl33_shader_program_get_debug_label,
1158 		.shader = gl33_shader,
1159 		.shader_current = gl33_shader_current,
1160 		.shader_uniform = gl33_shader_uniform,
1161 		.uniform = gl33_uniform,
1162 		.uniform_type = gl33_uniform_type,
1163 		.texture_create = gl33_texture_create,
1164 		.texture_get_size = gl33_texture_get_size,
1165 		.texture_get_params = gl33_texture_get_params,
1166 		.texture_get_debug_label = gl33_texture_get_debug_label,
1167 		.texture_set_debug_label = gl33_texture_set_debug_label,
1168 		.texture_set_filter = gl33_texture_set_filter,
1169 		.texture_set_wrap = gl33_texture_set_wrap,
1170 		.texture_destroy = gl33_texture_destroy,
1171 		.texture_invalidate = gl33_texture_invalidate,
1172 		.texture_fill = gl33_texture_fill,
1173 		.texture_fill_region = gl33_texture_fill_region,
1174 		.texture_clear = gl33_texture_clear,
1175 		.framebuffer_create = gl33_framebuffer_create,
1176 		.framebuffer_destroy = gl33_framebuffer_destroy,
1177 		.framebuffer_attach = gl33_framebuffer_attach,
1178 		.framebuffer_get_debug_label = gl33_framebuffer_get_debug_label,
1179 		.framebuffer_set_debug_label = gl33_framebuffer_set_debug_label,
1180 		.framebuffer_get_attachment = gl33_framebuffer_get_attachment,
1181 		.framebuffer_get_attachment_mipmap = gl33_framebuffer_get_attachment_mipmap,
1182 		.framebuffer_viewport = gl33_framebuffer_viewport,
1183 		.framebuffer_viewport_current = gl33_framebuffer_viewport_current,
1184 		.framebuffer = gl33_framebuffer,
1185 		.framebuffer_current = gl33_framebuffer_current,
1186 		.framebuffer_clear = gl33_framebuffer_clear,
1187 		.framebuffer_get_size = gl33_framebuffer_get_size,
1188 		.vertex_buffer_create = gl33_vertex_buffer_create,
1189 		.vertex_buffer_set_debug_label = gl33_vertex_buffer_set_debug_label,
1190 		.vertex_buffer_get_debug_label = gl33_vertex_buffer_get_debug_label,
1191 		.vertex_buffer_destroy = gl33_vertex_buffer_destroy,
1192 		.vertex_buffer_invalidate = gl33_vertex_buffer_invalidate,
1193 		.vertex_buffer_get_stream = gl33_vertex_buffer_get_stream,
1194 		.index_buffer_create = gl33_index_buffer_create,
1195 		.index_buffer_get_capacity = gl33_index_buffer_get_capacity,
1196 		.index_buffer_get_debug_label = gl33_index_buffer_get_debug_label,
1197 		.index_buffer_set_debug_label = gl33_index_buffer_set_debug_label,
1198 		.index_buffer_set_offset = gl33_index_buffer_set_offset,
1199 		.index_buffer_get_offset = gl33_index_buffer_get_offset,
1200 		.index_buffer_add_indices = gl33_index_buffer_add_indices,
1201 		.index_buffer_destroy = gl33_index_buffer_destroy,
1202 		.vertex_array_destroy = gl33_vertex_array_destroy,
1203 		.vertex_array_create = gl33_vertex_array_create,
1204 		.vertex_array_set_debug_label = gl33_vertex_array_set_debug_label,
1205 		.vertex_array_get_debug_label = gl33_vertex_array_get_debug_label,
1206 		.vertex_array_layout = gl33_vertex_array_layout,
1207 		.vertex_array_attach_vertex_buffer = gl33_vertex_array_attach_vertex_buffer,
1208 		.vertex_array_get_vertex_attachment = gl33_vertex_array_get_vertex_attachment,
1209 		.vertex_array_attach_index_buffer = gl33_vertex_array_attach_index_buffer,
1210 		.vertex_array_get_index_attachment = gl33_vertex_array_get_index_attachment,
1211 		.vsync = gl33_vsync,
1212 		.vsync_current = gl33_vsync_current,
1213 		.swap = gl33_swap,
1214 		.screenshot = gl33_screenshot,
1215 	},
1216 	.custom = &(GLBackendData) {
1217 		.vtable = {
1218 			.texture_type_info = gl33_texture_type_info,
1219 			.texture_format_caps = gl33_texture_format_caps,
1220 			.init_context = gl33_init_context,
1221 		}
1222 	},
1223 };
1224