xbintsc 0.5.31 → 0.5.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -10
- package/dist/src/binder/references.js +14 -1
- package/dist/src/binder/references.js.map +1 -1
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/module.d.ts +1 -0
- package/dist/src/codegen/generator/module.js +54 -0
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/statements/variables.js +6 -4
- package/dist/src/codegen/generator/statements/variables.js.map +1 -1
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/css.d.ts +26 -0
- package/dist/src/extensions/gui/css.js +100 -0
- package/dist/src/extensions/gui/css.js.map +1 -0
- package/dist/src/extensions/gui/html.js +9 -2
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +16 -2
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +16 -0
- package/dist/src/extensions/gui/three.js +22 -0
- package/dist/src/extensions/gui/three.js.map +1 -0
- package/dist/src/extensions/media/index.d.ts +6 -5
- package/dist/src/extensions/media/index.js +12 -14
- package/dist/src/extensions/media/index.js.map +1 -1
- package/dist/tests/e2e/compile-builtins.test.js +24 -0
- package/dist/tests/e2e/compile-builtins.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +23 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/gui-browser.test.js +1 -1
- package/dist/tests/e2e/gui-browser.test.js.map +1 -1
- package/dist/tests/e2e/gui-effects.test.d.ts +6 -0
- package/dist/tests/e2e/gui-effects.test.js +262 -0
- package/dist/tests/e2e/gui-effects.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-webgl.test.d.ts +10 -0
- package/dist/tests/e2e/gui-example-webgl.test.js +75 -0
- package/dist/tests/e2e/gui-example-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-example-webgl2.test.d.ts +8 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js +72 -0
- package/dist/tests/e2e/gui-example-webgl2.test.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.js +48 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.js +5 -4
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.d.ts +11 -0
- package/dist/tests/e2e/gui-webgl.test.js +179 -0
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2.test.js +238 -0
- package/dist/tests/e2e/gui-webgl2.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +41 -0
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/dist/tests/extensions/media.test.js +7 -3
- package/dist/tests/extensions/media.test.js.map +1 -1
- package/doc/ai/extensions.md +29 -9
- package/doc/ai/troubleshooting.md +12 -8
- package/doc/ai/zh-CN/extensions.md +26 -8
- package/doc/ai/zh-CN/troubleshooting.md +10 -6
- package/doc/gui/api.md +3 -2
- package/doc/gui/build.md +72 -16
- package/doc/gui/canvas.md +11 -3
- package/doc/gui/dom.md +33 -18
- package/doc/gui/known-issues.md +57 -24
- package/doc/gui/layout.md +18 -0
- package/doc/gui/media.md +17 -13
- package/doc/gui/rendering.md +50 -3
- package/doc/gui/webgl.md +256 -0
- package/doc/gui.md +108 -17
- package/doc/npm-package.md +6 -4
- package/doc/requirements.md +18 -9
- package/doc/zh-CN/gui/api.md +3 -2
- package/doc/zh-CN/gui/build.md +64 -15
- package/doc/zh-CN/gui/canvas.md +9 -2
- package/doc/zh-CN/gui/dom.md +20 -7
- package/doc/zh-CN/gui/known-issues.md +45 -19
- package/doc/zh-CN/gui/layout.md +14 -0
- package/doc/zh-CN/gui/media.md +15 -11
- package/doc/zh-CN/gui/rendering.md +41 -4
- package/doc/zh-CN/gui/webgl.md +115 -0
- package/doc/zh-CN/gui.md +89 -14
- package/doc/zh-CN/npm-package.md +9 -6
- package/doc/zh-CN/requirements.md +12 -6
- package/llms.txt +2 -0
- package/package.json +1 -1
- package/runtime/ext_gui/browser.cpp +39 -13
- package/runtime/ext_gui/canvas.cpp +3 -18
- package/runtime/ext_gui/canvas_internal.h +10 -0
- package/runtime/ext_gui/canvas_raster.cpp +60 -0
- package/runtime/ext_gui/clip_values.cpp +246 -0
- package/runtime/ext_gui/css.cpp +94 -0
- package/runtime/ext_gui/css.h +22 -1
- package/runtime/ext_gui/css_match.cpp +3 -0
- package/runtime/ext_gui/css_selector.cpp +9 -0
- package/runtime/ext_gui/css_sheet.cpp +89 -45
- package/runtime/ext_gui/document.cpp +4 -1
- package/runtime/ext_gui/document.h +2 -0
- package/runtime/ext_gui/dom.h +16 -0
- package/runtime/ext_gui/dom_api.cpp +1 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +17 -80
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +130 -1
- package/runtime/ext_gui/dom_api_canvas_pending.cpp +41 -0
- package/runtime/ext_gui/dom_api_internal.h +259 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +376 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +434 -0
- package/runtime/ext_gui/dom_api_webgl2_draw.cpp +269 -0
- package/runtime/ext_gui/dom_api_webgl_buffer.cpp +212 -0
- package/runtime/ext_gui/dom_api_webgl_rt.h +30 -0
- package/runtime/ext_gui/dom_api_webgl_shader.cpp +443 -0
- package/runtime/ext_gui/dom_api_webgl_state.cpp +444 -0
- package/runtime/ext_gui/dom_api_webgl_texture.cpp +445 -0
- package/runtime/ext_gui/effect_values.cpp +312 -0
- package/runtime/ext_gui/gradient_values.cpp +476 -0
- package/runtime/ext_gui/grid_values.cpp +230 -0
- package/runtime/ext_gui/gui_canvas.cpp +50 -2
- package/runtime/ext_gui/gui_engine.h +27 -0
- package/runtime/ext_gui/gui_events.cpp +4 -1
- package/runtime/ext_gui/gui_media.cpp +1 -1
- package/runtime/ext_gui/gui_webgl.cpp +83 -0
- package/runtime/ext_gui/layout.cpp +21 -0
- package/runtime/ext_gui/layout_flow.cpp +81 -4
- package/runtime/ext_gui/layout_flow_internal.h +31 -0
- package/runtime/ext_gui/layout_grid.cpp +374 -0
- package/runtime/ext_gui/media.h +1 -1
- package/runtime/ext_gui/media_api.h +2 -2
- package/runtime/ext_gui/media_query.cpp +211 -0
- package/runtime/ext_gui/paint.cpp +111 -77
- package/runtime/ext_gui/paint.h +33 -3
- package/runtime/ext_gui/paint_background.cpp +229 -0
- package/runtime/ext_gui/paint_clip.cpp +268 -0
- package/runtime/ext_gui/paint_effects.cpp +324 -0
- package/runtime/ext_gui/paint_internal.h +85 -0
- package/runtime/ext_gui/renderer.cpp +8 -31
- package/runtime/ext_gui/renderer_clip.cpp +196 -0
- package/runtime/ext_gui/renderer_image.cpp +13 -8
- package/runtime/ext_gui/renderer_internal.h +15 -8
- package/runtime/ext_gui/renderer_text.cpp +6 -31
- package/runtime/ext_gui/style.cpp +343 -20
- package/runtime/ext_gui/style.h +144 -3
- package/runtime/ext_gui/style_print.cpp +134 -1
- package/runtime/ext_gui/style_values.cpp +152 -126
- package/runtime/ext_gui/style_values_internal.h +35 -0
- package/runtime/ext_gui/webgl.h +466 -0
- package/runtime/ext_gui/webgl2_constants.h +274 -0
- package/runtime/ext_gui/webgl_buffer.cpp +565 -0
- package/runtime/ext_gui/webgl_constants.h +317 -0
- package/runtime/ext_gui/webgl_context.cpp +466 -0
- package/runtime/ext_gui/webgl_draw.cpp +495 -0
- package/runtime/ext_gui/webgl_glsl.h +125 -0
- package/runtime/ext_gui/webgl_glsl_compile.cpp +431 -0
- package/runtime/ext_gui/webgl_glsl_rewrite.cpp +349 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +581 -0
- package/runtime/ext_gui/webgl_msl.cpp +62 -0
- package/runtime/ext_gui/webgl_msl.h +33 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +274 -0
- package/runtime/ext_gui/webgl_program_internal.h +18 -0
- package/runtime/ext_gui/webgl_shader.cpp +582 -0
- package/runtime/ext_gui/webgl_texture.cpp +293 -0
- package/runtime/ext_gui/webgl_uniform.cpp +167 -0
- package/runtime/ext_gui/webgl_webgl2.cpp +224 -0
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +9 -3
- package/runtime/rt_internal.h +1 -0
- package/runtime/xt_containers/access.inc +8 -0
- package/runtime/xt_regex/api.inc +2 -0
- package/runtime/xt_regex/matcher.inc +16 -3
- package/runtime/xt_regex/parser.inc +8 -2
- package/runtime/xt_regex/types.inc +3 -0
- package/runtime/xt_stdlib2/regexp-match.inc +60 -21
- package/runtime/xt_stdlib2/regexp.inc +1 -0
- package/runtime/xt_typed_array.c +1 -1
- package/scripts/build-gui.ts +90 -3
- package/scripts/build-media.ts +323 -58
- package/scripts/setup-vs-toolchain.ps1 +152 -0
- package/src/binder/references.ts +13 -1
- package/src/codegen/generator/module.ts +50 -0
- package/src/codegen/generator/statements/variables.ts +6 -3
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/css.ts +113 -0
- package/src/extensions/gui/html.ts +9 -2
- package/src/extensions/gui/index.ts +16 -2
- package/src/extensions/gui/three.ts +25 -0
- package/src/extensions/media/index.ts +13 -16
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — WebGL draw calls.
|
|
3
|
+
*
|
|
4
|
+
* SDL_GPU has no dynamic state for blend/depth/rasterisation: those live in a
|
|
5
|
+
* `SDL_GPUGraphicsPipeline`. WebGL changes them with `glEnable`/`glDepthFunc`,
|
|
6
|
+
* so a pipeline is built lazily per (program, vertex layout, the subset of
|
|
7
|
+
* fixed-function state that matters) and cached on the program.
|
|
8
|
+
*
|
|
9
|
+
* A matrix attribute consumes several consecutive vertex locations; the
|
|
10
|
+
* pipeline spells out one `SDL_GPUVertexAttribute` per column, all reading the
|
|
11
|
+
* same vertex buffer binding.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
#include "webgl.h"
|
|
15
|
+
|
|
16
|
+
#include <algorithm>
|
|
17
|
+
#include <cstring>
|
|
18
|
+
#include <string>
|
|
19
|
+
#include <vector>
|
|
20
|
+
|
|
21
|
+
#include "gui_internal.h"
|
|
22
|
+
|
|
23
|
+
namespace xtgui {
|
|
24
|
+
namespace {
|
|
25
|
+
|
|
26
|
+
int type_size(int type) {
|
|
27
|
+
switch (type) {
|
|
28
|
+
case GL_BYTE:
|
|
29
|
+
case GL_UNSIGNED_BYTE:
|
|
30
|
+
return 1;
|
|
31
|
+
case GL_SHORT:
|
|
32
|
+
case GL_UNSIGNED_SHORT:
|
|
33
|
+
return 2;
|
|
34
|
+
default:
|
|
35
|
+
return 4;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
int components_of_type(const std::string &type) {
|
|
40
|
+
if (!type.empty() && type.back() >= '2' && type.back() <= '4') return type.back() - '0';
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
SDL_GPUVertexElementFormat float_format(int size) {
|
|
45
|
+
switch (size) {
|
|
46
|
+
case 1:
|
|
47
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT;
|
|
48
|
+
case 2:
|
|
49
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
|
|
50
|
+
case 3:
|
|
51
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
|
|
52
|
+
default:
|
|
53
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
SDL_GPUVertexElementFormat format_of(int size, int type, bool normalized) {
|
|
58
|
+
if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
59
|
+
if (type == GL_FLOAT) return float_format(size);
|
|
60
|
+
if (type == GL_UNSIGNED_BYTE || type == GL_BYTE) {
|
|
61
|
+
const bool is_byte = type == GL_BYTE;
|
|
62
|
+
if (size == 2) {
|
|
63
|
+
return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2_NORM
|
|
64
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2_NORM)
|
|
65
|
+
: (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2
|
|
66
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2);
|
|
67
|
+
}
|
|
68
|
+
if (size == 4) {
|
|
69
|
+
return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4_NORM
|
|
70
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM)
|
|
71
|
+
: (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4
|
|
72
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4);
|
|
73
|
+
}
|
|
74
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
75
|
+
}
|
|
76
|
+
if (type == GL_UNSIGNED_SHORT || type == GL_SHORT) {
|
|
77
|
+
const bool is_short = type == GL_SHORT;
|
|
78
|
+
if (size == 2) {
|
|
79
|
+
return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2_NORM
|
|
80
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT2_NORM)
|
|
81
|
+
: (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2
|
|
82
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT2);
|
|
83
|
+
}
|
|
84
|
+
if (size == 4) {
|
|
85
|
+
return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4_NORM
|
|
86
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4_NORM)
|
|
87
|
+
: (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4
|
|
88
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4);
|
|
89
|
+
}
|
|
90
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
91
|
+
}
|
|
92
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** `vertexAttribIPointer` formats: integer attributes keep their integer type
|
|
96
|
+
* in the shader (`in ivec3 …`). SDL has no 1- or 3-component byte/short
|
|
97
|
+
* integer formats, so only the sizes it can express are accepted. */
|
|
98
|
+
SDL_GPUVertexElementFormat int_format_of(int size, int type) {
|
|
99
|
+
if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
100
|
+
if (type == GL_INT) {
|
|
101
|
+
switch (size) {
|
|
102
|
+
case 1:
|
|
103
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT;
|
|
104
|
+
case 2:
|
|
105
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT2;
|
|
106
|
+
case 3:
|
|
107
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT3;
|
|
108
|
+
default:
|
|
109
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT4;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (type == GL_UNSIGNED_INT) {
|
|
113
|
+
switch (size) {
|
|
114
|
+
case 1:
|
|
115
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT;
|
|
116
|
+
case 2:
|
|
117
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT2;
|
|
118
|
+
case 3:
|
|
119
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT3;
|
|
120
|
+
default:
|
|
121
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT4;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (type == GL_SHORT && (size == 2 || size == 4)) {
|
|
125
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2 : SDL_GPU_VERTEXELEMENTFORMAT_SHORT4;
|
|
126
|
+
}
|
|
127
|
+
if (type == GL_UNSIGNED_SHORT && (size == 2 || size == 4)) {
|
|
128
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_USHORT2
|
|
129
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4;
|
|
130
|
+
}
|
|
131
|
+
if (type == GL_BYTE && (size == 2 || size == 4)) {
|
|
132
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_BYTE4;
|
|
133
|
+
}
|
|
134
|
+
if (type == GL_UNSIGNED_BYTE && (size == 2 || size == 4)) {
|
|
135
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4;
|
|
136
|
+
}
|
|
137
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** A cache key covering everything (other than the program) that a
|
|
141
|
+
* `SDL_GPUGraphicsPipeline` bakes in. */
|
|
142
|
+
std::string pipeline_key(int mode, int index_size,
|
|
143
|
+
const std::vector<SDL_GPUVertexAttribute> &attrs,
|
|
144
|
+
const std::vector<SDL_GPUVertexBufferDescription> &buffers,
|
|
145
|
+
const WebGLDrawState &state) {
|
|
146
|
+
std::string key = std::to_string(mode) + "/" + std::to_string(index_size);
|
|
147
|
+
for (const SDL_GPUVertexAttribute &attr : attrs) {
|
|
148
|
+
key += "/" + std::to_string(attr.location) + ":" + std::to_string(attr.buffer_slot) + ":" +
|
|
149
|
+
std::to_string((int)attr.format) + ":" + std::to_string(attr.offset);
|
|
150
|
+
}
|
|
151
|
+
for (const SDL_GPUVertexBufferDescription &buffer : buffers) {
|
|
152
|
+
key += "|" + std::to_string(buffer.slot) + ":" + std::to_string(buffer.pitch) + ":" +
|
|
153
|
+
std::to_string((int)buffer.input_rate);
|
|
154
|
+
}
|
|
155
|
+
char state_key[160];
|
|
156
|
+
snprintf(state_key, sizeof(state_key), "|%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
|
|
157
|
+
(int)state.blend, state.blend_src_rgb, state.blend_dst_rgb, state.blend_src_alpha,
|
|
158
|
+
state.blend_dst_alpha, state.blend_eq_rgb, state.blend_eq_alpha, (int)state.depth_test,
|
|
159
|
+
(int)state.depth_write, state.depth_func, (int)state.cull, state.cull_face,
|
|
160
|
+
state.front_face, (int)state.color_mask[0]);
|
|
161
|
+
key += state_key;
|
|
162
|
+
key += std::to_string((int)state.color_mask[1]);
|
|
163
|
+
key += std::to_string((int)state.color_mask[2]);
|
|
164
|
+
key += std::to_string((int)state.color_mask[3]);
|
|
165
|
+
return key;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
} // namespace
|
|
169
|
+
|
|
170
|
+
void WebGLContext::draw_arrays(int mode, int first, int count) {
|
|
171
|
+
if (count < 0) {
|
|
172
|
+
set_error(GL_INVALID_VALUE);
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
draw(mode, first, count, 0, 0, 1);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
void WebGLContext::draw_elements(int mode, int count, int type, int offset) {
|
|
179
|
+
if (count < 0) {
|
|
180
|
+
set_error(GL_INVALID_VALUE);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT && type != GL_UNSIGNED_BYTE) {
|
|
184
|
+
set_error(GL_INVALID_ENUM);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
draw(mode, 0, count, type, offset, 1);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
void WebGLContext::draw_arrays_instanced(int mode, int first, int count, int instances) {
|
|
191
|
+
if (count < 0 || instances < 0) {
|
|
192
|
+
set_error(GL_INVALID_VALUE);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
draw(mode, first, count, 0, 0, instances > 0 ? instances : 1);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
void WebGLContext::draw_elements_instanced(int mode, int count, int type, int offset,
|
|
199
|
+
int instances) {
|
|
200
|
+
if (count < 0 || instances < 0) {
|
|
201
|
+
set_error(GL_INVALID_VALUE);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (type != GL_UNSIGNED_SHORT && type != GL_UNSIGNED_INT && type != GL_UNSIGNED_BYTE) {
|
|
205
|
+
set_error(GL_INVALID_ENUM);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
draw(mode, 0, count, type, offset, instances > 0 ? instances : 1);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void WebGLContext::draw_range_elements(int mode, int start, int end, int count, int type,
|
|
212
|
+
int offset) {
|
|
213
|
+
(void)start;
|
|
214
|
+
(void)end;
|
|
215
|
+
draw_elements(mode, count, type, offset);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
void WebGLContext::draw(int mode, int first, int count, int index_type, int offset,
|
|
219
|
+
int instances) {
|
|
220
|
+
if (count <= 0) return;
|
|
221
|
+
WebGLProgram *program_ = program(current_program_);
|
|
222
|
+
if (program_ == nullptr || !program_->linked || program_->vs_shader == nullptr) {
|
|
223
|
+
set_error(GL_INVALID_OPERATION);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (mode != GL_POINTS && mode != GL_LINES && mode != GL_LINE_STRIP && mode != GL_TRIANGLES &&
|
|
227
|
+
mode != GL_TRIANGLE_STRIP && mode != GL_TRIANGLE_FAN && mode != GL_LINE_LOOP) {
|
|
228
|
+
set_error(GL_INVALID_ENUM);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
ensure_fallback();
|
|
232
|
+
end_pass();
|
|
233
|
+
ensure_command();
|
|
234
|
+
|
|
235
|
+
/* Expand source indices when the draw needs a primitive SDL_GPU lacks or a
|
|
236
|
+
* byte-sized index type. */
|
|
237
|
+
std::vector<uint32_t> expanded;
|
|
238
|
+
SDL_GPUBuffer *index_gpu = nullptr;
|
|
239
|
+
int index_size = 0;
|
|
240
|
+
int first_index = 0;
|
|
241
|
+
int draw_mode = mode;
|
|
242
|
+
const bool needs_expand =
|
|
243
|
+
mode == GL_TRIANGLE_FAN || mode == GL_LINE_LOOP || index_type == GL_UNSIGNED_BYTE;
|
|
244
|
+
if (needs_expand) {
|
|
245
|
+
std::vector<uint32_t> source;
|
|
246
|
+
source.reserve((size_t)count);
|
|
247
|
+
if (index_type != 0) {
|
|
248
|
+
WebGLBuffer *element = buffer(bound_element_);
|
|
249
|
+
if (element == nullptr || element->data.empty()) {
|
|
250
|
+
set_error(GL_INVALID_OPERATION);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const int element_size = type_size(index_type);
|
|
254
|
+
for (int i = 0; i < count; i++) {
|
|
255
|
+
const size_t at = (size_t)offset + (size_t)i * element_size;
|
|
256
|
+
if (at + element_size > element->data.size()) {
|
|
257
|
+
source.push_back(0);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
uint32_t value = element->data[at];
|
|
261
|
+
if (element_size >= 2) value |= (uint32_t)element->data[at + 1] << 8;
|
|
262
|
+
if (element_size >= 4) {
|
|
263
|
+
value |= (uint32_t)element->data[at + 2] << 16;
|
|
264
|
+
value |= (uint32_t)element->data[at + 3] << 24;
|
|
265
|
+
}
|
|
266
|
+
source.push_back(value);
|
|
267
|
+
}
|
|
268
|
+
} else {
|
|
269
|
+
for (int i = 0; i < count; i++) source.push_back((uint32_t)(first + i));
|
|
270
|
+
}
|
|
271
|
+
if (mode == GL_TRIANGLE_FAN) {
|
|
272
|
+
for (size_t i = 1; i + 1 < source.size(); i++) {
|
|
273
|
+
expanded.push_back(source[0]);
|
|
274
|
+
expanded.push_back(source[i]);
|
|
275
|
+
expanded.push_back(source[i + 1]);
|
|
276
|
+
}
|
|
277
|
+
draw_mode = GL_TRIANGLES;
|
|
278
|
+
} else if (mode == GL_LINE_LOOP) {
|
|
279
|
+
for (size_t i = 0; i < source.size(); i++) {
|
|
280
|
+
expanded.push_back(source[i]);
|
|
281
|
+
expanded.push_back(source[(i + 1) % source.size()]);
|
|
282
|
+
}
|
|
283
|
+
draw_mode = GL_LINES;
|
|
284
|
+
} else {
|
|
285
|
+
expanded = source;
|
|
286
|
+
draw_mode = mode;
|
|
287
|
+
}
|
|
288
|
+
index_size = 4;
|
|
289
|
+
if (!expanded.empty()) {
|
|
290
|
+
index_gpu = upload_temp_buffer(expanded.data(),
|
|
291
|
+
(uint32_t)(expanded.size() * sizeof(uint32_t)),
|
|
292
|
+
SDL_GPU_BUFFERUSAGE_INDEX);
|
|
293
|
+
if (index_gpu == nullptr) return;
|
|
294
|
+
}
|
|
295
|
+
} else if (index_type != 0) {
|
|
296
|
+
WebGLBuffer *element = buffer(bound_element_);
|
|
297
|
+
if (element == nullptr || element->data.empty()) {
|
|
298
|
+
set_error(GL_INVALID_OPERATION);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
index_gpu = ensure_buffer_gpu(element);
|
|
302
|
+
if (index_gpu == nullptr) return;
|
|
303
|
+
index_size = type_size(index_type) == 4 ? 4 : 2;
|
|
304
|
+
first_index = offset / index_size;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
WebGLFramebuffer *framebuffer_ =
|
|
308
|
+
bound_framebuffer_ != 0 ? framebuffer(bound_framebuffer_) : nullptr;
|
|
309
|
+
const int target_width = framebuffer_ != nullptr ? framebuffer_->width : width_;
|
|
310
|
+
const int target_height = framebuffer_ != nullptr ? framebuffer_->height : height_;
|
|
311
|
+
|
|
312
|
+
std::vector<SDL_GPUVertexAttribute> attributes;
|
|
313
|
+
std::vector<SDL_GPUVertexBufferDescription> buffers;
|
|
314
|
+
std::vector<SDL_GPUBufferBinding> bindings;
|
|
315
|
+
|
|
316
|
+
for (const GlslUniformDecl &decl : program_->attribs) {
|
|
317
|
+
auto location_it = program_->attrib_locations.find(decl.name);
|
|
318
|
+
if (location_it == program_->attrib_locations.end()) continue;
|
|
319
|
+
const int base_location = location_it->second;
|
|
320
|
+
if (base_location < 0 || base_location >= kWebGLMaxAttribs) continue;
|
|
321
|
+
WebGLAttribState &attrib = attribs_[base_location];
|
|
322
|
+
const int slots = decl.type == "mat2" ? 2 : (decl.type == "mat3" ? 3 : (decl.type == "mat4" ? 4 : 1));
|
|
323
|
+
const int components = slots > 1 ? slots : (components_of_type(decl.type) > 4 ? 4
|
|
324
|
+
: components_of_type(decl.type));
|
|
325
|
+
const uint32_t slot = (uint32_t)buffers.size();
|
|
326
|
+
SDL_GPUVertexBufferDescription description;
|
|
327
|
+
memset(&description, 0, sizeof(description));
|
|
328
|
+
description.slot = slot;
|
|
329
|
+
description.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
330
|
+
SDL_GPUBufferBinding binding;
|
|
331
|
+
memset(&binding, 0, sizeof(binding));
|
|
332
|
+
if (!attrib.enabled) {
|
|
333
|
+
float values[4] = {attrib.current[0], attrib.current[1], attrib.current[2], attrib.current[3]};
|
|
334
|
+
binding.buffer = upload_temp_buffer(values, sizeof(values), SDL_GPU_BUFFERUSAGE_VERTEX);
|
|
335
|
+
description.pitch = 0;
|
|
336
|
+
if (binding.buffer == nullptr) continue;
|
|
337
|
+
for (int column = 0; column < slots; column++) {
|
|
338
|
+
SDL_GPUVertexAttribute attribute;
|
|
339
|
+
memset(&attribute, 0, sizeof(attribute));
|
|
340
|
+
attribute.location = (Uint32)(base_location + column);
|
|
341
|
+
attribute.buffer_slot = slot;
|
|
342
|
+
attribute.format = float_format(components);
|
|
343
|
+
attribute.offset = 0;
|
|
344
|
+
attributes.push_back(attribute);
|
|
345
|
+
}
|
|
346
|
+
buffers.push_back(description);
|
|
347
|
+
bindings.push_back(binding);
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
WebGLBuffer *buffer_ = buffer(attrib.buffer);
|
|
351
|
+
if (buffer_ == nullptr || buffer_->data.empty()) {
|
|
352
|
+
set_error(GL_INVALID_OPERATION);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
SDL_GPUVertexElementFormat format = attrib.integer
|
|
356
|
+
? int_format_of(attrib.size, attrib.type)
|
|
357
|
+
: format_of(attrib.size, attrib.type, attrib.normalized);
|
|
358
|
+
if (format == SDL_GPU_VERTEXELEMENTFORMAT_INVALID) {
|
|
359
|
+
set_error(GL_INVALID_OPERATION);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
description.input_rate = attrib.divisor > 0 ? SDL_GPU_VERTEXINPUTRATE_INSTANCE
|
|
363
|
+
: SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
364
|
+
const int stride =
|
|
365
|
+
attrib.stride > 0 ? attrib.stride : components * type_size(attrib.type) * slots;
|
|
366
|
+
description.pitch = (Uint32)stride;
|
|
367
|
+
SDL_GPUBuffer *gpu = ensure_buffer_gpu(buffer_);
|
|
368
|
+
if (gpu == nullptr) return;
|
|
369
|
+
binding.buffer = gpu;
|
|
370
|
+
binding.offset = 0;
|
|
371
|
+
for (int column = 0; column < slots; column++) {
|
|
372
|
+
SDL_GPUVertexAttribute attribute;
|
|
373
|
+
memset(&attribute, 0, sizeof(attribute));
|
|
374
|
+
attribute.location = (Uint32)(base_location + column);
|
|
375
|
+
attribute.buffer_slot = slot;
|
|
376
|
+
attribute.format = format;
|
|
377
|
+
attribute.offset = (Uint32)(attrib.offset + column * components * type_size(attrib.type));
|
|
378
|
+
attributes.push_back(attribute);
|
|
379
|
+
}
|
|
380
|
+
buffers.push_back(description);
|
|
381
|
+
bindings.push_back(binding);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
begin_pass(false, false);
|
|
385
|
+
if (pass_ == nullptr) return;
|
|
386
|
+
|
|
387
|
+
SDL_GPUViewport viewport;
|
|
388
|
+
memset(&viewport, 0, sizeof(viewport));
|
|
389
|
+
viewport.x = (float)viewport_[0];
|
|
390
|
+
viewport.y = (float)(target_height - (viewport_[1] + viewport_[3]));
|
|
391
|
+
viewport.w = (float)std::max(1, viewport_[2]);
|
|
392
|
+
viewport.h = (float)std::max(1, viewport_[3]);
|
|
393
|
+
viewport.min_depth = 0.0f;
|
|
394
|
+
viewport.max_depth = 1.0f;
|
|
395
|
+
SDL_SetGPUViewport(pass_, &viewport);
|
|
396
|
+
|
|
397
|
+
SDL_Rect scissor;
|
|
398
|
+
scissor.x = 0;
|
|
399
|
+
scissor.y = 0;
|
|
400
|
+
scissor.w = target_width;
|
|
401
|
+
scissor.h = target_height;
|
|
402
|
+
if (scissor_test_ && scissor_box_[2] > 0 && scissor_box_[3] > 0) {
|
|
403
|
+
scissor.x = scissor_box_[0];
|
|
404
|
+
scissor.y = target_height - (scissor_box_[1] + scissor_box_[3]);
|
|
405
|
+
scissor.w = scissor_box_[2];
|
|
406
|
+
scissor.h = scissor_box_[3];
|
|
407
|
+
}
|
|
408
|
+
if (scissor.x < 0) {
|
|
409
|
+
scissor.w += scissor.x;
|
|
410
|
+
scissor.x = 0;
|
|
411
|
+
}
|
|
412
|
+
if (scissor.y < 0) {
|
|
413
|
+
scissor.h += scissor.y;
|
|
414
|
+
scissor.y = 0;
|
|
415
|
+
}
|
|
416
|
+
if (scissor.x + scissor.w > target_width) scissor.w = target_width - scissor.x;
|
|
417
|
+
if (scissor.y + scissor.h > target_height) scissor.h = target_height - scissor.y;
|
|
418
|
+
if (scissor.w < 0) scissor.w = 0;
|
|
419
|
+
if (scissor.h < 0) scissor.h = 0;
|
|
420
|
+
SDL_SetGPUScissor(pass_, &scissor);
|
|
421
|
+
|
|
422
|
+
const std::string key = pipeline_key(draw_mode, index_size, attributes, buffers, state_);
|
|
423
|
+
SDL_GPUGraphicsPipeline *pipeline = nullptr;
|
|
424
|
+
auto cached = program_->pipeline_cache.find(key);
|
|
425
|
+
if (cached != program_->pipeline_cache.end()) {
|
|
426
|
+
pipeline = cached->second;
|
|
427
|
+
} else {
|
|
428
|
+
pipeline = create_pipeline(program_, draw_mode, index_size, (int)attributes.size(),
|
|
429
|
+
(int)buffers.size(), attributes.data(), buffers.data(), key);
|
|
430
|
+
}
|
|
431
|
+
if (pipeline == nullptr) return;
|
|
432
|
+
|
|
433
|
+
SDL_BindGPUGraphicsPipeline(pass_, pipeline);
|
|
434
|
+
if (!bindings.empty()) {
|
|
435
|
+
SDL_BindGPUVertexBuffers(pass_, 0, bindings.data(), (Uint32)bindings.size());
|
|
436
|
+
}
|
|
437
|
+
if (index_size > 0) {
|
|
438
|
+
SDL_GPUBufferBinding binding;
|
|
439
|
+
binding.buffer = index_gpu;
|
|
440
|
+
binding.offset = 0;
|
|
441
|
+
SDL_BindGPUIndexBuffer(pass_, &binding,
|
|
442
|
+
index_size == 4 ? SDL_GPU_INDEXELEMENTSIZE_32BIT
|
|
443
|
+
: SDL_GPU_INDEXELEMENTSIZE_16BIT);
|
|
444
|
+
}
|
|
445
|
+
if (program_->vs_has_block && program_->block_size > 0) {
|
|
446
|
+
SDL_PushGPUVertexUniformData(cmd_, 0, program_->block.data(), (Uint32)program_->block.size());
|
|
447
|
+
}
|
|
448
|
+
if (program_->fs_has_block && program_->block_size > 0) {
|
|
449
|
+
SDL_PushGPUFragmentUniformData(cmd_, 0, program_->block.data(), (Uint32)program_->block.size());
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
auto bind_samplers = [&](const std::vector<int> &stage, bool vertex_stage) {
|
|
453
|
+
if (stage.empty()) return;
|
|
454
|
+
std::vector<SDL_GPUTextureSamplerBinding> sampler_bindings;
|
|
455
|
+
sampler_bindings.reserve(stage.size());
|
|
456
|
+
for (int uniform_index : stage) {
|
|
457
|
+
const WebGLUniform &uniform = program_->uniforms[(size_t)uniform_index];
|
|
458
|
+
const int unit =
|
|
459
|
+
uniform.unit >= 0 && uniform.unit < kWebGLMaxTextureUnits ? uniform.unit : 0;
|
|
460
|
+
WebGLTexture *sampled = texture(bound_textures_[unit]);
|
|
461
|
+
SDL_GPUTexture *gpu = sampled != nullptr ? ensure_texture_gpu(sampled, sampled->as_target)
|
|
462
|
+
: nullptr;
|
|
463
|
+
WebGLSampler *sampler_object = this->sampler(bound_samplers_[unit]);
|
|
464
|
+
SDL_GPUSampler *sampler = sampler_object != nullptr
|
|
465
|
+
? sampler_gpu(sampler_object)
|
|
466
|
+
: (sampled != nullptr ? sampler_for(sampled) : nullptr);
|
|
467
|
+
if (gpu == nullptr || sampler == nullptr) {
|
|
468
|
+
gpu = fallback_texture_;
|
|
469
|
+
sampler = fallback_sampler_;
|
|
470
|
+
}
|
|
471
|
+
SDL_GPUTextureSamplerBinding texture_binding;
|
|
472
|
+
texture_binding.texture = gpu;
|
|
473
|
+
texture_binding.sampler = sampler;
|
|
474
|
+
sampler_bindings.push_back(texture_binding);
|
|
475
|
+
}
|
|
476
|
+
if (vertex_stage) {
|
|
477
|
+
SDL_BindGPUVertexSamplers(pass_, 0, sampler_bindings.data(),
|
|
478
|
+
(Uint32)sampler_bindings.size());
|
|
479
|
+
} else {
|
|
480
|
+
SDL_BindGPUFragmentSamplers(pass_, 0, sampler_bindings.data(),
|
|
481
|
+
(Uint32)sampler_bindings.size());
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
bind_samplers(program_->vs_sampler_uniforms, true);
|
|
485
|
+
bind_samplers(program_->fs_sampler_uniforms, false);
|
|
486
|
+
|
|
487
|
+
if (index_size > 0) {
|
|
488
|
+
SDL_DrawGPUIndexedPrimitives(pass_, (Uint32)count, (Uint32)instances, (Uint32)first_index, 0,
|
|
489
|
+
0);
|
|
490
|
+
} else {
|
|
491
|
+
SDL_DrawGPUPrimitives(pass_, (Uint32)count, (Uint32)instances, (Uint32)first, 0);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — GLSL ES for WebGL.
|
|
3
|
+
*
|
|
4
|
+
* WebGL shaders reach `shaderSource` as GLSL ES 1.00/3.00 text, while SDL_GPU's
|
|
5
|
+
* Vulkan backend consumes SPIR-V. There is no GLSL compiler in SDL_GPU, so this
|
|
6
|
+
* module does two things:
|
|
7
|
+
*
|
|
8
|
+
* 1. rewrites a WebGL shader into Vulkan-flavoured GLSL ES 3.10
|
|
9
|
+
* (`attribute` -> `in`, `varying` -> in/out with explicit locations,
|
|
10
|
+
* `gl_FragColor` -> an output, non-sampler uniforms -> one std140 block,
|
|
11
|
+
* samplers -> explicit descriptor set/binding, `texture2D` -> `texture`);
|
|
12
|
+
* 2. compiles it with glslang and reflects the resulting SPIR-V, which yields
|
|
13
|
+
* the exact std140 offsets, array strides and matrix strides of the
|
|
14
|
+
* uniform block plus the active attributes and sampler bindings.
|
|
15
|
+
*
|
|
16
|
+
* Reflection is the source of truth for layout: the shader text may size an
|
|
17
|
+
* array with a macro, but glslang has already resolved it by the time we look
|
|
18
|
+
* at the block members.
|
|
19
|
+
*/
|
|
20
|
+
#ifndef XT_GUI_WEBGL_GLSL_H
|
|
21
|
+
#define XT_GUI_WEBGL_GLSL_H
|
|
22
|
+
|
|
23
|
+
#include <cstdint>
|
|
24
|
+
#include <string>
|
|
25
|
+
#include <unordered_map>
|
|
26
|
+
#include <utility>
|
|
27
|
+
#include <vector>
|
|
28
|
+
|
|
29
|
+
namespace xtgui {
|
|
30
|
+
|
|
31
|
+
/** One `uniform` declaration found in a shader source. */
|
|
32
|
+
struct GlslUniformDecl {
|
|
33
|
+
std::string type; // `mat4`, `vec3`, `sampler2D`, …
|
|
34
|
+
std::string name;
|
|
35
|
+
std::string array; // `[4]` (raw text, may contain a macro)
|
|
36
|
+
std::string precision; // `highp` / `mediump` / `lowp` / empty
|
|
37
|
+
bool sampler = false;
|
|
38
|
+
/** Extra qualifiers (`layout(...)`) that were already present; empty for a
|
|
39
|
+
* WebGL 1 source. */
|
|
40
|
+
std::string extra;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Where one declaration sits in the source text, and what it declares. */
|
|
44
|
+
struct GlslDeclSite {
|
|
45
|
+
enum Kind { Uniform, Sampler, Attribute, Varying, FragmentOut };
|
|
46
|
+
Kind kind = Uniform;
|
|
47
|
+
size_t begin = 0; // byte offset of the first token (`layout` included)
|
|
48
|
+
size_t end = 0; // byte offset just past the `;`
|
|
49
|
+
GlslUniformDecl decl;
|
|
50
|
+
int existing_location = -1; // from a `layout(location = …)` qualifier
|
|
51
|
+
/** True when a preprocessor `#if`/`#ifdef` encloses the declaration. */
|
|
52
|
+
bool conditional = false;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/** The declarations a shader contributes to a program. */
|
|
56
|
+
struct GlslShaderInfo {
|
|
57
|
+
std::vector<GlslUniformDecl> uniforms; // non-sampler
|
|
58
|
+
std::vector<GlslUniformDecl> samplers;
|
|
59
|
+
std::vector<GlslUniformDecl> attributes; // vertex only
|
|
60
|
+
std::vector<GlslUniformDecl> varyings;
|
|
61
|
+
/** Every top-level declaration, in source order, for the rewriter. */
|
|
62
|
+
std::vector<GlslDeclSite> sites;
|
|
63
|
+
/** Active top-level `struct Name { … };` definitions, hoisted before the
|
|
64
|
+
* uniform block because the block may name those types (three.js lights). */
|
|
65
|
+
std::vector<std::pair<size_t, size_t>> structs;
|
|
66
|
+
/** The text of those definitions, shared across stages at link time. */
|
|
67
|
+
std::vector<std::string> struct_definitions;
|
|
68
|
+
/** True when the source writes `gl_FragColor` / `gl_FragData[0]`. */
|
|
69
|
+
bool legacy_fragment_output = false;
|
|
70
|
+
/** True when the source declared its own `out` variable (ES 3.00). */
|
|
71
|
+
bool has_fragment_output = false;
|
|
72
|
+
/** Byte offset of the first non-sampler uniform declaration (block insertion
|
|
73
|
+
* point); `npos` when the shader has none. */
|
|
74
|
+
size_t first_uniform_offset = std::string::npos;
|
|
75
|
+
/** A declaration this engine cannot translate (struct uniform, block, …). */
|
|
76
|
+
std::string unsupported;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** Locations and bindings assigned at link time. */
|
|
80
|
+
struct GlslLinkLayout {
|
|
81
|
+
std::unordered_map<std::string, int> attributes; // name -> location
|
|
82
|
+
std::unordered_map<std::string, int> varyings; // name -> location
|
|
83
|
+
/** stage-local sampler binding: name -> binding index inside the stage. */
|
|
84
|
+
std::unordered_map<std::string, int> samplers;
|
|
85
|
+
/** Merged, declaration-ordered non-sampler uniforms (shared block members). */
|
|
86
|
+
std::vector<GlslUniformDecl> block_members;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/** Scan `source` for the declarations WebGL needs to know about. */
|
|
90
|
+
void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info);
|
|
91
|
+
|
|
92
|
+
/** Rewrite `source` into Vulkan GLSL ES 3.10 (`layout` added everywhere). */
|
|
93
|
+
std::string rewrite_glsl(const std::string &source, bool fragment, const GlslLinkLayout &layout,
|
|
94
|
+
const GlslShaderInfo &info);
|
|
95
|
+
|
|
96
|
+
/** Compile a rewritten shader to SPIR-V. Returns false and fills `log`. */
|
|
97
|
+
bool compile_glsl(const std::string &source, bool fragment, std::vector<uint32_t> *spirv,
|
|
98
|
+
std::string *log);
|
|
99
|
+
|
|
100
|
+
/** One std140 block member, reflected from SPIR-V. */
|
|
101
|
+
struct GlslBlockMember {
|
|
102
|
+
std::string name;
|
|
103
|
+
int gl_type = 0; // GL_FLOAT, GL_FLOAT_VEC4, GL_FLOAT_MAT4, GL_INT_VEC2, …
|
|
104
|
+
int components = 0; // 1..4
|
|
105
|
+
bool is_matrix = false;
|
|
106
|
+
int columns = 0; // matrix columns; 0 for non-matrix members
|
|
107
|
+
int rows = 0;
|
|
108
|
+
bool is_array = false;
|
|
109
|
+
int array_size = 1;
|
|
110
|
+
int offset = 0; // byte offset of the member in the block
|
|
111
|
+
int array_stride = 0; // byte stride between array elements
|
|
112
|
+
int matrix_stride = 0; // byte stride between matrix columns
|
|
113
|
+
int scalar_type = 0; // GL_FLOAT / GL_INT / GL_BOOL
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/** Reflect the (single) uniform block of a compiled shader. */
|
|
117
|
+
bool reflect_uniform_block(const std::vector<uint32_t> &spirv, std::vector<GlslBlockMember> *out);
|
|
118
|
+
|
|
119
|
+
/** Reflect `in` variable locations (vertex attributes) from SPIR-V. */
|
|
120
|
+
bool reflect_attributes(const std::vector<uint32_t> &spirv,
|
|
121
|
+
std::unordered_map<std::string, int> *out);
|
|
122
|
+
|
|
123
|
+
} // namespace xtgui
|
|
124
|
+
|
|
125
|
+
#endif /* XT_GUI_WEBGL_GLSL_H */
|