v / thirdparty / sokol /
1#if defined(SOKOL_IMPL) && !defined(SOKOL_GFX_IMPL)
2#define SOKOL_GFX_IMPL
3#endif
4#ifndef SOKOL_GFX_INCLUDED
5/*
6 sokol_gfx.h -- simple 3D API wrapper
7
8 Project URL: https://github.com/floooh/sokol
9
10 Example code: https://github.com/floooh/sokol-samples
11
12 Do this:
13 #define SOKOL_IMPL or
14 #define SOKOL_GFX_IMPL
15 before you include this file in *one* C or C++ file to create the
16 implementation.
17
18 In the same place define one of the following to select the rendering
19 backend:
20 #define SOKOL_GLCORE33
21 #define SOKOL_GLES2
22 #define SOKOL_GLES3
23 #define SOKOL_D3D11
24 #define SOKOL_METAL
25 #define SOKOL_WGPU
26 #define SOKOL_DUMMY_BACKEND
27
28 I.e. for the GL 3.3 Core Profile it should look like this:
29
30 #include ...
31 #include ...
32 #define SOKOL_IMPL
33 #define SOKOL_GLCORE33
34 #include "sokol_gfx.h"
35
36 The dummy backend replaces the platform-specific backend code with empty
37 stub functions. This is useful for writing tests that need to run on the
38 command line.
39
40 Optionally provide the following defines with your own implementations:
41
42 SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
43 SOKOL_MALLOC(s) - your own malloc function (default: malloc(s))
44 SOKOL_FREE(p) - your own free function (default: free(p))
45 SOKOL_LOG(msg) - your own logging function (default: puts(msg))
46 SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
47 SOKOL_GFX_API_DECL - public function declaration prefix (default: extern)
48 SOKOL_API_DECL - same as SOKOL_GFX_API_DECL
49 SOKOL_API_IMPL - public function implementation prefix (default: -)
50 SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS)
51 SOKOL_EXTERNAL_GL_LOADER - indicates that you're using your own GL loader, in this case
52 sokol_gfx.h will not include any platform GL headers and disable
53 the integrated Win32 GL loader
54
55 If sokol_gfx.h is compiled as a DLL, define the following before
56 including the declaration or implementation:
57
58 SOKOL_DLL
59
60 On Windows, SOKOL_DLL will define SOKOL_GFX_API_DECL as __declspec(dllexport)
61 or __declspec(dllimport) as needed.
62
63 If you want to compile without deprecated structs and functions,
64 define:
65
66 SOKOL_NO_DEPRECATED
67
68 Optionally define the following to force debug checks and validations
69 even in release mode:
70
71 SOKOL_DEBUG - by default this is defined if _DEBUG is defined
72
73 sokol_gfx DOES NOT:
74 ===================
75 - create a window or the 3D-API context/device, you must do this
76 before sokol_gfx is initialized, and pass any required information
77 (like 3D device pointers) to the sokol_gfx initialization call
78
79 - present the rendered frame, how this is done exactly usually depends
80 on how the window and 3D-API context/device was created
81
82 - provide a unified shader language, instead 3D-API-specific shader
83 source-code or shader-bytecode must be provided (for the "official"
84 offline shader cross-compiler, see here:
85 https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md)
86
87 STEP BY STEP
88 ============
89 --- to initialize sokol_gfx, after creating a window and a 3D-API
90 context/device, call:
91
92 sg_setup(const sg_desc*)
93
94 --- create resource objects (at least buffers, shaders and pipelines,
95 and optionally images and passes):
96
97 sg_buffer sg_make_buffer(const sg_buffer_desc*)
98 sg_image sg_make_image(const sg_image_desc*)
99 sg_shader sg_make_shader(const sg_shader_desc*)
100 sg_pipeline sg_make_pipeline(const sg_pipeline_desc*)
101 sg_pass sg_make_pass(const sg_pass_desc*)
102
103 --- start rendering to the default frame buffer with:
104
105 sg_begin_default_pass(const sg_pass_action* action, int width, int height)
106
107 ...or alternatively with:
108
109 sg_begin_default_passf(const sg_pass_action* action, float width, float height)
110
111 ...which takes the framebuffer width and height as float values.
112
113 --- or start rendering to an offscreen framebuffer with:
114
115 sg_begin_pass(sg_pass pass, const sg_pass_action* action)
116
117 --- set the pipeline state for the next draw call with:
118
119 sg_apply_pipeline(sg_pipeline pip)
120
121 --- fill an sg_bindings struct with the resource bindings for the next
122 draw call (1..N vertex buffers, 0 or 1 index buffer, 0..N image objects
123 to use as textures each on the vertex-shader- and fragment-shader-stage
124 and then call
125
126 sg_apply_bindings(const sg_bindings* bindings)
127
128 to update the resource bindings
129
130 --- optionally update shader uniform data with:
131
132 sg_apply_uniforms(sg_shader_stage stage, int ub_index, const void* data, int num_bytes)
133
134 --- kick off a draw call with:
135
136 sg_draw(int base_element, int num_elements, int num_instances)
137
138 The sg_draw() function unifies all the different ways to render primitives
139 in a single call (indexed vs non-indexed rendering, and instanced vs non-instanced
140 rendering). In case of indexed rendering, base_element and num_element specify
141 indices in the currently bound index buffer. In case of non-indexed rendering
142 base_element and num_elements specify vertices in the currently bound
143 vertex-buffer(s). To perform instanced rendering, the rendering pipeline
144 must be setup for instancing (see sg_pipeline_desc below), a separate vertex buffer
145 containing per-instance data must be bound, and the num_instances parameter
146 must be > 1.
147
148 --- finish the current rendering pass with:
149
150 sg_end_pass()
151
152 --- when done with the current frame, call
153
154 sg_commit()
155
156 --- at the end of your program, shutdown sokol_gfx with:
157
158 sg_shutdown()
159
160 --- if you need to destroy resources before sg_shutdown(), call:
161
162 sg_destroy_buffer(sg_buffer buf)
163 sg_destroy_image(sg_image img)
164 sg_destroy_shader(sg_shader shd)
165 sg_destroy_pipeline(sg_pipeline pip)
166 sg_destroy_pass(sg_pass pass)
167
168 --- to set a new viewport rectangle, call
169
170 sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left)
171
172 ...or if you want to specifiy the viewport rectangle with float values:
173
174 sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left)
175
176 --- to set a new scissor rect, call:
177
178 sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left)
179
180 ...or with float values:
181
182 sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left)
183
184 Both sg_apply_viewport() and sg_apply_scissor_rect() must be called
185 inside a rendering pass
186
187 Note that sg_begin_default_pass() and sg_begin_pass() will reset both the
188 viewport and scissor rectangles to cover the entire framebuffer.
189
190 --- to update (overwrite) the content of buffer and image resources, call:
191
192 sg_update_buffer(sg_buffer buf, const sg_range* data)
193 sg_update_image(sg_image img, const sg_image_data* data)
194
195 Buffers and images to be updated must have been created with
196 SG_USAGE_DYNAMIC or SG_USAGE_STREAM
197
198 Only one update per frame is allowed for buffer and image resources when
199 using the sg_update_*() functions. The rationale is to have a simple
200 countermeasure to avoid the CPU scribbling over data the GPU is currently
201 using, or the CPU having to wait for the GPU
202
203 Buffer and image updates can be partial, as long as a rendering
204 operation only references the valid (updated) data in the
205 buffer or image.
206
207 --- to append a chunk of data to a buffer resource, call:
208
209 int sg_append_buffer(sg_buffer buf, const sg_range* data)
210
211 The difference to sg_update_buffer() is that sg_append_buffer()
212 can be called multiple times per frame to append new data to the
213 buffer piece by piece, optionally interleaved with draw calls referencing
214 the previously written data.
215
216 sg_append_buffer() returns a byte offset to the start of the
217 written data, this offset can be assigned to
218 sg_bindings.vertex_buffer_offsets[n] or
219 sg_bindings.index_buffer_offset
220
221 Code example:
222
223 for (...) {
224 const void* data = ...;
225 const int num_bytes = ...;
226 int offset = sg_append_buffer(buf, &(sg_range) { .ptr=data, .size=num_bytes });
227 bindings.vertex_buffer_offsets[0] = offset;
228 sg_apply_pipeline(pip);
229 sg_apply_bindings(&bindings);
230 sg_apply_uniforms(...);
231 sg_draw(...);
232 }
233
234 A buffer to be used with sg_append_buffer() must have been created
235 with SG_USAGE_DYNAMIC or SG_USAGE_STREAM.
236
237 If the application appends more data to the buffer then fits into
238 the buffer, the buffer will go into the "overflow" state for the
239 rest of the frame.
240
241 Any draw calls attempting to render an overflown buffer will be
242 silently dropped (in debug mode this will also result in a
243 validation error).
244
245 You can also check manually if a buffer is in overflow-state by calling
246
247 bool sg_query_buffer_overflow(sg_buffer buf)
248
249 NOTE: Due to restrictions in underlying 3D-APIs, appended chunks of
250 data will be 4-byte aligned in the destination buffer. This means
251 that there will be gaps in index buffers containing 16-bit indices
252 when the number of indices in a call to sg_append_buffer() is
253 odd. This isn't a problem when each call to sg_append_buffer()
254 is associated with one draw call, but will be problematic when
255 a single indexed draw call spans several appended chunks of indices.
256
257 --- to check at runtime for optional features, limits and pixelformat support,
258 call:
259
260 sg_features sg_query_features()
261 sg_limits sg_query_limits()
262 sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt)
263
264 --- if you need to call into the underlying 3D-API directly, you must call:
265
266 sg_reset_state_cache()
267
268 ...before calling sokol_gfx functions again
269
270 --- you can inspect the original sg_desc structure handed to sg_setup()
271 by calling sg_query_desc(). This will return an sg_desc struct with
272 the default values patched in instead of any zero-initialized values
273
274 --- you can inspect various internal resource attributes via:
275
276 sg_buffer_info sg_query_buffer_info(sg_buffer buf)
277 sg_image_info sg_query_image_info(sg_image img)
278 sg_shader_info sg_query_shader_info(sg_shader shd)
279 sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip)
280 sg_pass_info sg_query_pass_info(sg_pass pass)
281
282 ...please note that the returned info-structs are tied quite closely
283 to sokol_gfx.h internals, and may change more often than other
284 public API functions and structs.
285
286 --- you can ask at runtime what backend sokol_gfx.h has been compiled
287 for, or whether the GLES3 backend had to fall back to GLES2 with:
288
289 sg_backend sg_query_backend(void)
290
291 --- you can query the default resource creation parameters through the functions
292
293 sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc)
294 sg_image_desc sg_query_image_defaults(const sg_image_desc* desc)
295 sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc)
296 sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc)
297 sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc)
298
299 These functions take a pointer to a desc structure which may contain
300 zero-initialized items for default values. These zero-init values
301 will be replaced with their concrete values in the returned desc
302 struct.
303
304 ON INITIALIZATION:
305 ==================
306 When calling sg_setup(), a pointer to an sg_desc struct must be provided
307 which contains initialization options. These options provide two types
308 of information to sokol-gfx:
309
310 (1) upper bounds and limits needed to allocate various internal
311 data structures:
312 - the max number of resources of each type that can
313 be alive at the same time, this is used for allocating
314 internal pools
315 - the max overall size of uniform data that can be
316 updated per frame, including a worst-case alignment
317 per uniform update (this worst-case alignment is 256 bytes)
318 - the max size of all dynamic resource updates (sg_update_buffer,
319 sg_append_buffer and sg_update_image) per frame
320 - the max number of entries in the texture sampler cache
321 (how many unique texture sampler can exist at the same time)
322 Not all of those limit values are used by all backends, but it is
323 good practice to provide them none-the-less.
324
325 (2) 3D-API "context information" (sometimes also called "bindings"):
326 sokol_gfx.h doesn't create or initialize 3D API objects which are
327 closely related to the presentation layer (this includes the "rendering
328 device", the swapchain, and any objects which depend on the
329 swapchain). These API objects (or callback functions to obtain
330 them, if those objects might change between frames), must
331 be provided in a nested sg_context_desc struct inside the
332 sg_desc struct. If sokol_gfx.h is used together with
333 sokol_app.h, have a look at the sokol_glue.h header which provides
334 a convenience function to get a sg_context_desc struct filled out
335 with context information provided by sokol_app.h
336
337 See the documention block of the sg_desc struct below for more information.
338
339 BACKEND-SPECIFIC TOPICS:
340 ========================
341 --- the GL backends need to know about the internal structure of uniform
342 blocks, and the texture sampler-name and -type:
343
344 typedef struct {
345 float mvp[16]; // model-view-projection matrix
346 float offset0[2]; // some 2D vectors
347 float offset1[2];
348 float offset2[2];
349 } params_t;
350
351 // uniform block structure and texture image definition in sg_shader_desc:
352 sg_shader_desc desc = {
353 // uniform block description (size and internal structure)
354 .vs.uniform_blocks[0] = {
355 .size = sizeof(params_t),
356 .uniforms = {
357 [0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 },
358 [1] = { .name="offset0", .type=SG_UNIFORMTYPE_VEC2 },
359 ...
360 }
361 },
362 // one texture on the fragment-shader-stage, GLES2/WebGL needs name and image type
363 .fs.images[0] = { .name="tex", .type=SG_IMAGETYPE_ARRAY }
364 ...
365 };
366
367 --- the Metal and D3D11 backends only need to know the size of uniform blocks,
368 not their internal member structure, and they only need to know
369 the type of a texture sampler, not its name:
370
371 sg_shader_desc desc = {
372 .vs.uniform_blocks[0].size = sizeof(params_t),
373 .fs.images[0].type = SG_IMAGETYPE_ARRAY,
374 ...
375 };
376
377 --- when creating a shader object, GLES2/WebGL need to know the vertex
378 attribute names as used in the vertex shader:
379
380 sg_shader_desc desc = {
381 .attrs = {
382 [0] = { .name="position" },
383 [1] = { .name="color1" }
384 }
385 };
386
387 The vertex attribute names provided when creating a shader will be
388 used later in sg_create_pipeline() for matching the vertex layout
389 to vertex shader inputs.
390
391 --- on D3D11 you need to provide a semantic name and semantic index in the
392 shader description struct instead (see the D3D11 documentation on
393 D3D11_INPUT_ELEMENT_DESC for details):
394
395 sg_shader_desc desc = {
396 .attrs = {
397 [0] = { .sem_name="POSITION", .sem_index=0 }
398 [1] = { .sem_name="COLOR", .sem_index=1 }
399 }
400 };
401
402 The provided semantic information will be used later in sg_create_pipeline()
403 to match the vertex layout to vertex shader inputs.
404
405 --- on D3D11, and when passing HLSL source code (instead of byte code) to shader
406 creation, you can optionally define the shader model targets on the vertex
407 stage:
408
409 sg_shader_Desc desc = {
410 .vs = {
411 ...
412 .d3d11_target = "vs_5_0"
413 },
414 .fs = {
415 ...
416 .d3d11_target = "ps_5_0"
417 }
418 };
419
420 The default targets are "ps_4_0" and "fs_4_0". Note that those target names
421 are only used when compiling shaders from source. They are ignored when
422 creating a shader from bytecode.
423
424 --- on Metal, GL 3.3 or GLES3/WebGL2, you don't need to provide an attribute
425 name or semantic name, since vertex attributes can be bound by their slot index
426 (this is mandatory in Metal, and optional in GL):
427
428 sg_pipeline_desc desc = {
429 .layout = {
430 .attrs = {
431 [0] = { .format=SG_VERTEXFORMAT_FLOAT3 },
432 [1] = { .format=SG_VERTEXFORMAT_FLOAT4 }
433 }
434 }
435 };
436
437 WORKING WITH CONTEXTS
438 =====================
439 sokol-gfx allows to switch between different rendering contexts and
440 associate resource objects with contexts. This is useful to
441 create GL applications that render into multiple windows.
442
443 A rendering context keeps track of all resources created while
444 the context is active. When the context is destroyed, all resources
445 "belonging to the context" are destroyed as well.
446
447 A default context will be created and activated implicitly in
448 sg_setup(), and destroyed in sg_shutdown(). So for a typical application
449 which *doesn't* use multiple contexts, nothing changes, and calling
450 the context functions isn't necessary.
451
452 Three functions have been added to work with contexts:
453
454 --- sg_context sg_setup_context():
455 This must be called once after a GL context has been created and
456 made active.
457
458 --- void sg_activate_context(sg_context ctx)
459 This must be called after making a different GL context active.
460 Apart from 3D-API-specific actions, the call to sg_activate_context()
461 will internally call sg_reset_state_cache().
462
463 --- void sg_discard_context(sg_context ctx)
464 This must be called right before a GL context is destroyed and
465 will destroy all resources associated with the context (that
466 have been created while the context was active) The GL context must be
467 active at the time sg_discard_context(sg_context ctx) is called.
468
469 Also note that resources (buffers, images, shaders and pipelines) must
470 only be used or destroyed while the same GL context is active that
471 was also active while the resource was created (an exception is
472 resource sharing on GL, such resources can be used while
473 another context is active, but must still be destroyed under
474 the same context that was active during creation).
475
476 For more information, check out the multiwindow-glfw sample:
477
478 https://github.com/floooh/sokol-samples/blob/master/glfw/multiwindow-glfw.c
479
480 TRACE HOOKS:
481 ============
482 sokol_gfx.h optionally allows to install "trace hook" callbacks for
483 each public API functions. When a public API function is called, and
484 a trace hook callback has been installed for this function, the
485 callback will be invoked with the parameters and result of the function.
486 This is useful for things like debugging- and profiling-tools, or
487 keeping track of resource creation and destruction.
488
489 To use the trace hook feature:
490
491 --- Define SOKOL_TRACE_HOOKS before including the implementation.
492
493 --- Setup an sg_trace_hooks structure with your callback function
494 pointers (keep all function pointers you're not interested
495 in zero-initialized), optionally set the user_data member
496 in the sg_trace_hooks struct.
497
498 --- Install the trace hooks by calling sg_install_trace_hooks(),
499 the return value of this function is another sg_trace_hooks
500 struct which contains the previously set of trace hooks.
501 You should keep this struct around, and call those previous
502 functions pointers from your own trace callbacks for proper
503 chaining.
504
505 As an example of how trace hooks are used, have a look at the
506 imgui/sokol_gfx_imgui.h header which implements a realtime
507 debugging UI for sokol_gfx.h on top of Dear ImGui.
508
509 A NOTE ON PORTABLE PACKED VERTEX FORMATS:
510 =========================================
511 There are two things to consider when using packed
512 vertex formats like UBYTE4, SHORT2, etc which need to work
513 across all backends:
514
515 - D3D11 can only convert *normalized* vertex formats to
516 floating point during vertex fetch, normalized formats
517 have a trailing 'N', and are "normalized" to a range
518 -1.0..+1.0 (for the signed formats) or 0.0..1.0 (for the
519 unsigned formats):
520
521 - SG_VERTEXFORMAT_BYTE4N
522 - SG_VERTEXFORMAT_UBYTE4N
523 - SG_VERTEXFORMAT_SHORT2N
524 - SG_VERTEXFORMAT_USHORT2N
525 - SG_VERTEXFORMAT_SHORT4N
526 - SG_VERTEXFORMAT_USHORT4N
527
528 D3D11 will not convert *non-normalized* vertex formats to floating point
529 vertex shader inputs, those can only be uses with the *ivecn* vertex shader
530 input types when D3D11 is used as backend (GL and Metal can use both formats)
531
532 - SG_VERTEXFORMAT_BYTE4,
533 - SG_VERTEXFORMAT_UBYTE4
534 - SG_VERTEXFORMAT_SHORT2
535 - SG_VERTEXFORMAT_SHORT4
536
537 - WebGL/GLES2 cannot use integer vertex shader inputs (int or ivecn)
538
539 - SG_VERTEXFORMAT_UINT10_N2 is not supported on WebGL/GLES2
540
541 So for a vertex input layout which works on all platforms, only use the following
542 vertex formats, and if needed "expand" the normalized vertex shader
543 inputs in the vertex shader by multiplying with 127.0, 255.0, 32767.0 or
544 65535.0:
545
546 - SG_VERTEXFORMAT_FLOAT,
547 - SG_VERTEXFORMAT_FLOAT2,
548 - SG_VERTEXFORMAT_FLOAT3,
549 - SG_VERTEXFORMAT_FLOAT4,
550 - SG_VERTEXFORMAT_BYTE4N,
551 - SG_VERTEXFORMAT_UBYTE4N,
552 - SG_VERTEXFORMAT_SHORT2N,
553 - SG_VERTEXFORMAT_USHORT2N
554 - SG_VERTEXFORMAT_SHORT4N,
555 - SG_VERTEXFORMAT_USHORT4N
556
557 TODO:
558 ====
559 - talk about asynchronous resource creation
560
561 zlib/libpng license
562
563 Copyright (c) 2018 Andre Weissflog
564
565 This software is provided 'as-is', without any express or implied warranty.
566 In no event will the authors be held liable for any damages arising from the
567 use of this software.
568
569 Permission is granted to anyone to use this software for any purpose,
570 including commercial applications, and to alter it and redistribute it
571 freely, subject to the following restrictions:
572
573 1. The origin of this software must not be misrepresented; you must not
574 claim that you wrote the original software. If you use this software in a
575 product, an acknowledgment in the product documentation would be
576 appreciated but is not required.
577
578 2. Altered source versions must be plainly marked as such, and must not
579 be misrepresented as being the original software.
580
581 3. This notice may not be removed or altered from any source
582 distribution.
583*/
584#define SOKOL_GFX_INCLUDED (1)
585#include <stddef.h> // size_t
586#include <stdint.h>
587#include <stdbool.h>
588
589#if defined(SOKOL_API_DECL) && !defined(SOKOL_GFX_API_DECL)
590#define SOKOL_GFX_API_DECL SOKOL_API_DECL
591#endif
592#ifndef SOKOL_GFX_API_DECL
593#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_GFX_IMPL)
594#define SOKOL_GFX_API_DECL __declspec(dllexport)
595#elif defined(_WIN32) && defined(SOKOL_DLL)
596#define SOKOL_GFX_API_DECL __declspec(dllimport)
597#else
598#define SOKOL_GFX_API_DECL extern
599#endif
600#endif
601
602#ifdef __cplusplus
603extern "C" {
604#endif
605
606/*
607 Resource id typedefs:
608
609 sg_buffer: vertex- and index-buffers
610 sg_image: textures and render targets
611 sg_shader: vertex- and fragment-shaders, uniform blocks
612 sg_pipeline: associated shader and vertex-layouts, and render states
613 sg_pass: a bundle of render targets and actions on them
614 sg_context: a 'context handle' for switching between 3D-API contexts
615
616 Instead of pointers, resource creation functions return a 32-bit
617 number which uniquely identifies the resource object.
618
619 The 32-bit resource id is split into a 16-bit pool index in the lower bits,
620 and a 16-bit 'unique counter' in the upper bits. The index allows fast
621 pool lookups, and combined with the unique-mask it allows to detect
622 'dangling accesses' (trying to use an object which no longer exists, and
623 its pool slot has been reused for a new object)
624
625 The resource ids are wrapped into a struct so that the compiler
626 can complain when the wrong resource type is used.
627*/
628typedef struct sg_buffer { uint32_t id; } sg_buffer;
629typedef struct sg_image { uint32_t id; } sg_image;
630typedef struct sg_shader { uint32_t id; } sg_shader;
631typedef struct sg_pipeline { uint32_t id; } sg_pipeline;
632typedef struct sg_pass { uint32_t id; } sg_pass;
633typedef struct sg_context { uint32_t id; } sg_context;
634
635/*
636 sg_range is a pointer-size-pair struct used to pass memory blobs into
637 sokol-gfx. When initialized from a value type (array or struct), you can
638 use the SG_RANGE() macro to build an sg_range struct. For functions which
639 take either a sg_range pointer, or a (C++) sg_range reference, use the
640 SG_RANGE_REF macro as a solution which compiles both in C and C++.
641*/
642typedef struct sg_range {
643 const void* ptr;
644 size_t size;
645} sg_range;
646
647// disabling this for every includer isn't great, but the warnings are also quite pointless
648#if defined(_MSC_VER)
649#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */
650#pragma warning(disable:4204) /* VS2015: nonstandard extension used: non-constant aggregate initializer */
651#endif
652#if defined(__cplusplus)
653#define SG_RANGE(x) sg_range{ &x, sizeof(x) }
654#define SG_RANGE_REF(x) sg_range{ &x, sizeof(x) }
655#else
656#define SG_RANGE(x) (sg_range){ &x, sizeof(x) }
657#define SG_RANGE_REF(x) &(sg_range){ &x, sizeof(x) }
658#endif
659
660// various compile-time constants
661enum {
662 SG_INVALID_ID = 0,
663 SG_NUM_SHADER_STAGES = 2,
664 SG_NUM_INFLIGHT_FRAMES = 2,
665 SG_MAX_COLOR_ATTACHMENTS = 4,
666 SG_MAX_SHADERSTAGE_BUFFERS = 8,
667 SG_MAX_SHADERSTAGE_IMAGES = 12,
668 SG_MAX_SHADERSTAGE_UBS = 4,
669 SG_MAX_UB_MEMBERS = 16,
670 SG_MAX_VERTEX_ATTRIBUTES = 16, /* NOTE: actual max vertex attrs can be less on GLES2, see sg_limits! */
671 SG_MAX_MIPMAPS = 16,
672 SG_MAX_TEXTUREARRAY_LAYERS = 128
673};
674
675/*
676 sg_color
677
678 An RGBA color value.
679*/
680typedef struct sg_color { float r, g, b, a; } sg_color;
681
682/*
683 sg_backend
684
685 The active 3D-API backend, use the function sg_query_backend()
686 to get the currently active backend.
687
688 NOTE that SG_BACKEND_GLES2 will be returned if sokol-gfx was
689 compiled with SOKOL_GLES3, but the runtime platform doesn't support
690 GLES3/WebGL2 and sokol-gfx had to fallback to GLES2/WebGL.
691*/
692typedef enum sg_backend {
693 SG_BACKEND_GLCORE33,
694 SG_BACKEND_GLES2,
695 SG_BACKEND_GLES3,
696 SG_BACKEND_D3D11,
697 SG_BACKEND_METAL_IOS,
698 SG_BACKEND_METAL_MACOS,
699 SG_BACKEND_METAL_SIMULATOR,
700 SG_BACKEND_WGPU,
701 SG_BACKEND_DUMMY,
702} sg_backend;
703
704/*
705 sg_pixel_format
706
707 sokol_gfx.h basically uses the same pixel formats as WebGPU, since these
708 are supported on most newer GPUs. GLES2 and WebGL only supports a much
709 smaller subset of actually available pixel formats. Call
710 sg_query_pixelformat() to check at runtime if a pixel format supports the
711 desired features.
712
713 A pixelformat name consist of three parts:
714
715 - components (R, RG, RGB or RGBA)
716 - bit width per component (8, 16 or 32)
717 - component data type:
718 - unsigned normalized (no postfix)
719 - signed normalized (SN postfix)
720 - unsigned integer (UI postfix)
721 - signed integer (SI postfix)
722 - float (F postfix)
723
724 Not all pixel formats can be used for everything, call sg_query_pixelformat()
725 to inspect the capabilities of a given pixelformat. The function returns
726 an sg_pixelformat_info struct with the following bool members:
727
728 - sample: the pixelformat can be sampled as texture at least with
729 nearest filtering
730 - filter: the pixelformat can be samples as texture with linear
731 filtering
732 - render: the pixelformat can be used for render targets
733 - blend: blending is supported when using the pixelformat for
734 render targets
735 - msaa: multisample-antialiasing is supported when using the
736 pixelformat for render targets
737 - depth: the pixelformat can be used for depth-stencil attachments
738
739 When targeting GLES2/WebGL, the only safe formats to use
740 as texture are SG_PIXELFORMAT_R8 and SG_PIXELFORMAT_RGBA8. For rendering
741 in GLES2/WebGL, only SG_PIXELFORMAT_RGBA8 is safe. All other formats
742 must be checked via sg_query_pixelformats().
743
744 The default pixel format for texture images is SG_PIXELFORMAT_RGBA8.
745
746 The default pixel format for render target images is platform-dependent:
747 - for Metal and D3D11 it is SG_PIXELFORMAT_BGRA8
748 - for GL backends it is SG_PIXELFORMAT_RGBA8
749
750 This is mainly because of the default framebuffer which is setup outside
751 of sokol_gfx.h. On some backends, using BGRA for the default frame buffer
752 allows more efficient frame flips. For your own offscreen-render-targets,
753 use whatever renderable pixel format is convenient for you.
754*/
755typedef enum sg_pixel_format {
756 _SG_PIXELFORMAT_DEFAULT, /* value 0 reserved for default-init */
757 SG_PIXELFORMAT_NONE,
758
759 SG_PIXELFORMAT_R8,
760 SG_PIXELFORMAT_R8SN,
761 SG_PIXELFORMAT_R8UI,
762 SG_PIXELFORMAT_R8SI,
763
764 SG_PIXELFORMAT_R16,
765 SG_PIXELFORMAT_R16SN,
766 SG_PIXELFORMAT_R16UI,
767 SG_PIXELFORMAT_R16SI,
768 SG_PIXELFORMAT_R16F,
769 SG_PIXELFORMAT_RG8,
770 SG_PIXELFORMAT_RG8SN,
771 SG_PIXELFORMAT_RG8UI,
772 SG_PIXELFORMAT_RG8SI,
773
774 SG_PIXELFORMAT_R32UI,
775 SG_PIXELFORMAT_R32SI,
776 SG_PIXELFORMAT_R32F,
777 SG_PIXELFORMAT_RG16,
778 SG_PIXELFORMAT_RG16SN,
779 SG_PIXELFORMAT_RG16UI,
780 SG_PIXELFORMAT_RG16SI,
781 SG_PIXELFORMAT_RG16F,
782 SG_PIXELFORMAT_RGBA8,
783 SG_PIXELFORMAT_RGBA8SN,
784 SG_PIXELFORMAT_RGBA8UI,
785 SG_PIXELFORMAT_RGBA8SI,
786 SG_PIXELFORMAT_BGRA8,
787 SG_PIXELFORMAT_RGB10A2,
788 SG_PIXELFORMAT_RG11B10F,
789
790 SG_PIXELFORMAT_RG32UI,
791 SG_PIXELFORMAT_RG32SI,
792 SG_PIXELFORMAT_RG32F,
793 SG_PIXELFORMAT_RGBA16,
794 SG_PIXELFORMAT_RGBA16SN,
795 SG_PIXELFORMAT_RGBA16UI,
796 SG_PIXELFORMAT_RGBA16SI,
797 SG_PIXELFORMAT_RGBA16F,
798
799 SG_PIXELFORMAT_RGBA32UI,
800 SG_PIXELFORMAT_RGBA32SI,
801 SG_PIXELFORMAT_RGBA32F,
802
803 SG_PIXELFORMAT_DEPTH,
804 SG_PIXELFORMAT_DEPTH_STENCIL,
805
806 SG_PIXELFORMAT_BC1_RGBA,
807 SG_PIXELFORMAT_BC2_RGBA,
808 SG_PIXELFORMAT_BC3_RGBA,
809 SG_PIXELFORMAT_BC4_R,
810 SG_PIXELFORMAT_BC4_RSN,
811 SG_PIXELFORMAT_BC5_RG,
812 SG_PIXELFORMAT_BC5_RGSN,
813 SG_PIXELFORMAT_BC6H_RGBF,
814 SG_PIXELFORMAT_BC6H_RGBUF,
815 SG_PIXELFORMAT_BC7_RGBA,
816 SG_PIXELFORMAT_PVRTC_RGB_2BPP,
817 SG_PIXELFORMAT_PVRTC_RGB_4BPP,
818 SG_PIXELFORMAT_PVRTC_RGBA_2BPP,
819 SG_PIXELFORMAT_PVRTC_RGBA_4BPP,
820 SG_PIXELFORMAT_ETC2_RGB8,
821 SG_PIXELFORMAT_ETC2_RGB8A1,
822 SG_PIXELFORMAT_ETC2_RGBA8,
823 SG_PIXELFORMAT_ETC2_RG11,
824 SG_PIXELFORMAT_ETC2_RG11SN,
825
826 _SG_PIXELFORMAT_NUM,
827 _SG_PIXELFORMAT_FORCE_U32 = 0x7FFFFFFF
828} sg_pixel_format;
829
830/*
831 Runtime information about a pixel format, returned
832 by sg_query_pixelformat().
833*/
834typedef struct sg_pixelformat_info {
835 bool sample; // pixel format can be sampled in shaders
836 bool filter; // pixel format can be sampled with filtering
837 bool render; // pixel format can be used as render target
838 bool blend; // alpha-blending is supported
839 bool msaa; // pixel format can be used as MSAA render target
840 bool depth; // pixel format is a depth format
841 #if defined(SOKOL_ZIG_BINDINGS)
842 uint32_t __pad[3];
843 #endif
844} sg_pixelformat_info;
845
846/*
847 Runtime information about available optional features,
848 returned by sg_query_features()
849*/
850typedef struct sg_features {
851 bool instancing; // hardware instancing supported
852 bool origin_top_left; // framebuffer and texture origin is in top left corner
853 bool multiple_render_targets; // offscreen render passes can have multiple render targets attached
854 bool msaa_render_targets; // offscreen render passes support MSAA antialiasing
855 bool imagetype_3d; // creation of SG_IMAGETYPE_3D images is supported
856 bool imagetype_array; // creation of SG_IMAGETYPE_ARRAY images is supported
857 bool image_clamp_to_border; // border color and clamp-to-border UV-wrap mode is supported
858 bool mrt_independent_blend_state; // multiple-render-target rendering can use per-render-target blend state
859 bool mrt_independent_write_mask; // multiple-render-target rendering can use per-render-target color write masks
860 #if defined(SOKOL_ZIG_BINDINGS)
861 uint32_t __pad[3];
862 #endif
863} sg_features;
864
865/*
866 Runtime information about resource limits, returned by sg_query_limit()
867*/
868typedef struct sg_limits {
869 int max_image_size_2d; // max width/height of SG_IMAGETYPE_2D images
870 int max_image_size_cube; // max width/height of SG_IMAGETYPE_CUBE images
871 int max_image_size_3d; // max width/height/depth of SG_IMAGETYPE_3D images
872 int max_image_size_array; // max width/height of SG_IMAGETYPE_ARRAY images
873 int max_image_array_layers; // max number of layers in SG_IMAGETYPE_ARRAY images
874 int max_vertex_attrs; // <= SG_MAX_VERTEX_ATTRIBUTES (only on some GLES2 impls)
875} sg_limits;
876
877/*
878 sg_resource_state
879
880 The current state of a resource in its resource pool.
881 Resources start in the INITIAL state, which means the
882 pool slot is unoccupied and can be allocated. When a resource is
883 created, first an id is allocated, and the resource pool slot
884 is set to state ALLOC. After allocation, the resource is
885 initialized, which may result in the VALID or FAILED state. The
886 reason why allocation and initialization are separate is because
887 some resource types (e.g. buffers and images) might be asynchronously
888 initialized by the user application. If a resource which is not
889 in the VALID state is attempted to be used for rendering, rendering
890 operations will silently be dropped.
891
892 The special INVALID state is returned in sg_query_xxx_state() if no
893 resource object exists for the provided resource id.
894*/
895typedef enum sg_resource_state {
896 SG_RESOURCESTATE_INITIAL,
897 SG_RESOURCESTATE_ALLOC,
898 SG_RESOURCESTATE_VALID,
899 SG_RESOURCESTATE_FAILED,
900 SG_RESOURCESTATE_INVALID,
901 _SG_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF
902} sg_resource_state;
903
904/*
905 sg_usage
906
907 A resource usage hint describing the update strategy of
908 buffers and images. This is used in the sg_buffer_desc.usage
909 and sg_image_desc.usage members when creating buffers
910 and images:
911
912 SG_USAGE_IMMUTABLE: the resource will never be updated with
913 new data, instead the content of the
914 resource must be provided on creation
915 SG_USAGE_DYNAMIC: the resource will be updated infrequently
916 with new data (this could range from "once
917 after creation", to "quite often but not
918 every frame")
919 SG_USAGE_STREAM: the resource will be updated each frame
920 with new content
921
922 The rendering backends use this hint to prevent that the
923 CPU needs to wait for the GPU when attempting to update
924 a resource that might be currently accessed by the GPU.
925
926 Resource content is updated with the functions sg_update_buffer() or
927 sg_append_buffer() for buffer objects, and sg_update_image() for image
928 objects. For the sg_update_*() functions, only one update is allowed per
929 frame and resource object, while sg_append_buffer() can be called
930 multiple times per frame on the same buffer. The application must update
931 all data required for rendering (this means that the update data can be
932 smaller than the resource size, if only a part of the overall resource
933 size is used for rendering, you only need to make sure that the data that
934 *is* used is valid).
935
936 The default usage is SG_USAGE_IMMUTABLE.
937*/
938typedef enum sg_usage {
939 _SG_USAGE_DEFAULT, /* value 0 reserved for default-init */
940 SG_USAGE_IMMUTABLE,
941 SG_USAGE_DYNAMIC,
942 SG_USAGE_STREAM,
943 _SG_USAGE_NUM,
944 _SG_USAGE_FORCE_U32 = 0x7FFFFFFF
945} sg_usage;
946
947/*
948 sg_buffer_type
949
950 This indicates whether a buffer contains vertex- or index-data,
951 used in the sg_buffer_desc.type member when creating a buffer.
952
953 The default value is SG_BUFFERTYPE_VERTEXBUFFER.
954*/
955typedef enum sg_buffer_type {
956 _SG_BUFFERTYPE_DEFAULT, /* value 0 reserved for default-init */
957 SG_BUFFERTYPE_VERTEXBUFFER,
958 SG_BUFFERTYPE_INDEXBUFFER,
959 _SG_BUFFERTYPE_NUM,
960 _SG_BUFFERTYPE_FORCE_U32 = 0x7FFFFFFF
961} sg_buffer_type;
962
963/*
964 sg_index_type
965
966 Indicates whether indexed rendering (fetching vertex-indices from an
967 index buffer) is used, and if yes, the index data type (16- or 32-bits).
968 This is used in the sg_pipeline_desc.index_type member when creating a
969 pipeline object.
970
971 The default index type is SG_INDEXTYPE_NONE.
972*/
973typedef enum sg_index_type {
974 _SG_INDEXTYPE_DEFAULT, /* value 0 reserved for default-init */
975 SG_INDEXTYPE_NONE,
976 SG_INDEXTYPE_UINT16,
977 SG_INDEXTYPE_UINT32,
978 _SG_INDEXTYPE_NUM,
979 _SG_INDEXTYPE_FORCE_U32 = 0x7FFFFFFF
980} sg_index_type;
981
982/*
983 sg_image_type
984
985 Indicates the basic type of an image object (2D-texture, cubemap,
986 3D-texture or 2D-array-texture). 3D- and array-textures are not supported
987 on the GLES2/WebGL backend (use sg_query_features().imagetype_3d and
988 sg_query_features().imagetype_array to check for support). The image type
989 is used in the sg_image_desc.type member when creating an image, and
990 in sg_shader_image_desc when describing a shader's texture sampler binding.
991
992 The default image type when creating an image is SG_IMAGETYPE_2D.
993*/
994typedef enum sg_image_type {
995 _SG_IMAGETYPE_DEFAULT, /* value 0 reserved for default-init */
996 SG_IMAGETYPE_2D,
997 SG_IMAGETYPE_CUBE,
998 SG_IMAGETYPE_3D,
999 SG_IMAGETYPE_ARRAY,
1000 _SG_IMAGETYPE_NUM,
1001 _SG_IMAGETYPE_FORCE_U32 = 0x7FFFFFFF
1002} sg_image_type;
1003
1004/*
1005 sg_sampler_type
1006
1007 Indicates the basic data type of a shader's texture sampler which
1008 can be float , unsigned integer or signed integer. The sampler
1009 type is used in the sg_shader_image_desc to describe the
1010 sampler type of a shader's texture sampler binding.
1011
1012 The default sampler type is SG_SAMPLERTYPE_FLOAT.
1013*/
1014typedef enum sg_sampler_type {
1015 _SG_SAMPLERTYPE_DEFAULT, /* value 0 reserved for default-init */
1016 SG_SAMPLERTYPE_FLOAT,
1017 SG_SAMPLERTYPE_SINT,
1018 SG_SAMPLERTYPE_UINT,
1019} sg_sampler_type;
1020
1021/*
1022 sg_cube_face
1023
1024 The cubemap faces. Use these as indices in the sg_image_desc.content
1025 array.
1026*/
1027typedef enum sg_cube_face {
1028 SG_CUBEFACE_POS_X,
1029 SG_CUBEFACE_NEG_X,
1030 SG_CUBEFACE_POS_Y,
1031 SG_CUBEFACE_NEG_Y,
1032 SG_CUBEFACE_POS_Z,
1033 SG_CUBEFACE_NEG_Z,
1034 SG_CUBEFACE_NUM,
1035 _SG_CUBEFACE_FORCE_U32 = 0x7FFFFFFF
1036} sg_cube_face;
1037
1038/*
1039 sg_shader_stage
1040
1041 There are 2 shader stages: vertex- and fragment-shader-stage.
1042 Each shader stage consists of:
1043
1044 - one slot for a shader function (provided as source- or byte-code)
1045 - SG_MAX_SHADERSTAGE_UBS slots for uniform blocks
1046 - SG_MAX_SHADERSTAGE_IMAGES slots for images used as textures by
1047 the shader function
1048*/
1049typedef enum sg_shader_stage {
1050 SG_SHADERSTAGE_VS,
1051 SG_SHADERSTAGE_FS,
1052 _SG_SHADERSTAGE_FORCE_U32 = 0x7FFFFFFF
1053} sg_shader_stage;
1054
1055/*
1056 sg_primitive_type
1057
1058 This is the common subset of 3D primitive types supported across all 3D
1059 APIs. This is used in the sg_pipeline_desc.primitive_type member when
1060 creating a pipeline object.
1061
1062 The default primitive type is SG_PRIMITIVETYPE_TRIANGLES.
1063*/
1064typedef enum sg_primitive_type {
1065 _SG_PRIMITIVETYPE_DEFAULT, /* value 0 reserved for default-init */
1066 SG_PRIMITIVETYPE_POINTS,
1067 SG_PRIMITIVETYPE_LINES,
1068 SG_PRIMITIVETYPE_LINE_STRIP,
1069 SG_PRIMITIVETYPE_TRIANGLES,
1070 SG_PRIMITIVETYPE_TRIANGLE_STRIP,
1071 _SG_PRIMITIVETYPE_NUM,
1072 _SG_PRIMITIVETYPE_FORCE_U32 = 0x7FFFFFFF
1073} sg_primitive_type;
1074
1075/*
1076 sg_filter
1077
1078 The filtering mode when sampling a texture image. This is
1079 used in the sg_image_desc.min_filter and sg_image_desc.mag_filter
1080 members when creating an image object.
1081
1082 The default filter mode is SG_FILTER_NEAREST.
1083*/
1084typedef enum sg_filter {
1085 _SG_FILTER_DEFAULT, /* value 0 reserved for default-init */
1086 SG_FILTER_NEAREST,
1087 SG_FILTER_LINEAR,
1088 SG_FILTER_NEAREST_MIPMAP_NEAREST,
1089 SG_FILTER_NEAREST_MIPMAP_LINEAR,
1090 SG_FILTER_LINEAR_MIPMAP_NEAREST,
1091 SG_FILTER_LINEAR_MIPMAP_LINEAR,
1092 _SG_FILTER_NUM,
1093 _SG_FILTER_FORCE_U32 = 0x7FFFFFFF
1094} sg_filter;
1095
1096/*
1097 sg_wrap
1098
1099 The texture coordinates wrapping mode when sampling a texture
1100 image. This is used in the sg_image_desc.wrap_u, .wrap_v
1101 and .wrap_w members when creating an image.
1102
1103 The default wrap mode is SG_WRAP_REPEAT.
1104
1105 NOTE: SG_WRAP_CLAMP_TO_BORDER is not supported on all backends
1106 and platforms. To check for support, call sg_query_features()
1107 and check the "clamp_to_border" boolean in the returned
1108 sg_features struct.
1109
1110 Platforms which don't support SG_WRAP_CLAMP_TO_BORDER will silently fall back
1111 to SG_WRAP_CLAMP_TO_EDGE without a validation error.
1112
1113 Platforms which support clamp-to-border are:
1114
1115 - all desktop GL platforms
1116 - Metal on macOS
1117 - D3D11
1118
1119 Platforms which do not support clamp-to-border:
1120
1121 - GLES2/3 and WebGL/WebGL2
1122 - Metal on iOS
1123*/
1124typedef enum sg_wrap {
1125 _SG_WRAP_DEFAULT, /* value 0 reserved for default-init */
1126 SG_WRAP_REPEAT,
1127 SG_WRAP_CLAMP_TO_EDGE,
1128 SG_WRAP_CLAMP_TO_BORDER,
1129 SG_WRAP_MIRRORED_REPEAT,
1130 _SG_WRAP_NUM,
1131 _SG_WRAP_FORCE_U32 = 0x7FFFFFFF
1132} sg_wrap;
1133
1134/*
1135 sg_border_color
1136
1137 The border color to use when sampling a texture, and the UV wrap
1138 mode is SG_WRAP_CLAMP_TO_BORDER.
1139
1140 The default border color is SG_BORDERCOLOR_OPAQUE_BLACK
1141*/
1142typedef enum sg_border_color {
1143 _SG_BORDERCOLOR_DEFAULT, /* value 0 reserved for default-init */
1144 SG_BORDERCOLOR_TRANSPARENT_BLACK,
1145 SG_BORDERCOLOR_OPAQUE_BLACK,
1146 SG_BORDERCOLOR_OPAQUE_WHITE,
1147 _SG_BORDERCOLOR_NUM,
1148 _SG_BORDERCOLOR_FORCE_U32 = 0x7FFFFFFF
1149} sg_border_color;
1150
1151/*
1152 sg_vertex_format
1153
1154 The data type of a vertex component. This is used to describe
1155 the layout of vertex data when creating a pipeline object.
1156*/
1157typedef enum sg_vertex_format {
1158 SG_VERTEXFORMAT_INVALID,
1159 SG_VERTEXFORMAT_FLOAT,
1160 SG_VERTEXFORMAT_FLOAT2,
1161 SG_VERTEXFORMAT_FLOAT3,
1162 SG_VERTEXFORMAT_FLOAT4,
1163 SG_VERTEXFORMAT_BYTE4,
1164 SG_VERTEXFORMAT_BYTE4N,
1165 SG_VERTEXFORMAT_UBYTE4,
1166 SG_VERTEXFORMAT_UBYTE4N,
1167 SG_VERTEXFORMAT_SHORT2,
1168 SG_VERTEXFORMAT_SHORT2N,
1169 SG_VERTEXFORMAT_USHORT2N,
1170 SG_VERTEXFORMAT_SHORT4,
1171 SG_VERTEXFORMAT_SHORT4N,
1172 SG_VERTEXFORMAT_USHORT4N,
1173 SG_VERTEXFORMAT_UINT10_N2,
1174 _SG_VERTEXFORMAT_NUM,
1175 _SG_VERTEXFORMAT_FORCE_U32 = 0x7FFFFFFF
1176} sg_vertex_format;
1177
1178/*
1179 sg_vertex_step
1180
1181 Defines whether the input pointer of a vertex input stream is advanced
1182 'per vertex' or 'per instance'. The default step-func is
1183 SG_VERTEXSTEP_PER_VERTEX. SG_VERTEXSTEP_PER_INSTANCE is used with
1184 instanced-rendering.
1185
1186 The vertex-step is part of the vertex-layout definition
1187 when creating pipeline objects.
1188*/
1189typedef enum sg_vertex_step {
1190 _SG_VERTEXSTEP_DEFAULT, /* value 0 reserved for default-init */
1191 SG_VERTEXSTEP_PER_VERTEX,
1192 SG_VERTEXSTEP_PER_INSTANCE,
1193 _SG_VERTEXSTEP_NUM,
1194 _SG_VERTEXSTEP_FORCE_U32 = 0x7FFFFFFF
1195} sg_vertex_step;
1196
1197/*
1198 sg_uniform_type
1199
1200 The data type of a uniform block member. This is used to
1201 describe the internal layout of uniform blocks when creating
1202 a shader object.
1203*/
1204typedef enum sg_uniform_type {
1205 SG_UNIFORMTYPE_INVALID,
1206 SG_UNIFORMTYPE_FLOAT,
1207 SG_UNIFORMTYPE_FLOAT2,
1208 SG_UNIFORMTYPE_FLOAT3,
1209 SG_UNIFORMTYPE_FLOAT4,
1210 SG_UNIFORMTYPE_MAT4,
1211 _SG_UNIFORMTYPE_NUM,
1212 _SG_UNIFORMTYPE_FORCE_U32 = 0x7FFFFFFF
1213} sg_uniform_type;
1214
1215/*
1216 sg_cull_mode
1217
1218 The face-culling mode, this is used in the
1219 sg_pipeline_desc.cull_mode member when creating a
1220 pipeline object.
1221
1222 The default cull mode is SG_CULLMODE_NONE
1223*/
1224typedef enum sg_cull_mode {
1225 _SG_CULLMODE_DEFAULT, /* value 0 reserved for default-init */
1226 SG_CULLMODE_NONE,
1227 SG_CULLMODE_FRONT,
1228 SG_CULLMODE_BACK,
1229 _SG_CULLMODE_NUM,
1230 _SG_CULLMODE_FORCE_U32 = 0x7FFFFFFF
1231} sg_cull_mode;
1232
1233/*
1234 sg_face_winding
1235
1236 The vertex-winding rule that determines a front-facing primitive. This
1237 is used in the member sg_pipeline_desc.face_winding
1238 when creating a pipeline object.
1239
1240 The default winding is SG_FACEWINDING_CW (clockwise)
1241*/
1242typedef enum sg_face_winding {
1243 _SG_FACEWINDING_DEFAULT, /* value 0 reserved for default-init */
1244 SG_FACEWINDING_CCW,
1245 SG_FACEWINDING_CW,
1246 _SG_FACEWINDING_NUM,
1247 _SG_FACEWINDING_FORCE_U32 = 0x7FFFFFFF
1248} sg_face_winding;
1249
1250/*
1251 sg_compare_func
1252
1253 The compare-function for depth- and stencil-ref tests.
1254 This is used when creating pipeline objects in the members:
1255
1256 sg_pipeline_desc
1257 .depth
1258 .compare
1259 .stencil
1260 .front.compare
1261 .back.compar
1262
1263 The default compare func for depth- and stencil-tests is
1264 SG_COMPAREFUNC_ALWAYS.
1265*/
1266typedef enum sg_compare_func {
1267 _SG_COMPAREFUNC_DEFAULT, /* value 0 reserved for default-init */
1268 SG_COMPAREFUNC_NEVER,
1269 SG_COMPAREFUNC_LESS,
1270 SG_COMPAREFUNC_EQUAL,
1271 SG_COMPAREFUNC_LESS_EQUAL,
1272 SG_COMPAREFUNC_GREATER,
1273 SG_COMPAREFUNC_NOT_EQUAL,
1274 SG_COMPAREFUNC_GREATER_EQUAL,
1275 SG_COMPAREFUNC_ALWAYS,
1276 _SG_COMPAREFUNC_NUM,
1277 _SG_COMPAREFUNC_FORCE_U32 = 0x7FFFFFFF
1278} sg_compare_func;
1279
1280/*
1281 sg_stencil_op
1282
1283 The operation performed on a currently stored stencil-value when a
1284 comparison test passes or fails. This is used when creating a pipeline
1285 object in the members:
1286
1287 sg_pipeline_desc
1288 .stencil
1289 .front
1290 .fail_op
1291 .depth_fail_op
1292 .pass_op
1293 .back
1294 .fail_op
1295 .depth_fail_op
1296 .pass_op
1297
1298 The default value is SG_STENCILOP_KEEP.
1299*/
1300typedef enum sg_stencil_op {
1301 _SG_STENCILOP_DEFAULT, /* value 0 reserved for default-init */
1302 SG_STENCILOP_KEEP,
1303 SG_STENCILOP_ZERO,
1304 SG_STENCILOP_REPLACE,
1305 SG_STENCILOP_INCR_CLAMP,
1306 SG_STENCILOP_DECR_CLAMP,
1307 SG_STENCILOP_INVERT,
1308 SG_STENCILOP_INCR_WRAP,
1309 SG_STENCILOP_DECR_WRAP,
1310 _SG_STENCILOP_NUM,
1311 _SG_STENCILOP_FORCE_U32 = 0x7FFFFFFF
1312} sg_stencil_op;
1313
1314/*
1315 sg_blend_factor
1316
1317 The source and destination factors in blending operations.
1318 This is used in the following members when creating a pipeline object:
1319
1320 sg_pipeline_desc
1321 .colors[i]
1322 .blend
1323 .src_factor_rgb
1324 .dst_factor_rgb
1325 .src_factor_alpha
1326 .dst_factor_alpha
1327
1328 The default value is SG_BLENDFACTOR_ONE for source
1329 factors, and SG_BLENDFACTOR_ZERO for destination factors.
1330*/
1331typedef enum sg_blend_factor {
1332 _SG_BLENDFACTOR_DEFAULT, /* value 0 reserved for default-init */
1333 SG_BLENDFACTOR_ZERO,
1334 SG_BLENDFACTOR_ONE,
1335 SG_BLENDFACTOR_SRC_COLOR,
1336 SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR,
1337 SG_BLENDFACTOR_SRC_ALPHA,
1338 SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA,
1339 SG_BLENDFACTOR_DST_COLOR,
1340 SG_BLENDFACTOR_ONE_MINUS_DST_COLOR,
1341 SG_BLENDFACTOR_DST_ALPHA,
1342 SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA,
1343 SG_BLENDFACTOR_SRC_ALPHA_SATURATED,
1344 SG_BLENDFACTOR_BLEND_COLOR,
1345 SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR,
1346 SG_BLENDFACTOR_BLEND_ALPHA,
1347 SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA,
1348 _SG_BLENDFACTOR_NUM,
1349 _SG_BLENDFACTOR_FORCE_U32 = 0x7FFFFFFF
1350} sg_blend_factor;
1351
1352/*
1353 sg_blend_op
1354
1355 Describes how the source and destination values are combined in the
1356 fragment blending operation. It is used in the following members when
1357 creating a pipeline object:
1358
1359 sg_pipeline_desc
1360 .colors[i]
1361 .blend
1362 .op_rgb
1363 .op_alpha
1364
1365 The default value is SG_BLENDOP_ADD.
1366*/
1367typedef enum sg_blend_op {
1368 _SG_BLENDOP_DEFAULT, /* value 0 reserved for default-init */
1369 SG_BLENDOP_ADD,
1370 SG_BLENDOP_SUBTRACT,
1371 SG_BLENDOP_REVERSE_SUBTRACT,
1372 _SG_BLENDOP_NUM,
1373 _SG_BLENDOP_FORCE_U32 = 0x7FFFFFFF
1374} sg_blend_op;
1375
1376/*
1377 sg_color_mask
1378
1379 Selects the active color channels when writing a fragment color to the
1380 framebuffer. This is used in the members
1381 sg_pipeline_desc.colors[i].write_mask when creating a pipeline object.
1382
1383 The default colormask is SG_COLORMASK_RGBA (write all colors channels)
1384
1385 NOTE: since the color mask value 0 is reserved for the default value
1386 (SG_COLORMASK_RGBA), use SG_COLORMASK_NONE if all color channels
1387 should be disabled.
1388*/
1389typedef enum sg_color_mask {
1390 _SG_COLORMASK_DEFAULT = 0, /* value 0 reserved for default-init */
1391 SG_COLORMASK_NONE = 0x10, /* special value for 'all channels disabled */
1392 SG_COLORMASK_R = 0x1,
1393 SG_COLORMASK_G = 0x2,
1394 SG_COLORMASK_RG = 0x3,
1395 SG_COLORMASK_B = 0x4,
1396 SG_COLORMASK_RB = 0x5,
1397 SG_COLORMASK_GB = 0x6,
1398 SG_COLORMASK_RGB = 0x7,
1399 SG_COLORMASK_A = 0x8,
1400 SG_COLORMASK_RA = 0x9,
1401 SG_COLORMASK_GA = 0xA,
1402 SG_COLORMASK_RGA = 0xB,
1403 SG_COLORMASK_BA = 0xC,
1404 SG_COLORMASK_RBA = 0xD,
1405 SG_COLORMASK_GBA = 0xE,
1406 SG_COLORMASK_RGBA = 0xF,
1407 _SG_COLORMASK_FORCE_U32 = 0x7FFFFFFF
1408} sg_color_mask;
1409
1410/*
1411 sg_action
1412
1413 Defines what action should be performed at the start of a render pass:
1414
1415 SG_ACTION_CLEAR: clear the render target image
1416 SG_ACTION_LOAD: load the previous content of the render target image
1417 SG_ACTION_DONTCARE: leave the render target image content undefined
1418
1419 This is used in the sg_pass_action structure.
1420
1421 The default action for all pass attachments is SG_ACTION_CLEAR, with the
1422 clear color rgba = {0.5f, 0.5f, 0.5f, 1.0f], depth=1.0 and stencil=0.
1423
1424 If you want to override the default behaviour, it is important to not
1425 only set the clear color, but the 'action' field as well (as long as this
1426 is in its _SG_ACTION_DEFAULT, the value fields will be ignored).
1427*/
1428typedef enum sg_action {
1429 _SG_ACTION_DEFAULT,
1430 SG_ACTION_CLEAR,
1431 SG_ACTION_LOAD,
1432 SG_ACTION_DONTCARE,
1433 _SG_ACTION_NUM,
1434 _SG_ACTION_FORCE_U32 = 0x7FFFFFFF
1435} sg_action;
1436
1437/*
1438 sg_pass_action
1439
1440 The sg_pass_action struct defines the actions to be performed
1441 at the start of a rendering pass in the functions sg_begin_pass()
1442 and sg_begin_default_pass().
1443
1444 A separate action and clear values can be defined for each
1445 color attachment, and for the depth-stencil attachment.
1446
1447 The default clear values are defined by the macros:
1448
1449 - SG_DEFAULT_CLEAR_RED: 0.5f
1450 - SG_DEFAULT_CLEAR_GREEN: 0.5f
1451 - SG_DEFAULT_CLEAR_BLUE: 0.5f
1452 - SG_DEFAULT_CLEAR_ALPHA: 1.0f
1453 - SG_DEFAULT_CLEAR_DEPTH: 1.0f
1454 - SG_DEFAULT_CLEAR_STENCIL: 0
1455*/
1456typedef struct sg_color_attachment_action {
1457 sg_action action;
1458 sg_color value;
1459} sg_color_attachment_action;
1460
1461typedef struct sg_depth_attachment_action {
1462 sg_action action;
1463 float value;
1464} sg_depth_attachment_action;
1465
1466typedef struct sg_stencil_attachment_action {
1467 sg_action action;
1468 uint8_t value;
1469} sg_stencil_attachment_action;
1470
1471typedef struct sg_pass_action {
1472 uint32_t _start_canary;
1473 sg_color_attachment_action colors[SG_MAX_COLOR_ATTACHMENTS];
1474 sg_depth_attachment_action depth;
1475 sg_stencil_attachment_action stencil;
1476 uint32_t _end_canary;
1477} sg_pass_action;
1478
1479/*
1480 sg_bindings
1481
1482 The sg_bindings structure defines the resource binding slots
1483 of the sokol_gfx render pipeline, used as argument to the
1484 sg_apply_bindings() function.
1485
1486 A resource binding struct contains:
1487
1488 - 1..N vertex buffers
1489 - 0..N vertex buffer offsets
1490 - 0..1 index buffers
1491 - 0..1 index buffer offsets
1492 - 0..N vertex shader stage images
1493 - 0..N fragment shader stage images
1494
1495 The max number of vertex buffer and shader stage images
1496 are defined by the SG_MAX_SHADERSTAGE_BUFFERS and
1497 SG_MAX_SHADERSTAGE_IMAGES configuration constants.
1498
1499 The optional buffer offsets can be used to put different unrelated
1500 chunks of vertex- and/or index-data into the same buffer objects.
1501*/
1502typedef struct sg_bindings {
1503 uint32_t _start_canary;
1504 sg_buffer vertex_buffers[SG_MAX_SHADERSTAGE_BUFFERS];
1505 int vertex_buffer_offsets[SG_MAX_SHADERSTAGE_BUFFERS];
1506 sg_buffer index_buffer;
1507 int index_buffer_offset;
1508 sg_image vs_images[SG_MAX_SHADERSTAGE_IMAGES];
1509 sg_image fs_images[SG_MAX_SHADERSTAGE_IMAGES];
1510 uint32_t _end_canary;
1511} sg_bindings;
1512
1513/*
1514 sg_buffer_desc
1515
1516 Creation parameters for sg_buffer objects, used in the
1517 sg_make_buffer() call.
1518
1519 The default configuration is:
1520
1521 .size: 0 (*must* be >0 for buffers without data)
1522 .type: SG_BUFFERTYPE_VERTEXBUFFER
1523 .usage: SG_USAGE_IMMUTABLE
1524 .data.ptr 0 (*must* be valid for immutable buffers)
1525 .data.size 0 (*must* be > 0 for immutable buffers)
1526 .label 0 (optional string label for trace hooks)
1527
1528 The label will be ignored by sokol_gfx.h, it is only useful
1529 when hooking into sg_make_buffer() or sg_init_buffer() via
1530 the sg_install_trace_hooks() function.
1531
1532 For immutable buffers which are initialized with initial data,
1533 keep the .size item zero-initialized, and set the size together with the
1534 pointer to the initial data in the .data item.
1535
1536 For mutable buffers without initial data, keep the .data item
1537 zero-initialized, and set the buffer size in the .size item instead.
1538
1539 You can also set both size values, but currently both size values must
1540 be identical (this may change in the future when the dynamic resource
1541 management may become more flexible).
1542
1543 ADVANCED TOPIC: Injecting native 3D-API buffers:
1544
1545 The following struct members allow to inject your own GL, Metal
1546 or D3D11 buffers into sokol_gfx:
1547
1548 .gl_buffers[SG_NUM_INFLIGHT_FRAMES]
1549 .mtl_buffers[SG_NUM_INFLIGHT_FRAMES]
1550 .d3d11_buffer
1551
1552 You must still provide all other struct items except the .data item, and
1553 these must match the creation parameters of the native buffers you
1554 provide. For SG_USAGE_IMMUTABLE, only provide a single native 3D-API
1555 buffer, otherwise you need to provide SG_NUM_INFLIGHT_FRAMES buffers
1556 (only for GL and Metal, not D3D11). Providing multiple buffers for GL and
1557 Metal is necessary because sokol_gfx will rotate through them when
1558 calling sg_update_buffer() to prevent lock-stalls.
1559
1560 Note that it is expected that immutable injected buffer have already been
1561 initialized with content, and the .content member must be 0!
1562
1563 Also you need to call sg_reset_state_cache() after calling native 3D-API
1564 functions, and before calling any sokol_gfx function.
1565*/
1566typedef struct sg_buffer_desc {
1567 uint32_t _start_canary;
1568 size_t size;
1569 sg_buffer_type type;
1570 sg_usage usage;
1571 sg_range data;
1572 const char* label;
1573 /* GL specific */
1574 uint32_t gl_buffers[SG_NUM_INFLIGHT_FRAMES];
1575 /* Metal specific */
1576 const void* mtl_buffers[SG_NUM_INFLIGHT_FRAMES];
1577 /* D3D11 specific */
1578 const void* d3d11_buffer;
1579 /* WebGPU specific */
1580 const void* wgpu_buffer;
1581 uint32_t _end_canary;
1582} sg_buffer_desc;
1583
1584/*
1585 sg_image_data
1586
1587 Defines the content of an image through a 2D array of sg_range structs.
1588 The first array dimension is the cubemap face, and the second array
1589 dimension the mipmap level.
1590*/
1591typedef struct sg_image_data {
1592 sg_range subimage[SG_CUBEFACE_NUM][SG_MAX_MIPMAPS];
1593} sg_image_data;
1594
1595/*
1596 sg_image_desc
1597
1598 Creation parameters for sg_image objects, used in the sg_make_image()
1599 call.
1600
1601 The default configuration is:
1602
1603 .type: SG_IMAGETYPE_2D
1604 .render_target: false
1605 .width 0 (must be set to >0)
1606 .height 0 (must be set to >0)
1607 .num_slices 1 (3D textures: depth; array textures: number of layers)
1608 .num_mipmaps: 1
1609 .usage: SG_USAGE_IMMUTABLE
1610 .pixel_format: SG_PIXELFORMAT_RGBA8 for textures, or sg_desc.context.color_format for render targets
1611 .sample_count: 1 for textures, or sg_desc.context.sample_count for render targets
1612 .min_filter: SG_FILTER_NEAREST
1613 .mag_filter: SG_FILTER_NEAREST
1614 .wrap_u: SG_WRAP_REPEAT
1615 .wrap_v: SG_WRAP_REPEAT
1616 .wrap_w: SG_WRAP_REPEAT (only SG_IMAGETYPE_3D)
1617 .border_color SG_BORDERCOLOR_OPAQUE_BLACK
1618 .max_anisotropy 1 (must be 1..16)
1619 .min_lod 0.0f
1620 .max_lod FLT_MAX
1621 .data an sg_image_data struct to define the initial content
1622 .label 0 (optional string label for trace hooks)
1623
1624 Q: Why is the default sample_count for render targets identical with the
1625 "default sample count" from sg_desc.context.sample_count?
1626
1627 A: So that it matches the default sample count in pipeline objects. Even
1628 though it is a bit strange/confusing that offscreen render targets by default
1629 get the same sample count as the default framebuffer, but it's better that
1630 an offscreen render target created with default parameters matches
1631 a pipeline object created with default parameters.
1632
1633 NOTE:
1634
1635 SG_IMAGETYPE_ARRAY and SG_IMAGETYPE_3D are not supported on WebGL/GLES2,
1636 use sg_query_features().imagetype_array and
1637 sg_query_features().imagetype_3d at runtime to check if array- and
1638 3D-textures are supported.
1639
1640 Images with usage SG_USAGE_IMMUTABLE must be fully initialized by
1641 providing a valid .data member which points to initialization data.
1642
1643 ADVANCED TOPIC: Injecting native 3D-API textures:
1644
1645 The following struct members allow to inject your own GL, Metal or D3D11
1646 textures into sokol_gfx:
1647
1648 .gl_textures[SG_NUM_INFLIGHT_FRAMES]
1649 .mtl_textures[SG_NUM_INFLIGHT_FRAMES]
1650 .d3d11_texture
1651 .d3d11_shader_resource_view
1652
1653 For GL, you can also specify the texture target or leave it empty to use
1654 the default texture target for the image type (GL_TEXTURE_2D for
1655 SG_IMAGETYPE_2D etc)
1656
1657 For D3D11, you can provide either a D3D11 texture, or a
1658 shader-resource-view, or both. If only a texture is provided, a matching
1659 shader-resource-view will be created. If only a shader-resource-view is
1660 provided, the texture will be looked up from the shader-resource-view.
1661
1662 The same rules apply as for injecting native buffers (see sg_buffer_desc
1663 documentation for more details).
1664*/
1665typedef struct sg_image_desc {
1666 uint32_t _start_canary;
1667 sg_image_type type;
1668 bool render_target;
1669 int width;
1670 int height;
1671 int num_slices;
1672 int num_mipmaps;
1673 sg_usage usage;
1674 sg_pixel_format pixel_format;
1675 int sample_count;
1676 sg_filter min_filter;
1677 sg_filter mag_filter;
1678 sg_wrap wrap_u;
1679 sg_wrap wrap_v;
1680 sg_wrap wrap_w;
1681 sg_border_color border_color;
1682 uint32_t max_anisotropy;
1683 float min_lod;
1684 float max_lod;
1685 sg_image_data data;
1686 const char* label;
1687 /* GL specific */
1688 uint32_t gl_textures[SG_NUM_INFLIGHT_FRAMES];
1689 uint32_t gl_texture_target;
1690 /* Metal specific */
1691 const void* mtl_textures[SG_NUM_INFLIGHT_FRAMES];
1692 /* D3D11 specific */
1693 const void* d3d11_texture;
1694 const void* d3d11_shader_resource_view;
1695 /* WebGPU specific */
1696 const void* wgpu_texture;
1697 uint32_t _end_canary;
1698} sg_image_desc;
1699
1700/*
1701 sg_shader_desc
1702
1703 The structure sg_shader_desc defines all creation parameters for shader
1704 programs, used as input to the sg_make_shader() function:
1705
1706 - reflection information for vertex attributes (vertex shader inputs):
1707 - vertex attribute name (required for GLES2, optional for GLES3 and GL)
1708 - a semantic name and index (required for D3D11)
1709 - for each shader-stage (vertex and fragment):
1710 - the shader source or bytecode
1711 - an optional entry function name
1712 - an optional compile target (only for D3D11 when source is provided,
1713 defaults are "vs_4_0" and "ps_4_0")
1714 - reflection info for each uniform block used by the shader stage:
1715 - the size of the uniform block in bytes
1716 - reflection info for each uniform block member (only required for GL backends):
1717 - member name
1718 - member type (SG_UNIFORMTYPE_xxx)
1719 - if the member is an array, the number of array items
1720 - reflection info for the texture images used by the shader stage:
1721 - the image type (SG_IMAGETYPE_xxx)
1722 - the sampler type (SG_SAMPLERTYPE_xxx, default is SG_SAMPLERTYPE_FLOAT)
1723 - the name of the texture sampler (required for GLES2, optional everywhere else)
1724
1725 For all GL backends, shader source-code must be provided. For D3D11 and Metal,
1726 either shader source-code or byte-code can be provided.
1727
1728 For D3D11, if source code is provided, the d3dcompiler_47.dll will be loaded
1729 on demand. If this fails, shader creation will fail. When compiling HLSL
1730 source code, you can provide an optional target string via
1731 sg_shader_stage_desc.d3d11_target, the default target is "vs_4_0" for the
1732 vertex shader stage and "ps_4_0" for the pixel shader stage.
1733*/
1734typedef struct sg_shader_attr_desc {
1735 const char* name; // GLSL vertex attribute name (only strictly required for GLES2)
1736 const char* sem_name; // HLSL semantic name
1737 int sem_index; // HLSL semantic index
1738} sg_shader_attr_desc;
1739
1740typedef struct sg_shader_uniform_desc {
1741 const char* name;
1742 sg_uniform_type type;
1743 int array_count;
1744} sg_shader_uniform_desc;
1745
1746typedef struct sg_shader_uniform_block_desc {
1747 size_t size;
1748 sg_shader_uniform_desc uniforms[SG_MAX_UB_MEMBERS];
1749} sg_shader_uniform_block_desc;
1750
1751typedef struct sg_shader_image_desc {
1752 const char* name;
1753 sg_image_type image_type;
1754 sg_sampler_type sampler_type;
1755} sg_shader_image_desc;
1756
1757typedef struct sg_shader_stage_desc {
1758 const char* source;
1759 sg_range bytecode;
1760 const char* entry;
1761 const char* d3d11_target;
1762 sg_shader_uniform_block_desc uniform_blocks[SG_MAX_SHADERSTAGE_UBS];
1763 sg_shader_image_desc images[SG_MAX_SHADERSTAGE_IMAGES];
1764} sg_shader_stage_desc;
1765
1766typedef struct sg_shader_desc {
1767 uint32_t _start_canary;
1768 sg_shader_attr_desc attrs[SG_MAX_VERTEX_ATTRIBUTES];
1769 sg_shader_stage_desc vs;
1770 sg_shader_stage_desc fs;
1771 const char* label;
1772 uint32_t _end_canary;
1773} sg_shader_desc;
1774
1775/*
1776 sg_pipeline_desc
1777
1778 The sg_pipeline_desc struct defines all creation parameters for an
1779 sg_pipeline object, used as argument to the sg_make_pipeline() function:
1780
1781 - the vertex layout for all input vertex buffers
1782 - a shader object
1783 - the 3D primitive type (points, lines, triangles, ...)
1784 - the index type (none, 16- or 32-bit)
1785 - all the fixed-function-pipeline state (depth-, stencil-, blend-state, etc...)
1786
1787 If the vertex data has no gaps between vertex components, you can omit
1788 the .layout.buffers[].stride and layout.attrs[].offset items (leave them
1789 default-initialized to 0), sokol-gfx will then compute the offsets and
1790 strides from the vertex component formats (.layout.attrs[].format).
1791 Please note that ALL vertex attribute offsets must be 0 in order for the
1792 automatic offset computation to kick in.
1793
1794 The default configuration is as follows:
1795
1796 .shader: 0 (must be initialized with a valid sg_shader id!)
1797 .layout:
1798 .buffers[]: vertex buffer layouts
1799 .stride: 0 (if no stride is given it will be computed)
1800 .step_func SG_VERTEXSTEP_PER_VERTEX
1801 .step_rate 1
1802 .attrs[]: vertex attribute declarations
1803 .buffer_index 0 the vertex buffer bind slot
1804 .offset 0 (offsets can be omitted if the vertex layout has no gaps)
1805 .format SG_VERTEXFORMAT_INVALID (must be initialized!)
1806 .depth:
1807 .pixel_format: sg_desc.context.depth_format
1808 .compare: SG_COMPAREFUNC_ALWAYS
1809 .write_enabled: false
1810 .bias: 0.0f
1811 .bias_slope_scale: 0.0f
1812 .bias_clamp: 0.0f
1813 .stencil:
1814 .enabled: false
1815 .front/back:
1816 .compare: SG_COMPAREFUNC_ALWAYS
1817 .depth_fail_op: SG_STENCILOP_KEEP
1818 .pass_op: SG_STENCILOP_KEEP
1819 .compare: SG_COMPAREFUNC_ALWAYS
1820 .read_mask: 0
1821 .write_mask: 0
1822 .ref: 0
1823 .color_count 1
1824 .colors[0..color_count]
1825 .pixel_format sg_desc.context.color_format
1826 .write_mask: SG_COLORMASK_RGBA
1827 .blend:
1828 .enabled: false
1829 .src_factor_rgb: SG_BLENDFACTOR_ONE
1830 .dst_factor_rgb: SG_BLENDFACTOR_ZERO
1831 .op_rgb: SG_BLENDOP_ADD
1832 .src_factor_alpha: SG_BLENDFACTOR_ONE
1833 .dst_factor_alpha: SG_BLENDFACTOR_ZERO
1834 .op_alpha: SG_BLENDOP_ADD
1835 .primitive_type: SG_PRIMITIVETYPE_TRIANGLES
1836 .index_type: SG_INDEXTYPE_NONE
1837 .cull_mode: SG_CULLMODE_NONE
1838 .face_winding: SG_FACEWINDING_CW
1839 .sample_count: sg_desc.context.sample_count
1840 .blend_color: (sg_color) { 0.0f, 0.0f, 0.0f, 0.0f }
1841 .alpha_to_coverage_enabled: false
1842 .label 0 (optional string label for trace hooks)
1843*/
1844typedef struct sg_buffer_layout_desc {
1845 int stride;
1846 sg_vertex_step step_func;
1847 int step_rate;
1848 #if defined(SOKOL_ZIG_BINDINGS)
1849 uint32_t __pad[2];
1850 #endif
1851} sg_buffer_layout_desc;
1852
1853typedef struct sg_vertex_attr_desc {
1854 int buffer_index;
1855 int offset;
1856 sg_vertex_format format;
1857 #if defined(SOKOL_ZIG_BINDINGS)
1858 uint32_t __pad[2];
1859 #endif
1860} sg_vertex_attr_desc;
1861
1862typedef struct sg_layout_desc {
1863 sg_buffer_layout_desc buffers[SG_MAX_SHADERSTAGE_BUFFERS];
1864 sg_vertex_attr_desc attrs[SG_MAX_VERTEX_ATTRIBUTES];
1865} sg_layout_desc;
1866
1867typedef struct sg_stencil_face_state {
1868 sg_compare_func compare;
1869 sg_stencil_op fail_op;
1870 sg_stencil_op depth_fail_op;
1871 sg_stencil_op pass_op;
1872} sg_stencil_face_state;
1873
1874typedef struct sg_stencil_state {
1875 bool enabled;
1876 sg_stencil_face_state front;
1877 sg_stencil_face_state back;
1878 uint8_t read_mask;
1879 uint8_t write_mask;
1880 uint8_t ref;
1881} sg_stencil_state;
1882
1883typedef struct sg_depth_state {
1884 sg_pixel_format pixel_format;
1885 sg_compare_func compare;
1886 bool write_enabled;
1887 float bias;
1888 float bias_slope_scale;
1889 float bias_clamp;
1890} sg_depth_state;
1891
1892typedef struct sg_blend_state {
1893 bool enabled;
1894 sg_blend_factor src_factor_rgb;
1895 sg_blend_factor dst_factor_rgb;
1896 sg_blend_op op_rgb;
1897 sg_blend_factor src_factor_alpha;
1898 sg_blend_factor dst_factor_alpha;
1899 sg_blend_op op_alpha;
1900} sg_blend_state;
1901
1902typedef struct sg_color_state {
1903 sg_pixel_format pixel_format;
1904 sg_color_mask write_mask;
1905 sg_blend_state blend;
1906} sg_color_state;
1907
1908typedef struct sg_pipeline_desc {
1909 uint32_t _start_canary;
1910 sg_shader shader;
1911 sg_layout_desc layout;
1912 sg_depth_state depth;
1913 sg_stencil_state stencil;
1914 int color_count;
1915 sg_color_state colors[SG_MAX_COLOR_ATTACHMENTS];
1916 sg_primitive_type primitive_type;
1917 sg_index_type index_type;
1918 sg_cull_mode cull_mode;
1919 sg_face_winding face_winding;
1920 int sample_count;
1921 sg_color blend_color;
1922 bool alpha_to_coverage_enabled;
1923 const char* label;
1924 uint32_t _end_canary;
1925} sg_pipeline_desc;
1926
1927/*
1928 sg_pass_desc
1929
1930 Creation parameters for an sg_pass object, used as argument
1931 to the sg_make_pass() function.
1932
1933 A pass object contains 1..4 color-attachments and none, or one,
1934 depth-stencil-attachment. Each attachment consists of
1935 an image, and two additional indices describing
1936 which subimage the pass will render to: one mipmap index, and
1937 if the image is a cubemap, array-texture or 3D-texture, the
1938 face-index, array-layer or depth-slice.
1939
1940 Pass images must fulfill the following requirements:
1941
1942 All images must have:
1943 - been created as render target (sg_image_desc.render_target = true)
1944 - the same size
1945 - the same sample count
1946
1947 In addition, all color-attachment images must have the same pixel format.
1948*/
1949typedef struct sg_pass_attachment_desc {
1950 sg_image image;
1951 int mip_level;
1952 int slice; /* cube texture: face; array texture: layer; 3D texture: slice */
1953} sg_pass_attachment_desc;
1954
1955typedef struct sg_pass_desc {
1956 uint32_t _start_canary;
1957 sg_pass_attachment_desc color_attachments[SG_MAX_COLOR_ATTACHMENTS];
1958 sg_pass_attachment_desc depth_stencil_attachment;
1959 const char* label;
1960 uint32_t _end_canary;
1961} sg_pass_desc;
1962
1963/*
1964 sg_trace_hooks
1965
1966 Installable callback functions to keep track of the sokol-gfx calls,
1967 this is useful for debugging, or keeping track of resource creation
1968 and destruction.
1969
1970 Trace hooks are installed with sg_install_trace_hooks(), this returns
1971 another sg_trace_hooks struct with the previous set of
1972 trace hook function pointers. These should be invoked by the
1973 new trace hooks to form a proper call chain.
1974*/
1975typedef struct sg_trace_hooks {
1976 void* user_data;
1977 void (*reset_state_cache)(void* user_data);
1978 void (*make_buffer)(const sg_buffer_desc* desc, sg_buffer result, void* user_data);
1979 void (*make_image)(const sg_image_desc* desc, sg_image result, void* user_data);
1980 void (*make_shader)(const sg_shader_desc* desc, sg_shader result, void* user_data);
1981 void (*make_pipeline)(const sg_pipeline_desc* desc, sg_pipeline result, void* user_data);
1982 void (*make_pass)(const sg_pass_desc* desc, sg_pass result, void* user_data);
1983 void (*destroy_buffer)(sg_buffer buf, void* user_data);
1984 void (*destroy_image)(sg_image img, void* user_data);
1985 void (*destroy_shader)(sg_shader shd, void* user_data);
1986 void (*destroy_pipeline)(sg_pipeline pip, void* user_data);
1987 void (*destroy_pass)(sg_pass pass, void* user_data);
1988 void (*update_buffer)(sg_buffer buf, const sg_range* data, void* user_data);
1989 void (*update_image)(sg_image img, const sg_image_data* data, void* user_data);
1990 void (*append_buffer)(sg_buffer buf, const sg_range* data, int result, void* user_data);
1991 void (*begin_default_pass)(const sg_pass_action* pass_action, int width, int height, void* user_data);
1992 void (*begin_pass)(sg_pass pass, const sg_pass_action* pass_action, void* user_data);
1993 void (*apply_viewport)(int x, int y, int width, int height, bool origin_top_left, void* user_data);
1994 void (*apply_scissor_rect)(int x, int y, int width, int height, bool origin_top_left, void* user_data);
1995 void (*apply_pipeline)(sg_pipeline pip, void* user_data);
1996 void (*apply_bindings)(const sg_bindings* bindings, void* user_data);
1997 void (*apply_uniforms)(sg_shader_stage stage, int ub_index, const sg_range* data, void* user_data);
1998 void (*draw)(int base_element, int num_elements, int num_instances, void* user_data);
1999 void (*end_pass)(void* user_data);
2000 void (*commit)(void* user_data);
2001 void (*alloc_buffer)(sg_buffer result, void* user_data);
2002 void (*alloc_image)(sg_image result, void* user_data);
2003 void (*alloc_shader)(sg_shader result, void* user_data);
2004 void (*alloc_pipeline)(sg_pipeline result, void* user_data);
2005 void (*alloc_pass)(sg_pass result, void* user_data);
2006 void (*dealloc_buffer)(sg_buffer buf_id, void* user_data);
2007 void (*dealloc_image)(sg_image img_id, void* user_data);
2008 void (*dealloc_shader)(sg_shader shd_id, void* user_data);
2009 void (*dealloc_pipeline)(sg_pipeline pip_id, void* user_data);
2010 void (*dealloc_pass)(sg_pass pass_id, void* user_data);
2011 void (*init_buffer)(sg_buffer buf_id, const sg_buffer_desc* desc, void* user_data);
2012 void (*init_image)(sg_image img_id, const sg_image_desc* desc, void* user_data);
2013 void (*init_shader)(sg_shader shd_id, const sg_shader_desc* desc, void* user_data);
2014 void (*init_pipeline)(sg_pipeline pip_id, const sg_pipeline_desc* desc, void* user_data);
2015 void (*init_pass)(sg_pass pass_id, const sg_pass_desc* desc, void* user_data);
2016 void (*uninit_buffer)(sg_buffer buf_id, void* user_data);
2017 void (*uninit_image)(sg_image img_id, void* user_data);
2018 void (*uninit_shader)(sg_shader shd_id, void* user_data);
2019 void (*uninit_pipeline)(sg_pipeline pip_id, void* user_data);
2020 void (*uninit_pass)(sg_pass pass_id, void* user_data);
2021 void (*fail_buffer)(sg_buffer buf_id, void* user_data);
2022 void (*fail_image)(sg_image img_id, void* user_data);
2023 void (*fail_shader)(sg_shader shd_id, void* user_data);
2024 void (*fail_pipeline)(sg_pipeline pip_id, void* user_data);
2025 void (*fail_pass)(sg_pass pass_id, void* user_data);
2026 void (*push_debug_group)(const char* name, void* user_data);
2027 void (*pop_debug_group)(void* user_data);
2028 void (*err_buffer_pool_exhausted)(void* user_data);
2029 void (*err_image_pool_exhausted)(void* user_data);
2030 void (*err_shader_pool_exhausted)(void* user_data);
2031 void (*err_pipeline_pool_exhausted)(void* user_data);
2032 void (*err_pass_pool_exhausted)(void* user_data);
2033 void (*err_context_mismatch)(void* user_data);
2034 void (*err_pass_invalid)(void* user_data);
2035 void (*err_draw_invalid)(void* user_data);
2036 void (*err_bindings_invalid)(void* user_data);
2037} sg_trace_hooks;
2038
2039/*
2040 sg_buffer_info
2041 sg_image_info
2042 sg_shader_info
2043 sg_pipeline_info
2044 sg_pass_info
2045
2046 These structs contain various internal resource attributes which
2047 might be useful for debug-inspection. Please don't rely on the
2048 actual content of those structs too much, as they are quite closely
2049 tied to sokol_gfx.h internals and may change more frequently than
2050 the other public API elements.
2051
2052 The *_info structs are used as the return values of the following functions:
2053
2054 sg_query_buffer_info()
2055 sg_query_image_info()
2056 sg_query_shader_info()
2057 sg_query_pipeline_info()
2058 sg_query_pass_info()
2059*/
2060typedef struct sg_slot_info {
2061 sg_resource_state state; /* the current state of this resource slot */
2062 uint32_t res_id; /* type-neutral resource if (e.g. sg_buffer.id) */
2063 uint32_t ctx_id; /* the context this resource belongs to */
2064} sg_slot_info;
2065
2066typedef struct sg_buffer_info {
2067 sg_slot_info slot; /* resource pool slot info */
2068 uint32_t update_frame_index; /* frame index of last sg_update_buffer() */
2069 uint32_t append_frame_index; /* frame index of last sg_append_buffer() */
2070 int append_pos; /* current position in buffer for sg_append_buffer() */
2071 bool append_overflow; /* is buffer in overflow state (due to sg_append_buffer) */
2072 int num_slots; /* number of renaming-slots for dynamically updated buffers */
2073 int active_slot; /* currently active write-slot for dynamically updated buffers */
2074} sg_buffer_info;
2075
2076typedef struct sg_image_info {
2077 sg_slot_info slot; /* resource pool slot info */
2078 uint32_t upd_frame_index; /* frame index of last sg_update_image() */
2079 int num_slots; /* number of renaming-slots for dynamically updated images */
2080 int active_slot; /* currently active write-slot for dynamically updated images */
2081 int width; /* image width */
2082 int height; /* image height */
2083} sg_image_info;
2084
2085typedef struct sg_shader_info {
2086 sg_slot_info slot; /* resoure pool slot info */
2087} sg_shader_info;
2088
2089typedef struct sg_pipeline_info {
2090 sg_slot_info slot; /* resource pool slot info */
2091} sg_pipeline_info;
2092
2093typedef struct sg_pass_info {
2094 sg_slot_info slot; /* resource pool slot info */
2095} sg_pass_info;
2096
2097/*
2098 sg_desc
2099
2100 The sg_desc struct contains configuration values for sokol_gfx,
2101 it is used as parameter to the sg_setup() call.
2102
2103 NOTE that all callback function pointers come in two versions, one without
2104 a userdata pointer, and one with a userdata pointer. You would
2105 either initialize one or the other depending on whether you pass data
2106 to your callbacks.
2107
2108 FIXME: explain the various configuration options
2109
2110 The default configuration is:
2111
2112 .buffer_pool_size 128
2113 .image_pool_size 128
2114 .shader_pool_size 32
2115 .pipeline_pool_size 64
2116 .pass_pool_size 16
2117 .context_pool_size 16
2118 .sampler_cache_size 64
2119 .uniform_buffer_size 4 MB (4*1024*1024)
2120 .staging_buffer_size 8 MB (8*1024*1024)
2121
2122 .context.color_format: default value depends on selected backend:
2123 all GL backends: SG_PIXELFORMAT_RGBA8
2124 Metal and D3D11: SG_PIXELFORMAT_BGRA8
2125 WGPU: *no default* (must be queried from WGPU swapchain)
2126 .context.depth_format SG_PIXELFORMAT_DEPTH_STENCIL
2127 .context.sample_count 1
2128
2129 GL specific:
2130 .context.gl.force_gles2
2131 if this is true the GL backend will act in "GLES2 fallback mode" even
2132 when compiled with SOKOL_GLES3, this is useful to fall back
2133 to traditional WebGL if a browser doesn't support a WebGL2 context
2134
2135 Metal specific:
2136 (NOTE: All Objective-C object references are transferred through
2137 a bridged (const void*) to sokol_gfx, which will use a unretained
2138 bridged cast (__bridged id<xxx>) to retrieve the Objective-C
2139 references back. Since the bridge cast is unretained, the caller
2140 must hold a strong reference to the Objective-C object for the
2141 duration of the sokol_gfx call!
2142
2143 .context.metal.device
2144 a pointer to the MTLDevice object
2145 .context.metal.renderpass_descriptor_cb
2146 .context.metal_renderpass_descriptor_userdata_cb
2147 A C callback function to obtain the MTLRenderPassDescriptor for the
2148 current frame when rendering to the default framebuffer, will be called
2149 in sg_begin_default_pass().
2150 .context.metal.drawable_cb
2151 .context.metal.drawable_userdata_cb
2152 a C callback function to obtain a MTLDrawable for the current
2153 frame when rendering to the default framebuffer, will be called in
2154 sg_end_pass() of the default pass
2155 .context.metal.user_data
2156 optional user data pointer passed to the userdata versions of
2157 callback functions
2158
2159 D3D11 specific:
2160 .context.d3d11.device
2161 a pointer to the ID3D11Device object, this must have been created
2162 before sg_setup() is called
2163 .context.d3d11.device_context
2164 a pointer to the ID3D11DeviceContext object
2165 .context.d3d11.render_target_view_cb
2166 .context.d3d11.render_target_view_userdata_cb
2167 a C callback function to obtain a pointer to the current
2168 ID3D11RenderTargetView object of the default framebuffer,
2169 this function will be called in sg_begin_pass() when rendering
2170 to the default framebuffer
2171 .context.d3d11.depth_stencil_view_cb
2172 .context.d3d11.depth_stencil_view_userdata_cb
2173 a C callback function to obtain a pointer to the current
2174 ID3D11DepthStencilView object of the default framebuffer,
2175 this function will be called in sg_begin_pass() when rendering
2176 to the default framebuffer
2177 .context.metal.user_data
2178 optional user data pointer passed to the userdata versions of
2179 callback functions
2180
2181 WebGPU specific:
2182 .context.wgpu.device
2183 a WGPUDevice handle
2184 .context.wgpu.render_format
2185 WGPUTextureFormat of the swap chain surface
2186 .context.wgpu.render_view_cb
2187 .context.wgpu.render_view_userdata_cb
2188 callback to get the current WGPUTextureView of the swapchain's
2189 rendering attachment (may be an MSAA surface)
2190 .context.wgpu.resolve_view_cb
2191 .context.wgpu.resolve_view_userdata_cb
2192 callback to get the current WGPUTextureView of the swapchain's
2193 MSAA-resolve-target surface, must return 0 if not MSAA rendering
2194 .context.wgpu.depth_stencil_view_cb
2195 .context.wgpu.depth_stencil_view_userdata_cb
2196 callback to get current default-pass depth-stencil-surface WGPUTextureView
2197 the pixel format of the default WGPUTextureView must be WGPUTextureFormat_Depth24Plus8
2198 .context.metal.user_data
2199 optional user data pointer passed to the userdata versions of
2200 callback functions
2201
2202 When using sokol_gfx.h and sokol_app.h together, consider using the
2203 helper function sapp_sgcontext() in the sokol_glue.h header to
2204 initialize the sg_desc.context nested struct. sapp_sgcontext() returns
2205 a completely initialized sg_context_desc struct with information
2206 provided by sokol_app.h.
2207*/
2208typedef struct sg_gl_context_desc {
2209 bool force_gles2;
2210} sg_gl_context_desc;
2211
2212typedef struct sg_metal_context_desc {
2213 const void* device;
2214 const void* (*renderpass_descriptor_cb)(void);
2215 const void* (*renderpass_descriptor_userdata_cb)(void*);
2216 const void* (*drawable_cb)(void);
2217 const void* (*drawable_userdata_cb)(void*);
2218 void* user_data;
2219} sg_metal_context_desc;
2220
2221typedef struct sg_d3d11_context_desc {
2222 const void* device;
2223 const void* device_context;
2224 const void* (*render_target_view_cb)(void);
2225 const void* (*render_target_view_userdata_cb)(void*);
2226 const void* (*depth_stencil_view_cb)(void);
2227 const void* (*depth_stencil_view_userdata_cb)(void*);
2228 void* user_data;
2229} sg_d3d11_context_desc;
2230
2231typedef struct sg_wgpu_context_desc {
2232 const void* device; /* WGPUDevice */
2233 const void* (*render_view_cb)(void); /* returns WGPUTextureView */
2234 const void* (*render_view_userdata_cb)(void*);
2235 const void* (*resolve_view_cb)(void); /* returns WGPUTextureView */
2236 const void* (*resolve_view_userdata_cb)(void*);
2237 const void* (*depth_stencil_view_cb)(void); /* returns WGPUTextureView, must be WGPUTextureFormat_Depth24Plus8 */
2238 const void* (*depth_stencil_view_userdata_cb)(void*);
2239 void* user_data;
2240} sg_wgpu_context_desc;
2241
2242typedef struct sg_context_desc {
2243 sg_pixel_format color_format;
2244 sg_pixel_format depth_format;
2245 int sample_count;
2246 sg_gl_context_desc gl;
2247 sg_metal_context_desc metal;
2248 sg_d3d11_context_desc d3d11;
2249 sg_wgpu_context_desc wgpu;
2250} sg_context_desc;
2251
2252typedef struct sg_desc {
2253 uint32_t _start_canary;
2254 int buffer_pool_size;
2255 int image_pool_size;
2256 int shader_pool_size;
2257 int pipeline_pool_size;
2258 int pass_pool_size;
2259 int context_pool_size;
2260 int uniform_buffer_size;
2261 int staging_buffer_size;
2262 int sampler_cache_size;
2263 sg_context_desc context;
2264 uint32_t _end_canary;
2265} sg_desc;
2266
2267/* setup and misc functions */
2268SOKOL_GFX_API_DECL void sg_setup(const sg_desc* desc);
2269SOKOL_GFX_API_DECL void sg_shutdown(void);
2270SOKOL_GFX_API_DECL bool sg_isvalid(void);
2271SOKOL_GFX_API_DECL void sg_reset_state_cache(void);
2272SOKOL_GFX_API_DECL sg_trace_hooks sg_install_trace_hooks(const sg_trace_hooks* trace_hooks);
2273SOKOL_GFX_API_DECL void sg_push_debug_group(const char* name);
2274SOKOL_GFX_API_DECL void sg_pop_debug_group(void);
2275
2276/* resource creation, destruction and updating */
2277SOKOL_GFX_API_DECL sg_buffer sg_make_buffer(const sg_buffer_desc* desc);
2278SOKOL_GFX_API_DECL sg_image sg_make_image(const sg_image_desc* desc);
2279SOKOL_GFX_API_DECL sg_shader sg_make_shader(const sg_shader_desc* desc);
2280SOKOL_GFX_API_DECL sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc);
2281SOKOL_GFX_API_DECL sg_pass sg_make_pass(const sg_pass_desc* desc);
2282SOKOL_GFX_API_DECL void sg_destroy_buffer(sg_buffer buf);
2283SOKOL_GFX_API_DECL void sg_destroy_image(sg_image img);
2284SOKOL_GFX_API_DECL void sg_destroy_shader(sg_shader shd);
2285SOKOL_GFX_API_DECL void sg_destroy_pipeline(sg_pipeline pip);
2286SOKOL_GFX_API_DECL void sg_destroy_pass(sg_pass pass);
2287SOKOL_GFX_API_DECL void sg_update_buffer(sg_buffer buf, const sg_range* data);
2288SOKOL_GFX_API_DECL void sg_update_image(sg_image img, const sg_image_data* data);
2289SOKOL_GFX_API_DECL int sg_append_buffer(sg_buffer buf, const sg_range* data);
2290SOKOL_GFX_API_DECL bool sg_query_buffer_overflow(sg_buffer buf);
2291
2292/* rendering functions */
2293SOKOL_GFX_API_DECL void sg_begin_default_pass(const sg_pass_action* pass_action, int width, int height);
2294SOKOL_GFX_API_DECL void sg_begin_default_passf(const sg_pass_action* pass_action, float width, float height);
2295SOKOL_GFX_API_DECL void sg_begin_pass(sg_pass pass, const sg_pass_action* pass_action);
2296SOKOL_GFX_API_DECL void sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left);
2297SOKOL_GFX_API_DECL void sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left);
2298SOKOL_GFX_API_DECL void sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left);
2299SOKOL_GFX_API_DECL void sg_apply_scissor_rectf(float x, float y, float width, float height, bool origin_top_left);
2300SOKOL_GFX_API_DECL void sg_apply_pipeline(sg_pipeline pip);
2301SOKOL_GFX_API_DECL void sg_apply_bindings(const sg_bindings* bindings);
2302SOKOL_GFX_API_DECL void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data);
2303SOKOL_GFX_API_DECL void sg_draw(int base_element, int num_elements, int num_instances);
2304SOKOL_GFX_API_DECL void sg_end_pass(void);
2305SOKOL_GFX_API_DECL void sg_commit(void);
2306
2307/* getting information */
2308SOKOL_GFX_API_DECL sg_desc sg_query_desc(void);
2309SOKOL_GFX_API_DECL sg_backend sg_query_backend(void);
2310SOKOL_GFX_API_DECL sg_features sg_query_features(void);
2311SOKOL_GFX_API_DECL sg_limits sg_query_limits(void);
2312SOKOL_GFX_API_DECL sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt);
2313/* get current state of a resource (INITIAL, ALLOC, VALID, FAILED, INVALID) */
2314SOKOL_GFX_API_DECL sg_resource_state sg_query_buffer_state(sg_buffer buf);
2315SOKOL_GFX_API_DECL sg_resource_state sg_query_image_state(sg_image img);
2316SOKOL_GFX_API_DECL sg_resource_state sg_query_shader_state(sg_shader shd);
2317SOKOL_GFX_API_DECL sg_resource_state sg_query_pipeline_state(sg_pipeline pip);
2318SOKOL_GFX_API_DECL sg_resource_state sg_query_pass_state(sg_pass pass);
2319/* get runtime information about a resource */
2320SOKOL_GFX_API_DECL sg_buffer_info sg_query_buffer_info(sg_buffer buf);
2321SOKOL_GFX_API_DECL sg_image_info sg_query_image_info(sg_image img);
2322SOKOL_GFX_API_DECL sg_shader_info sg_query_shader_info(sg_shader shd);
2323SOKOL_GFX_API_DECL sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip);
2324SOKOL_GFX_API_DECL sg_pass_info sg_query_pass_info(sg_pass pass);
2325/* get resource creation desc struct with their default values replaced */
2326SOKOL_GFX_API_DECL sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc);
2327SOKOL_GFX_API_DECL sg_image_desc sg_query_image_defaults(const sg_image_desc* desc);
2328SOKOL_GFX_API_DECL sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc);
2329SOKOL_GFX_API_DECL sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc);
2330SOKOL_GFX_API_DECL sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc);
2331
2332/* separate resource allocation and initialization (for async setup) */
2333SOKOL_GFX_API_DECL sg_buffer sg_alloc_buffer(void);
2334SOKOL_GFX_API_DECL sg_image sg_alloc_image(void);
2335SOKOL_GFX_API_DECL sg_shader sg_alloc_shader(void);
2336SOKOL_GFX_API_DECL sg_pipeline sg_alloc_pipeline(void);
2337SOKOL_GFX_API_DECL sg_pass sg_alloc_pass(void);
2338SOKOL_GFX_API_DECL void sg_dealloc_buffer(sg_buffer buf_id);
2339SOKOL_GFX_API_DECL void sg_dealloc_image(sg_image img_id);
2340SOKOL_GFX_API_DECL void sg_dealloc_shader(sg_shader shd_id);
2341SOKOL_GFX_API_DECL void sg_dealloc_pipeline(sg_pipeline pip_id);
2342SOKOL_GFX_API_DECL void sg_dealloc_pass(sg_pass pass_id);
2343SOKOL_GFX_API_DECL void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc* desc);
2344SOKOL_GFX_API_DECL void sg_init_image(sg_image img_id, const sg_image_desc* desc);
2345SOKOL_GFX_API_DECL void sg_init_shader(sg_shader shd_id, const sg_shader_desc* desc);
2346SOKOL_GFX_API_DECL void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc* desc);
2347SOKOL_GFX_API_DECL void sg_init_pass(sg_pass pass_id, const sg_pass_desc* desc);
2348SOKOL_GFX_API_DECL bool sg_uninit_buffer(sg_buffer buf_id);
2349SOKOL_GFX_API_DECL bool sg_uninit_image(sg_image img_id);
2350SOKOL_GFX_API_DECL bool sg_uninit_shader(sg_shader shd_id);
2351SOKOL_GFX_API_DECL bool sg_uninit_pipeline(sg_pipeline pip_id);
2352SOKOL_GFX_API_DECL bool sg_uninit_pass(sg_pass pass_id);
2353SOKOL_GFX_API_DECL void sg_fail_buffer(sg_buffer buf_id);
2354SOKOL_GFX_API_DECL void sg_fail_image(sg_image img_id);
2355SOKOL_GFX_API_DECL void sg_fail_shader(sg_shader shd_id);
2356SOKOL_GFX_API_DECL void sg_fail_pipeline(sg_pipeline pip_id);
2357SOKOL_GFX_API_DECL void sg_fail_pass(sg_pass pass_id);
2358
2359/* rendering contexts (optional) */
2360SOKOL_GFX_API_DECL sg_context sg_setup_context(void);
2361SOKOL_GFX_API_DECL void sg_activate_context(sg_context ctx_id);
2362SOKOL_GFX_API_DECL void sg_discard_context(sg_context ctx_id);
2363
2364/* Backend-specific helper functions, these may come in handy for mixing
2365 sokol-gfx rendering with 'native backend' rendering functions.
2366
2367 This group of functions will be expanded as needed.
2368*/
2369
2370/* D3D11: return ID3D11Device */
2371SOKOL_GFX_API_DECL const void* sg_d3d11_device(void);
2372
2373/* Metal: return __bridge-casted MTLDevice */
2374SOKOL_GFX_API_DECL const void* sg_mtl_device(void);
2375
2376/* Metal: return __bridge-casted MTLRenderCommandEncoder in current pass (or zero if outside pass) */
2377SOKOL_GFX_API_DECL const void* sg_mtl_render_command_encoder(void);
2378
2379#ifdef __cplusplus
2380} /* extern "C" */
2381
2382/* reference-based equivalents for c++ */
2383inline void sg_setup(const sg_desc& desc) { return sg_setup(&desc); }
2384
2385inline sg_buffer sg_make_buffer(const sg_buffer_desc& desc) { return sg_make_buffer(&desc); }
2386inline sg_image sg_make_image(const sg_image_desc& desc) { return sg_make_image(&desc); }
2387inline sg_shader sg_make_shader(const sg_shader_desc& desc) { return sg_make_shader(&desc); }
2388inline sg_pipeline sg_make_pipeline(const sg_pipeline_desc& desc) { return sg_make_pipeline(&desc); }
2389inline sg_pass sg_make_pass(const sg_pass_desc& desc) { return sg_make_pass(&desc); }
2390inline void sg_update_image(sg_image img, const sg_image_data& data) { return sg_update_image(img, &data); }
2391
2392inline void sg_begin_default_pass(const sg_pass_action& pass_action, int width, int height) { return sg_begin_default_pass(&pass_action, width, height); }
2393inline void sg_begin_default_passf(const sg_pass_action& pass_action, float width, float height) { return sg_begin_default_passf(&pass_action, width, height); }
2394inline void sg_begin_pass(sg_pass pass, const sg_pass_action& pass_action) { return sg_begin_pass(pass, &pass_action); }
2395inline void sg_apply_bindings(const sg_bindings& bindings) { return sg_apply_bindings(&bindings); }
2396inline void sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range& data) { return sg_apply_uniforms(stage, ub_index, &data); }
2397
2398inline sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc& desc) { return sg_query_buffer_defaults(&desc); }
2399inline sg_image_desc sg_query_image_defaults(const sg_image_desc& desc) { return sg_query_image_defaults(&desc); }
2400inline sg_shader_desc sg_query_shader_defaults(const sg_shader_desc& desc) { return sg_query_shader_defaults(&desc); }
2401inline sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc& desc) { return sg_query_pipeline_defaults(&desc); }
2402inline sg_pass_desc sg_query_pass_defaults(const sg_pass_desc& desc) { return sg_query_pass_defaults(&desc); }
2403
2404inline void sg_init_buffer(sg_buffer buf_id, const sg_buffer_desc& desc) { return sg_init_buffer(buf_id, &desc); }
2405inline void sg_init_image(sg_image img_id, const sg_image_desc& desc) { return sg_init_image(img_id, &desc); }
2406inline void sg_init_shader(sg_shader shd_id, const sg_shader_desc& desc) { return sg_init_shader(shd_id, &desc); }
2407inline void sg_init_pipeline(sg_pipeline pip_id, const sg_pipeline_desc& desc) { return sg_init_pipeline(pip_id, &desc); }
2408inline void sg_init_pass(sg_pass pass_id, const sg_pass_desc& desc) { return sg_init_pass(pass_id, &desc); }
2409
2410inline void sg_update_buffer(sg_buffer buf_id, const sg_range& data) { return sg_update_buffer(buf_id, &data); }
2411inline int sg_append_buffer(sg_buffer buf_id, const sg_range& data) { return sg_append_buffer(buf_id, &data); }
2412#endif
2413#endif // SOKOL_GFX_INCLUDED
2414
2415/*--- IMPLEMENTATION ---------------------------------------------------------*/
2416#ifdef SOKOL_GFX_IMPL
2417#define SOKOL_GFX_IMPL_INCLUDED (1)
2418
2419#if !(defined(SOKOL_GLCORE33)||defined(SOKOL_GLES2)||defined(SOKOL_GLES3)||defined(SOKOL_D3D11)||defined(SOKOL_METAL)||defined(SOKOL_WGPU)||defined(SOKOL_DUMMY_BACKEND))
2420#error "Please select a backend with SOKOL_GLCORE33, SOKOL_GLES2, SOKOL_GLES3, SOKOL_D3D11, SOKOL_METAL, SOKOL_WGPU or SOKOL_DUMMY_BACKEND"
2421#endif
2422#include <string.h> /* memset */
2423#include <float.h> /* FLT_MAX */
2424
2425#ifndef SOKOL_API_IMPL
2426 #define SOKOL_API_IMPL
2427#endif
2428#ifndef SOKOL_DEBUG
2429 #ifndef NDEBUG
2430 #define SOKOL_DEBUG (1)
2431 #endif
2432#endif
2433#ifndef SOKOL_ASSERT
2434 #include <assert.h>
2435 #define SOKOL_ASSERT(c) assert(c)
2436#endif
2437#ifndef SOKOL_VALIDATE_BEGIN
2438 #define SOKOL_VALIDATE_BEGIN() _sg_validate_begin()
2439#endif
2440#ifndef SOKOL_VALIDATE
2441 #define SOKOL_VALIDATE(cond, err) _sg_validate((cond), err)
2442#endif
2443#ifndef SOKOL_VALIDATE_END
2444 #define SOKOL_VALIDATE_END() _sg_validate_end()
2445#endif
2446#ifndef SOKOL_UNREACHABLE
2447 #define SOKOL_UNREACHABLE SOKOL_ASSERT(false)
2448#endif
2449#ifndef SOKOL_MALLOC
2450 #include <stdlib.h>
2451 #define SOKOL_MALLOC(s) malloc(s)
2452 #define SOKOL_FREE(p) free(p)
2453#endif
2454#ifndef SOKOL_LOG
2455 #ifdef SOKOL_DEBUG
2456 #include <stdio.h>
2457 #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
2458 #else
2459 #define SOKOL_LOG(s)
2460 #endif
2461#endif
2462
2463#ifndef _SOKOL_PRIVATE
2464 #if defined(__GNUC__) || defined(__clang__)
2465 #define _SOKOL_PRIVATE __attribute__((unused)) static
2466 #else
2467 #define _SOKOL_PRIVATE static
2468 #endif
2469#endif
2470
2471#ifndef _SOKOL_UNUSED
2472 #define _SOKOL_UNUSED(x) (void)(x)
2473#endif
2474
2475#if defined(SOKOL_TRACE_HOOKS)
2476#define _SG_TRACE_ARGS(fn, ...) if (_sg.hooks.fn) { _sg.hooks.fn(__VA_ARGS__, _sg.hooks.user_data); }
2477#define _SG_TRACE_NOARGS(fn) if (_sg.hooks.fn) { _sg.hooks.fn(_sg.hooks.user_data); }
2478#else
2479#define _SG_TRACE_ARGS(fn, ...)
2480#define _SG_TRACE_NOARGS(fn)
2481#endif
2482
2483/* default clear values */
2484#ifndef SG_DEFAULT_CLEAR_RED
2485#define SG_DEFAULT_CLEAR_RED (0.5f)
2486#endif
2487#ifndef SG_DEFAULT_CLEAR_GREEN
2488#define SG_DEFAULT_CLEAR_GREEN (0.5f)
2489#endif
2490#ifndef SG_DEFAULT_CLEAR_BLUE
2491#define SG_DEFAULT_CLEAR_BLUE (0.5f)
2492#endif
2493#ifndef SG_DEFAULT_CLEAR_ALPHA
2494#define SG_DEFAULT_CLEAR_ALPHA (1.0f)
2495#endif
2496#ifndef SG_DEFAULT_CLEAR_DEPTH
2497#define SG_DEFAULT_CLEAR_DEPTH (1.0f)
2498#endif
2499#ifndef SG_DEFAULT_CLEAR_STENCIL
2500#define SG_DEFAULT_CLEAR_STENCIL (0)
2501#endif
2502
2503#ifdef _MSC_VER
2504#pragma warning(push)
2505#pragma warning(disable:4115) /* named type definition in parentheses */
2506#pragma warning(disable:4505) /* unreferenced local function has been removed */
2507#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union (needed by d3d11.h) */
2508#pragma warning(disable:4054) /* 'type cast': from function pointer */
2509#pragma warning(disable:4055) /* 'type cast': from data pointer */
2510#endif
2511
2512#if defined(SOKOL_D3D11)
2513 #ifndef D3D11_NO_HELPERS
2514 #define D3D11_NO_HELPERS
2515 #endif
2516 #ifndef WIN32_LEAN_AND_MEAN
2517 #define WIN32_LEAN_AND_MEAN
2518 #endif
2519 #ifndef NOMINMAX
2520 #define NOMINMAX
2521 #endif
2522 #include <d3d11.h>
2523 #include <d3dcompiler.h>
2524 #ifdef _MSC_VER
2525 #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
2526 #pragma comment (lib, "WindowsApp")
2527 #else
2528 #pragma comment (lib, "kernel32")
2529 #pragma comment (lib, "user32")
2530 #pragma comment (lib, "dxgi")
2531 #pragma comment (lib, "d3d11")
2532 #pragma comment (lib, "dxguid")
2533 #endif
2534 #endif
2535#elif defined(SOKOL_METAL)
2536 // see https://clang.llvm.org/docs/LanguageExtensions.html#automatic-reference-counting
2537 #if !defined(__cplusplus)
2538 #if __has_feature(objc_arc) && !__has_feature(objc_arc_fields)
2539 #error "sokol_gfx.h requires __has_feature(objc_arc_field) if ARC is enabled (use a more recent compiler version)"
2540 #endif
2541 #endif
2542 #include <TargetConditionals.h>
2543 #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
2544 #define _SG_TARGET_MACOS (1)
2545 #else
2546 #define _SG_TARGET_IOS (1)
2547 #if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
2548 #define _SG_TARGET_IOS_SIMULATOR (1)
2549 #endif
2550 #endif
2551 #import <Metal/Metal.h>
2552#elif defined(SOKOL_WGPU)
2553 #if defined(__EMSCRIPTEN__)
2554 #include <webgpu/webgpu.h>
2555 #else
2556 #include <dawn/webgpu.h>
2557 #endif
2558#elif defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3)
2559 #define _SOKOL_ANY_GL (1)
2560
2561 // include platform specific GL headers (or on Win32: use an embedded GL loader)
2562 #if !defined(SOKOL_EXTERNAL_GL_LOADER)
2563 #if defined(_WIN32)
2564 #if defined(SOKOL_GLCORE33) && !defined(SOKOL_EXTERNAL_GL_LOADER)
2565 #ifndef WIN32_LEAN_AND_MEAN
2566 #define WIN32_LEAN_AND_MEAN
2567 #endif
2568 #ifndef NOMINMAX
2569 #define NOMINMAX
2570 #endif
2571 #include <windows.h>
2572 #define _SOKOL_USE_WIN32_GL_LOADER (1)
2573 #pragma comment (lib, "kernel32") // GetProcAddress()
2574 #endif
2575 #elif defined(__APPLE__)
2576 #include <TargetConditionals.h>
2577 #ifndef GL_SILENCE_DEPRECATION
2578 #define GL_SILENCE_DEPRECATION
2579 #endif
2580 #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
2581 #include <OpenGL/gl3.h>
2582 #else
2583 #include <OpenGLES/ES3/gl.h>
2584 #include <OpenGLES/ES3/glext.h>
2585 #endif
2586 #elif defined(__EMSCRIPTEN__) || defined(__ANDROID__)
2587 #if defined(SOKOL_GLES3)
2588 #include <GLES3/gl3.h>
2589 #elif defined(SOKOL_GLES2)
2590 #ifndef GL_EXT_PROTOTYPES
2591 #define GL_GLEXT_PROTOTYPES
2592 #endif
2593 #include <GLES2/gl2.h>
2594 #include <GLES2/gl2ext.h>
2595 #endif
2596 #elif defined(__linux__) || defined(__unix__)
2597 #define GL_GLEXT_PROTOTYPES
2598 #include <GL/gl.h>
2599 #endif
2600 #endif
2601
2602 // optional GL loader definitions (only on Win32)
2603 #if defined(_SOKOL_USE_WIN32_GL_LOADER)
2604 #define __gl_h_ 1
2605 #define __gl32_h_ 1
2606 #define __gl31_h_ 1
2607 #define __GL_H__ 1
2608 #define __glext_h_ 1
2609 #define __GLEXT_H_ 1
2610 #define __gltypes_h_ 1
2611 #define __glcorearb_h_ 1
2612 #define __gl_glcorearb_h_ 1
2613 #define GL_APIENTRY APIENTRY
2614
2615 typedef unsigned int GLenum;
2616 typedef unsigned int GLuint;
2617 typedef int GLsizei;
2618 typedef char GLchar;
2619 typedef ptrdiff_t GLintptr;
2620 typedef ptrdiff_t GLsizeiptr;
2621 typedef double GLclampd;
2622 typedef unsigned short GLushort;
2623 typedef unsigned char GLubyte;
2624 typedef unsigned char GLboolean;
2625 typedef uint64_t GLuint64;
2626 typedef double GLdouble;
2627 typedef unsigned short GLhalf;
2628 typedef float GLclampf;
2629 typedef unsigned int GLbitfield;
2630 typedef signed char GLbyte;
2631 typedef short GLshort;
2632 typedef void GLvoid;
2633 typedef int64_t GLint64;
2634 typedef float GLfloat;
2635 typedef struct __GLsync * GLsync;
2636 typedef int GLint;
2637 #define GL_INT_2_10_10_10_REV 0x8D9F
2638 #define GL_R32F 0x822E
2639 #define GL_PROGRAM_POINT_SIZE 0x8642
2640 #define GL_STENCIL_ATTACHMENT 0x8D20
2641 #define GL_DEPTH_ATTACHMENT 0x8D00
2642 #define GL_COLOR_ATTACHMENT2 0x8CE2
2643 #define GL_COLOR_ATTACHMENT0 0x8CE0
2644 #define GL_R16F 0x822D
2645 #define GL_COLOR_ATTACHMENT22 0x8CF6
2646 #define GL_DRAW_FRAMEBUFFER 0x8CA9
2647 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5
2648 #define GL_NUM_EXTENSIONS 0x821D
2649 #define GL_INFO_LOG_LENGTH 0x8B84
2650 #define GL_VERTEX_SHADER 0x8B31
2651 #define GL_INCR 0x1E02
2652 #define GL_DYNAMIC_DRAW 0x88E8
2653 #define GL_STATIC_DRAW 0x88E4
2654 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
2655 #define GL_TEXTURE_CUBE_MAP 0x8513
2656 #define GL_FUNC_SUBTRACT 0x800A
2657 #define GL_FUNC_REVERSE_SUBTRACT 0x800B
2658 #define GL_CONSTANT_COLOR 0x8001
2659 #define GL_DECR_WRAP 0x8508
2660 #define GL_R8 0x8229
2661 #define GL_LINEAR_MIPMAP_LINEAR 0x2703
2662 #define GL_ELEMENT_ARRAY_BUFFER 0x8893
2663 #define GL_SHORT 0x1402
2664 #define GL_DEPTH_TEST 0x0B71
2665 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
2666 #define GL_LINK_STATUS 0x8B82
2667 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
2668 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
2669 #define GL_RGBA16F 0x881A
2670 #define GL_CONSTANT_ALPHA 0x8003
2671 #define GL_READ_FRAMEBUFFER 0x8CA8
2672 #define GL_TEXTURE0 0x84C0
2673 #define GL_TEXTURE_MIN_LOD 0x813A
2674 #define GL_CLAMP_TO_EDGE 0x812F
2675 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
2676 #define GL_TEXTURE_WRAP_R 0x8072
2677 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
2678 #define GL_NEAREST_MIPMAP_NEAREST 0x2700
2679 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
2680 #define GL_SRC_ALPHA_SATURATE 0x0308
2681 #define GL_STREAM_DRAW 0x88E0
2682 #define GL_ONE 1
2683 #define GL_NEAREST_MIPMAP_LINEAR 0x2702
2684 #define GL_RGB10_A2 0x8059
2685 #define GL_RGBA8 0x8058
2686 #define GL_COLOR_ATTACHMENT1 0x8CE1
2687 #define GL_RGBA4 0x8056
2688 #define GL_RGB8 0x8051
2689 #define GL_ARRAY_BUFFER 0x8892
2690 #define GL_STENCIL 0x1802
2691 #define GL_TEXTURE_2D 0x0DE1
2692 #define GL_DEPTH 0x1801
2693 #define GL_FRONT 0x0404
2694 #define GL_STENCIL_BUFFER_BIT 0x00000400
2695 #define GL_REPEAT 0x2901
2696 #define GL_RGBA 0x1908
2697 #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
2698 #define GL_DECR 0x1E03
2699 #define GL_FRAGMENT_SHADER 0x8B30
2700 #define GL_FLOAT 0x1406
2701 #define GL_TEXTURE_MAX_LOD 0x813B
2702 #define GL_DEPTH_COMPONENT 0x1902
2703 #define GL_ONE_MINUS_DST_ALPHA 0x0305
2704 #define GL_COLOR 0x1800
2705 #define GL_TEXTURE_2D_ARRAY 0x8C1A
2706 #define GL_TRIANGLES 0x0004
2707 #define GL_UNSIGNED_BYTE 0x1401
2708 #define GL_TEXTURE_MAG_FILTER 0x2800
2709 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
2710 #define GL_NONE 0
2711 #define GL_SRC_COLOR 0x0300
2712 #define GL_BYTE 0x1400
2713 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
2714 #define GL_LINE_STRIP 0x0003
2715 #define GL_TEXTURE_3D 0x806F
2716 #define GL_CW 0x0900
2717 #define GL_LINEAR 0x2601
2718 #define GL_RENDERBUFFER 0x8D41
2719 #define GL_GEQUAL 0x0206
2720 #define GL_COLOR_BUFFER_BIT 0x00004000
2721 #define GL_RGBA32F 0x8814
2722 #define GL_BLEND 0x0BE2
2723 #define GL_ONE_MINUS_SRC_ALPHA 0x0303
2724 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
2725 #define GL_TEXTURE_WRAP_T 0x2803
2726 #define GL_TEXTURE_WRAP_S 0x2802
2727 #define GL_TEXTURE_MIN_FILTER 0x2801
2728 #define GL_LINEAR_MIPMAP_NEAREST 0x2701
2729 #define GL_EXTENSIONS 0x1F03
2730 #define GL_NO_ERROR 0
2731 #define GL_REPLACE 0x1E01
2732 #define GL_KEEP 0x1E00
2733 #define GL_CCW 0x0901
2734 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
2735 #define GL_RGB 0x1907
2736 #define GL_TRIANGLE_STRIP 0x0005
2737 #define GL_FALSE 0
2738 #define GL_ZERO 0
2739 #define GL_CULL_FACE 0x0B44
2740 #define GL_INVERT 0x150A
2741 #define GL_INT 0x1404
2742 #define GL_UNSIGNED_INT 0x1405
2743 #define GL_UNSIGNED_SHORT 0x1403
2744 #define GL_NEAREST 0x2600
2745 #define GL_SCISSOR_TEST 0x0C11
2746 #define GL_LEQUAL 0x0203
2747 #define GL_STENCIL_TEST 0x0B90
2748 #define GL_DITHER 0x0BD0
2749 #define GL_DEPTH_COMPONENT16 0x81A5
2750 #define GL_EQUAL 0x0202
2751 #define GL_FRAMEBUFFER 0x8D40
2752 #define GL_RGB5 0x8050
2753 #define GL_LINES 0x0001
2754 #define GL_DEPTH_BUFFER_BIT 0x00000100
2755 #define GL_SRC_ALPHA 0x0302
2756 #define GL_INCR_WRAP 0x8507
2757 #define GL_LESS 0x0201
2758 #define GL_MULTISAMPLE 0x809D
2759 #define GL_FRAMEBUFFER_BINDING 0x8CA6
2760 #define GL_BACK 0x0405
2761 #define GL_ALWAYS 0x0207
2762 #define GL_FUNC_ADD 0x8006
2763 #define GL_ONE_MINUS_DST_COLOR 0x0307
2764 #define GL_NOTEQUAL 0x0205
2765 #define GL_DST_COLOR 0x0306
2766 #define GL_COMPILE_STATUS 0x8B81
2767 #define GL_RED 0x1903
2768 #define GL_COLOR_ATTACHMENT3 0x8CE3
2769 #define GL_DST_ALPHA 0x0304
2770 #define GL_RGB5_A1 0x8057
2771 #define GL_GREATER 0x0204
2772 #define GL_POLYGON_OFFSET_FILL 0x8037
2773 #define GL_TRUE 1
2774 #define GL_NEVER 0x0200
2775 #define GL_POINTS 0x0000
2776 #define GL_ONE_MINUS_SRC_COLOR 0x0301
2777 #define GL_MIRRORED_REPEAT 0x8370
2778 #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
2779 #define GL_R11F_G11F_B10F 0x8C3A
2780 #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
2781 #define GL_RGBA32UI 0x8D70
2782 #define GL_RGB32UI 0x8D71
2783 #define GL_RGBA16UI 0x8D76
2784 #define GL_RGB16UI 0x8D77
2785 #define GL_RGBA8UI 0x8D7C
2786 #define GL_RGB8UI 0x8D7D
2787 #define GL_RGBA32I 0x8D82
2788 #define GL_RGB32I 0x8D83
2789 #define GL_RGBA16I 0x8D88
2790 #define GL_RGB16I 0x8D89
2791 #define GL_RGBA8I 0x8D8E
2792 #define GL_RGB8I 0x8D8F
2793 #define GL_RED_INTEGER 0x8D94
2794 #define GL_RG 0x8227
2795 #define GL_RG_INTEGER 0x8228
2796 #define GL_R8 0x8229
2797 #define GL_R16 0x822A
2798 #define GL_RG8 0x822B
2799 #define GL_RG16 0x822C
2800 #define GL_R16F 0x822D
2801 #define GL_R32F 0x822E
2802 #define GL_RG16F 0x822F
2803 #define GL_RG32F 0x8230
2804 #define GL_R8I 0x8231
2805 #define GL_R8UI 0x8232
2806 #define GL_R16I 0x8233
2807 #define GL_R16UI 0x8234
2808 #define GL_R32I 0x8235
2809 #define GL_R32UI 0x8236
2810 #define GL_RG8I 0x8237
2811 #define GL_RG8UI 0x8238
2812 #define GL_RG16I 0x8239
2813 #define GL_RG16UI 0x823A
2814 #define GL_RG32I 0x823B
2815 #define GL_RG32UI 0x823C
2816 #define GL_RGBA_INTEGER 0x8D99
2817 #define GL_R8_SNORM 0x8F94
2818 #define GL_RG8_SNORM 0x8F95
2819 #define GL_RGB8_SNORM 0x8F96
2820 #define GL_RGBA8_SNORM 0x8F97
2821 #define GL_R16_SNORM 0x8F98
2822 #define GL_RG16_SNORM 0x8F99
2823 #define GL_RGB16_SNORM 0x8F9A
2824 #define GL_RGBA16_SNORM 0x8F9B
2825 #define GL_RGBA16 0x805B
2826 #define GL_MAX_TEXTURE_SIZE 0x0D33
2827 #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
2828 #define GL_MAX_3D_TEXTURE_SIZE 0x8073
2829 #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
2830 #define GL_MAX_VERTEX_ATTRIBS 0x8869
2831 #define GL_CLAMP_TO_BORDER 0x812D
2832 #define GL_TEXTURE_BORDER_COLOR 0x1004
2833 #define GL_CURRENT_PROGRAM 0x8B8D
2834 #endif
2835
2836 #ifndef GL_UNSIGNED_INT_2_10_10_10_REV
2837 #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
2838 #endif
2839 #ifndef GL_UNSIGNED_INT_24_8
2840 #define GL_UNSIGNED_INT_24_8 0x84FA
2841 #endif
2842 #ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
2843 #define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
2844 #endif
2845 #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
2846 #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
2847 #endif
2848 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
2849 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
2850 #endif
2851 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
2852 #define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
2853 #endif
2854 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
2855 #define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
2856 #endif
2857 #ifndef GL_COMPRESSED_RED_RGTC1
2858 #define GL_COMPRESSED_RED_RGTC1 0x8DBB
2859 #endif
2860 #ifndef GL_COMPRESSED_SIGNED_RED_RGTC1
2861 #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC
2862 #endif
2863 #ifndef GL_COMPRESSED_RED_GREEN_RGTC2
2864 #define GL_COMPRESSED_RED_GREEN_RGTC2 0x8DBD
2865 #endif
2866 #ifndef GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2
2867 #define GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2 0x8DBE
2868 #endif
2869 #ifndef GL_COMPRESSED_RGBA_BPTC_UNORM_ARB
2870 #define GL_COMPRESSED_RGBA_BPTC_UNORM_ARB 0x8E8C
2871 #endif
2872 #ifndef GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB
2873 #define GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB 0x8E8D
2874 #endif
2875 #ifndef GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB
2876 #define GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB 0x8E8E
2877 #endif
2878 #ifndef GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB
2879 #define GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB 0x8E8F
2880 #endif
2881 #ifndef GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
2882 #define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
2883 #endif
2884 #ifndef GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
2885 #define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
2886 #endif
2887 #ifndef GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
2888 #define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
2889 #endif
2890 #ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
2891 #define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
2892 #endif
2893 #ifndef GL_COMPRESSED_RGB8_ETC2
2894 #define GL_COMPRESSED_RGB8_ETC2 0x9274
2895 #endif
2896 #ifndef GL_COMPRESSED_RGBA8_ETC2_EAC
2897 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
2898 #endif
2899 #ifndef GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
2900 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
2901 #endif
2902 #ifndef GL_COMPRESSED_RG11_EAC
2903 #define GL_COMPRESSED_RG11_EAC 0x9272
2904 #endif
2905 #ifndef GL_COMPRESSED_SIGNED_RG11_EAC
2906 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
2907 #endif
2908 #ifndef GL_DEPTH24_STENCIL8
2909 #define GL_DEPTH24_STENCIL8 0x88F0
2910 #endif
2911 #ifndef GL_HALF_FLOAT
2912 #define GL_HALF_FLOAT 0x140B
2913 #endif
2914 #ifndef GL_DEPTH_STENCIL
2915 #define GL_DEPTH_STENCIL 0x84F9
2916 #endif
2917 #ifndef GL_LUMINANCE
2918 #define GL_LUMINANCE 0x1909
2919 #endif
2920
2921 #ifdef SOKOL_GLES2
2922 #ifdef GL_ANGLE_instanced_arrays
2923 #define _SOKOL_GL_INSTANCING_ENABLED
2924 #define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedANGLE(mode, first, count, instancecount)
2925 #define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedANGLE(mode, count, type, indices, instancecount)
2926 #define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorANGLE(index, divisor)
2927 #elif defined(GL_EXT_draw_instanced) && defined(GL_EXT_instanced_arrays)
2928 #define _SOKOL_GL_INSTANCING_ENABLED
2929 #define glDrawArraysInstanced(mode, first, count, instancecount) glDrawArraysInstancedEXT(mode, first, count, instancecount)
2930 #define glDrawElementsInstanced(mode, count, type, indices, instancecount) glDrawElementsInstancedEXT(mode, count, type, indices, instancecount)
2931 #define glVertexAttribDivisor(index, divisor) glVertexAttribDivisorEXT(index, divisor)
2932 #else
2933 #define _SOKOL_GLES2_INSTANCING_ERROR "Select GL_ANGLE_instanced_arrays or (GL_EXT_draw_instanced & GL_EXT_instanced_arrays) to enable instancing in GLES2"
2934 #define glDrawArraysInstanced(mode, first, count, instancecount) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR)
2935 #define glDrawElementsInstanced(mode, count, type, indices, instancecount) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR)
2936 #define glVertexAttribDivisor(index, divisor) SOKOL_ASSERT(0 && _SOKOL_GLES2_INSTANCING_ERROR)
2937 #endif
2938 #else
2939 #define _SOKOL_GL_INSTANCING_ENABLED
2940 #endif
2941 #define _SG_GL_CHECK_ERROR() { SOKOL_ASSERT(glGetError() == GL_NO_ERROR); }
2942#endif
2943
2944/*=== COMMON BACKEND STUFF ===================================================*/
2945
2946/* resource pool slots */
2947typedef struct {
2948 uint32_t id;
2949 uint32_t ctx_id;
2950 sg_resource_state state;
2951} _sg_slot_t;
2952
2953/* constants */
2954enum {
2955 _SG_STRING_SIZE = 16,
2956 _SG_SLOT_SHIFT = 16,
2957 _SG_SLOT_MASK = (1<<_SG_SLOT_SHIFT)-1,
2958 _SG_MAX_POOL_SIZE = (1<<_SG_SLOT_SHIFT),
2959 _SG_DEFAULT_BUFFER_POOL_SIZE = 128,
2960 _SG_DEFAULT_IMAGE_POOL_SIZE = 128,
2961 _SG_DEFAULT_SHADER_POOL_SIZE = 32,
2962 _SG_DEFAULT_PIPELINE_POOL_SIZE = 64,
2963 _SG_DEFAULT_PASS_POOL_SIZE = 16,
2964 _SG_DEFAULT_CONTEXT_POOL_SIZE = 16,
2965 _SG_DEFAULT_SAMPLER_CACHE_CAPACITY = 64,
2966 _SG_DEFAULT_UB_SIZE = 4 * 1024 * 1024,
2967 _SG_DEFAULT_STAGING_SIZE = 8 * 1024 * 1024,
2968};
2969
2970/* fixed-size string */
2971typedef struct {
2972 char buf[_SG_STRING_SIZE];
2973} _sg_str_t;
2974
2975/* helper macros */
2976#define _sg_def(val, def) (((val) == 0) ? (def) : (val))
2977#define _sg_def_flt(val, def) (((val) == 0.0f) ? (def) : (val))
2978#define _sg_min(a,b) ((a<b)?a:b)
2979#define _sg_max(a,b) ((a>b)?a:b)
2980#define _sg_clamp(v,v0,v1) ((v<v0)?(v0):((v>v1)?(v1):(v)))
2981#define _sg_fequal(val,cmp,delta) (((val-cmp)> -delta)&&((val-cmp)<delta))
2982
2983typedef struct {
2984 int size;
2985 int append_pos;
2986 bool append_overflow;
2987 sg_buffer_type type;
2988 sg_usage usage;
2989 uint32_t update_frame_index;
2990 uint32_t append_frame_index;
2991 int num_slots;
2992 int active_slot;
2993} _sg_buffer_common_t;
2994
2995_SOKOL_PRIVATE void _sg_buffer_common_init(_sg_buffer_common_t* cmn, const sg_buffer_desc* desc) {
2996 cmn->size = (int)desc->size;
2997 cmn->append_pos = 0;
2998 cmn->append_overflow = false;
2999 cmn->type = desc->type;
3000 cmn->usage = desc->usage;
3001 cmn->update_frame_index = 0;
3002 cmn->append_frame_index = 0;
3003 cmn->num_slots = (cmn->usage == SG_USAGE_IMMUTABLE) ? 1 : SG_NUM_INFLIGHT_FRAMES;
3004 cmn->active_slot = 0;
3005}
3006
3007typedef struct {
3008 sg_image_type type;
3009 bool render_target;
3010 int width;
3011 int height;
3012 int num_slices;
3013 int num_mipmaps;
3014 sg_usage usage;
3015 sg_pixel_format pixel_format;
3016 int sample_count;
3017 sg_filter min_filter;
3018 sg_filter mag_filter;
3019 sg_wrap wrap_u;
3020 sg_wrap wrap_v;
3021 sg_wrap wrap_w;
3022 sg_border_color border_color;
3023 uint32_t max_anisotropy;
3024 uint32_t upd_frame_index;
3025 int num_slots;
3026 int active_slot;
3027} _sg_image_common_t;
3028
3029_SOKOL_PRIVATE void _sg_image_common_init(_sg_image_common_t* cmn, const sg_image_desc* desc) {
3030 cmn->type = desc->type;
3031 cmn->render_target = desc->render_target;
3032 cmn->width = desc->width;
3033 cmn->height = desc->height;
3034 cmn->num_slices = desc->num_slices;
3035 cmn->num_mipmaps = desc->num_mipmaps;
3036 cmn->usage = desc->usage;
3037 cmn->pixel_format = desc->pixel_format;
3038 cmn->sample_count = desc->sample_count;
3039 cmn->min_filter = desc->min_filter;
3040 cmn->mag_filter = desc->mag_filter;
3041 cmn->wrap_u = desc->wrap_u;
3042 cmn->wrap_v = desc->wrap_v;
3043 cmn->wrap_w = desc->wrap_w;
3044 cmn->border_color = desc->border_color;
3045 cmn->max_anisotropy = desc->max_anisotropy;
3046 cmn->upd_frame_index = 0;
3047 cmn->num_slots = (cmn->usage == SG_USAGE_IMMUTABLE) ? 1 : SG_NUM_INFLIGHT_FRAMES;
3048 cmn->active_slot = 0;
3049}
3050
3051typedef struct {
3052 size_t size;
3053} _sg_uniform_block_t;
3054
3055typedef struct {
3056 sg_image_type image_type;
3057 sg_sampler_type sampler_type;
3058} _sg_shader_image_t;
3059
3060typedef struct {
3061 int num_uniform_blocks;
3062 int num_images;
3063 _sg_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS];
3064 _sg_shader_image_t images[SG_MAX_SHADERSTAGE_IMAGES];
3065} _sg_shader_stage_t;
3066
3067typedef struct {
3068 _sg_shader_stage_t stage[SG_NUM_SHADER_STAGES];
3069} _sg_shader_common_t;
3070
3071_SOKOL_PRIVATE void _sg_shader_common_init(_sg_shader_common_t* cmn, const sg_shader_desc* desc) {
3072 for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) {
3073 const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs;
3074 _sg_shader_stage_t* stage = &cmn->stage[stage_index];
3075 SOKOL_ASSERT(stage->num_uniform_blocks == 0);
3076 for (int ub_index = 0; ub_index < SG_MAX_SHADERSTAGE_UBS; ub_index++) {
3077 const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index];
3078 if (0 == ub_desc->size) {
3079 break;
3080 }
3081 stage->uniform_blocks[ub_index].size = ub_desc->size;
3082 stage->num_uniform_blocks++;
3083 }
3084 SOKOL_ASSERT(stage->num_images == 0);
3085 for (int img_index = 0; img_index < SG_MAX_SHADERSTAGE_IMAGES; img_index++) {
3086 const sg_shader_image_desc* img_desc = &stage_desc->images[img_index];
3087 if (img_desc->image_type == _SG_IMAGETYPE_DEFAULT) {
3088 break;
3089 }
3090 stage->images[img_index].image_type = img_desc->image_type;
3091 stage->images[img_index].sampler_type = img_desc->sampler_type;
3092 stage->num_images++;
3093 }
3094 }
3095}
3096
3097typedef struct {
3098 sg_shader shader_id;
3099 sg_index_type index_type;
3100 bool vertex_layout_valid[SG_MAX_SHADERSTAGE_BUFFERS];
3101 int color_attachment_count;
3102 sg_pixel_format color_formats[SG_MAX_COLOR_ATTACHMENTS];
3103 sg_pixel_format depth_format;
3104 int sample_count;
3105 float depth_bias;
3106 float depth_bias_slope_scale;
3107 float depth_bias_clamp;
3108 sg_color blend_color;
3109} _sg_pipeline_common_t;
3110
3111_SOKOL_PRIVATE void _sg_pipeline_common_init(_sg_pipeline_common_t* cmn, const sg_pipeline_desc* desc) {
3112 SOKOL_ASSERT(desc->color_count < SG_MAX_COLOR_ATTACHMENTS);
3113 cmn->shader_id = desc->shader;
3114 cmn->index_type = desc->index_type;
3115 for (int i = 0; i < SG_MAX_SHADERSTAGE_BUFFERS; i++) {
3116 cmn->vertex_layout_valid[i] = false;
3117 }
3118 cmn->color_attachment_count = desc->color_count;
3119 for (int i = 0; i < cmn->color_attachment_count; i++) {
3120 cmn->color_formats[i] = desc->colors[i].pixel_format;
3121 }
3122 cmn->depth_format = desc->depth.pixel_format;
3123 cmn->sample_count = desc->sample_count;
3124 cmn->depth_bias = desc->depth.bias;
3125 cmn->depth_bias_slope_scale = desc->depth.bias_slope_scale;
3126 cmn->depth_bias_clamp = desc->depth.bias_clamp;
3127 cmn->blend_color = desc->blend_color;
3128}
3129
3130typedef struct {
3131 sg_image image_id;
3132 int mip_level;
3133 int slice;
3134} _sg_pass_attachment_common_t;
3135
3136typedef struct {
3137 int num_color_atts;
3138 _sg_pass_attachment_common_t color_atts[SG_MAX_COLOR_ATTACHMENTS];
3139 _sg_pass_attachment_common_t ds_att;
3140} _sg_pass_common_t;
3141
3142_SOKOL_PRIVATE void _sg_pass_common_init(_sg_pass_common_t* cmn, const sg_pass_desc* desc) {
3143 const sg_pass_attachment_desc* att_desc;
3144 _sg_pass_attachment_common_t* att;
3145 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
3146 att_desc = &desc->color_attachments[i];
3147 if (att_desc->image.id != SG_INVALID_ID) {
3148 cmn->num_color_atts++;
3149 att = &cmn->color_atts[i];
3150 att->image_id = att_desc->image;
3151 att->mip_level = att_desc->mip_level;
3152 att->slice = att_desc->slice;
3153 }
3154 }
3155 att_desc = &desc->depth_stencil_attachment;
3156 if (att_desc->image.id != SG_INVALID_ID) {
3157 att = &cmn->ds_att;
3158 att->image_id = att_desc->image;
3159 att->mip_level = att_desc->mip_level;
3160 att->slice = att_desc->slice;
3161 }
3162}
3163
3164/*=== GENERIC SAMPLER CACHE ==================================================*/
3165
3166/*
3167 this is used by the Metal and WGPU backends to reduce the
3168 number of sampler state objects created through the backend API
3169*/
3170typedef struct {
3171 sg_filter min_filter;
3172 sg_filter mag_filter;
3173 sg_wrap wrap_u;
3174 sg_wrap wrap_v;
3175 sg_wrap wrap_w;
3176 sg_border_color border_color;
3177 uint32_t max_anisotropy;
3178 int min_lod; /* orig min/max_lod is float, this is int(min/max_lod*1000.0) */
3179 int max_lod;
3180 uintptr_t sampler_handle;
3181} _sg_sampler_cache_item_t;
3182
3183typedef struct {
3184 int capacity;
3185 int num_items;
3186 _sg_sampler_cache_item_t* items;
3187} _sg_sampler_cache_t;
3188
3189_SOKOL_PRIVATE void _sg_smpcache_init(_sg_sampler_cache_t* cache, int capacity) {
3190 SOKOL_ASSERT(cache && (capacity > 0));
3191 memset(cache, 0, sizeof(_sg_sampler_cache_t));
3192 cache->capacity = capacity;
3193 const size_t size = (size_t)cache->capacity * sizeof(_sg_sampler_cache_item_t);
3194 cache->items = (_sg_sampler_cache_item_t*) SOKOL_MALLOC(size);
3195 SOKOL_ASSERT(cache->items);
3196 memset(cache->items, 0, size);
3197}
3198
3199_SOKOL_PRIVATE void _sg_smpcache_discard(_sg_sampler_cache_t* cache) {
3200 SOKOL_ASSERT(cache && cache->items);
3201 SOKOL_FREE(cache->items);
3202 cache->items = 0;
3203 cache->num_items = 0;
3204 cache->capacity = 0;
3205}
3206
3207_SOKOL_PRIVATE int _sg_smpcache_minlod_int(float min_lod) {
3208 return (int) (min_lod * 1000.0f);
3209}
3210
3211_SOKOL_PRIVATE int _sg_smpcache_maxlod_int(float max_lod) {
3212 return (int) (_sg_clamp(max_lod, 0.0f, 1000.0f) * 1000.0f);
3213}
3214
3215_SOKOL_PRIVATE int _sg_smpcache_find_item(const _sg_sampler_cache_t* cache, const sg_image_desc* img_desc) {
3216 /* return matching sampler cache item index or -1 */
3217 SOKOL_ASSERT(cache && cache->items);
3218 SOKOL_ASSERT(img_desc);
3219 const int min_lod = _sg_smpcache_minlod_int(img_desc->min_lod);
3220 const int max_lod = _sg_smpcache_maxlod_int(img_desc->max_lod);
3221 for (int i = 0; i < cache->num_items; i++) {
3222 const _sg_sampler_cache_item_t* item = &cache->items[i];
3223 if ((img_desc->min_filter == item->min_filter) &&
3224 (img_desc->mag_filter == item->mag_filter) &&
3225 (img_desc->wrap_u == item->wrap_u) &&
3226 (img_desc->wrap_v == item->wrap_v) &&
3227 (img_desc->wrap_w == item->wrap_w) &&
3228 (img_desc->max_anisotropy == item->max_anisotropy) &&
3229 (img_desc->border_color == item->border_color) &&
3230 (min_lod == item->min_lod) &&
3231 (max_lod == item->max_lod))
3232 {
3233 return i;
3234 }
3235 }
3236 /* fallthrough: no matching cache item found */
3237 return -1;
3238}
3239
3240_SOKOL_PRIVATE void _sg_smpcache_add_item(_sg_sampler_cache_t* cache, const sg_image_desc* img_desc, uintptr_t sampler_handle) {
3241 SOKOL_ASSERT(cache && cache->items);
3242 SOKOL_ASSERT(img_desc);
3243 SOKOL_ASSERT(cache->num_items < cache->capacity);
3244 const int item_index = cache->num_items++;
3245 _sg_sampler_cache_item_t* item = &cache->items[item_index];
3246 item->min_filter = img_desc->min_filter;
3247 item->mag_filter = img_desc->mag_filter;
3248 item->wrap_u = img_desc->wrap_u;
3249 item->wrap_v = img_desc->wrap_v;
3250 item->wrap_w = img_desc->wrap_w;
3251 item->border_color = img_desc->border_color;
3252 item->max_anisotropy = img_desc->max_anisotropy;
3253 item->min_lod = _sg_smpcache_minlod_int(img_desc->min_lod);
3254 item->max_lod = _sg_smpcache_maxlod_int(img_desc->max_lod);
3255 item->sampler_handle = sampler_handle;
3256}
3257
3258_SOKOL_PRIVATE uintptr_t _sg_smpcache_sampler(_sg_sampler_cache_t* cache, int item_index) {
3259 SOKOL_ASSERT(cache && cache->items);
3260 SOKOL_ASSERT(item_index < cache->num_items);
3261 return cache->items[item_index].sampler_handle;
3262}
3263
3264/*=== DUMMY BACKEND DECLARATIONS =============================================*/
3265#if defined(SOKOL_DUMMY_BACKEND)
3266typedef struct {
3267 _sg_slot_t slot;
3268 _sg_buffer_common_t cmn;
3269} _sg_dummy_buffer_t;
3270typedef _sg_dummy_buffer_t _sg_buffer_t;
3271
3272typedef struct {
3273 _sg_slot_t slot;
3274 _sg_image_common_t cmn;
3275} _sg_dummy_image_t;
3276typedef _sg_dummy_image_t _sg_image_t;
3277
3278typedef struct {
3279 _sg_slot_t slot;
3280 _sg_shader_common_t cmn;
3281} _sg_dummy_shader_t;
3282typedef _sg_dummy_shader_t _sg_shader_t;
3283
3284typedef struct {
3285 _sg_slot_t slot;
3286 _sg_shader_t* shader;
3287 _sg_pipeline_common_t cmn;
3288} _sg_dummy_pipeline_t;
3289typedef _sg_dummy_pipeline_t _sg_pipeline_t;
3290
3291typedef struct {
3292 _sg_image_t* image;
3293} _sg_dummy_attachment_t;
3294
3295typedef struct {
3296 _sg_slot_t slot;
3297 _sg_pass_common_t cmn;
3298 struct {
3299 _sg_dummy_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS];
3300 _sg_dummy_attachment_t ds_att;
3301 } dmy;
3302} _sg_dummy_pass_t;
3303typedef _sg_dummy_pass_t _sg_pass_t;
3304typedef _sg_pass_attachment_common_t _sg_pass_attachment_t;
3305
3306typedef struct {
3307 _sg_slot_t slot;
3308} _sg_dummy_context_t;
3309typedef _sg_dummy_context_t _sg_context_t;
3310
3311/*== GL BACKEND DECLARATIONS =================================================*/
3312#elif defined(_SOKOL_ANY_GL)
3313typedef struct {
3314 _sg_slot_t slot;
3315 _sg_buffer_common_t cmn;
3316 struct {
3317 GLuint buf[SG_NUM_INFLIGHT_FRAMES];
3318 bool ext_buffers; /* if true, external buffers were injected with sg_buffer_desc.gl_buffers */
3319 } gl;
3320} _sg_gl_buffer_t;
3321typedef _sg_gl_buffer_t _sg_buffer_t;
3322
3323typedef struct {
3324 _sg_slot_t slot;
3325 _sg_image_common_t cmn;
3326 struct {
3327 GLenum target;
3328 GLuint depth_render_buffer;
3329 GLuint msaa_render_buffer;
3330 GLuint tex[SG_NUM_INFLIGHT_FRAMES];
3331 bool ext_textures; /* if true, external textures were injected with sg_image_desc.gl_textures */
3332 } gl;
3333} _sg_gl_image_t;
3334typedef _sg_gl_image_t _sg_image_t;
3335
3336typedef struct {
3337 GLint gl_loc;
3338 sg_uniform_type type;
3339 uint8_t count;
3340 uint16_t offset;
3341} _sg_gl_uniform_t;
3342
3343typedef struct {
3344 int num_uniforms;
3345 _sg_gl_uniform_t uniforms[SG_MAX_UB_MEMBERS];
3346} _sg_gl_uniform_block_t;
3347
3348typedef struct {
3349 int gl_tex_slot;
3350} _sg_gl_shader_image_t;
3351
3352typedef struct {
3353 _sg_str_t name;
3354} _sg_gl_shader_attr_t;
3355
3356typedef struct {
3357 _sg_gl_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS];
3358 _sg_gl_shader_image_t images[SG_MAX_SHADERSTAGE_IMAGES];
3359} _sg_gl_shader_stage_t;
3360
3361typedef struct {
3362 _sg_slot_t slot;
3363 _sg_shader_common_t cmn;
3364 struct {
3365 GLuint prog;
3366 _sg_gl_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES];
3367 _sg_gl_shader_stage_t stage[SG_NUM_SHADER_STAGES];
3368 } gl;
3369} _sg_gl_shader_t;
3370typedef _sg_gl_shader_t _sg_shader_t;
3371
3372typedef struct {
3373 int8_t vb_index; /* -1 if attr is not enabled */
3374 int8_t divisor; /* -1 if not initialized */
3375 uint8_t stride;
3376 uint8_t size;
3377 uint8_t normalized;
3378 int offset;
3379 GLenum type;
3380} _sg_gl_attr_t;
3381
3382typedef struct {
3383 _sg_slot_t slot;
3384 _sg_pipeline_common_t cmn;
3385 _sg_shader_t* shader;
3386 struct {
3387 _sg_gl_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES];
3388 sg_depth_state depth;
3389 sg_stencil_state stencil;
3390 sg_primitive_type primitive_type;
3391 sg_blend_state blend;
3392 sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS];
3393 sg_cull_mode cull_mode;
3394 sg_face_winding face_winding;
3395 int sample_count;
3396 bool alpha_to_coverage_enabled;
3397 } gl;
3398} _sg_gl_pipeline_t;
3399typedef _sg_gl_pipeline_t _sg_pipeline_t;
3400
3401typedef struct {
3402 _sg_image_t* image;
3403 GLuint gl_msaa_resolve_buffer;
3404} _sg_gl_attachment_t;
3405
3406typedef struct {
3407 _sg_slot_t slot;
3408 _sg_pass_common_t cmn;
3409 struct {
3410 GLuint fb;
3411 _sg_gl_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS];
3412 _sg_gl_attachment_t ds_att;
3413 } gl;
3414} _sg_gl_pass_t;
3415typedef _sg_gl_pass_t _sg_pass_t;
3416typedef _sg_pass_attachment_common_t _sg_pass_attachment_t;
3417
3418typedef struct {
3419 _sg_slot_t slot;
3420 #if !defined(SOKOL_GLES2)
3421 GLuint vao;
3422 #endif
3423 GLuint default_framebuffer;
3424} _sg_gl_context_t;
3425typedef _sg_gl_context_t _sg_context_t;
3426
3427typedef struct {
3428 _sg_gl_attr_t gl_attr;
3429 GLuint gl_vbuf;
3430} _sg_gl_cache_attr_t;
3431
3432typedef struct {
3433 GLenum target;
3434 GLuint texture;
3435} _sg_gl_texture_bind_slot;
3436
3437typedef struct {
3438 sg_depth_state depth;
3439 sg_stencil_state stencil;
3440 sg_blend_state blend;
3441 sg_color_mask color_write_mask[SG_MAX_COLOR_ATTACHMENTS];
3442 sg_cull_mode cull_mode;
3443 sg_face_winding face_winding;
3444 bool polygon_offset_enabled;
3445 int sample_count;
3446 sg_color blend_color;
3447 bool alpha_to_coverage_enabled;
3448 _sg_gl_cache_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES];
3449 GLuint vertex_buffer;
3450 GLuint index_buffer;
3451 GLuint stored_vertex_buffer;
3452 GLuint stored_index_buffer;
3453 GLuint prog;
3454 _sg_gl_texture_bind_slot textures[SG_MAX_SHADERSTAGE_IMAGES];
3455 _sg_gl_texture_bind_slot stored_texture;
3456 int cur_ib_offset;
3457 GLenum cur_primitive_type;
3458 GLenum cur_index_type;
3459 GLenum cur_active_texture;
3460 _sg_pipeline_t* cur_pipeline;
3461 sg_pipeline cur_pipeline_id;
3462} _sg_gl_state_cache_t;
3463
3464typedef struct {
3465 bool valid;
3466 bool gles2;
3467 bool in_pass;
3468 int cur_pass_width;
3469 int cur_pass_height;
3470 _sg_context_t* cur_context;
3471 _sg_pass_t* cur_pass;
3472 sg_pass cur_pass_id;
3473 _sg_gl_state_cache_t cache;
3474 bool ext_anisotropic;
3475 GLint max_anisotropy;
3476 GLint max_combined_texture_image_units;
3477 #if _SOKOL_USE_WIN32_GL_LOADER
3478 HINSTANCE opengl32_dll;
3479 #endif
3480} _sg_gl_backend_t;
3481
3482/*== D3D11 BACKEND DECLARATIONS ==============================================*/
3483#elif defined(SOKOL_D3D11)
3484
3485typedef struct {
3486 _sg_slot_t slot;
3487 _sg_buffer_common_t cmn;
3488 struct {
3489 ID3D11Buffer* buf;
3490 } d3d11;
3491} _sg_d3d11_buffer_t;
3492typedef _sg_d3d11_buffer_t _sg_buffer_t;
3493
3494typedef struct {
3495 _sg_slot_t slot;
3496 _sg_image_common_t cmn;
3497 struct {
3498 DXGI_FORMAT format;
3499 ID3D11Texture2D* tex2d;
3500 ID3D11Texture3D* tex3d;
3501 ID3D11Texture2D* texds;
3502 ID3D11Texture2D* texmsaa;
3503 ID3D11ShaderResourceView* srv;
3504 ID3D11SamplerState* smp;
3505 } d3d11;
3506} _sg_d3d11_image_t;
3507typedef _sg_d3d11_image_t _sg_image_t;
3508
3509typedef struct {
3510 _sg_str_t sem_name;
3511 int sem_index;
3512} _sg_d3d11_shader_attr_t;
3513
3514typedef struct {
3515 ID3D11Buffer* cbufs[SG_MAX_SHADERSTAGE_UBS];
3516} _sg_d3d11_shader_stage_t;
3517
3518typedef struct {
3519 _sg_slot_t slot;
3520 _sg_shader_common_t cmn;
3521 struct {
3522 _sg_d3d11_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES];
3523 _sg_d3d11_shader_stage_t stage[SG_NUM_SHADER_STAGES];
3524 ID3D11VertexShader* vs;
3525 ID3D11PixelShader* fs;
3526 void* vs_blob;
3527 size_t vs_blob_length;
3528 } d3d11;
3529} _sg_d3d11_shader_t;
3530typedef _sg_d3d11_shader_t _sg_shader_t;
3531
3532typedef struct {
3533 _sg_slot_t slot;
3534 _sg_pipeline_common_t cmn;
3535 _sg_shader_t* shader;
3536 struct {
3537 UINT stencil_ref;
3538 UINT vb_strides[SG_MAX_SHADERSTAGE_BUFFERS];
3539 D3D_PRIMITIVE_TOPOLOGY topology;
3540 DXGI_FORMAT index_format;
3541 ID3D11InputLayout* il;
3542 ID3D11RasterizerState* rs;
3543 ID3D11DepthStencilState* dss;
3544 ID3D11BlendState* bs;
3545 } d3d11;
3546} _sg_d3d11_pipeline_t;
3547typedef _sg_d3d11_pipeline_t _sg_pipeline_t;
3548
3549typedef struct {
3550 _sg_image_t* image;
3551 ID3D11RenderTargetView* rtv;
3552} _sg_d3d11_color_attachment_t;
3553
3554typedef struct {
3555 _sg_image_t* image;
3556 ID3D11DepthStencilView* dsv;
3557} _sg_d3d11_ds_attachment_t;
3558
3559typedef struct {
3560 _sg_slot_t slot;
3561 _sg_pass_common_t cmn;
3562 struct {
3563 _sg_d3d11_color_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS];
3564 _sg_d3d11_ds_attachment_t ds_att;
3565 } d3d11;
3566} _sg_d3d11_pass_t;
3567typedef _sg_d3d11_pass_t _sg_pass_t;
3568typedef _sg_pass_attachment_common_t _sg_pass_attachment_t;
3569
3570typedef struct {
3571 _sg_slot_t slot;
3572} _sg_d3d11_context_t;
3573typedef _sg_d3d11_context_t _sg_context_t;
3574
3575typedef struct {
3576 bool valid;
3577 ID3D11Device* dev;
3578 ID3D11DeviceContext* ctx;
3579 const void* (*rtv_cb)(void);
3580 const void* (*rtv_userdata_cb)(void*);
3581 const void* (*dsv_cb)(void);
3582 const void* (*dsv_userdata_cb)(void*);
3583 void* user_data;
3584 bool in_pass;
3585 bool use_indexed_draw;
3586 int cur_width;
3587 int cur_height;
3588 int num_rtvs;
3589 _sg_pass_t* cur_pass;
3590 sg_pass cur_pass_id;
3591 _sg_pipeline_t* cur_pipeline;
3592 sg_pipeline cur_pipeline_id;
3593 ID3D11RenderTargetView* cur_rtvs[SG_MAX_COLOR_ATTACHMENTS];
3594 ID3D11DepthStencilView* cur_dsv;
3595 /* on-demand loaded d3dcompiler_47.dll handles */
3596 HINSTANCE d3dcompiler_dll;
3597 bool d3dcompiler_dll_load_failed;
3598 pD3DCompile D3DCompile_func;
3599 /* the following arrays are used for unbinding resources, they will always contain zeroes */
3600 ID3D11RenderTargetView* zero_rtvs[SG_MAX_COLOR_ATTACHMENTS];
3601 ID3D11Buffer* zero_vbs[SG_MAX_SHADERSTAGE_BUFFERS];
3602 UINT zero_vb_offsets[SG_MAX_SHADERSTAGE_BUFFERS];
3603 UINT zero_vb_strides[SG_MAX_SHADERSTAGE_BUFFERS];
3604 ID3D11Buffer* zero_cbs[SG_MAX_SHADERSTAGE_UBS];
3605 ID3D11ShaderResourceView* zero_srvs[SG_MAX_SHADERSTAGE_IMAGES];
3606 ID3D11SamplerState* zero_smps[SG_MAX_SHADERSTAGE_IMAGES];
3607 /* global subresourcedata array for texture updates */
3608 D3D11_SUBRESOURCE_DATA subres_data[SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS];
3609} _sg_d3d11_backend_t;
3610
3611/*=== METAL BACKEND DECLARATIONS =============================================*/
3612#elif defined(SOKOL_METAL)
3613
3614#if defined(_SG_TARGET_MACOS) || defined(_SG_TARGET_IOS_SIMULATOR)
3615#define _SG_MTL_UB_ALIGN (256)
3616#else
3617#define _SG_MTL_UB_ALIGN (16)
3618#endif
3619#define _SG_MTL_INVALID_SLOT_INDEX (0)
3620
3621typedef struct {
3622 uint32_t frame_index; /* frame index at which it is safe to release this resource */
3623 int slot_index;
3624} _sg_mtl_release_item_t;
3625
3626typedef struct {
3627 NSMutableArray* pool;
3628 int num_slots;
3629 int free_queue_top;
3630 int* free_queue;
3631 int release_queue_front;
3632 int release_queue_back;
3633 _sg_mtl_release_item_t* release_queue;
3634} _sg_mtl_idpool_t;
3635
3636typedef struct {
3637 _sg_slot_t slot;
3638 _sg_buffer_common_t cmn;
3639 struct {
3640 int buf[SG_NUM_INFLIGHT_FRAMES]; /* index into _sg_mtl_pool */
3641 } mtl;
3642} _sg_mtl_buffer_t;
3643typedef _sg_mtl_buffer_t _sg_buffer_t;
3644
3645typedef struct {
3646 _sg_slot_t slot;
3647 _sg_image_common_t cmn;
3648 struct {
3649 int tex[SG_NUM_INFLIGHT_FRAMES];
3650 int depth_tex;
3651 int msaa_tex;
3652 int sampler_state;
3653 } mtl;
3654} _sg_mtl_image_t;
3655typedef _sg_mtl_image_t _sg_image_t;
3656
3657typedef struct {
3658 int mtl_lib;
3659 int mtl_func;
3660} _sg_mtl_shader_stage_t;
3661
3662typedef struct {
3663 _sg_slot_t slot;
3664 _sg_shader_common_t cmn;
3665 struct {
3666 _sg_mtl_shader_stage_t stage[SG_NUM_SHADER_STAGES];
3667 } mtl;
3668} _sg_mtl_shader_t;
3669typedef _sg_mtl_shader_t _sg_shader_t;
3670
3671typedef struct {
3672 _sg_slot_t slot;
3673 _sg_pipeline_common_t cmn;
3674 _sg_shader_t* shader;
3675 struct {
3676 MTLPrimitiveType prim_type;
3677 int index_size;
3678 MTLIndexType index_type;
3679 MTLCullMode cull_mode;
3680 MTLWinding winding;
3681 uint32_t stencil_ref;
3682 int rps;
3683 int dss;
3684 } mtl;
3685} _sg_mtl_pipeline_t;
3686typedef _sg_mtl_pipeline_t _sg_pipeline_t;
3687
3688typedef struct {
3689 _sg_image_t* image;
3690} _sg_mtl_attachment_t;
3691
3692typedef struct {
3693 _sg_slot_t slot;
3694 _sg_pass_common_t cmn;
3695 struct {
3696 _sg_mtl_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS];
3697 _sg_mtl_attachment_t ds_att;
3698 } mtl;
3699} _sg_mtl_pass_t;
3700typedef _sg_mtl_pass_t _sg_pass_t;
3701typedef _sg_pass_attachment_common_t _sg_pass_attachment_t;
3702
3703typedef struct {
3704 _sg_slot_t slot;
3705} _sg_mtl_context_t;
3706typedef _sg_mtl_context_t _sg_context_t;
3707
3708/* resouce binding state cache */
3709typedef struct {
3710 const _sg_pipeline_t* cur_pipeline;
3711 sg_pipeline cur_pipeline_id;
3712 const _sg_buffer_t* cur_indexbuffer;
3713 int cur_indexbuffer_offset;
3714 sg_buffer cur_indexbuffer_id;
3715 const _sg_buffer_t* cur_vertexbuffers[SG_MAX_SHADERSTAGE_BUFFERS];
3716 int cur_vertexbuffer_offsets[SG_MAX_SHADERSTAGE_BUFFERS];
3717 sg_buffer cur_vertexbuffer_ids[SG_MAX_SHADERSTAGE_BUFFERS];
3718 const _sg_image_t* cur_vs_images[SG_MAX_SHADERSTAGE_IMAGES];
3719 sg_image cur_vs_image_ids[SG_MAX_SHADERSTAGE_IMAGES];
3720 const _sg_image_t* cur_fs_images[SG_MAX_SHADERSTAGE_IMAGES];
3721 sg_image cur_fs_image_ids[SG_MAX_SHADERSTAGE_IMAGES];
3722} _sg_mtl_state_cache_t;
3723
3724typedef struct {
3725 bool valid;
3726 const void*(*renderpass_descriptor_cb)(void);
3727 const void*(*renderpass_descriptor_userdata_cb)(void*);
3728 const void*(*drawable_cb)(void);
3729 const void*(*drawable_userdata_cb)(void*);
3730 void* user_data;
3731 uint32_t frame_index;
3732 uint32_t cur_frame_rotate_index;
3733 int ub_size;
3734 int cur_ub_offset;
3735 uint8_t* cur_ub_base_ptr;
3736 bool in_pass;
3737 bool pass_valid;
3738 int cur_width;
3739 int cur_height;
3740 _sg_mtl_state_cache_t state_cache;
3741 _sg_sampler_cache_t sampler_cache;
3742 _sg_mtl_idpool_t idpool;
3743 dispatch_semaphore_t sem;
3744 id<MTLDevice> device;
3745 id<MTLCommandQueue> cmd_queue;
3746 id<MTLCommandBuffer> cmd_buffer;
3747 id<MTLRenderCommandEncoder> cmd_encoder;
3748 id<MTLBuffer> uniform_buffers[SG_NUM_INFLIGHT_FRAMES];
3749} _sg_mtl_backend_t;
3750
3751/*=== WGPU BACKEND DECLARATIONS ==============================================*/
3752#elif defined(SOKOL_WGPU)
3753
3754#define _SG_WGPU_STAGING_ALIGN (256)
3755#define _SG_WGPU_STAGING_PIPELINE_SIZE (8)
3756#define _SG_WGPU_ROWPITCH_ALIGN (256)
3757#define _SG_WGPU_MAX_SHADERSTAGE_IMAGES (8)
3758#define _SG_WGPU_MAX_UNIFORM_UPDATE_SIZE (1<<16)
3759
3760typedef struct {
3761 _sg_slot_t slot;
3762 _sg_buffer_common_t cmn;
3763 struct {
3764 WGPUBuffer buf;
3765 } wgpu;
3766} _sg_wgpu_buffer_t;
3767typedef _sg_wgpu_buffer_t _sg_buffer_t;
3768
3769typedef struct {
3770 _sg_slot_t slot;
3771 _sg_image_common_t cmn;
3772 struct {
3773 WGPUTexture tex;
3774 WGPUTextureView tex_view;
3775 WGPUTexture msaa_tex;
3776 WGPUSampler sampler;
3777 } wgpu;
3778} _sg_wgpu_image_t;
3779typedef _sg_wgpu_image_t _sg_image_t;
3780
3781typedef struct {
3782 WGPUShaderModule module;
3783 WGPUBindGroupLayout bind_group_layout;
3784 _sg_str_t entry;
3785} _sg_wgpu_shader_stage_t;
3786
3787typedef struct {
3788 _sg_slot_t slot;
3789 _sg_shader_common_t cmn;
3790 struct {
3791 _sg_wgpu_shader_stage_t stage[SG_NUM_SHADER_STAGES];
3792 } wgpu;
3793} _sg_wgpu_shader_t;
3794typedef _sg_wgpu_shader_t _sg_shader_t;
3795
3796typedef struct {
3797 _sg_slot_t slot;
3798 _sg_pipeline_common_t cmn;
3799 _sg_shader_t* shader;
3800 struct {
3801 WGPURenderPipeline pip;
3802 uint32_t stencil_ref;
3803 } wgpu;
3804} _sg_wgpu_pipeline_t;
3805typedef _sg_wgpu_pipeline_t _sg_pipeline_t;
3806
3807typedef struct {
3808 _sg_image_t* image;
3809 WGPUTextureView render_tex_view;
3810 WGPUTextureView resolve_tex_view;
3811} _sg_wgpu_attachment_t;
3812
3813typedef struct {
3814 _sg_slot_t slot;
3815 _sg_pass_common_t cmn;
3816 struct {
3817 _sg_wgpu_attachment_t color_atts[SG_MAX_COLOR_ATTACHMENTS];
3818 _sg_wgpu_attachment_t ds_att;
3819 } wgpu;
3820} _sg_wgpu_pass_t;
3821typedef _sg_wgpu_pass_t _sg_pass_t;
3822typedef _sg_pass_attachment_common_t _sg_pass_attachment_t;
3823
3824typedef struct {
3825 _sg_slot_t slot;
3826} _sg_wgpu_context_t;
3827typedef _sg_wgpu_context_t _sg_context_t;
3828
3829/* a pool of per-frame uniform buffers */
3830typedef struct {
3831 WGPUBindGroupLayout bindgroup_layout;
3832 uint32_t num_bytes;
3833 uint32_t offset; /* current offset into current frame's mapped uniform buffer */
3834 uint32_t bind_offsets[SG_NUM_SHADER_STAGES][SG_MAX_SHADERSTAGE_UBS];
3835 WGPUBuffer buf; /* the GPU-side uniform buffer */
3836 WGPUBindGroup bindgroup;
3837 struct {
3838 int num;
3839 int cur;
3840 WGPUBuffer buf[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* CPU-side staging buffers */
3841 uint8_t* ptr[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* if != 0, staging buffer currently mapped */
3842 } stage;
3843} _sg_wgpu_ubpool_t;
3844
3845/* ...a similar pool (like uniform buffer pool) of dynamic-resource staging buffers */
3846typedef struct {
3847 uint32_t num_bytes;
3848 uint32_t offset; /* current offset into current frame's staging buffer */
3849 int num; /* number of staging buffers */
3850 int cur; /* this frame's staging buffer */
3851 WGPUBuffer buf[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* CPU-side staging buffers */
3852 uint8_t* ptr[_SG_WGPU_STAGING_PIPELINE_SIZE]; /* if != 0, staging buffer currently mapped */
3853} _sg_wgpu_stagingpool_t;
3854
3855/* the WGPU backend state */
3856typedef struct {
3857 bool valid;
3858 bool in_pass;
3859 bool draw_indexed;
3860 int cur_width;
3861 int cur_height;
3862 WGPUDevice dev;
3863 WGPUTextureView (*render_view_cb)(void);
3864 WGPUTextureView (*render_view_userdata_cb)(void*);
3865 WGPUTextureView (*resolve_view_cb)(void);
3866 WGPUTextureView (*resolve_view_userdata_cb)(void*);
3867 WGPUTextureView (*depth_stencil_view_cb)(void);
3868 WGPUTextureView (*depth_stencil_view_userdata_cb)(void*);
3869 void* user_data;
3870 WGPUQueue queue;
3871 WGPUCommandEncoder render_cmd_enc;
3872 WGPUCommandEncoder staging_cmd_enc;
3873 WGPURenderPassEncoder pass_enc;
3874 WGPUBindGroup empty_bind_group;
3875 const _sg_pipeline_t* cur_pipeline;
3876 sg_pipeline cur_pipeline_id;
3877 _sg_sampler_cache_t sampler_cache;
3878 _sg_wgpu_ubpool_t ub;
3879 _sg_wgpu_stagingpool_t staging;
3880} _sg_wgpu_backend_t;
3881#endif
3882
3883/*=== RESOURCE POOL DECLARATIONS =============================================*/
3884
3885/* this *MUST* remain 0 */
3886#define _SG_INVALID_SLOT_INDEX (0)
3887
3888typedef struct {
3889 int size;
3890 int queue_top;
3891 uint32_t* gen_ctrs;
3892 int* free_queue;
3893} _sg_pool_t;
3894
3895typedef struct {
3896 _sg_pool_t buffer_pool;
3897 _sg_pool_t image_pool;
3898 _sg_pool_t shader_pool;
3899 _sg_pool_t pipeline_pool;
3900 _sg_pool_t pass_pool;
3901 _sg_pool_t context_pool;
3902 _sg_buffer_t* buffers;
3903 _sg_image_t* images;
3904 _sg_shader_t* shaders;
3905 _sg_pipeline_t* pipelines;
3906 _sg_pass_t* passes;
3907 _sg_context_t* contexts;
3908} _sg_pools_t;
3909
3910/*=== VALIDATION LAYER DECLARATIONS ==========================================*/
3911typedef enum {
3912 /* special case 'validation was successful' */
3913 _SG_VALIDATE_SUCCESS,
3914
3915 /* buffer creation */
3916 _SG_VALIDATE_BUFFERDESC_CANARY,
3917 _SG_VALIDATE_BUFFERDESC_SIZE,
3918 _SG_VALIDATE_BUFFERDESC_DATA,
3919 _SG_VALIDATE_BUFFERDESC_DATA_SIZE,
3920 _SG_VALIDATE_BUFFERDESC_NO_DATA,
3921
3922 /* image creation */
3923 _SG_VALIDATE_IMAGEDESC_CANARY,
3924 _SG_VALIDATE_IMAGEDESC_WIDTH,
3925 _SG_VALIDATE_IMAGEDESC_HEIGHT,
3926 _SG_VALIDATE_IMAGEDESC_RT_PIXELFORMAT,
3927 _SG_VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT,
3928 _SG_VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT,
3929 _SG_VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT,
3930 _SG_VALIDATE_IMAGEDESC_RT_IMMUTABLE,
3931 _SG_VALIDATE_IMAGEDESC_RT_NO_DATA,
3932 _SG_VALIDATE_IMAGEDESC_DATA,
3933 _SG_VALIDATE_IMAGEDESC_NO_DATA,
3934
3935 /* shader creation */
3936 _SG_VALIDATE_SHADERDESC_CANARY,
3937 _SG_VALIDATE_SHADERDESC_SOURCE,
3938 _SG_VALIDATE_SHADERDESC_BYTECODE,
3939 _SG_VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE,
3940 _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE,
3941 _SG_VALIDATE_SHADERDESC_NO_CONT_UBS,
3942 _SG_VALIDATE_SHADERDESC_NO_CONT_IMGS,
3943 _SG_VALIDATE_SHADERDESC_NO_CONT_UB_MEMBERS,
3944 _SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS,
3945 _SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME,
3946 _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH,
3947 _SG_VALIDATE_SHADERDESC_IMG_NAME,
3948 _SG_VALIDATE_SHADERDESC_ATTR_NAMES,
3949 _SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS,
3950 _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG,
3951
3952 /* pipeline creation */
3953 _SG_VALIDATE_PIPELINEDESC_CANARY,
3954 _SG_VALIDATE_PIPELINEDESC_SHADER,
3955 _SG_VALIDATE_PIPELINEDESC_NO_ATTRS,
3956 _SG_VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4,
3957 _SG_VALIDATE_PIPELINEDESC_ATTR_NAME,
3958 _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS,
3959
3960 /* pass creation */
3961 _SG_VALIDATE_PASSDESC_CANARY,
3962 _SG_VALIDATE_PASSDESC_NO_COLOR_ATTS,
3963 _SG_VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS,
3964 _SG_VALIDATE_PASSDESC_IMAGE,
3965 _SG_VALIDATE_PASSDESC_MIPLEVEL,
3966 _SG_VALIDATE_PASSDESC_FACE,
3967 _SG_VALIDATE_PASSDESC_LAYER,
3968 _SG_VALIDATE_PASSDESC_SLICE,
3969 _SG_VALIDATE_PASSDESC_IMAGE_NO_RT,
3970 _SG_VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT,
3971 _SG_VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT,
3972 _SG_VALIDATE_PASSDESC_IMAGE_SIZES,
3973 _SG_VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS,
3974
3975 /* sg_begin_pass validation */
3976 _SG_VALIDATE_BEGINPASS_PASS,
3977 _SG_VALIDATE_BEGINPASS_IMAGE,
3978
3979 /* sg_apply_pipeline validation */
3980 _SG_VALIDATE_APIP_PIPELINE_VALID_ID,
3981 _SG_VALIDATE_APIP_PIPELINE_EXISTS,
3982 _SG_VALIDATE_APIP_PIPELINE_VALID,
3983 _SG_VALIDATE_APIP_SHADER_EXISTS,
3984 _SG_VALIDATE_APIP_SHADER_VALID,
3985 _SG_VALIDATE_APIP_ATT_COUNT,
3986 _SG_VALIDATE_APIP_COLOR_FORMAT,
3987 _SG_VALIDATE_APIP_DEPTH_FORMAT,
3988 _SG_VALIDATE_APIP_SAMPLE_COUNT,
3989
3990 /* sg_apply_bindings validation */
3991 _SG_VALIDATE_ABND_PIPELINE,
3992 _SG_VALIDATE_ABND_PIPELINE_EXISTS,
3993 _SG_VALIDATE_ABND_PIPELINE_VALID,
3994 _SG_VALIDATE_ABND_VBS,
3995 _SG_VALIDATE_ABND_VB_EXISTS,
3996 _SG_VALIDATE_ABND_VB_TYPE,
3997 _SG_VALIDATE_ABND_VB_OVERFLOW,
3998 _SG_VALIDATE_ABND_NO_IB,
3999 _SG_VALIDATE_ABND_IB,
4000 _SG_VALIDATE_ABND_IB_EXISTS,
4001 _SG_VALIDATE_ABND_IB_TYPE,
4002 _SG_VALIDATE_ABND_IB_OVERFLOW,
4003 _SG_VALIDATE_ABND_VS_IMGS,
4004 _SG_VALIDATE_ABND_VS_IMG_EXISTS,
4005 _SG_VALIDATE_ABND_VS_IMG_TYPES,
4006 _SG_VALIDATE_ABND_FS_IMGS,
4007 _SG_VALIDATE_ABND_FS_IMG_EXISTS,
4008 _SG_VALIDATE_ABND_FS_IMG_TYPES,
4009
4010 /* sg_apply_uniforms validation */
4011 _SG_VALIDATE_AUB_NO_PIPELINE,
4012 _SG_VALIDATE_AUB_NO_UB_AT_SLOT,
4013 _SG_VALIDATE_AUB_SIZE,
4014
4015 /* sg_update_buffer validation */
4016 _SG_VALIDATE_UPDATEBUF_USAGE,
4017 _SG_VALIDATE_UPDATEBUF_SIZE,
4018 _SG_VALIDATE_UPDATEBUF_ONCE,
4019 _SG_VALIDATE_UPDATEBUF_APPEND,
4020
4021 /* sg_append_buffer validation */
4022 _SG_VALIDATE_APPENDBUF_USAGE,
4023 _SG_VALIDATE_APPENDBUF_SIZE,
4024 _SG_VALIDATE_APPENDBUF_UPDATE,
4025
4026 /* sg_update_image validation */
4027 _SG_VALIDATE_UPDIMG_USAGE,
4028 _SG_VALIDATE_UPDIMG_NOTENOUGHDATA,
4029 _SG_VALIDATE_UPDIMG_SIZE,
4030 _SG_VALIDATE_UPDIMG_COMPRESSED,
4031 _SG_VALIDATE_UPDIMG_ONCE
4032} _sg_validate_error_t;
4033
4034/*=== GENERIC BACKEND STATE ==================================================*/
4035
4036typedef struct {
4037 bool valid;
4038 sg_desc desc; /* original desc with default values patched in */
4039 uint32_t frame_index;
4040 sg_context active_context;
4041 sg_pass cur_pass;
4042 sg_pipeline cur_pipeline;
4043 bool pass_valid;
4044 bool bindings_valid;
4045 bool next_draw_valid;
4046 #if defined(SOKOL_DEBUG)
4047 _sg_validate_error_t validate_error;
4048 #endif
4049 _sg_pools_t pools;
4050 sg_backend backend;
4051 sg_features features;
4052 sg_limits limits;
4053 sg_pixelformat_info formats[_SG_PIXELFORMAT_NUM];
4054 #if defined(_SOKOL_ANY_GL)
4055 _sg_gl_backend_t gl;
4056 #elif defined(SOKOL_METAL)
4057 _sg_mtl_backend_t mtl;
4058 #elif defined(SOKOL_D3D11)
4059 _sg_d3d11_backend_t d3d11;
4060 #elif defined(SOKOL_WGPU)
4061 _sg_wgpu_backend_t wgpu;
4062 #endif
4063 #if defined(SOKOL_TRACE_HOOKS)
4064 sg_trace_hooks hooks;
4065 #endif
4066} _sg_state_t;
4067static _sg_state_t _sg;
4068
4069/*-- helper functions --------------------------------------------------------*/
4070
4071_SOKOL_PRIVATE bool _sg_strempty(const _sg_str_t* str) {
4072 return 0 == str->buf[0];
4073}
4074
4075_SOKOL_PRIVATE const char* _sg_strptr(const _sg_str_t* str) {
4076 return &str->buf[0];
4077}
4078
4079_SOKOL_PRIVATE void _sg_strcpy(_sg_str_t* dst, const char* src) {
4080 SOKOL_ASSERT(dst);
4081 if (src) {
4082 #if defined(_MSC_VER)
4083 strncpy_s(dst->buf, _SG_STRING_SIZE, src, (_SG_STRING_SIZE-1));
4084 #else
4085 strncpy(dst->buf, src, _SG_STRING_SIZE);
4086 #endif
4087 dst->buf[_SG_STRING_SIZE-1] = 0;
4088 }
4089 else {
4090 memset(dst->buf, 0, _SG_STRING_SIZE);
4091 }
4092}
4093
4094/* return byte size of a vertex format */
4095_SOKOL_PRIVATE int _sg_vertexformat_bytesize(sg_vertex_format fmt) {
4096 switch (fmt) {
4097 case SG_VERTEXFORMAT_FLOAT: return 4;
4098 case SG_VERTEXFORMAT_FLOAT2: return 8;
4099 case SG_VERTEXFORMAT_FLOAT3: return 12;
4100 case SG_VERTEXFORMAT_FLOAT4: return 16;
4101 case SG_VERTEXFORMAT_BYTE4: return 4;
4102 case SG_VERTEXFORMAT_BYTE4N: return 4;
4103 case SG_VERTEXFORMAT_UBYTE4: return 4;
4104 case SG_VERTEXFORMAT_UBYTE4N: return 4;
4105 case SG_VERTEXFORMAT_SHORT2: return 4;
4106 case SG_VERTEXFORMAT_SHORT2N: return 4;
4107 case SG_VERTEXFORMAT_USHORT2N: return 4;
4108 case SG_VERTEXFORMAT_SHORT4: return 8;
4109 case SG_VERTEXFORMAT_SHORT4N: return 8;
4110 case SG_VERTEXFORMAT_USHORT4N: return 8;
4111 case SG_VERTEXFORMAT_UINT10_N2: return 4;
4112 case SG_VERTEXFORMAT_INVALID: return 0;
4113 default:
4114 SOKOL_UNREACHABLE;
4115 return -1;
4116 }
4117}
4118
4119/* return the byte size of a shader uniform */
4120_SOKOL_PRIVATE int _sg_uniform_size(sg_uniform_type type, int count) {
4121 switch (type) {
4122 case SG_UNIFORMTYPE_INVALID: return 0;
4123 case SG_UNIFORMTYPE_FLOAT: return 4 * count;
4124 case SG_UNIFORMTYPE_FLOAT2: return 8 * count;
4125 case SG_UNIFORMTYPE_FLOAT3: return 12 * count; /* FIXME: std140??? */
4126 case SG_UNIFORMTYPE_FLOAT4: return 16 * count;
4127 case SG_UNIFORMTYPE_MAT4: return 64 * count;
4128 default:
4129 SOKOL_UNREACHABLE;
4130 return -1;
4131 }
4132}
4133
4134/* return true if pixel format is a compressed format */
4135_SOKOL_PRIVATE bool _sg_is_compressed_pixel_format(sg_pixel_format fmt) {
4136 switch (fmt) {
4137 case SG_PIXELFORMAT_BC1_RGBA:
4138 case SG_PIXELFORMAT_BC2_RGBA:
4139 case SG_PIXELFORMAT_BC3_RGBA:
4140 case SG_PIXELFORMAT_BC4_R:
4141 case SG_PIXELFORMAT_BC4_RSN:
4142 case SG_PIXELFORMAT_BC5_RG:
4143 case SG_PIXELFORMAT_BC5_RGSN:
4144 case SG_PIXELFORMAT_BC6H_RGBF:
4145 case SG_PIXELFORMAT_BC6H_RGBUF:
4146 case SG_PIXELFORMAT_BC7_RGBA:
4147 case SG_PIXELFORMAT_PVRTC_RGB_2BPP:
4148 case SG_PIXELFORMAT_PVRTC_RGB_4BPP:
4149 case SG_PIXELFORMAT_PVRTC_RGBA_2BPP:
4150 case SG_PIXELFORMAT_PVRTC_RGBA_4BPP:
4151 case SG_PIXELFORMAT_ETC2_RGB8:
4152 case SG_PIXELFORMAT_ETC2_RGB8A1:
4153 case SG_PIXELFORMAT_ETC2_RGBA8:
4154 case SG_PIXELFORMAT_ETC2_RG11:
4155 case SG_PIXELFORMAT_ETC2_RG11SN:
4156 return true;
4157 default:
4158 return false;
4159 }
4160}
4161
4162/* return true if pixel format is a valid render target format */
4163_SOKOL_PRIVATE bool _sg_is_valid_rendertarget_color_format(sg_pixel_format fmt) {
4164 const int fmt_index = (int) fmt;
4165 SOKOL_ASSERT((fmt_index >= 0) && (fmt_index < _SG_PIXELFORMAT_NUM));
4166 return _sg.formats[fmt_index].render && !_sg.formats[fmt_index].depth;
4167}
4168
4169/* return true if pixel format is a valid depth format */
4170_SOKOL_PRIVATE bool _sg_is_valid_rendertarget_depth_format(sg_pixel_format fmt) {
4171 const int fmt_index = (int) fmt;
4172 SOKOL_ASSERT((fmt_index >= 0) && (fmt_index < _SG_PIXELFORMAT_NUM));
4173 return _sg.formats[fmt_index].render && _sg.formats[fmt_index].depth;
4174}
4175
4176/* return true if pixel format is a depth-stencil format */
4177_SOKOL_PRIVATE bool _sg_is_depth_stencil_format(sg_pixel_format fmt) {
4178 return (SG_PIXELFORMAT_DEPTH_STENCIL == fmt);
4179}
4180
4181/* return the bytes-per-pixel for a pixel format */
4182_SOKOL_PRIVATE int _sg_pixelformat_bytesize(sg_pixel_format fmt) {
4183 switch (fmt) {
4184 case SG_PIXELFORMAT_R8:
4185 case SG_PIXELFORMAT_R8SN:
4186 case SG_PIXELFORMAT_R8UI:
4187 case SG_PIXELFORMAT_R8SI:
4188 return 1;
4189
4190 case SG_PIXELFORMAT_R16:
4191 case SG_PIXELFORMAT_R16SN:
4192 case SG_PIXELFORMAT_R16UI:
4193 case SG_PIXELFORMAT_R16SI:
4194 case SG_PIXELFORMAT_R16F:
4195 case SG_PIXELFORMAT_RG8:
4196 case SG_PIXELFORMAT_RG8SN:
4197 case SG_PIXELFORMAT_RG8UI:
4198 case SG_PIXELFORMAT_RG8SI:
4199 return 2;
4200
4201 case SG_PIXELFORMAT_R32UI:
4202 case SG_PIXELFORMAT_R32SI:
4203 case SG_PIXELFORMAT_R32F:
4204 case SG_PIXELFORMAT_RG16:
4205 case SG_PIXELFORMAT_RG16SN:
4206 case SG_PIXELFORMAT_RG16UI:
4207 case SG_PIXELFORMAT_RG16SI:
4208 case SG_PIXELFORMAT_RG16F:
4209 case SG_PIXELFORMAT_RGBA8:
4210 case SG_PIXELFORMAT_RGBA8SN:
4211 case SG_PIXELFORMAT_RGBA8UI:
4212 case SG_PIXELFORMAT_RGBA8SI:
4213 case SG_PIXELFORMAT_BGRA8:
4214 case SG_PIXELFORMAT_RGB10A2:
4215 case SG_PIXELFORMAT_RG11B10F:
4216 return 4;
4217
4218 case SG_PIXELFORMAT_RG32UI:
4219 case SG_PIXELFORMAT_RG32SI:
4220 case SG_PIXELFORMAT_RG32F:
4221 case SG_PIXELFORMAT_RGBA16:
4222 case SG_PIXELFORMAT_RGBA16SN:
4223 case SG_PIXELFORMAT_RGBA16UI:
4224 case SG_PIXELFORMAT_RGBA16SI:
4225 case SG_PIXELFORMAT_RGBA16F:
4226 return 8;
4227
4228 case SG_PIXELFORMAT_RGBA32UI:
4229 case SG_PIXELFORMAT_RGBA32SI:
4230 case SG_PIXELFORMAT_RGBA32F:
4231 return 16;
4232
4233 default:
4234 SOKOL_UNREACHABLE;
4235 return 0;
4236 }
4237}
4238
4239_SOKOL_PRIVATE int _sg_roundup(int val, int round_to) {
4240 return (val+(round_to-1)) & ~(round_to-1);
4241}
4242
4243/* return row pitch for an image
4244 see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp
4245*/
4246_SOKOL_PRIVATE int _sg_row_pitch(sg_pixel_format fmt, int width, int row_align) {
4247 int pitch;
4248 switch (fmt) {
4249 case SG_PIXELFORMAT_BC1_RGBA:
4250 case SG_PIXELFORMAT_BC4_R:
4251 case SG_PIXELFORMAT_BC4_RSN:
4252 case SG_PIXELFORMAT_ETC2_RGB8:
4253 case SG_PIXELFORMAT_ETC2_RGB8A1:
4254 pitch = ((width + 3) / 4) * 8;
4255 pitch = pitch < 8 ? 8 : pitch;
4256 break;
4257 case SG_PIXELFORMAT_BC2_RGBA:
4258 case SG_PIXELFORMAT_BC3_RGBA:
4259 case SG_PIXELFORMAT_BC5_RG:
4260 case SG_PIXELFORMAT_BC5_RGSN:
4261 case SG_PIXELFORMAT_BC6H_RGBF:
4262 case SG_PIXELFORMAT_BC6H_RGBUF:
4263 case SG_PIXELFORMAT_BC7_RGBA:
4264 case SG_PIXELFORMAT_ETC2_RGBA8:
4265 case SG_PIXELFORMAT_ETC2_RG11:
4266 case SG_PIXELFORMAT_ETC2_RG11SN:
4267 pitch = ((width + 3) / 4) * 16;
4268 pitch = pitch < 16 ? 16 : pitch;
4269 break;
4270 case SG_PIXELFORMAT_PVRTC_RGB_4BPP:
4271 case SG_PIXELFORMAT_PVRTC_RGBA_4BPP:
4272 {
4273 const int block_size = 4*4;
4274 const int bpp = 4;
4275 int width_blocks = width / 4;
4276 width_blocks = width_blocks < 2 ? 2 : width_blocks;
4277 pitch = width_blocks * ((block_size * bpp) / 8);
4278 }
4279 break;
4280 case SG_PIXELFORMAT_PVRTC_RGB_2BPP:
4281 case SG_PIXELFORMAT_PVRTC_RGBA_2BPP:
4282 {
4283 const int block_size = 8*4;
4284 const int bpp = 2;
4285 int width_blocks = width / 4;
4286 width_blocks = width_blocks < 2 ? 2 : width_blocks;
4287 pitch = width_blocks * ((block_size * bpp) / 8);
4288 }
4289 break;
4290 default:
4291 pitch = width * _sg_pixelformat_bytesize(fmt);
4292 break;
4293 }
4294 pitch = _sg_roundup(pitch, row_align);
4295 return pitch;
4296}
4297
4298/* compute the number of rows in a surface depending on pixel format */
4299_SOKOL_PRIVATE int _sg_num_rows(sg_pixel_format fmt, int height) {
4300 int num_rows;
4301 switch (fmt) {
4302 case SG_PIXELFORMAT_BC1_RGBA:
4303 case SG_PIXELFORMAT_BC4_R:
4304 case SG_PIXELFORMAT_BC4_RSN:
4305 case SG_PIXELFORMAT_ETC2_RGB8:
4306 case SG_PIXELFORMAT_ETC2_RGB8A1:
4307 case SG_PIXELFORMAT_ETC2_RGBA8:
4308 case SG_PIXELFORMAT_ETC2_RG11:
4309 case SG_PIXELFORMAT_ETC2_RG11SN:
4310 case SG_PIXELFORMAT_BC2_RGBA:
4311 case SG_PIXELFORMAT_BC3_RGBA:
4312 case SG_PIXELFORMAT_BC5_RG:
4313 case SG_PIXELFORMAT_BC5_RGSN:
4314 case SG_PIXELFORMAT_BC6H_RGBF:
4315 case SG_PIXELFORMAT_BC6H_RGBUF:
4316 case SG_PIXELFORMAT_BC7_RGBA:
4317 case SG_PIXELFORMAT_PVRTC_RGB_4BPP:
4318 case SG_PIXELFORMAT_PVRTC_RGBA_4BPP:
4319 case SG_PIXELFORMAT_PVRTC_RGB_2BPP:
4320 case SG_PIXELFORMAT_PVRTC_RGBA_2BPP:
4321 num_rows = ((height + 3) / 4);
4322 break;
4323 default:
4324 num_rows = height;
4325 break;
4326 }
4327 if (num_rows < 1) {
4328 num_rows = 1;
4329 }
4330 return num_rows;
4331}
4332
4333/* return pitch of a 2D subimage / texture slice
4334 see ComputePitch in https://github.com/microsoft/DirectXTex/blob/master/DirectXTex/DirectXTexUtil.cpp
4335*/
4336_SOKOL_PRIVATE int _sg_surface_pitch(sg_pixel_format fmt, int width, int height, int row_align) {
4337 int num_rows = _sg_num_rows(fmt, height);
4338 return num_rows * _sg_row_pitch(fmt, width, row_align);
4339}
4340
4341/* capability table pixel format helper functions */
4342_SOKOL_PRIVATE void _sg_pixelformat_all(sg_pixelformat_info* pfi) {
4343 pfi->sample = true;
4344 pfi->filter = true;
4345 pfi->blend = true;
4346 pfi->render = true;
4347 pfi->msaa = true;
4348}
4349
4350_SOKOL_PRIVATE void _sg_pixelformat_s(sg_pixelformat_info* pfi) {
4351 pfi->sample = true;
4352}
4353
4354_SOKOL_PRIVATE void _sg_pixelformat_sf(sg_pixelformat_info* pfi) {
4355 pfi->sample = true;
4356 pfi->filter = true;
4357}
4358
4359_SOKOL_PRIVATE void _sg_pixelformat_sr(sg_pixelformat_info* pfi) {
4360 pfi->sample = true;
4361 pfi->render = true;
4362}
4363
4364_SOKOL_PRIVATE void _sg_pixelformat_srmd(sg_pixelformat_info* pfi) {
4365 pfi->sample = true;
4366 pfi->render = true;
4367 pfi->msaa = true;
4368 pfi->depth = true;
4369}
4370
4371_SOKOL_PRIVATE void _sg_pixelformat_srm(sg_pixelformat_info* pfi) {
4372 pfi->sample = true;
4373 pfi->render = true;
4374 pfi->msaa = true;
4375}
4376
4377_SOKOL_PRIVATE void _sg_pixelformat_sfrm(sg_pixelformat_info* pfi) {
4378 pfi->sample = true;
4379 pfi->filter = true;
4380 pfi->render = true;
4381 pfi->msaa = true;
4382}
4383_SOKOL_PRIVATE void _sg_pixelformat_sbrm(sg_pixelformat_info* pfi) {
4384 pfi->sample = true;
4385 pfi->blend = true;
4386 pfi->render = true;
4387 pfi->msaa = true;
4388}
4389
4390_SOKOL_PRIVATE void _sg_pixelformat_sbr(sg_pixelformat_info* pfi) {
4391 pfi->sample = true;
4392 pfi->blend = true;
4393 pfi->render = true;
4394}
4395
4396_SOKOL_PRIVATE void _sg_pixelformat_sfbr(sg_pixelformat_info* pfi) {
4397 pfi->sample = true;
4398 pfi->filter = true;
4399 pfi->blend = true;
4400 pfi->render = true;
4401}
4402
4403/* resolve pass action defaults into a new pass action struct */
4404_SOKOL_PRIVATE void _sg_resolve_default_pass_action(const sg_pass_action* from, sg_pass_action* to) {
4405 SOKOL_ASSERT(from && to);
4406 *to = *from;
4407 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
4408 if (to->colors[i].action == _SG_ACTION_DEFAULT) {
4409 to->colors[i].action = SG_ACTION_CLEAR;
4410 to->colors[i].value.r = SG_DEFAULT_CLEAR_RED;
4411 to->colors[i].value.g = SG_DEFAULT_CLEAR_GREEN;
4412 to->colors[i].value.b = SG_DEFAULT_CLEAR_BLUE;
4413 to->colors[i].value.a = SG_DEFAULT_CLEAR_ALPHA;
4414 }
4415 }
4416 if (to->depth.action == _SG_ACTION_DEFAULT) {
4417 to->depth.action = SG_ACTION_CLEAR;
4418 to->depth.value = SG_DEFAULT_CLEAR_DEPTH;
4419 }
4420 if (to->stencil.action == _SG_ACTION_DEFAULT) {
4421 to->stencil.action = SG_ACTION_CLEAR;
4422 to->stencil.value = SG_DEFAULT_CLEAR_STENCIL;
4423 }
4424}
4425
4426/*== DUMMY BACKEND IMPL ======================================================*/
4427#if defined(SOKOL_DUMMY_BACKEND)
4428
4429_SOKOL_PRIVATE void _sg_dummy_setup_backend(const sg_desc* desc) {
4430 SOKOL_ASSERT(desc);
4431 _SOKOL_UNUSED(desc);
4432 _sg.backend = SG_BACKEND_DUMMY;
4433 for (int i = SG_PIXELFORMAT_R8; i < SG_PIXELFORMAT_BC1_RGBA; i++) {
4434 _sg.formats[i].sample = true;
4435 _sg.formats[i].filter = true;
4436 _sg.formats[i].render = true;
4437 _sg.formats[i].blend = true;
4438 _sg.formats[i].msaa = true;
4439 }
4440 _sg.formats[SG_PIXELFORMAT_DEPTH].depth = true;
4441 _sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL].depth = true;
4442}
4443
4444_SOKOL_PRIVATE void _sg_dummy_discard_backend(void) {
4445 /* empty */
4446}
4447
4448_SOKOL_PRIVATE void _sg_dummy_reset_state_cache(void) {
4449 /* empty*/
4450}
4451
4452_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_context(_sg_context_t* ctx) {
4453 SOKOL_ASSERT(ctx);
4454 _SOKOL_UNUSED(ctx);
4455 return SG_RESOURCESTATE_VALID;
4456}
4457
4458_SOKOL_PRIVATE void _sg_dummy_destroy_context(_sg_context_t* ctx) {
4459 SOKOL_ASSERT(ctx);
4460 _SOKOL_UNUSED(ctx);
4461}
4462
4463_SOKOL_PRIVATE void _sg_dummy_activate_context(_sg_context_t* ctx) {
4464 SOKOL_ASSERT(ctx);
4465 _SOKOL_UNUSED(ctx);
4466}
4467
4468_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) {
4469 SOKOL_ASSERT(buf && desc);
4470 _sg_buffer_common_init(&buf->cmn, desc);
4471 return SG_RESOURCESTATE_VALID;
4472}
4473
4474_SOKOL_PRIVATE void _sg_dummy_destroy_buffer(_sg_buffer_t* buf) {
4475 SOKOL_ASSERT(buf);
4476 _SOKOL_UNUSED(buf);
4477}
4478
4479_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_image(_sg_image_t* img, const sg_image_desc* desc) {
4480 SOKOL_ASSERT(img && desc);
4481 _sg_image_common_init(&img->cmn, desc);
4482 return SG_RESOURCESTATE_VALID;
4483}
4484
4485_SOKOL_PRIVATE void _sg_dummy_destroy_image(_sg_image_t* img) {
4486 SOKOL_ASSERT(img);
4487 _SOKOL_UNUSED(img);
4488}
4489
4490_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) {
4491 SOKOL_ASSERT(shd && desc);
4492 _sg_shader_common_init(&shd->cmn, desc);
4493 return SG_RESOURCESTATE_VALID;
4494}
4495
4496_SOKOL_PRIVATE void _sg_dummy_destroy_shader(_sg_shader_t* shd) {
4497 SOKOL_ASSERT(shd);
4498 _SOKOL_UNUSED(shd);
4499}
4500
4501_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) {
4502 SOKOL_ASSERT(pip && desc);
4503 pip->shader = shd;
4504 _sg_pipeline_common_init(&pip->cmn, desc);
4505 for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) {
4506 const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index];
4507 if (a_desc->format == SG_VERTEXFORMAT_INVALID) {
4508 break;
4509 }
4510 SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS);
4511 pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true;
4512 }
4513 return SG_RESOURCESTATE_VALID;
4514}
4515
4516_SOKOL_PRIVATE void _sg_dummy_destroy_pipeline(_sg_pipeline_t* pip) {
4517 SOKOL_ASSERT(pip);
4518 _SOKOL_UNUSED(pip);
4519}
4520
4521_SOKOL_PRIVATE sg_resource_state _sg_dummy_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) {
4522 SOKOL_ASSERT(pass && desc);
4523 SOKOL_ASSERT(att_images && att_images[0]);
4524
4525 _sg_pass_common_init(&pass->cmn, desc);
4526
4527 const sg_pass_attachment_desc* att_desc;
4528 for (int i = 0; i < pass->cmn.num_color_atts; i++) {
4529 att_desc = &desc->color_attachments[i];
4530 SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID);
4531 SOKOL_ASSERT(0 == pass->dmy.color_atts[i].image);
4532 SOKOL_ASSERT(att_images[i] && (att_images[i]->slot.id == att_desc->image.id));
4533 SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(att_images[i]->cmn.pixel_format));
4534 pass->dmy.color_atts[i].image = att_images[i];
4535 }
4536
4537 SOKOL_ASSERT(0 == pass->dmy.ds_att.image);
4538 att_desc = &desc->depth_stencil_attachment;
4539 if (att_desc->image.id != SG_INVALID_ID) {
4540 const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS;
4541 SOKOL_ASSERT(att_images[ds_img_index] && (att_images[ds_img_index]->slot.id == att_desc->image.id));
4542 SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(att_images[ds_img_index]->cmn.pixel_format));
4543 pass->dmy.ds_att.image = att_images[ds_img_index];
4544 }
4545 return SG_RESOURCESTATE_VALID;
4546}
4547
4548_SOKOL_PRIVATE void _sg_dummy_destroy_pass(_sg_pass_t* pass) {
4549 SOKOL_ASSERT(pass);
4550 _SOKOL_UNUSED(pass);
4551}
4552
4553_SOKOL_PRIVATE _sg_image_t* _sg_dummy_pass_color_image(const _sg_pass_t* pass, int index) {
4554 SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS));
4555 /* NOTE: may return null */
4556 return pass->dmy.color_atts[index].image;
4557}
4558
4559_SOKOL_PRIVATE _sg_image_t* _sg_dummy_pass_ds_image(const _sg_pass_t* pass) {
4560 /* NOTE: may return null */
4561 SOKOL_ASSERT(pass);
4562 return pass->dmy.ds_att.image;
4563}
4564
4565_SOKOL_PRIVATE void _sg_dummy_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) {
4566 SOKOL_ASSERT(action);
4567 _SOKOL_UNUSED(pass);
4568 _SOKOL_UNUSED(action);
4569 _SOKOL_UNUSED(w);
4570 _SOKOL_UNUSED(h);
4571}
4572
4573_SOKOL_PRIVATE void _sg_dummy_end_pass(void) {
4574 /* empty */
4575}
4576
4577_SOKOL_PRIVATE void _sg_dummy_commit(void) {
4578 /* empty */
4579}
4580
4581_SOKOL_PRIVATE void _sg_dummy_apply_viewport(int x, int y, int w, int h, bool origin_top_left) {
4582 _SOKOL_UNUSED(x);
4583 _SOKOL_UNUSED(y);
4584 _SOKOL_UNUSED(w);
4585 _SOKOL_UNUSED(h);
4586 _SOKOL_UNUSED(origin_top_left);
4587}
4588
4589_SOKOL_PRIVATE void _sg_dummy_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) {
4590 _SOKOL_UNUSED(x);
4591 _SOKOL_UNUSED(y);
4592 _SOKOL_UNUSED(w);
4593 _SOKOL_UNUSED(h);
4594 _SOKOL_UNUSED(origin_top_left);
4595}
4596
4597_SOKOL_PRIVATE void _sg_dummy_apply_pipeline(_sg_pipeline_t* pip) {
4598 SOKOL_ASSERT(pip);
4599 _SOKOL_UNUSED(pip);
4600}
4601
4602_SOKOL_PRIVATE void _sg_dummy_apply_bindings(
4603 _sg_pipeline_t* pip,
4604 _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs,
4605 _sg_buffer_t* ib, int ib_offset,
4606 _sg_image_t** vs_imgs, int num_vs_imgs,
4607 _sg_image_t** fs_imgs, int num_fs_imgs)
4608{
4609 SOKOL_ASSERT(pip);
4610 SOKOL_ASSERT(vbs && vb_offsets);
4611 SOKOL_ASSERT(vs_imgs);
4612 SOKOL_ASSERT(fs_imgs);
4613 _SOKOL_UNUSED(pip);
4614 _SOKOL_UNUSED(vbs); _SOKOL_UNUSED(vb_offsets); _SOKOL_UNUSED(num_vbs);
4615 _SOKOL_UNUSED(ib); _SOKOL_UNUSED(ib_offset);
4616 _SOKOL_UNUSED(vs_imgs); _SOKOL_UNUSED(num_vs_imgs);
4617 _SOKOL_UNUSED(fs_imgs); _SOKOL_UNUSED(num_fs_imgs);
4618}
4619
4620_SOKOL_PRIVATE void _sg_dummy_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) {
4621 _SOKOL_UNUSED(stage_index);
4622 _SOKOL_UNUSED(ub_index);
4623 _SOKOL_UNUSED(data);
4624}
4625
4626_SOKOL_PRIVATE void _sg_dummy_draw(int base_element, int num_elements, int num_instances) {
4627 _SOKOL_UNUSED(base_element);
4628 _SOKOL_UNUSED(num_elements);
4629 _SOKOL_UNUSED(num_instances);
4630}
4631
4632_SOKOL_PRIVATE void _sg_dummy_update_buffer(_sg_buffer_t* buf, const sg_range* data) {
4633 SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0));
4634 _SOKOL_UNUSED(data);
4635 if (++buf->cmn.active_slot >= buf->cmn.num_slots) {
4636 buf->cmn.active_slot = 0;
4637 }
4638}
4639
4640_SOKOL_PRIVATE int _sg_dummy_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) {
4641 SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0));
4642 _SOKOL_UNUSED(data);
4643 if (new_frame) {
4644 if (++buf->cmn.active_slot >= buf->cmn.num_slots) {
4645 buf->cmn.active_slot = 0;
4646 }
4647 }
4648 /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */
4649 return _sg_roundup((int)data->size, 4);
4650}
4651
4652_SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data* data) {
4653 SOKOL_ASSERT(img && data);
4654 _SOKOL_UNUSED(data);
4655 if (++img->cmn.active_slot >= img->cmn.num_slots) {
4656 img->cmn.active_slot = 0;
4657 }
4658}
4659
4660/*== GL BACKEND ==============================================================*/
4661#elif defined(_SOKOL_ANY_GL)
4662
4663/*=== OPTIONAL GL LOADER FOR WIN32 ===========================================*/
4664#if defined(_SOKOL_USE_WIN32_GL_LOADER)
4665
4666// X Macro list of GL function names and signatures
4667#define _SG_GL_FUNCS \
4668 _SG_XMACRO(glBindVertexArray, void, (GLuint array)) \
4669 _SG_XMACRO(glFramebufferTextureLayer, void, (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)) \
4670 _SG_XMACRO(glGenFramebuffers, void, (GLsizei n, GLuint * framebuffers)) \
4671 _SG_XMACRO(glBindFramebuffer, void, (GLenum target, GLuint framebuffer)) \
4672 _SG_XMACRO(glBindRenderbuffer, void, (GLenum target, GLuint renderbuffer)) \
4673 _SG_XMACRO(glGetStringi, const GLubyte *, (GLenum name, GLuint index)) \
4674 _SG_XMACRO(glClearBufferfi, void, (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)) \
4675 _SG_XMACRO(glClearBufferfv, void, (GLenum buffer, GLint drawbuffer, const GLfloat * value)) \
4676 _SG_XMACRO(glClearBufferuiv, void, (GLenum buffer, GLint drawbuffer, const GLuint * value)) \
4677 _SG_XMACRO(glClearBufferiv, void, (GLenum buffer, GLint drawbuffer, const GLint * value)) \
4678 _SG_XMACRO(glDeleteRenderbuffers, void, (GLsizei n, const GLuint * renderbuffers)) \
4679 _SG_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
4680 _SG_XMACRO(glUniform2fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
4681 _SG_XMACRO(glUseProgram, void, (GLuint program)) \
4682 _SG_XMACRO(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length)) \
4683 _SG_XMACRO(glLinkProgram, void, (GLuint program)) \
4684 _SG_XMACRO(glGetUniformLocation, GLint, (GLuint program, const GLchar * name)) \
4685 _SG_XMACRO(glGetShaderiv, void, (GLuint shader, GLenum pname, GLint * params)) \
4686 _SG_XMACRO(glGetProgramInfoLog, void, (GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \
4687 _SG_XMACRO(glGetAttribLocation, GLint, (GLuint program, const GLchar * name)) \
4688 _SG_XMACRO(glDisableVertexAttribArray, void, (GLuint index)) \
4689 _SG_XMACRO(glDeleteShader, void, (GLuint shader)) \
4690 _SG_XMACRO(glDeleteProgram, void, (GLuint program)) \
4691 _SG_XMACRO(glCompileShader, void, (GLuint shader)) \
4692 _SG_XMACRO(glStencilFuncSeparate, void, (GLenum face, GLenum func, GLint ref, GLuint mask)) \
4693 _SG_XMACRO(glStencilOpSeparate, void, (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)) \
4694 _SG_XMACRO(glRenderbufferStorageMultisample, void, (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)) \
4695 _SG_XMACRO(glDrawBuffers, void, (GLsizei n, const GLenum * bufs)) \
4696 _SG_XMACRO(glVertexAttribDivisor, void, (GLuint index, GLuint divisor)) \
4697 _SG_XMACRO(glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void * data)) \
4698 _SG_XMACRO(glGenBuffers, void, (GLsizei n, GLuint * buffers)) \
4699 _SG_XMACRO(glCheckFramebufferStatus, GLenum, (GLenum target)) \
4700 _SG_XMACRO(glFramebufferRenderbuffer, void, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)) \
4701 _SG_XMACRO(glCompressedTexImage2D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data)) \
4702 _SG_XMACRO(glCompressedTexImage3D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data)) \
4703 _SG_XMACRO(glActiveTexture, void, (GLenum texture)) \
4704 _SG_XMACRO(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels)) \
4705 _SG_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \
4706 _SG_XMACRO(glRenderbufferStorage, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) \
4707 _SG_XMACRO(glGenTextures, void, (GLsizei n, GLuint * textures)) \
4708 _SG_XMACRO(glPolygonOffset, void, (GLfloat factor, GLfloat units)) \
4709 _SG_XMACRO(glDrawElements, void, (GLenum mode, GLsizei count, GLenum type, const void * indices)) \
4710 _SG_XMACRO(glDeleteFramebuffers, void, (GLsizei n, const GLuint * framebuffers)) \
4711 _SG_XMACRO(glBlendEquationSeparate, void, (GLenum modeRGB, GLenum modeAlpha)) \
4712 _SG_XMACRO(glDeleteTextures, void, (GLsizei n, const GLuint * textures)) \
4713 _SG_XMACRO(glGetProgramiv, void, (GLuint program, GLenum pname, GLint * params)) \
4714 _SG_XMACRO(glBindTexture, void, (GLenum target, GLuint texture)) \
4715 _SG_XMACRO(glTexImage3D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels)) \
4716 _SG_XMACRO(glCreateShader, GLuint, (GLenum type)) \
4717 _SG_XMACRO(glTexSubImage2D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels)) \
4718 _SG_XMACRO(glClearDepth, void, (GLdouble depth)) \
4719 _SG_XMACRO(glFramebufferTexture2D, void, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)) \
4720 _SG_XMACRO(glCreateProgram, GLuint, (void)) \
4721 _SG_XMACRO(glViewport, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \
4722 _SG_XMACRO(glDeleteBuffers, void, (GLsizei n, const GLuint * buffers)) \
4723 _SG_XMACRO(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) \
4724 _SG_XMACRO(glDrawElementsInstanced, void, (GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount)) \
4725 _SG_XMACRO(glVertexAttribPointer, void, (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)) \
4726 _SG_XMACRO(glUniform1i, void, (GLint location, GLint v0)) \
4727 _SG_XMACRO(glDisable, void, (GLenum cap)) \
4728 _SG_XMACRO(glColorMask, void, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \
4729 _SG_XMACRO(glColorMaski, void, (GLuint buf, GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) \
4730 _SG_XMACRO(glBindBuffer, void, (GLenum target, GLuint buffer)) \
4731 _SG_XMACRO(glDeleteVertexArrays, void, (GLsizei n, const GLuint * arrays)) \
4732 _SG_XMACRO(glDepthMask, void, (GLboolean flag)) \
4733 _SG_XMACRO(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)) \
4734 _SG_XMACRO(glClearStencil, void, (GLint s)) \
4735 _SG_XMACRO(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \
4736 _SG_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
4737 _SG_XMACRO(glGenRenderbuffers, void, (GLsizei n, GLuint * renderbuffers)) \
4738 _SG_XMACRO(glBufferData, void, (GLenum target, GLsizeiptr size, const void * data, GLenum usage)) \
4739 _SG_XMACRO(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) \
4740 _SG_XMACRO(glTexParameteri, void, (GLenum target, GLenum pname, GLint param)) \
4741 _SG_XMACRO(glGetIntegerv, void, (GLenum pname, GLint * data)) \
4742 _SG_XMACRO(glEnable, void, (GLenum cap)) \
4743 _SG_XMACRO(glBlitFramebuffer, void, (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)) \
4744 _SG_XMACRO(glStencilMask, void, (GLuint mask)) \
4745 _SG_XMACRO(glAttachShader, void, (GLuint program, GLuint shader)) \
4746 _SG_XMACRO(glGetError, GLenum, (void)) \
4747 _SG_XMACRO(glClearColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \
4748 _SG_XMACRO(glBlendColor, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) \
4749 _SG_XMACRO(glTexParameterf, void, (GLenum target, GLenum pname, GLfloat param)) \
4750 _SG_XMACRO(glTexParameterfv, void, (GLenum target, GLenum pname, GLfloat* params)) \
4751 _SG_XMACRO(glGetShaderInfoLog, void, (GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog)) \
4752 _SG_XMACRO(glDepthFunc, void, (GLenum func)) \
4753 _SG_XMACRO(glStencilOp , void, (GLenum fail, GLenum zfail, GLenum zpass)) \
4754 _SG_XMACRO(glStencilFunc, void, (GLenum func, GLint ref, GLuint mask)) \
4755 _SG_XMACRO(glEnableVertexAttribArray, void, (GLuint index)) \
4756 _SG_XMACRO(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) \
4757 _SG_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
4758 _SG_XMACRO(glReadBuffer, void, (GLenum src)) \
4759 _SG_XMACRO(glClear, void, (GLbitfield mask)) \
4760 _SG_XMACRO(glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels)) \
4761 _SG_XMACRO(glGenVertexArrays, void, (GLsizei n, GLuint * arrays)) \
4762 _SG_XMACRO(glFrontFace, void, (GLenum mode)) \
4763 _SG_XMACRO(glCullFace, void, (GLenum mode))
4764
4765// generate GL function pointer typedefs
4766#define _SG_XMACRO(name, ret, args) typedef ret (GL_APIENTRY* PFN_ ## name) args;
4767_SG_GL_FUNCS
4768#undef _SG_XMACRO
4769
4770// generate GL function pointers
4771#define _SG_XMACRO(name, ret, args) static PFN_ ## name name;
4772_SG_GL_FUNCS
4773#undef _SG_XMACRO
4774
4775// helper function to lookup GL functions in GL DLL
4776typedef PROC (WINAPI * _sg_wglGetProcAddress)(LPCSTR);
4777_SOKOL_PRIVATE void* _sg_gl_getprocaddr(const char* name, _sg_wglGetProcAddress wgl_getprocaddress) {
4778 void* proc_addr = (void*) wgl_getprocaddress(name);
4779 if (0 == proc_addr) {
4780 proc_addr = (void*) GetProcAddress(_sg.gl.opengl32_dll, name);
4781 }
4782 SOKOL_ASSERT(proc_addr);
4783 return proc_addr;
4784}
4785
4786// populate GL function pointers
4787_SOKOL_PRIVATE void _sg_gl_load_opengl(void) {
4788 SOKOL_ASSERT(0 == _sg.gl.opengl32_dll);
4789 _sg.gl.opengl32_dll = LoadLibraryA("opengl32.dll");
4790 SOKOL_ASSERT(_sg.gl.opengl32_dll);
4791 _sg_wglGetProcAddress wgl_getprocaddress = (_sg_wglGetProcAddress) GetProcAddress(_sg.gl.opengl32_dll, "wglGetProcAddress");
4792 SOKOL_ASSERT(wgl_getprocaddress);
4793 #define _SG_XMACRO(name, ret, args) name = (PFN_ ## name) _sg_gl_getprocaddr(#name, wgl_getprocaddress);
4794 _SG_GL_FUNCS
4795 #undef _SG_XMACRO
4796}
4797
4798_SOKOL_PRIVATE void _sg_gl_unload_opengl(void) {
4799 SOKOL_ASSERT(_sg.gl.opengl32_dll);
4800 FreeLibrary(_sg.gl.opengl32_dll);
4801 _sg.gl.opengl32_dll = 0;
4802}
4803#endif // _SOKOL_USE_WIN32_GL_LOADER
4804
4805/*-- type translation --------------------------------------------------------*/
4806_SOKOL_PRIVATE GLenum _sg_gl_buffer_target(sg_buffer_type t) {
4807 switch (t) {
4808 case SG_BUFFERTYPE_VERTEXBUFFER: return GL_ARRAY_BUFFER;
4809 case SG_BUFFERTYPE_INDEXBUFFER: return GL_ELEMENT_ARRAY_BUFFER;
4810 default: SOKOL_UNREACHABLE; return 0;
4811 }
4812}
4813
4814_SOKOL_PRIVATE GLenum _sg_gl_texture_target(sg_image_type t) {
4815 switch (t) {
4816 case SG_IMAGETYPE_2D: return GL_TEXTURE_2D;
4817 case SG_IMAGETYPE_CUBE: return GL_TEXTURE_CUBE_MAP;
4818 #if !defined(SOKOL_GLES2)
4819 case SG_IMAGETYPE_3D: return GL_TEXTURE_3D;
4820 case SG_IMAGETYPE_ARRAY: return GL_TEXTURE_2D_ARRAY;
4821 #endif
4822 default: SOKOL_UNREACHABLE; return 0;
4823 }
4824}
4825
4826_SOKOL_PRIVATE GLenum _sg_gl_usage(sg_usage u) {
4827 switch (u) {
4828 case SG_USAGE_IMMUTABLE: return GL_STATIC_DRAW;
4829 case SG_USAGE_DYNAMIC: return GL_DYNAMIC_DRAW;
4830 case SG_USAGE_STREAM: return GL_STREAM_DRAW;
4831 default: SOKOL_UNREACHABLE; return 0;
4832 }
4833}
4834
4835_SOKOL_PRIVATE GLenum _sg_gl_shader_stage(sg_shader_stage stage) {
4836 switch (stage) {
4837 case SG_SHADERSTAGE_VS: return GL_VERTEX_SHADER;
4838 case SG_SHADERSTAGE_FS: return GL_FRAGMENT_SHADER;
4839 default: SOKOL_UNREACHABLE; return 0;
4840 }
4841}
4842
4843_SOKOL_PRIVATE GLint _sg_gl_vertexformat_size(sg_vertex_format fmt) {
4844 switch (fmt) {
4845 case SG_VERTEXFORMAT_FLOAT: return 1;
4846 case SG_VERTEXFORMAT_FLOAT2: return 2;
4847 case SG_VERTEXFORMAT_FLOAT3: return 3;
4848 case SG_VERTEXFORMAT_FLOAT4: return 4;
4849 case SG_VERTEXFORMAT_BYTE4: return 4;
4850 case SG_VERTEXFORMAT_BYTE4N: return 4;
4851 case SG_VERTEXFORMAT_UBYTE4: return 4;
4852 case SG_VERTEXFORMAT_UBYTE4N: return 4;
4853 case SG_VERTEXFORMAT_SHORT2: return 2;
4854 case SG_VERTEXFORMAT_SHORT2N: return 2;
4855 case SG_VERTEXFORMAT_USHORT2N: return 2;
4856 case SG_VERTEXFORMAT_SHORT4: return 4;
4857 case SG_VERTEXFORMAT_SHORT4N: return 4;
4858 case SG_VERTEXFORMAT_USHORT4N: return 4;
4859 case SG_VERTEXFORMAT_UINT10_N2: return 4;
4860 default: SOKOL_UNREACHABLE; return 0;
4861 }
4862}
4863
4864_SOKOL_PRIVATE GLenum _sg_gl_vertexformat_type(sg_vertex_format fmt) {
4865 switch (fmt) {
4866 case SG_VERTEXFORMAT_FLOAT:
4867 case SG_VERTEXFORMAT_FLOAT2:
4868 case SG_VERTEXFORMAT_FLOAT3:
4869 case SG_VERTEXFORMAT_FLOAT4:
4870 return GL_FLOAT;
4871 case SG_VERTEXFORMAT_BYTE4:
4872 case SG_VERTEXFORMAT_BYTE4N:
4873 return GL_BYTE;
4874 case SG_VERTEXFORMAT_UBYTE4:
4875 case SG_VERTEXFORMAT_UBYTE4N:
4876 return GL_UNSIGNED_BYTE;
4877 case SG_VERTEXFORMAT_SHORT2:
4878 case SG_VERTEXFORMAT_SHORT2N:
4879 case SG_VERTEXFORMAT_SHORT4:
4880 case SG_VERTEXFORMAT_SHORT4N:
4881 return GL_SHORT;
4882 case SG_VERTEXFORMAT_USHORT2N:
4883 case SG_VERTEXFORMAT_USHORT4N:
4884 return GL_UNSIGNED_SHORT;
4885 case SG_VERTEXFORMAT_UINT10_N2:
4886 return GL_UNSIGNED_INT_2_10_10_10_REV;
4887 default:
4888 SOKOL_UNREACHABLE; return 0;
4889 }
4890}
4891
4892_SOKOL_PRIVATE GLboolean _sg_gl_vertexformat_normalized(sg_vertex_format fmt) {
4893 switch (fmt) {
4894 case SG_VERTEXFORMAT_BYTE4N:
4895 case SG_VERTEXFORMAT_UBYTE4N:
4896 case SG_VERTEXFORMAT_SHORT2N:
4897 case SG_VERTEXFORMAT_USHORT2N:
4898 case SG_VERTEXFORMAT_SHORT4N:
4899 case SG_VERTEXFORMAT_USHORT4N:
4900 case SG_VERTEXFORMAT_UINT10_N2:
4901 return GL_TRUE;
4902 default:
4903 return GL_FALSE;
4904 }
4905}
4906
4907_SOKOL_PRIVATE GLenum _sg_gl_primitive_type(sg_primitive_type t) {
4908 switch (t) {
4909 case SG_PRIMITIVETYPE_POINTS: return GL_POINTS;
4910 case SG_PRIMITIVETYPE_LINES: return GL_LINES;
4911 case SG_PRIMITIVETYPE_LINE_STRIP: return GL_LINE_STRIP;
4912 case SG_PRIMITIVETYPE_TRIANGLES: return GL_TRIANGLES;
4913 case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return GL_TRIANGLE_STRIP;
4914 default: SOKOL_UNREACHABLE; return 0;
4915 }
4916}
4917
4918_SOKOL_PRIVATE GLenum _sg_gl_index_type(sg_index_type t) {
4919 switch (t) {
4920 case SG_INDEXTYPE_NONE: return 0;
4921 case SG_INDEXTYPE_UINT16: return GL_UNSIGNED_SHORT;
4922 case SG_INDEXTYPE_UINT32: return GL_UNSIGNED_INT;
4923 default: SOKOL_UNREACHABLE; return 0;
4924 }
4925}
4926
4927_SOKOL_PRIVATE GLenum _sg_gl_compare_func(sg_compare_func cmp) {
4928 switch (cmp) {
4929 case SG_COMPAREFUNC_NEVER: return GL_NEVER;
4930 case SG_COMPAREFUNC_LESS: return GL_LESS;
4931 case SG_COMPAREFUNC_EQUAL: return GL_EQUAL;
4932 case SG_COMPAREFUNC_LESS_EQUAL: return GL_LEQUAL;
4933 case SG_COMPAREFUNC_GREATER: return GL_GREATER;
4934 case SG_COMPAREFUNC_NOT_EQUAL: return GL_NOTEQUAL;
4935 case SG_COMPAREFUNC_GREATER_EQUAL: return GL_GEQUAL;
4936 case SG_COMPAREFUNC_ALWAYS: return GL_ALWAYS;
4937 default: SOKOL_UNREACHABLE; return 0;
4938 }
4939}
4940
4941_SOKOL_PRIVATE GLenum _sg_gl_stencil_op(sg_stencil_op op) {
4942 switch (op) {
4943 case SG_STENCILOP_KEEP: return GL_KEEP;
4944 case SG_STENCILOP_ZERO: return GL_ZERO;
4945 case SG_STENCILOP_REPLACE: return GL_REPLACE;
4946 case SG_STENCILOP_INCR_CLAMP: return GL_INCR;
4947 case SG_STENCILOP_DECR_CLAMP: return GL_DECR;
4948 case SG_STENCILOP_INVERT: return GL_INVERT;
4949 case SG_STENCILOP_INCR_WRAP: return GL_INCR_WRAP;
4950 case SG_STENCILOP_DECR_WRAP: return GL_DECR_WRAP;
4951 default: SOKOL_UNREACHABLE; return 0;
4952 }
4953}
4954
4955_SOKOL_PRIVATE GLenum _sg_gl_blend_factor(sg_blend_factor f) {
4956 switch (f) {
4957 case SG_BLENDFACTOR_ZERO: return GL_ZERO;
4958 case SG_BLENDFACTOR_ONE: return GL_ONE;
4959 case SG_BLENDFACTOR_SRC_COLOR: return GL_SRC_COLOR;
4960 case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return GL_ONE_MINUS_SRC_COLOR;
4961 case SG_BLENDFACTOR_SRC_ALPHA: return GL_SRC_ALPHA;
4962 case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return GL_ONE_MINUS_SRC_ALPHA;
4963 case SG_BLENDFACTOR_DST_COLOR: return GL_DST_COLOR;
4964 case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return GL_ONE_MINUS_DST_COLOR;
4965 case SG_BLENDFACTOR_DST_ALPHA: return GL_DST_ALPHA;
4966 case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return GL_ONE_MINUS_DST_ALPHA;
4967 case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return GL_SRC_ALPHA_SATURATE;
4968 case SG_BLENDFACTOR_BLEND_COLOR: return GL_CONSTANT_COLOR;
4969 case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return GL_ONE_MINUS_CONSTANT_COLOR;
4970 case SG_BLENDFACTOR_BLEND_ALPHA: return GL_CONSTANT_ALPHA;
4971 case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return GL_ONE_MINUS_CONSTANT_ALPHA;
4972 default: SOKOL_UNREACHABLE; return 0;
4973 }
4974}
4975
4976_SOKOL_PRIVATE GLenum _sg_gl_blend_op(sg_blend_op op) {
4977 switch (op) {
4978 case SG_BLENDOP_ADD: return GL_FUNC_ADD;
4979 case SG_BLENDOP_SUBTRACT: return GL_FUNC_SUBTRACT;
4980 case SG_BLENDOP_REVERSE_SUBTRACT: return GL_FUNC_REVERSE_SUBTRACT;
4981 default: SOKOL_UNREACHABLE; return 0;
4982 }
4983}
4984
4985_SOKOL_PRIVATE GLenum _sg_gl_filter(sg_filter f) {
4986 switch (f) {
4987 case SG_FILTER_NEAREST: return GL_NEAREST;
4988 case SG_FILTER_LINEAR: return GL_LINEAR;
4989 case SG_FILTER_NEAREST_MIPMAP_NEAREST: return GL_NEAREST_MIPMAP_NEAREST;
4990 case SG_FILTER_NEAREST_MIPMAP_LINEAR: return GL_NEAREST_MIPMAP_LINEAR;
4991 case SG_FILTER_LINEAR_MIPMAP_NEAREST: return GL_LINEAR_MIPMAP_NEAREST;
4992 case SG_FILTER_LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
4993 default: SOKOL_UNREACHABLE; return 0;
4994 }
4995}
4996
4997_SOKOL_PRIVATE GLenum _sg_gl_wrap(sg_wrap w) {
4998 switch (w) {
4999 case SG_WRAP_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE;
5000 #if defined(SOKOL_GLCORE33)
5001 case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_BORDER;
5002 #else
5003 case SG_WRAP_CLAMP_TO_BORDER: return GL_CLAMP_TO_EDGE;
5004 #endif
5005 case SG_WRAP_REPEAT: return GL_REPEAT;
5006 case SG_WRAP_MIRRORED_REPEAT: return GL_MIRRORED_REPEAT;
5007 default: SOKOL_UNREACHABLE; return 0;
5008 }
5009}
5010
5011_SOKOL_PRIVATE GLenum _sg_gl_teximage_type(sg_pixel_format fmt) {
5012 switch (fmt) {
5013 case SG_PIXELFORMAT_R8:
5014 case SG_PIXELFORMAT_R8UI:
5015 case SG_PIXELFORMAT_RG8:
5016 case SG_PIXELFORMAT_RG8UI:
5017 case SG_PIXELFORMAT_RGBA8:
5018 case SG_PIXELFORMAT_RGBA8UI:
5019 case SG_PIXELFORMAT_BGRA8:
5020 return GL_UNSIGNED_BYTE;
5021 case SG_PIXELFORMAT_R8SN:
5022 case SG_PIXELFORMAT_R8SI:
5023 case SG_PIXELFORMAT_RG8SN:
5024 case SG_PIXELFORMAT_RG8SI:
5025 case SG_PIXELFORMAT_RGBA8SN:
5026 case SG_PIXELFORMAT_RGBA8SI:
5027 return GL_BYTE;
5028 case SG_PIXELFORMAT_R16:
5029 case SG_PIXELFORMAT_R16UI:
5030 case SG_PIXELFORMAT_RG16:
5031 case SG_PIXELFORMAT_RG16UI:
5032 case SG_PIXELFORMAT_RGBA16:
5033 case SG_PIXELFORMAT_RGBA16UI:
5034 return GL_UNSIGNED_SHORT;
5035 case SG_PIXELFORMAT_R16SN:
5036 case SG_PIXELFORMAT_R16SI:
5037 case SG_PIXELFORMAT_RG16SN:
5038 case SG_PIXELFORMAT_RG16SI:
5039 case SG_PIXELFORMAT_RGBA16SN:
5040 case SG_PIXELFORMAT_RGBA16SI:
5041 return GL_SHORT;
5042 case SG_PIXELFORMAT_R16F:
5043 case SG_PIXELFORMAT_RG16F:
5044 case SG_PIXELFORMAT_RGBA16F:
5045 return GL_HALF_FLOAT;
5046 case SG_PIXELFORMAT_R32UI:
5047 case SG_PIXELFORMAT_RG32UI:
5048 case SG_PIXELFORMAT_RGBA32UI:
5049 return GL_UNSIGNED_INT;
5050 case SG_PIXELFORMAT_R32SI:
5051 case SG_PIXELFORMAT_RG32SI:
5052 case SG_PIXELFORMAT_RGBA32SI:
5053 return GL_INT;
5054 case SG_PIXELFORMAT_R32F:
5055 case SG_PIXELFORMAT_RG32F:
5056 case SG_PIXELFORMAT_RGBA32F:
5057 return GL_FLOAT;
5058 #if !defined(SOKOL_GLES2)
5059 case SG_PIXELFORMAT_RGB10A2:
5060 return GL_UNSIGNED_INT_2_10_10_10_REV;
5061 case SG_PIXELFORMAT_RG11B10F:
5062 return GL_UNSIGNED_INT_10F_11F_11F_REV;
5063 #endif
5064 case SG_PIXELFORMAT_DEPTH:
5065 return GL_UNSIGNED_SHORT;
5066 case SG_PIXELFORMAT_DEPTH_STENCIL:
5067 return GL_UNSIGNED_INT_24_8;
5068 default:
5069 SOKOL_UNREACHABLE; return 0;
5070 }
5071}
5072
5073_SOKOL_PRIVATE GLenum _sg_gl_teximage_format(sg_pixel_format fmt) {
5074 switch (fmt) {
5075 case SG_PIXELFORMAT_R8:
5076 case SG_PIXELFORMAT_R8SN:
5077 case SG_PIXELFORMAT_R16:
5078 case SG_PIXELFORMAT_R16SN:
5079 case SG_PIXELFORMAT_R16F:
5080 case SG_PIXELFORMAT_R32F:
5081 #if defined(SOKOL_GLES2)
5082 return GL_LUMINANCE;
5083 #else
5084 if (_sg.gl.gles2) {
5085 return GL_LUMINANCE;
5086 }
5087 else {
5088 return GL_RED;
5089 }
5090 #endif
5091 #if !defined(SOKOL_GLES2)
5092 case SG_PIXELFORMAT_R8UI:
5093 case SG_PIXELFORMAT_R8SI:
5094 case SG_PIXELFORMAT_R16UI:
5095 case SG_PIXELFORMAT_R16SI:
5096 case SG_PIXELFORMAT_R32UI:
5097 case SG_PIXELFORMAT_R32SI:
5098 return GL_RED_INTEGER;
5099 case SG_PIXELFORMAT_RG8:
5100 case SG_PIXELFORMAT_RG8SN:
5101 case SG_PIXELFORMAT_RG16:
5102 case SG_PIXELFORMAT_RG16SN:
5103 case SG_PIXELFORMAT_RG16F:
5104 case SG_PIXELFORMAT_RG32F:
5105 return GL_RG;
5106 case SG_PIXELFORMAT_RG8UI:
5107 case SG_PIXELFORMAT_RG8SI:
5108 case SG_PIXELFORMAT_RG16UI:
5109 case SG_PIXELFORMAT_RG16SI:
5110 case SG_PIXELFORMAT_RG32UI:
5111 case SG_PIXELFORMAT_RG32SI:
5112 return GL_RG_INTEGER;
5113 #endif
5114 case SG_PIXELFORMAT_RGBA8:
5115 case SG_PIXELFORMAT_RGBA8SN:
5116 case SG_PIXELFORMAT_RGBA16:
5117 case SG_PIXELFORMAT_RGBA16SN:
5118 case SG_PIXELFORMAT_RGBA16F:
5119 case SG_PIXELFORMAT_RGBA32F:
5120 case SG_PIXELFORMAT_RGB10A2:
5121 return GL_RGBA;
5122 #if !defined(SOKOL_GLES2)
5123 case SG_PIXELFORMAT_RGBA8UI:
5124 case SG_PIXELFORMAT_RGBA8SI:
5125 case SG_PIXELFORMAT_RGBA16UI:
5126 case SG_PIXELFORMAT_RGBA16SI:
5127 case SG_PIXELFORMAT_RGBA32UI:
5128 case SG_PIXELFORMAT_RGBA32SI:
5129 return GL_RGBA_INTEGER;
5130 #endif
5131 case SG_PIXELFORMAT_RG11B10F:
5132 return GL_RGB;
5133 case SG_PIXELFORMAT_DEPTH:
5134 return GL_DEPTH_COMPONENT;
5135 case SG_PIXELFORMAT_DEPTH_STENCIL:
5136 return GL_DEPTH_STENCIL;
5137 case SG_PIXELFORMAT_BC1_RGBA:
5138 return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
5139 case SG_PIXELFORMAT_BC2_RGBA:
5140 return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
5141 case SG_PIXELFORMAT_BC3_RGBA:
5142 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
5143 case SG_PIXELFORMAT_BC4_R:
5144 return GL_COMPRESSED_RED_RGTC1;
5145 case SG_PIXELFORMAT_BC4_RSN:
5146 return GL_COMPRESSED_SIGNED_RED_RGTC1;
5147 case SG_PIXELFORMAT_BC5_RG:
5148 return GL_COMPRESSED_RED_GREEN_RGTC2;
5149 case SG_PIXELFORMAT_BC5_RGSN:
5150 return GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2;
5151 case SG_PIXELFORMAT_BC6H_RGBF:
5152 return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB;
5153 case SG_PIXELFORMAT_BC6H_RGBUF:
5154 return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB;
5155 case SG_PIXELFORMAT_BC7_RGBA:
5156 return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
5157 case SG_PIXELFORMAT_PVRTC_RGB_2BPP:
5158 return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
5159 case SG_PIXELFORMAT_PVRTC_RGB_4BPP:
5160 return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
5161 case SG_PIXELFORMAT_PVRTC_RGBA_2BPP:
5162 return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
5163 case SG_PIXELFORMAT_PVRTC_RGBA_4BPP:
5164 return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
5165 case SG_PIXELFORMAT_ETC2_RGB8:
5166 return GL_COMPRESSED_RGB8_ETC2;
5167 case SG_PIXELFORMAT_ETC2_RGB8A1:
5168 return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
5169 case SG_PIXELFORMAT_ETC2_RGBA8:
5170 return GL_COMPRESSED_RGBA8_ETC2_EAC;
5171 case SG_PIXELFORMAT_ETC2_RG11:
5172 return GL_COMPRESSED_RG11_EAC;
5173 case SG_PIXELFORMAT_ETC2_RG11SN:
5174 return GL_COMPRESSED_SIGNED_RG11_EAC;
5175 default:
5176 SOKOL_UNREACHABLE; return 0;
5177 }
5178}
5179
5180_SOKOL_PRIVATE GLenum _sg_gl_teximage_internal_format(sg_pixel_format fmt) {
5181 #if defined(SOKOL_GLES2)
5182 return _sg_gl_teximage_format(fmt);
5183 #else
5184 if (_sg.gl.gles2) {
5185 return _sg_gl_teximage_format(fmt);
5186 }
5187 else {
5188 switch (fmt) {
5189 case SG_PIXELFORMAT_R8: return GL_R8;
5190 case SG_PIXELFORMAT_R8SN: return GL_R8_SNORM;
5191 case SG_PIXELFORMAT_R8UI: return GL_R8UI;
5192 case SG_PIXELFORMAT_R8SI: return GL_R8I;
5193 #if !defined(SOKOL_GLES3)
5194 case SG_PIXELFORMAT_R16: return GL_R16;
5195 case SG_PIXELFORMAT_R16SN: return GL_R16_SNORM;
5196 #endif
5197 case SG_PIXELFORMAT_R16UI: return GL_R16UI;
5198 case SG_PIXELFORMAT_R16SI: return GL_R16I;
5199 case SG_PIXELFORMAT_R16F: return GL_R16F;
5200 case SG_PIXELFORMAT_RG8: return GL_RG8;
5201 case SG_PIXELFORMAT_RG8SN: return GL_RG8_SNORM;
5202 case SG_PIXELFORMAT_RG8UI: return GL_RG8UI;
5203 case SG_PIXELFORMAT_RG8SI: return GL_RG8I;
5204 case SG_PIXELFORMAT_R32UI: return GL_R32UI;
5205 case SG_PIXELFORMAT_R32SI: return GL_R32I;
5206 case SG_PIXELFORMAT_R32F: return GL_R32F;
5207 #if !defined(SOKOL_GLES3)
5208 case SG_PIXELFORMAT_RG16: return GL_RG16;
5209 case SG_PIXELFORMAT_RG16SN: return GL_RG16_SNORM;
5210 #endif
5211 case SG_PIXELFORMAT_RG16UI: return GL_RG16UI;
5212 case SG_PIXELFORMAT_RG16SI: return GL_RG16I;
5213 case SG_PIXELFORMAT_RG16F: return GL_RG16F;
5214 case SG_PIXELFORMAT_RGBA8: return GL_RGBA8;
5215 case SG_PIXELFORMAT_RGBA8SN: return GL_RGBA8_SNORM;
5216 case SG_PIXELFORMAT_RGBA8UI: return GL_RGBA8UI;
5217 case SG_PIXELFORMAT_RGBA8SI: return GL_RGBA8I;
5218 case SG_PIXELFORMAT_RGB10A2: return GL_RGB10_A2;
5219 case SG_PIXELFORMAT_RG11B10F: return GL_R11F_G11F_B10F;
5220 case SG_PIXELFORMAT_RG32UI: return GL_RG32UI;
5221 case SG_PIXELFORMAT_RG32SI: return GL_RG32I;
5222 case SG_PIXELFORMAT_RG32F: return GL_RG32F;
5223 #if !defined(SOKOL_GLES3)
5224 case SG_PIXELFORMAT_RGBA16: return GL_RGBA16;
5225 case SG_PIXELFORMAT_RGBA16SN: return GL_RGBA16_SNORM;
5226 #endif
5227 case SG_PIXELFORMAT_RGBA16UI: return GL_RGBA16UI;
5228 case SG_PIXELFORMAT_RGBA16SI: return GL_RGBA16I;
5229 case SG_PIXELFORMAT_RGBA16F: return GL_RGBA16F;
5230 case SG_PIXELFORMAT_RGBA32UI: return GL_RGBA32UI;
5231 case SG_PIXELFORMAT_RGBA32SI: return GL_RGBA32I;
5232 case SG_PIXELFORMAT_RGBA32F: return GL_RGBA32F;
5233 case SG_PIXELFORMAT_DEPTH: return GL_DEPTH_COMPONENT16;
5234 case SG_PIXELFORMAT_DEPTH_STENCIL: return GL_DEPTH24_STENCIL8;
5235 case SG_PIXELFORMAT_BC1_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
5236 case SG_PIXELFORMAT_BC2_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
5237 case SG_PIXELFORMAT_BC3_RGBA: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
5238 case SG_PIXELFORMAT_BC4_R: return GL_COMPRESSED_RED_RGTC1;
5239 case SG_PIXELFORMAT_BC4_RSN: return GL_COMPRESSED_SIGNED_RED_RGTC1;
5240 case SG_PIXELFORMAT_BC5_RG: return GL_COMPRESSED_RED_GREEN_RGTC2;
5241 case SG_PIXELFORMAT_BC5_RGSN: return GL_COMPRESSED_SIGNED_RED_GREEN_RGTC2;
5242 case SG_PIXELFORMAT_BC6H_RGBF: return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB;
5243 case SG_PIXELFORMAT_BC6H_RGBUF: return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB;
5244 case SG_PIXELFORMAT_BC7_RGBA: return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
5245 case SG_PIXELFORMAT_PVRTC_RGB_2BPP: return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
5246 case SG_PIXELFORMAT_PVRTC_RGB_4BPP: return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
5247 case SG_PIXELFORMAT_PVRTC_RGBA_2BPP: return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
5248 case SG_PIXELFORMAT_PVRTC_RGBA_4BPP: return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
5249 case SG_PIXELFORMAT_ETC2_RGB8: return GL_COMPRESSED_RGB8_ETC2;
5250 case SG_PIXELFORMAT_ETC2_RGB8A1: return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
5251 case SG_PIXELFORMAT_ETC2_RGBA8: return GL_COMPRESSED_RGBA8_ETC2_EAC;
5252 case SG_PIXELFORMAT_ETC2_RG11: return GL_COMPRESSED_RG11_EAC;
5253 case SG_PIXELFORMAT_ETC2_RG11SN: return GL_COMPRESSED_SIGNED_RG11_EAC;
5254 default: SOKOL_UNREACHABLE; return 0;
5255 }
5256 }
5257 #endif
5258}
5259
5260_SOKOL_PRIVATE GLenum _sg_gl_cubeface_target(int face_index) {
5261 switch (face_index) {
5262 case 0: return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
5263 case 1: return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
5264 case 2: return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
5265 case 3: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
5266 case 4: return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
5267 case 5: return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
5268 default: SOKOL_UNREACHABLE; return 0;
5269 }
5270}
5271
5272_SOKOL_PRIVATE GLenum _sg_gl_depth_attachment_format(sg_pixel_format fmt) {
5273 switch (fmt) {
5274 case SG_PIXELFORMAT_DEPTH: return GL_DEPTH_COMPONENT16;
5275 case SG_PIXELFORMAT_DEPTH_STENCIL: return GL_DEPTH24_STENCIL8;
5276 default: SOKOL_UNREACHABLE; return 0;
5277 }
5278}
5279
5280/* see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml */
5281_SOKOL_PRIVATE void _sg_gl_init_pixelformats(bool has_bgra) {
5282 #if !defined(SOKOL_GLES2)
5283 if (!_sg.gl.gles2) {
5284 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R8]);
5285 }
5286 else {
5287 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8]);
5288 }
5289 #else
5290 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8]);
5291 #endif
5292 #if !defined(SOKOL_GLES2)
5293 if (!_sg.gl.gles2) {
5294 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R8SN]);
5295 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8UI]);
5296 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R8SI]);
5297 #if !defined(SOKOL_GLES3)
5298 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16]);
5299 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16SN]);
5300 #endif
5301 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16UI]);
5302 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_R16SI]);
5303 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG8]);
5304 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG8SN]);
5305 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8UI]);
5306 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG8SI]);
5307 _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32UI]);
5308 _sg_pixelformat_sr(&_sg.formats[SG_PIXELFORMAT_R32SI]);
5309 #if !defined(SOKOL_GLES3)
5310 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16]);
5311 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16SN]);
5312 #endif
5313 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16UI]);
5314 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG16SI]);
5315 }
5316 #endif
5317 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA8]);
5318 #if !defined(SOKOL_GLES2)
5319 if (!_sg.gl.gles2) {
5320 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA8SN]);
5321 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8UI]);
5322 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA8SI]);
5323 }
5324 #endif
5325 if (has_bgra) {
5326 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_BGRA8]);
5327 }
5328 #if !defined(SOKOL_GLES2)
5329 if (!_sg.gl.gles2) {
5330 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGB10A2]);
5331 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG11B10F]);
5332 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32UI]);
5333 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RG32SI]);
5334 #if !defined(SOKOL_GLES3)
5335 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16]);
5336 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16SN]);
5337 #endif
5338 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16UI]);
5339 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA16SI]);
5340 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32UI]);
5341 _sg_pixelformat_srm(&_sg.formats[SG_PIXELFORMAT_RGBA32SI]);
5342 }
5343 #endif
5344 // FIXME: WEBGL_depth_texture extension?
5345 _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH]);
5346 _sg_pixelformat_srmd(&_sg.formats[SG_PIXELFORMAT_DEPTH_STENCIL]);
5347}
5348
5349/* FIXME: OES_half_float_blend */
5350_SOKOL_PRIVATE void _sg_gl_init_pixelformats_half_float(bool has_colorbuffer_half_float, bool has_texture_half_float_linear) {
5351 #if !defined(SOKOL_GLES2)
5352 if (!_sg.gl.gles2) {
5353 if (has_texture_half_float_linear) {
5354 if (has_colorbuffer_half_float) {
5355 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R16F]);
5356 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG16F]);
5357 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5358 }
5359 else {
5360 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R16F]);
5361 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG16F]);
5362 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5363 }
5364 }
5365 else {
5366 if (has_colorbuffer_half_float) {
5367 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_R16F]);
5368 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RG16F]);
5369 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5370 }
5371 else {
5372 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R16F]);
5373 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RG16F]);
5374 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5375 }
5376 }
5377 }
5378 else {
5379 #endif
5380 /* GLES2 can only render to RGBA, and there's no RG format */
5381 if (has_texture_half_float_linear) {
5382 if (has_colorbuffer_half_float) {
5383 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5384 }
5385 else {
5386 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5387 }
5388 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R16F]);
5389 }
5390 else {
5391 if (has_colorbuffer_half_float) {
5392 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5393 }
5394 else {
5395 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA16F]);
5396 }
5397 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R16F]);
5398 }
5399 #if !defined(SOKOL_GLES2)
5400 }
5401 #endif
5402}
5403
5404_SOKOL_PRIVATE void _sg_gl_init_pixelformats_float(bool has_colorbuffer_float, bool has_texture_float_linear, bool has_float_blend) {
5405 #if !defined(SOKOL_GLES2)
5406 if (!_sg.gl.gles2) {
5407 if (has_texture_float_linear) {
5408 if (has_colorbuffer_float) {
5409 if (has_float_blend) {
5410 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_R32F]);
5411 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RG32F]);
5412 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5413 }
5414 else {
5415 _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_R32F]);
5416 _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RG32F]);
5417 _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5418 }
5419 }
5420 else {
5421 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R32F]);
5422 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RG32F]);
5423 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5424 }
5425 }
5426 else {
5427 if (has_colorbuffer_float) {
5428 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_R32F]);
5429 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RG32F]);
5430 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5431 }
5432 else {
5433 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R32F]);
5434 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RG32F]);
5435 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5436 }
5437 }
5438 }
5439 else {
5440 #endif
5441 /* GLES2 can only render to RGBA, and there's no RG format */
5442 if (has_texture_float_linear) {
5443 if (has_colorbuffer_float) {
5444 if (has_float_blend) {
5445 _sg_pixelformat_all(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5446 }
5447 else {
5448 _sg_pixelformat_sfrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5449 }
5450 }
5451 else {
5452 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5453 }
5454 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_R32F]);
5455 }
5456 else {
5457 if (has_colorbuffer_float) {
5458 _sg_pixelformat_sbrm(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5459 }
5460 else {
5461 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_RGBA32F]);
5462 }
5463 _sg_pixelformat_s(&_sg.formats[SG_PIXELFORMAT_R32F]);
5464 }
5465 #if !defined(SOKOL_GLES2)
5466 }
5467 #endif
5468}
5469
5470_SOKOL_PRIVATE void _sg_gl_init_pixelformats_s3tc(void) {
5471 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC1_RGBA]);
5472 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC2_RGBA]);
5473 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC3_RGBA]);
5474}
5475
5476_SOKOL_PRIVATE void _sg_gl_init_pixelformats_rgtc(void) {
5477 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_R]);
5478 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC4_RSN]);
5479 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RG]);
5480 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC5_RGSN]);
5481}
5482
5483_SOKOL_PRIVATE void _sg_gl_init_pixelformats_bptc(void) {
5484 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBF]);
5485 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC6H_RGBUF]);
5486 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_BC7_RGBA]);
5487}
5488
5489_SOKOL_PRIVATE void _sg_gl_init_pixelformats_pvrtc(void) {
5490 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_2BPP]);
5491 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGB_4BPP]);
5492 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_2BPP]);
5493 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_PVRTC_RGBA_4BPP]);
5494}
5495
5496_SOKOL_PRIVATE void _sg_gl_init_pixelformats_etc2(void) {
5497 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8]);
5498 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGB8A1]);
5499 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RGBA8]);
5500 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11]);
5501 _sg_pixelformat_sf(&_sg.formats[SG_PIXELFORMAT_ETC2_RG11SN]);
5502}
5503
5504_SOKOL_PRIVATE void _sg_gl_init_limits(void) {
5505 _SG_GL_CHECK_ERROR();
5506 GLint gl_int;
5507 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl_int);
5508 _SG_GL_CHECK_ERROR();
5509 _sg.limits.max_image_size_2d = gl_int;
5510 _sg.limits.max_image_size_array = gl_int;
5511 glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &gl_int);
5512 _SG_GL_CHECK_ERROR();
5513 _sg.limits.max_image_size_cube = gl_int;
5514 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &gl_int);
5515 _SG_GL_CHECK_ERROR();
5516 if (gl_int > SG_MAX_VERTEX_ATTRIBUTES) {
5517 gl_int = SG_MAX_VERTEX_ATTRIBUTES;
5518 }
5519 _sg.limits.max_vertex_attrs = gl_int;
5520 #if !defined(SOKOL_GLES2)
5521 if (!_sg.gl.gles2) {
5522 glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &gl_int);
5523 _SG_GL_CHECK_ERROR();
5524 _sg.limits.max_image_size_3d = gl_int;
5525 glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &gl_int);
5526 _SG_GL_CHECK_ERROR();
5527 _sg.limits.max_image_array_layers = gl_int;
5528 }
5529 #endif
5530 if (_sg.gl.ext_anisotropic) {
5531 glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gl_int);
5532 _SG_GL_CHECK_ERROR();
5533 _sg.gl.max_anisotropy = gl_int;
5534 }
5535 else {
5536 _sg.gl.max_anisotropy = 1;
5537 }
5538 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &gl_int);
5539 _SG_GL_CHECK_ERROR();
5540 _sg.gl.max_combined_texture_image_units = gl_int;
5541}
5542
5543#if defined(SOKOL_GLCORE33)
5544_SOKOL_PRIVATE void _sg_gl_init_caps_glcore33(void) {
5545 _sg.backend = SG_BACKEND_GLCORE33;
5546
5547 _sg.features.origin_top_left = false;
5548 _sg.features.instancing = true;
5549 _sg.features.multiple_render_targets = true;
5550 _sg.features.msaa_render_targets = true;
5551 _sg.features.imagetype_3d = true;
5552 _sg.features.imagetype_array = true;
5553 _sg.features.image_clamp_to_border = true;
5554 _sg.features.mrt_independent_blend_state = false;
5555 _sg.features.mrt_independent_write_mask = true;
5556
5557 /* scan extensions */
5558 bool has_s3tc = false; /* BC1..BC3 */
5559 bool has_rgtc = false; /* BC4 and BC5 */
5560 bool has_bptc = false; /* BC6H and BC7 */
5561 bool has_pvrtc = false;
5562 bool has_etc2 = false;
5563 GLint num_ext = 0;
5564 glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext);
5565 for (int i = 0; i < num_ext; i++) {
5566 const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i);
5567 if (ext) {
5568 if (strstr(ext, "_texture_compression_s3tc")) {
5569 has_s3tc = true;
5570 }
5571 else if (strstr(ext, "_texture_compression_rgtc")) {
5572 has_rgtc = true;
5573 }
5574 else if (strstr(ext, "_texture_compression_bptc")) {
5575 has_bptc = true;
5576 }
5577 else if (strstr(ext, "_texture_compression_pvrtc")) {
5578 has_pvrtc = true;
5579 }
5580 else if (strstr(ext, "_ES3_compatibility")) {
5581 has_etc2 = true;
5582 }
5583 else if (strstr(ext, "_texture_filter_anisotropic")) {
5584 _sg.gl.ext_anisotropic = true;
5585 }
5586 }
5587 }
5588
5589 /* limits */
5590 _sg_gl_init_limits();
5591
5592 /* pixel formats */
5593 const bool has_bgra = false; /* not a bug */
5594 const bool has_colorbuffer_float = true;
5595 const bool has_colorbuffer_half_float = true;
5596 const bool has_texture_float_linear = true; /* FIXME??? */
5597 const bool has_texture_half_float_linear = true;
5598 const bool has_float_blend = true;
5599 _sg_gl_init_pixelformats(has_bgra);
5600 _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend);
5601 _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float, has_texture_half_float_linear);
5602 if (has_s3tc) {
5603 _sg_gl_init_pixelformats_s3tc();
5604 }
5605 if (has_rgtc) {
5606 _sg_gl_init_pixelformats_rgtc();
5607 }
5608 if (has_bptc) {
5609 _sg_gl_init_pixelformats_bptc();
5610 }
5611 if (has_pvrtc) {
5612 _sg_gl_init_pixelformats_pvrtc();
5613 }
5614 if (has_etc2) {
5615 _sg_gl_init_pixelformats_etc2();
5616 }
5617}
5618#endif
5619
5620#if defined(SOKOL_GLES3)
5621_SOKOL_PRIVATE void _sg_gl_init_caps_gles3(void) {
5622 _sg.backend = SG_BACKEND_GLES3;
5623
5624 _sg.features.origin_top_left = false;
5625 _sg.features.instancing = true;
5626 _sg.features.multiple_render_targets = true;
5627 _sg.features.msaa_render_targets = true;
5628 _sg.features.imagetype_3d = true;
5629 _sg.features.imagetype_array = true;
5630 _sg.features.image_clamp_to_border = false;
5631 _sg.features.mrt_independent_blend_state = false;
5632 _sg.features.mrt_independent_write_mask = false;
5633
5634 bool has_s3tc = false; /* BC1..BC3 */
5635 bool has_rgtc = false; /* BC4 and BC5 */
5636 bool has_bptc = false; /* BC6H and BC7 */
5637 bool has_pvrtc = false;
5638 #if defined(__EMSCRIPTEN__)
5639 bool has_etc2 = false;
5640 #else
5641 bool has_etc2 = true;
5642 #endif
5643 bool has_colorbuffer_float = false;
5644 bool has_colorbuffer_half_float = false;
5645 bool has_texture_float_linear = false;
5646 bool has_float_blend = false;
5647 GLint num_ext = 0;
5648 glGetIntegerv(GL_NUM_EXTENSIONS, &num_ext);
5649 for (int i = 0; i < num_ext; i++) {
5650 const char* ext = (const char*) glGetStringi(GL_EXTENSIONS, (GLuint)i);
5651 if (ext) {
5652 if (strstr(ext, "_texture_compression_s3tc")) {
5653 has_s3tc = true;
5654 }
5655 else if (strstr(ext, "_compressed_texture_s3tc")) {
5656 has_s3tc = true;
5657 }
5658 else if (strstr(ext, "_texture_compression_rgtc")) {
5659 has_rgtc = true;
5660 }
5661 else if (strstr(ext, "_texture_compression_bptc")) {
5662 has_bptc = true;
5663 }
5664 else if (strstr(ext, "_texture_compression_pvrtc")) {
5665 has_pvrtc = true;
5666 }
5667 else if (strstr(ext, "_compressed_texture_pvrtc")) {
5668 has_pvrtc = true;
5669 }
5670 else if (strstr(ext, "_compressed_texture_etc")) {
5671 has_etc2 = true;
5672 }
5673 else if (strstr(ext, "_color_buffer_float")) {
5674 has_colorbuffer_float = true;
5675 }
5676 else if (strstr(ext, "_color_buffer_half_float")) {
5677 has_colorbuffer_half_float = true;
5678 }
5679 else if (strstr(ext, "_texture_float_linear")) {
5680 has_texture_float_linear = true;
5681 }
5682 else if (strstr(ext, "_float_blend")) {
5683 has_float_blend = true;
5684 }
5685 else if (strstr(ext, "_texture_filter_anisotropic")) {
5686 _sg.gl.ext_anisotropic = true;
5687 }
5688 }
5689 }
5690
5691 /* on WebGL2, color_buffer_float also includes 16-bit formats
5692 see: https://developer.mozilla.org/en-US/docs/Web/API/EXT_color_buffer_float
5693 */
5694 #if defined(__EMSCRIPTEN__)
5695 has_colorbuffer_half_float = has_colorbuffer_float;
5696 #endif
5697
5698 /* limits */
5699 _sg_gl_init_limits();
5700
5701 /* pixel formats */
5702 const bool has_texture_half_float_linear = true;
5703 const bool has_bgra = false; /* not a bug */
5704 _sg_gl_init_pixelformats(has_bgra);
5705 _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend);
5706 _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float, has_texture_half_float_linear);
5707 if (has_s3tc) {
5708 _sg_gl_init_pixelformats_s3tc();
5709 }
5710 if (has_rgtc) {
5711 _sg_gl_init_pixelformats_rgtc();
5712 }
5713 if (has_bptc) {
5714 _sg_gl_init_pixelformats_bptc();
5715 }
5716 if (has_pvrtc) {
5717 _sg_gl_init_pixelformats_pvrtc();
5718 }
5719 if (has_etc2) {
5720 _sg_gl_init_pixelformats_etc2();
5721 }
5722}
5723#endif
5724
5725#if defined(SOKOL_GLES3) || defined(SOKOL_GLES2)
5726_SOKOL_PRIVATE void _sg_gl_init_caps_gles2(void) {
5727 _sg.backend = SG_BACKEND_GLES2;
5728
5729 bool has_s3tc = false; /* BC1..BC3 */
5730 bool has_rgtc = false; /* BC4 and BC5 */
5731 bool has_bptc = false; /* BC6H and BC7 */
5732 bool has_pvrtc = false;
5733 bool has_etc2 = false;
5734 bool has_texture_float = false;
5735 bool has_texture_float_linear = false;
5736 bool has_colorbuffer_float = false;
5737 bool has_float_blend = false;
5738 bool has_instancing = false;
5739 const char* ext = (const char*) glGetString(GL_EXTENSIONS);
5740 if (ext) {
5741 has_s3tc = strstr(ext, "_texture_compression_s3tc") || strstr(ext, "_compressed_texture_s3tc");
5742 has_rgtc = strstr(ext, "_texture_compression_rgtc");
5743 has_bptc = strstr(ext, "_texture_compression_bptc");
5744 has_pvrtc = strstr(ext, "_texture_compression_pvrtc") || strstr(ext, "_compressed_texture_pvrtc");
5745 has_etc2 = strstr(ext, "_compressed_texture_etc");
5746 has_texture_float = strstr(ext, "_texture_float");
5747 has_texture_float_linear = strstr(ext, "_texture_float_linear");
5748 has_colorbuffer_float = strstr(ext, "_color_buffer_float");
5749 has_float_blend = strstr(ext, "_float_blend");
5750 /* don't bother with half_float support on WebGL1
5751 has_texture_half_float = strstr(ext, "_texture_half_float");
5752 has_texture_half_float_linear = strstr(ext, "_texture_half_float_linear");
5753 has_colorbuffer_half_float = strstr(ext, "_color_buffer_half_float");
5754 */
5755 has_instancing = strstr(ext, "_instanced_arrays");
5756 _sg.gl.ext_anisotropic = strstr(ext, "ext_anisotropic");
5757 }
5758
5759 _sg.features.origin_top_left = false;
5760 #if defined(_SOKOL_GL_INSTANCING_ENABLED)
5761 _sg.features.instancing = has_instancing;
5762 #endif
5763 _sg.features.multiple_render_targets = false;
5764 _sg.features.msaa_render_targets = false;
5765 _sg.features.imagetype_3d = false;
5766 _sg.features.imagetype_array = false;
5767 _sg.features.image_clamp_to_border = false;
5768 _sg.features.mrt_independent_blend_state = false;
5769 _sg.features.mrt_independent_write_mask = false;
5770
5771 /* limits */
5772 _sg_gl_init_limits();
5773
5774 /* pixel formats */
5775 const bool has_bgra = false; /* not a bug */
5776 const bool has_texture_half_float = false;
5777 const bool has_texture_half_float_linear = false;
5778 const bool has_colorbuffer_half_float = false;
5779 _sg_gl_init_pixelformats(has_bgra);
5780 if (has_texture_float) {
5781 _sg_gl_init_pixelformats_float(has_colorbuffer_float, has_texture_float_linear, has_float_blend);
5782 }
5783 if (has_texture_half_float) {
5784 _sg_gl_init_pixelformats_half_float(has_colorbuffer_half_float, has_texture_half_float_linear);
5785 }
5786 if (has_s3tc) {
5787 _sg_gl_init_pixelformats_s3tc();
5788 }
5789 if (has_rgtc) {
5790 _sg_gl_init_pixelformats_rgtc();
5791 }
5792 if (has_bptc) {
5793 _sg_gl_init_pixelformats_bptc();
5794 }
5795 if (has_pvrtc) {
5796 _sg_gl_init_pixelformats_pvrtc();
5797 }
5798 if (has_etc2) {
5799 _sg_gl_init_pixelformats_etc2();
5800 }
5801 /* GLES2 doesn't allow multi-sampled render targets at all */
5802 for (int i = 0; i < _SG_PIXELFORMAT_NUM; i++) {
5803 _sg.formats[i].msaa = false;
5804 }
5805}
5806#endif
5807
5808/*-- state cache implementation ----------------------------------------------*/
5809_SOKOL_PRIVATE void _sg_gl_cache_clear_buffer_bindings(bool force) {
5810 if (force || (_sg.gl.cache.vertex_buffer != 0)) {
5811 glBindBuffer(GL_ARRAY_BUFFER, 0);
5812 _sg.gl.cache.vertex_buffer = 0;
5813 }
5814 if (force || (_sg.gl.cache.index_buffer != 0)) {
5815 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
5816 _sg.gl.cache.index_buffer = 0;
5817 }
5818}
5819
5820_SOKOL_PRIVATE void _sg_gl_cache_bind_buffer(GLenum target, GLuint buffer) {
5821 SOKOL_ASSERT((GL_ARRAY_BUFFER == target) || (GL_ELEMENT_ARRAY_BUFFER == target));
5822 if (target == GL_ARRAY_BUFFER) {
5823 if (_sg.gl.cache.vertex_buffer != buffer) {
5824 _sg.gl.cache.vertex_buffer = buffer;
5825 glBindBuffer(target, buffer);
5826 }
5827 }
5828 else {
5829 if (_sg.gl.cache.index_buffer != buffer) {
5830 _sg.gl.cache.index_buffer = buffer;
5831 glBindBuffer(target, buffer);
5832 }
5833 }
5834}
5835
5836_SOKOL_PRIVATE void _sg_gl_cache_store_buffer_binding(GLenum target) {
5837 if (target == GL_ARRAY_BUFFER) {
5838 _sg.gl.cache.stored_vertex_buffer = _sg.gl.cache.vertex_buffer;
5839 }
5840 else {
5841 _sg.gl.cache.stored_index_buffer = _sg.gl.cache.index_buffer;
5842 }
5843}
5844
5845_SOKOL_PRIVATE void _sg_gl_cache_restore_buffer_binding(GLenum target) {
5846 if (target == GL_ARRAY_BUFFER) {
5847 if (_sg.gl.cache.stored_vertex_buffer != 0) {
5848 /* we only care restoring valid ids */
5849 _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_vertex_buffer);
5850 _sg.gl.cache.stored_vertex_buffer = 0;
5851 }
5852 }
5853 else {
5854 if (_sg.gl.cache.stored_index_buffer != 0) {
5855 /* we only care restoring valid ids */
5856 _sg_gl_cache_bind_buffer(target, _sg.gl.cache.stored_index_buffer);
5857 _sg.gl.cache.stored_index_buffer = 0;
5858 }
5859 }
5860}
5861
5862/* called when from _sg_gl_destroy_buffer() */
5863_SOKOL_PRIVATE void _sg_gl_cache_invalidate_buffer(GLuint buf) {
5864 if (buf == _sg.gl.cache.vertex_buffer) {
5865 _sg.gl.cache.vertex_buffer = 0;
5866 glBindBuffer(GL_ARRAY_BUFFER, 0);
5867 }
5868 if (buf == _sg.gl.cache.index_buffer) {
5869 _sg.gl.cache.index_buffer = 0;
5870 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
5871 }
5872 if (buf == _sg.gl.cache.stored_vertex_buffer) {
5873 _sg.gl.cache.stored_vertex_buffer = 0;
5874 }
5875 if (buf == _sg.gl.cache.stored_index_buffer) {
5876 _sg.gl.cache.stored_index_buffer = 0;
5877 }
5878 for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) {
5879 if (buf == _sg.gl.cache.attrs[i].gl_vbuf) {
5880 _sg.gl.cache.attrs[i].gl_vbuf = 0;
5881 }
5882 }
5883}
5884
5885_SOKOL_PRIVATE void _sg_gl_cache_active_texture(GLenum texture) {
5886 if (_sg.gl.cache.cur_active_texture != texture) {
5887 _sg.gl.cache.cur_active_texture = texture;
5888 glActiveTexture(texture);
5889 }
5890}
5891
5892_SOKOL_PRIVATE void _sg_gl_cache_clear_texture_bindings(bool force) {
5893 for (int i = 0; (i < SG_MAX_SHADERSTAGE_IMAGES) && (i < _sg.gl.max_combined_texture_image_units); i++) {
5894 if (force || (_sg.gl.cache.textures[i].texture != 0)) {
5895 GLenum gl_texture_slot = (GLenum) (GL_TEXTURE0 + i);
5896 glActiveTexture(gl_texture_slot);
5897 glBindTexture(GL_TEXTURE_2D, 0);
5898 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
5899 #if !defined(SOKOL_GLES2)
5900 if (!_sg.gl.gles2) {
5901 glBindTexture(GL_TEXTURE_3D, 0);
5902 glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
5903 }
5904 #endif
5905 _sg.gl.cache.textures[i].target = 0;
5906 _sg.gl.cache.textures[i].texture = 0;
5907 _sg.gl.cache.cur_active_texture = gl_texture_slot;
5908 }
5909 }
5910}
5911
5912_SOKOL_PRIVATE void _sg_gl_cache_bind_texture(int slot_index, GLenum target, GLuint texture) {
5913 /* it's valid to call this function with target=0 and/or texture=0
5914 target=0 will unbind the previous binding, texture=0 will clear
5915 the new binding
5916 */
5917 SOKOL_ASSERT(slot_index < SG_MAX_SHADERSTAGE_IMAGES);
5918 if (slot_index >= _sg.gl.max_combined_texture_image_units) {
5919 return;
5920 }
5921 _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.textures[slot_index];
5922 if ((slot->target != target) || (slot->texture != texture)) {
5923 _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + slot_index));
5924 /* if the target has changed, clear the previous binding on that target */
5925 if ((target != slot->target) && (slot->target != 0)) {
5926 glBindTexture(slot->target, 0);
5927 }
5928 /* apply new binding (texture can be 0 to unbind) */
5929 if (target != 0) {
5930 glBindTexture(target, texture);
5931 }
5932 slot->target = target;
5933 slot->texture = texture;
5934 }
5935}
5936
5937_SOKOL_PRIVATE void _sg_gl_cache_store_texture_binding(int slot_index) {
5938 SOKOL_ASSERT(slot_index < SG_MAX_SHADERSTAGE_IMAGES);
5939 _sg.gl.cache.stored_texture = _sg.gl.cache.textures[slot_index];
5940}
5941
5942_SOKOL_PRIVATE void _sg_gl_cache_restore_texture_binding(int slot_index) {
5943 SOKOL_ASSERT(slot_index < SG_MAX_SHADERSTAGE_IMAGES);
5944 _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.stored_texture;
5945 if (slot->texture != 0) {
5946 /* we only care restoring valid ids */
5947 SOKOL_ASSERT(slot->target != 0);
5948 _sg_gl_cache_bind_texture(slot_index, slot->target, slot->texture);
5949 slot->target = 0;
5950 slot->texture = 0;
5951 }
5952}
5953
5954/* called from _sg_gl_destroy_texture() */
5955_SOKOL_PRIVATE void _sg_gl_cache_invalidate_texture(GLuint tex) {
5956 for (int i = 0; i < SG_MAX_SHADERSTAGE_IMAGES; i++) {
5957 _sg_gl_texture_bind_slot* slot = &_sg.gl.cache.textures[i];
5958 if (tex == slot->texture) {
5959 _sg_gl_cache_active_texture((GLenum)(GL_TEXTURE0 + i));
5960 glBindTexture(slot->target, 0);
5961 slot->target = 0;
5962 slot->texture = 0;
5963 }
5964 }
5965 if (tex == _sg.gl.cache.stored_texture.texture) {
5966 _sg.gl.cache.stored_texture.target = 0;
5967 _sg.gl.cache.stored_texture.texture = 0;
5968 }
5969}
5970
5971/* called from _sg_gl_destroy_shader() */
5972_SOKOL_PRIVATE void _sg_gl_cache_invalidate_program(GLuint prog) {
5973 if (prog == _sg.gl.cache.prog) {
5974 _sg.gl.cache.prog = 0;
5975 glUseProgram(0);
5976 }
5977}
5978
5979_SOKOL_PRIVATE void _sg_gl_reset_state_cache(void) {
5980 if (_sg.gl.cur_context) {
5981 _SG_GL_CHECK_ERROR();
5982 #if !defined(SOKOL_GLES2)
5983 if (!_sg.gl.gles2) {
5984 glBindVertexArray(_sg.gl.cur_context->vao);
5985 _SG_GL_CHECK_ERROR();
5986 }
5987 #endif
5988 memset(&_sg.gl.cache, 0, sizeof(_sg.gl.cache));
5989 _sg_gl_cache_clear_buffer_bindings(true);
5990 _SG_GL_CHECK_ERROR();
5991 _sg_gl_cache_clear_texture_bindings(true);
5992 _SG_GL_CHECK_ERROR();
5993 for (int i = 0; i < _sg.limits.max_vertex_attrs; i++) {
5994 _sg_gl_attr_t* attr = &_sg.gl.cache.attrs[i].gl_attr;
5995 attr->vb_index = -1;
5996 attr->divisor = -1;
5997 glDisableVertexAttribArray((GLuint)i);
5998 _SG_GL_CHECK_ERROR();
5999 }
6000 _sg.gl.cache.cur_primitive_type = GL_TRIANGLES;
6001
6002 /* shader program */
6003 glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&_sg.gl.cache.prog);
6004 _SG_GL_CHECK_ERROR();
6005
6006 /* depth and stencil state */
6007 _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS;
6008 _sg.gl.cache.stencil.front.compare = SG_COMPAREFUNC_ALWAYS;
6009 _sg.gl.cache.stencil.front.fail_op = SG_STENCILOP_KEEP;
6010 _sg.gl.cache.stencil.front.depth_fail_op = SG_STENCILOP_KEEP;
6011 _sg.gl.cache.stencil.front.pass_op = SG_STENCILOP_KEEP;
6012 _sg.gl.cache.stencil.back.compare = SG_COMPAREFUNC_ALWAYS;
6013 _sg.gl.cache.stencil.back.fail_op = SG_STENCILOP_KEEP;
6014 _sg.gl.cache.stencil.back.depth_fail_op = SG_STENCILOP_KEEP;
6015 _sg.gl.cache.stencil.back.pass_op = SG_STENCILOP_KEEP;
6016 glEnable(GL_DEPTH_TEST);
6017 glDepthFunc(GL_ALWAYS);
6018 glDepthMask(GL_FALSE);
6019 glDisable(GL_STENCIL_TEST);
6020 glStencilFunc(GL_ALWAYS, 0, 0);
6021 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
6022 glStencilMask(0);
6023
6024 /* blend state */
6025 _sg.gl.cache.blend.src_factor_rgb = SG_BLENDFACTOR_ONE;
6026 _sg.gl.cache.blend.dst_factor_rgb = SG_BLENDFACTOR_ZERO;
6027 _sg.gl.cache.blend.op_rgb = SG_BLENDOP_ADD;
6028 _sg.gl.cache.blend.src_factor_alpha = SG_BLENDFACTOR_ONE;
6029 _sg.gl.cache.blend.dst_factor_alpha = SG_BLENDFACTOR_ZERO;
6030 _sg.gl.cache.blend.op_alpha = SG_BLENDOP_ADD;
6031 glDisable(GL_BLEND);
6032 glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO);
6033 glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
6034 glBlendColor(0.0f, 0.0f, 0.0f, 0.0f);
6035
6036 /* standalone state */
6037 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
6038 _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA;
6039 }
6040 _sg.gl.cache.cull_mode = SG_CULLMODE_NONE;
6041 _sg.gl.cache.face_winding = SG_FACEWINDING_CW;
6042 _sg.gl.cache.sample_count = 1;
6043 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6044 glPolygonOffset(0.0f, 0.0f);
6045 glDisable(GL_POLYGON_OFFSET_FILL);
6046 glDisable(GL_CULL_FACE);
6047 glFrontFace(GL_CW);
6048 glCullFace(GL_BACK);
6049 glEnable(GL_SCISSOR_TEST);
6050 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
6051 glEnable(GL_DITHER);
6052 glDisable(GL_POLYGON_OFFSET_FILL);
6053 #if defined(SOKOL_GLCORE33)
6054 glEnable(GL_MULTISAMPLE);
6055 glEnable(GL_PROGRAM_POINT_SIZE);
6056 #endif
6057 }
6058}
6059
6060_SOKOL_PRIVATE void _sg_gl_setup_backend(const sg_desc* desc) {
6061 /* assumes that _sg.gl is already zero-initialized */
6062 _sg.gl.valid = true;
6063 #if defined(SOKOL_GLES2) || defined(SOKOL_GLES3)
6064 _sg.gl.gles2 = desc->context.gl.force_gles2;
6065 #else
6066 _SOKOL_UNUSED(desc);
6067 _sg.gl.gles2 = false;
6068 #endif
6069
6070 #if defined(_SOKOL_USE_WIN32_GL_LOADER)
6071 _sg_gl_load_opengl();
6072 #endif
6073
6074 /* clear initial GL error state */
6075 #if defined(SOKOL_DEBUG)
6076 while (glGetError() != GL_NO_ERROR);
6077 #endif
6078 #if defined(SOKOL_GLCORE33)
6079 _sg_gl_init_caps_glcore33();
6080 #elif defined(SOKOL_GLES3)
6081 if (_sg.gl.gles2) {
6082 _sg_gl_init_caps_gles2();
6083 }
6084 else {
6085 _sg_gl_init_caps_gles3();
6086 }
6087 #else
6088 _sg_gl_init_caps_gles2();
6089 #endif
6090}
6091
6092_SOKOL_PRIVATE void _sg_gl_discard_backend(void) {
6093 SOKOL_ASSERT(_sg.gl.valid);
6094 _sg.gl.valid = false;
6095 #if defined(_SOKOL_USE_WIN32_GL_LOADER)
6096 _sg_gl_unload_opengl();
6097 #endif
6098}
6099
6100_SOKOL_PRIVATE void _sg_gl_activate_context(_sg_context_t* ctx) {
6101 SOKOL_ASSERT(_sg.gl.valid);
6102 /* NOTE: ctx can be 0 to unset the current context */
6103 _sg.gl.cur_context = ctx;
6104 _sg_gl_reset_state_cache();
6105}
6106
6107/*-- GL backend resource creation and destruction ----------------------------*/
6108_SOKOL_PRIVATE sg_resource_state _sg_gl_create_context(_sg_context_t* ctx) {
6109 SOKOL_ASSERT(ctx);
6110 SOKOL_ASSERT(0 == ctx->default_framebuffer);
6111 _SG_GL_CHECK_ERROR();
6112 glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&ctx->default_framebuffer);
6113 _SG_GL_CHECK_ERROR();
6114 #if !defined(SOKOL_GLES2)
6115 if (!_sg.gl.gles2) {
6116 SOKOL_ASSERT(0 == ctx->vao);
6117 glGenVertexArrays(1, &ctx->vao);
6118 glBindVertexArray(ctx->vao);
6119 _SG_GL_CHECK_ERROR();
6120 }
6121 #endif
6122 return SG_RESOURCESTATE_VALID;
6123}
6124
6125_SOKOL_PRIVATE void _sg_gl_destroy_context(_sg_context_t* ctx) {
6126 SOKOL_ASSERT(ctx);
6127 #if !defined(SOKOL_GLES2)
6128 if (!_sg.gl.gles2) {
6129 if (ctx->vao) {
6130 glDeleteVertexArrays(1, &ctx->vao);
6131 }
6132 _SG_GL_CHECK_ERROR();
6133 }
6134 #else
6135 _SOKOL_UNUSED(ctx);
6136 #endif
6137}
6138
6139_SOKOL_PRIVATE sg_resource_state _sg_gl_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) {
6140 SOKOL_ASSERT(buf && desc);
6141 _SG_GL_CHECK_ERROR();
6142 _sg_buffer_common_init(&buf->cmn, desc);
6143 buf->gl.ext_buffers = (0 != desc->gl_buffers[0]);
6144 GLenum gl_target = _sg_gl_buffer_target(buf->cmn.type);
6145 GLenum gl_usage = _sg_gl_usage(buf->cmn.usage);
6146 for (int slot = 0; slot < buf->cmn.num_slots; slot++) {
6147 GLuint gl_buf = 0;
6148 if (buf->gl.ext_buffers) {
6149 SOKOL_ASSERT(desc->gl_buffers[slot]);
6150 gl_buf = desc->gl_buffers[slot];
6151 }
6152 else {
6153 glGenBuffers(1, &gl_buf);
6154 _sg_gl_cache_store_buffer_binding(gl_target);
6155 _sg_gl_cache_bind_buffer(gl_target, gl_buf);
6156 glBufferData(gl_target, buf->cmn.size, 0, gl_usage);
6157 if (buf->cmn.usage == SG_USAGE_IMMUTABLE) {
6158 SOKOL_ASSERT(desc->data.ptr);
6159 glBufferSubData(gl_target, 0, buf->cmn.size, desc->data.ptr);
6160 }
6161 _sg_gl_cache_restore_buffer_binding(gl_target);
6162 }
6163 buf->gl.buf[slot] = gl_buf;
6164 }
6165 _SG_GL_CHECK_ERROR();
6166 return SG_RESOURCESTATE_VALID;
6167}
6168
6169_SOKOL_PRIVATE void _sg_gl_destroy_buffer(_sg_buffer_t* buf) {
6170 SOKOL_ASSERT(buf);
6171 _SG_GL_CHECK_ERROR();
6172 for (int slot = 0; slot < buf->cmn.num_slots; slot++) {
6173 if (buf->gl.buf[slot]) {
6174 _sg_gl_cache_invalidate_buffer(buf->gl.buf[slot]);
6175 if (!buf->gl.ext_buffers) {
6176 glDeleteBuffers(1, &buf->gl.buf[slot]);
6177 }
6178 }
6179 }
6180 _SG_GL_CHECK_ERROR();
6181}
6182
6183_SOKOL_PRIVATE bool _sg_gl_supported_texture_format(sg_pixel_format fmt) {
6184 const int fmt_index = (int) fmt;
6185 SOKOL_ASSERT((fmt_index > SG_PIXELFORMAT_NONE) && (fmt_index < _SG_PIXELFORMAT_NUM));
6186 return _sg.formats[fmt_index].sample;
6187}
6188
6189_SOKOL_PRIVATE sg_resource_state _sg_gl_create_image(_sg_image_t* img, const sg_image_desc* desc) {
6190 SOKOL_ASSERT(img && desc);
6191 _SG_GL_CHECK_ERROR();
6192 _sg_image_common_init(&img->cmn, desc);
6193 img->gl.ext_textures = (0 != desc->gl_textures[0]);
6194
6195 /* check if texture format is support */
6196 if (!_sg_gl_supported_texture_format(img->cmn.pixel_format)) {
6197 SOKOL_LOG("texture format not supported by GL context\n");
6198 return SG_RESOURCESTATE_FAILED;
6199 }
6200 /* check for optional texture types */
6201 if ((img->cmn.type == SG_IMAGETYPE_3D) && !_sg.features.imagetype_3d) {
6202 SOKOL_LOG("3D textures not supported by GL context\n");
6203 return SG_RESOURCESTATE_FAILED;
6204 }
6205 if ((img->cmn.type == SG_IMAGETYPE_ARRAY) && !_sg.features.imagetype_array) {
6206 SOKOL_LOG("array textures not supported by GL context\n");
6207 return SG_RESOURCESTATE_FAILED;
6208 }
6209
6210 #if !defined(SOKOL_GLES2)
6211 bool msaa = false;
6212 if (!_sg.gl.gles2) {
6213 msaa = (img->cmn.sample_count > 1) && (_sg.features.msaa_render_targets);
6214 }
6215 #endif
6216
6217 if (_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format)) {
6218 /* special case depth-stencil-buffer? */
6219 SOKOL_ASSERT((img->cmn.usage == SG_USAGE_IMMUTABLE) && (img->cmn.num_slots == 1));
6220 SOKOL_ASSERT(!img->gl.ext_textures); /* cannot provide external texture for depth images */
6221 glGenRenderbuffers(1, &img->gl.depth_render_buffer);
6222 glBindRenderbuffer(GL_RENDERBUFFER, img->gl.depth_render_buffer);
6223 GLenum gl_depth_format = _sg_gl_depth_attachment_format(img->cmn.pixel_format);
6224 #if !defined(SOKOL_GLES2)
6225 if (!_sg.gl.gles2 && msaa) {
6226 glRenderbufferStorageMultisample(GL_RENDERBUFFER, img->cmn.sample_count, gl_depth_format, img->cmn.width, img->cmn.height);
6227 }
6228 else
6229 #endif
6230 {
6231 glRenderbufferStorage(GL_RENDERBUFFER, gl_depth_format, img->cmn.width, img->cmn.height);
6232 }
6233 }
6234 else {
6235 /* regular color texture */
6236 img->gl.target = _sg_gl_texture_target(img->cmn.type);
6237 const GLenum gl_internal_format = _sg_gl_teximage_internal_format(img->cmn.pixel_format);
6238
6239 /* if this is a MSAA render target, need to create a separate render buffer */
6240 #if !defined(SOKOL_GLES2)
6241 if (!_sg.gl.gles2 && img->cmn.render_target && msaa) {
6242 glGenRenderbuffers(1, &img->gl.msaa_render_buffer);
6243 glBindRenderbuffer(GL_RENDERBUFFER, img->gl.msaa_render_buffer);
6244 glRenderbufferStorageMultisample(GL_RENDERBUFFER, img->cmn.sample_count, gl_internal_format, img->cmn.width, img->cmn.height);
6245 }
6246 #endif
6247
6248 if (img->gl.ext_textures) {
6249 /* inject externally GL textures */
6250 for (int slot = 0; slot < img->cmn.num_slots; slot++) {
6251 SOKOL_ASSERT(desc->gl_textures[slot]);
6252 img->gl.tex[slot] = desc->gl_textures[slot];
6253 }
6254 if (desc->gl_texture_target) {
6255 img->gl.target = (GLenum)desc->gl_texture_target;
6256 }
6257 }
6258 else {
6259 /* create our own GL texture(s) */
6260 const GLenum gl_format = _sg_gl_teximage_format(img->cmn.pixel_format);
6261 const bool is_compressed = _sg_is_compressed_pixel_format(img->cmn.pixel_format);
6262 for (int slot = 0; slot < img->cmn.num_slots; slot++) {
6263 glGenTextures(1, &img->gl.tex[slot]);
6264 SOKOL_ASSERT(img->gl.tex[slot]);
6265 _sg_gl_cache_store_texture_binding(0);
6266 _sg_gl_cache_bind_texture(0, img->gl.target, img->gl.tex[slot]);
6267 GLenum gl_min_filter = _sg_gl_filter(img->cmn.min_filter);
6268 GLenum gl_mag_filter = _sg_gl_filter(img->cmn.mag_filter);
6269 glTexParameteri(img->gl.target, GL_TEXTURE_MIN_FILTER, (GLint)gl_min_filter);
6270 glTexParameteri(img->gl.target, GL_TEXTURE_MAG_FILTER, (GLint)gl_mag_filter);
6271 if (_sg.gl.ext_anisotropic && (img->cmn.max_anisotropy > 1)) {
6272 GLint max_aniso = (GLint) img->cmn.max_anisotropy;
6273 if (max_aniso > _sg.gl.max_anisotropy) {
6274 max_aniso = _sg.gl.max_anisotropy;
6275 }
6276 glTexParameteri(img->gl.target, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);
6277 }
6278 if (img->cmn.type == SG_IMAGETYPE_CUBE) {
6279 glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6280 glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6281 }
6282 else {
6283 glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_S, (GLint)_sg_gl_wrap(img->cmn.wrap_u));
6284 glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_T, (GLint)_sg_gl_wrap(img->cmn.wrap_v));
6285 #if !defined(SOKOL_GLES2)
6286 if (!_sg.gl.gles2 && (img->cmn.type == SG_IMAGETYPE_3D)) {
6287 glTexParameteri(img->gl.target, GL_TEXTURE_WRAP_R, (GLint)_sg_gl_wrap(img->cmn.wrap_w));
6288 }
6289 #endif
6290 #if defined(SOKOL_GLCORE33)
6291 float border[4];
6292 switch (img->cmn.border_color) {
6293 case SG_BORDERCOLOR_TRANSPARENT_BLACK:
6294 border[0] = 0.0f; border[1] = 0.0f; border[2] = 0.0f; border[3] = 0.0f;
6295 break;
6296 case SG_BORDERCOLOR_OPAQUE_WHITE:
6297 border[0] = 1.0f; border[1] = 1.0f; border[2] = 1.0f; border[3] = 1.0f;
6298 break;
6299 default:
6300 border[0] = 0.0f; border[1] = 0.0f; border[2] = 0.0f; border[3] = 1.0f;
6301 break;
6302 }
6303 glTexParameterfv(img->gl.target, GL_TEXTURE_BORDER_COLOR, border);
6304 #endif
6305 }
6306 #if !defined(SOKOL_GLES2)
6307 if (!_sg.gl.gles2) {
6308 /* GL spec has strange defaults for mipmap min/max lod: -1000 to +1000 */
6309 const float min_lod = _sg_clamp(desc->min_lod, 0.0f, 1000.0f);
6310 const float max_lod = _sg_clamp(desc->max_lod, 0.0f, 1000.0f);
6311 glTexParameterf(img->gl.target, GL_TEXTURE_MIN_LOD, min_lod);
6312 glTexParameterf(img->gl.target, GL_TEXTURE_MAX_LOD, max_lod);
6313 }
6314 #endif
6315 const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1;
6316 int data_index = 0;
6317 for (int face_index = 0; face_index < num_faces; face_index++) {
6318 for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, data_index++) {
6319 GLenum gl_img_target = img->gl.target;
6320 if (SG_IMAGETYPE_CUBE == img->cmn.type) {
6321 gl_img_target = _sg_gl_cubeface_target(face_index);
6322 }
6323 const GLvoid* data_ptr = desc->data.subimage[face_index][mip_index].ptr;
6324 const GLsizei data_size = (GLsizei) desc->data.subimage[face_index][mip_index].size;
6325 int mip_width = img->cmn.width >> mip_index;
6326 if (mip_width == 0) {
6327 mip_width = 1;
6328 }
6329 int mip_height = img->cmn.height >> mip_index;
6330 if (mip_height == 0) {
6331 mip_height = 1;
6332 }
6333 if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) {
6334 if (is_compressed) {
6335 glCompressedTexImage2D(gl_img_target, mip_index, gl_internal_format,
6336 mip_width, mip_height, 0, data_size, data_ptr);
6337 }
6338 else {
6339 const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format);
6340 glTexImage2D(gl_img_target, mip_index, (GLint)gl_internal_format,
6341 mip_width, mip_height, 0, gl_format, gl_type, data_ptr);
6342 }
6343 }
6344 #if !defined(SOKOL_GLES2)
6345 else if (!_sg.gl.gles2 && ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type))) {
6346 int mip_depth = img->cmn.num_slices;
6347 if (SG_IMAGETYPE_3D == img->cmn.type) {
6348 mip_depth >>= mip_index;
6349 }
6350 if (mip_depth == 0) {
6351 mip_depth = 1;
6352 }
6353 if (is_compressed) {
6354 glCompressedTexImage3D(gl_img_target, mip_index, gl_internal_format,
6355 mip_width, mip_height, mip_depth, 0, data_size, data_ptr);
6356 }
6357 else {
6358 const GLenum gl_type = _sg_gl_teximage_type(img->cmn.pixel_format);
6359 glTexImage3D(gl_img_target, mip_index, (GLint)gl_internal_format,
6360 mip_width, mip_height, mip_depth, 0, gl_format, gl_type, data_ptr);
6361 }
6362 }
6363 #endif
6364 }
6365 }
6366 _sg_gl_cache_restore_texture_binding(0);
6367 }
6368 }
6369 }
6370 _SG_GL_CHECK_ERROR();
6371 return SG_RESOURCESTATE_VALID;
6372}
6373
6374_SOKOL_PRIVATE void _sg_gl_destroy_image(_sg_image_t* img) {
6375 SOKOL_ASSERT(img);
6376 _SG_GL_CHECK_ERROR();
6377 for (int slot = 0; slot < img->cmn.num_slots; slot++) {
6378 if (img->gl.tex[slot]) {
6379 _sg_gl_cache_invalidate_texture(img->gl.tex[slot]);
6380 if (!img->gl.ext_textures) {
6381 glDeleteTextures(1, &img->gl.tex[slot]);
6382 }
6383 }
6384 }
6385 if (img->gl.depth_render_buffer) {
6386 glDeleteRenderbuffers(1, &img->gl.depth_render_buffer);
6387 }
6388 if (img->gl.msaa_render_buffer) {
6389 glDeleteRenderbuffers(1, &img->gl.msaa_render_buffer);
6390 }
6391 _SG_GL_CHECK_ERROR();
6392}
6393
6394_SOKOL_PRIVATE GLuint _sg_gl_compile_shader(sg_shader_stage stage, const char* src) {
6395 SOKOL_ASSERT(src);
6396 _SG_GL_CHECK_ERROR();
6397 GLuint gl_shd = glCreateShader(_sg_gl_shader_stage(stage));
6398 glShaderSource(gl_shd, 1, &src, 0);
6399 glCompileShader(gl_shd);
6400 GLint compile_status = 0;
6401 glGetShaderiv(gl_shd, GL_COMPILE_STATUS, &compile_status);
6402 if (!compile_status) {
6403 /* compilation failed, log error and delete shader */
6404 GLint log_len = 0;
6405 glGetShaderiv(gl_shd, GL_INFO_LOG_LENGTH, &log_len);
6406 if (log_len > 0) {
6407 GLchar* log_buf = (GLchar*) SOKOL_MALLOC((size_t)log_len);
6408 glGetShaderInfoLog(gl_shd, log_len, &log_len, log_buf);
6409 SOKOL_LOG(log_buf);
6410 SOKOL_FREE(log_buf);
6411 }
6412 glDeleteShader(gl_shd);
6413 gl_shd = 0;
6414 }
6415 _SG_GL_CHECK_ERROR();
6416 return gl_shd;
6417}
6418
6419_SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const sg_shader_desc* desc) {
6420 SOKOL_ASSERT(shd && desc);
6421 SOKOL_ASSERT(!shd->gl.prog);
6422 _SG_GL_CHECK_ERROR();
6423
6424 _sg_shader_common_init(&shd->cmn, desc);
6425
6426 /* copy vertex attribute names over, these are required for GLES2, and optional for GLES3 and GL3.x */
6427 for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) {
6428 _sg_strcpy(&shd->gl.attrs[i].name, desc->attrs[i].name);
6429 }
6430
6431 GLuint gl_vs = _sg_gl_compile_shader(SG_SHADERSTAGE_VS, desc->vs.source);
6432 GLuint gl_fs = _sg_gl_compile_shader(SG_SHADERSTAGE_FS, desc->fs.source);
6433 if (!(gl_vs && gl_fs)) {
6434 return SG_RESOURCESTATE_FAILED;
6435 }
6436 GLuint gl_prog = glCreateProgram();
6437 glAttachShader(gl_prog, gl_vs);
6438 glAttachShader(gl_prog, gl_fs);
6439 glLinkProgram(gl_prog);
6440 glDeleteShader(gl_vs);
6441 glDeleteShader(gl_fs);
6442 _SG_GL_CHECK_ERROR();
6443
6444 GLint link_status;
6445 glGetProgramiv(gl_prog, GL_LINK_STATUS, &link_status);
6446 if (!link_status) {
6447 GLint log_len = 0;
6448 glGetProgramiv(gl_prog, GL_INFO_LOG_LENGTH, &log_len);
6449 if (log_len > 0) {
6450 GLchar* log_buf = (GLchar*) SOKOL_MALLOC((size_t)log_len);
6451 glGetProgramInfoLog(gl_prog, log_len, &log_len, log_buf);
6452 SOKOL_LOG(log_buf);
6453 SOKOL_FREE(log_buf);
6454 }
6455 glDeleteProgram(gl_prog);
6456 return SG_RESOURCESTATE_FAILED;
6457 }
6458 shd->gl.prog = gl_prog;
6459
6460 /* resolve uniforms */
6461 _SG_GL_CHECK_ERROR();
6462 for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) {
6463 const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &desc->vs : &desc->fs;
6464 _sg_gl_shader_stage_t* gl_stage = &shd->gl.stage[stage_index];
6465 for (int ub_index = 0; ub_index < shd->cmn.stage[stage_index].num_uniform_blocks; ub_index++) {
6466 const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index];
6467 SOKOL_ASSERT(ub_desc->size > 0);
6468 _sg_gl_uniform_block_t* ub = &gl_stage->uniform_blocks[ub_index];
6469 SOKOL_ASSERT(ub->num_uniforms == 0);
6470 int cur_uniform_offset = 0;
6471 for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) {
6472 const sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index];
6473 if (u_desc->type == SG_UNIFORMTYPE_INVALID) {
6474 break;
6475 }
6476 _sg_gl_uniform_t* u = &ub->uniforms[u_index];
6477 u->type = u_desc->type;
6478 u->count = (uint8_t) u_desc->array_count;
6479 u->offset = (uint16_t) cur_uniform_offset;
6480 cur_uniform_offset += _sg_uniform_size(u->type, u->count);
6481 if (u_desc->name) {
6482 u->gl_loc = glGetUniformLocation(gl_prog, u_desc->name);
6483 }
6484 else {
6485 u->gl_loc = u_index;
6486 }
6487 ub->num_uniforms++;
6488 }
6489 SOKOL_ASSERT(ub_desc->size == (size_t)cur_uniform_offset);
6490 }
6491 }
6492
6493 /* resolve image locations */
6494 _SG_GL_CHECK_ERROR();
6495 GLuint cur_prog = 0;
6496 glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&cur_prog);
6497 glUseProgram(gl_prog);
6498 int gl_tex_slot = 0;
6499 for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) {
6500 const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS)? &desc->vs : &desc->fs;
6501 _sg_gl_shader_stage_t* gl_stage = &shd->gl.stage[stage_index];
6502 for (int img_index = 0; img_index < shd->cmn.stage[stage_index].num_images; img_index++) {
6503 const sg_shader_image_desc* img_desc = &stage_desc->images[img_index];
6504 SOKOL_ASSERT(img_desc->image_type != _SG_IMAGETYPE_DEFAULT);
6505 _sg_gl_shader_image_t* gl_img = &gl_stage->images[img_index];
6506 GLint gl_loc = img_index;
6507 if (img_desc->name) {
6508 gl_loc = glGetUniformLocation(gl_prog, img_desc->name);
6509 }
6510 if (gl_loc != -1) {
6511 gl_img->gl_tex_slot = gl_tex_slot++;
6512 glUniform1i(gl_loc, gl_img->gl_tex_slot);
6513 }
6514 else {
6515 gl_img->gl_tex_slot = -1;
6516 }
6517 }
6518 }
6519 /* it's legal to call glUseProgram with 0 */
6520 glUseProgram(cur_prog);
6521 _SG_GL_CHECK_ERROR();
6522 return SG_RESOURCESTATE_VALID;
6523}
6524
6525_SOKOL_PRIVATE void _sg_gl_destroy_shader(_sg_shader_t* shd) {
6526 SOKOL_ASSERT(shd);
6527 _SG_GL_CHECK_ERROR();
6528 if (shd->gl.prog) {
6529 _sg_gl_cache_invalidate_program(shd->gl.prog);
6530 glDeleteProgram(shd->gl.prog);
6531 }
6532 _SG_GL_CHECK_ERROR();
6533}
6534
6535_SOKOL_PRIVATE sg_resource_state _sg_gl_create_pipeline(_sg_pipeline_t* pip, _sg_shader_t* shd, const sg_pipeline_desc* desc) {
6536 SOKOL_ASSERT(pip && shd && desc);
6537 SOKOL_ASSERT(!pip->shader && pip->cmn.shader_id.id == SG_INVALID_ID);
6538 SOKOL_ASSERT(desc->shader.id == shd->slot.id);
6539 SOKOL_ASSERT(shd->gl.prog);
6540 pip->shader = shd;
6541 _sg_pipeline_common_init(&pip->cmn, desc);
6542 pip->gl.primitive_type = desc->primitive_type;
6543 pip->gl.depth = desc->depth;
6544 pip->gl.stencil = desc->stencil;
6545 // FIXME: blend color and write mask per draw-buffer-attachment (requires GL4)
6546 pip->gl.blend = desc->colors[0].blend;
6547 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
6548 pip->gl.color_write_mask[i] = desc->colors[i].write_mask;
6549 }
6550 pip->gl.cull_mode = desc->cull_mode;
6551 pip->gl.face_winding = desc->face_winding;
6552 pip->gl.sample_count = desc->sample_count;
6553 pip->gl.alpha_to_coverage_enabled = desc->alpha_to_coverage_enabled;
6554
6555 /* resolve vertex attributes */
6556 for (int attr_index = 0; attr_index < SG_MAX_VERTEX_ATTRIBUTES; attr_index++) {
6557 pip->gl.attrs[attr_index].vb_index = -1;
6558 }
6559 for (int attr_index = 0; attr_index < _sg.limits.max_vertex_attrs; attr_index++) {
6560 const sg_vertex_attr_desc* a_desc = &desc->layout.attrs[attr_index];
6561 if (a_desc->format == SG_VERTEXFORMAT_INVALID) {
6562 break;
6563 }
6564 SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS);
6565 const sg_buffer_layout_desc* l_desc = &desc->layout.buffers[a_desc->buffer_index];
6566 const sg_vertex_step step_func = l_desc->step_func;
6567 const int step_rate = l_desc->step_rate;
6568 GLint attr_loc = attr_index;
6569 if (!_sg_strempty(&shd->gl.attrs[attr_index].name)) {
6570 attr_loc = glGetAttribLocation(pip->shader->gl.prog, _sg_strptr(&shd->gl.attrs[attr_index].name));
6571 }
6572 SOKOL_ASSERT(attr_loc < (GLint)_sg.limits.max_vertex_attrs);
6573 if (attr_loc != -1) {
6574 _sg_gl_attr_t* gl_attr = &pip->gl.attrs[attr_loc];
6575 SOKOL_ASSERT(gl_attr->vb_index == -1);
6576 gl_attr->vb_index = (int8_t) a_desc->buffer_index;
6577 if (step_func == SG_VERTEXSTEP_PER_VERTEX) {
6578 gl_attr->divisor = 0;
6579 }
6580 else {
6581 gl_attr->divisor = (int8_t) step_rate;
6582 }
6583 SOKOL_ASSERT(l_desc->stride > 0);
6584 gl_attr->stride = (uint8_t) l_desc->stride;
6585 gl_attr->offset = a_desc->offset;
6586 gl_attr->size = (uint8_t) _sg_gl_vertexformat_size(a_desc->format);
6587 gl_attr->type = _sg_gl_vertexformat_type(a_desc->format);
6588 gl_attr->normalized = _sg_gl_vertexformat_normalized(a_desc->format);
6589 pip->cmn.vertex_layout_valid[a_desc->buffer_index] = true;
6590 }
6591 else {
6592 SOKOL_LOG("Vertex attribute not found in shader: ");
6593 SOKOL_LOG(_sg_strptr(&shd->gl.attrs[attr_index].name));
6594 }
6595 }
6596 return SG_RESOURCESTATE_VALID;
6597}
6598
6599_SOKOL_PRIVATE void _sg_gl_destroy_pipeline(_sg_pipeline_t* pip) {
6600 SOKOL_ASSERT(pip);
6601 _SOKOL_UNUSED(pip);
6602 /* empty */
6603}
6604
6605/*
6606 _sg_create_pass
6607
6608 att_imgs must point to a _sg_image* att_imgs[SG_MAX_COLOR_ATTACHMENTS+1] array,
6609 first entries are the color attachment images (or nullptr), last entry
6610 is the depth-stencil image (or nullptr).
6611*/
6612_SOKOL_PRIVATE sg_resource_state _sg_gl_create_pass(_sg_pass_t* pass, _sg_image_t** att_images, const sg_pass_desc* desc) {
6613 SOKOL_ASSERT(pass && att_images && desc);
6614 SOKOL_ASSERT(att_images && att_images[0]);
6615 _SG_GL_CHECK_ERROR();
6616
6617 _sg_pass_common_init(&pass->cmn, desc);
6618
6619 /* copy image pointers */
6620 const sg_pass_attachment_desc* att_desc;
6621 for (int i = 0; i < pass->cmn.num_color_atts; i++) {
6622 att_desc = &desc->color_attachments[i];
6623 SOKOL_ASSERT(att_desc->image.id != SG_INVALID_ID);
6624 SOKOL_ASSERT(0 == pass->gl.color_atts[i].image);
6625 SOKOL_ASSERT(att_images[i] && (att_images[i]->slot.id == att_desc->image.id));
6626 SOKOL_ASSERT(_sg_is_valid_rendertarget_color_format(att_images[i]->cmn.pixel_format));
6627 pass->gl.color_atts[i].image = att_images[i];
6628 }
6629 SOKOL_ASSERT(0 == pass->gl.ds_att.image);
6630 att_desc = &desc->depth_stencil_attachment;
6631 if (att_desc->image.id != SG_INVALID_ID) {
6632 const int ds_img_index = SG_MAX_COLOR_ATTACHMENTS;
6633 SOKOL_ASSERT(att_images[ds_img_index] && (att_images[ds_img_index]->slot.id == att_desc->image.id));
6634 SOKOL_ASSERT(_sg_is_valid_rendertarget_depth_format(att_images[ds_img_index]->cmn.pixel_format));
6635 pass->gl.ds_att.image = att_images[ds_img_index];
6636 }
6637
6638 /* store current framebuffer binding (restored at end of function) */
6639 GLuint gl_orig_fb;
6640 glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&gl_orig_fb);
6641
6642 /* create a framebuffer object */
6643 glGenFramebuffers(1, &pass->gl.fb);
6644 glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.fb);
6645
6646 /* attach msaa render buffer or textures */
6647 const bool is_msaa = (0 != att_images[0]->gl.msaa_render_buffer);
6648 if (is_msaa) {
6649 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
6650 const _sg_image_t* att_img = pass->gl.color_atts[i].image;
6651 if (att_img) {
6652 const GLuint gl_render_buffer = att_img->gl.msaa_render_buffer;
6653 SOKOL_ASSERT(gl_render_buffer);
6654 glFramebufferRenderbuffer(GL_FRAMEBUFFER, (GLenum)(GL_COLOR_ATTACHMENT0+i), GL_RENDERBUFFER, gl_render_buffer);
6655 }
6656 }
6657 }
6658 else {
6659 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
6660 const _sg_image_t* att_img = pass->gl.color_atts[i].image;
6661 const int mip_level = pass->cmn.color_atts[i].mip_level;
6662 const int slice = pass->cmn.color_atts[i].slice;
6663 if (att_img) {
6664 const GLuint gl_tex = att_img->gl.tex[0];
6665 SOKOL_ASSERT(gl_tex);
6666 const GLenum gl_att = (GLenum)(GL_COLOR_ATTACHMENT0 + i);
6667 switch (att_img->cmn.type) {
6668 case SG_IMAGETYPE_2D:
6669 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att, GL_TEXTURE_2D, gl_tex, mip_level);
6670 break;
6671 case SG_IMAGETYPE_CUBE:
6672 glFramebufferTexture2D(GL_FRAMEBUFFER, gl_att, _sg_gl_cubeface_target(slice), gl_tex, mip_level);
6673 break;
6674 default:
6675 /* 3D- or array-texture */
6676 #if !defined(SOKOL_GLES2)
6677 if (!_sg.gl.gles2) {
6678 glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_att, gl_tex, mip_level, slice);
6679 }
6680 #endif
6681 break;
6682 }
6683 }
6684 }
6685 }
6686
6687 /* attach depth-stencil buffer to framebuffer */
6688 if (pass->gl.ds_att.image) {
6689 const GLuint gl_render_buffer = pass->gl.ds_att.image->gl.depth_render_buffer;
6690 SOKOL_ASSERT(gl_render_buffer);
6691 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, gl_render_buffer);
6692 if (_sg_is_depth_stencil_format(pass->gl.ds_att.image->cmn.pixel_format)) {
6693 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, gl_render_buffer);
6694 }
6695 }
6696
6697 /* check if framebuffer is complete */
6698 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
6699 SOKOL_LOG("Framebuffer completeness check failed!\n");
6700 return SG_RESOURCESTATE_FAILED;
6701 }
6702
6703 /* setup color attachments for the framebuffer */
6704 #if !defined(SOKOL_GLES2)
6705 if (!_sg.gl.gles2) {
6706 GLenum att[SG_MAX_COLOR_ATTACHMENTS] = {
6707 GL_COLOR_ATTACHMENT0,
6708 GL_COLOR_ATTACHMENT1,
6709 GL_COLOR_ATTACHMENT2,
6710 GL_COLOR_ATTACHMENT3
6711 };
6712 glDrawBuffers(pass->cmn.num_color_atts, att);
6713 }
6714 #endif
6715
6716 /* create MSAA resolve framebuffers if necessary */
6717 if (is_msaa) {
6718 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
6719 _sg_gl_attachment_t* gl_att = &pass->gl.color_atts[i];
6720 _sg_pass_attachment_t* cmn_att = &pass->cmn.color_atts[i];
6721 if (gl_att->image) {
6722 SOKOL_ASSERT(0 == gl_att->gl_msaa_resolve_buffer);
6723 glGenFramebuffers(1, &gl_att->gl_msaa_resolve_buffer);
6724 glBindFramebuffer(GL_FRAMEBUFFER, gl_att->gl_msaa_resolve_buffer);
6725 const GLuint gl_tex = gl_att->image->gl.tex[0];
6726 SOKOL_ASSERT(gl_tex);
6727 switch (gl_att->image->cmn.type) {
6728 case SG_IMAGETYPE_2D:
6729 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
6730 GL_TEXTURE_2D, gl_tex, cmn_att->mip_level);
6731 break;
6732 case SG_IMAGETYPE_CUBE:
6733 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
6734 _sg_gl_cubeface_target(cmn_att->slice), gl_tex, cmn_att->mip_level);
6735 break;
6736 default:
6737 #if !defined(SOKOL_GLES2)
6738 if (!_sg.gl.gles2) {
6739 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl_tex, cmn_att->mip_level, cmn_att->slice);
6740 }
6741 #endif
6742 break;
6743 }
6744 /* check if framebuffer is complete */
6745 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
6746 SOKOL_LOG("Framebuffer completeness check failed (msaa resolve buffer)!\n");
6747 return SG_RESOURCESTATE_FAILED;
6748 }
6749 /* setup color attachments for the framebuffer */
6750 #if !defined(SOKOL_GLES2)
6751 if (!_sg.gl.gles2) {
6752 const GLenum gl_draw_bufs = GL_COLOR_ATTACHMENT0;
6753 glDrawBuffers(1, &gl_draw_bufs);
6754 }
6755 #endif
6756 }
6757 }
6758 }
6759
6760 /* restore original framebuffer binding */
6761 glBindFramebuffer(GL_FRAMEBUFFER, gl_orig_fb);
6762 _SG_GL_CHECK_ERROR();
6763 return SG_RESOURCESTATE_VALID;
6764}
6765
6766_SOKOL_PRIVATE void _sg_gl_destroy_pass(_sg_pass_t* pass) {
6767 SOKOL_ASSERT(pass);
6768 _SG_GL_CHECK_ERROR();
6769 if (0 != pass->gl.fb) {
6770 glDeleteFramebuffers(1, &pass->gl.fb);
6771 }
6772 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
6773 if (pass->gl.color_atts[i].gl_msaa_resolve_buffer) {
6774 glDeleteFramebuffers(1, &pass->gl.color_atts[i].gl_msaa_resolve_buffer);
6775 }
6776 }
6777 if (pass->gl.ds_att.gl_msaa_resolve_buffer) {
6778 glDeleteFramebuffers(1, &pass->gl.ds_att.gl_msaa_resolve_buffer);
6779 }
6780 _SG_GL_CHECK_ERROR();
6781}
6782
6783_SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_color_image(const _sg_pass_t* pass, int index) {
6784 SOKOL_ASSERT(pass && (index >= 0) && (index < SG_MAX_COLOR_ATTACHMENTS));
6785 /* NOTE: may return null */
6786 return pass->gl.color_atts[index].image;
6787}
6788
6789_SOKOL_PRIVATE _sg_image_t* _sg_gl_pass_ds_image(const _sg_pass_t* pass) {
6790 /* NOTE: may return null */
6791 SOKOL_ASSERT(pass);
6792 return pass->gl.ds_att.image;
6793}
6794
6795_SOKOL_PRIVATE void _sg_gl_begin_pass(_sg_pass_t* pass, const sg_pass_action* action, int w, int h) {
6796 /* FIXME: what if a texture used as render target is still bound, should we
6797 unbind all currently bound textures in begin pass? */
6798 SOKOL_ASSERT(action);
6799 SOKOL_ASSERT(!_sg.gl.in_pass);
6800 _SG_GL_CHECK_ERROR();
6801 _sg.gl.in_pass = true;
6802 _sg.gl.cur_pass = pass; /* can be 0 */
6803 if (pass) {
6804 _sg.gl.cur_pass_id.id = pass->slot.id;
6805 }
6806 else {
6807 _sg.gl.cur_pass_id.id = SG_INVALID_ID;
6808 }
6809 _sg.gl.cur_pass_width = w;
6810 _sg.gl.cur_pass_height = h;
6811
6812 /* number of color attachments */
6813 const int num_color_atts = pass ? pass->cmn.num_color_atts : 1;
6814
6815 /* bind the render pass framebuffer */
6816 if (pass) {
6817 /* offscreen pass */
6818 SOKOL_ASSERT(pass->gl.fb);
6819 glBindFramebuffer(GL_FRAMEBUFFER, pass->gl.fb);
6820 }
6821 else {
6822 /* default pass */
6823 SOKOL_ASSERT(_sg.gl.cur_context);
6824 glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer);
6825 }
6826 glViewport(0, 0, w, h);
6827 glScissor(0, 0, w, h);
6828
6829 /* clear color and depth-stencil attachments if needed */
6830 bool clear_color = false;
6831 for (int i = 0; i < num_color_atts; i++) {
6832 if (SG_ACTION_CLEAR == action->colors[i].action) {
6833 clear_color = true;
6834 break;
6835 }
6836 }
6837 const bool clear_depth = (action->depth.action == SG_ACTION_CLEAR);
6838 const bool clear_stencil = (action->stencil.action == SG_ACTION_CLEAR);
6839
6840 bool need_pip_cache_flush = false;
6841 if (clear_color) {
6842 bool need_color_mask_flush = false;
6843 // NOTE: not a bug to iterate over all possible color attachments
6844 for (int i = 0; i < SG_MAX_COLOR_ATTACHMENTS; i++) {
6845 if (SG_COLORMASK_RGBA != _sg.gl.cache.color_write_mask[i]) {
6846 need_pip_cache_flush = true;
6847 need_color_mask_flush = true;
6848 _sg.gl.cache.color_write_mask[i] = SG_COLORMASK_RGBA;
6849 }
6850 }
6851 if (need_color_mask_flush) {
6852 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6853 }
6854 }
6855 if (clear_depth) {
6856 if (!_sg.gl.cache.depth.write_enabled) {
6857 need_pip_cache_flush = true;
6858 _sg.gl.cache.depth.write_enabled = true;
6859 glDepthMask(GL_TRUE);
6860 }
6861 if (_sg.gl.cache.depth.compare != SG_COMPAREFUNC_ALWAYS) {
6862 need_pip_cache_flush = true;
6863 _sg.gl.cache.depth.compare = SG_COMPAREFUNC_ALWAYS;
6864 glDepthFunc(GL_ALWAYS);
6865 }
6866 }
6867 if (clear_stencil) {
6868 if (_sg.gl.cache.stencil.write_mask != 0xFF) {
6869 need_pip_cache_flush = true;
6870 _sg.gl.cache.stencil.write_mask = 0xFF;
6871 glStencilMask(0xFF);
6872 }
6873 }
6874 if (need_pip_cache_flush) {
6875 /* we messed with the state cache directly, need to clear cached
6876 pipeline to force re-evaluation in next sg_apply_pipeline() */
6877 _sg.gl.cache.cur_pipeline = 0;
6878 _sg.gl.cache.cur_pipeline_id.id = SG_INVALID_ID;
6879 }
6880 bool use_mrt_clear = (0 != pass);
6881 #if defined(SOKOL_GLES2)
6882 use_mrt_clear = false;
6883 #else
6884 if (_sg.gl.gles2) {
6885 use_mrt_clear = false;
6886 }
6887 #endif
6888 if (!use_mrt_clear) {
6889 GLbitfield clear_mask = 0;
6890 if (clear_color) {
6891 clear_mask |= GL_COLOR_BUFFER_BIT;
6892 const sg_color c = action->colors[0].value;
6893 glClearColor(c.r, c.g, c.b, c.a);
6894 }
6895 if (clear_depth) {
6896 clear_mask |= GL_DEPTH_BUFFER_BIT;
6897 #ifdef SOKOL_GLCORE33
6898 glClearDepth(action->depth.value);
6899 #else
6900 glClearDepthf(action->depth.value);
6901 #endif
6902 }
6903 if (clear_stencil) {
6904 clear_mask |= GL_STENCIL_BUFFER_BIT;
6905 glClearStencil(action->stencil.value);
6906 }
6907 if (0 != clear_mask) {
6908 glClear(clear_mask);
6909 }
6910 }
6911 #if !defined SOKOL_GLES2
6912 else {
6913 SOKOL_ASSERT(pass);
6914 for (int i = 0; i < num_color_atts; i++) {
6915 if (action->colors[i].action == SG_ACTION_CLEAR) {
6916 glClearBufferfv(GL_COLOR, i, &action->colors[i].value.r);
6917 }
6918 }
6919 if (pass->gl.ds_att.image) {
6920 if (clear_depth && clear_stencil) {
6921 glClearBufferfi(GL_DEPTH_STENCIL, 0, action->depth.value, action->stencil.value);
6922 }
6923 else if (clear_depth) {
6924 glClearBufferfv(GL_DEPTH, 0, &action->depth.value);
6925 }
6926 else if (clear_stencil) {
6927 GLint val = (GLint) action->stencil.value;
6928 glClearBufferiv(GL_STENCIL, 0, &val);
6929 }
6930 }
6931 }
6932 #endif
6933 _SG_GL_CHECK_ERROR();
6934}
6935
6936_SOKOL_PRIVATE void _sg_gl_end_pass(void) {
6937 SOKOL_ASSERT(_sg.gl.in_pass);
6938 _SG_GL_CHECK_ERROR();
6939
6940 /* if this was an offscreen pass, and MSAA rendering was used, need
6941 to resolve into the pass images */
6942 #if !defined(SOKOL_GLES2)
6943 if (!_sg.gl.gles2 && _sg.gl.cur_pass) {
6944 /* check if the pass object is still valid */
6945 const _sg_pass_t* pass = _sg.gl.cur_pass;
6946 SOKOL_ASSERT(pass->slot.id == _sg.gl.cur_pass_id.id);
6947 bool is_msaa = (0 != _sg.gl.cur_pass->gl.color_atts[0].gl_msaa_resolve_buffer);
6948 if (is_msaa) {
6949 SOKOL_ASSERT(pass->gl.fb);
6950 glBindFramebuffer(GL_READ_FRAMEBUFFER, pass->gl.fb);
6951 SOKOL_ASSERT(pass->gl.color_atts[0].image);
6952 const int w = pass->gl.color_atts[0].image->cmn.width;
6953 const int h = pass->gl.color_atts[0].image->cmn.height;
6954 for (int att_index = 0; att_index < SG_MAX_COLOR_ATTACHMENTS; att_index++) {
6955 const _sg_gl_attachment_t* gl_att = &pass->gl.color_atts[att_index];
6956 if (gl_att->image) {
6957 SOKOL_ASSERT(gl_att->gl_msaa_resolve_buffer);
6958 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gl_att->gl_msaa_resolve_buffer);
6959 glReadBuffer((GLenum)(GL_COLOR_ATTACHMENT0 + att_index));
6960 glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
6961 }
6962 else {
6963 break;
6964 }
6965 }
6966 }
6967 }
6968 #endif
6969 _sg.gl.cur_pass = 0;
6970 _sg.gl.cur_pass_id.id = SG_INVALID_ID;
6971 _sg.gl.cur_pass_width = 0;
6972 _sg.gl.cur_pass_height = 0;
6973
6974 SOKOL_ASSERT(_sg.gl.cur_context);
6975 glBindFramebuffer(GL_FRAMEBUFFER, _sg.gl.cur_context->default_framebuffer);
6976 _sg.gl.in_pass = false;
6977 _SG_GL_CHECK_ERROR();
6978}
6979
6980_SOKOL_PRIVATE void _sg_gl_apply_viewport(int x, int y, int w, int h, bool origin_top_left) {
6981 SOKOL_ASSERT(_sg.gl.in_pass);
6982 y = origin_top_left ? (_sg.gl.cur_pass_height - (y+h)) : y;
6983 glViewport(x, y, w, h);
6984}
6985
6986_SOKOL_PRIVATE void _sg_gl_apply_scissor_rect(int x, int y, int w, int h, bool origin_top_left) {
6987 SOKOL_ASSERT(_sg.gl.in_pass);
6988 y = origin_top_left ? (_sg.gl.cur_pass_height - (y+h)) : y;
6989 glScissor(x, y, w, h);
6990}
6991
6992_SOKOL_PRIVATE void _sg_gl_apply_pipeline(_sg_pipeline_t* pip) {
6993 SOKOL_ASSERT(pip);
6994 SOKOL_ASSERT(pip->shader && (pip->cmn.shader_id.id == pip->shader->slot.id));
6995 _SG_GL_CHECK_ERROR();
6996 if ((_sg.gl.cache.cur_pipeline != pip) || (_sg.gl.cache.cur_pipeline_id.id != pip->slot.id)) {
6997 _sg.gl.cache.cur_pipeline = pip;
6998 _sg.gl.cache.cur_pipeline_id.id = pip->slot.id;
6999 _sg.gl.cache.cur_primitive_type = _sg_gl_primitive_type(pip->gl.primitive_type);
7000 _sg.gl.cache.cur_index_type = _sg_gl_index_type(pip->cmn.index_type);
7001
7002 /* update depth state */
7003 {
7004 const sg_depth_state* state_ds = &pip->gl.depth;
7005 sg_depth_state* cache_ds = &_sg.gl.cache.depth;
7006 if (state_ds->compare != cache_ds->compare) {
7007 cache_ds->compare = state_ds->compare;
7008 glDepthFunc(_sg_gl_compare_func(state_ds->compare));
7009 }
7010 if (state_ds->write_enabled != cache_ds->write_enabled) {
7011 cache_ds->write_enabled = state_ds->write_enabled;
7012 glDepthMask(state_ds->write_enabled);
7013 }
7014 if (!_sg_fequal(state_ds->bias, cache_ds->bias, 0.000001f) ||
7015 !_sg_fequal(state_ds->bias_slope_scale, cache_ds->bias_slope_scale, 0.000001f))
7016 {
7017 /* according to ANGLE's D3D11 backend:
7018 D3D11 SlopeScaledDepthBias ==> GL polygonOffsetFactor
7019 D3D11 DepthBias ==> GL polygonOffsetUnits
7020 DepthBiasClamp has no meaning on GL
7021 */
7022 cache_ds->bias = state_ds->bias;
7023 cache_ds->bias_slope_scale = state_ds->bias_slope_scale;
7024 glPolygonOffset(state_ds->bias_slope_scale, state_ds->bias);
7025 bool po_enabled = true;
7026 if (_sg_fequal(state_ds->bias, 0.0f, 0.000001f) &&
7027 _sg_fequal(state_ds->bias_slope_scale, 0.0f, 0.000001f))
7028 {
7029 po_enabled = false;
7030 }
7031 if (po_enabled != _sg.gl.cache.polygon_offset_enabled) {
7032 _sg.gl.cache.polygon_offset_enabled = po_enabled;
7033 if (po_enabled) {
7034 glEnable(GL_POLYGON_OFFSET_FILL);
7035 }
7036 else {
7037 glDisable(GL_POLYGON_OFFSET_FILL);
7038 }
7039 }
7040 }
7041 }
7042
7043 /* update stencil state */
7044 {
7045 const sg_stencil_state* state_ss = &pip->gl.stencil;
7046 sg_stencil_state* cache_ss = &_sg.gl.cache.stencil;
7047 if (state_ss->enabled != cache_ss->enabled) {
7048 cache_ss->enabled = state_ss->enabled;
7049 if (state_ss->enabled) {
7050 glEnable(GL_STENCIL_TEST);
7051 }
7052 else {
7053 glDisable(GL_STENCIL_TEST);
7054 }
7055 }
7056 if (state_ss->write_mask != cache_ss->write_mask) {
7057 cache_ss->write_mask = state_ss->write_mask;
7058 glStencilMask(state_ss->write_mask);
7059 }
7060 for (int i = 0; i < 2; i++) {
7061 const sg_stencil_face_state* state_sfs = (i==0)? &state_ss->front : &state_ss->back;
7062 sg_stencil_face_state* cache_sfs = (i==0)? &cache_ss->front : &cache_ss->back;
7063 GLenum gl_face = (i==0)? GL_FRONT : GL_BACK;
7064 if ((state_sfs->compare != cache_sfs->compare) ||
7065 (state_ss->read_mask != cache_ss->read_mask) ||
7066 (state_ss->ref != cache_ss->ref))
7067 {
7068 cache_sfs->compare = state_sfs->compare;
7069 glStencilFuncSeparate(gl_face,
7070 _sg_gl_compare_func(state_sfs->compare),
7071 state_ss->ref,
7072 state_ss->read_mask);
7073 }
7074 if ((state_sfs->fail_op != cache_sfs->fail_op) ||
7075 (state_sfs->depth_fail_op != cache_sfs->depth_fail_op) ||
7076 (state_sfs->pass_op != cache_sfs->pass_op))
7077 {
7078 cache_sfs->fail_op = state_sfs->fail_op;
7079 cache_sfs->depth_fail_op = state_sfs->depth_fail_op;
7080 cache_sfs->pass_op = state_sfs->pass_op;
7081 glStencilOpSeparate(gl_face,
7082 _sg_gl_stencil_op(state_sfs->fail_op),
7083 _sg_gl_stencil_op(state_sfs->depth_fail_op),
7084 _sg_gl_stencil_op(state_sfs->pass_op));
7085 }
7086 }
7087 cache_ss->read_mask = state_ss->read_mask;
7088 cache_ss->ref = state_ss->ref;
7089 }
7090
7091 /* update blend state
7092 FIXME: separate blend state per color attachment not support, needs GL4
7093 */
7094 {
7095 const sg_blend_state* state_bs = &pip->gl.blend;
7096 sg_blend_state* cache_bs = &_sg.gl.cache.blend;
7097 if (state_bs->enabled != cache_bs->enabled) {
7098 cache_bs->enabled = state_bs->enabled;
7099 if (state_bs->enabled) {
7100 glEnable(GL_BLEND);
7101 }
7102 else {
7103 glDisable(GL_BLEND);
7104 }
7105 }
7106 if ((state_bs->src_factor_rgb != cache_bs->src_factor_rgb) ||
7107 (state_bs->dst_factor_rgb != cache_bs->dst_factor_rgb) ||
7108 (state_bs->src_factor_alpha != cache_bs->src_factor_alpha) ||
7109 (state_bs->dst_factor_alpha != cache_bs->dst_factor_alpha))
7110 {
7111 cache_bs->src_factor_rgb = state_bs->src_factor_rgb;
7112 cache_bs->dst_factor_rgb = state_bs->dst_factor_rgb;
7113 cache_bs->src_factor_alpha = state_bs->src_factor_alpha;
7114 cache_bs->dst_factor_alpha = state_bs->dst_factor_alpha;
7115 glBlendFuncSeparate(_sg_gl_blend_factor(state_bs->src_factor_rgb),
7116 _sg_gl_blend_factor(state_bs->dst_factor_rgb),
7117 _sg_gl_blend_factor(state_bs->src_factor_alpha),
7118 _sg_gl_blend_factor(state_bs->dst_factor_alpha));
7119 }
7120 if ((state_bs->op_rgb != cache_bs->op_rgb) || (state_bs->op_alpha != cache_bs->op_alpha)) {
7121 cache_bs->op_rgb = state_bs->op_rgb;
7122 cache_bs->op_alpha = state_bs->op_alpha;
7123 glBlendEquationSeparate(_sg_gl_blend_op(state_bs->op_rgb), _sg_gl_blend_op(state_bs->op_alpha));
7124 }
7125 }
7126
7127 /* standalone state */
7128 for (GLuint i = 0; i < (GLuint)pip->cmn.color_attachment_count; i++) {
7129 if (pip->gl.color_write_mask[i] != _sg.gl.cache.color_write_mask[i]) {
7130 const sg_color_mask cm = pip->gl.color_write_mask[i];
7131 _sg.gl.cache.color_write_mask[i] = cm;
7132 #ifdef SOKOL_GLCORE33
7133 glColorMaski(i,
7134 (cm & SG_COLORMASK_R) != 0,
7135 (cm & SG_COLORMASK_G) != 0,
7136 (cm & SG_COLORMASK_B) != 0,
7137 (cm & SG_COLORMASK_A) != 0);
7138 #else
7139 if (0 == i) {
7140 glColorMask((cm & SG_COLORMASK_R) != 0,
7141 (cm & SG_COLORMASK_G) != 0,
7142 (cm & SG_COLORMASK_B) != 0,
7143 (cm & SG_COLORMASK_A) != 0);
7144 }
7145 #endif
7146 }
7147 }
7148
7149 if (!_sg_fequal(pip->cmn.blend_color.r, _sg.gl.cache.blend_color.r, 0.0001f) ||
7150 !_sg_fequal(pip->cmn.blend_color.g, _sg.gl.cache.blend_color.g, 0.0001f) ||
7151 !_sg_fequal(pip->cmn.blend_color.b, _sg.gl.cache.blend_color.b, 0.0001f) ||
7152 !_sg_fequal(pip->cmn.blend_color.a, _sg.gl.cache.blend_color.a, 0.0001f))
7153 {
7154 sg_color c = pip->cmn.blend_color;
7155 _sg.gl.cache.blend_color = c;
7156 glBlendColor(c.r, c.g, c.b, c.a);
7157 }
7158 if (pip->gl.cull_mode != _sg.gl.cache.cull_mode) {
7159 _sg.gl.cache.cull_mode = pip->gl.cull_mode;
7160 if (SG_CULLMODE_NONE == pip->gl.cull_mode) {
7161 glDisable(GL_CULL_FACE);
7162 }
7163 else {
7164 glEnable(GL_CULL_FACE);
7165 GLenum gl_mode = (SG_CULLMODE_FRONT == pip->gl.cull_mode) ? GL_FRONT : GL_BACK;
7166 glCullFace(gl_mode);
7167 }
7168 }
7169 if (pip->gl.face_winding != _sg.gl.cache.face_winding) {
7170 _sg.gl.cache.face_winding = pip->gl.face_winding;
7171 GLenum gl_winding = (SG_FACEWINDING_CW == pip->gl.face_winding) ? GL_CW : GL_CCW;
7172 glFrontFace(gl_winding);
7173 }
7174 if (pip->gl.alpha_to_coverage_enabled != _sg.gl.cache.alpha_to_coverage_enabled) {
7175 _sg.gl.cache.alpha_to_coverage_enabled = pip->gl.alpha_to_coverage_enabled;
7176 if (pip->gl.alpha_to_coverage_enabled) {
7177 glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
7178 }
7179 else {
7180 glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
7181 }
7182 }
7183 #ifdef SOKOL_GLCORE33
7184 if (pip->gl.sample_count != _sg.gl.cache.sample_count) {
7185 _sg.gl.cache.sample_count = pip->gl.sample_count;
7186 if (pip->gl.sample_count > 1) {
7187 glEnable(GL_MULTISAMPLE);
7188 }
7189 else {
7190 glDisable(GL_MULTISAMPLE);
7191 }
7192 }
7193 #endif
7194
7195 /* bind shader program */
7196 if (pip->shader->gl.prog != _sg.gl.cache.prog) {
7197 _sg.gl.cache.prog = pip->shader->gl.prog;
7198 glUseProgram(pip->shader->gl.prog);
7199 }
7200 }
7201 _SG_GL_CHECK_ERROR();
7202}
7203
7204_SOKOL_PRIVATE void _sg_gl_apply_bindings(
7205 _sg_pipeline_t* pip,
7206 _sg_buffer_t** vbs, const int* vb_offsets, int num_vbs,
7207 _sg_buffer_t* ib, int ib_offset,
7208 _sg_image_t** vs_imgs, int num_vs_imgs,
7209 _sg_image_t** fs_imgs, int num_fs_imgs)
7210{
7211 SOKOL_ASSERT(pip);
7212 _SOKOL_UNUSED(num_fs_imgs);
7213 _SOKOL_UNUSED(num_vs_imgs);
7214 _SOKOL_UNUSED(num_vbs);
7215 _SG_GL_CHECK_ERROR();
7216
7217 /* bind textures */
7218 _SG_GL_CHECK_ERROR();
7219 for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) {
7220 const _sg_shader_stage_t* stage = &pip->shader->cmn.stage[stage_index];
7221 const _sg_gl_shader_stage_t* gl_stage = &pip->shader->gl.stage[stage_index];
7222 _sg_image_t** imgs = (stage_index == SG_SHADERSTAGE_VS)? vs_imgs : fs_imgs;
7223 SOKOL_ASSERT(((stage_index == SG_SHADERSTAGE_VS)? num_vs_imgs : num_fs_imgs) == stage->num_images);
7224 for (int img_index = 0; img_index < stage->num_images; img_index++) {
7225 const _sg_gl_shader_image_t* gl_shd_img = &gl_stage->images[img_index];
7226 if (gl_shd_img->gl_tex_slot != -1) {
7227 _sg_image_t* img = imgs[img_index];
7228 const GLuint gl_tex = img->gl.tex[img->cmn.active_slot];
7229 SOKOL_ASSERT(img && img->gl.target);
7230 SOKOL_ASSERT((gl_shd_img->gl_tex_slot != -1) && gl_tex);
7231 _sg_gl_cache_bind_texture(gl_shd_img->gl_tex_slot, img->gl.target, gl_tex);
7232 }
7233 }
7234 }
7235 _SG_GL_CHECK_ERROR();
7236
7237 /* index buffer (can be 0) */
7238 const GLuint gl_ib = ib ? ib->gl.buf[ib->cmn.active_slot] : 0;
7239 _sg_gl_cache_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, gl_ib);
7240 _sg.gl.cache.cur_ib_offset = ib_offset;
7241
7242 /* vertex attributes */
7243 for (GLuint attr_index = 0; attr_index < (GLuint)_sg.limits.max_vertex_attrs; attr_index++) {
7244 _sg_gl_attr_t* attr = &pip->gl.attrs[attr_index];
7245 _sg_gl_cache_attr_t* cache_attr = &_sg.gl.cache.attrs[attr_index];
7246 bool cache_attr_dirty = false;
7247 int vb_offset = 0;
7248 GLuint gl_vb = 0;
7249 if (attr->vb_index >= 0) {
7250 /* attribute is enabled */
7251 SOKOL_ASSERT(attr->vb_index < num_vbs);
7252 _sg_buffer_t* vb = vbs[attr->vb_index];
7253 SOKOL_ASSERT(vb);
7254 gl_vb = vb->gl.buf[vb->cmn.active_slot];
7255 vb_offset = vb_offsets[attr->vb_index] + attr->offset;
7256 if ((gl_vb != cache_attr->gl_vbuf) ||
7257 (attr->size != cache_attr->gl_attr.size) ||
7258 (attr->type != cache_attr->gl_attr.type) ||
7259 (attr->normalized != cache_attr->gl_attr.normalized) ||
7260 (attr->stride != cache_attr->gl_attr.stride) ||
7261 (vb_offset != cache_attr->gl_attr.offset) ||
7262 (cache_attr->gl_attr.divisor != attr->divisor))
7263 {
7264 _sg_gl_cache_bind_buffer(GL_ARRAY_BUFFER, gl_vb);
7265 glVertexAttribPointer(attr_index, attr->size, attr->type,
7266 attr->normalized, attr->stride,
7267 (const GLvoid*)(GLintptr)vb_offset);
7268 #if defined(_SOKOL_GL_INSTANCING_ENABLED)
7269 if (_sg.features.instancing) {
7270 glVertexAttribDivisor(attr_index, (GLuint)attr->divisor);
7271 }
7272 #endif
7273 cache_attr_dirty = true;
7274 }
7275 if (cache_attr->gl_attr.vb_index == -1) {
7276 glEnableVertexAttribArray(attr_index);
7277 cache_attr_dirty = true;
7278 }
7279 }
7280 else {
7281 /* attribute is disabled */
7282 if (cache_attr->gl_attr.vb_index != -1) {
7283 glDisableVertexAttribArray(attr_index);
7284 cache_attr_dirty = true;
7285 }
7286 }
7287 if (cache_attr_dirty) {
7288 cache_attr->gl_attr = *attr;
7289 cache_attr->gl_attr.offset = vb_offset;
7290 cache_attr->gl_vbuf = gl_vb;
7291 }
7292 }
7293 _SG_GL_CHECK_ERROR();
7294}
7295
7296_SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_index, const sg_range* data) {
7297 SOKOL_ASSERT(_sg.gl.cache.cur_pipeline);
7298 SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->slot.id == _sg.gl.cache.cur_pipeline_id.id);
7299 SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->slot.id == _sg.gl.cache.cur_pipeline->cmn.shader_id.id);
7300 SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].num_uniform_blocks > ub_index);
7301 SOKOL_ASSERT(_sg.gl.cache.cur_pipeline->shader->cmn.stage[stage_index].uniform_blocks[ub_index].size == data->size);
7302 const _sg_gl_shader_stage_t* gl_stage = &_sg.gl.cache.cur_pipeline->shader->gl.stage[stage_index];
7303 const _sg_gl_uniform_block_t* gl_ub = &gl_stage->uniform_blocks[ub_index];
7304 for (int u_index = 0; u_index < gl_ub->num_uniforms; u_index++) {
7305 const _sg_gl_uniform_t* u = &gl_ub->uniforms[u_index];
7306 SOKOL_ASSERT(u->type != SG_UNIFORMTYPE_INVALID);
7307 if (u->gl_loc == -1) {
7308 continue;
7309 }
7310 GLfloat* ptr = (GLfloat*) (((uint8_t*)data->ptr) + u->offset);
7311 switch (u->type) {
7312 case SG_UNIFORMTYPE_INVALID:
7313 break;
7314 case SG_UNIFORMTYPE_FLOAT:
7315 glUniform1fv(u->gl_loc, u->count, ptr);
7316 break;
7317 case SG_UNIFORMTYPE_FLOAT2:
7318 glUniform2fv(u->gl_loc, u->count, ptr);
7319 break;
7320 case SG_UNIFORMTYPE_FLOAT3:
7321 glUniform3fv(u->gl_loc, u->count, ptr);
7322 break;
7323 case SG_UNIFORMTYPE_FLOAT4:
7324 glUniform4fv(u->gl_loc, u->count, ptr);
7325 break;
7326 case SG_UNIFORMTYPE_MAT4:
7327 glUniformMatrix4fv(u->gl_loc, u->count, GL_FALSE, ptr);
7328 break;
7329 default:
7330 SOKOL_UNREACHABLE;
7331 break;
7332 }
7333 }
7334}
7335
7336_SOKOL_PRIVATE void _sg_gl_draw(int base_element, int num_elements, int num_instances) {
7337 const GLenum i_type = _sg.gl.cache.cur_index_type;
7338 const GLenum p_type = _sg.gl.cache.cur_primitive_type;
7339 if (0 != i_type) {
7340 /* indexed rendering */
7341 const int i_size = (i_type == GL_UNSIGNED_SHORT) ? 2 : 4;
7342 const int ib_offset = _sg.gl.cache.cur_ib_offset;
7343 const GLvoid* indices = (const GLvoid*)(GLintptr)(base_element*i_size+ib_offset);
7344 if (num_instances == 1) {
7345 glDrawElements(p_type, num_elements, i_type, indices);
7346 }
7347 else {
7348 if (_sg.features.instancing) {
7349 glDrawElementsInstanced(p_type, num_elements, i_type, indices, num_instances);
7350 }
7351 }
7352 }
7353 else {
7354 /* non-indexed rendering */
7355 if (num_instances == 1) {
7356 glDrawArrays(p_type, base_element, num_elements);
7357 }
7358 else {
7359 if (_sg.features.instancing) {
7360 glDrawArraysInstanced(p_type, base_element, num_elements, num_instances);
7361 }
7362 }
7363 }
7364}
7365
7366_SOKOL_PRIVATE void _sg_gl_commit(void) {
7367 SOKOL_ASSERT(!_sg.gl.in_pass);
7368 /* "soft" clear bindings (only those that are actually bound) */
7369 _sg_gl_cache_clear_buffer_bindings(false);
7370 _sg_gl_cache_clear_texture_bindings(false);
7371}
7372
7373_SOKOL_PRIVATE void _sg_gl_update_buffer(_sg_buffer_t* buf, const sg_range* data) {
7374 SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0));
7375 /* only one update per buffer per frame allowed */
7376 if (++buf->cmn.active_slot >= buf->cmn.num_slots) {
7377 buf->cmn.active_slot = 0;
7378 }
7379 GLenum gl_tgt = _sg_gl_buffer_target(buf->cmn.type);
7380 SOKOL_ASSERT(buf->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES);
7381 GLuint gl_buf = buf->gl.buf[buf->cmn.active_slot];
7382 SOKOL_ASSERT(gl_buf);
7383 _SG_GL_CHECK_ERROR();
7384 _sg_gl_cache_store_buffer_binding(gl_tgt);
7385 _sg_gl_cache_bind_buffer(gl_tgt, gl_buf);
7386 glBufferSubData(gl_tgt, 0, (GLsizeiptr)data->size, data->ptr);
7387 _sg_gl_cache_restore_buffer_binding(gl_tgt);
7388 _SG_GL_CHECK_ERROR();
7389}
7390
7391_SOKOL_PRIVATE int _sg_gl_append_buffer(_sg_buffer_t* buf, const sg_range* data, bool new_frame) {
7392 SOKOL_ASSERT(buf && data && data->ptr && (data->size > 0));
7393 if (new_frame) {
7394 if (++buf->cmn.active_slot >= buf->cmn.num_slots) {
7395 buf->cmn.active_slot = 0;
7396 }
7397 }
7398 GLenum gl_tgt = _sg_gl_buffer_target(buf->cmn.type);
7399 SOKOL_ASSERT(buf->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES);
7400 GLuint gl_buf = buf->gl.buf[buf->cmn.active_slot];
7401 SOKOL_ASSERT(gl_buf);
7402 _SG_GL_CHECK_ERROR();
7403 _sg_gl_cache_store_buffer_binding(gl_tgt);
7404 _sg_gl_cache_bind_buffer(gl_tgt, gl_buf);
7405 glBufferSubData(gl_tgt, buf->cmn.append_pos, (GLsizeiptr)data->size, data->ptr);
7406 _sg_gl_cache_restore_buffer_binding(gl_tgt);
7407 _SG_GL_CHECK_ERROR();
7408 /* NOTE: this is a requirement from WebGPU, but we want identical behaviour across all backend */
7409 return _sg_roundup((int)data->size, 4);
7410}
7411
7412_SOKOL_PRIVATE void _sg_gl_update_image(_sg_image_t* img, const sg_image_data* data) {
7413 SOKOL_ASSERT(img && data);
7414 /* only one update per image per frame allowed */
7415 if (++img->cmn.active_slot >= img->cmn.num_slots) {
7416 img->cmn.active_slot = 0;
7417 }
7418 SOKOL_ASSERT(img->cmn.active_slot < SG_NUM_INFLIGHT_FRAMES);
7419 SOKOL_ASSERT(0 != img->gl.tex[img->cmn.active_slot]);
7420 _sg_gl_cache_store_texture_binding(0);
7421 _sg_gl_cache_bind_texture(0, img->gl.target, img->gl.tex[img->cmn.active_slot]);
7422 const GLenum gl_img_format = _sg_gl_teximage_format(img->cmn.pixel_format);
7423 const GLenum gl_img_type = _sg_gl_teximage_type(img->cmn.pixel_format);
7424 const int num_faces = img->cmn.type == SG_IMAGETYPE_CUBE ? 6 : 1;
7425 const int num_mips = img->cmn.num_mipmaps;
7426 for (int face_index = 0; face_index < num_faces; face_index++) {
7427 for (int mip_index = 0; mip_index < num_mips; mip_index++) {
7428 GLenum gl_img_target = img->gl.target;
7429 if (SG_IMAGETYPE_CUBE == img->cmn.type) {
7430 gl_img_target = _sg_gl_cubeface_target(face_index);
7431 }
7432 const GLvoid* data_ptr = data->subimage[face_index][mip_index].ptr;
7433 int mip_width = img->cmn.width >> mip_index;
7434 if (mip_width == 0) {
7435 mip_width = 1;
7436 }
7437 int mip_height = img->cmn.height >> mip_index;
7438 if (mip_height == 0) {
7439 mip_height = 1;
7440 }
7441 if ((SG_IMAGETYPE_2D == img->cmn.type) || (SG_IMAGETYPE_CUBE == img->cmn.type)) {
7442 glTexSubImage2D(gl_img_target, mip_index,
7443 0, 0,
7444 mip_width, mip_height,
7445 gl_img_format, gl_img_type,
7446 data_ptr);
7447 }
7448 #if !defined(SOKOL_GLES2)
7449 else if (!_sg.gl.gles2 && ((SG_IMAGETYPE_3D == img->cmn.type) || (SG_IMAGETYPE_ARRAY == img->cmn.type))) {
7450 int mip_depth = img->cmn.num_slices >> mip_index;
7451 if (mip_depth == 0) {
7452 mip_depth = 1;
7453 }
7454 glTexSubImage3D(gl_img_target, mip_index,
7455 0, 0, 0,
7456 mip_width, mip_height, mip_depth,
7457 gl_img_format, gl_img_type,
7458 data_ptr);
7459
7460 }
7461 #endif
7462 }
7463 }
7464 _sg_gl_cache_restore_texture_binding(0);
7465}
7466
7467/*== D3D11 BACKEND IMPLEMENTATION ============================================*/
7468#elif defined(SOKOL_D3D11)
7469
7470#if defined(__cplusplus)
7471#define _sg_d3d11_AddRef(self) (self)->AddRef()
7472#else
7473#define _sg_d3d11_AddRef(self) (self)->lpVtbl->AddRef(self)
7474#endif
7475
7476#if defined(__cplusplus)
7477#define _sg_d3d11_Release(self) (self)->Release()
7478#else
7479#define _sg_d3d11_Release(self) (self)->lpVtbl->Release(self)
7480#endif
7481
7482/*-- D3D11 C/C++ wrappers ----------------------------------------------------*/
7483static inline HRESULT _sg_d3d11_CheckFormatSupport(ID3D11Device* self, DXGI_FORMAT Format, UINT* pFormatSupport) {
7484 #if defined(__cplusplus)
7485 return self->CheckFormatSupport(Format, pFormatSupport);
7486 #else
7487 return self->lpVtbl->CheckFormatSupport(self, Format, pFormatSupport);
7488 #endif
7489}
7490
7491static inline void _sg_d3d11_OMSetRenderTargets(ID3D11DeviceContext* self, UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView) {
7492 #if defined(__cplusplus)
7493 self->OMSetRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView);
7494 #else
7495 self->lpVtbl->OMSetRenderTargets(self, NumViews, ppRenderTargetViews, pDepthStencilView);
7496 #endif
7497}
7498
7499static inline void _sg_d3d11_RSSetState(ID3D11DeviceContext* self, ID3D11RasterizerState* pRasterizerState) {
7500 #if defined(__cplusplus)
7501 self->RSSetState(pRasterizerState);
7502 #else
7503 self->lpVtbl->RSSetState(self, pRasterizerState);
7504 #endif
7505}
7506
7507static inline void _sg_d3d11_OMSetDepthStencilState(ID3D11DeviceContext* self, ID3D11DepthStencilState* pDepthStencilState, UINT StencilRef) {
7508 #if defined(__cplusplus)
7509 self->OMSetDepthStencilState(pDepthStencilState, StencilRef);
7510 #else
7511 self->lpVtbl->OMSetDepthStencilState(self, pDepthStencilState, StencilRef);
7512 #endif
7513}
7514
7515static inline void _sg_d3d11_OMSetBlendState(ID3D11DeviceContext* self, ID3D11BlendState* pBlendState, const FLOAT BlendFactor[4], UINT SampleMask) {
7516 #if defined(__cplusplus)
7517 self->OMSetBlendState(pBlendState, BlendFactor, SampleMask);
7518 #else
7519 self->lpVtbl->OMSetBlendState(self, pBlendState, BlendFactor, SampleMask);
7520 #endif
7521}
7522
7523static inline void _sg_d3d11_IASetVertexBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppVertexBuffers, const UINT* pStrides, const UINT* pOffsets) {
7524 #if defined(__cplusplus)
7525 self->IASetVertexBuffers(StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets);
7526 #else
7527 self->lpVtbl->IASetVertexBuffers(self, StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets);
7528 #endif
7529}
7530
7531static inline void _sg_d3d11_IASetIndexBuffer(ID3D11DeviceContext* self, ID3D11Buffer* pIndexBuffer, DXGI_FORMAT Format, UINT Offset) {
7532 #if defined(__cplusplus)
7533 self->IASetIndexBuffer(pIndexBuffer, Format, Offset);
7534 #else
7535 self->lpVtbl->IASetIndexBuffer(self, pIndexBuffer, Format, Offset);
7536 #endif
7537}
7538
7539static inline void _sg_d3d11_IASetInputLayout(ID3D11DeviceContext* self, ID3D11InputLayout* pInputLayout) {
7540 #if defined(__cplusplus)
7541 self->IASetInputLayout(pInputLayout);
7542 #else
7543 self->lpVtbl->IASetInputLayout(self, pInputLayout);
7544 #endif
7545}
7546
7547static inline void _sg_d3d11_VSSetShader(ID3D11DeviceContext* self, ID3D11VertexShader* pVertexShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) {
7548 #if defined(__cplusplus)
7549 self->VSSetShader(pVertexShader, ppClassInstances, NumClassInstances);
7550 #else
7551 self->lpVtbl->VSSetShader(self, pVertexShader, ppClassInstances, NumClassInstances);
7552 #endif
7553}
7554
7555static inline void _sg_d3d11_PSSetShader(ID3D11DeviceContext* self, ID3D11PixelShader* pPixelShader, ID3D11ClassInstance* const* ppClassInstances, UINT NumClassInstances) {
7556 #if defined(__cplusplus)
7557 self->PSSetShader(pPixelShader, ppClassInstances, NumClassInstances);
7558 #else
7559 self->lpVtbl->PSSetShader(self, pPixelShader, ppClassInstances, NumClassInstances);
7560 #endif
7561}
7562
7563static inline void _sg_d3d11_VSSetConstantBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) {
7564 #if defined(__cplusplus)
7565 self->VSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers);
7566 #else
7567 self->lpVtbl->VSSetConstantBuffers(self, StartSlot, NumBuffers, ppConstantBuffers);
7568 #endif
7569}
7570
7571static inline void _sg_d3d11_PSSetConstantBuffers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumBuffers, ID3D11Buffer* const* ppConstantBuffers) {
7572 #if defined(__cplusplus)
7573 self->PSSetConstantBuffers(StartSlot, NumBuffers, ppConstantBuffers);
7574 #else
7575 self->lpVtbl->PSSetConstantBuffers(self, StartSlot, NumBuffers, ppConstantBuffers);
7576 #endif
7577}
7578
7579static inline void _sg_d3d11_VSSetShaderResources(ID3D11DeviceContext* self, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) {
7580 #if defined(__cplusplus)
7581 self->VSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews);
7582 #else
7583 self->lpVtbl->VSSetShaderResources(self, StartSlot, NumViews, ppShaderResourceViews);
7584 #endif
7585}
7586
7587static inline void _sg_d3d11_PSSetShaderResources(ID3D11DeviceContext* self, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView* const* ppShaderResourceViews) {
7588 #if defined(__cplusplus)
7589 self->PSSetShaderResources(StartSlot, NumViews, ppShaderResourceViews);
7590 #else
7591 self->lpVtbl->PSSetShaderResources(self, StartSlot, NumViews, ppShaderResourceViews);
7592 #endif
7593}
7594
7595static inline void _sg_d3d11_VSSetSamplers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) {
7596 #if defined(__cplusplus)
7597 self->VSSetSamplers(StartSlot, NumSamplers, ppSamplers);
7598 #else
7599 self->lpVtbl->VSSetSamplers(self, StartSlot, NumSamplers, ppSamplers);
7600 #endif
7601}
7602
7603static inline void _sg_d3d11_PSSetSamplers(ID3D11DeviceContext* self, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState* const* ppSamplers) {
7604 #if defined(__cplusplus)
7605 self->PSSetSamplers(StartSlot, NumSamplers, ppSamplers);
7606 #else
7607 self->lpVtbl->PSSetSamplers(self, StartSlot, NumSamplers, ppSamplers);
7608 #endif
7609}
7610
7611static inline HRESULT _sg_d3d11_CreateBuffer(ID3D11Device* self, const D3D11_BUFFER_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Buffer** ppBuffer) {
7612 #if defined(__cplusplus)
7613 return self->CreateBuffer(pDesc, pInitialData, ppBuffer);
7614 #else
7615 return self->lpVtbl->CreateBuffer(self, pDesc, pInitialData, ppBuffer);
7616 #endif
7617}
7618
7619static inline HRESULT _sg_d3d11_CreateTexture2D(ID3D11Device* self, const D3D11_TEXTURE2D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture2D** ppTexture2D) {
7620 #if defined(__cplusplus)
7621 return self->CreateTexture2D(pDesc, pInitialData, ppTexture2D);
7622 #else
7623 return self->lpVtbl->CreateTexture2D(self, pDesc, pInitialData, ppTexture2D);
7624 #endif
7625}
7626
7627static inline HRESULT _sg_d3d11_CreateShaderResourceView(ID3D11Device* self, ID3D11Resource* pResource, const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc, ID3D11ShaderResourceView** ppSRView) {
7628 #if defined(__cplusplus)
7629 return self->CreateShaderResourceView(pResource, pDesc, ppSRView);
7630 #else
7631 return self->lpVtbl->CreateShaderResourceView(self, pResource, pDesc, ppSRView);
7632 #endif
7633}
7634
7635static inline void _sg_d3d11_GetResource(ID3D11View* self, ID3D11Resource** ppResource) {
7636 #if defined(__cplusplus)
7637 self->GetResource(ppResource);
7638 #else
7639 self->lpVtbl->GetResource(self, ppResource);
7640 #endif
7641}
7642
7643static inline HRESULT _sg_d3d11_CreateTexture3D(ID3D11Device* self, const D3D11_TEXTURE3D_DESC* pDesc, const D3D11_SUBRESOURCE_DATA* pInitialData, ID3D11Texture3D** ppTexture3D) {
7644 #if defined(__cplusplus)
7645 return self->CreateTexture3D(pDesc, pInitialData, ppTexture3D);
7646 #else
7647 return self->lpVtbl->CreateTexture3D(self, pDesc, pInitialData, ppTexture3D);
7648 #endif
7649}
7650
7651static inline HRESULT _sg_d3d11_CreateSamplerState(ID3D11Device* self, const D3D11_SAMPLER_DESC* pSamplerDesc, ID3D11SamplerState** ppSamplerState) {
7652 #if defined(__cplusplus)
7653 return self->CreateSamplerState(pSamplerDesc, ppSamplerState);
7654 #else
7655 return self->lpVtbl->CreateSamplerState(self, pSamplerDesc, ppSamplerState);
7656 #endif
7657}
7658
7659static inline LPVOID _sg_d3d11_GetBufferPointer(ID3D10Blob* self) {
7660 #if defined(__cplusplus)
7661 return self->GetBufferPointer();
7662 #else
7663 return self->lpVtbl->GetBufferPointer(self);
7664 #endif
7665}
7666
7667static inline SIZE_T _sg_d3d11_GetBufferSize(ID3D10Blob* self) {
7668 #if defined(__cplusplus)
7669 return self->GetBufferSize();
7670 #else
7671 return self->lpVtbl->GetBufferSize(self);
7672 #endif
7673}
7674
7675static inline HRESULT _sg_d3d11_CreateVertexShader(ID3D11Device* self, const void* pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11VertexShader** ppVertexShader) {
7676 #if defined(__cplusplus)
7677 return self->CreateVertexShader(pShaderBytecode, BytecodeLength, pClassLinkage, ppVertexShader);
7678 #else
7679 return self->lpVtbl->CreateVertexShader(self, pShaderBytecode, BytecodeLength, pClassLinkage, ppVertexShader);
7680 #endif
7681}
7682
7683static inline HRESULT _sg_d3d11_CreatePixelShader(ID3D11Device* self, const void* pShaderBytecode, SIZE_T BytecodeLength, ID3D11ClassLinkage* pClassLinkage, ID3D11PixelShader** ppPixelShader) {
7684 #if defined(__cplusplus)
7685 return self->CreatePixelShader(pShaderBytecode, BytecodeLength, pClassLinkage, ppPixelShader);
7686 #else
7687 return self->lpVtbl->CreatePixelShader(self, pShaderBytecode, BytecodeLength, pClassLinkage, ppPixelShader);
7688 #endif
7689}
7690
7691static inline HRESULT _sg_d3d11_CreateInputLayout(ID3D11Device* self, const D3D11_INPUT_ELEMENT_DESC* pInputElementDescs, UINT NumElements, const void* pShaderBytecodeWithInputSignature, SIZE_T BytecodeLength, ID3D11InputLayout **ppInputLayout) {
7692 #if defined(__cplusplus)
7693 return self->CreateInputLayout(pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout);
7694 #else
7695 return self->lpVtbl->CreateInputLayout(self, pInputElementDescs, NumElements, pShaderBytecodeWithInputSignature, BytecodeLength, ppInputLayout);
7696 #endif
7697}
7698
7699static inline HRESULT _sg_d3d11_CreateRasterizerState(ID3D11Device* self, const D3D11_RASTERIZER_DESC* pRasterizerDesc, ID3D11RasterizerState** ppRasterizerState) {
7700 #if defined(__cplusplus)
7701 return self->CreateRasterizerState(pRasterizerDesc, ppRasterizerState);
7702 #else
7703 return self->lpVtbl->CreateRasterizerState(self, pRasterizerDesc, ppRasterizerState);
7704 #endif
7705}
7706
7707static inline HRESULT _sg_d3d11_CreateDepthStencilState(ID3D11Device* self, const D3D11_DEPTH_STENCIL_DESC* pDepthStencilDesc, ID3D11DepthStencilState** ppDepthStencilState) {
7708 #if defined(__cplusplus)
7709 return self->CreateDepthStencilState(pDepthStencilDesc, ppDepthStencilState);
7710 #else
7711 return self->lpVtbl->CreateDepthStencilState(self, pDepthStencilDesc, ppDepthStencilState);
7712 #endif
7713}
7714
7715static inline HRESULT _sg_d3d11_CreateBlendState(ID3D11Device* self, const D3D11_BLEND_DESC* pBlendStateDesc, ID3D11BlendState** ppBlendState) {
7716 #if defined(__cplusplus)
7717 return self->CreateBlendState(pBlendStateDesc, ppBlendState);
7718 #else
7719 return self->lpVtbl->CreateBlendState(self, pBlendStateDesc, ppBlendState);
7720 #endif
7721}
7722
7723static inline HRESULT _sg_d3d11_CreateRenderTargetView(ID3D11Device* self, ID3D11Resource *pResource, const D3D11_RENDER_TARGET_VIEW_DESC* pDesc, ID3D11RenderTargetView** ppRTView) {
7724 #if defined(__cplusplus)
7725 return self->CreateRenderTargetView(pResource, pDesc, ppRTView);
7726 #else
7727 return self->lpVtbl->CreateRenderTargetView(self, pResource, pDesc, ppRTView);
7728 #endif
7729}
7730
7731static inline HRESULT _sg_d3d11_CreateDepthStencilView(ID3D11Device* self, ID3D11Resource* pResource, const D3D11_DEPTH_STENCIL_VIEW_DESC* pDesc, ID3D11DepthStencilView** ppDepthStencilView) {
7732 #if defined(__cplusplus)
7733 return self->CreateDepthStencilView(pResource, pDesc, ppDepthStencilView);
7734 #else
7735 return self->lpVtbl->CreateDepthStencilView(self, pResource, pDesc, ppDepthStencilView);
7736 #endif
7737}
7738
7739static inline void _sg_d3d11_RSSetViewports(ID3D11DeviceContext* self, UINT NumViewports, const D3D11_VIEWPORT* pViewports) {
7740 #if defined(__cplusplus)
7741 self->RSSetViewports(NumViewports, pViewports);
7742 #else
7743 self->lpVtbl->RSSetViewports(self, NumViewports, pViewports);
7744 #endif
7745}
7746
7747static inline void _sg_d3d11_RSSetScissorRects(ID3D11DeviceContext* self, UINT NumRects, const D3D11_RECT* pRects) {
7748 #if defined(__cplusplus)
7749 self->RSSetScissorRects(NumRects, pRects);
7750 #else
7751 self->lpVtbl->RSSetScissorRects(self, NumRects, pRects);
7752 #endif
7753}
7754
7755static inline void _sg_d3d11_ClearRenderTargetView(ID3D11DeviceContext* self, ID3D11RenderTargetView* pRenderTargetView, const FLOAT ColorRGBA[4]) {
7756 #if defined(__cplusplus)
7757 self->ClearRenderTargetView(pRenderTargetView, ColorRGBA);
7758 #else
7759 self->lpVtbl->ClearRenderTargetView(self, pRenderTargetView, ColorRGBA);
7760 #endif
7761}
7762
7763static inline void _sg_d3d11_ClearDepthStencilView(ID3D11DeviceContext* self, ID3D11DepthStencilView* pDepthStencilView, UINT ClearFlags, FLOAT Depth, UINT8 Stencil) {
7764 #if defined(__cplusplus)
7765 self->ClearDepthStencilView(pDepthStencilView, ClearFlags, Depth, Stencil);
7766 #else
7767 self->lpVtbl->ClearDepthStencilView(self, pDepthStencilView, ClearFlags, Depth, Stencil);
7768 #endif
7769}
7770
7771static inline void _sg_d3d11_ResolveSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, ID3D11Resource* pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) {
7772 #if defined(__cplusplus)
7773 self->ResolveSubresource(pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format);
7774 #else
7775 self->lpVtbl->ResolveSubresource(self, pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format);
7776 #endif
7777}
7778
7779static inline void _sg_d3d11_IASetPrimitiveTopology(ID3D11DeviceContext* self, D3D11_PRIMITIVE_TOPOLOGY Topology) {
7780 #if defined(__cplusplus)
7781 self->IASetPrimitiveTopology(Topology);
7782 #else
7783 self->lpVtbl->IASetPrimitiveTopology(self, Topology);
7784 #endif
7785}
7786
7787static inline void _sg_d3d11_UpdateSubresource(ID3D11DeviceContext* self, ID3D11Resource* pDstResource, UINT DstSubresource, const D3D11_BOX* pDstBox, const void* pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) {
7788 #if defined(__cplusplus)
7789 self->UpdateSubresource(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch);
7790 #else
7791 self->lpVtbl->UpdateSubresource(self, pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch);
7792 #endif
7793}
7794
7795static inline void _sg_d3d11_DrawIndexed(ID3D11DeviceContext* self, UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation) {
7796 #if defined(__cplusplus)
7797 self->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation);
7798 #else
7799 self->lpVtbl->DrawIndexed(self, IndexCount, StartIndexLocation, BaseVertexLocation);
7800 #endif
7801}
7802
7803static inline void _sg_d3d11_DrawIndexedInstanced(ID3D11DeviceContext* self, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation) {
7804 #if defined(__cplusplus)
7805 self->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation);
7806 #else
7807 self->lpVtbl->DrawIndexedInstanced(self, IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation);
7808 #endif
7809}
7810
7811static inline void _sg_d3d11_Draw(ID3D11DeviceContext* self, UINT VertexCount, UINT StartVertexLocation) {
7812 #if defined(__cplusplus)
7813 self->Draw(VertexCount, StartVertexLocation);
7814 #else
7815 self->lpVtbl->Draw(self, VertexCount, StartVertexLocation);
7816 #endif
7817}
7818
7819static inline void _sg_d3d11_DrawInstanced(ID3D11DeviceContext* self, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) {
7820 #if defined(__cplusplus)
7821 self->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation);
7822 #else
7823 self->lpVtbl->DrawInstanced(self, VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation);
7824 #endif
7825}
7826
7827static inline HRESULT _sg_d3d11_Map(ID3D11DeviceContext* self, ID3D11Resource* pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE* pMappedResource) {
7828 #if defined(__cplusplus)
7829 return self->Map(pResource, Subresource, MapType, MapFlags, pMappedResource);
7830 #else
7831 return self->lpVtbl->Map(self, pResource, Subresource, MapType, MapFlags, pMappedResource);
7832 #endif
7833}
7834
7835static inline void _sg_d3d11_Unmap(ID3D11DeviceContext* self, ID3D11Resource* pResource, UINT Subresource) {
7836 #if defined(__cplusplus)
7837 self->Unmap(pResource, Subresource);
7838 #else
7839 self->lpVtbl->Unmap(self, pResource, Subresource);
7840 #endif
7841}
7842
7843/*-- enum translation functions ----------------------------------------------*/
7844_SOKOL_PRIVATE D3D11_USAGE _sg_d3d11_usage(sg_usage usg) {
7845 switch (usg) {
7846 case SG_USAGE_IMMUTABLE:
7847 return D3D11_USAGE_IMMUTABLE;
7848 case SG_USAGE_DYNAMIC:
7849 case SG_USAGE_STREAM:
7850 return D3D11_USAGE_DYNAMIC;
7851 default:
7852 SOKOL_UNREACHABLE;
7853 return (D3D11_USAGE) 0;
7854 }
7855}
7856
7857_SOKOL_PRIVATE UINT _sg_d3d11_cpu_access_flags(sg_usage usg) {
7858 switch (usg) {
7859 case SG_USAGE_IMMUTABLE:
7860 return 0;
7861 case SG_USAGE_DYNAMIC:
7862 case SG_USAGE_STREAM:
7863 return D3D11_CPU_ACCESS_WRITE;
7864 default:
7865 SOKOL_UNREACHABLE;
7866 return 0;
7867 }
7868}
7869
7870_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_pixel_format(sg_pixel_format fmt) {
7871 switch (fmt) {
7872 case SG_PIXELFORMAT_R8: return DXGI_FORMAT_R8_UNORM;
7873 case SG_PIXELFORMAT_R8SN: return DXGI_FORMAT_R8_SNORM;
7874 case SG_PIXELFORMAT_R8UI: return DXGI_FORMAT_R8_UINT;
7875 case SG_PIXELFORMAT_R8SI: return DXGI_FORMAT_R8_SINT;
7876 case SG_PIXELFORMAT_R16: return DXGI_FORMAT_R16_UNORM;
7877 case SG_PIXELFORMAT_R16SN: return DXGI_FORMAT_R16_SNORM;
7878 case SG_PIXELFORMAT_R16UI: return DXGI_FORMAT_R16_UINT;
7879 case SG_PIXELFORMAT_R16SI: return DXGI_FORMAT_R16_SINT;
7880 case SG_PIXELFORMAT_R16F: return DXGI_FORMAT_R16_FLOAT;
7881 case SG_PIXELFORMAT_RG8: return DXGI_FORMAT_R8G8_UNORM;
7882 case SG_PIXELFORMAT_RG8SN: return DXGI_FORMAT_R8G8_SNORM;
7883 case SG_PIXELFORMAT_RG8UI: return DXGI_FORMAT_R8G8_UINT;
7884 case SG_PIXELFORMAT_RG8SI: return DXGI_FORMAT_R8G8_SINT;
7885 case SG_PIXELFORMAT_R32UI: return DXGI_FORMAT_R32_UINT;
7886 case SG_PIXELFORMAT_R32SI: return DXGI_FORMAT_R32_SINT;
7887 case SG_PIXELFORMAT_R32F: return DXGI_FORMAT_R32_FLOAT;
7888 case SG_PIXELFORMAT_RG16: return DXGI_FORMAT_R16G16_UNORM;
7889 case SG_PIXELFORMAT_RG16SN: return DXGI_FORMAT_R16G16_SNORM;
7890 case SG_PIXELFORMAT_RG16UI: return DXGI_FORMAT_R16G16_UINT;
7891 case SG_PIXELFORMAT_RG16SI: return DXGI_FORMAT_R16G16_SINT;
7892 case SG_PIXELFORMAT_RG16F: return DXGI_FORMAT_R16G16_FLOAT;
7893 case SG_PIXELFORMAT_RGBA8: return DXGI_FORMAT_R8G8B8A8_UNORM;
7894 case SG_PIXELFORMAT_RGBA8SN: return DXGI_FORMAT_R8G8B8A8_SNORM;
7895 case SG_PIXELFORMAT_RGBA8UI: return DXGI_FORMAT_R8G8B8A8_UINT;
7896 case SG_PIXELFORMAT_RGBA8SI: return DXGI_FORMAT_R8G8B8A8_SINT;
7897 case SG_PIXELFORMAT_BGRA8: return DXGI_FORMAT_B8G8R8A8_UNORM;
7898 case SG_PIXELFORMAT_RGB10A2: return DXGI_FORMAT_R10G10B10A2_UNORM;
7899 case SG_PIXELFORMAT_RG11B10F: return DXGI_FORMAT_R11G11B10_FLOAT;
7900 case SG_PIXELFORMAT_RG32UI: return DXGI_FORMAT_R32G32_UINT;
7901 case SG_PIXELFORMAT_RG32SI: return DXGI_FORMAT_R32G32_SINT;
7902 case SG_PIXELFORMAT_RG32F: return DXGI_FORMAT_R32G32_FLOAT;
7903 case SG_PIXELFORMAT_RGBA16: return DXGI_FORMAT_R16G16B16A16_UNORM;
7904 case SG_PIXELFORMAT_RGBA16SN: return DXGI_FORMAT_R16G16B16A16_SNORM;
7905 case SG_PIXELFORMAT_RGBA16UI: return DXGI_FORMAT_R16G16B16A16_UINT;
7906 case SG_PIXELFORMAT_RGBA16SI: return DXGI_FORMAT_R16G16B16A16_SINT;
7907 case SG_PIXELFORMAT_RGBA16F: return DXGI_FORMAT_R16G16B16A16_FLOAT;
7908 case SG_PIXELFORMAT_RGBA32UI: return DXGI_FORMAT_R32G32B32A32_UINT;
7909 case SG_PIXELFORMAT_RGBA32SI: return DXGI_FORMAT_R32G32B32A32_SINT;
7910 case SG_PIXELFORMAT_RGBA32F: return DXGI_FORMAT_R32G32B32A32_FLOAT;
7911 case SG_PIXELFORMAT_DEPTH: return DXGI_FORMAT_D32_FLOAT;
7912 case SG_PIXELFORMAT_DEPTH_STENCIL: return DXGI_FORMAT_D24_UNORM_S8_UINT;
7913 case SG_PIXELFORMAT_BC1_RGBA: return DXGI_FORMAT_BC1_UNORM;
7914 case SG_PIXELFORMAT_BC2_RGBA: return DXGI_FORMAT_BC2_UNORM;
7915 case SG_PIXELFORMAT_BC3_RGBA: return DXGI_FORMAT_BC3_UNORM;
7916 case SG_PIXELFORMAT_BC4_R: return DXGI_FORMAT_BC4_UNORM;
7917 case SG_PIXELFORMAT_BC4_RSN: return DXGI_FORMAT_BC4_SNORM;
7918 case SG_PIXELFORMAT_BC5_RG: return DXGI_FORMAT_BC5_UNORM;
7919 case SG_PIXELFORMAT_BC5_RGSN: return DXGI_FORMAT_BC5_SNORM;
7920 case SG_PIXELFORMAT_BC6H_RGBF: return DXGI_FORMAT_BC6H_SF16;
7921 case SG_PIXELFORMAT_BC6H_RGBUF: return DXGI_FORMAT_BC6H_UF16;
7922 case SG_PIXELFORMAT_BC7_RGBA: return DXGI_FORMAT_BC7_UNORM;
7923 default: return DXGI_FORMAT_UNKNOWN;
7924 };
7925}
7926
7927_SOKOL_PRIVATE D3D11_PRIMITIVE_TOPOLOGY _sg_d3d11_primitive_topology(sg_primitive_type prim_type) {
7928 switch (prim_type) {
7929 case SG_PRIMITIVETYPE_POINTS: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST;
7930 case SG_PRIMITIVETYPE_LINES: return D3D11_PRIMITIVE_TOPOLOGY_LINELIST;
7931 case SG_PRIMITIVETYPE_LINE_STRIP: return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP;
7932 case SG_PRIMITIVETYPE_TRIANGLES: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
7933 case SG_PRIMITIVETYPE_TRIANGLE_STRIP: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
7934 default: SOKOL_UNREACHABLE; return (D3D11_PRIMITIVE_TOPOLOGY) 0;
7935 }
7936}
7937
7938_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_index_format(sg_index_type index_type) {
7939 switch (index_type) {
7940 case SG_INDEXTYPE_NONE: return DXGI_FORMAT_UNKNOWN;
7941 case SG_INDEXTYPE_UINT16: return DXGI_FORMAT_R16_UINT;
7942 case SG_INDEXTYPE_UINT32: return DXGI_FORMAT_R32_UINT;
7943 default: SOKOL_UNREACHABLE; return (DXGI_FORMAT) 0;
7944 }
7945}
7946
7947_SOKOL_PRIVATE D3D11_FILTER _sg_d3d11_filter(sg_filter min_f, sg_filter mag_f, uint32_t max_anisotropy) {
7948 if (max_anisotropy > 1) {
7949 return D3D11_FILTER_ANISOTROPIC;
7950 }
7951 else if (mag_f == SG_FILTER_NEAREST) {
7952 switch (min_f) {
7953 case SG_FILTER_NEAREST:
7954 case SG_FILTER_NEAREST_MIPMAP_NEAREST:
7955 return D3D11_FILTER_MIN_MAG_MIP_POINT;
7956 case SG_FILTER_LINEAR:
7957 case SG_FILTER_LINEAR_MIPMAP_NEAREST:
7958 return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
7959 case SG_FILTER_NEAREST_MIPMAP_LINEAR:
7960 return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
7961 case SG_FILTER_LINEAR_MIPMAP_LINEAR:
7962 return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
7963 default:
7964 SOKOL_UNREACHABLE; break;
7965 }
7966 }
7967 else if (mag_f == SG_FILTER_LINEAR) {
7968 switch (min_f) {
7969 case SG_FILTER_NEAREST:
7970 case SG_FILTER_NEAREST_MIPMAP_NEAREST:
7971 return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
7972 case SG_FILTER_LINEAR:
7973 case SG_FILTER_LINEAR_MIPMAP_NEAREST:
7974 return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
7975 case SG_FILTER_NEAREST_MIPMAP_LINEAR:
7976 return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
7977 case SG_FILTER_LINEAR_MIPMAP_LINEAR:
7978 return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
7979 default:
7980 SOKOL_UNREACHABLE; break;
7981 }
7982 }
7983 /* invalid value for mag filter */
7984 SOKOL_UNREACHABLE;
7985 return D3D11_FILTER_MIN_MAG_MIP_POINT;
7986}
7987
7988_SOKOL_PRIVATE D3D11_TEXTURE_ADDRESS_MODE _sg_d3d11_address_mode(sg_wrap m) {
7989 switch (m) {
7990 case SG_WRAP_REPEAT: return D3D11_TEXTURE_ADDRESS_WRAP;
7991 case SG_WRAP_CLAMP_TO_EDGE: return D3D11_TEXTURE_ADDRESS_CLAMP;
7992 case SG_WRAP_CLAMP_TO_BORDER: return D3D11_TEXTURE_ADDRESS_BORDER;
7993 case SG_WRAP_MIRRORED_REPEAT: return D3D11_TEXTURE_ADDRESS_MIRROR;
7994 default: SOKOL_UNREACHABLE; return (D3D11_TEXTURE_ADDRESS_MODE) 0;
7995 }
7996}
7997
7998_SOKOL_PRIVATE DXGI_FORMAT _sg_d3d11_vertex_format(sg_vertex_format fmt) {
7999 switch (fmt) {
8000 case SG_VERTEXFORMAT_FLOAT: return DXGI_FORMAT_R32_FLOAT;
8001 case SG_VERTEXFORMAT_FLOAT2: return DXGI_FORMAT_R32G32_FLOAT;
8002 case SG_VERTEXFORMAT_FLOAT3: return DXGI_FORMAT_R32G32B32_FLOAT;
8003 case SG_VERTEXFORMAT_FLOAT4: return DXGI_FORMAT_R32G32B32A32_FLOAT;
8004 case SG_VERTEXFORMAT_BYTE4: return DXGI_FORMAT_R8G8B8A8_SINT;
8005 case SG_VERTEXFORMAT_BYTE4N: return DXGI_FORMAT_R8G8B8A8_SNORM;
8006 case SG_VERTEXFORMAT_UBYTE4: return DXGI_FORMAT_R8G8B8A8_UINT;
8007 case SG_VERTEXFORMAT_UBYTE4N: return DXGI_FORMAT_R8G8B8A8_UNORM;
8008 case SG_VERTEXFORMAT_SHORT2: return DXGI_FORMAT_R16G16_SINT;
8009 case SG_VERTEXFORMAT_SHORT2N: return DXGI_FORMAT_R16G16_SNORM;
8010 case SG_VERTEXFORMAT_USHORT2N: return DXGI_FORMAT_R16G16_UNORM;
8011 case SG_VERTEXFORMAT_SHORT4: return DXGI_FORMAT_R16G16B16A16_SINT;
8012 case SG_VERTEXFORMAT_SHORT4N: return DXGI_FORMAT_R16G16B16A16_SNORM;
8013 case SG_VERTEXFORMAT_USHORT4N: return DXGI_FORMAT_R16G16B16A16_UNORM;
8014 case SG_VERTEXFORMAT_UINT10_N2: return DXGI_FORMAT_R10G10B10A2_UNORM;
8015 default: SOKOL_UNREACHABLE; return (DXGI_FORMAT) 0;
8016 }
8017}
8018
8019_SOKOL_PRIVATE D3D11_INPUT_CLASSIFICATION _sg_d3d11_input_classification(sg_vertex_step step) {
8020 switch (step) {
8021 case SG_VERTEXSTEP_PER_VERTEX: return D3D11_INPUT_PER_VERTEX_DATA;
8022 case SG_VERTEXSTEP_PER_INSTANCE: return D3D11_INPUT_PER_INSTANCE_DATA;
8023 default: SOKOL_UNREACHABLE; return (D3D11_INPUT_CLASSIFICATION) 0;
8024 }
8025}
8026
8027_SOKOL_PRIVATE D3D11_CULL_MODE _sg_d3d11_cull_mode(sg_cull_mode m) {
8028 switch (m) {
8029 case SG_CULLMODE_NONE: return D3D11_CULL_NONE;
8030 case SG_CULLMODE_FRONT: return D3D11_CULL_FRONT;
8031 case SG_CULLMODE_BACK: return D3D11_CULL_BACK;
8032 default: SOKOL_UNREACHABLE; return (D3D11_CULL_MODE) 0;
8033 }
8034}
8035
8036_SOKOL_PRIVATE D3D11_COMPARISON_FUNC _sg_d3d11_compare_func(sg_compare_func f) {
8037 switch (f) {
8038 case SG_COMPAREFUNC_NEVER: return D3D11_COMPARISON_NEVER;
8039 case SG_COMPAREFUNC_LESS: return D3D11_COMPARISON_LESS;
8040 case SG_COMPAREFUNC_EQUAL: return D3D11_COMPARISON_EQUAL;
8041 case SG_COMPAREFUNC_LESS_EQUAL: return D3D11_COMPARISON_LESS_EQUAL;
8042 case SG_COMPAREFUNC_GREATER: return D3D11_COMPARISON_GREATER;
8043 case SG_COMPAREFUNC_NOT_EQUAL: return D3D11_COMPARISON_NOT_EQUAL;
8044 case SG_COMPAREFUNC_GREATER_EQUAL: return D3D11_COMPARISON_GREATER_EQUAL;
8045 case SG_COMPAREFUNC_ALWAYS: return D3D11_COMPARISON_ALWAYS;
8046 default: SOKOL_UNREACHABLE; return (D3D11_COMPARISON_FUNC) 0;
8047 }
8048}
8049
8050_SOKOL_PRIVATE D3D11_STENCIL_OP _sg_d3d11_stencil_op(sg_stencil_op op) {
8051 switch (op) {
8052 case SG_STENCILOP_KEEP: return D3D11_STENCIL_OP_KEEP;
8053 case SG_STENCILOP_ZERO: return D3D11_STENCIL_OP_ZERO;
8054 case SG_STENCILOP_REPLACE: return D3D11_STENCIL_OP_REPLACE;
8055 case SG_STENCILOP_INCR_CLAMP: return D3D11_STENCIL_OP_INCR_SAT;
8056 case SG_STENCILOP_DECR_CLAMP: return D3D11_STENCIL_OP_DECR_SAT;
8057 case SG_STENCILOP_INVERT: return D3D11_STENCIL_OP_INVERT;
8058 case SG_STENCILOP_INCR_WRAP: return D3D11_STENCIL_OP_INCR;
8059 case SG_STENCILOP_DECR_WRAP: return D3D11_STENCIL_OP_DECR;
8060 default: SOKOL_UNREACHABLE; return (D3D11_STENCIL_OP) 0;
8061 }
8062}
8063
8064_SOKOL_PRIVATE D3D11_BLEND _sg_d3d11_blend_factor(sg_blend_factor f) {
8065 switch (f) {
8066 case SG_BLENDFACTOR_ZERO: return D3D11_BLEND_ZERO;
8067 case SG_BLENDFACTOR_ONE: return D3D11_BLEND_ONE;
8068 case SG_BLENDFACTOR_SRC_COLOR: return D3D11_BLEND_SRC_COLOR;
8069 case SG_BLENDFACTOR_ONE_MINUS_SRC_COLOR: return D3D11_BLEND_INV_SRC_COLOR;
8070 case SG_BLENDFACTOR_SRC_ALPHA: return D3D11_BLEND_SRC_ALPHA;
8071 case SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA: return D3D11_BLEND_INV_SRC_ALPHA;
8072 case SG_BLENDFACTOR_DST_COLOR: return D3D11_BLEND_DEST_COLOR;
8073 case SG_BLENDFACTOR_ONE_MINUS_DST_COLOR: return D3D11_BLEND_INV_DEST_COLOR;
8074 case SG_BLENDFACTOR_DST_ALPHA: return D3D11_BLEND_DEST_ALPHA;
8075 case SG_BLENDFACTOR_ONE_MINUS_DST_ALPHA: return D3D11_BLEND_INV_DEST_ALPHA;
8076 case SG_BLENDFACTOR_SRC_ALPHA_SATURATED: return D3D11_BLEND_SRC_ALPHA_SAT;
8077 case SG_BLENDFACTOR_BLEND_COLOR: return D3D11_BLEND_BLEND_FACTOR;
8078 case SG_BLENDFACTOR_ONE_MINUS_BLEND_COLOR: return D3D11_BLEND_INV_BLEND_FACTOR;
8079 case SG_BLENDFACTOR_BLEND_ALPHA: return D3D11_BLEND_BLEND_FACTOR;
8080 case SG_BLENDFACTOR_ONE_MINUS_BLEND_ALPHA: return D3D11_BLEND_INV_BLEND_FACTOR;
8081 default: SOKOL_UNREACHABLE; return (D3D11_BLEND) 0;
8082 }
8083}
8084
8085_SOKOL_PRIVATE D3D11_BLEND_OP _sg_d3d11_blend_op(sg_blend_op op) {
8086 switch (op) {
8087 case SG_BLENDOP_ADD: return D3D11_BLEND_OP_ADD;
8088 case SG_BLENDOP_SUBTRACT: return D3D11_BLEND_OP_SUBTRACT;
8089 case SG_BLENDOP_REVERSE_SUBTRACT: return D3D11_BLEND_OP_REV_SUBTRACT;
8090 default: SOKOL_UNREACHABLE; return (D3D11_BLEND_OP) 0;
8091 }
8092}
8093
8094_SOKOL_PRIVATE UINT8 _sg_d3d11_color_write_mask(sg_color_mask m) {
8095 UINT8 res = 0;
8096 if (m & SG_COLORMASK_R) {
8097 res |= D3D11_COLOR_WRITE_ENABLE_RED;
8098 }
8099 if (m & SG_COLORMASK_G) {
8100 res |= D3D11_COLOR_WRITE_ENABLE_GREEN;
8101 }
8102 if (m & SG_COLORMASK_B) {
8103 res |= D3D11_COLOR_WRITE_ENABLE_BLUE;
8104 }
8105 if (m & SG_COLORMASK_A) {
8106 res |= D3D11_COLOR_WRITE_ENABLE_ALPHA;
8107 }
8108 return res;
8109}
8110
8111/* see: https://docs.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-limits#resource-limits-for-feature-level-11-hardware */
8112_SOKOL_PRIVATE void _sg_d3d11_init_caps(void) {
8113 _sg.backend = SG_BACKEND_D3D11;
8114
8115 _sg.features.instancing = true;
8116 _sg.features.origin_top_left = true;
8117 _sg.features.multiple_render_targets = true;
8118 _sg.features.msaa_render_targets = true;
8119 _sg.features.imagetype_3d = true;
8120 _sg.features.imagetype_array = true;
8121 _sg.features.image_clamp_to_border = true;
8122 _sg.features.mrt_independent_blend_state = true;
8123 _sg.features.mrt_independent_write_mask = true;
8124
8125 _sg.limits.max_image_size_2d = 16 * 1024;
8126 _sg.limits.max_image_size_cube = 16 * 1024;
8127 _sg.limits.max_image_size_3d = 2 * 1024;
8128 _sg.limits.max_image_size_array = 16 * 1024;
8129 _sg.limits.max_image_array_layers = 2 * 1024;
8130 _sg.limits.max_vertex_attrs = SG_MAX_VERTEX_ATTRIBUTES;
8131
8132 /* see: https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_format_support */
8133 for (int fmt = (SG_PIXELFORMAT_NONE+1); fmt < _SG_PIXELFORMAT_NUM; fmt++) {
8134 UINT dxgi_fmt_caps = 0;
8135 const DXGI_FORMAT dxgi_fmt = _sg_d3d11_pixel_format((sg_pixel_format)fmt);
8136 if (dxgi_fmt != DXGI_FORMAT_UNKNOWN) {
8137 HRESULT hr = _sg_d3d11_CheckFormatSupport(_sg.d3d11.dev, dxgi_fmt, &dxgi_fmt_caps);
8138 SOKOL_ASSERT(SUCCEEDED(hr) || (E_FAIL == hr));
8139 if (!SUCCEEDED(hr)) {
8140 dxgi_fmt_caps = 0;
8141 }
8142 }
8143 sg_pixelformat_info* info = &_sg.formats[fmt];
8144 info->sample = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_TEXTURE2D);
8145 info->filter = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_SHADER_SAMPLE);
8146 info->render = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_RENDER_TARGET);
8147 info->blend = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_BLENDABLE);
8148 info->msaa = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RENDERTARGET);
8149 info->depth = 0 != (dxgi_fmt_caps & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL);
8150 if (info->depth) {
8151 info->render = true;
8152 }
8153 }
8154}
8155
8156_SOKOL_PRIVATE void _sg_d3d11_setup_backend(const sg_desc* desc) {
8157 /* assume _sg.d3d11 already is zero-initialized */
8158 SOKOL_ASSERT(desc);
8159 SOKOL_ASSERT(desc->context.d3d11.device);
8160 SOKOL_ASSERT(desc->context.d3d11.device_context);
8161 SOKOL_ASSERT(desc->context.d3d11.render_target_view_cb || desc->context.d3d11.render_target_view_userdata_cb);
8162 SOKOL_ASSERT(desc->context.d3d11.depth_stencil_view_cb || desc->context.d3d11.depth_stencil_view_userdata_cb);
8163 _sg.d3d11.valid = true;
8164 _sg.d3d11.dev = (ID3D11Device*) desc->context.d3d11.device;
8165 _sg.d3d11.ctx = (ID3D11DeviceContext*) desc->context.d3d11.device_context;
8166 _sg.d3d11.rtv_cb = desc->context.d3d11.render_target_view_cb;
8167 _sg.d3d11.rtv_userdata_cb = desc->context.d3d11.render_target_view_userdata_cb;
8168 _sg.d3d11.dsv_cb = desc->context.d3d11.depth_stencil_view_cb;
8169 _sg.d3d11.dsv_userdata_cb = desc->context.d3d11.depth_stencil_view_userdata_cb;
8170 _sg.d3d11.user_data = desc->context.d3d11.user_data;
8171 _sg_d3d11_init_caps();
8172}
8173
8174_SOKOL_PRIVATE void _sg_d3d11_discard_backend(void) {
8175 SOKOL_ASSERT(_sg.d3d11.valid);
8176 _sg.d3d11.valid = false;
8177}
8178
8179_SOKOL_PRIVATE void _sg_d3d11_clear_state(void) {
8180 /* clear all the device context state, so that resource refs don't keep stuck in the d3d device context */
8181 _sg_d3d11_OMSetRenderTargets(_sg.d3d11.ctx, SG_MAX_COLOR_ATTACHMENTS, _sg.d3d11.zero_rtvs, NULL);
8182 _sg_d3d11_RSSetState(_sg.d3d11.ctx, NULL);
8183 _sg_d3d11_OMSetDepthStencilState(_sg.d3d11.ctx, NULL, 0);
8184 _sg_d3d11_OMSetBlendState(_sg.d3d11.ctx, NULL, NULL, 0xFFFFFFFF);
8185 _sg_d3d11_IASetVertexBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_BUFFERS, _sg.d3d11.zero_vbs, _sg.d3d11.zero_vb_strides, _sg.d3d11.zero_vb_offsets);
8186 _sg_d3d11_IASetIndexBuffer(_sg.d3d11.ctx, NULL, DXGI_FORMAT_UNKNOWN, 0);
8187 _sg_d3d11_IASetInputLayout(_sg.d3d11.ctx, NULL);
8188 _sg_d3d11_VSSetShader(_sg.d3d11.ctx, NULL, NULL, 0);
8189 _sg_d3d11_PSSetShader(_sg.d3d11.ctx, NULL, NULL, 0);
8190 _sg_d3d11_VSSetConstantBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_UBS, _sg.d3d11.zero_cbs);
8191 _sg_d3d11_PSSetConstantBuffers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_UBS, _sg.d3d11.zero_cbs);
8192 _sg_d3d11_VSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, _sg.d3d11.zero_srvs);
8193 _sg_d3d11_PSSetShaderResources(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, _sg.d3d11.zero_srvs);
8194 _sg_d3d11_VSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, _sg.d3d11.zero_smps);
8195 _sg_d3d11_PSSetSamplers(_sg.d3d11.ctx, 0, SG_MAX_SHADERSTAGE_IMAGES, _sg.d3d11.zero_smps);
8196}
8197
8198_SOKOL_PRIVATE void _sg_d3d11_reset_state_cache(void) {
8199 /* just clear the d3d11 device context state */
8200 _sg_d3d11_clear_state();
8201}
8202
8203_SOKOL_PRIVATE void _sg_d3d11_activate_context(_sg_context_t* ctx) {
8204 _SOKOL_UNUSED(ctx);
8205 _sg_d3d11_clear_state();
8206}
8207
8208_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_context(_sg_context_t* ctx) {
8209 SOKOL_ASSERT(ctx);
8210 _SOKOL_UNUSED(ctx);
8211 return SG_RESOURCESTATE_VALID;
8212}
8213
8214_SOKOL_PRIVATE void _sg_d3d11_destroy_context(_sg_context_t* ctx) {
8215 SOKOL_ASSERT(ctx);
8216 _SOKOL_UNUSED(ctx);
8217 /* empty */
8218}
8219
8220_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_buffer(_sg_buffer_t* buf, const sg_buffer_desc* desc) {
8221 SOKOL_ASSERT(buf && desc);
8222 SOKOL_ASSERT(!buf->d3d11.buf);
8223 _sg_buffer_common_init(&buf->cmn, desc);
8224 const bool injected = (0 != desc->d3d11_buffer);
8225 if (injected) {
8226 buf->d3d11.buf = (ID3D11Buffer*) desc->d3d11_buffer;
8227 _sg_d3d11_AddRef(buf->d3d11.buf);
8228 }
8229 else {
8230 D3D11_BUFFER_DESC d3d11_desc;
8231 memset(&d3d11_desc, 0, sizeof(d3d11_desc));
8232 d3d11_desc.ByteWidth = (UINT)buf->cmn.size;
8233 d3d11_desc.Usage = _sg_d3d11_usage(buf->cmn.usage);
8234 d3d11_desc.BindFlags = buf->cmn.type == SG_BUFFERTYPE_VERTEXBUFFER ? D3D11_BIND_VERTEX_BUFFER : D3D11_BIND_INDEX_BUFFER;
8235 d3d11_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(buf->cmn.usage);
8236 D3D11_SUBRESOURCE_DATA* init_data_ptr = 0;
8237 D3D11_SUBRESOURCE_DATA init_data;
8238 memset(&init_data, 0, sizeof(init_data));
8239 if (buf->cmn.usage == SG_USAGE_IMMUTABLE) {
8240 SOKOL_ASSERT(desc->data.ptr);
8241 init_data.pSysMem = desc->data.ptr;
8242 init_data_ptr = &init_data;
8243 }
8244 HRESULT hr = _sg_d3d11_CreateBuffer(_sg.d3d11.dev, &d3d11_desc, init_data_ptr, &buf->d3d11.buf);
8245 _SOKOL_UNUSED(hr);
8246 SOKOL_ASSERT(SUCCEEDED(hr) && buf->d3d11.buf);
8247 }
8248 return SG_RESOURCESTATE_VALID;
8249}
8250
8251_SOKOL_PRIVATE void _sg_d3d11_destroy_buffer(_sg_buffer_t* buf) {
8252 SOKOL_ASSERT(buf);
8253 if (buf->d3d11.buf) {
8254 _sg_d3d11_Release(buf->d3d11.buf);
8255 }
8256}
8257
8258_SOKOL_PRIVATE void _sg_d3d11_fill_subres_data(const _sg_image_t* img, const sg_image_data* data) {
8259 const int num_faces = (img->cmn.type == SG_IMAGETYPE_CUBE) ? 6:1;
8260 const int num_slices = (img->cmn.type == SG_IMAGETYPE_ARRAY) ? img->cmn.num_slices:1;
8261 int subres_index = 0;
8262 for (int face_index = 0; face_index < num_faces; face_index++) {
8263 for (int slice_index = 0; slice_index < num_slices; slice_index++) {
8264 for (int mip_index = 0; mip_index < img->cmn.num_mipmaps; mip_index++, subres_index++) {
8265 SOKOL_ASSERT(subres_index < (SG_MAX_MIPMAPS * SG_MAX_TEXTUREARRAY_LAYERS));
8266 D3D11_SUBRESOURCE_DATA* subres_data = &_sg.d3d11.subres_data[subres_index];
8267 const int mip_width = ((img->cmn.width>>mip_index)>0) ? img->cmn.width>>mip_index : 1;
8268 const int mip_height = ((img->cmn.height>>mip_index)>0) ? img->cmn.height>>mip_index : 1;
8269 const sg_range* subimg_data = &(data->subimage[face_index][mip_index]);
8270 const size_t slice_size = subimg_data->size / (size_t)num_slices;
8271 const size_t slice_offset = slice_size * (size_t)slice_index;
8272 const uint8_t* ptr = (const uint8_t*) subimg_data->ptr;
8273 subres_data->pSysMem = ptr + slice_offset;
8274 subres_data->SysMemPitch = (UINT)_sg_row_pitch(img->cmn.pixel_format, mip_width, 1);
8275 if (img->cmn.type == SG_IMAGETYPE_3D) {
8276 /* FIXME? const int mip_depth = ((img->depth>>mip_index)>0) ? img->depth>>mip_index : 1; */
8277 subres_data->SysMemSlicePitch = (UINT)_sg_surface_pitch(img->cmn.pixel_format, mip_width, mip_height, 1);
8278 }
8279 else {
8280 subres_data->SysMemSlicePitch = 0;
8281 }
8282 }
8283 }
8284 }
8285}
8286
8287_SOKOL_PRIVATE sg_resource_state _sg_d3d11_create_image(_sg_image_t* img, const sg_image_desc* desc) {
8288 SOKOL_ASSERT(img && desc);
8289 SOKOL_ASSERT(!img->d3d11.tex2d && !img->d3d11.tex3d && !img->d3d11.texds && !img->d3d11.texmsaa);
8290 SOKOL_ASSERT(!img->d3d11.srv && !img->d3d11.smp);
8291 HRESULT hr;
8292 _SOKOL_UNUSED(hr);
8293
8294 _sg_image_common_init(&img->cmn, desc);
8295 const bool injected = (0 != desc->d3d11_texture) || (0 != desc->d3d11_shader_resource_view);
8296 const bool msaa = (img->cmn.sample_count > 1);
8297 img->d3d11.format = _sg_d3d11_pixel_format(img->cmn.pixel_format);
8298
8299 /* special case depth-stencil buffer? */
8300 if (_sg_is_valid_rendertarget_depth_format(img->cmn.pixel_format)) {
8301 /* create only a depth-texture */
8302 SOKOL_ASSERT(!injected);
8303 if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) {
8304 SOKOL_LOG("trying to create a D3D11 depth-texture with unsupported pixel format\n");
8305 return SG_RESOURCESTATE_FAILED;
8306 }
8307 D3D11_TEXTURE2D_DESC d3d11_desc;
8308 memset(&d3d11_desc, 0, sizeof(d3d11_desc));
8309 d3d11_desc.Width = (UINT)img->cmn.width;
8310 d3d11_desc.Height = (UINT)img->cmn.height;
8311 d3d11_desc.MipLevels = 1;
8312 d3d11_desc.ArraySize = 1;
8313 d3d11_desc.Format = img->d3d11.format;
8314 d3d11_desc.Usage = D3D11_USAGE_DEFAULT;
8315 d3d11_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
8316 d3d11_desc.SampleDesc.Count = (UINT)img->cmn.sample_count;
8317 d3d11_desc.SampleDesc.Quality = (UINT) (msaa ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0);
8318 hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_desc, NULL, &img->d3d11.texds);
8319 SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.texds);
8320 }
8321 else {
8322 /* create (or inject) color texture and shader-resource-view */
8323
8324 /* prepare initial content pointers */
8325 D3D11_SUBRESOURCE_DATA* init_data = 0;
8326 if (!injected && (img->cmn.usage == SG_USAGE_IMMUTABLE) && !img->cmn.render_target) {
8327 _sg_d3d11_fill_subres_data(img, &desc->data);
8328 init_data = _sg.d3d11.subres_data;
8329 }
8330 if (img->cmn.type != SG_IMAGETYPE_3D) {
8331 /* 2D-, cube- or array-texture */
8332 /* if this is an MSAA render target, the following texture will be the 'resolve-texture' */
8333
8334 /* first check for injected texture and/or resource view */
8335 if (injected) {
8336 img->d3d11.tex2d = (ID3D11Texture2D*) desc->d3d11_texture;
8337 img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view;
8338 if (img->d3d11.tex2d) {
8339 _sg_d3d11_AddRef(img->d3d11.tex2d);
8340 }
8341 else {
8342 /* if only a shader-resource-view was provided, but no texture, lookup
8343 the texture from the shader-resource-view, this also bumps the refcount
8344 */
8345 SOKOL_ASSERT(img->d3d11.srv);
8346 _sg_d3d11_GetResource((ID3D11View*)img->d3d11.srv, (ID3D11Resource**)&img->d3d11.tex2d);
8347 SOKOL_ASSERT(img->d3d11.tex2d);
8348 }
8349 if (img->d3d11.srv) {
8350 _sg_d3d11_AddRef(img->d3d11.srv);
8351 }
8352 }
8353
8354 /* if not injected, create texture */
8355 if (0 == img->d3d11.tex2d) {
8356 D3D11_TEXTURE2D_DESC d3d11_tex_desc;
8357 memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc));
8358 d3d11_tex_desc.Width = (UINT)img->cmn.width;
8359 d3d11_tex_desc.Height = (UINT)img->cmn.height;
8360 d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps;
8361 switch (img->cmn.type) {
8362 case SG_IMAGETYPE_ARRAY: d3d11_tex_desc.ArraySize = (UINT)img->cmn.num_slices; break;
8363 case SG_IMAGETYPE_CUBE: d3d11_tex_desc.ArraySize = 6; break;
8364 default: d3d11_tex_desc.ArraySize = 1; break;
8365 }
8366 d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
8367 d3d11_tex_desc.Format = img->d3d11.format;
8368 if (img->cmn.render_target) {
8369 d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT;
8370 if (!msaa) {
8371 d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
8372 }
8373 d3d11_tex_desc.CPUAccessFlags = 0;
8374 }
8375 else {
8376 d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage);
8377 d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage);
8378 }
8379 if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) {
8380 /* trying to create a texture format that's not supported by D3D */
8381 SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n");
8382 return SG_RESOURCESTATE_FAILED;
8383 }
8384 d3d11_tex_desc.SampleDesc.Count = 1;
8385 d3d11_tex_desc.SampleDesc.Quality = 0;
8386 d3d11_tex_desc.MiscFlags = (img->cmn.type == SG_IMAGETYPE_CUBE) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
8387
8388 hr = _sg_d3d11_CreateTexture2D(_sg.d3d11.dev, &d3d11_tex_desc, init_data, &img->d3d11.tex2d);
8389 SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.tex2d);
8390 }
8391
8392 /* ...and similar, if not injected, create shader-resource-view */
8393 if (0 == img->d3d11.srv) {
8394 D3D11_SHADER_RESOURCE_VIEW_DESC d3d11_srv_desc;
8395 memset(&d3d11_srv_desc, 0, sizeof(d3d11_srv_desc));
8396 d3d11_srv_desc.Format = img->d3d11.format;
8397 switch (img->cmn.type) {
8398 case SG_IMAGETYPE_2D:
8399 d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
8400 d3d11_srv_desc.Texture2D.MipLevels = (UINT)img->cmn.num_mipmaps;
8401 break;
8402 case SG_IMAGETYPE_CUBE:
8403 d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURECUBE;
8404 d3d11_srv_desc.TextureCube.MipLevels = (UINT)img->cmn.num_mipmaps;
8405 break;
8406 case SG_IMAGETYPE_ARRAY:
8407 d3d11_srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
8408 d3d11_srv_desc.Texture2DArray.MipLevels = (UINT)img->cmn.num_mipmaps;
8409 d3d11_srv_desc.Texture2DArray.ArraySize = (UINT)img->cmn.num_slices;
8410 break;
8411 default:
8412 SOKOL_UNREACHABLE; break;
8413 }
8414 hr = _sg_d3d11_CreateShaderResourceView(_sg.d3d11.dev, (ID3D11Resource*)img->d3d11.tex2d, &d3d11_srv_desc, &img->d3d11.srv);
8415 SOKOL_ASSERT(SUCCEEDED(hr) && img->d3d11.srv);
8416 }
8417 }
8418 else {
8419 /* 3D texture - same procedure, first check if injected, than create non-injected */
8420 if (injected) {
8421 img->d3d11.tex3d = (ID3D11Texture3D*) desc->d3d11_texture;
8422 img->d3d11.srv = (ID3D11ShaderResourceView*) desc->d3d11_shader_resource_view;
8423 if (img->d3d11.tex3d) {
8424 _sg_d3d11_AddRef(img->d3d11.tex3d);
8425 }
8426 else {
8427 SOKOL_ASSERT(img->d3d11.srv);
8428 _sg_d3d11_GetResource((ID3D11View*)img->d3d11.srv, (ID3D11Resource**)&img->d3d11.tex3d);
8429 SOKOL_ASSERT(img->d3d11.tex3d);
8430 }
8431 if (img->d3d11.srv) {
8432 _sg_d3d11_AddRef(img->d3d11.srv);
8433 }
8434 }
8435
8436 if (0 == img->d3d11.tex3d) {
8437 D3D11_TEXTURE3D_DESC d3d11_tex_desc;
8438 memset(&d3d11_tex_desc, 0, sizeof(d3d11_tex_desc));
8439 d3d11_tex_desc.Width = (UINT)img->cmn.width;
8440 d3d11_tex_desc.Height = (UINT)img->cmn.height;
8441 d3d11_tex_desc.Depth = (UINT)img->cmn.num_slices;
8442 d3d11_tex_desc.MipLevels = (UINT)img->cmn.num_mipmaps;
8443 d3d11_tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
8444 d3d11_tex_desc.Format = img->d3d11.format;
8445 if (img->cmn.render_target) {
8446 d3d11_tex_desc.Usage = D3D11_USAGE_DEFAULT;
8447 if (!msaa) {
8448 d3d11_tex_desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
8449 }
8450 d3d11_tex_desc.CPUAccessFlags = 0;
8451 }
8452 else {
8453 d3d11_tex_desc.Usage = _sg_d3d11_usage(img->cmn.usage);
8454 d3d11_tex_desc.CPUAccessFlags = _sg_d3d11_cpu_access_flags(img->cmn.usage);
8455 }
8456 if (img->d3d11.format == DXGI_FORMAT_UNKNOWN) {
8457 /* trying to create a texture format that's not supported by D3D */
8458 SOKOL_LOG("trying to create a D3D11 texture with unsupported pixel format\n");