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
|
@@ -11,13 +11,15 @@
|
|
|
11
11
|
[WebGL](./webgl.md)):GLSL ES 着色器由内置 glslang 翻译为 SPIR-V——Vulkan
|
|
12
12
|
后端直接消费,Metal 上再由内置 SPIRV-Cross 交叉编译为 MSL——绘图缓冲
|
|
13
13
|
是一张离屏颜色纹理,页面直接合成而无须读回。WebGL 2 增加了 VAO、实例化、
|
|
14
|
-
整数属性、采样器对象、`texStorage2D
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
整数属性、采样器对象、`texStorage2D`、缓冲拷贝、Uniform 块、立方体/3D/数组
|
|
15
|
+
纹理、浮点/深度/压缩纹理、多渲染目标与 scissor 清除。`blitFramebuffer` 复制
|
|
16
|
+
颜色与深度;transform feedback、MSAA 与模板 blit 尚未实现(SDL_GPU 没有
|
|
17
|
+
transform feedback 阶段,其 Metal 多采样 resolve 不可靠,模板附件也无法采样)。
|
|
17
18
|
在两种格式都不接受的 SDL_GPU 后端(Direct3D 12,需要 DXIL)上两种上下文都为
|
|
18
19
|
`null`。`.js` 资源加载器现在只修补 three.js 的着色器循环展开;
|
|
19
20
|
`WebGLRenderer` 直接运行在真实后端上,不再有 Canvas2D 回退。阴影贴图
|
|
20
|
-
|
|
21
|
+
(比较型 `sampler2DShadow` 采样深度纹理)、立方体贴图/环境贴图与 HDR 渲染目标
|
|
22
|
+
均已支持。
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
- **自动关闭时的偶发崩溃。** 设置 `XT_GUI_AUTOCLOSE_MS` 结束运行时,约五次中有两次会以原生
|
|
@@ -57,6 +59,21 @@
|
|
|
57
59
|
图像内部(这里的 `fill`/`stroke` 是 SVG 表现属性,不是 CSS 属性)。需要这些
|
|
58
60
|
能力的矢量美术必须预先光栅化、用盒子绘制,或限制在受支持的语法内。参见
|
|
59
61
|
[媒体](./media.md#图像m6a)。
|
|
62
|
+
- **每次变更仍是整文档重算。** 一次 DOM 变更会重新计算层叠并重新布局整个文档
|
|
63
|
+
(没有增量子树失效),只影响绘制的变更(例如 hover 颜色)同样会重排。带生成
|
|
64
|
+
内容(`::before`/`::after`)的文档没有特殊处理。各阶段的实测开销由
|
|
65
|
+
`win.stats()`/`XT_GUI_PERF` 暴露,后续优化以它为依据;参见
|
|
66
|
+
[性能](./rendering.md#性能m20)。
|
|
67
|
+
- **绘制调用遵循画家顺序。** 只有当 run 在画家顺序上相邻且 pipeline、裁剪与
|
|
68
|
+
纹理都相同时才会合并,因此"背景与文本逐行交替"的列表每行要付一个图形 run 和
|
|
69
|
+
一个文本 run(见 `win.stats()` 的 `drawCalls`)。要减少绘制调用需要感知重叠的
|
|
70
|
+
合并器(文本可能被后续背景覆盖),目前未实现。实测:200 行基准页发出 400 次
|
|
71
|
+
绘制调用,绘制阶段约耗时 0.4 ms,因此它是"绘制调用占主导"的页面的后续优化项,
|
|
72
|
+
而不是当前的瓶颈。
|
|
73
|
+
- **文本整形缓存有界。** 两代、每代最多 2 MiB 字形 / 8,192 条条目保存
|
|
74
|
+
`(face, text) -> 字形`。不同单词数超过上限的文档在缓存轮换后会重新整形一部分;
|
|
75
|
+
`win.stats()` 的 `textCacheBytes`/`textShapeHits` 能看出它是否成为瓶颈。
|
|
76
|
+
元素自带的 `style="…"` 内联属性在该元素每次重算样式时都会重新解析。
|
|
60
77
|
|
|
61
78
|
## 待决问题
|
|
62
79
|
|
|
@@ -128,3 +128,62 @@ shader 改动,但边缘是硬边(没有解析抗锯齿)。支持两层嵌
|
|
|
128
128
|
- 布局使用这些真实度量进行文本宽度、断行与 `line-height: normal` 计算;
|
|
129
129
|
`measureText`/`fontMetrics` 把它们暴露给测试。
|
|
130
130
|
|
|
131
|
+
## 性能(M20)
|
|
132
|
+
|
|
133
|
+
引擎是保留模式管线:一次 DOM 变更会重算样式、重新布局、重建显示列表并上传
|
|
134
|
+
顶点数组;没有任何变化的帧不产生 CPU 或 GPU 工作。为了让上千个元素的文档保持
|
|
135
|
+
可交互,每个阶段都有预算,并且都可以测量。设置 `XT_GUI_PERF=1` 会逐帧打印一行
|
|
136
|
+
(`XT_GUI_PERF=<N>` 则每 N 帧聚合一行);`win.stats()` 返回同样的计数器,
|
|
137
|
+
`tests/e2e/gui-perf.test.ts` 断言的正是这些计数。
|
|
138
|
+
|
|
139
|
+
- **层叠。** 每次重算样式时,`@media` 前导条件**每条规则只求值一次**(过去是
|
|
140
|
+
每条规则 × 每个节点各解析一次,这是大文档上最大的一笔开销)。样式表里没有
|
|
141
|
+
`::before`/`::after` 规则时完全跳过生成内容;声明候选列表在深度优先遍历中
|
|
142
|
+
复用而不是每个元素分配一次;只有样式表真的包含 `:hover`/`:focus` 规则时,
|
|
143
|
+
这两个状态变化才会触发重算。
|
|
144
|
+
- **文本。** 布局与绘制共享一个有界的整形缓存(`text_cache.cpp`):
|
|
145
|
+
`(face, text) -> 字形 + 前进宽度`。它使用两代、每代最多 2 MiB 字形 / 8,192 条
|
|
146
|
+
条目;某一代写满时丢弃**备用**代并切换过去,因此热路径上没有 LRU 记账。
|
|
147
|
+
一个词只整形一次,之后每次布局和重绘都复用它。主字体查找也按
|
|
148
|
+
(字体族类别,字号)缓存。
|
|
149
|
+
- **帧循环。** 只有文档发生变化(或首帧)时才把媒体/画布表与 DOM 对齐,不再每帧
|
|
150
|
+
遍历整棵树。只有确实发生了事情才提交呈现(present)——DOM 变更、滚动、动画帧、
|
|
151
|
+
过渡、新的视频/画布帧、expose/resize 事件——因此静态页面完全不获取 swapchain、
|
|
152
|
+
也不绘制。expose 是唯一由窗口系统(而非页面)要求的呈现,`exposes` 统计这些帧,
|
|
153
|
+
因此即使窗口服务器很晚才映射窗口,`presents - exposes - deferred` 仍然只是
|
|
154
|
+
文档自身的工作量。取不到交换链图像的帧(GPU 仍持有图像时 SDL 的非阻塞获取会跳过
|
|
155
|
+
该帧,最小化的窗口则完全没有图像)不会丢弃这次失效,而是保留到下一帧再呈现,
|
|
156
|
+
这类呈现计为 `deferred`。调试"漏掉的失效"时可用 `XT_GUI_ALWAYS_PRESENT=1`
|
|
157
|
+
恢复旧的每帧提交。
|
|
158
|
+
- **绘制与上传。** 显示列表和顶点暂存数组挂在窗口中按帧清理,容量得以保留。
|
|
159
|
+
一个脏帧的所有顶点/图集上传共用一个命令缓冲区(一次提交),几何体的暂存
|
|
160
|
+
transfer buffer 被复用(上一帧的拷贝可能仍在飞行中,因此按 cycle 方式映射),
|
|
161
|
+
没有任何子元素带 z-index 时绘制会跳过排序和临时数组。
|
|
162
|
+
- **绘制调用。** 相邻且 pipeline、裁剪和纹理相同的 op 仍会合并为一个 run,
|
|
163
|
+
渲染器现在只在 pipeline / 顶点缓冲 / 裁剪矩形真正变化时才重新绑定。
|
|
164
|
+
`win.stats()` 里的 `drawCalls`/`drawMs` 报告 run 数量与其开销,它们是后续工作
|
|
165
|
+
(感知重叠的合并)的度量依据——在它落地之前,画家顺序要求背景与文本交替的
|
|
166
|
+
run 必须保持独立。
|
|
167
|
+
- **立即模式绘制表面。** `<canvas>` 2D 与 WebGL 由脚本驱动,开销按调用次数计
|
|
168
|
+
而不是按文档变更计;上面的计数器只覆盖保留模式管线。
|
|
169
|
+
`tests/e2e/gui-draw-perf.test.ts` 测量它们:在参考的 Windows x64/Vulkan 机器上,
|
|
170
|
+
一帧 1280×720、包含 5,000 个纯色 `fillRect`、200 条 8 点折线、300 次
|
|
171
|
+
`fillText` 和 200 次 1:1 `drawImage` 的场景从 231ms 降到 158ms(填充 4.3ms、
|
|
172
|
+
描边 151ms、文本 1.4ms、图像 1.6ms);2,000 次带逐次矩阵的 WebGL
|
|
173
|
+
`drawElements` 从 38.6ms 降到 27.5ms,同时每帧打开的渲染 pass 从 2,001 次
|
|
174
|
+
降到 1 次,向 4 MiB 缓冲写入 64 KiB 的 `bufferSubData` 不再重传整个缓冲。
|
|
175
|
+
100×100 的画布局部重绘现在只上传 40 KB,而不是整张 1.2 MB 位图。测试断言的是
|
|
176
|
+
计数器(每帧一次上传、稳定状态不新建管线、只传脏字节),因此墙钟数字仅供
|
|
177
|
+
参考,CI 上的软件 GPU 不会被误判。
|
|
178
|
+
|
|
179
|
+
已知限制:一次变更仍会对**整个**文档重算样式并重新布局(没有增量子树失效),
|
|
180
|
+
只影响绘制的变更(例如 hover 颜色)目前同样会重排;后续工作应以 `win.stats()`
|
|
181
|
+
的数据为依据。元素自带的 `style="…"` 内联属性在该元素每次重算样式时都会重新解析。
|
|
182
|
+
|
|
183
|
+
作为参照,`tests/e2e/gui-perf.test.ts` 会构建一个 200 行的列表(约 1,000 个元素、
|
|
184
|
+
400 个绘制 run)并打印实测数字,例如在 Windows x64/Vulkan 机器上修改一个
|
|
185
|
+
`textContent` 字段得到
|
|
186
|
+
`textFrame=5.2ms restyle=3.6ms layout=1.7ms paint=1.0ms upload=0.8ms draw=0.4ms`。
|
|
187
|
+
绝对值因机器而异;测试断言的是**计数器**(一次重算、一次布局、命中缓存而不是
|
|
188
|
+
重新整形、空闲帧不做任何工作),回归时变化的正是这些。
|
|
189
|
+
|
package/doc/zh-CN/gui/runtime.md
CHANGED
|
@@ -19,11 +19,21 @@ GUI 引擎既可以通过 `xt_loop_set_main` 注册自己的循环,也可以
|
|
|
19
19
|
普通原生调用。每次 tick 它都会:
|
|
20
20
|
|
|
21
21
|
1. 为每个窗口泵送 SDL 窗口/输入事件,
|
|
22
|
-
2.
|
|
22
|
+
2. **只在文档发生变化(或首帧)时**把解码器/画布表与 DOM 对齐,
|
|
23
|
+
3. 当显示列表变化时构建/上传它,并渲染每个打开的窗口(清除通道 + 图形几何
|
|
23
24
|
+ 文本几何),
|
|
24
|
-
|
|
25
|
+
4. 调用 `xt_loop_poll(0)` 与 `xt_drain_microtasks()`,使 socket/定时器与
|
|
25
26
|
`await` 续体持续取得进展,
|
|
26
|
-
|
|
27
|
+
5. 重复直到所有窗口关闭或调用 `quit()`。
|
|
28
|
+
|
|
29
|
+
只有**确实发生了事情**帧才会呈现:DOM 变更、滚动、已排队的动画帧、正在运行的
|
|
30
|
+
过渡、新的视频/画布帧、expose/resize 事件,或首帧。因此静态文档不会获取
|
|
31
|
+
swapchain、也不会绘制,而循环仍在处理事件、定时器与 promise。expose/shown/restore
|
|
32
|
+
事件是唯一由窗口系统(而非文档)要求的呈现,它们在 `win.stats()` 中计为
|
|
33
|
+
`exposes`;取不到交换链图像而被推迟的呈现计为 `deferred`,`presents - exposes -
|
|
34
|
+
deferred` 才是页面自身造成的工作。调试"漏掉的失效"时可用
|
|
35
|
+
`XT_GUI_ALWAYS_PRESENT=1` 恢复旧的每帧提交行为。`XT_GUI_PERF=1` 会打印每一帧
|
|
36
|
+
做了哪些工作(见[性能](./rendering.md#性能m20))。
|
|
27
37
|
|
|
28
38
|
`xt_loop_set_main` 钩子仍保留给希望自行掌控循环的宿主。
|
|
29
39
|
|
package/doc/zh-CN/gui/webgl.md
CHANGED
|
@@ -16,16 +16,31 @@ if (gl == null) {
|
|
|
16
16
|
|
|
17
17
|
2D 上下文把图形光栅化到 CPU 位图再上传为纹理;WebGL 上下文则**在 GPU 上渲染**:顶点变换、光照、纹理采样、深度测试与混合全部在 SDL_GPU 管线中执行(Windows/Linux 上是 Vulkan,macOS 上是 Metal)。页面直接合成该上下文的颜色纹理,因此显示时不需要把像素读回 CPU。
|
|
18
18
|
|
|
19
|
-
同时提供 **WebGL 1.0** 与 **WebGL 2.0**。一个 canvas 会固定为它第一次申请的上下文类型:先调用 `getContext("webgl2")` 之后,`getContext("webgl")` 返回 `null`,反之亦然。WebGL 2
|
|
19
|
+
同时提供 **WebGL 1.0** 与 **WebGL 2.0**。一个 canvas 会固定为它第一次申请的上下文类型:先调用 `getContext("webgl2")` 之后,`getContext("webgl")` 返回 `null`,反之亦然。WebGL 2 上下文拥有自己的 `WebGL2RenderingContext` 原型(其中复制了 WebGL 1 的常量与方法),因此 `gl instanceof WebGL2RenderingContext` 为真,而 `gl instanceof WebGLRenderingContext` 为假,与浏览器一致——three.js 等库正是据此选择 WebGL 2 路径。`gl.constructor.name` 也会报告对应类型名。
|
|
20
20
|
|
|
21
21
|
## 一帧如何到达屏幕
|
|
22
22
|
|
|
23
23
|
- 每个上下文拥有一张离屏 `R8G8B8A8_UNORM` 颜色纹理(绘图缓冲)和一张 `D32_FLOAT` 深度纹理,尺寸取自 canvas 的 `width` / `height` 属性。`canvas.width = …` 会重建它们并丢弃内容,与 DOM 规则一致。
|
|
24
|
-
- 上下文记录到自己的 SDL_GPU 命令缓冲。`clear`/`draw*` 保持一个渲染 pass
|
|
24
|
+
- 上下文记录到自己的 SDL_GPU 命令缓冲。`clear`/`draw*` 保持一个渲染 pass 打开;只有缓冲区/纹理上传或切换 framebuffer 才会结束它,并以 `LOAD` 开始新 pass,因此绘图缓冲在多次绘制之间保留,和 WebGL 一样;没有上传的绘制不会中断 pass。
|
|
25
25
|
- 每帧一次,在页面自己的渲染 pass 之前,引擎提交所有 WebGL 命令缓冲。随后图像管线把颜色纹理当作普通 `PaintImage` 采样,没有 CPU 拷贝。
|
|
26
26
|
- WebGL 原点在左下,SDL_GPU 渲染目标原点在左上,因此帧缓冲按自上而下存储:转换 `viewport`/`scissor`,`readPixels` 再把行翻回去,合成器看到的是正立的纹理。
|
|
27
27
|
- 固定功能状态变化(`blendFunc`、`depthFunc`、`cullFace`、`colorMask` 等)会改变所需的 `SDL_GPUGraphicsPipeline`,因此管线按(程序、顶点布局、状态)惰性创建,并缓存在程序上。
|
|
28
28
|
|
|
29
|
+
## 性能
|
|
30
|
+
|
|
31
|
+
重复绘制命中缓存,而不是每次重建:当前(程序、属性布局、固定功能状态、附件格式)
|
|
32
|
+
对应的管线、顶点布局与缓冲绑定只准备一次并复用(`webgl_draw_setup.cpp`);状态变化时
|
|
33
|
+
缓存未命中并新建管线。固定功能状态被哈希进 128 位键,而不是每次 draw 拼字符串;活动
|
|
34
|
+
属性在链接时解析一次。上传被前移到渲染 pass 之前:没有上传的绘制不会结束 pass,禁用
|
|
35
|
+
的顶点属性读取持久的常量缓冲而不是每次 draw 分配 GPU 缓冲,状态未变的绘制不重复绑定。
|
|
36
|
+
`bufferSubData` 只拷贝写入的字节区间,增长中的缓冲按 2 的幂扩容。
|
|
37
|
+
|
|
38
|
+
`win.stats()` 报告 `webglDraws`、`webglPasses`、`webglPipelineMisses` 与
|
|
39
|
+
`webglBufferUploadBytes`;`tests/e2e/gui-draw-perf.test.ts` 正是用它们固定行为
|
|
40
|
+
(2,000 次绘制只开一个 pass、稳定状态不再创建管线、4 MiB 缓冲只重传 64 KiB 区间)。
|
|
41
|
+
剩余的每次 draw 开销来自后端自身的提交;大量相同对象仍应由应用改用
|
|
42
|
+
`drawElementsInstanced`。
|
|
43
|
+
|
|
29
44
|
## 着色器:GLSL ES 到 SPIR-V(再到 MSL)
|
|
30
45
|
|
|
31
46
|
SDL_GPU 不能在运行时编译 GLSL,且每个后端只消费自己的格式,因此引擎静态链接了两个翻译器:
|
|
@@ -51,12 +66,16 @@ SDL_GPU 不能在运行时编译 GLSL,且每个后端只消费自己的格式
|
|
|
51
66
|
| 非采样器 uniform | 一个 `layout(std140) uniform XtUniforms { … }` 块 |
|
|
52
67
|
| `uniform sampler2D u_tex` | `layout(set = 2, binding = N) uniform sampler2D u_tex`(片元)或 set 0(顶点) |
|
|
53
68
|
| `gl_FragData[0]` | `xt_FragColor` |
|
|
69
|
+
| `gl_FragDepth` / `gl_FragDepthEXT` | 保留(SPIR-V `DepthReplacing`;MSL `[[depth(any)]]`) |
|
|
70
|
+
| `sampler2DShadow` / `samplerCubeShadow` / `sampler2DArrayShadow` | 保留;绑定为 SDL_GPU 比较采样器 |
|
|
54
71
|
| 缺少 `#version` / `#version 100` | `#version 310 es` |
|
|
55
72
|
|
|
56
|
-
|
|
73
|
+
实现限制:结构体 uniform、用户 uniform 块、预处理阶段无法确定长度的 uniform 数组,以及用非常量表达式索引的采样器数组会被拒绝(shader/link info log 会说明)。`#pragma unroll_loop_start` 循环会在改写前展开,因此 three.js 生成的 `sampler2D shadowMap[ NUM_DIR_LIGHT_SHADOWS ]` / `shadowMap[ i ]` 会变成常量索引。`#ifdef` 内的着色器代码可用;非采样器 uniform 声明会被移动到顶层,保证块保持无条件。两个阶段的非采样器 uniform 会合并成同一个块,并在每个阶段各声明一次(顶点 set 1、片元 set 3),与 SDL_GPU 的 Vulkan 描述符布局一致。在 Metal 上同一批声明会变成 `[[buffer(0)]]` 与 `[[texture(N)]]`/`[[sampler(N)]]`,正是 SDL_GPU Metal 后端绑定的槽位。`uniformMatrix4fv` 按列主序写入反射出的偏移;对采样器调用 `uniform1i` 时记录纹理单元。每次绘制都用动态 uniform 缓冲接口推送该块。
|
|
57
74
|
|
|
58
75
|
翻译器的限制:结构体 uniform、用户 uniform 块、预处理后仍无法确定长度的 uniform 数组、采样器数组与采样器类型不匹配的声明会被拒绝(着色器/链接日志会说明)。`#ifdef` 内的代码没问题;非采样器 uniform 声明会被移到外层顶层位置,保证块是无条件的。
|
|
59
76
|
|
|
77
|
+
片元着色器可以写 `gl_FragDepth`:glslang 会把 SPIR-V 标记为 `DepthReplacing`,SPIRV-Cross 会生成 `[[depth(any)]]`,因此两个后端上深度写入都会到达深度附件。比较采样器(`sampler2DShadow`、`samplerCubeShadow`、`sampler2DArrayShadow`)复用 SDL_GPU 采样器对象并设置 `enable_compare`;`TEXTURE_COMPARE_MODE` 与 `TEXTURE_COMPARE_FUNC` 从纹理读取(WebGL 2 也可从绑定的采样器对象读取)。
|
|
78
|
+
|
|
60
79
|
### GLSL ES 3.00(WebGL 2)
|
|
61
80
|
|
|
62
81
|
`#version 300 es` 源码除版本号提升外会被原样接受:顶层 `in`/`out` 声明会变成属性/`varying`,命名片元输出(`out vec4 fragColor;`)会变成 `xt_FragColor` 形式的输出,`texture()` / `textureLod()` 本就与 Vulkan 方言一致。多个片元输出会分配连续 location,但渲染 pass 只有一个颜色目标,因此只写入第一个。GLSL ES 3.00 提供 `gl_VertexID` 与 `gl_InstanceID`,实例化示例正是用它。
|
|
@@ -69,7 +88,7 @@ SDL_GPU 不能在运行时编译 GLSL,且每个后端只消费自己的格式
|
|
|
69
88
|
- **缓冲与顶点属性**:`createBuffer`、`bindBuffer`、`bufferData`、`bufferSubData`、`deleteBuffer`、`getBufferParameter`、`enableVertexAttribArray`、`disableVertexAttribArray`、`vertexAttribPointer`、`vertexAttrib1f`…`4f` / `1fv`…`4fv`、`getVertexAttrib`。`bufferData` 的 `usage` 提示(`STREAM_DRAW`/`STATIC_DRAW`/`DYNAMIC_DRAW`)会被记录,`getBufferParameter(…, BUFFER_USAGE)` 可读回。
|
|
70
89
|
- **绘制**:`drawArrays`、`drawElements`(UNSIGNED_BYTE、UNSIGNED_SHORT、UNSIGNED_INT;`TRIANGLE_FAN` 与 `LINE_LOOP` 会展开为列表)。`POINTS`、`LINES`、`LINE_STRIP`、`TRIANGLES`、`TRIANGLE_STRIP` 映射到对应的 SDL 图元。
|
|
71
90
|
- **纹理**:`createTexture`、`bindTexture`、`activeTexture`、`texParameteri`/`texParameterf`、`getTexParameter`、`texImage2D`(原始像素、`<img>`、`<canvas>`、`ImageData`)、`texSubImage2D`、`generateMipmap`、`deleteTexture`。支持 `UNPACK_FLIP_Y_WEBGL` 与 `UNPACK_PREMULTIPLY_ALPHA_WEBGL`。默认转换为 RGBA8;`RGBA`/`RGB`/`LUMINANCE`/`ALPHA`/`LUMINANCE_ALPHA` 配 `UNSIGNED_BYTE` 可用。浮点纹理(`RGBA32F`、`RGBA16F`、`RGB32F`、`RGB16F`、`RG32F`/`RG16F`、`R32F`/`R16F`,`FLOAT` 或 `HALF_FLOAT` 数据,以及 WebGL 1 的 `OES_texture_float`/`OES_texture_half_float`)映射到 SDL 的 RGBA32F/RGBA16F;深度纹理(`DEPTH_COMPONENT16/24/32F`、`DEPTH_STENCIL`、`DEPTH24_STENCIL8`)映射到 `D32_FLOAT`/`D32_FLOAT_S8_UINT`,可作为采样源或深度附件。压缩纹理通过 `compressedTexImage2D`/`compressedTexSubImage2D` 上传,支持 `WEBGL_compressed_texture_s3tc`(BC1/BC2/BC3)、`WEBGL_compressed_texture_s3tc_srgb` 与 `WEBGL_compressed_texture_astc`;扩展只在设备确实支持对应格式时公布。`texImage2D` 还接受 `<video>` 的最新解码帧与 `createImageBitmap` 产生的 `ImageBitmap`。立方体贴图(`bindTexture(TEXTURE_CUBE_MAP)` + 六个 `texImage2D` 面)与 3D/数组纹理(`texImage3D`/`texStorage3D`)可用对应采样器(`samplerCube`、`sampler3D`、`sampler2DArray`)采样;`texSubImage3D` 可更新 3D/数组纹理的子区域,`framebufferTextureLayer` 可把数组/立方体贴图的指定层作为颜色附件渲染。
|
|
72
|
-
- **Framebuffer**:`createFramebuffer`、`bindFramebuffer`(`FRAMEBUFFER`/`READ_FRAMEBUFFER`/`DRAW_FRAMEBUFFER`)、`framebufferTexture2D`(`COLOR_ATTACHMENT0`、`DEPTH_ATTACHMENT`、`DEPTH_STENCIL_ATTACHMENT`)、`checkFramebufferStatus`、`createRenderbuffer`、`bindRenderbuffer`、`renderbufferStorage`(深度/深度模板)、`framebufferRenderbuffer`、`delete*`,以及 `blitFramebuffer
|
|
91
|
+
- **Framebuffer**:`createFramebuffer`、`bindFramebuffer`(`FRAMEBUFFER`/`READ_FRAMEBUFFER`/`DRAW_FRAMEBUFFER`)、`framebufferTexture2D`(`COLOR_ATTACHMENT0`、`DEPTH_ATTACHMENT`、`DEPTH_STENCIL_ATTACHMENT`)、`checkFramebufferStatus`、`createRenderbuffer`、`bindRenderbuffer`、`renderbufferStorage`(深度/深度模板)、`framebufferRenderbuffer`、`delete*`,以及 `blitFramebuffer`(颜色走 SDL blit;深度走一个写 `gl_FragDepth` 的采样 pass;模板位被接受但不复制)。足以实现渲染到纹理、阴影贴图与后处理。
|
|
73
92
|
- **状态**:`enable`/`disable`/`isEnabled`(`BLEND`、`DEPTH_TEST`、`CULL_FACE`、`SCISSOR_TEST`、`STENCIL_TEST`)、`clearColor`/`clearDepth`/`clearStencil`、`clear`(开启 `SCISSOR_TEST` 时颜色、深度与模板都只清除 scissor 矩形)、`blendColor`、`blendFunc`/`blendFuncSeparate`、`blendEquation`/`blendEquationSeparate`、`depthFunc`、`depthMask`、`colorMask`、`stencilFunc`/`stencilFuncSeparate`、`stencilOp`/`stencilOpSeparate`、`stencilMask`/`stencilMaskSeparate`、`cullFace`、`frontFace`、`viewport`、`scissor`、`pixelStorei`、`finish`。模板测试真正参与光栅化,`clear(STENCIL_BUFFER_BIT)` 会清空模板附件;SDL_GPU 只有一份前后脸共用的 reference 与 compare/write mask,若前后脸设置不同,使用前脸值。
|
|
74
93
|
- **读回**:`readPixels`(RGBA/UNSIGNED_BYTE),可从默认帧缓冲或绑定的 RGBA8 framebuffer 读取;浮点/深度附件先采样到 RGBA8 目标再读回。它会阻塞到 GPU 完成;用于测试和截图,不要每帧调用。
|
|
75
94
|
|
|
@@ -91,7 +110,9 @@ WebGL 2 额外提供:
|
|
|
91
110
|
|
|
92
111
|
## 未实现
|
|
93
112
|
|
|
94
|
-
transform feedback
|
|
113
|
+
transform feedback(入口为空操作:SDL_GPU 没有 transform feedback 阶段)与 MSAA/采样缓冲(SDL_GPU 3.2 能解析多采样颜色目标,但其 Metal resolve 在 scissor 与实例化绘制下会返回未定义像素,因此上下文保持单采样,`SAMPLE_BUFFERS` 报告 0)。`blitFramebuffer` 复制颜色与深度;模板位被接受但不复制,因为 SDL_GPU 无法采样模板附件。
|
|
114
|
+
|
|
115
|
+
仍存在的着色器限制:结构体 uniform 与用户 uniform 块会被展平,但内建接口块(如重声明 `gl_PerVertex`)不在翻译子集内;使用它的着色器仍会以编译/链接日志失败,而不是静默出错。
|
|
95
116
|
|
|
96
117
|
## 平台
|
|
97
118
|
|
|
@@ -101,7 +122,8 @@ transform feedback(入口为空操作)与 MSAA/采样缓冲(SDL_GPU 的 Me
|
|
|
101
122
|
|
|
102
123
|
## 测试
|
|
103
124
|
|
|
104
|
-
- `tests/e2e/gui-webgl.test.ts` 编译 GLSL、绘制带纹理和深度测试的四边形、检查面剔除,并读回像素;它还覆盖混合常量色、动态缓冲 usage、顶点着色器纹理采样、`gl_FragDepth
|
|
125
|
+
- `tests/e2e/gui-webgl.test.ts` 编译 GLSL、绘制带纹理和深度测试的四边形、检查面剔除,并读回像素;它还覆盖混合常量色、动态缓冲 usage、顶点着色器纹理采样、`gl_FragDepth`、上下文丢失/恢复与立方体贴图。
|
|
126
|
+
- `tests/e2e/gui-webgl2-shadow-sampler.test.ts` 覆盖硬件 `sampler2DShadow` 比较、着色器写 `gl_FragDepth` 遮挡后续绘制,以及 `blitFramebuffer` 的部分深度复制。
|
|
105
127
|
- `tests/e2e/gui-webgl2.test.ts` 覆盖 WebGL 2 的着色器/状态新增能力:`#version 300 es` 着色器、VAO 往返、带 divisor 的实例化绘制、`texStorage2D`、`clearBufferfv`、缓冲拷贝、采样器对象、结构体 uniform 字段与 `drawingBufferStorage`。
|
|
106
128
|
- `tests/e2e/gui-webgl2-formats.test.ts` 覆盖模板、浮点/深度纹理、压缩纹理与 `ImageBitmap`。
|
|
107
129
|
- `tests/e2e/gui-webgl2-blit.test.ts` 覆盖带 scissor 的颜色/深度清除、framebuffer blit,以及局部 blit 之外必须保留的像素(在 Metal 上,若目标 load-op 丢弃这些像素,该测试就会失败)。
|
|
@@ -116,6 +138,6 @@ transform feedback(入口为空操作)与 MSAA/采样缓冲(SDL_GPU 的 Me
|
|
|
116
138
|
|
|
117
139
|
## three.js
|
|
118
140
|
|
|
119
|
-
|
|
141
|
+
着色器改写器会把 three.js 的 `#pragma unroll_loop_start` 循环展开为常量索引(否则其采样器数组无法通过 Vulkan GLSL),`.js` 资源加载器则避免渲染器自带的展开器重复处理。`WebGLRenderer` 在本引擎真正的 WebGL 2 后端上原样运行,**不再打包 Canvas2D 回退**。已用 three.js r160 通过 SDL_GPU 验证:`MeshBasicMaterial`、`MeshStandardMaterial`、`MeshPhongMaterial`、`CanvasTexture`、线性雾、环境光/平行光/点光/聚光/半球光、`Sprite`、`Line`、`Points` 与 `InstancedMesh`。
|
|
120
142
|
|
|
121
|
-
本引擎子集之外的能力仍无法模拟:transform feedback 与 MSAA
|
|
143
|
+
本引擎子集之外的能力仍无法模拟:transform feedback 与 MSAA。立方体贴图/环境贴图、深度纹理、HDR/浮点渲染目标、压缩纹理与比较型 `sampler2DShadow` 采样都已可用(three.js 阴影贴图可在两个后端使用硬件深度比较)。需要 transform feedback 或 MSAA 的场景无法正确渲染;此前 Canvas2D 回退能显示的内容现在全部走 GPU。
|
package/doc/zh-CN/gui-scripts.md
CHANGED
|
@@ -146,15 +146,16 @@ export default __html;
|
|
|
146
146
|
### 2b. 外部 `<script src>`
|
|
147
147
|
|
|
148
148
|
`<script src="./app.ts">` 相对 HTML 文件读取、解析并拆分:其顶层
|
|
149
|
-
`import`/`export … from`
|
|
150
|
-
|
|
151
|
-
`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
`import`/`export … from` 语句从主体中移除,其余语句被包装进脚本函数。相对
|
|
150
|
+
import 会像浏览器的模块脚本一样**延迟**:loader 生成一个合成的
|
|
151
|
+
`__xt_deferred_module` 标记,生成的脚本在 `loadHTML` 时调用模块包装函数。
|
|
152
|
+
bundler 把整个本地 import 图包装成返回各自导出的函数(由 `__xt_defer`
|
|
153
|
+
记忆化),因此模块顶层代码在文档就绪后才运行,且两个脚本导入同一模块时共享
|
|
154
|
+
同一个实例。裸说明符(`gui`、npm 包)仍然立即加载。
|
|
155
|
+
|
|
156
|
+
缺失的 `src` 文件仍会抛出清晰的错误(被转换为 bundler 诊断);
|
|
157
|
+
`src` URL(`https://…`、`data:…`、`//host`)保持原样 —— 它们不是编译期资产,
|
|
158
|
+
永不运行。
|
|
158
159
|
|
|
159
160
|
`src` URL(`https://…`、`data:…`、`//host`)保持原样 —— 它们不是编译期资产,
|
|
160
161
|
永不运行。
|
|
@@ -283,10 +284,10 @@ Event 的 `target` 是句柄,其描述符(`toString`)与同一 `div#id.cla
|
|
|
283
284
|
- **M9b** ✅ —— gui `.html` 加载器(`src/extensions/gui/html.ts`)、
|
|
284
285
|
`__registerScript` 内置函数、脚本注册表(`runtime/ext_gui/script.cpp`)、
|
|
285
286
|
`loadHTML` 执行与 `DOMContentLoaded`/`load`;e2e 覆盖。
|
|
286
|
-
- **M9c** ✅ —— 读取 `<script src>`
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
覆盖。
|
|
287
|
+
- **M9c** ✅ —— 读取 `<script src>` 文件,其主体被包装并注册;相对 import
|
|
288
|
+
通过带记忆化的模块包装函数延迟到 `loadHTML` 求值,因此 import 图能看到
|
|
289
|
+
已解析的文档,且同一模块只实例化一次。缺失文件作为诊断浮现。所有脚本按
|
|
290
|
+
文档顺序运行。e2e 覆盖。
|
|
290
291
|
- **M9d** *(可选)* —— 检测传给 `win.loadHTML(...)` 的模板字面量中的内联
|
|
291
292
|
HTML 并同样转换它们(脆弱;推迟)。
|
|
292
293
|
- **M10 — 打磨** ✅ —— 窗口上的
|
package/doc/zh-CN/gui.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 语言 / Language:[English](../gui.md) | **简体中文**
|
|
4
4
|
|
|
5
|
-
状态:**
|
|
5
|
+
状态:**M20** —— 功能(M1–M15)已全部完成:HTML 解析、CSS 选择器匹配、层叠(cascade)、计算样式与布局(块级、行内、Flexbox 与 CSS 定位)均已就位,引擎还会**绘制**:它构建一个由矩形、图像与排版后的文本 run 组成的显示列表,并通过 SDL_GPU 渲染。输入事件会经过命中测试并投递给原生 TS 处理器,`:hover`/`:focus` 会被动态匹配,`<img>` 依据其固有尺寸确定大小并从纹理绘制——位图(PNG/JPEG/…)与 SVG 文件皆可,后者按绘制尺寸光栅化,因此矢量图保持清晰——CSS transition 会为绘制属性做动画。**M16** 让内联 `<svg>` 子树获得同样的处理:子树被序列化回 SVG 文档,并按绘制设备尺寸光栅化,因此图标不再需要单独的文件。**M8** 增加了交互式 DOM:具有稳定标识的元素句柄、变更操作(`appendChild`、`textContent`、`classList`、`style` 等)以及支持捕获/冒泡的元素级事件。**M9** 会提前编译 `<script>` 主体(内联与 `<script src>`)——参见 `gui-scripts.md`。**M10** 增加 `requestAnimationFrame` 以及若干 DOM 辅助方法。**M11** 增加 `position: relative`/`absolute`/`fixed` 及其偏移,`examples/gui/pelican-bike`(一个可玩的 2D 游戏)就构建在它之上。**M12** 明确了 DOM 节点生命周期(哪些变更释放、哪些保留),并让引擎内存有界:参见[节点生命周期](./gui/dom.md)与[内存与 GC](./gui/runtime.md)。**M13** 真正播放
|
|
6
6
|
`<video>`/`<audio>`——可选的 `media` 扩展用 vendored 的最小 FFmpeg 在主线程解码,
|
|
7
7
|
视频帧走图像纹理路径、音频进入 SDL 流,DOM 媒体 API 暴露
|
|
8
8
|
`play`/`pause`/`currentTime`/… 与媒体事件。只启用 `gui` 不会链接 FFmpeg。浏览器全局还带有真正可用的 `AudioContext`:`runtime/ext_gui/audio_mixer.cpp` 中的 48 kHz 混音器,以及 `decodeAudioData`(WAV 由引擎内解码,压缩格式经 `media`)——见 [GUI API](./gui/api.md#web-audio)。**M14** 增加了 `<canvas>`,配一个自研的 2D 软件光栅器(抗锯齿
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
渲染器,因此盒子(以及其中的文本、图像与子元素)可以被平移、缩放与旋转而
|
|
13
13
|
不触发任何重排——再加上 `transition: transform`,这些姿态可以动画(自绘的示例
|
|
14
14
|
`examples/gui/pelican-svg` 正是用它让矢量画动起来)。参见
|
|
15
|
-
[布局](./gui/layout.md#变换m15)与[动画](./gui/animation.md#css-transformm15)。**M17** 增加了真正的 **WebGL 1.0**,**M18** 增加了 **WebGL 2.0**:`<canvas>.getContext("webgl2")` 接受 `#version 300 es` 着色器、顶点数组对象、实例化绘制与采样器对象,全部由内置 glslang 编译为 SPIR-V(Metal 上再由内置 SPIRV-Cross 转成 MSL)并通过 SDL_GPU 渲染,几何、光照、纹理采样与混合都在 GPU 上完成,页面直接合成颜色纹理而无须读回——见 [WebGL](./gui/webgl.md)。**M19** 补齐 CSS 装饰层:`@media` 查询、生成内容(`::before`/`::after`)、线性/径向多层背景、`text-shadow`、`clip-path` 与 `filter` 颜色/阴影效果。`backdrop-filter` 与真正的组模糊需要离屏合成器,仍为有文档说明的近似或未支持——见[绘制](./gui/rendering.md#背景生成内容与特效m19)。本总览记录了锁定决策、架构、里程碑计划与当前进度;引擎本身按功能拆分在以上各页中。
|
|
15
|
+
[布局](./gui/layout.md#变换m15)与[动画](./gui/animation.md#css-transformm15)。**M17** 增加了真正的 **WebGL 1.0**,**M18** 增加了 **WebGL 2.0**:`<canvas>.getContext("webgl2")` 接受 `#version 300 es` 着色器、顶点数组对象、实例化绘制与采样器对象,全部由内置 glslang 编译为 SPIR-V(Metal 上再由内置 SPIRV-Cross 转成 MSL)并通过 SDL_GPU 渲染,几何、光照、纹理采样与混合都在 GPU 上完成,页面直接合成颜色纹理而无须读回——见 [WebGL](./gui/webgl.md)。**M19** 补齐 CSS 装饰层:`@media` 查询、生成内容(`::before`/`::after`)、线性/径向多层背景、`text-shadow`、`clip-path` 与 `filter` 颜色/阴影效果。`backdrop-filter` 与真正的组模糊需要离屏合成器,仍为有文档说明的近似或未支持——见[绘制](./gui/rendering.md#背景生成内容与特效m19)。**M20** 让大文档保持可交互:`@media` 每条规则只求值一次,布局与绘制共享一个有界的整形缓存,一帧只做(也只提交)变更所要求的工作——见[性能](./gui/rendering.md#性能m20)。本总览记录了锁定决策、架构、里程碑计划与当前进度;引擎本身按功能拆分在以上各页中。
|
|
16
16
|
|
|
17
17
|
## 目录
|
|
18
18
|
|
|
@@ -167,9 +167,10 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
|
|
|
167
167
|
`__registerScript` 内置函数注册,并替换为
|
|
168
168
|
`<script data-xt-id="<hash>">` 标记;`win.loadHTML` 在解析后运行匹配的
|
|
169
169
|
函数并触发 `DOMContentLoaded` 然后是 `load`。
|
|
170
|
-
- **M9c** ✅ —— `<script src>` 文件相对 HTML
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
- **M9c** ✅ —— `<script src>` 文件相对 HTML 读取,其主体被包装/注册;
|
|
171
|
+
相对 import 通过带记忆化的模块包装函数延迟到 `loadHTML` 求值,因此被导入
|
|
172
|
+
模块能看到已解析的文档并共享状态。缺失文件会成为诊断。一切都按文档顺序
|
|
173
|
+
运行。
|
|
173
174
|
10. **M10 — 打磨** ✅
|
|
174
175
|
- `win.requestAnimationFrame(fn)` / `win.cancelAnimationFrame(id)`;回调
|
|
175
176
|
在每帧顶部以帧时间戳运行,并可修改 DOM
|
|
@@ -272,6 +273,16 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
|
|
|
272
273
|
[已知问题](./gui/known-issues.md))。
|
|
273
274
|
- e2e 覆盖见 `tests/e2e/gui-effects.test.ts`;参见
|
|
274
275
|
[绘制](./gui/rendering.md#背景生成内容与特效m19)。
|
|
276
|
+
20. **M20 — 渲染性能** ✅
|
|
277
|
+
- `@media` 每次重算样式时每条规则只求值一次;没有伪元素的样式表跳过生成
|
|
278
|
+
内容;只有样式表跟踪 `:hover`/`:focus` 时才因它们重算样式。
|
|
279
|
+
- 有界的两代整形缓存同时服务布局与绘制,并缓存主字体。
|
|
280
|
+
- 帧循环:只在文档变化时对齐媒体/画布表,只在发生事情时提交呈现,并据此
|
|
281
|
+
决定是否执行整帧工作。
|
|
282
|
+
- 复用显示列表/顶点暂存/transfer buffer,一个脏帧只提交一次上传,去掉
|
|
283
|
+
冗余的渲染状态绑定。
|
|
284
|
+
- `win.stats()`/`XT_GUI_PERF` 计数器与 `tests/e2e/gui-perf.test.ts`;参见
|
|
285
|
+
[性能](./gui/rendering.md#性能m20)。
|
|
275
286
|
|
|
276
287
|
## 进度日志
|
|
277
288
|
|
|
@@ -317,9 +328,9 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
|
|
|
317
328
|
编译为启动时注册、由 `win.loadHTML` 运行的 AOT 函数(在首次布局之前;
|
|
318
329
|
`DOMContentLoaded` 然后是 `load`)。`tests/extensions/gui.test.ts` 中的单元
|
|
319
330
|
测试,`tests/e2e/gui-*.test.ts` 中的 e2e。
|
|
320
|
-
- **M9c** ✅ 外部 `<script src>`
|
|
321
|
-
|
|
322
|
-
|
|
331
|
+
- **M9c** ✅ 外部 `<script src>` 文件被读取,其主体被包装/注册;相对 import
|
|
332
|
+
通过带记忆化的模块包装函数延迟到 `loadHTML`(模块级 DOM 工作因此能看到已解析
|
|
333
|
+
文档);缺失文件会成为诊断。加载器错误被 `loadGraph` 捕获并报告为构建错误。
|
|
323
334
|
- **M10** ✅ 窗口句柄上的 `requestAnimationFrame`/`cancelAnimationFrame`
|
|
324
335
|
(回调在每帧布局之前以帧时间戳运行),以及元素句柄上的
|
|
325
336
|
`offsetWidth`/`offsetHeight`/`contains`;e2e 覆盖在
|
|
@@ -401,4 +412,17 @@ FFmpeg `7.1`(供可选的 `media` 归档使用;可用 `SDL3_TAG` /
|
|
|
401
412
|
采样模糊/投影并生成 `text-shadow` run,`paint_clip.cpp`/`renderer_clip.cpp`
|
|
402
413
|
对三角化的 `clip-path` 多边形裁剪几何。e2e 见
|
|
403
414
|
`tests/e2e/gui-effects.test.ts`。
|
|
415
|
+
- **M20** ✅ 渲染性能。`@media` 每次重算样式时每条规则只求值一次;没有
|
|
416
|
+
`::before`/`::after` 的样式表完全跳过生成内容;只有样式表包含
|
|
417
|
+
`:hover`/`:focus` 规则时才因这两个状态重算样式(`style.cpp`、
|
|
418
|
+
`css_sheet.cpp`)。一个有界的两代整形缓存(`text_cache.cpp`)同时服务布局与
|
|
419
|
+
绘制,因此一个词只整形一次,而不是每次布局和重绘都整形一次;主字体也按
|
|
420
|
+
(类别,字号)缓存。帧循环只在文档变化时对齐解码器/画布,并且只在确实发生了
|
|
421
|
+
事情时提交呈现(`gui_events.cpp`),因此静态页面不产生任何 GPU 工作
|
|
422
|
+
(调试时可用 `XT_GUI_ALWAYS_PRESENT=1` 恢复旧行为)。显示列表、顶点暂存与
|
|
423
|
+
transfer buffer 都被复用,一个脏帧的多次上传共用一次命令缓冲区提交,渲染器
|
|
424
|
+
只在状态真正变化时重新绑定(`renderer*.cpp`、`gui_engine.h`)。
|
|
425
|
+
`win.stats()` 报告帧耗时与累计工作量计数器,`XT_GUI_PERF` 打印它们
|
|
426
|
+
(`perf.{h,cpp}`);`tests/e2e/gui-perf.test.ts` 用 200 行列表固化这些断言。
|
|
427
|
+
参见[性能](./gui/rendering.md#性能m20)。
|
|
404
428
|
|
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
- 全局 `fetch(input, init)` 是 HTTP/1.1 客户端。阻塞的套接字交换(`getaddrinfo`、connect、send、receive)运行在异步 I/O 工作线程池上,因此进行中的请求**不会**卡住事件循环:定时器、套接字与其他 `await` 继续运行,promise 在 reactor 派发完成结果时 settle。
|
|
8
8
|
- 重定向在主线程上处理:每一跳是一次 offload 交换,最多 20 次;301/302/303 会把 POST 改成 GET。
|
|
9
9
|
- 只接受 `http://` URL —— 由于未链接 TLS 后端,`https://` 会以 `TypeError` 拒绝。
|
|
10
|
+
- **没有协议的引用**(相对路径)与 `file://` URL 会读取本地文件,因此编译后的程序
|
|
11
|
+
无需 HTTP 服务即可加载磁盘资源。相对路径相对工作目录解析;支持 `GET` / `HEAD`。
|
|
12
|
+
在 Windows 上,标准写法 `file:///C:/dir/file` 与 `file://C:/dir/file` /
|
|
13
|
+
`file://C:\dir\file` 都指向同一个文件。
|
|
10
14
|
- 选项:`method`、`headers`(普通对象或 `Headers`)、`body` 与 `redirect`(`follow` / `manual` / `error`)。
|
|
11
15
|
- 解析出的 `Response` 形状对象暴露 `ok` / `status` / `statusText` / `url` / `headers` 以及 `text()` / `json()` / `arrayBuffer()` / `bytes()` / `clone()`。响应体在 promise settle 前已完整缓冲;不支持流式响应体。
|
|
12
16
|
- `Headers` 大小写不敏感,提供 `get` / `has` / `set` / `append` / `delete` / `keys` / `values` / `entries` / `forEach` / `getSetCookie`。
|
|
@@ -19,6 +19,16 @@
|
|
|
19
19
|
- 导入绑定与命名空间成员是模块求值时的快照(无实时绑定)—— 见[未实现:模块系统](../unimplemented/modules.md)。
|
|
20
20
|
- 纯类型导入与再导出(`import type { T } from "..."`、`import { type T } from "..."`、`export type { T } from "..."`)会被擦除,**不构成模块依赖边**:目标模块不会被加载或打包,模块之间的纯类型循环也不属于循环依赖。若需要仅求值一个模块而不绑定名字,请使用副作用导入(`import "./mod"`)。
|
|
21
21
|
|
|
22
|
+
## 延迟求值
|
|
23
|
+
|
|
24
|
+
- `gui` 的 `.html` 资产加载器用合成的 `__xt_deferred_module` 绑定标记相对的
|
|
25
|
+
`<script src>` import。bundler 会把该模块及其本地 import 图包装成返回各自
|
|
26
|
+
导出的函数,生成的脚本在 `loadHTML` 之后调用它们(`__xt_defer` 对每个模块
|
|
27
|
+
做记忆化)。这与浏览器的模块脚本一致:文档就绪后才求值 import 图。
|
|
28
|
+
- 同时被普通(非标记)import 引用的模块保持立即求值,并获得一个返回已初始化
|
|
29
|
+
导出的薄包装。
|
|
30
|
+
- 包装体是同步的:延迟脚本模块中的顶层 `await` 不受支持。
|
|
31
|
+
|
|
22
32
|
## import.meta
|
|
23
33
|
|
|
24
34
|
- `import.meta.url` / `.dirname` / `.filename`,由正在运行的可执行文件路径解析。
|
|
@@ -53,6 +53,21 @@
|
|
|
53
53
|
- `Symbol(description)` 原始值(`XT_OBJECT_KIND_SYMBOL`)、13 个著名符号(`Symbol.iterator`、`Symbol.asyncIterator`、`Symbol.match` 等)、`Symbol.for` / `Symbol.keyFor` 全局注册表、`symbol.description` / `toString()` / `valueOf()`。
|
|
54
54
|
- symbol 可作为属性键(`Object.getOwnPropertySymbols`,symbol 键的 `get`/`set`/`in`/`delete`),会被 `Object.keys` / `values` / `entries` / `for...in` / `JSON.stringify` 跳过,打印为 `Symbol(desc)`。
|
|
55
55
|
|
|
56
|
+
## URL
|
|
57
|
+
|
|
58
|
+
- `URL` 实现在 `runtime/xt_url_object.c`:支持 `new URL(input)` 与
|
|
59
|
+
`new URL(input, base)`(base 也可以是另一个 `URL`),并按层级式
|
|
60
|
+
`scheme://authority/path` base 解析相对引用。
|
|
61
|
+
- **没有协议的引用按文件路径处理**:`new URL("./model.glb")` 相对工作目录解析,
|
|
62
|
+
得到 `file:` URL(显式 base 仍然生效,因此 `new URL("./x", import.meta.url)`
|
|
63
|
+
也可用)。
|
|
64
|
+
- 只读属性 `href`、`protocol`、`origin`、`host`、`hostname`、`port`、
|
|
65
|
+
`pathname`、`search`、`hash`、`searchParams` 以及 `toString()` / `toJSON()`;
|
|
66
|
+
绝对输入按原样保留,但 `file:` URL 的 Windows 写法(`file://C:/dir` 与
|
|
67
|
+
`file://C:\dir`)会规范化为 `file:///C:/dir`,与 Node 一致。
|
|
68
|
+
- 不是完整的 WHATWG 解析器:未实现路径百分号编码、IDNA、setter 与
|
|
69
|
+
`searchParams` 的实时同步 —— 见[运行时偏差](../unimplemented/deviations.md)。
|
|
70
|
+
|
|
56
71
|
## URLSearchParams
|
|
57
72
|
|
|
58
73
|
- `URLSearchParams` 实现在 `runtime/xt_url.c`。
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
| --- | --- |
|
|
9
9
|
| 正则按字节匹配 | 引擎按 UTF-8 字节匹配:多字节字面量仍可匹配,但 `.` 与字符类每次只消费一个字节(`\d`/`\w` 仍是 ASCII)。`exec` / `search` / 替换回调返回的偏移会转换为 UTF-16 码元 |
|
|
10
10
|
| 全局正则 `lastIndex` | `/g`、`/y` 正则的 `test` / `exec` 不推进也不读取调用方设置的 `lastIndex` |
|
|
11
|
+
| `URL` 解析器 | 只读 WHATWG 子集:未实现路径百分号编码、IDNA、setter 与 `searchParams` 实时联动;无协议引用按工作目录解析为 `file:` URL |
|
|
11
12
|
| `String.normalize` | 未实现 |
|
|
12
13
|
| 内置方法一等公民 | 以未绑定方法值实现(见[函数](./functions.md));`fn.toString()` 返回占位字符串而非源码文本 |
|
|
13
14
|
| `for...in` | 枚举对象 / 数组 / 字符串的自身键;不含原型链属性 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xbintsc",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.41",
|
|
4
4
|
"description": "xbintsc - a TypeScript binary compiler (TypeScript -> LLVM IR -> native binary)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -72,12 +72,12 @@
|
|
|
72
72
|
"vitest": "^2.1.8"
|
|
73
73
|
},
|
|
74
74
|
"optionalDependencies": {
|
|
75
|
-
"@xbintsc/linux-x64": "0.5.
|
|
76
|
-
"@xbintsc/linux-arm64": "0.5.
|
|
77
|
-
"@xbintsc/darwin-x64": "0.5.
|
|
78
|
-
"@xbintsc/darwin-arm64": "0.5.
|
|
79
|
-
"@xbintsc/win32-x64": "0.5.
|
|
80
|
-
"@xbintsc/win32-arm64": "0.5.
|
|
75
|
+
"@xbintsc/linux-x64": "0.5.41",
|
|
76
|
+
"@xbintsc/linux-arm64": "0.5.41",
|
|
77
|
+
"@xbintsc/darwin-x64": "0.5.41",
|
|
78
|
+
"@xbintsc/darwin-arm64": "0.5.41",
|
|
79
|
+
"@xbintsc/win32-x64": "0.5.41",
|
|
80
|
+
"@xbintsc/win32-arm64": "0.5.41"
|
|
81
81
|
},
|
|
82
82
|
"engines": {
|
|
83
83
|
"node": ">=22"
|
|
@@ -337,6 +337,7 @@ xt_value type_proto(const std::string &name) {
|
|
|
337
337
|
if (name == "WebGLSync") return domapi::webgl_object_proto("sync");
|
|
338
338
|
if (name == "WebGLTransformFeedback") return domapi::webgl_object_proto("transformfeedback");
|
|
339
339
|
if (name == "Path2D") return domapi::path2d_proto();
|
|
340
|
+
if (name == "OffscreenCanvas") return domapi::offscreen_canvas_proto();
|
|
340
341
|
if (name == "ImageBitmap") {
|
|
341
342
|
/* A bitmap is a plain immutable object, not a DOM node: a node proto would
|
|
342
343
|
* expose the element width/height accessors and answer 0. */
|
|
@@ -383,6 +384,7 @@ xt_value host_type_construct(xt_value self, xt_value env, int32_t argc, xt_value
|
|
|
383
384
|
return domapi::event_construct(xt_arg(argc, argv, 0), xt_arg(argc, argv, 1));
|
|
384
385
|
}
|
|
385
386
|
if (name == "Path2D") return domapi::path2d_create(xt_arg(argc, argv, 0));
|
|
387
|
+
if (name == "OffscreenCanvas") return domapi::offscreen_canvas_create(argc, argv);
|
|
386
388
|
xt_value target = xt_object_new_with_proto(type_proto(name));
|
|
387
389
|
set_prop(target, "constructor", type_value(name));
|
|
388
390
|
return target;
|
|
@@ -518,7 +520,7 @@ xt_value xt_browser_type(int32_t argc, xt_value *argv) {
|
|
|
518
520
|
(void)argv;
|
|
519
521
|
if (argc < 1) return XT_UNDEFINED;
|
|
520
522
|
std::string name = cstr(xt_arg(argc, argv, 0));
|
|
521
|
-
if (name == "XRWebGLLayer" || name == "XRWebGLBinding" ||
|
|
523
|
+
if (name == "XRWebGLLayer" || name == "XRWebGLBinding" ||
|
|
522
524
|
name == "ImageData" || name == "Response" ||
|
|
523
525
|
name == "ReadableStream" || name == "Request" || name == "Headers" ||
|
|
524
526
|
name == "DOMParser") {
|