xbintsc 0.5.37 → 0.5.41
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/dist/src/cli/help.d.ts +1 -1
- package/dist/src/codegen/generator/module.js +23 -7
- package/dist/src/codegen/generator/module.js.map +1 -1
- package/dist/src/codegen/generator/state.js +1 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.js +1 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/deferred.d.ts +63 -0
- package/dist/src/driver/bundler/deferred.js +279 -0
- package/dist/src/driver/bundler/deferred.js.map +1 -0
- package/dist/src/driver/bundler/merge.js +214 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/runtime-objects.d.ts +1 -1
- package/dist/src/driver/runtime-objects.js +1 -0
- package/dist/src/driver/runtime-objects.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/html.js +98 -15
- package/dist/src/extensions/gui/html.js.map +1 -1
- package/dist/src/extensions/gui/index.js +1 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/gui/three.d.ts +4 -3
- package/dist/src/extensions/gui/three.js +4 -3
- package/dist/src/extensions/gui/three.js.map +1 -1
- package/dist/tests/codegen/closures.test.js +7 -0
- package/dist/tests/codegen/closures.test.js.map +1 -1
- package/dist/tests/e2e/compile-objects-classes.test.js +31 -0
- package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
- package/dist/tests/e2e/gui-canvas-state.test.d.ts +9 -0
- package/dist/tests/e2e/gui-canvas-state.test.js +297 -0
- package/dist/tests/e2e/gui-canvas-state.test.js.map +1 -0
- package/dist/tests/e2e/gui-draw-perf.test.d.ts +22 -0
- package/dist/tests/e2e/gui-draw-perf.test.js +405 -0
- package/dist/tests/e2e/gui-draw-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-perf.test.d.ts +23 -0
- package/dist/tests/e2e/gui-perf.test.js +283 -0
- package/dist/tests/e2e/gui-perf.test.js.map +1 -0
- package/dist/tests/e2e/gui-script-import-order.test.d.ts +10 -0
- package/dist/tests/e2e/gui-script-import-order.test.js +169 -0
- package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl.test.js +4 -4
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js +336 -0
- package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js +108 -0
- package/dist/tests/e2e/gui-webgl2-shadow.test.js.map +1 -0
- package/dist/tests/e2e/url.test.d.ts +6 -0
- package/dist/tests/e2e/url.test.js +114 -0
- package/dist/tests/e2e/url.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.js +45 -10
- package/dist/tests/extensions/gui.test.js.map +1 -1
- package/doc/gui/api.md +28 -2
- package/doc/gui/canvas.md +110 -27
- package/doc/gui/known-issues.md +32 -10
- package/doc/gui/rendering.md +77 -0
- package/doc/gui/runtime.md +18 -3
- package/doc/gui/webgl.md +58 -29
- package/doc/gui-scripts.md +19 -19
- package/doc/gui.md +43 -9
- package/doc/implemented/fetch.md +5 -0
- package/doc/implemented/modules.md +13 -0
- package/doc/implemented/stdlib.md +17 -0
- package/doc/unimplemented/deviations.md +1 -0
- package/doc/zh-CN/gui/api.md +25 -2
- package/doc/zh-CN/gui/canvas.md +95 -26
- package/doc/zh-CN/gui/known-issues.md +21 -4
- package/doc/zh-CN/gui/rendering.md +59 -0
- package/doc/zh-CN/gui/runtime.md +13 -3
- package/doc/zh-CN/gui/webgl.md +30 -8
- package/doc/zh-CN/gui-scripts.md +14 -13
- package/doc/zh-CN/gui.md +32 -8
- package/doc/zh-CN/implemented/fetch.md +4 -0
- package/doc/zh-CN/implemented/modules.md +10 -0
- package/doc/zh-CN/implemented/stdlib.md +15 -0
- package/doc/zh-CN/unimplemented/deviations.md +1 -0
- package/package.json +7 -7
- package/runtime/ext_gui/browser.cpp +3 -1
- package/runtime/ext_gui/canvas.cpp +135 -89
- package/runtime/ext_gui/canvas.h +116 -0
- package/runtime/ext_gui/canvas_clip.cpp +143 -0
- package/runtime/ext_gui/canvas_composite.cpp +241 -0
- package/runtime/ext_gui/canvas_coverage.cpp +241 -0
- package/runtime/ext_gui/canvas_gradient.cpp +41 -4
- package/runtime/ext_gui/canvas_image_data.cpp +4 -0
- package/runtime/ext_gui/canvas_internal.h +34 -9
- package/runtime/ext_gui/canvas_raster.cpp +207 -178
- package/runtime/ext_gui/canvas_shadow.cpp +161 -0
- package/runtime/ext_gui/canvas_stroke.cpp +37 -9
- package/runtime/ext_gui/canvas_style.cpp +59 -0
- package/runtime/ext_gui/canvas_text.cpp +140 -0
- package/runtime/ext_gui/css.h +7 -0
- package/runtime/ext_gui/css_sheet.cpp +22 -0
- package/runtime/ext_gui/document.cpp +25 -1
- package/runtime/ext_gui/document.h +8 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +16 -1
- package/runtime/ext_gui/dom_api_canvas_image.cpp +9 -0
- package/runtime/ext_gui/dom_api_canvas_state.cpp +217 -0
- package/runtime/ext_gui/dom_api_internal.h +36 -37
- package/runtime/ext_gui/dom_api_offscreen.cpp +213 -0
- package/runtime/ext_gui/dom_api_proto.cpp +18 -0
- package/runtime/ext_gui/dom_api_webgl.cpp +29 -9
- package/runtime/ext_gui/dom_api_webgl2.cpp +33 -1
- package/runtime/ext_gui/dom_api_webgl_internal.h +58 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +18 -0
- package/runtime/ext_gui/gradient_values.cpp +12 -1
- package/runtime/ext_gui/gui.cpp +5 -0
- package/runtime/ext_gui/gui_canvas.cpp +4 -0
- package/runtime/ext_gui/gui_engine.h +32 -0
- package/runtime/ext_gui/gui_events.cpp +182 -58
- package/runtime/ext_gui/gui_media.cpp +3 -0
- package/runtime/ext_gui/image.cpp +69 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +11 -0
- package/runtime/ext_gui/layout.cpp +4 -0
- package/runtime/ext_gui/paint.cpp +19 -0
- package/runtime/ext_gui/paint_background.cpp +18 -1
- package/runtime/ext_gui/perf.cpp +171 -0
- package/runtime/ext_gui/perf.h +127 -0
- package/runtime/ext_gui/renderer.cpp +109 -41
- package/runtime/ext_gui/renderer.h +33 -9
- package/runtime/ext_gui/renderer_image.cpp +135 -65
- package/runtime/ext_gui/renderer_internal.h +15 -3
- package/runtime/ext_gui/renderer_text.cpp +24 -12
- package/runtime/ext_gui/script.cpp +31 -0
- package/runtime/ext_gui/style.cpp +101 -30
- package/runtime/ext_gui/style.h +6 -3
- package/runtime/ext_gui/style_print.cpp +7 -1
- package/runtime/ext_gui/text.cpp +23 -4
- package/runtime/ext_gui/text.h +29 -0
- package/runtime/ext_gui/text_cache.cpp +118 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +100 -0
- package/runtime/ext_gui/webgl.h +48 -146
- package/runtime/ext_gui/webgl_blit.cpp +12 -1
- package/runtime/ext_gui/webgl_blit_depth.cpp +270 -0
- package/runtime/ext_gui/webgl_buffer.cpp +59 -1
- package/runtime/ext_gui/webgl_buffer_objects.cpp +106 -9
- package/runtime/ext_gui/webgl_clear.cpp +3 -0
- package/runtime/ext_gui/webgl_context.cpp +29 -3
- package/runtime/ext_gui/webgl_draw.cpp +75 -270
- package/runtime/ext_gui/webgl_draw_buffers.cpp +1 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +321 -0
- package/runtime/ext_gui/webgl_draw_state.h +130 -0
- package/runtime/ext_gui/webgl_glsl.h +3 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +3 -8
- package/runtime/ext_gui/webgl_glsl_unroll.cpp +283 -0
- package/runtime/ext_gui/webgl_msl.cpp +4 -0
- package/runtime/ext_gui/webgl_objects.h +148 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +8 -8
- package/runtime/ext_gui/webgl_program_internal.h +35 -0
- package/runtime/ext_gui/webgl_shader.cpp +34 -36
- package/runtime/ext_gui/webgl_webgl2.cpp +36 -0
- package/runtime/ext_gui/window.cpp +56 -1
- package/runtime/rt.h +3 -0
- package/runtime/xt_fetch/async.inc +60 -0
- package/runtime/xt_url_object.c +463 -0
- package/src/codegen/generator/module.ts +22 -7
- package/src/codegen/generator/state.ts +1 -0
- package/src/codegen/generator/tables.ts +1 -0
- package/src/driver/bundler/deferred.ts +351 -0
- package/src/driver/bundler/merge.ts +219 -2
- package/src/driver/runtime-objects.ts +1 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/html.ts +100 -17
- package/src/extensions/gui/index.ts +1 -0
- package/src/extensions/gui/three.ts +4 -3
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — prepared WebGL draws.
|
|
3
|
+
*
|
|
4
|
+
* Every draw needs the same three things: the pipeline for the current
|
|
5
|
+
* fixed-function state, the vertex layout of the program's active attributes,
|
|
6
|
+
* and the GPU buffer handles behind them. Building that per draw was the
|
|
7
|
+
* dominant CPU cost of a multi-element scene, so it is built once per
|
|
8
|
+
* (program, layout version, state) and cached in `draw_setups_`.
|
|
9
|
+
*
|
|
10
|
+
* A setup is invalidated by bumping one of the context's state versions:
|
|
11
|
+
* `attribs_version_` for anything that changes the vertex layout (attribute
|
|
12
|
+
* pointers, enables, VAO loads), `gpu_version_` for buffer handle changes, and
|
|
13
|
+
* `framebuffer_version_` for attachment-format changes.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include "webgl.h"
|
|
17
|
+
|
|
18
|
+
#include <cstring>
|
|
19
|
+
#include <utility>
|
|
20
|
+
#include <vector>
|
|
21
|
+
|
|
22
|
+
#include "gui_internal.h"
|
|
23
|
+
|
|
24
|
+
namespace xtgui {
|
|
25
|
+
namespace {
|
|
26
|
+
|
|
27
|
+
int components_of_type(const std::string &type) {
|
|
28
|
+
if (!type.empty() && type.back() >= '2' && type.back() <= '4') return type.back() - '0';
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
int matrix_slots(const std::string &type) {
|
|
33
|
+
if (type == "mat2") return 2;
|
|
34
|
+
if (type == "mat3") return 3;
|
|
35
|
+
if (type == "mat4") return 4;
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
SDL_GPUVertexElementFormat float_format(int size) {
|
|
40
|
+
switch (size) {
|
|
41
|
+
case 1:
|
|
42
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT;
|
|
43
|
+
case 2:
|
|
44
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
|
|
45
|
+
case 3:
|
|
46
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
|
|
47
|
+
default:
|
|
48
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
SDL_GPUVertexElementFormat format_of(int size, int type, bool normalized) {
|
|
53
|
+
if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
54
|
+
if (type == GL_FLOAT) return float_format(size);
|
|
55
|
+
if (type == GL_UNSIGNED_BYTE || type == GL_BYTE) {
|
|
56
|
+
const bool is_byte = type == GL_BYTE;
|
|
57
|
+
if (size == 2) {
|
|
58
|
+
return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2_NORM
|
|
59
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2_NORM)
|
|
60
|
+
: (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2
|
|
61
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2);
|
|
62
|
+
}
|
|
63
|
+
if (size == 4) {
|
|
64
|
+
return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4_NORM
|
|
65
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM)
|
|
66
|
+
: (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4
|
|
67
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4);
|
|
68
|
+
}
|
|
69
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
70
|
+
}
|
|
71
|
+
if (type == GL_UNSIGNED_SHORT || type == GL_SHORT) {
|
|
72
|
+
const bool is_short = type == GL_SHORT;
|
|
73
|
+
if (size == 2) {
|
|
74
|
+
return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2_NORM
|
|
75
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT2_NORM)
|
|
76
|
+
: (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2
|
|
77
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT2);
|
|
78
|
+
}
|
|
79
|
+
if (size == 4) {
|
|
80
|
+
return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4_NORM
|
|
81
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4_NORM)
|
|
82
|
+
: (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4
|
|
83
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4);
|
|
84
|
+
}
|
|
85
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
86
|
+
}
|
|
87
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
SDL_GPUVertexElementFormat int_format_of(int size, int type) {
|
|
91
|
+
if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
92
|
+
if (type == GL_INT) {
|
|
93
|
+
switch (size) {
|
|
94
|
+
case 1:
|
|
95
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT;
|
|
96
|
+
case 2:
|
|
97
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT2;
|
|
98
|
+
case 3:
|
|
99
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT3;
|
|
100
|
+
default:
|
|
101
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT4;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (type == GL_UNSIGNED_INT) {
|
|
105
|
+
switch (size) {
|
|
106
|
+
case 1:
|
|
107
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT;
|
|
108
|
+
case 2:
|
|
109
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT2;
|
|
110
|
+
case 3:
|
|
111
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT3;
|
|
112
|
+
default:
|
|
113
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT4;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (type == GL_SHORT && (size == 2 || size == 4)) {
|
|
117
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2 : SDL_GPU_VERTEXELEMENTFORMAT_SHORT4;
|
|
118
|
+
}
|
|
119
|
+
if (type == GL_UNSIGNED_SHORT && (size == 2 || size == 4)) {
|
|
120
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_USHORT2
|
|
121
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4;
|
|
122
|
+
}
|
|
123
|
+
if (type == GL_BYTE && (size == 2 || size == 4)) {
|
|
124
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_BYTE4;
|
|
125
|
+
}
|
|
126
|
+
if (type == GL_UNSIGNED_BYTE && (size == 2 || size == 4)) {
|
|
127
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4;
|
|
128
|
+
}
|
|
129
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
int type_size(int type) {
|
|
133
|
+
switch (type) {
|
|
134
|
+
case GL_BYTE:
|
|
135
|
+
case GL_UNSIGNED_BYTE:
|
|
136
|
+
return 1;
|
|
137
|
+
case GL_SHORT:
|
|
138
|
+
case GL_UNSIGNED_SHORT:
|
|
139
|
+
return 2;
|
|
140
|
+
default:
|
|
141
|
+
return 4;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
} // namespace
|
|
146
|
+
|
|
147
|
+
void WebGLContext::draw_state_hash(uint64_t *first, uint64_t *second) const {
|
|
148
|
+
uint64_t h1 = 1469598103934665603ull;
|
|
149
|
+
uint64_t h2 = 0x9e3779b97f4a7c15ull;
|
|
150
|
+
auto mix = [&h1, &h2](uint64_t value) {
|
|
151
|
+
h1 ^= value;
|
|
152
|
+
h1 *= 1099511628211ull;
|
|
153
|
+
h1 ^= h1 >> 32;
|
|
154
|
+
h2 += value + 0x9e3779b97f4a7c15ull;
|
|
155
|
+
h2 = (h2 << 27) | (h2 >> 37);
|
|
156
|
+
h2 *= 0xbf58476d1ce4e5b9ull;
|
|
157
|
+
};
|
|
158
|
+
auto mix_face = [&mix](const WebGLStencilFace &face) {
|
|
159
|
+
/* `ref` is a per-pass dynamic value, not part of the pipeline. */
|
|
160
|
+
mix((uint64_t)(uint32_t)face.func);
|
|
161
|
+
mix(face.value_mask);
|
|
162
|
+
mix(face.write_mask);
|
|
163
|
+
mix((uint64_t)(uint32_t)face.fail);
|
|
164
|
+
mix((uint64_t)(uint32_t)face.zfail);
|
|
165
|
+
mix((uint64_t)(uint32_t)face.zpass);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
mix(state_.blend ? 1u : 0u);
|
|
169
|
+
mix((uint64_t)(uint32_t)state_.blend_src_rgb);
|
|
170
|
+
mix((uint64_t)(uint32_t)state_.blend_dst_rgb);
|
|
171
|
+
mix((uint64_t)(uint32_t)state_.blend_src_alpha);
|
|
172
|
+
mix((uint64_t)(uint32_t)state_.blend_dst_alpha);
|
|
173
|
+
mix((uint64_t)(uint32_t)state_.blend_eq_rgb);
|
|
174
|
+
mix((uint64_t)(uint32_t)state_.blend_eq_alpha);
|
|
175
|
+
mix(state_.depth_test ? 1u : 0u);
|
|
176
|
+
mix(state_.depth_write ? 1u : 0u);
|
|
177
|
+
mix((uint64_t)(uint32_t)state_.depth_func);
|
|
178
|
+
mix(state_.stencil ? 1u : 0u);
|
|
179
|
+
mix_face(state_.stencil_front);
|
|
180
|
+
mix_face(state_.stencil_back);
|
|
181
|
+
mix(state_.cull ? 1u : 0u);
|
|
182
|
+
mix((uint64_t)(uint32_t)state_.cull_face);
|
|
183
|
+
mix((uint64_t)(uint32_t)state_.front_face);
|
|
184
|
+
for (bool channel : state_.color_mask) mix(channel ? 1u : 0u);
|
|
185
|
+
mix((uint64_t)(uint32_t)state_.color_target_count);
|
|
186
|
+
for (int i = 0; i < state_.color_target_count; i++) {
|
|
187
|
+
mix((uint64_t)(uint32_t)state_.color_formats[i]);
|
|
188
|
+
}
|
|
189
|
+
mix((uint64_t)(uint32_t)state_.depth_format);
|
|
190
|
+
|
|
191
|
+
*first = h1;
|
|
192
|
+
*second = h2;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
void WebGLContext::clear_draw_cache() {
|
|
196
|
+
draw_setups_.clear();
|
|
197
|
+
last_setup_ = nullptr;
|
|
198
|
+
last_pipeline_ = nullptr;
|
|
199
|
+
last_setup_pass_ = 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const WebGLDrawSetup *WebGLContext::prepare_draw(const WebGLDrawKey &key) {
|
|
203
|
+
auto found = draw_setups_.find(key);
|
|
204
|
+
if (found != draw_setups_.end()) return &found->second;
|
|
205
|
+
WebGLProgram *program_ = program(key.program);
|
|
206
|
+
if (program_ == nullptr) {
|
|
207
|
+
set_error(GL_INVALID_OPERATION);
|
|
208
|
+
return nullptr;
|
|
209
|
+
}
|
|
210
|
+
/* A page that cycles through many states would otherwise grow the table
|
|
211
|
+
* without bound; clearing only costs one rebuild per live state. */
|
|
212
|
+
if (draw_setups_.size() >= 256) clear_draw_cache();
|
|
213
|
+
|
|
214
|
+
WebGLDrawSetup setup;
|
|
215
|
+
setup.attributes.reserve(program_->draw_attribs.size());
|
|
216
|
+
setup.buffers.reserve(program_->draw_attribs.size());
|
|
217
|
+
setup.bindings.reserve(program_->draw_attribs.size());
|
|
218
|
+
|
|
219
|
+
for (const WebGLDrawAttribPlan &plan : program_->draw_attribs) {
|
|
220
|
+
if (plan.location < 0 || plan.location >= kWebGLMaxAttribs) continue;
|
|
221
|
+
WebGLAttribState &attrib = attribs_[plan.location];
|
|
222
|
+
const int slots = matrix_slots(plan.type);
|
|
223
|
+
const int type_components = components_of_type(plan.type);
|
|
224
|
+
const int components = slots > 1 ? slots : (type_components > 4 ? 4 : type_components);
|
|
225
|
+
const uint32_t slot = (uint32_t)setup.buffers.size();
|
|
226
|
+
|
|
227
|
+
SDL_GPUVertexBufferDescription description;
|
|
228
|
+
memset(&description, 0, sizeof(description));
|
|
229
|
+
description.slot = slot;
|
|
230
|
+
description.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
231
|
+
SDL_GPUBufferBinding binding;
|
|
232
|
+
memset(&binding, 0, sizeof(binding));
|
|
233
|
+
|
|
234
|
+
if (!attrib.enabled) {
|
|
235
|
+
/* A disabled attribute is a constant read from a persistent 16-byte
|
|
236
|
+
* buffer, not a fresh GPU allocation per draw. */
|
|
237
|
+
SDL_GPUBuffer *constant = constant_attrib_buffer(plan.location);
|
|
238
|
+
if (constant == nullptr) return nullptr;
|
|
239
|
+
binding.buffer = constant;
|
|
240
|
+
description.pitch = 0;
|
|
241
|
+
for (int column = 0; column < slots; column++) {
|
|
242
|
+
SDL_GPUVertexAttribute attribute;
|
|
243
|
+
memset(&attribute, 0, sizeof(attribute));
|
|
244
|
+
attribute.location = (Uint32)(plan.location + column);
|
|
245
|
+
attribute.buffer_slot = slot;
|
|
246
|
+
attribute.format = float_format(components);
|
|
247
|
+
attribute.offset = 0;
|
|
248
|
+
setup.attributes.push_back(attribute);
|
|
249
|
+
}
|
|
250
|
+
setup.buffers.push_back(description);
|
|
251
|
+
setup.bindings.push_back(binding);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
WebGLBuffer *buffer_ = buffer(attrib.buffer);
|
|
256
|
+
if (buffer_ == nullptr || buffer_->data.empty()) {
|
|
257
|
+
set_error(GL_INVALID_OPERATION);
|
|
258
|
+
return nullptr;
|
|
259
|
+
}
|
|
260
|
+
SDL_GPUVertexElementFormat format = attrib.integer
|
|
261
|
+
? int_format_of(attrib.size, attrib.type)
|
|
262
|
+
: format_of(attrib.size, attrib.type, attrib.normalized);
|
|
263
|
+
if (format == SDL_GPU_VERTEXELEMENTFORMAT_INVALID) {
|
|
264
|
+
set_error(GL_INVALID_OPERATION);
|
|
265
|
+
return nullptr;
|
|
266
|
+
}
|
|
267
|
+
description.input_rate = attrib.divisor > 0 ? SDL_GPU_VERTEXINPUTRATE_INSTANCE
|
|
268
|
+
: SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
269
|
+
const int stride =
|
|
270
|
+
attrib.stride > 0 ? attrib.stride : components * type_size(attrib.type) * slots;
|
|
271
|
+
description.pitch = (Uint32)stride;
|
|
272
|
+
SDL_GPUBuffer *gpu = ensure_buffer_gpu(buffer_);
|
|
273
|
+
if (gpu == nullptr) return nullptr;
|
|
274
|
+
binding.buffer = gpu;
|
|
275
|
+
for (int column = 0; column < slots; column++) {
|
|
276
|
+
SDL_GPUVertexAttribute attribute;
|
|
277
|
+
memset(&attribute, 0, sizeof(attribute));
|
|
278
|
+
attribute.location = (Uint32)(plan.location + column);
|
|
279
|
+
attribute.buffer_slot = slot;
|
|
280
|
+
attribute.format = format;
|
|
281
|
+
attribute.offset = (Uint32)(attrib.offset + column * components * type_size(attrib.type));
|
|
282
|
+
setup.attributes.push_back(attribute);
|
|
283
|
+
}
|
|
284
|
+
setup.buffers.push_back(description);
|
|
285
|
+
setup.bindings.push_back(binding);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (key.index_size > 0 && key.element_buffer != 0) {
|
|
289
|
+
WebGLBuffer *element = buffer(key.element_buffer);
|
|
290
|
+
if (element == nullptr || element->data.empty()) {
|
|
291
|
+
set_error(GL_INVALID_OPERATION);
|
|
292
|
+
return nullptr;
|
|
293
|
+
}
|
|
294
|
+
setup.index_buffer = ensure_buffer_gpu(element);
|
|
295
|
+
if (setup.index_buffer == nullptr) return nullptr;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* The pipeline depends on the vertex layout and fixed-function state, not on
|
|
299
|
+
* which GPU buffer happens to hold the data (a buffer can be recreated after
|
|
300
|
+
* a grow) nor on the element-buffer binding. Normalise those fields out so a
|
|
301
|
+
* dynamic buffer does not create a fresh pipeline. */
|
|
302
|
+
WebGLDrawKey pipeline_key = key;
|
|
303
|
+
pipeline_key.gpu_version = 0;
|
|
304
|
+
pipeline_key.element_buffer = 0;
|
|
305
|
+
auto cached = program_->pipeline_cache.find(pipeline_key);
|
|
306
|
+
if (cached != program_->pipeline_cache.end()) {
|
|
307
|
+
setup.pipeline = cached->second;
|
|
308
|
+
} else {
|
|
309
|
+
setup.pipeline = create_pipeline(program_, key.mode, (int)setup.attributes.size(),
|
|
310
|
+
(int)setup.buffers.size(), setup.attributes.data(),
|
|
311
|
+
setup.buffers.data());
|
|
312
|
+
if (setup.pipeline == nullptr) return nullptr;
|
|
313
|
+
program_->pipeline_cache[pipeline_key] = setup.pipeline;
|
|
314
|
+
program_->pipelines.push_back(setup.pipeline);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
auto inserted = draw_setups_.emplace(key, std::move(setup));
|
|
318
|
+
return &inserted.first->second;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — the fixed-function WebGL state a pipeline depends on.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `webgl.h` to keep that header under the repository's
|
|
5
|
+
* file-length budget.
|
|
6
|
+
*/
|
|
7
|
+
#ifndef XT_GUI_WEBGL_DRAW_STATE_H
|
|
8
|
+
#define XT_GUI_WEBGL_DRAW_STATE_H
|
|
9
|
+
|
|
10
|
+
#include <cstddef>
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
#include <SDL3/SDL.h>
|
|
16
|
+
|
|
17
|
+
#include "webgl_constants.h"
|
|
18
|
+
|
|
19
|
+
namespace xtgui {
|
|
20
|
+
|
|
21
|
+
/** One face's stencil test and update state. */
|
|
22
|
+
struct WebGLStencilFace {
|
|
23
|
+
int func = GL_ALWAYS;
|
|
24
|
+
int ref = 0;
|
|
25
|
+
uint32_t value_mask = 0xFFFFFFFFu; // compare mask
|
|
26
|
+
uint32_t write_mask = 0xFFFFFFFFu;
|
|
27
|
+
int fail = GL_KEEP;
|
|
28
|
+
int zfail = GL_KEEP;
|
|
29
|
+
int zpass = GL_KEEP;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** The fixed-function state a pipeline depends on. */
|
|
33
|
+
struct WebGLDrawState {
|
|
34
|
+
bool blend = false;
|
|
35
|
+
int blend_src_rgb = GL_ONE;
|
|
36
|
+
int blend_dst_rgb = GL_ZERO;
|
|
37
|
+
int blend_src_alpha = GL_ONE;
|
|
38
|
+
int blend_dst_alpha = GL_ZERO;
|
|
39
|
+
int blend_eq_rgb = GL_FUNC_ADD;
|
|
40
|
+
int blend_eq_alpha = GL_FUNC_ADD;
|
|
41
|
+
bool depth_test = false;
|
|
42
|
+
bool depth_write = true;
|
|
43
|
+
int depth_func = GL_LESS;
|
|
44
|
+
bool stencil = false;
|
|
45
|
+
WebGLStencilFace stencil_front;
|
|
46
|
+
WebGLStencilFace stencil_back;
|
|
47
|
+
bool cull = false;
|
|
48
|
+
int cull_face = GL_BACK;
|
|
49
|
+
int front_face = GL_CCW;
|
|
50
|
+
bool color_mask[4] = {true, true, true, true};
|
|
51
|
+
/** Attachment formats of the bound target; pipelines are format-specific. */
|
|
52
|
+
int color_formats[4] = {
|
|
53
|
+
SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
|
|
54
|
+
SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM};
|
|
55
|
+
int color_target_count = 1;
|
|
56
|
+
int depth_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Identity of one prepared draw. Everything a draw's pipeline, vertex layout
|
|
61
|
+
* and GPU buffer handles depend on is either an exact integer here or folds
|
|
62
|
+
* into `state_hash`/`state_hash2` (a 128-bit hash of `WebGLDrawState`). Two
|
|
63
|
+
* independent hashes keep a collision in the same place a 128-bit hash would
|
|
64
|
+
* have it — the state struct has no padding-sensitive fields to compare.
|
|
65
|
+
*/
|
|
66
|
+
struct WebGLDrawKey {
|
|
67
|
+
uint32_t program = 0;
|
|
68
|
+
int mode = 0; // GL primitive mode
|
|
69
|
+
int index_size = 0; // 0 = drawArrays, otherwise index element bytes
|
|
70
|
+
uint32_t element_buffer = 0; // bound GL_ELEMENT_ARRAY_BUFFER, 0 = none
|
|
71
|
+
uint64_t attribs_version = 0;
|
|
72
|
+
uint64_t gpu_version = 0;
|
|
73
|
+
uint64_t framebuffer_version = 0;
|
|
74
|
+
uint64_t state_hash = 0;
|
|
75
|
+
uint64_t state_hash2 = 0;
|
|
76
|
+
|
|
77
|
+
bool operator==(const WebGLDrawKey &other) const {
|
|
78
|
+
return program == other.program && mode == other.mode && index_size == other.index_size &&
|
|
79
|
+
element_buffer == other.element_buffer && attribs_version == other.attribs_version &&
|
|
80
|
+
gpu_version == other.gpu_version &&
|
|
81
|
+
framebuffer_version == other.framebuffer_version && state_hash == other.state_hash &&
|
|
82
|
+
state_hash2 == other.state_hash2;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
struct WebGLDrawKeyHash {
|
|
87
|
+
size_t operator()(const WebGLDrawKey &key) const {
|
|
88
|
+
uint64_t hash = 1469598103934665603ull;
|
|
89
|
+
auto mix = [&hash](uint64_t value) {
|
|
90
|
+
hash ^= value;
|
|
91
|
+
hash *= 1099511628211ull;
|
|
92
|
+
hash ^= hash >> 29;
|
|
93
|
+
};
|
|
94
|
+
mix(key.program);
|
|
95
|
+
mix((uint64_t)(uint32_t)key.mode);
|
|
96
|
+
mix((uint64_t)(uint32_t)key.index_size);
|
|
97
|
+
mix(key.element_buffer);
|
|
98
|
+
mix(key.attribs_version);
|
|
99
|
+
mix(key.gpu_version);
|
|
100
|
+
mix(key.framebuffer_version);
|
|
101
|
+
mix(key.state_hash);
|
|
102
|
+
mix(key.state_hash2);
|
|
103
|
+
return (size_t)hash;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* One active vertex attribute, resolved once at link time: `location` is the
|
|
109
|
+
* base attribute location and `type` the GLSL type name the draw needs to size
|
|
110
|
+
* the vertex layout. Keeping this out of the draw path removes the per-draw
|
|
111
|
+
* `attribs` scan and the `name -> location` string hash lookup.
|
|
112
|
+
*/
|
|
113
|
+
struct WebGLDrawAttribPlan {
|
|
114
|
+
int location = -1;
|
|
115
|
+
std::string type;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** A pipeline and the vertex-layout/binding set the draw prepared for it. A
|
|
119
|
+
* cache hit is a bind (when it changed) and a draw. */
|
|
120
|
+
struct WebGLDrawSetup {
|
|
121
|
+
SDL_GPUGraphicsPipeline *pipeline = nullptr;
|
|
122
|
+
std::vector<SDL_GPUVertexAttribute> attributes;
|
|
123
|
+
std::vector<SDL_GPUVertexBufferDescription> buffers;
|
|
124
|
+
std::vector<SDL_GPUBufferBinding> bindings;
|
|
125
|
+
SDL_GPUBuffer *index_buffer = nullptr;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
} // namespace xtgui
|
|
129
|
+
|
|
130
|
+
#endif /* XT_GUI_WEBGL_DRAW_STATE_H */
|
|
@@ -126,6 +126,9 @@ struct GlslLinkLayout {
|
|
|
126
126
|
std::vector<GlslUniformDecl> block_members;
|
|
127
127
|
};
|
|
128
128
|
|
|
129
|
+
/** Expand three.js's `#pragma unroll_loop_start` loops into constant indices. */
|
|
130
|
+
std::string unroll_glsl_pragmas(const std::string &source);
|
|
131
|
+
|
|
129
132
|
/** Scan `source` for the declarations WebGL needs to know about. */
|
|
130
133
|
void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info);
|
|
131
134
|
|
|
@@ -425,14 +425,9 @@ void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info) {
|
|
|
425
425
|
info->legacy_fragment_output = true;
|
|
426
426
|
continue;
|
|
427
427
|
}
|
|
428
|
-
/*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
if (inactive == 0 && fragment && token.kind == Token::Ident &&
|
|
432
|
-
(token.text == "gl_FragDepth" || token.text == "gl_FragDepthEXT")) {
|
|
433
|
-
info->unsupported = "gl_FragDepth is not supported";
|
|
434
|
-
continue;
|
|
435
|
-
}
|
|
428
|
+
/* `gl_FragDepth`/`gl_FragDepthEXT`: the Vulkan SPIR-V path emits
|
|
429
|
+
* `DepthReplacing`, and SPIRV-Cross turns that into `[[depth(any)]]` for
|
|
430
|
+
* Metal, so a fragment shader may write the depth attachment directly. */
|
|
436
431
|
/* Declarations inside a definitively false preprocessor branch never reach
|
|
437
432
|
* the compiler; rewriting them would move their types/macros (and array
|
|
438
433
|
* sizes such as `MORPHTARGETS_COUNT`) outside that branch. */
|