xbintsc 0.5.45 → 0.5.52
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/AGENTS.md +1 -1
- package/README.md +5 -4
- package/README.zh-CN.md +4 -3
- package/dist/src/cli/extensions.d.ts +24 -0
- package/dist/src/cli/extensions.js +62 -0
- package/dist/src/cli/extensions.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/help.js +3 -1
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hints.js +8 -3
- package/dist/src/cli/hints.js.map +1 -1
- package/dist/src/cli/main.js +21 -28
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/diagnostics/diagnostic.d.ts +3 -1
- package/dist/src/diagnostics/diagnostic.js +2 -0
- package/dist/src/diagnostics/diagnostic.js.map +1 -1
- package/dist/src/driver/build-key.d.ts +2 -0
- package/dist/src/driver/build-key.js +1 -0
- package/dist/src/driver/build-key.js.map +1 -1
- package/dist/src/driver/compiler.js +61 -8
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +4 -0
- package/dist/src/driver/config.js +2 -0
- package/dist/src/driver/config.js.map +1 -1
- package/dist/src/driver/link-features.d.ts +37 -0
- package/dist/src/driver/link-features.js +123 -0
- package/dist/src/driver/link-features.js.map +1 -0
- package/dist/src/driver/options.d.ts +10 -0
- package/dist/src/driver/runtime-objects.d.ts +5 -0
- package/dist/src/driver/runtime-objects.js +20 -1
- package/dist/src/driver/runtime-objects.js.map +1 -1
- package/dist/src/driver/usage.d.ts +23 -0
- package/dist/src/driver/usage.js +353 -0
- package/dist/src/driver/usage.js.map +1 -0
- package/dist/src/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/catalog.js +1 -2
- package/dist/src/extensions/catalog.js.map +1 -1
- package/dist/src/extensions/gui/features.d.ts +34 -0
- package/dist/src/extensions/gui/features.js +165 -0
- package/dist/src/extensions/gui/features.js.map +1 -0
- package/dist/src/extensions/gui/index.js +10 -4
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/link-feature.d.ts +70 -0
- package/dist/src/extensions/link-feature.js +18 -0
- package/dist/src/extensions/link-feature.js.map +1 -0
- package/dist/src/extensions/registry.d.ts +24 -4
- package/dist/src/extensions/registry.js +26 -3
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +1 -1
- package/dist/tests/cli/hints.test.js +5 -7
- package/dist/tests/cli/hints.test.js.map +1 -1
- package/dist/tests/driver/link-features.test.js +105 -0
- package/dist/tests/driver/link-features.test.js.map +1 -0
- package/dist/tests/driver/usage.test.d.ts +1 -0
- package/dist/tests/driver/usage.test.js +88 -0
- package/dist/tests/driver/usage.test.js.map +1 -0
- package/dist/tests/e2e/gui-audio.test.js +4 -4
- package/dist/tests/e2e/gui-audio.test.js.map +1 -1
- package/dist/tests/e2e/gui-css-coverage.test.d.ts +9 -0
- package/dist/tests/e2e/gui-css-coverage.test.js +333 -0
- package/dist/tests/e2e/gui-css-coverage.test.js.map +1 -0
- package/dist/tests/e2e/gui-css-features.test.d.ts +6 -0
- package/dist/tests/e2e/gui-css-features.test.js +270 -0
- package/dist/tests/e2e/gui-css-features.test.js.map +1 -0
- package/dist/tests/e2e/gui-effects.test.js +92 -11
- package/dist/tests/e2e/gui-effects.test.js.map +1 -1
- package/dist/tests/e2e/gui-feature-linking.test.d.ts +9 -0
- package/dist/tests/e2e/gui-feature-linking.test.js +68 -0
- package/dist/tests/e2e/gui-feature-linking.test.js.map +1 -0
- package/dist/tests/e2e/gui-font-face.test.d.ts +10 -0
- package/dist/tests/e2e/gui-font-face.test.js +142 -0
- package/dist/tests/e2e/gui-font-face.test.js.map +1 -0
- package/dist/tests/e2e/gui-fonts.test.d.ts +10 -0
- package/dist/tests/e2e/gui-fonts.test.js +150 -0
- package/dist/tests/e2e/gui-fonts.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +10 -1
- package/dist/tests/e2e/gui-helpers.js +6 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-layout.test.js +7 -3
- package/dist/tests/e2e/gui-layout.test.js.map +1 -1
- package/dist/tests/e2e/gui-media-disabled.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media-disabled.test.js +7 -6
- package/dist/tests/e2e/gui-media-disabled.test.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.d.ts +5 -4
- package/dist/tests/e2e/gui-media.test.js +9 -9
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-paint.test.js +5 -2
- package/dist/tests/e2e/gui-paint.test.js.map +1 -1
- package/dist/tests/e2e/gui-shaping.test.d.ts +5 -0
- package/dist/tests/e2e/gui-shaping.test.js +47 -0
- package/dist/tests/e2e/gui-shaping.test.js.map +1 -0
- package/dist/tests/e2e/gui-track-sizing.test.d.ts +6 -0
- package/dist/tests/e2e/gui-track-sizing.test.js +173 -0
- package/dist/tests/e2e/gui-track-sizing.test.js.map +1 -0
- package/dist/tests/e2e/gui-transform.test.js +3 -2
- package/dist/tests/e2e/gui-transform.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.d.ts +18 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js +120 -0
- package/dist/tests/e2e/gui-webgl-pipeline-cache.test.js.map +1 -0
- package/dist/tests/extensions/gui-features.test.d.ts +1 -0
- package/dist/tests/extensions/gui-features.test.js +175 -0
- package/dist/tests/extensions/gui-features.test.js.map +1 -0
- package/doc/ai/cli.md +5 -1
- package/doc/ai/extensions.md +56 -26
- package/doc/ai/troubleshooting.md +10 -7
- package/doc/ai/zh-CN/cli.md +5 -1
- package/doc/ai/zh-CN/extensions.md +48 -22
- package/doc/ai/zh-CN/troubleshooting.md +6 -5
- package/doc/gui/animation.md +39 -9
- package/doc/gui/api.md +2 -1
- package/doc/gui/build.md +137 -19
- package/doc/gui/canvas.md +1 -1
- package/doc/gui/dom.md +20 -4
- package/doc/gui/known-issues.md +63 -26
- package/doc/gui/layout.md +31 -8
- package/doc/gui/media.md +13 -7
- package/doc/gui/rendering.md +114 -39
- package/doc/gui/runtime.md +5 -0
- package/doc/gui/webgl.md +24 -6
- package/doc/gui.md +110 -47
- package/doc/implemented/cli.md +2 -0
- package/doc/implemented/extensions.md +9 -3
- package/doc/npm-package.md +4 -4
- package/doc/xbintsc.config.schema.json +10 -0
- package/doc/zh-CN/gui/animation.md +33 -10
- package/doc/zh-CN/gui/api.md +2 -1
- package/doc/zh-CN/gui/build.md +110 -16
- package/doc/zh-CN/gui/canvas.md +1 -1
- package/doc/zh-CN/gui/dom.md +16 -3
- package/doc/zh-CN/gui/known-issues.md +45 -15
- package/doc/zh-CN/gui/layout.md +23 -6
- package/doc/zh-CN/gui/media.md +11 -6
- package/doc/zh-CN/gui/rendering.md +84 -26
- package/doc/zh-CN/gui/runtime.md +3 -0
- package/doc/zh-CN/gui/webgl.md +3 -3
- package/doc/zh-CN/gui.md +92 -41
- package/doc/zh-CN/implemented/cli.md +2 -0
- package/doc/zh-CN/implemented/extensions.md +9 -3
- package/doc/zh-CN/npm-package.md +4 -3
- package/package.json +7 -7
- package/runtime/ext_gui/animation_values.cpp +425 -0
- package/runtime/ext_gui/animation_values.h +64 -0
- package/runtime/ext_gui/browser.cpp +22 -15
- package/runtime/ext_gui/browser_loop.cpp +13 -1
- package/runtime/ext_gui/canvas.h +1 -1
- package/runtime/ext_gui/canvas_raster.cpp +1 -1
- package/runtime/ext_gui/canvas_text.cpp +1 -1
- package/runtime/ext_gui/css.cpp +172 -21
- package/runtime/ext_gui/css.h +75 -4
- package/runtime/ext_gui/css_match.cpp +4 -0
- package/runtime/ext_gui/css_sheet.cpp +218 -2
- package/runtime/ext_gui/document.cpp +42 -192
- package/runtime/ext_gui/document.h +25 -12
- package/runtime/ext_gui/document_animation.cpp +428 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +15 -8
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +44 -20
- package/runtime/ext_gui/dom_api_canvas_image.cpp +3 -1
- package/runtime/ext_gui/dom_api_node_read.cpp +10 -0
- package/runtime/ext_gui/dom_api_offscreen.cpp +3 -1
- package/runtime/ext_gui/dom_api_style.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl_internal.h +4 -0
- package/runtime/ext_gui/dom_api_webgl_source.cpp +5 -2
- package/runtime/ext_gui/effect_values.cpp +245 -21
- package/runtime/ext_gui/gpu_bridge.c +28 -0
- package/runtime/ext_gui/gpu_feature.cpp +30 -0
- package/runtime/ext_gui/gpu_shader.cpp +22 -0
- package/runtime/ext_gui/gpu_shader_api.h +50 -0
- package/runtime/ext_gui/gradient_values.cpp +24 -0
- package/runtime/ext_gui/grid_values.cpp +23 -0
- package/runtime/ext_gui/gui.cpp +6 -37
- package/runtime/ext_gui/gui_canvas.cpp +14 -6
- package/runtime/ext_gui/gui_cursor.cpp +50 -0
- package/runtime/ext_gui/gui_engine.h +1 -18
- package/runtime/ext_gui/gui_events.cpp +19 -6
- package/runtime/ext_gui/gui_internal.h +3 -0
- package/runtime/ext_gui/gui_webgl.cpp +25 -10
- package/runtime/ext_gui/image_api.cpp +18 -0
- package/runtime/ext_gui/image_api.h +43 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +20 -11
- package/runtime/ext_gui/image_bridge.c +22 -0
- package/runtime/ext_gui/image_feature.cpp +107 -0
- package/runtime/ext_gui/inline_svg.cpp +95 -8
- package/runtime/ext_gui/inline_svg.h +5 -1
- package/runtime/ext_gui/layout.cpp +15 -9
- package/runtime/ext_gui/layout.h +8 -2
- package/runtime/ext_gui/layout_flex.cpp +134 -29
- package/runtime/ext_gui/layout_flow.cpp +58 -7
- package/runtime/ext_gui/layout_flow_internal.h +39 -4
- package/runtime/ext_gui/layout_grid.cpp +31 -0
- package/runtime/ext_gui/layout_inline.cpp +26 -2
- package/runtime/ext_gui/layout_vertical.cpp +196 -0
- package/runtime/ext_gui/media.cpp +4 -2
- package/runtime/ext_gui/media.h +3 -3
- package/runtime/ext_gui/media_api.h +7 -6
- package/runtime/ext_gui/paint.cpp +67 -9
- package/runtime/ext_gui/paint.h +61 -8
- package/runtime/ext_gui/paint_backdrop.cpp +211 -0
- package/runtime/ext_gui/paint_background.cpp +175 -97
- package/runtime/ext_gui/paint_effects.cpp +12 -6
- package/runtime/ext_gui/paint_internal.h +27 -0
- package/runtime/ext_gui/paint_outline.cpp +44 -0
- package/runtime/ext_gui/paint_shadow.cpp +368 -0
- package/runtime/ext_gui/renderer.cpp +15 -7
- package/runtime/ext_gui/renderer.h +11 -2
- package/runtime/ext_gui/renderer_backdrop.cpp +374 -0
- package/runtime/ext_gui/renderer_bitmap.cpp +82 -0
- package/runtime/ext_gui/renderer_gradient.cpp +51 -17
- package/runtime/ext_gui/renderer_image.cpp +19 -7
- package/runtime/ext_gui/renderer_internal.h +21 -0
- package/runtime/ext_gui/renderer_layer.cpp +37 -6
- package/runtime/ext_gui/renderer_text.cpp +2 -1
- package/runtime/ext_gui/stb_truetype.h +5077 -0
- package/runtime/ext_gui/style.cpp +62 -8
- package/runtime/ext_gui/style.h +111 -4
- package/runtime/ext_gui/style_cascade.cpp +83 -0
- package/runtime/ext_gui/style_internal.h +13 -1
- package/runtime/ext_gui/style_length.cpp +92 -0
- package/runtime/ext_gui/style_print.cpp +83 -2
- package/runtime/ext_gui/style_svg.cpp +40 -0
- package/runtime/ext_gui/style_text.cpp +302 -0
- package/runtime/ext_gui/style_ui.cpp +150 -0
- package/runtime/ext_gui/style_values.cpp +76 -62
- package/runtime/ext_gui/style_values_internal.h +23 -0
- package/runtime/ext_gui/text.cpp +27 -499
- package/runtime/ext_gui/text.h +18 -9
- package/runtime/ext_gui/text_api.h +45 -0
- package/runtime/ext_gui/text_bridge.c +23 -0
- package/runtime/ext_gui/text_cache.cpp +12 -3
- package/runtime/ext_gui/text_font_db.cpp +427 -0
- package/runtime/ext_gui/text_font_paths.cpp +250 -0
- package/runtime/ext_gui/text_font_paths.h +39 -0
- package/runtime/ext_gui/text_font_sfnt.cpp +396 -0
- package/runtime/ext_gui/text_font_sfnt.h +44 -0
- package/runtime/ext_gui/text_fonts.cpp +348 -0
- package/runtime/ext_gui/text_fonts.h +78 -0
- package/runtime/ext_gui/text_fonts_internal.h +77 -0
- package/runtime/ext_gui/text_glyph_cache.cpp +2 -2
- package/runtime/ext_gui/text_hb.cpp +438 -0
- package/runtime/ext_gui/text_stb.cpp +369 -0
- package/runtime/ext_gui/transform.cpp +107 -9
- package/runtime/ext_gui/transform.h +5 -0
- package/runtime/ext_gui/webgl_api.cpp +19 -0
- package/runtime/ext_gui/webgl_api.h +53 -0
- package/runtime/ext_gui/webgl_bridge.c +25 -0
- package/runtime/ext_gui/webgl_draw_setup.cpp +42 -1
- package/runtime/ext_gui/webgl_feature.cpp +82 -0
- package/runtime/ext_gui/webgl_feature.h +28 -0
- package/runtime/ext_gui/webgl_msl.cpp +41 -0
- package/runtime/ext_gui/webgl_msl.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +40 -32
- package/runtime/ext_gui/window.cpp +7 -7
- package/runtime/ext_media/decode_audio.cpp +1 -1
- package/runtime/ext_media/media.cpp +1 -1
- package/runtime/ext_media/media_bridge.c +7 -7
- package/scripts/build-gui.ts +97 -98
- package/scripts/check-file-length.ts +1 -0
- package/scripts/gui-build-options.ts +122 -0
- package/src/cli/extensions.ts +72 -0
- package/src/cli/help.ts +3 -1
- package/src/cli/hints.ts +9 -3
- package/src/cli/main.ts +21 -27
- package/src/diagnostics/diagnostic.ts +2 -0
- package/src/driver/build-key.ts +3 -0
- package/src/driver/compiler.ts +63 -8
- package/src/driver/config.ts +6 -0
- package/src/driver/link-features.ts +163 -0
- package/src/driver/options.ts +10 -0
- package/src/driver/runtime-objects.ts +26 -1
- package/src/driver/usage.ts +376 -0
- package/src/driver/version.ts +1 -1
- package/src/extensions/catalog.ts +1 -2
- package/src/extensions/gui/features.ts +166 -0
- package/src/extensions/gui/index.ts +10 -4
- package/src/extensions/link-feature.ts +72 -0
- package/src/extensions/registry.ts +45 -4
- package/src/index.ts +3 -2
- package/dist/src/extensions/media/index.d.ts +0 -28
- package/dist/src/extensions/media/index.js +0 -59
- package/dist/src/extensions/media/index.js.map +0 -1
- package/dist/tests/extensions/media.test.js +0 -63
- package/dist/tests/extensions/media.test.js.map +0 -1
- package/src/extensions/media/index.ts +0 -65
- /package/dist/tests/{extensions/media.test.d.ts → driver/link-features.test.d.ts} +0 -0
|
@@ -142,6 +142,42 @@ int type_size(int type) {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/** Content hash of the vertex input state a pipeline bakes in.
|
|
146
|
+
*
|
|
147
|
+
* `WebGLDrawKey` carries `attribs_version_`/`framebuffer_version_`, which are
|
|
148
|
+
* *monotonic counters*: every VAO bind and every framebuffer switch bumps them.
|
|
149
|
+
* A page that binds several VAOs per frame (three.js does, once per geometry)
|
|
150
|
+
* therefore produced a new pipeline key for every draw on every frame, and the
|
|
151
|
+
* per-program pipeline cache never hit — measured at ~250
|
|
152
|
+
* `SDL_CreateGPUGraphicsPipeline` calls per frame, several milliseconds of the
|
|
153
|
+
* frame on its own, with a cache that grew by that many entries every frame.
|
|
154
|
+
* The pipeline only depends on the layout itself, so key it by the layout's
|
|
155
|
+
* content: the same layout stays cached across frames and is shared by every
|
|
156
|
+
* object that uses it. */
|
|
157
|
+
uint64_t vertex_layout_hash(const std::vector<SDL_GPUVertexAttribute> &attributes,
|
|
158
|
+
const std::vector<SDL_GPUVertexBufferDescription> &buffers) {
|
|
159
|
+
uint64_t hash = 1469598103934665603ull;
|
|
160
|
+
auto mix = [&hash](uint64_t value) {
|
|
161
|
+
hash ^= value;
|
|
162
|
+
hash *= 1099511628211ull;
|
|
163
|
+
hash ^= hash >> 29;
|
|
164
|
+
};
|
|
165
|
+
mix(attributes.size());
|
|
166
|
+
for (const SDL_GPUVertexAttribute &attribute : attributes) {
|
|
167
|
+
mix(attribute.location);
|
|
168
|
+
mix(attribute.buffer_slot);
|
|
169
|
+
mix((uint64_t)(uint32_t)attribute.format);
|
|
170
|
+
mix(attribute.offset);
|
|
171
|
+
}
|
|
172
|
+
mix(buffers.size());
|
|
173
|
+
for (const SDL_GPUVertexBufferDescription &buffer : buffers) {
|
|
174
|
+
mix(buffer.slot);
|
|
175
|
+
mix(buffer.pitch);
|
|
176
|
+
mix((uint64_t)(uint32_t)buffer.input_rate);
|
|
177
|
+
}
|
|
178
|
+
return hash;
|
|
179
|
+
}
|
|
180
|
+
|
|
145
181
|
} // namespace
|
|
146
182
|
|
|
147
183
|
void WebGLContext::draw_state_hash(uint64_t *first, uint64_t *second) const {
|
|
@@ -298,10 +334,15 @@ const WebGLDrawSetup *WebGLContext::prepare_draw(const WebGLDrawKey &key) {
|
|
|
298
334
|
/* The pipeline depends on the vertex layout and fixed-function state, not on
|
|
299
335
|
* which GPU buffer happens to hold the data (a buffer can be recreated after
|
|
300
336
|
* a grow) nor on the element-buffer binding. Normalise those fields out so a
|
|
301
|
-
* dynamic buffer does not create a fresh pipeline.
|
|
337
|
+
* dynamic buffer does not create a fresh pipeline. The monotonic version
|
|
338
|
+
* counters are replaced by the layout's content hash (and zero): they change
|
|
339
|
+
* on every VAO bind / framebuffer switch without changing the pipeline, so
|
|
340
|
+
* keying on them re-created every pipeline once per frame. */
|
|
302
341
|
WebGLDrawKey pipeline_key = key;
|
|
303
342
|
pipeline_key.gpu_version = 0;
|
|
304
343
|
pipeline_key.element_buffer = 0;
|
|
344
|
+
pipeline_key.attribs_version = vertex_layout_hash(setup.attributes, setup.buffers);
|
|
345
|
+
pipeline_key.framebuffer_version = 0;
|
|
305
346
|
auto cached = program_->pipeline_cache.find(pipeline_key);
|
|
306
347
|
if (cached != program_->pipeline_cache.end()) {
|
|
307
348
|
setup.pipeline = cached->second;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — `webgl` link feature implementation.
|
|
3
|
+
*
|
|
4
|
+
* This translation unit is the only core-side place that references the WebGL
|
|
5
|
+
* context and DOM bindings. It is pulled out of `gui.a` only when
|
|
6
|
+
* `webgl_bridge.c` (the feature's C registration object) is linked, and installs
|
|
7
|
+
* `XtWebglApi` for the rest of the engine. Without it the table is null, so a
|
|
8
|
+
* page that never asks for WebGL does not link any `webgl_*`/`dom_api_webgl*`
|
|
9
|
+
* member.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#include "webgl_feature.h"
|
|
13
|
+
|
|
14
|
+
#include "webgl_api.h"
|
|
15
|
+
#include "dom_api_internal.h"
|
|
16
|
+
|
|
17
|
+
namespace {
|
|
18
|
+
|
|
19
|
+
void *get(XtGuiWindow *win, const void *node, bool webgl2) {
|
|
20
|
+
return xt_gui_webgl_get(win, static_cast<const xtgui::Node *>(node), webgl2);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
void *find(XtGuiWindow *win, const void *node) {
|
|
24
|
+
return xt_gui_webgl_find(win, static_cast<const xtgui::Node *>(node));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
void forget(XtGuiWindow *win, const void *node) {
|
|
28
|
+
xt_gui_webgl_forget(win, static_cast<const xtgui::Node *>(node));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
void shutdown(XtGuiWindow *win) { xt_gui_webgl_shutdown(win); }
|
|
32
|
+
|
|
33
|
+
bool submit_all() { return xt_gui_webgl_submit_all(); }
|
|
34
|
+
|
|
35
|
+
void info(void *context, float *width, float *height, uint64_t *id) {
|
|
36
|
+
auto *webgl = static_cast<xtgui::WebGLContext *>(context);
|
|
37
|
+
*width = (float)webgl->width();
|
|
38
|
+
*height = (float)webgl->height();
|
|
39
|
+
*id = webgl->id();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
void resize(void *context, int width, int height) {
|
|
43
|
+
static_cast<xtgui::WebGLContext *>(context)->resize(width, height);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
bool read_pixels(void *context, int x, int y, int width, int height, unsigned char *out) {
|
|
47
|
+
return static_cast<xtgui::WebGLContext *>(context)->read_pixels(x, y, width, height, out);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
xt_value handle(xt_value self, void *context) {
|
|
51
|
+
return domapi::webgl_context_handle(self, static_cast<xtgui::WebGLContext *>(context));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
xt_value proto(bool webgl2) {
|
|
55
|
+
return webgl2 ? domapi::webgl2_proto() : domapi::webgl_proto();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
xt_value object_proto(const char *kind) { return domapi::webgl_object_proto(kind); }
|
|
59
|
+
|
|
60
|
+
void *color_texture(uint64_t id) {
|
|
61
|
+
xtgui::WebGLContext *context = xtgui::xt_webgl_by_id(id);
|
|
62
|
+
return context != nullptr ? context->color_texture() : nullptr;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const XtWebglApi kWebglApi = {
|
|
66
|
+
get,
|
|
67
|
+
find,
|
|
68
|
+
forget,
|
|
69
|
+
shutdown,
|
|
70
|
+
submit_all,
|
|
71
|
+
info,
|
|
72
|
+
resize,
|
|
73
|
+
read_pixels,
|
|
74
|
+
handle,
|
|
75
|
+
proto,
|
|
76
|
+
object_proto,
|
|
77
|
+
color_texture,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
} // namespace
|
|
81
|
+
|
|
82
|
+
extern "C" void xt_webgl_feature_register(void) { xt_webgl_api_install(&kWebglApi); }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — WebGL context lifetime, implemented by the optional
|
|
3
|
+
* `webgl` feature.
|
|
4
|
+
*
|
|
5
|
+
* These functions are only referenced by `webgl_feature.cpp`, which installs
|
|
6
|
+
* them in `XtWebglApi`; no core translation unit calls them directly. The header
|
|
7
|
+
* is therefore only included by the feature's own translation units.
|
|
8
|
+
*/
|
|
9
|
+
#ifndef XT_GUI_WEBGL_FEATURE_H
|
|
10
|
+
#define XT_GUI_WEBGL_FEATURE_H
|
|
11
|
+
|
|
12
|
+
#include "gui_engine.h"
|
|
13
|
+
#include "webgl.h"
|
|
14
|
+
|
|
15
|
+
/** The WebGL context of a `<canvas>`, creating it on first use. `webgl2`
|
|
16
|
+
* selects the WebGL 2 API/prototype; a canvas keeps the first context kind it
|
|
17
|
+
* asked for. */
|
|
18
|
+
xtgui::WebGLContext *xt_gui_webgl_get(XtGuiWindow *win, const xtgui::Node *node, bool webgl2);
|
|
19
|
+
/** The existing WebGL context of `node`, or null (no side effects). */
|
|
20
|
+
xtgui::WebGLContext *xt_gui_webgl_find(XtGuiWindow *win, const xtgui::Node *node);
|
|
21
|
+
/** Drop a node's WebGL context (called when its handle is forgotten). */
|
|
22
|
+
void xt_gui_webgl_forget(XtGuiWindow *win, const xtgui::Node *node);
|
|
23
|
+
/** Release every WebGL context of `win`. */
|
|
24
|
+
void xt_gui_webgl_shutdown(XtGuiWindow *win);
|
|
25
|
+
/** Submit every live context's queued commands; true when any exists. */
|
|
26
|
+
bool xt_gui_webgl_submit_all();
|
|
27
|
+
|
|
28
|
+
#endif /* XT_GUI_WEBGL_FEATURE_H */
|
|
@@ -6,10 +6,19 @@
|
|
|
6
6
|
* share one GLSL front end: the Vulkan path hands the SPIR-V to SDL_GPU
|
|
7
7
|
* directly, the Metal path cross-compiles it to MSL text that SDL_GPU's Metal
|
|
8
8
|
* backend compiles at run time.
|
|
9
|
+
*
|
|
10
|
+
* Metal is the only SDL_GPU backend that consumes MSL, so `scripts/build-gui.ts`
|
|
11
|
+
* merges SPIRV-Cross into `gui.a` on macOS only; the rest of this file is a stub
|
|
12
|
+
* (the `#else` branch) so no caller needs an `#if`. Including the archive
|
|
13
|
+
* everywhere would instead add ~2.5 MiB of code no driver can ever ask for.
|
|
9
14
|
*/
|
|
10
15
|
|
|
11
16
|
#include "webgl_msl.h"
|
|
12
17
|
|
|
18
|
+
#if defined(__APPLE__)
|
|
19
|
+
|
|
20
|
+
#include <cstdio>
|
|
21
|
+
#include <cstdlib>
|
|
13
22
|
#include <exception>
|
|
14
23
|
|
|
15
24
|
#include <spirv_msl.hpp>
|
|
@@ -42,6 +51,13 @@ bool cross_compile_msl(const std::vector<uint32_t> &spirv, bool fragment,
|
|
|
42
51
|
options.msl_version = spirv_cross::CompilerMSL::Options::make_msl_version(2, 0);
|
|
43
52
|
compiler.set_msl_options(options);
|
|
44
53
|
*source = compiler.compile();
|
|
54
|
+
/* The GLSL dump (`XT_WEBGL_DUMP_GLSL`) stops at the SPIR-V front end; this
|
|
55
|
+
* one shows what SPIRV-Cross handed the Metal backend, which is where a
|
|
56
|
+
* backend-only sampling difference (depth/comparison samplers) shows up. */
|
|
57
|
+
if (getenv("XT_WEBGL_DUMP_MSL") != nullptr) {
|
|
58
|
+
fprintf(stderr, "--- MSL %s ---\n%s\n---\n", fragment ? "fragment" : "vertex",
|
|
59
|
+
source->c_str());
|
|
60
|
+
}
|
|
45
61
|
*entry = compiler.get_cleansed_entry_point_name(
|
|
46
62
|
"main", fragment ? spv::ExecutionModelFragment : spv::ExecutionModelVertex);
|
|
47
63
|
if (entry->empty()) {
|
|
@@ -64,3 +80,28 @@ bool cross_compile_msl(const std::vector<uint32_t> &spirv, bool fragment,
|
|
|
64
80
|
}
|
|
65
81
|
|
|
66
82
|
} // namespace xtgui
|
|
83
|
+
|
|
84
|
+
#else /* !__APPLE__ */
|
|
85
|
+
|
|
86
|
+
namespace xtgui {
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Non-Metal builds carry no SPIRV-Cross, so there is nothing to translate with.
|
|
90
|
+
*
|
|
91
|
+
* No SDL_GPU backend outside Apple platforms reports MSL, so no driver can reach
|
|
92
|
+
* this; it exists so the callers keep one unconditional branch and a device that
|
|
93
|
+
* ever did advertise MSL fails with an actionable log instead of a wrong shader.
|
|
94
|
+
*/
|
|
95
|
+
bool cross_compile_msl(const std::vector<uint32_t> &spirv, bool fragment,
|
|
96
|
+
std::string *source, std::string *entry, std::string *log) {
|
|
97
|
+
(void)spirv;
|
|
98
|
+
(void)fragment;
|
|
99
|
+
source->clear();
|
|
100
|
+
entry->clear();
|
|
101
|
+
*log = "this build has no MSL backend (SPIRV-Cross is macOS-only)";
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
} // namespace xtgui
|
|
106
|
+
|
|
107
|
+
#endif /* __APPLE__ */
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
* cross-compiles it to MSL while keeping the binding indices the rewriter
|
|
9
9
|
* assigned — one std140 block at buffer 0 and stage-local samplers at
|
|
10
10
|
* binding N, which is exactly the slot layout SDL_GPU's Metal backend binds.
|
|
11
|
+
*
|
|
12
|
+
* Only a macOS build links SPIRV-Cross (`scripts/build-gui.ts` skips the
|
|
13
|
+
* archive elsewhere); on every other platform the same function is a stub that
|
|
14
|
+
* reports the missing backend. No driver outside Apple platforms consumes MSL,
|
|
15
|
+
* so the stub is unreachable — keeping the declaration unconditional just means
|
|
16
|
+
* the callers need no `#if`.
|
|
11
17
|
*/
|
|
12
18
|
#ifndef XT_GUI_WEBGL_MSL_H
|
|
13
19
|
#define XT_GUI_WEBGL_MSL_H
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* xbintsc GUI engine — WebGL shaders, programs, linking and uniforms.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* and reflects the std140 block out of the SPIR-V. The SDL_GPU shader then
|
|
8
|
-
* takes whichever form the device accepts: the SPIR-V module itself on Vulkan,
|
|
9
|
-
* or the same module cross-compiled to MSL by SPIRV-Cross on Metal.
|
|
4
|
+
* Translation/compilation goes through the optional `gpu` table (glslang);
|
|
5
|
+
* `linkProgram` shares attribute/varying locations between the stages and
|
|
6
|
+
* reflects the std140 block from the SPIR-V.
|
|
10
7
|
*/
|
|
11
8
|
|
|
12
9
|
#include "webgl.h"
|
|
@@ -16,15 +13,13 @@
|
|
|
16
13
|
#include <cstring>
|
|
17
14
|
|
|
18
15
|
#include "gui_internal.h"
|
|
19
|
-
#include "
|
|
16
|
+
#include "gpu_shader_api.h"
|
|
20
17
|
#include "webgl_program_internal.h"
|
|
21
18
|
|
|
22
19
|
namespace xtgui {
|
|
23
20
|
namespace {
|
|
24
|
-
|
|
25
21
|
using webgl_detail::gl_type_of;
|
|
26
22
|
using webgl_detail::location_slots;
|
|
27
|
-
|
|
28
23
|
/** Merge uniforms declared by both stages, in declaration order. */
|
|
29
24
|
bool merge_uniforms(const GlslShaderInfo &vs, const GlslShaderInfo &fs,
|
|
30
25
|
std::vector<GlslUniformDecl> *out, std::string *error) {
|
|
@@ -80,17 +75,17 @@ struct StageCode {
|
|
|
80
75
|
std::string text;
|
|
81
76
|
};
|
|
82
77
|
|
|
83
|
-
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* Metal has no SPIR-V loader, so the module is cross-compiled to MSL; Vulkan
|
|
87
|
-
* takes the SPIR-V directly. `code` points into `text` for MSL, so the caller
|
|
88
|
-
* must keep the `StageCode` alive until `SDL_CreateGPUShader` has run.
|
|
89
|
-
*/
|
|
78
|
+
/** Turn a SPIR-V stage into what the device consumes (SPIR-V or MSL text);
|
|
79
|
+
* `code` points into `text` for MSL, so `stage` must outlive the SDL shader. */
|
|
90
80
|
bool prepare_stage(const std::vector<uint32_t> &spirv, bool fragment,
|
|
91
81
|
SDL_GPUShaderFormat formats, StageCode *stage, std::string *log) {
|
|
92
82
|
if ((formats & SDL_GPU_SHADERFORMAT_MSL) != 0) {
|
|
93
|
-
|
|
83
|
+
const GpuShaderApi *api = gpu_shader_api();
|
|
84
|
+
if (api == nullptr) {
|
|
85
|
+
*log = "shader translation was not linked (the 'gpu' link feature is inactive)";
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
if (!api->cross_compile_msl(spirv, fragment, &stage->text, &stage->entry, log)) return false;
|
|
94
89
|
stage->format = SDL_GPU_SHADERFORMAT_MSL;
|
|
95
90
|
stage->code = (const Uint8 *)stage->text.data();
|
|
96
91
|
stage->code_size = stage->text.size();
|
|
@@ -146,12 +141,18 @@ bool WebGLContext::compile_shader(uint32_t id) {
|
|
|
146
141
|
WebGLShader *record = shader(id);
|
|
147
142
|
if (record == nullptr) return false;
|
|
148
143
|
const bool fragment = record->type == GL_FRAGMENT_SHADER;
|
|
144
|
+
const GpuShaderApi *api = gpu_shader_api();
|
|
145
|
+
if (api == nullptr) {
|
|
146
|
+
record->log = "shader translation was not linked (the 'gpu' link feature is inactive)";
|
|
147
|
+
record->compiled = false;
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
149
150
|
/* Expand three.js's pragma-marked light loops first: a sampler-array index
|
|
150
151
|
* must be constant in Vulkan GLSL, and the expansion is the only place that
|
|
151
152
|
* knows the loop bounds. Scanning and rewriting then share one text. */
|
|
152
|
-
const std::string prepared = unroll_glsl_pragmas(record->source);
|
|
153
|
+
const std::string prepared = api->unroll_glsl_pragmas(record->source);
|
|
153
154
|
GlslShaderInfo info;
|
|
154
|
-
scan_glsl(prepared, fragment, &info);
|
|
155
|
+
api->scan_glsl(prepared, fragment, &info);
|
|
155
156
|
if (!info.unsupported.empty()) {
|
|
156
157
|
record->log = info.unsupported;
|
|
157
158
|
record->compiled = false;
|
|
@@ -162,9 +163,9 @@ bool WebGLContext::compile_shader(uint32_t id) {
|
|
|
162
163
|
assign_locations(info.varyings, {}, &layout.varyings);
|
|
163
164
|
assign_locations(info.samplers, {}, &layout.samplers);
|
|
164
165
|
layout.block_members = info.uniforms;
|
|
165
|
-
const std::string source = rewrite_glsl(prepared, fragment, layout, info);
|
|
166
|
+
const std::string source = api->rewrite_glsl(prepared, fragment, layout, info);
|
|
166
167
|
std::vector<uint32_t> spirv;
|
|
167
|
-
record->compiled = compile_glsl(source, fragment, &spirv, &record->log);
|
|
168
|
+
record->compiled = api->compile_glsl(source, fragment, &spirv, &record->log);
|
|
168
169
|
return record->compiled;
|
|
169
170
|
}
|
|
170
171
|
|
|
@@ -268,12 +269,19 @@ bool WebGLContext::link_program(uint32_t id) {
|
|
|
268
269
|
return false;
|
|
269
270
|
}
|
|
270
271
|
|
|
271
|
-
const
|
|
272
|
-
|
|
272
|
+
const GpuShaderApi *api = gpu_shader_api();
|
|
273
|
+
if (api == nullptr) {
|
|
274
|
+
record->log = "shader translation was not linked (the 'gpu' link feature is inactive)";
|
|
275
|
+
record->linked = false;
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const std::string prepared_vertex = api->unroll_glsl_pragmas(vertex->source);
|
|
280
|
+
const std::string prepared_fragment = api->unroll_glsl_pragmas(fragment->source);
|
|
273
281
|
GlslShaderInfo vs_info;
|
|
274
282
|
GlslShaderInfo fs_info;
|
|
275
|
-
scan_glsl(prepared_vertex, false, &vs_info);
|
|
276
|
-
scan_glsl(prepared_fragment, true, &fs_info);
|
|
283
|
+
api->scan_glsl(prepared_vertex, false, &vs_info);
|
|
284
|
+
api->scan_glsl(prepared_fragment, true, &fs_info);
|
|
277
285
|
if (!vs_info.unsupported.empty() || !fs_info.unsupported.empty()) {
|
|
278
286
|
record->log = vs_info.unsupported.empty() ? fs_info.unsupported : vs_info.unsupported;
|
|
279
287
|
record->linked = false;
|
|
@@ -342,17 +350,17 @@ bool WebGLContext::link_program(uint32_t id) {
|
|
|
342
350
|
}
|
|
343
351
|
fs_layout.varyings = vs_layout.varyings;
|
|
344
352
|
|
|
345
|
-
const std::string vs_source = rewrite_glsl(prepared_vertex, false, vs_layout, vs_info);
|
|
346
|
-
const std::string fs_source = rewrite_glsl(prepared_fragment, true, fs_layout, fs_info);
|
|
353
|
+
const std::string vs_source = api->rewrite_glsl(prepared_vertex, false, vs_layout, vs_info);
|
|
354
|
+
const std::string fs_source = api->rewrite_glsl(prepared_fragment, true, fs_layout, fs_info);
|
|
347
355
|
std::vector<uint32_t> vs_spirv;
|
|
348
356
|
std::vector<uint32_t> fs_spirv;
|
|
349
357
|
std::string log;
|
|
350
|
-
if (!compile_glsl(vs_source, false, &vs_spirv, &log)) {
|
|
358
|
+
if (!api->compile_glsl(vs_source, false, &vs_spirv, &log)) {
|
|
351
359
|
record->log = "vertex shader:\n" + log;
|
|
352
360
|
record->linked = false;
|
|
353
361
|
return false;
|
|
354
362
|
}
|
|
355
|
-
if (!compile_glsl(fs_source, true, &fs_spirv, &log)) {
|
|
363
|
+
if (!api->compile_glsl(fs_source, true, &fs_spirv, &log)) {
|
|
356
364
|
record->log = "fragment shader:\n" + log;
|
|
357
365
|
record->linked = false;
|
|
358
366
|
return false;
|
|
@@ -360,9 +368,9 @@ bool WebGLContext::link_program(uint32_t id) {
|
|
|
360
368
|
|
|
361
369
|
/* Reflect the std140 block (members survive even when unused). */
|
|
362
370
|
std::vector<GlslBlockMember> members;
|
|
363
|
-
reflect_uniform_block(vs_spirv, &members);
|
|
371
|
+
api->reflect_uniform_block(vs_spirv, &members);
|
|
364
372
|
std::vector<GlslBlockMember> fragment_members;
|
|
365
|
-
reflect_uniform_block(fs_spirv, &fragment_members);
|
|
373
|
+
api->reflect_uniform_block(fs_spirv, &fragment_members);
|
|
366
374
|
/* Keep members declared by either stage: a uniform block may only be read by
|
|
367
375
|
* the fragment shader while the vertex stage contributes other uniforms. */
|
|
368
376
|
for (const GlslBlockMember &member : fragment_members) {
|
|
@@ -380,7 +388,7 @@ bool WebGLContext::link_program(uint32_t id) {
|
|
|
380
388
|
* declarations, so the source scan over-reports; use the reflection and keep
|
|
381
389
|
* the declaration order from the source for stable `getActiveAttrib` order. */
|
|
382
390
|
std::unordered_map<std::string, int> active_attributes;
|
|
383
|
-
reflect_attributes(vs_spirv, &active_attributes);
|
|
391
|
+
api->reflect_attributes(vs_spirv, &active_attributes);
|
|
384
392
|
if (!active_attributes.empty()) {
|
|
385
393
|
std::vector<std::pair<int, GlslUniformDecl>> ordered;
|
|
386
394
|
for (const GlslUniformDecl &decl : vs_info.attributes) {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
#include <algorithm>
|
|
15
15
|
|
|
16
|
-
#include "
|
|
16
|
+
#include "image_api.h"
|
|
17
17
|
#include "paint.h"
|
|
18
18
|
#include "perf.h"
|
|
19
19
|
#include "text.h"
|
|
@@ -252,17 +252,17 @@ static xt_value win_inline_svg(xt_value self, xt_value env, int32_t argc, xt_val
|
|
|
252
252
|
const char *selector = xt_string_data(selectorValue);
|
|
253
253
|
if (selector == nullptr) return XT_UNDEFINED;
|
|
254
254
|
const xtgui::Node *node = win->document->querySelector(selector);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
int height = 0;
|
|
259
|
-
|
|
255
|
+
const XtImageApi *images = xt_image_api();
|
|
256
|
+
if (images == nullptr || !images->inline_is_root(node)) return XT_UNDEFINED;
|
|
257
|
+
std::string markup = images->inline_serialize(node, &win->document->styles());
|
|
258
|
+
int width = 0, height = 0;
|
|
259
|
+
images->svg_markup_size(markup, &width, &height);
|
|
260
260
|
xt_value object = xt_object_new();
|
|
261
261
|
xt_object_set(object, xt_string_from_cstr("markup"), xt_string_from_cstr(markup.c_str()));
|
|
262
262
|
xt_object_set(object, xt_string_from_cstr("width"), xt_number(width));
|
|
263
263
|
xt_object_set(object, xt_string_from_cstr("height"), xt_number(height));
|
|
264
264
|
xt_object_set(object, xt_string_from_cstr("shapes"),
|
|
265
|
-
xt_number(
|
|
265
|
+
xt_number(images->svg_markup_shapes(markup)));
|
|
266
266
|
return object;
|
|
267
267
|
}
|
|
268
268
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* xbintsc media
|
|
2
|
+
* xbintsc media link feature — in-memory audio decoding.
|
|
3
3
|
*
|
|
4
4
|
* `AudioContext.decodeAudioData` hands over bytes, not a path, so the file
|
|
5
5
|
* oriented `MediaPlayer` cannot be reused. This unit opens the bytes through a
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* xbintsc media
|
|
2
|
+
* xbintsc media link feature — `<video>`/`<audio>` decoding.
|
|
3
3
|
*
|
|
4
4
|
* This translation unit is the only place that knows about FFmpeg. It is
|
|
5
5
|
* compiled into the prebuilt `media.a`/`media.lib` by `scripts/build-media.ts` and linked
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* xbintsc media
|
|
2
|
+
* xbintsc media link feature — registration bridge.
|
|
3
3
|
*
|
|
4
4
|
* The decoders live in `media.a` (`media.lib` with the MSVC ABI on Windows), a
|
|
5
5
|
* prebuilt C++ archive. A static archive is
|
|
6
6
|
* only searched for members that satisfy an undefined symbol, so a backend that
|
|
7
7
|
* merely had a constructor would never be extracted. This tiny C translation
|
|
8
|
-
* unit is compiled and linked *directly*
|
|
9
|
-
* `runtimeSources()` entry): its
|
|
8
|
+
* unit is compiled and linked *directly* — but only when the compiler selects
|
|
9
|
+
* the `media` feature (it is the feature's `runtimeSources()` entry): its
|
|
10
|
+
* constructor references every backend entry
|
|
10
11
|
* point, which pulls the archive member in, and installs the table into the GUI
|
|
11
12
|
* engine before `main` runs.
|
|
12
13
|
*
|
|
13
|
-
* The bridge is intentionally C-only and has no FFmpeg (or SDL) dependency.
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* diagnostic (see `src/extensions/registry.ts`).
|
|
14
|
+
* The bridge is intentionally C-only and has no FFmpeg (or SDL) dependency. The
|
|
15
|
+
* feature belongs to `gui`, so it is only ever compiled with `gui` enabled;
|
|
16
|
+
* `xt_media_install` therefore always resolves.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
#include "../ext_gui/media_api.h"
|