forked from skylersaleh/SkyEmu
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchanges.patch
More file actions
7903 lines (7580 loc) · 389 KB
/
changes.patch
File metadata and controls
7903 lines (7580 loc) · 389 KB
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
diff --git a/src/sokol/sokol_gfx.h b/src/sokol/sokol_gfx.h
index 8727666..ecd79d9 100644
--- a/src/sokol/sokol_gfx.h
+++ b/src/sokol/sokol_gfx.h
@@ -39,15 +39,15 @@
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_GFX_API_DECL - public function declaration prefix (default: extern)
- SOKOL_API_DECL - same as SOKOL_GFX_API_DECL
- SOKOL_API_IMPL - public function implementation prefix (default: -)
- SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS)
+ SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
+ SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
+ SOKOL_GFX_API_DECL - public function declaration prefix (default: extern)
+ SOKOL_API_DECL - same as SOKOL_GFX_API_DECL
+ SOKOL_API_IMPL - public function implementation prefix (default: -)
+ SOKOL_TRACE_HOOKS - enable trace hook callbacks (search below for TRACE HOOKS)
+ SOKOL_EXTERNAL_GL_LOADER - indicates that you're using your own GL loader, in this case
+ sokol_gfx.h will not include any platform GL headers and disable
+ the integrated Win32 GL loader
If sokol_gfx.h is compiled as a DLL, define the following before
including the declaration or implementation:
@@ -81,6 +81,7 @@
offline shader cross-compiler, see here:
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
@@ -88,6 +89,30 @@
sg_setup(const sg_desc*)
+ Depending on the selected 3D backend, sokol-gfx requires some
+ information, like a device pointer framebuffer pixel formats
+ and so on. If you are using sokol_app.h for the window system
+ glue, you can use a helper function provided in the sokol_glue.h
+ header:
+
+ #include "sokol_gfx.h"
+ #include "sokol_app.h"
+ #include "sokol_glue.h"
+ //...
+ sg_setup(&(sg_desc){
+ .context = sapp_sgcontext(),
+ });
+
+ To get any logging output for errors and from the validation layer, you
+ need to provide a logging callback. Easiest way is through sokol_log.h:
+
+ #include "sokol_log.h"
+ //...
+ sg_setup(&(sg_desc){
+ //...
+ .logger.func = slog_func,
+ });
+
--- create resource objects (at least buffers, shaders and pipelines,
and optionally images and passes):
@@ -126,7 +151,10 @@
--- optionally update shader uniform data with:
- sg_apply_uniforms(sg_shader_stage stage, int ub_index, const void* data, int num_bytes)
+ sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data)
+
+ Read the section 'UNIFORM DATA LAYOUT' to learn about the expected memory layout
+ of the uniform data passed into sg_apply_uniforms().
--- kick off a draw call with:
@@ -166,7 +194,7 @@
sg_apply_viewport(int x, int y, int width, int height, bool origin_top_left)
- ...or if you want to specifiy the viewport rectangle with float values:
+ ...or if you want to specify the viewport rectangle with float values:
sg_apply_viewportf(float x, float y, float width, float height, bool origin_top_left)
@@ -243,6 +271,11 @@
bool sg_query_buffer_overflow(sg_buffer buf)
+ You can manually check to see if an overflow would occur before adding
+ any data to a buffer by calling
+
+ bool sg_query_buffer_will_overflow(sg_buffer buf, size_t size)
+
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
@@ -268,22 +301,25 @@
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)
+ --- you can get a desc struct matching the creation attributes of a
+ specific resource object via:
- ...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.
+ sg_buffer_desc sg_query_buffer_desc(sg_buffer buf)
+ sg_image_desc sg_query_image_desc(sg_image img)
+ sg_shader_desc sq_query_shader_desc(sg_shader shd)
+ sg_pipeline_desc sg_query_pipeline_desc(sg_pipeline pip)
+ sg_pass_desc sg_query_pass_desc(sg_pass pass)
- --- 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:
+ ...but NOTE that the returned desc structs may be incomplete, only
+ creation attributes that are kept around internally after resource
+ creation will be filled in, and in some cases (like shaders) that's
+ very little. Any missing attributes will be set to zero. The returned
+ desc structs might still be useful as partial blueprint for creating
+ similar resources if filled up with the missing attributes.
- sg_backend sg_query_backend(void)
+ Calling the query-desc functions on an invalid resource will return
+ completely zeroed structs (it makes sense to check the resource state
+ with sg_query_*_state() first)
--- you can query the default resource creation parameters through the functions
@@ -298,6 +334,24 @@
will be replaced with their concrete values in the returned desc
struct.
+ --- you can inspect various internal resource runtime values 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)
+
+
ON INITIALIZATION:
==================
When calling sg_setup(), a pointer to an sg_desc struct must be provided
@@ -331,30 +385,129 @@
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.
+ See the documentation block of the sg_desc struct below for more information.
+
+
+ UNIFORM DATA LAYOUT:
+ ====================
+ NOTE: if you use the sokol-shdc shader compiler tool, you don't need to worry
+ about the following details.
+
+ The data that's passed into the sg_apply_uniforms() function must adhere to
+ specific layout rules so that the GPU shader finds the uniform block
+ items at the right offset.
+
+ For the D3D11 and Metal backends, sokol-gfx only cares about the size of uniform
+ blocks, but not about the internal layout. The data will just be copied into
+ a uniform/constant buffer in a single operation and it's up you to arrange the
+ CPU-side layout so that it matches the GPU side layout. This also means that with
+ the D3D11 and Metal backends you are not limited to a 'cross-platform' subset
+ of uniform variable types.
+
+ If you ever only use one of the D3D11, Metal *or* WebGPU backend, you can stop reading here.
+
+ For the GL backends, the internal layout of uniform blocks matters though,
+ and you are limited to a small number of uniform variable types. This is
+ because sokol-gfx must be able to locate the uniform block members in order
+ to upload them to the GPU with glUniformXXX() calls.
+
+ To describe the uniform block layout to sokol-gfx, the following information
+ must be passed to the sg_make_shader() call in the sg_shader_desc struct:
+
+ - a hint about the used packing rule (either SG_UNIFORMLAYOUT_NATIVE or
+ SG_UNIFORMLAYOUT_STD140)
+ - a list of the uniform block members types in the correct order they
+ appear on the CPU side
+
+ For example if the GLSL shader has the following uniform declarations:
+
+ uniform mat4 mvp;
+ uniform vec2 offset0;
+ uniform vec2 offset1;
+ uniform vec2 offset2;
+
+ ...and on the CPU side, there's a similar C struct:
+
+ typedef struct {
+ float mvp[16];
+ float offset0[2];
+ float offset1[2];
+ float offset2[2];
+ } params_t;
+
+ ...the uniform block description in the sg_shader_desc must look like this:
+
+ sg_shader_desc desc = {
+ .vs.uniform_blocks[0] = {
+ .size = sizeof(params_t),
+ .layout = SG_UNIFORMLAYOUT_NATIVE, // this is the default and can be omitted
+ .uniforms = {
+ // order must be the same as in 'params_t':
+ [0] = { .name = "mvp", .type = SG_UNIFORMTYPE_MAT4 },
+ [1] = { .name = "offset0", .type = SG_UNIFORMTYPE_VEC2 },
+ [2] = { .name = "offset1", .type = SG_UNIFORMTYPE_VEC2 },
+ [3] = { .name = "offset2", .type = SG_UNIFORMTYPE_VEC2 },
+ }
+ }
+ };
+
+ With this information sokol-gfx can now compute the correct offsets of the data items
+ within the uniform block struct.
+
+ The SG_UNIFORMLAYOUT_NATIVE packing rule works fine if only the GL backends are used,
+ but for proper D3D11/Metal/GL a subset of the std140 layout must be used which is
+ described in the next section:
+
+
+ CROSS-BACKEND COMMON UNIFORM DATA LAYOUT
+ ========================================
+ For cross-platform / cross-3D-backend code it is important that the same uniform block
+ layout on the CPU side can be used for all sokol-gfx backends. To achieve this,
+ a common subset of the std140 layout must be used:
+
+ - The uniform block layout hint in sg_shader_desc must be explicitly set to
+ SG_UNIFORMLAYOUT_STD140.
+ - Only the following GLSL uniform types can be used (with their associated sokol-gfx enums):
+ - float => SG_UNIFORMTYPE_FLOAT
+ - vec2 => SG_UNIFORMTYPE_FLOAT2
+ - vec3 => SG_UNIFORMTYPE_FLOAT3
+ - vec4 => SG_UNIFORMTYPE_FLOAT4
+ - int => SG_UNIFORMTYPE_INT
+ - ivec2 => SG_UNIFORMTYPE_INT2
+ - ivec3 => SG_UNIFORMTYPE_INT3
+ - ivec4 => SG_UNIFORMTYPE_INT4
+ - mat4 => SG_UNIFORMTYPE_MAT4
+ - Alignment for those types must be as follows (in bytes):
+ - float => 4
+ - vec2 => 8
+ - vec3 => 16
+ - vec4 => 16
+ - int => 4
+ - ivec2 => 8
+ - ivec3 => 16
+ - ivec4 => 16
+ - mat4 => 16
+ - Arrays are only allowed for the following types: vec4, int4, mat4.
+
+ Note that the HLSL cbuffer layout rules are slightly different from the
+ std140 layout rules, this means that the cbuffer declarations in HLSL code
+ must be tweaked so that the layout is compatible with std140.
+
+ The by far easiest way to tacke the common uniform block layout problem is
+ to use the sokol-shdc shader cross-compiler tool!
+
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;
+ --- The GL backends need to know about the internal structure of uniform
+ blocks, and the texture sampler-name and -type. The uniform layout details
+ are described in the UNIFORM DATA LAYOUT section above.
// 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 }
@@ -431,6 +584,7 @@
}
};
+
WORKING WITH CONTEXTS
=====================
sokol-gfx allows to switch between different rendering contexts and
@@ -474,6 +628,7 @@
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
@@ -503,6 +658,7 @@
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
@@ -531,9 +687,11 @@
- SG_VERTEXFORMAT_SHORT2
- SG_VERTEXFORMAT_SHORT4
- - WebGL/GLES2 cannot use integer vertex shader inputs (int or ivecn)
+ - WebGL/GLES2 cannot use integer vertex shader inputs (int or ivecn) or the following:
- - SG_VERTEXFORMAT_UINT10_N2 is not supported on WebGL/GLES2
+ - SG_VERTEXFORMAT_UINT10_N2
+ - SG_VERTEXFORMAT_HALF2, SG_VERTEXFORMAT_HALF4
+ (commonly supported extension: OES_vertex_half_float)
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
@@ -551,10 +709,278 @@
- SG_VERTEXFORMAT_SHORT4N,
- SG_VERTEXFORMAT_USHORT4N
- TODO:
- ====
- - talk about asynchronous resource creation
+ MEMORY ALLOCATION OVERRIDE
+ ==========================
+ You can override the memory allocation functions at initialization time
+ like this:
+
+ void* my_alloc(size_t size, void* user_data) {
+ return malloc(size);
+ }
+
+ void my_free(void* ptr, void* user_data) {
+ free(ptr);
+ }
+
+ ...
+ sg_setup(&(sg_desc){
+ // ...
+ .allocator = {
+ .alloc = my_alloc,
+ .free = my_free,
+ .user_data = ...,
+ }
+ });
+ ...
+
+ If no overrides are provided, malloc and free will be used.
+
+ This only affects memory allocation calls done by sokol_gfx.h
+ itself though, not any allocations in OS libraries.
+
+ ERROR REPORTING AND LOGGING
+ ===========================
+ To get any logging information at all you need to provide a logging callback in the setup call
+ the easiest way is to use sokol_log.h:
+
+ #include "sokol_log.h"
+
+ sg_setup(&(sg_desc){ .logger.func = slog_func });
+
+ To override logging with your own callback, first write a logging function like this:
+
+ void my_log(const char* tag, // e.g. 'sg'
+ uint32_t log_level, // 0=panic, 1=error, 2=warn, 3=info
+ uint32_t log_item_id, // SG_LOGITEM_*
+ const char* message_or_null, // a message string, may be nullptr in release mode
+ uint32_t line_nr, // line number in sokol_gfx.h
+ const char* filename_or_null, // source filename, may be nullptr in release mode
+ void* user_data)
+ {
+ ...
+ }
+
+ ...and then setup sokol-gfx like this:
+
+ sg_setup(&(sg_desc){
+ .logger = {
+ .func = my_log,
+ .user_data = my_user_data,
+ }
+ });
+
+ The provided logging function must be reentrant (e.g. be callable from
+ different threads).
+
+ If you don't want to provide your own custom logger it is highly recommended to use
+ the standard logger in sokol_log.h instead, otherwise you won't see any warnings or
+ errors.
+
+
+ COMMIT LISTENERS
+ ================
+ It's possible to hook callback functions into sokol-gfx which are called from
+ inside sg_commit() in unspecified order. This is mainly useful for libraries
+ that build on top of sokol_gfx.h to be notified about the end/start of a frame.
+
+ To add a commit listener, call:
+
+ static void my_commit_listener(void* user_data) {
+ ...
+ }
+
+ bool success = sg_add_commit_listener((sg_commit_listener){
+ .func = my_commit_listener,
+ .user_data = ...,
+ });
+
+ The function returns false if the internal array of commit listeners is full,
+ or the same commit listener had already been added.
+
+ If the function returns true, my_commit_listener() will be called each frame
+ from inside sg_commit().
+
+ By default, 1024 distinct commit listeners can be added, but this number
+ can be tweaked in the sg_setup() call:
+
+ sg_setup(&(sg_desc){
+ .max_commit_listeners = 2048,
+ });
+
+ An sg_commit_listener item is equal to another if both the function
+ pointer and user_data field are equal.
+
+ To remove a commit listener:
+
+ bool success = sg_remove_commit_listener((sg_commit_listener){
+ .func = my_commit_listener,
+ .user_data = ...,
+ });
+
+ ...where the .func and .user_data field are equal to a previous
+ sg_add_commit_listener() call. The function returns true if the commit
+ listener item was found and removed, and false otherwise.
+
+
+ RESOURCE CREATION AND DESTRUCTION IN DETAIL
+ ===========================================
+ The 'vanilla' way to create resource objects is with the 'make functions':
+
+ sg_buffer sg_make_buffer(const sg_buffer_desc* desc)
+ sg_image sg_make_image(const sg_image_desc* desc)
+ sg_shader sg_make_shader(const sg_shader_desc* desc)
+ sg_pipeline sg_make_pipeline(const sg_pipeline_desc* desc)
+ sg_pass sg_make_pass(const sg_pass_desc* desc)
+
+ This will result in one of three cases:
+
+ 1. The returned handle is invalid. This happens when there are no more
+ free slots in the resource pool for this resource type. An invalid
+ handle is associated with the INVALID resource state, for instance:
+
+ sg_buffer buf = sg_make_buffer(...)
+ if (sg_query_buffer_state(buf) == SG_RESOURCESTATE_INVALID) {
+ // buffer pool is exhausted
+ }
+
+ 2. The returned handle is valid, but creating the underlying resource
+ has failed for some reason. This results in a resource object in the
+ FAILED state. The reason *why* resource creation has failed differ
+ by resource type. Look for log messages with more details. A failed
+ resource state can be checked with:
+
+ sg_buffer buf = sg_make_buffer(...)
+ if (sg_query_buffer_state(buf) == SG_RESOURCESTATE_FAILED) {
+ // creating the resource has failed
+ }
+
+ 3. And finally, if everything goes right, the returned resource is
+ in resource state VALID and ready to use. This can be checked
+ with:
+
+ sg_buffer buf = sg_make_buffer(...)
+ if (sg_query_buffer_state(buf) == SG_RESOURCESTATE_VALID) {
+ // creating the resource has failed
+ }
+
+ When calling the 'make functions', the created resource goes through a number
+ of states:
+
+ - INITIAL: the resource slot associated with the new resource is currently
+ free (technically, there is no resource yet, just an empty pool slot)
+ - ALLOC: a handle for the new resource has been allocated, this just means
+ a pool slot has been reserved.
+ - VALID or FAILED: in VALID state any 3D API backend resource objects have
+ been successfully created, otherwise if anything went wrong, the resource
+ will be in FAILED state.
+
+ Sometimes it makes sense to first grab a handle, but initialize the
+ underlying resource at a later time. For instance when loading data
+ asynchronously from a slow data source, you may know what buffers and
+ textures are needed at an early stage of the loading process, but actually
+ loading the buffer or texture content can only be completed at a later time.
+
+ For such situations, sokol-gfx resource objects can be created in two steps.
+ You can allocate a handle upfront with one of the 'alloc functions':
+
+ sg_buffer sg_alloc_buffer(void)
+ sg_image sg_alloc_image(void)
+ sg_shader sg_alloc_shader(void)
+ sg_pipeline sg_alloc_pipeline(void)
+ sg_pass sg_alloc_pass(void)
+
+ This will return a handle with the underlying resource object in the
+ ALLOC state:
+
+ sg_image img = sg_alloc_image();
+ if (sg_query_image_state(img) == SG_RESOURCESTATE_ALLOC) {
+ // allocating an image handle has succeeded, otherwise
+ // the image pool is full
+ }
+
+ Such an 'incomplete' handle can be used in most sokol-gfx rendering functions
+ without doing any harm, sokol-gfx will simply skip any rendering operation
+ that involve resources which are not in VALID state.
+
+ At a later time (for instance once the texture has completed loading
+ asynchronously), the resource creation can be completed by calling one of
+ the 'init functions', those functions take an existing resource handle and
+ 'desc struct':
+
+ void sg_init_buffer(sg_buffer buf, const sg_buffer_desc* desc)
+ void sg_init_image(sg_image img, const sg_image_desc* desc)
+ void sg_init_shader(sg_shader shd, const sg_shader_desc* desc)
+ void sg_init_pipeline(sg_pipeline pip, const sg_pipeline_desc* desc)
+ void sg_init_pass(sg_pass pass, const sg_pass_desc* desc)
+
+ The init functions expect a resource in ALLOC state, and after the function
+ returns, the resource will be either in VALID or FAILED state. Calling
+ an 'alloc function' followed by the matching 'init function' is fully
+ equivalent with calling the 'make function' alone.
+
+ Destruction can also happen as a two-step process. The 'uninit functions'
+ will put a resource object from the VALID or FAILED state back into the
+ ALLOC state:
+
+ void sg_uninit_buffer(sg_buffer buf)
+ void sg_uninit_image(sg_image img)
+ void sg_uninit_shader(sg_shader shd)
+ void sg_uninit_pipeline(sg_pipeline pip)
+ void sg_uninit_pass(sg_pass pass)
+
+ Calling the 'uninit functions' with a resource that is not in the VALID or
+ FAILED state is a no-op.
+
+ To finally free the pool slot for recycling call the 'dealloc functions':
+
+ void sg_dealloc_buffer(sg_buffer buf)
+ void sg_dealloc_image(sg_image img)
+ void sg_dealloc_shader(sg_shader shd)
+ void sg_dealloc_pipeline(sg_pipeline pip)
+ void sg_dealloc_pass(sg_pass pass)
+
+ Calling the 'dealloc functions' on a resource that's not in ALLOC state is
+ a no-op, but will generate a warning log message.
+
+ Calling an 'uninit function' and 'dealloc function' in sequence is equivalent
+ with calling the associated 'destroy function':
+
+ void sg_destroy_buffer(sg_buffer buf)
+ void sg_destroy_image(sg_image img)
+ void sg_destroy_shader(sg_shader shd)
+ void sg_destroy_pipeline(sg_pipeline pip)
+ void sg_destroy_pass(sg_pass pass)
+
+ The 'destroy functions' can be called on resources in any state and generally
+ do the right thing (for instance if the resource is in ALLOC state, the destroy
+ function will be equivalent to the 'dealloc function' and skip the 'uninit part').
+
+ And finally to close the circle, the 'fail functions' can be called to manually
+ put a resource in ALLOC state into the FAILED state:
+
+ sg_fail_buffer(sg_buffer buf)
+ sg_fail_image(sg_image img)
+ sg_fail_shader(sg_shader shd)
+ sg_fail_pipeline(sg_pipeline pip)
+ sg_fail_pass(sg_pass pass)
+
+ This is recommended if anything went wrong outside of sokol-gfx during asynchronous
+ resource creation (for instance the file loading operation failed). In this case,
+ the 'fail function' should be called instead of the 'init function'.
+
+ Calling a 'fail function' on a resource that's not in ALLOC state is a no-op,
+ but will generate a warning log message.
+
+ NOTE: that two-step resource creation usually only makes sense for buffers
+ and images, but not for shaders, pipelines or passes. Most notably, trying
+ to create a pipeline object with a shader that's not in VALID state will
+ trigger a validation layer error, or if the validation layer is disabled,
+ result in a pipeline object in FAILED state. Same when trying to create
+ a pass object with image invalid image objects.
+
+ LICENSE
+ =======
zlib/libpng license
Copyright (c) 2018 Andre Weissflog
@@ -644,7 +1070,7 @@ typedef struct sg_range {
// disabling this for every includer isn't great, but the warnings are also quite pointless
#if defined(_MSC_VER)
#pragma warning(disable:4221) /* /W4 only: nonstandard extension used: 'x': cannot be initialized using address of automatic variable 'y' */
-#pragma warning(disable:4202) /* VS2015: nonstandard extension used: non-constant aggregate initializer */
+#pragma warning(disable:4204) /* VS2015: nonstandard extension used: non-constant aggregate initializer */
#endif
#if defined(__cplusplus)
#define SG_RANGE(x) sg_range{ &x, sizeof(x) }
@@ -777,6 +1203,7 @@ typedef enum sg_pixel_format {
SG_PIXELFORMAT_RG16SI,
SG_PIXELFORMAT_RG16F,
SG_PIXELFORMAT_RGBA8,
+ SG_PIXELFORMAT_SRGB8A8,
SG_PIXELFORMAT_RGBA8SN,
SG_PIXELFORMAT_RGBA8UI,
SG_PIXELFORMAT_RGBA8SI,
@@ -820,6 +1247,8 @@ typedef enum sg_pixel_format {
SG_PIXELFORMAT_ETC2_RG11,
SG_PIXELFORMAT_ETC2_RG11SN,
+ SG_PIXELFORMAT_RGB9E5,
+
_SG_PIXELFORMAT_NUM,
_SG_PIXELFORMAT_FORCE_U32 = 0x7FFFFFFF
} sg_pixel_format;
@@ -868,7 +1297,9 @@ typedef struct sg_limits {
int max_image_size_3d; // max width/height/depth of SG_IMAGETYPE_3D images
int max_image_size_array; // max width/height of SG_IMAGETYPE_ARRAY images
int max_image_array_layers; // max number of layers in SG_IMAGETYPE_ARRAY images
- int max_vertex_attrs; // <= SG_MAX_VERTEX_ATTRIBUTES (only on some GLES2 impls)
+ int max_vertex_attrs; // <= SG_MAX_VERTEX_ATTRIBUTES or less (on some GLES2 impls)
+ int gl_max_vertex_uniform_vectors; // <= GL_MAX_VERTEX_UNIFORM_VECTORS (only on GL backends)
+ int gl_max_combined_texture_image_units; // <= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS (only on GL backends)
} sg_limits;
/*
@@ -1168,6 +1599,8 @@ typedef enum sg_vertex_format {
SG_VERTEXFORMAT_SHORT4N,
SG_VERTEXFORMAT_USHORT4N,
SG_VERTEXFORMAT_UINT10_N2,
+ SG_VERTEXFORMAT_HALF2,
+ SG_VERTEXFORMAT_HALF4,
_SG_VERTEXFORMAT_NUM,
_SG_VERTEXFORMAT_FORCE_U32 = 0x7FFFFFFF
} sg_vertex_format;
@@ -1204,11 +1637,57 @@ typedef enum sg_uniform_type {
SG_UNIFORMTYPE_FLOAT2,
SG_UNIFORMTYPE_FLOAT3,
SG_UNIFORMTYPE_FLOAT4,
+ SG_UNIFORMTYPE_INT,
+ SG_UNIFORMTYPE_INT2,
+ SG_UNIFORMTYPE_INT3,
+ SG_UNIFORMTYPE_INT4,
SG_UNIFORMTYPE_MAT4,
_SG_UNIFORMTYPE_NUM,
_SG_UNIFORMTYPE_FORCE_U32 = 0x7FFFFFFF
} sg_uniform_type;
+/*
+ sg_uniform_layout
+
+ A hint for the interior memory layout of uniform blocks. This is
+ only really relevant for the GL backend where the internal layout
+ of uniform blocks must be known to sokol-gfx. For all other backends the
+ internal memory layout of uniform blocks doesn't matter, sokol-gfx
+ will just pass uniform data as a single memory blob to the
+ 3D backend.
+
+ SG_UNIFORMLAYOUT_NATIVE (default)
+ Native layout means that a 'backend-native' memory layout
+ is used. For the GL backend this means that uniforms
+ are packed tightly in memory (e.g. there are no padding
+ bytes).
+
+ SG_UNIFORMLAYOUT_STD140
+ The memory layout is a subset of std140. Arrays are only
+ allowed for the FLOAT4, INT4 and MAT4. Alignment is as
+ is as follows:
+
+ FLOAT, INT: 4 byte alignment
+ FLOAT2, INT2: 8 byte alignment
+ FLOAT3, INT3: 16 byte alignment(!)
+ FLOAT4, INT4: 16 byte alignment
+ MAT4: 16 byte alignment
+ FLOAT4[], INT4[]: 16 byte alignment
+
+ The overall size of the uniform block must be a multiple
+ of 16.
+
+ For more information search for 'UNIFORM DATA LAYOUT' in the documentation block
+ at the start of the header.
+*/
+typedef enum sg_uniform_layout {
+ _SG_UNIFORMLAYOUT_DEFAULT, /* value 0 reserved for default-init */
+ SG_UNIFORMLAYOUT_NATIVE, /* default: layout depends on currently active backend */
+ SG_UNIFORMLAYOUT_STD140, /* std140: memory layout according to std140 */
+ _SG_UNIFORMLAYOUT_NUM,
+ _SG_UNIFORMLAYOUT_FORCE_U32 = 0x7FFFFFFF
+} sg_uniform_layout;
+
/*
sg_cull_mode
@@ -1710,6 +2189,7 @@ typedef struct sg_image_desc {
defaults are "vs_4_0" and "ps_4_0")
- reflection info for each uniform block used by the shader stage:
- the size of the uniform block in bytes
+ - a memory layout hint (native vs std140, only required for GL backends)
- reflection info for each uniform block member (only required for GL backends):
- member name
- member type (SG_UNIFORMTYPE_xxx)
@@ -1742,6 +2222,7 @@ typedef struct sg_shader_uniform_desc {
typedef struct sg_shader_uniform_block_desc {
size_t size;
+ sg_uniform_layout layout;
sg_shader_uniform_desc uniforms[SG_MAX_UB_MEMBERS];
} sg_shader_uniform_block_desc;
@@ -1811,9 +2292,9 @@ typedef struct sg_shader_desc {
.enabled: false
.front/back:
.compare: SG_COMPAREFUNC_ALWAYS
+ .fail_op: SG_STENCILOP_KEEP
.depth_fail_op: SG_STENCILOP_KEEP
.pass_op: SG_STENCILOP_KEEP
- .compare: SG_COMPAREFUNC_ALWAYS
.read_mask: 0
.write_mask: 0
.ref: 0
@@ -2075,12 +2556,10 @@ typedef struct sg_image_info {
uint32_t upd_frame_index; /* frame index of last sg_update_image() */
int num_slots; /* number of renaming-slots for dynamically updated images */
int active_slot; /* currently active write-slot for dynamically updated images */
- int width; /* image width */
- int height; /* image height */
} sg_image_info;
typedef struct sg_shader_info {
- sg_slot_info slot; /* resoure pool slot info */
+ sg_slot_info slot; /* resource pool slot info */
} sg_shader_info;
typedef struct sg_pipeline_info {
@@ -2091,6 +2570,198 @@ typedef struct sg_pass_info {
sg_slot_info slot; /* resource pool slot info */
} sg_pass_info;
+/*
+ sg_log_item
+
+ An enum with a unique item for each log message, warning, error
+ and validation layer message.
+*/
+#define _SG_LOG_ITEMS \
+ _SG_LOGITEM_XMACRO(OK, "Ok") \
+ _SG_LOGITEM_XMACRO(MALLOC_FAILED, "memory allocation failed") \
+ _SG_LOGITEM_XMACRO(GL_TEXTURE_FORMAT_NOT_SUPPORTED, "pixel format not supported for texture (gl)") \
+ _SG_LOGITEM_XMACRO(GL_3D_TEXTURES_NOT_SUPPORTED, "3d textures not supported (gl)") \
+ _SG_LOGITEM_XMACRO(GL_ARRAY_TEXTURES_NOT_SUPPORTED, "array textures not supported (gl)") \
+ _SG_LOGITEM_XMACRO(GL_SHADER_COMPILATION_FAILED, "shader compilation failed (gl)") \
+ _SG_LOGITEM_XMACRO(GL_SHADER_LINKING_FAILED, "shader linking failed (gl)") \
+ _SG_LOGITEM_XMACRO(GL_VERTEX_ATTRIBUTE_NOT_FOUND_IN_SHADER, "vertex attribute not found in shader (gl)") \
+ _SG_LOGITEM_XMACRO(GL_FRAMEBUFFER_INCOMPLETE, "framebuffer completeness check failed (gl)") \
+ _SG_LOGITEM_XMACRO(GL_MSAA_FRAMEBUFFER_INCOMPLETE, "completeness check failed for msaa resolve framebuffer (gl)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_BUFFER_FAILED, "CreateBuffer() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for depth-stencil texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_TEXTURE_FAILED, "CreateTexture2D() failed for depth-stencil texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_2D_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for 2d-, cube- or array-texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_2D_TEXTURE_FAILED, "CreateTexture2D() failed for 2d-, cube- or array-texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_2D_SRV_FAILED, "CreateShaderResourceView() failed for 2d-, cube- or array-texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_3D_TEXTURE_UNSUPPORTED_PIXEL_FORMAT, "pixel format not supported for 3D texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_3D_TEXTURE_FAILED, "CreateTexture3D() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_3D_SRV_FAILED, "CreateShaderResourceView() failed for 3d texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_MSAA_TEXTURE_FAILED, "CreateTexture2D() failed for MSAA render target texture (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_SAMPLER_STATE_FAILED, "CreateSamplerState() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_LOAD_D3DCOMPILER_47_DLL_FAILED, "loading d3dcompiler_47.dll failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_SHADER_COMPILATION_FAILED, "shader compilation failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_SHADER_COMPILATION_OUTPUT, "") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_CONSTANT_BUFFER_FAILED, "CreateBuffer() failed for uniform constant buffer (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_INPUT_LAYOUT_FAILED, "CreateInputLayout() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_RASTERIZER_STATE_FAILED, "CreateRasterizerState() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_DEPTH_STENCIL_STATE_FAILED, "CreateDepthStencilState() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_BLEND_STATE_FAILED, "CreateBlendState() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_RTV_FAILED, "CreateRenderTargetView() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_CREATE_DSV_FAILED, "CreateDepthStencilView() failed (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_UPDATE_BUFFER_FAILED, "Map() failed when updating buffer (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_APPEND_BUFFER_FAILED, "Map() failed when appending to buffer (d3d11)") \
+ _SG_LOGITEM_XMACRO(D3D11_MAP_FOR_UPDATE_IMAGE_FAILED, "Map() failed when updating image (d3d11)") \
+ _SG_LOGITEM_XMACRO(METAL_TEXTURE_FORMAT_NOT_SUPPORTED, "pixel format not supported for texture (metal)") \
+ _SG_LOGITEM_XMACRO(METAL_SHADER_COMPILATION_FAILED, "shader compilation failed (metal)") \
+ _SG_LOGITEM_XMACRO(METAL_SHADER_CREATION_FAILED, "shader creation failed (metal)") \
+ _SG_LOGITEM_XMACRO(METAL_SHADER_COMPILATION_OUTPUT, "") \
+ _SG_LOGITEM_XMACRO(METAL_VERTEX_SHADER_ENTRY_NOT_FOUND, "vertex shader entry function not found (metal)") \
+ _SG_LOGITEM_XMACRO(METAL_FRAGMENT_SHADER_ENTRY_NOT_FOUND, "fragment shader entry not found (metal)") \
+ _SG_LOGITEM_XMACRO(METAL_CREATE_RPS_FAILED, "failed to create render pipeline state (metal)") \
+ _SG_LOGITEM_XMACRO(METAL_CREATE_RPS_OUTPUT, "") \
+ _SG_LOGITEM_XMACRO(WGPU_MAP_UNIFORM_BUFFER_FAILED, "mapping uniform buffer failed (wgpu)") \
+ _SG_LOGITEM_XMACRO(WGPU_STAGING_BUFFER_FULL_COPY_TO_BUFFER, "per frame staging buffer full when copying to buffer (wgpu)") \
+ _SG_LOGITEM_XMACRO(WGPU_STAGING_BUFFER_FULL_COPY_TO_TEXTURE, "per frame staging buffer full when copying to texture (wgpu)") \
+ _SG_LOGITEM_XMACRO(WGPU_RESET_STATE_CACHE_FIXME, "_sg_wgpu_reset_state_cache: fixme") \
+ _SG_LOGITEM_XMACRO(WGPU_ACTIVATE_CONTEXT_FIXME, "_sg_wgpu_activate_context: fixme") \
+ _SG_LOGITEM_XMACRO(UNINIT_BUFFER_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in buffer uninit (must be same as for creation)") \
+ _SG_LOGITEM_XMACRO(UNINIT_IMAGE_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in image uninit (must be same as for creation)") \
+ _SG_LOGITEM_XMACRO(UNINIT_SHADER_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in shader uninit (must be same as for creation)") \
+ _SG_LOGITEM_XMACRO(UNINIT_PIPELINE_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in pipeline uninit (must be same as for creation)") \
+ _SG_LOGITEM_XMACRO(UNINIT_PASS_ACTIVE_CONTEXT_MISMATCH, "active context mismatch in pass uninit (must be same as for creation)") \
+ _SG_LOGITEM_XMACRO(IDENTICAL_COMMIT_LISTENER, "attempting to add identical commit listener") \
+ _SG_LOGITEM_XMACRO(COMMIT_LISTENER_ARRAY_FULL, "commit listener array full") \
+ _SG_LOGITEM_XMACRO(TRACE_HOOKS_NOT_ENABLED, "sg_install_trace_hooks() called, but SG_TRACE_HOOKS is not defined") \
+ _SG_LOGITEM_XMACRO(DEALLOC_BUFFER_INVALID_STATE, "sg_dealloc_buffer(): buffer must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(DEALLOC_IMAGE_INVALID_STATE, "sg_dealloc_image(): image must be in alloc state") \
+ _SG_LOGITEM_XMACRO(DEALLOC_SHADER_INVALID_STATE, "sg_dealloc_shader(): shader must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(DEALLOC_PIPELINE_INVALID_STATE, "sg_dealloc_pipeline(): pipeline must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(DEALLOC_PASS_INVALID_STATE, "sg_dealloc_pass(): pass must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(INIT_BUFFER_INVALID_STATE, "sg_init_buffer(): buffer must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(INIT_IMAGE_INVALID_STATE, "sg_init_image(): image must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(INIT_SHADER_INVALID_STATE, "sg_init_shader(): shader must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(INIT_PIPELINE_INVALID_STATE, "sg_init_pipeline(): pipeline must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(INIT_PASS_INVALID_STATE, "sg_init_pass(): pass must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(UNINIT_BUFFER_INVALID_STATE, "sg_uninit_buffer(): buffer must be in VALID or FAILED state") \
+ _SG_LOGITEM_XMACRO(UNINIT_IMAGE_INVALID_STATE, "sg_uninit_image(): image must be in VALID or FAILED state") \
+ _SG_LOGITEM_XMACRO(UNINIT_SHADER_INVALID_STATE, "sg_uninit_shader(): shader must be in VALID or FAILED state") \
+ _SG_LOGITEM_XMACRO(UNINIT_PIPELINE_INVALID_STATE, "sg_uninit_pipeline(): pipeline must be in VALID or FAILED state") \
+ _SG_LOGITEM_XMACRO(UNINIT_PASS_INVALID_STATE, "sg_uninit_pass(): pass must be in VALID or FAILED state") \
+ _SG_LOGITEM_XMACRO(FAIL_BUFFER_INVALID_STATE, "sg_fail_buffer(): buffer must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(FAIL_IMAGE_INVALID_STATE, "sg_fail_image(): image must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(FAIL_SHADER_INVALID_STATE, "sg_fail_shader(): shader must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(FAIL_PIPELINE_INVALID_STATE, "sg_fail_pipeline(): pipeline must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(FAIL_PASS_INVALID_STATE, "sg_fail_pass(): pass must be in ALLOC state") \
+ _SG_LOGITEM_XMACRO(BUFFER_POOL_EXHAUSTED, "buffer pool exhausted") \
+ _SG_LOGITEM_XMACRO(IMAGE_POOL_EXHAUSTED, "image pool exhausted") \
+ _SG_LOGITEM_XMACRO(SHADER_POOL_EXHAUSTED, "shader pool exhausted") \
+ _SG_LOGITEM_XMACRO(PIPELINE_POOL_EXHAUSTED, "pipeline pool exhausted") \
+ _SG_LOGITEM_XMACRO(PASS_POOL_EXHAUSTED, "pass pool exhausted") \
+ _SG_LOGITEM_XMACRO(DRAW_WITHOUT_BINDINGS, "attempting to draw without resource bindings") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_CANARY, "sg_buffer_desc not initialized") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_SIZE, "sg_buffer_desc.size cannot be 0") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_DATA, "immutable buffers must be initialized with data (sg_buffer_desc.data.ptr and sg_buffer_desc.data.size)") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_DATA_SIZE, "immutable buffer data size differs from buffer size") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BUFFERDESC_NO_DATA, "dynamic/stream usage buffers cannot be initialized with data") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDATA_NODATA, "sg_image_data: no data (.ptr and/or .size is zero)") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDATA_DATA_SIZE, "sg_image_data: data size doesn't match expected surface size") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_CANARY, "sg_image_desc not initialized") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_WIDTH, "sg_image_desc.width must be > 0") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_HEIGHT, "sg_image_desc.height must be > 0") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_RT_PIXELFORMAT, "invalid pixel format for render-target image") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_NONRT_PIXELFORMAT, "invalid pixel format for non-render-target image") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_MSAA_BUT_NO_RT, "non-render-target images cannot be multisampled") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_NO_MSAA_RT_SUPPORT, "MSAA not supported for this pixel format") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_RT_IMMUTABLE, "render target images must be SG_USAGE_IMMUTABLE") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_RT_NO_DATA, "render target images cannot be initialized with data") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_INJECTED_NO_DATA, "images with injected textures cannot be initialized with data") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_DYNAMIC_NO_DATA, "dynamic/stream images cannot be initialized with data") \
+ _SG_LOGITEM_XMACRO(VALIDATE_IMAGEDESC_COMPRESSED_IMMUTABLE, "compressed images must be immutable") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_CANARY, "sg_shader_desc not initialized") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SOURCE, "shader source code required") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_BYTECODE, "shader byte code required") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_SOURCE_OR_BYTECODE, "shader source or byte code required") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_BYTECODE_SIZE, "shader byte code length (in bytes) required") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_UBS, "shader uniform blocks must occupy continuous slots") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_UB_MEMBERS, "uniform block members must occupy continuous slots") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_UB_MEMBERS, "GL backend requires uniform block member declarations") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_MEMBER_NAME, "uniform block member name missing") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_SIZE_MISMATCH, "size of uniform block members doesn't match uniform block size") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_ARRAY_COUNT, "uniform array count must be >= 1") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE, "uniform arrays only allowed for FLOAT4, INT4, MAT4 in std140 layout") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_NO_CONT_IMGS, "shader images must occupy continuous slots") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_IMG_NAME, "GL backend requires uniform block member names") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_ATTR_NAMES, "GLES2 backend requires vertex attribute names") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_ATTR_SEMANTICS, "D3D11 backend requires vertex attribute semantics") \
+ _SG_LOGITEM_XMACRO(VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG, "vertex attribute name/semantic string too long (max len 16)") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_CANARY, "sg_pipeline_desc not initialized") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_SHADER, "sg_pipeline_desc.shader missing or invalid") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_NO_ATTRS, "sg_pipeline_desc.layout.attrs is empty or not continuous") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4, "sg_pipeline_desc.layout.buffers[].stride must be multiple of 4") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_ATTR_NAME, "GLES2/WebGL missing vertex attribute name in shader") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PIPELINEDESC_ATTR_SEMANTICS, "D3D11 missing vertex attribute semantics in shader") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_CANARY, "sg_pass_desc not initialized") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_NO_COLOR_ATTS, "sg_pass_desc.color_attachments[0] must be valid") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_NO_CONT_COLOR_ATTS, "color attachments must occupy continuous slots") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE, "pass attachment image is not valid") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_MIPLEVEL, "pass attachment mip level is bigger than image has mipmaps") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_FACE, "pass attachment image is cubemap, but face index is too big") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_LAYER, "pass attachment image is array texture, but layer index is too big") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_SLICE, "pass attachment image is 3d texture, but slice value is too big") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE_NO_RT, "pass attachment image must be render targets") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_COLOR_INV_PIXELFORMAT, "pass color-attachment images must have a renderable pixel format") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_DEPTH_INV_PIXELFORMAT, "pass depth-attachment image must have depth pixel format") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE_SIZES, "all pass attachments must have the same size") \
+ _SG_LOGITEM_XMACRO(VALIDATE_PASSDESC_IMAGE_SAMPLE_COUNTS, "all pass attachments must have the same sample count") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_PASS, "sg_begin_pass: pass must be valid") \
+ _SG_LOGITEM_XMACRO(VALIDATE_BEGINPASS_IMAGE, "sg_begin_pass: one or more attachment images are not valid") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_VALID_ID, "sg_apply_pipeline: invalid pipeline id provided") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_EXISTS, "sg_apply_pipeline: pipeline object no longer alive") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_PIPELINE_VALID, "sg_apply_pipeline: pipeline object not in valid state") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_EXISTS, "sg_apply_pipeline: shader object no longer alive") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_SHADER_VALID, "sg_apply_pipeline: shader object not in valid state") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_ATT_COUNT, "sg_apply_pipeline: number of pipeline color attachments doesn't match number of pass color attachments") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_COLOR_FORMAT, "sg_apply_pipeline: pipeline color attachment pixel format doesn't match pass color attachment pixel format") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_DEPTH_FORMAT, "sg_apply_pipeline: pipeline depth pixel_format doesn't match pass depth attachment pixel format") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APIP_SAMPLE_COUNT, "sg_apply_pipeline: pipeline MSAA sample count doesn't match render pass attachment sample count") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_PIPELINE, "sg_apply_bindings: must be called after sg_apply_pipeline") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_PIPELINE_EXISTS, "sg_apply_bindings: currently applied pipeline object no longer alive") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_PIPELINE_VALID, "sg_apply_bindings: currently applied pipeline object not in valid state") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VBS, "sg_apply_bindings: number of vertex buffers doesn't match number of pipeline vertex layouts") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VB_EXISTS, "sg_apply_bindings: vertex buffer no longer alive") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VB_TYPE, "sg_apply_bindings: buffer in vertex buffer slot is not a SG_BUFFERTYPE_VERTEXBUFFER") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VB_OVERFLOW, "sg_apply_bindings: buffer in vertex buffer slot is overflown") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_NO_IB, "sg_apply_bindings: pipeline object defines indexed rendering, but no index buffer provided") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB, "sg_apply_bindings: pipeline object defines non-indexed rendering, but index buffer provided") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB_EXISTS, "sg_apply_bindings: index buffer no longer alive") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB_TYPE, "sg_apply_bindings: buffer in index buffer slot is not a SG_BUFFERTYPE_INDEXBUFFER") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_IB_OVERFLOW, "sg_apply_bindings: buffer in index buffer slot is overflown") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_IMGS, "sg_apply_bindings: vertex shader image count doesn't match sg_shader_desc") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_IMG_EXISTS, "sg_apply_bindings: vertex shader image no longer alive") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_VS_IMG_TYPES, "sg_apply_bindings: one or more vertex shader image types don't match sg_shader_desc") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMGS, "sg_apply_bindings: fragment shader image count doesn't match sg_shader_desc") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMG_EXISTS, "sg_apply_bindings: fragment shader image no longer alive") \
+ _SG_LOGITEM_XMACRO(VALIDATE_ABND_FS_IMG_TYPES, "sg_apply_bindings: one or more fragment shader image types don't match sg_shader_desc") \
+ _SG_LOGITEM_XMACRO(VALIDATE_AUB_NO_PIPELINE, "sg_apply_uniforms: must be called after sg_apply_pipeline()") \
+ _SG_LOGITEM_XMACRO(VALIDATE_AUB_NO_UB_AT_SLOT, "sg_apply_uniforms: no uniform block declaration at this shader stage UB slot") \
+ _SG_LOGITEM_XMACRO(VALIDATE_AUB_SIZE, "sg_apply_uniforms: data size exceeds declared uniform block size") \
+ _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_USAGE, "sg_update_buffer: cannot update immutable buffer") \
+ _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_SIZE, "sg_update_buffer: update size is bigger than buffer size") \
+ _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_ONCE, "sg_update_buffer: only one update allowed per buffer and frame") \
+ _SG_LOGITEM_XMACRO(VALIDATE_UPDATEBUF_APPEND, "sg_update_buffer: cannot call sg_update_buffer and sg_append_buffer in same frame") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APPENDBUF_USAGE, "sg_append_buffer: cannot append to immutable buffer") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APPENDBUF_SIZE, "sg_append_buffer: overall appended size is bigger than buffer size") \
+ _SG_LOGITEM_XMACRO(VALIDATE_APPENDBUF_UPDATE, "sg_append_buffer: cannot call sg_append_buffer and sg_update_buffer in same frame") \
+ _SG_LOGITEM_XMACRO(VALIDATE_UPDIMG_USAGE, "sg_update_image: cannot update immutable image") \
+ _SG_LOGITEM_XMACRO(VALIDATE_UPDIMG_ONCE, "sg_update_image: only one update allowed per image and frame") \
+ _SG_LOGITEM_XMACRO(VALIDATION_FAILED, "validation layer checks failed") \
+
+#define _SG_LOGITEM_XMACRO(item,msg) SG_LOGITEM_##item,
+typedef enum sg_log_item {
+ _SG_LOG_ITEMS
+} sg_log_item;
+#undef _SG_LOGITEM_XMACRO
+
/*
sg_desc
@@ -2112,9 +2783,15 @@ typedef struct sg_pass_info {
.pipeline_pool_size 64
.pass_pool_size 16
.context_pool_size 16
- .sampler_cache_size 64
.uniform_buffer_size 4 MB (4*1024*1024)
.staging_buffer_size 8 MB (8*1024*1024)
+ .sampler_cache_size 64
+ .max_commit_listeners 1024
+ .disable_validation false
+
+ .allocator.alloc 0 (in this case, malloc() will be called)
+ .allocator.free 0 (in this case, free() will be called)
+ .allocator.user_data 0
.context.color_format: default value depends on selected backend:
all GL backends: SG_PIXELFORMAT_RGBA8
@@ -2171,7 +2848,7 @@ typedef struct sg_pass_info {
ID3D11DepthStencilView object of the default framebuffer,
this function will be called in sg_begin_pass() when rendering
to the default framebuffer
- .context.metal.user_data
+ .context.d3d11.user_data
optional user data pointer passed to the userdata versions of
callback functions