forked from floooh/sokol
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sokol_gfx.h
14146 lines (12910 loc) · 578 KB
/
sokol_gfx.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef SOKOL_GFX_INCLUDED
/*
sokol_gfx.h -- simple 3D API wrapper
Project URL: https://github.com/floooh/sokol
Do this:
#define SOKOL_IMPL
before you include this file in *one* C or C++ file to create the
implementation.
In the same place define one of the following to select the rendering
backend:
#define SOKOL_GLCORE33
#define SOKOL_GLES2
#define SOKOL_GLES3
#define SOKOL_D3D11
#define SOKOL_METAL
#define SOKOL_WGPU
#define SOKOL_DUMMY_BACKEND
I.e. for the GL 3.3 Core Profile it should look like this:
#include ...
#include ...
#define SOKOL_IMPL
#define SOKOL_GLCORE33
#include "sokol_gfx.h"
The dummy backend replaces the platform-specific backend code with empty
stub functions. This is useful for writing tests that need to run on the
command line.
Optionally provide the following defines with your own implementations:
SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
SOKOL_MALLOC(s) - your own malloc function (default: malloc(s))
SOKOL_FREE(p) - your own free function (default: free(p))
SOKOL_LOG(msg) - your own logging function (default: puts(msg))
SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
SOKOL_API_DECL - public function declaration prefix (default: extern)
SOKOL_API_IMPL - public function implementation prefix (default: -)
SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS)
If sokol_gfx.h is compiled as a DLL, define the following before
including the declaration or implementation:
SOKOL_DLL
On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport)
or __declspec(dllimport) as needed.
If you want to compile without deprecated structs and functions,
define:
SOKOL_NO_DEPRECATED
API usage validation macros:
SOKOL_VALIDATE_BEGIN() - begin a validation block (default:_sg_validate_begin())
SOKOL_VALIDATE(cond, err) - like assert but for API validation (default: _sg_validate(cond, err))
SOKOL_VALIDATE_END() - end a validation block, return true if all checks in block passed (default: bool _sg_validate())
If you don't want validation errors to be fatal, define SOKOL_VALIDATE_NON_FATAL,
be aware though that this may spam SOKOL_LOG messages.
Optionally define the following to force debug checks and validations
even in release mode:
SOKOL_DEBUG - by default this is defined if _DEBUG is defined
sokol_gfx DOES NOT:
===================
- create a window or the 3D-API context/device, you must do this
before sokol_gfx is initialized, and pass any required information
(like 3D device pointers) to the sokol_gfx initialization call
- present the rendered frame, how this is done exactly usually depends
on how the window and 3D-API context/device was created
- provide a unified shader language, instead 3D-API-specific shader
source-code or shader-bytecode must be provided
For complete code examples using the various backend 3D-APIs, see:
https://github.com/floooh/sokol-samples
For an optional shader-cross-compile solution, see:
https://github.com/floooh/sokol-tools/blob/master/docs/sokol-shdc.md
STEP BY STEP
============
--- to initialize sokol_gfx, after creating a window and a 3D-API
context/device, call:
sg_setup(const sg_desc*)
--- create resource objects (at least buffers, shaders and pipelines,
and optionally images and passes):
sg_buffer sg_make_buffer(const sg_buffer_desc*)
sg_image sg_make_image(const sg_image_desc*)
sg_shader sg_make_shader(const sg_shader_desc*)
sg_pipeline sg_make_pipeline(const sg_pipeline_desc*)
sg_pass sg_make_pass(const sg_pass_desc*)
--- start rendering to the default frame buffer with:
sg_begin_default_pass(const sg_pass_action* actions, int width, int height)
--- or start rendering to an offscreen framebuffer with:
sg_begin_pass(sg_pass pass, const sg_pass_action* actions)
--- set the pipeline state for the next draw call with:
sg_apply_pipeline(sg_pipeline pip)
--- fill an sg_bindings struct with the resource bindings for the next
draw call (1..N vertex buffers, 0 or 1 index buffer, 0..N image objects
to use as textures each on the vertex-shader- and fragment-shader-stage
and then call
sg_apply_bindings(const sg_bindings* bindings)
to update the resource bindings
--- optionally update shader uniform data with:
sg_apply_uniforms(sg_shader_stage stage, int ub_index, const void* data, int num_bytes)
--- kick off a draw call with:
sg_draw(int base_element, int num_elements, int num_instances)
--- finish the current rendering pass with:
sg_end_pass()
--- when done with the current frame, call
sg_commit()
--- at the end of your program, shutdown sokol_gfx with:
sg_shutdown()
--- if you need to destroy resources before sg_shutdown(), call:
sg_destroy_buffer(sg_buffer buf)
sg_destroy_image(sg_image img)
sg_destroy_shader(sg_shader shd)
sg_destroy_pipeline(sg_pipeline pip)
sg_destroy_pass(sg_pass pass)
--- to set a new viewport rectangle, call
sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left)
--- to set a new scissor rect, call:
sg_apply_scissor_rect(int x, int y, int width, int height, bool origin_top_left)
both sg_apply_viewport() and sg_apply_scissor_rect() must be called
inside a rendering pass
beginning a pass will reset the viewport to the size of the framebuffer used
in the new pass,
--- to update (overwrite) the content of buffer and image resources, call:
sg_update_buffer(sg_buffer buf, const void* ptr, int num_bytes)
sg_update_image(sg_image img, const sg_image_content* content)
Buffers and images to be updated must have been created with
SG_USAGE_DYNAMIC or SG_USAGE_STREAM
Only one update per frame is allowed for buffer and image resources.
The rationale is to have a simple countermeasure to avoid the CPU
scribbling over data the GPU is currently using, or the CPU having to
wait for the GPU
Buffer and image updates can be partial, as long as a rendering
operation only references the valid (updated) data in the
buffer or image.
--- to append a chunk of data to a buffer resource, call:
int sg_append_buffer(sg_buffer buf, const void* ptr, int num_bytes)
The difference to sg_update_buffer() is that sg_append_buffer()
can be called multiple times per frame to append new data to the
buffer piece by piece, optionally interleaved with draw calls referencing
the previously written data.
sg_append_buffer() returns a byte offset to the start of the
written data, this offset can be assigned to
sg_bindings.vertex_buffer_offsets[n] or
sg_bindings.index_buffer_offset
Code example:
for (...) {
const void* data = ...;
const int num_bytes = ...;
int offset = sg_append_buffer(buf, data, num_bytes);
bindings.vertex_buffer_offsets[0] = offset;
sg_apply_pipeline(pip);
sg_apply_bindings(&bindings);
sg_apply_uniforms(...);
sg_draw(...);
}
A buffer to be used with sg_append_buffer() must have been created
with SG_USAGE_DYNAMIC or SG_USAGE_STREAM.
If the application appends more data to the buffer then fits into
the buffer, the buffer will go into the "overflow" state for the
rest of the frame.
Any draw calls attempting to render an overflown buffer will be
silently dropped (in debug mode this will also result in a
validation error).
You can also check manually if a buffer is in overflow-state by calling
bool sg_query_buffer_overflow(sg_buffer buf)
NOTE: Due to restrictions in underlying 3D-APIs, appended chunks of
data will be 4-byte aligned in the destination buffer. This means
that there will be gaps in index buffers containing 16-bit indices
when the number of indices in a call to sg_append_buffer() is
odd. This isn't a problem when each call to sg_append_buffer()
is associated with one draw call, but will be problematic when
a single indexed draw call spans several appended chunks of indices.
--- to check at runtime for optional features, limits and pixelformat support,
call:
sg_features sg_query_features()
sg_limits sg_query_limits()
sg_pixelformat_info sg_query_pixelformat(sg_pixel_format fmt)
--- if you need to call into the underlying 3D-API directly, you must call:
sg_reset_state_cache()
...before calling sokol_gfx functions again
--- you can inspect the original sg_desc structure handed to sg_setup()
by calling sg_query_desc(). This will return an sg_desc struct with
the default values patched in instead of any zero-initialized values
--- you can inspect various internal resource attributes via:
sg_buffer_info sg_query_buffer_info(sg_buffer buf)
sg_image_info sg_query_image_info(sg_image img)
sg_shader_info sg_query_shader_info(sg_shader shd)
sg_pipeline_info sg_query_pipeline_info(sg_pipeline pip)
sg_pass_info sg_query_pass_info(sg_pass pass)
...please note that the returned info-structs are tied quite closely
to sokol_gfx.h internals, and may change more often than other
public API functions and structs.
--- you can ask at runtime what backend sokol_gfx.h has been compiled
for, or whether the GLES3 backend had to fall back to GLES2 with:
sg_backend sg_query_backend(void)
--- you can query the default resource creation parameters through the functions
sg_buffer_desc sg_query_buffer_defaults(const sg_buffer_desc* desc)
sg_image_desc sg_query_image_defaults(const sg_image_desc* desc)
sg_shader_desc sg_query_shader_defaults(const sg_shader_desc* desc)
sg_pipeline_desc sg_query_pipeline_defaults(const sg_pipeline_desc* desc)
sg_pass_desc sg_query_pass_defaults(const sg_pass_desc* desc)
These functions take a pointer to a desc structure which may contain
zero-initialized items for default values. These zero-init values
will be replaced with their concrete values in the returned desc
struct.
ON INITIALIZATION:
==================
When calling sg_setup(), a pointer to an sg_desc struct must be provided
which contains initialization options. These options provide two types
of information to sokol-gfx:
(1) upper bounds and limits needed to allocate various internal
data structures:
- the max number of resources of each type that can
be alive at the same time, this is used for allocating
internal pools
- the max overall size of uniform data that can be
updated per frame, including a worst-case alignment
per uniform update (this worst-case alignment is 256 bytes)
- the max size of all dynamic resource updates (sg_update_buffer,
sg_append_buffer and sg_update_image) per frame
- the max number of entries in the texture sampler cache
(how many unique texture sampler can exist at the same time)
Not all of those limit values are used by all backends, but it is
good practice to provide them none-the-less.
(2) 3D-API "context information" (sometimes also called "bindings"):
sokol_gfx.h doesn't create or initialize 3D API objects which are
closely related to the presentation layer (this includes the "rendering
device", the swapchain, and any objects which depend on the
swapchain). These API objects (or callback functions to obtain
them, if those objects might change between frames), must
be provided in a nested sg_context_desc struct inside the
sg_desc struct. If sokol_gfx.h is used together with
sokol_app.h, have a look at the sokol_glue.h header which provides
a convenience function to get a sg_context_desc struct filled out
with context information provided by sokol_app.h
See the documention block of the sg_desc struct below for more information.
BACKEND-SPECIFIC TOPICS:
========================
--- the GL backends need to know about the internal structure of uniform
blocks, and the texture sampler-name and -type:
typedef struct {
float mvp[16]; // model-view-projection matrix
float offset0[2]; // some 2D vectors
float offset1[2];
float offset2[2];
} params_t;
// uniform block structure and texture image definition in sg_shader_desc:
sg_shader_desc desc = {
// uniform block description (size and internal structure)
.vs.uniform_blocks[0] = {
.size = sizeof(params_t),
.uniforms = {
[0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 },
[1] = { .name="offset0", .type=SG_UNIFORMTYPE_VEC2 },
...
}
},
// one texture on the fragment-shader-stage, GLES2/WebGL needs name and image type
.fs.images[0] = { .name="tex", .type=SG_IMAGETYPE_ARRAY }
...
};
--- the Metal and D3D11 backends only need to know the size of uniform blocks,
not their internal member structure, and they only need to know
the type of a texture sampler, not its name:
sg_shader_desc desc = {
.vs.uniform_blocks[0].size = sizeof(params_t),
.fs.images[0].type = SG_IMAGETYPE_ARRAY,
...
};
--- when creating a shader object, GLES2/WebGL need to know the vertex
attribute names as used in the vertex shader:
sg_shader_desc desc = {
.attrs = {
[0] = { .name="position" },
[1] = { .name="color1" }
}
};
The vertex attribute names provided when creating a shader will be
used later in sg_create_pipeline() for matching the vertex layout
to vertex shader inputs.
--- on D3D11 you need to provide a semantic name and semantic index in the
shader description struct instead (see the D3D11 documentation on
D3D11_INPUT_ELEMENT_DESC for details):
sg_shader_desc desc = {
.attrs = {
[0] = { .sem_name="POSITION", .sem_index=0 }
[1] = { .sem_name="COLOR", .sem_index=1 }
}
};
The provided semantic information will be used later in sg_create_pipeline()
to match the vertex layout to vertex shader inputs.
--- on Metal, GL 3.3 or GLES3/WebGL2, you don't need to provide an attribute
name or semantic name, since vertex attributes can be bound by their slot index
(this is mandatory in Metal, and optional in GL):
sg_pipeline_desc desc = {
.layout = {
.attrs = {
[0] = { .format=SG_VERTEXFORMAT_FLOAT3 },
[1] = { .format=SG_VERTEXFORMAT_FLOAT4 }
}
}
};
WORKING WITH CONTEXTS
=====================
sokol-gfx allows to switch between different rendering contexts and
associate resource objects with contexts. This is useful to
create GL applications that render into multiple windows.
A rendering context keeps track of all resources created while
the context is active. When the context is destroyed, all resources
"belonging to the context" are destroyed as well.
A default context will be created and activated implicitly in
sg_setup(), and destroyed in sg_shutdown(). So for a typical application
which *doesn't* use multiple contexts, nothing changes, and calling
the context functions isn't necessary.
Three functions have been added to work with contexts:
--- sg_context sg_setup_context():
This must be called once after a GL context has been created and
made active.
--- void sg_activate_context(sg_context ctx)
This must be called after making a different GL context active.
Apart from 3D-API-specific actions, the call to sg_activate_context()
will internally call sg_reset_state_cache().
--- void sg_discard_context(sg_context ctx)
This must be called right before a GL context is destroyed and
will destroy all resources associated with the context (that
have been created while the context was active) The GL context must be
active at the time sg_discard_context(sg_context ctx) is called.
Also note that resources (buffers, images, shaders and pipelines) must
only be used or destroyed while the same GL context is active that
was also active while the resource was created (an exception is
resource sharing on GL, such resources can be used while
another context is active, but must still be destroyed under
the same context that was active during creation).
For more information, check out the multiwindow-glfw sample:
https://github.com/floooh/sokol-samples/blob/master/glfw/multiwindow-glfw.c
TRACE HOOKS:
============
sokol_gfx.h optionally allows to install "trace hook" callbacks for
each public API functions. When a public API function is called, and
a trace hook callback has been installed for this function, the
callback will be invoked with the parameters and result of the function.
This is useful for things like debugging- and profiling-tools, or
keeping track of resource creation and destruction.
To use the trace hook feature:
--- Define SOKOL_TRACE_HOOKS before including the implementation.
--- Setup an sg_trace_hooks structure with your callback function
pointers (keep all function pointers you're not interested
in zero-initialized), optionally set the user_data member
in the sg_trace_hooks struct.
--- Install the trace hooks by calling sg_install_trace_hooks(),
the return value of this function is another sg_trace_hooks
struct which contains the previously set of trace hooks.
You should keep this struct around, and call those previous
functions pointers from your own trace callbacks for proper
chaining.
As an example of how trace hooks are used, have a look at the
imgui/sokol_gfx_imgui.h header which implements a realtime
debugging UI for sokol_gfx.h on top of Dear ImGui.
A NOTE ON PORTABLE PACKED VERTEX FORMATS:
=========================================
There are two things to consider when using packed
vertex formats like UBYTE4, SHORT2, etc which need to work
across all backends:
- D3D11 can only convert *normalized* vertex formats to
floating point during vertex fetch, normalized formats
have a trailing 'N', and are "normalized" to a range
-1.0..+1.0 (for the signed formats) or 0.0..1.0 (for the
unsigned formats):
- SG_VERTEXFORMAT_BYTE4N
- SG_VERTEXFORMAT_UBYTE4N
- SG_VERTEXFORMAT_SHORT2N
- SG_VERTEXFORMAT_USHORT2N
- SG_VERTEXFORMAT_SHORT4N
- SG_VERTEXFORMAT_USHORT4N
D3D11 will not convert *non-normalized* vertex formats to floating point
vertex shader inputs, those can only be uses with the *ivecn* vertex shader
input types when D3D11 is used as backend (GL and Metal can use both formats)
- SG_VERTEXFORMAT_BYTE4,
- SG_VERTEXFORMAT_UBYTE4
- SG_VERTEXFORMAT_SHORT2
- SG_VERTEXFORMAT_SHORT4
- WebGL/GLES2 cannot use integer vertex shader inputs (int or ivecn)
- SG_VERTEXFORMAT_UINT10_N2 is not supported on WebGL/GLES2
So for a vertex input layout which works on all platforms, only use the following
vertex formats, and if needed "expand" the normalized vertex shader
inputs in the vertex shader by multiplying with 127.0, 255.0, 32767.0 or
65535.0:
- SG_VERTEXFORMAT_FLOAT,
- SG_VERTEXFORMAT_FLOAT2,
- SG_VERTEXFORMAT_FLOAT3,
- SG_VERTEXFORMAT_FLOAT4,
- SG_VERTEXFORMAT_BYTE4N,
- SG_VERTEXFORMAT_UBYTE4N,
- SG_VERTEXFORMAT_SHORT2N,
- SG_VERTEXFORMAT_USHORT2N
- SG_VERTEXFORMAT_SHORT4N,
- SG_VERTEXFORMAT_USHORT4N
TODO:
====
- talk about asynchronous resource creation
zlib/libpng license
Copyright (c) 2018 Andre Weissflog
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software in a
product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#define SOKOL_GFX_INCLUDED (1)
#include <stdint.h>
#include <stdbool.h>
#ifndef SOKOL_API_DECL
#if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL)
#define SOKOL_API_DECL __declspec(dllexport)
#elif defined(_WIN32) && defined(SOKOL_DLL)
#define SOKOL_API_DECL __declspec(dllimport)
#else
#define SOKOL_API_DECL extern
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */
#endif
/*
Resource id typedefs:
sg_buffer: vertex- and index-buffers
sg_image: textures and render targets
sg_shader: vertex- and fragment-shaders, uniform blocks
sg_pipeline: associated shader and vertex-layouts, and render states
sg_pass: a bundle of render targets and actions on them
sg_context: a 'context handle' for switching between 3D-API contexts
Instead of pointers, resource creation functions return a 32-bit
number which uniquely identifies the resource object.
The 32-bit resource id is split into a 16-bit pool index in the lower bits,
and a 16-bit 'unique counter' in the upper bits. The index allows fast
pool lookups, and combined with the unique-mask it allows to detect
'dangling accesses' (trying to use an object which no longer exists, and
its pool slot has been reused for a new object)
The resource ids are wrapped into a struct so that the compiler
can complain when the wrong resource type is used.
*/
typedef struct sg_buffer { uint32_t id; } sg_buffer;
typedef struct sg_image { uint32_t id; } sg_image;
typedef struct sg_shader { uint32_t id; } sg_shader;
typedef struct sg_pipeline { uint32_t id; } sg_pipeline;
typedef struct sg_pass { uint32_t id; } sg_pass;
typedef struct sg_context { uint32_t id; } sg_context;
/*
various compile-time constants
FIXME: it may make sense to convert some of those into defines so
that the user code can override them.
*/
enum {
SG_INVALID_ID = 0,
SG_NUM_SHADER_STAGES = 2,
SG_NUM_INFLIGHT_FRAMES = 2,
SG_MAX_COLOR_ATTACHMENTS = 4,
SG_MAX_SHADERSTAGE_BUFFERS = 8,
SG_MAX_SHADERSTAGE_IMAGES = 12,
SG_MAX_SHADERSTAGE_UBS = 4,
SG_MAX_UB_MEMBERS = 16,
SG_MAX_VERTEX_ATTRIBUTES = 16, /* NOTE: actual max vertex attrs can be less on GLES2, see sg_limits! */
SG_MAX_MIPMAPS = 16,
SG_MAX_TEXTUREARRAY_LAYERS = 128
};
/*
sg_backend
The active 3D-API backend, use the function sg_query_backend()
to get the currently active backend.
For returned value corresponds with the compile-time define to select
a backend, with the only exception of SOKOL_GLES3: this may
return SG_BACKEND_GLES2 if the backend has to fallback to GLES2 mode
because GLES3 isn't supported.
*/
typedef enum sg_backend {
SG_BACKEND_GLCORE33,
SG_BACKEND_GLES2,
SG_BACKEND_GLES3,
SG_BACKEND_D3D11,
SG_BACKEND_METAL_IOS,
SG_BACKEND_METAL_MACOS,
SG_BACKEND_METAL_SIMULATOR,
SG_BACKEND_WGPU,
SG_BACKEND_DUMMY,
} sg_backend;
/*
sg_pixel_format
sokol_gfx.h basically uses the same pixel formats as WebGPU, since these
are supported on most newer GPUs. GLES2 and WebGL has a much smaller
subset of available pixel formats. Call sg_query_pixelformat() to check
at runtime if a pixel format supports the desired features.
A pixelformat name consist of three parts:
- components (R, RG, RGB or RGBA)
- bit width per component (8, 16 or 32)
- component data type:
- unsigned normalized (no postfix)
- signed normalized (SN postfix)
- unsigned integer (UI postfix)
- signed integer (SI postfix)
- float (F postfix)
Not all pixel formats can be used for everything, call sg_query_pixelformat()
to inspect the capabilities of a given pixelformat. The function returns
an sg_pixelformat_info struct with the following bool members:
- sample: the pixelformat can be sampled as texture at least with
nearest filtering
- filter: the pixelformat can be samples as texture with linear
filtering
- render: the pixelformat can be used for render targets
- blend: blending is supported when using the pixelformat for
render targets
- msaa: multisample-antialiasing is supported when using the
pixelformat for render targets
- depth: the pixelformat can be used for depth-stencil attachments
When targeting GLES2/WebGL, the only safe formats to use
as texture are SG_PIXELFORMAT_R8 and SG_PIXELFORMAT_RGBA8. For rendering
in GLES2/WebGL, only SG_PIXELFORMAT_RGBA8 is safe. All other formats
must be checked via sg_query_pixelformats().
The default pixel format for texture images is SG_PIXELFORMAT_RGBA8.
The default pixel format for render target images is platform-dependent:
- for Metal and D3D11 it is SG_PIXELFORMAT_BGRA8
- for GL backends it is SG_PIXELFORMAT_RGBA8
This is mainly because of the default framebuffer which is setup outside
of sokol_gfx.h. On some backends, using BGRA for the default frame buffer
allows more efficient frame flips. For your own offscreen-render-targets,
use whatever renderable pixel format is convenient for you.
*/
typedef enum sg_pixel_format {
_SG_PIXELFORMAT_DEFAULT, /* value 0 reserved for default-init */
SG_PIXELFORMAT_NONE,
SG_PIXELFORMAT_R8,
SG_PIXELFORMAT_R8SN,
SG_PIXELFORMAT_R8UI,
SG_PIXELFORMAT_R8SI,
SG_PIXELFORMAT_R16,
SG_PIXELFORMAT_R16SN,
SG_PIXELFORMAT_R16UI,
SG_PIXELFORMAT_R16SI,
SG_PIXELFORMAT_R16F,
SG_PIXELFORMAT_RG8,
SG_PIXELFORMAT_RG8SN,
SG_PIXELFORMAT_RG8UI,
SG_PIXELFORMAT_RG8SI,
SG_PIXELFORMAT_R32UI,
SG_PIXELFORMAT_R32SI,
SG_PIXELFORMAT_R32F,
SG_PIXELFORMAT_RG16,
SG_PIXELFORMAT_RG16SN,
SG_PIXELFORMAT_RG16UI,
SG_PIXELFORMAT_RG16SI,
SG_PIXELFORMAT_RG16F,
SG_PIXELFORMAT_RGBA8,
SG_PIXELFORMAT_RGBA8SN,
SG_PIXELFORMAT_RGBA8UI,
SG_PIXELFORMAT_RGBA8SI,
SG_PIXELFORMAT_BGRA8,
SG_PIXELFORMAT_RGB10A2,
SG_PIXELFORMAT_RG11B10F,
SG_PIXELFORMAT_RG32UI,
SG_PIXELFORMAT_RG32SI,
SG_PIXELFORMAT_RG32F,
SG_PIXELFORMAT_RGBA16,
SG_PIXELFORMAT_RGBA16SN,
SG_PIXELFORMAT_RGBA16UI,
SG_PIXELFORMAT_RGBA16SI,
SG_PIXELFORMAT_RGBA16F,
SG_PIXELFORMAT_RGBA32UI,
SG_PIXELFORMAT_RGBA32SI,
SG_PIXELFORMAT_RGBA32F,
SG_PIXELFORMAT_DEPTH,
SG_PIXELFORMAT_DEPTH_STENCIL,
SG_PIXELFORMAT_BC1_RGBA,
SG_PIXELFORMAT_BC2_RGBA,
SG_PIXELFORMAT_BC3_RGBA,
SG_PIXELFORMAT_BC4_R,
SG_PIXELFORMAT_BC4_RSN,
SG_PIXELFORMAT_BC5_RG,
SG_PIXELFORMAT_BC5_RGSN,
SG_PIXELFORMAT_BC6H_RGBF,
SG_PIXELFORMAT_BC6H_RGBUF,
SG_PIXELFORMAT_BC7_RGBA,
SG_PIXELFORMAT_PVRTC_RGB_2BPP,
SG_PIXELFORMAT_PVRTC_RGB_4BPP,
SG_PIXELFORMAT_PVRTC_RGBA_2BPP,
SG_PIXELFORMAT_PVRTC_RGBA_4BPP,
SG_PIXELFORMAT_ETC2_RGB8,
SG_PIXELFORMAT_ETC2_RGB8A1,
SG_PIXELFORMAT_ETC2_RGBA8,
SG_PIXELFORMAT_ETC2_RG11,
SG_PIXELFORMAT_ETC2_RG11SN,
_SG_PIXELFORMAT_NUM,
_SG_PIXELFORMAT_FORCE_U32 = 0x7FFFFFFF
} sg_pixel_format;
/*
Runtime information about a pixel format, returned
by sg_query_pixelformat().
*/
typedef struct sg_pixelformat_info {
bool sample; /* pixel format can be sampled in shaders */
bool filter; /* pixel format can be sampled with filtering */
bool render; /* pixel format can be used as render target */
bool blend; /* alpha-blending is supported */
bool msaa; /* pixel format can be used as MSAA render target */
bool depth; /* pixel format is a depth format */
} sg_pixelformat_info;
/*
Runtime information about available optional features,
returned by sg_query_features()
*/
typedef struct sg_features {
bool instancing; /* hardware instancing supported */
bool origin_top_left; /* framebuffer and texture origin is in top left corner */
bool multiple_render_targets; /* offscreen render passes can have multiple render targets attached */
bool msaa_render_targets; /* offscreen render passes support MSAA antialiasing */
bool imagetype_3d; /* creation of SG_IMAGETYPE_3D images is supported */
bool imagetype_array; /* creation of SG_IMAGETYPE_ARRAY images is supported */
bool image_clamp_to_border; /* border color and clamp-to-border UV-wrap mode is supported */
} sg_features;
/*
Runtime information about resource limits, returned by sg_query_limit()
*/
typedef struct sg_limits {
uint32_t max_image_size_2d; /* max width/height of SG_IMAGETYPE_2D images */
uint32_t max_image_size_cube; /* max width/height of SG_IMAGETYPE_CUBE images */
uint32_t max_image_size_3d; /* max width/height/depth of SG_IMAGETYPE_3D images */
uint32_t max_image_size_array; /* max width/height pf SG_IMAGETYPE_ARRAY images */
uint32_t max_image_array_layers; /* max number of layers in SG_IMAGETYPE_ARRAY images */
uint32_t max_vertex_attrs; /* <= SG_MAX_VERTEX_ATTRIBUTES (only on some GLES2 impls) */
} sg_limits;
/*
sg_resource_state
The current state of a resource in its resource pool.
Resources start in the INITIAL state, which means the
pool slot is unoccupied and can be allocated. When a resource is
created, first an id is allocated, and the resource pool slot
is set to state ALLOC. After allocation, the resource is
initialized, which may result in the VALID or FAILED state. The
reason why allocation and initialization are separate is because
some resource types (e.g. buffers and images) might be asynchronously
initialized by the user application. If a resource which is not
in the VALID state is attempted to be used for rendering, rendering
operations will silently be dropped.
The special INVALID state is returned in sg_query_xxx_state() if no
resource object exists for the provided resource id.
*/
typedef enum sg_resource_state {
SG_RESOURCESTATE_INITIAL,
SG_RESOURCESTATE_ALLOC,
SG_RESOURCESTATE_VALID,
SG_RESOURCESTATE_FAILED,
SG_RESOURCESTATE_INVALID,
_SG_RESOURCESTATE_FORCE_U32 = 0x7FFFFFFF
} sg_resource_state;
/*
sg_usage
A resource usage hint describing the update strategy of
buffers and images. This is used in the sg_buffer_desc.usage
and sg_image_desc.usage members when creating buffers
and images:
SG_USAGE_IMMUTABLE: the resource will never be updated with
new data, instead the content of the
resource must be provided on creation
SG_USAGE_DYNAMIC: the resource will be updated infrequently
with new data (this could range from "once
after creation", to "quite often but not
every frame")
SG_USAGE_STREAM: the resource will be updated each frame
with new content
The rendering backends use this hint to prevent that the
CPU needs to wait for the GPU when attempting to update
a resource that might be currently accessed by the GPU.
Resource content is updated with the function sg_update_buffer() for
buffer objects, and sg_update_image() for image objects. Only
one update is allowed per frame and resource object. The
application must update all data required for rendering (this
means that the update data can be smaller than the resource size,
if only a part of the overall resource size is used for rendering,
you only need to make sure that the data that *is* used is valid).
The default usage is SG_USAGE_IMMUTABLE.
*/
typedef enum sg_usage {
_SG_USAGE_DEFAULT, /* value 0 reserved for default-init */
SG_USAGE_IMMUTABLE,
SG_USAGE_DYNAMIC,
SG_USAGE_STREAM,
_SG_USAGE_NUM,
_SG_USAGE_FORCE_U32 = 0x7FFFFFFF
} sg_usage;
/*
sg_buffer_type
This indicates whether a buffer contains vertex- or index-data,
used in the sg_buffer_desc.type member when creating a buffer.
The default value is SG_BUFFERTYPE_VERTEXBUFFER.
*/
typedef enum sg_buffer_type {
_SG_BUFFERTYPE_DEFAULT, /* value 0 reserved for default-init */
SG_BUFFERTYPE_VERTEXBUFFER,
SG_BUFFERTYPE_INDEXBUFFER,
_SG_BUFFERTYPE_NUM,
_SG_BUFFERTYPE_FORCE_U32 = 0x7FFFFFFF
} sg_buffer_type;
/*
sg_index_type
Indicates whether indexed rendering (fetching vertex-indices from an
index buffer) is used, and if yes, the index data type (16- or 32-bits).
This is used in the sg_pipeline_desc.index_type member when creating a
pipeline object.
The default index type is SG_INDEXTYPE_NONE.
*/
typedef enum sg_index_type {
_SG_INDEXTYPE_DEFAULT, /* value 0 reserved for default-init */
SG_INDEXTYPE_NONE,
SG_INDEXTYPE_UINT16,
SG_INDEXTYPE_UINT32,
_SG_INDEXTYPE_NUM,
_SG_INDEXTYPE_FORCE_U32 = 0x7FFFFFFF
} sg_index_type;
/*
sg_image_type
Indicates the basic type of an image object (2D-texture, cubemap,
3D-texture or 2D-array-texture). 3D- and array-textures are not supported
on the GLES2/WebGL backend (use sg_query_features().imagetype_3d and
sg_query_features().imagetype_array to check for support). The image type
is used in the sg_image_desc.type member when creating an image, and
in sg_shader_image_desc when describing a shader's texture sampler binding.
The default image type when creating an image is SG_IMAGETYPE_2D.
*/
typedef enum sg_image_type {
_SG_IMAGETYPE_DEFAULT, /* value 0 reserved for default-init */
SG_IMAGETYPE_2D,
SG_IMAGETYPE_CUBE,
SG_IMAGETYPE_3D,
SG_IMAGETYPE_ARRAY,
_SG_IMAGETYPE_NUM,
_SG_IMAGETYPE_FORCE_U32 = 0x7FFFFFFF
} sg_image_type;
/*
sg_sampler_type
Indicates the basic data type of a shader's texture sampler which
can be float , unsigned integer or signed integer. The sampler
type is used in the sg_shader_image_desc to describe the
sampler type of a shader's texture sampler binding.
The default sampler type is SG_SAMPLERTYPE_FLOAT.
*/
typedef enum sg_sampler_type {
_SG_SAMPLERTYPE_DEFAULT, /* value 0 reserved for default-init */
SG_SAMPLERTYPE_FLOAT,
SG_SAMPLERTYPE_SINT,
SG_SAMPLERTYPE_UINT,
} sg_sampler_type;
/*
sg_cube_face
The cubemap faces. Use these as indices in the sg_image_desc.content
array.
*/
typedef enum sg_cube_face {
SG_CUBEFACE_POS_X,
SG_CUBEFACE_NEG_X,
SG_CUBEFACE_POS_Y,
SG_CUBEFACE_NEG_Y,
SG_CUBEFACE_POS_Z,
SG_CUBEFACE_NEG_Z,
SG_CUBEFACE_NUM,
_SG_CUBEFACE_FORCE_U32 = 0x7FFFFFFF
} sg_cube_face;
/*
sg_shader_stage
There are 2 shader stages: vertex- and fragment-shader-stage.
Each shader stage consists of:
- one slot for a shader function (provided as source- or byte-code)
- SG_MAX_SHADERSTAGE_UBS slots for uniform blocks
- SG_MAX_SHADERSTAGE_IMAGES slots for images used as textures by
the shader function
*/
typedef enum sg_shader_stage {
SG_SHADERSTAGE_VS,
SG_SHADERSTAGE_FS,
_SG_SHADERSTAGE_FORCE_U32 = 0x7FFFFFFF
} sg_shader_stage;
/*
sg_primitive_type
This is the common subset of 3D primitive types supported across all 3D
APIs. This is used in the sg_pipeline_desc.primitive_type member when
creating a pipeline object.
The default primitive type is SG_PRIMITIVETYPE_TRIANGLES.
*/
typedef enum sg_primitive_type {
_SG_PRIMITIVETYPE_DEFAULT, /* value 0 reserved for default-init */
SG_PRIMITIVETYPE_POINTS,
SG_PRIMITIVETYPE_LINES,
SG_PRIMITIVETYPE_LINE_STRIP,
SG_PRIMITIVETYPE_TRIANGLES,
SG_PRIMITIVETYPE_TRIANGLE_STRIP,
_SG_PRIMITIVETYPE_NUM,
_SG_PRIMITIVETYPE_FORCE_U32 = 0x7FFFFFFF