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
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
#include <cstring>
|
|
16
16
|
|
|
17
17
|
#include "paint.h"
|
|
18
|
+
#include "perf.h"
|
|
18
19
|
#include "text.h"
|
|
19
20
|
|
|
20
21
|
#include "renderer_shaders.h"
|
|
@@ -39,10 +40,32 @@ bool g_atlas_dirty = false;
|
|
|
39
40
|
int g_atlas_dirty_x0 = 0, g_atlas_dirty_y0 = 0, g_atlas_dirty_x1 = 0, g_atlas_dirty_y1 = 0;
|
|
40
41
|
bool g_atlas_full_logged = false;
|
|
41
42
|
|
|
43
|
+
std::vector<Vertex> g_shape_staging;
|
|
44
|
+
std::vector<TextVertex> g_text_staging;
|
|
45
|
+
std::vector<TextVertex> g_image_staging;
|
|
46
|
+
|
|
47
|
+
/** The command buffer an upload records into. With a batch, the frame's single
|
|
48
|
+
* command buffer is acquired lazily and submitted by `xt_gui_upload_end`;
|
|
49
|
+
* without one, each upload submits on its own. */
|
|
50
|
+
SDL_GPUCommandBuffer *uploadCommand(SDL_GPUDevice *device, XtGuiUploadBatch *batch) {
|
|
51
|
+
if (batch == nullptr) return SDL_AcquireGPUCommandBuffer(device);
|
|
52
|
+
if (batch->cmd == nullptr) batch->cmd = SDL_AcquireGPUCommandBuffer(batch->device);
|
|
53
|
+
return batch->cmd;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void uploadDone(SDL_GPUCommandBuffer *cmd, XtGuiUploadBatch *batch) {
|
|
57
|
+
if (batch != nullptr) {
|
|
58
|
+
batch->recorded += 1;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
SDL_SubmitGPUCommandBuffer(cmd);
|
|
62
|
+
g_perf_frame.uploadSubmits += 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
42
65
|
/** Upload `count` vertices (of `stride` bytes) into `geometry`, reusing or
|
|
43
66
|
* growing its GPU buffer. Does nothing when `count` is zero. */
|
|
44
67
|
void uploadVertices(SDL_GPUDevice *device, XtGuiGeometry *geometry, const void *data,
|
|
45
|
-
uint32_t count, uint32_t stride) {
|
|
68
|
+
uint32_t count, uint32_t stride, XtGuiUploadBatch *batch) {
|
|
46
69
|
geometry->vertex_count = count;
|
|
47
70
|
if (count == 0) return;
|
|
48
71
|
uint32_t bytes = count * stride;
|
|
@@ -61,29 +84,37 @@ void uploadVertices(SDL_GPUDevice *device, XtGuiGeometry *geometry, const void *
|
|
|
61
84
|
return;
|
|
62
85
|
}
|
|
63
86
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
87
|
+
/* Reuse the geometry's staging buffer: a repaint used to create and release a
|
|
88
|
+
* transfer buffer for every vertex array, every frame. */
|
|
89
|
+
if (geometry->staging == nullptr || geometry->staging_capacity < bytes) {
|
|
90
|
+
if (geometry->staging != nullptr) SDL_ReleaseGPUTransferBuffer(device, geometry->staging);
|
|
91
|
+
SDL_GPUTransferBufferCreateInfo transfer_info;
|
|
92
|
+
memset(&transfer_info, 0, sizeof(transfer_info));
|
|
93
|
+
transfer_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
|
94
|
+
transfer_info.size = bytes;
|
|
95
|
+
geometry->staging = SDL_CreateGPUTransferBuffer(device, &transfer_info);
|
|
96
|
+
geometry->staging_capacity = geometry->staging != nullptr ? bytes : 0;
|
|
97
|
+
}
|
|
98
|
+
if (geometry->staging == nullptr) {
|
|
70
99
|
fprintf(stderr, "xt_gui: transfer buffer creation failed: %s\n", SDL_GetError());
|
|
71
100
|
geometry->vertex_count = 0;
|
|
72
101
|
return;
|
|
73
102
|
}
|
|
74
|
-
|
|
103
|
+
/* `cycle` rotates SDL's internal allocation while the previous frame's copy
|
|
104
|
+
* may still be in flight: the staging buffer is reused every frame, so the
|
|
105
|
+
* non-cycling map could overwrite data the GPU has not read yet. */
|
|
106
|
+
void *mapped = SDL_MapGPUTransferBuffer(device, geometry->staging, true);
|
|
75
107
|
std::memcpy(mapped, data, bytes);
|
|
76
|
-
SDL_UnmapGPUTransferBuffer(device,
|
|
108
|
+
SDL_UnmapGPUTransferBuffer(device, geometry->staging);
|
|
77
109
|
|
|
78
|
-
SDL_GPUCommandBuffer *cmd =
|
|
110
|
+
SDL_GPUCommandBuffer *cmd = uploadCommand(device, batch);
|
|
79
111
|
if (cmd == nullptr) {
|
|
80
|
-
SDL_ReleaseGPUTransferBuffer(device, transfer);
|
|
81
112
|
geometry->vertex_count = 0;
|
|
82
113
|
return;
|
|
83
114
|
}
|
|
84
115
|
SDL_GPUCopyPass *copy = SDL_BeginGPUCopyPass(cmd);
|
|
85
116
|
SDL_GPUTransferBufferLocation source;
|
|
86
|
-
source.transfer_buffer =
|
|
117
|
+
source.transfer_buffer = geometry->staging;
|
|
87
118
|
source.offset = 0;
|
|
88
119
|
SDL_GPUBufferRegion destination;
|
|
89
120
|
destination.buffer = geometry->buffer;
|
|
@@ -91,13 +122,26 @@ void uploadVertices(SDL_GPUDevice *device, XtGuiGeometry *geometry, const void *
|
|
|
91
122
|
destination.size = bytes;
|
|
92
123
|
SDL_UploadToGPUBuffer(copy, &source, &destination, false);
|
|
93
124
|
SDL_EndGPUCopyPass(copy);
|
|
94
|
-
|
|
95
|
-
|
|
125
|
+
uploadDone(cmd, batch);
|
|
126
|
+
g_perf_frame.vertices += count;
|
|
96
127
|
}
|
|
97
128
|
|
|
98
129
|
} // namespace renderer_detail
|
|
99
130
|
} // namespace xtgui
|
|
100
131
|
|
|
132
|
+
void xt_gui_upload_begin(XtGuiUploadBatch *batch, SDL_GPUDevice *device) {
|
|
133
|
+
batch->device = device;
|
|
134
|
+
batch->cmd = nullptr;
|
|
135
|
+
batch->recorded = 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
void xt_gui_upload_end(XtGuiUploadBatch *batch) {
|
|
139
|
+
if (batch == nullptr || batch->cmd == nullptr) return;
|
|
140
|
+
SDL_SubmitGPUCommandBuffer(batch->cmd);
|
|
141
|
+
batch->cmd = nullptr;
|
|
142
|
+
xtgui::g_perf_frame.uploadSubmits += 1;
|
|
143
|
+
}
|
|
144
|
+
|
|
101
145
|
bool xt_gui_renderer_ensure(SDL_GPUDevice *device, SDL_Window *reference) {
|
|
102
146
|
using namespace xtgui::renderer_detail;
|
|
103
147
|
if (g_pipeline != nullptr) return true;
|
|
@@ -238,15 +282,21 @@ void xt_gui_geometry_destroy(SDL_GPUDevice *device, XtGuiGeometry *geometry) {
|
|
|
238
282
|
SDL_ReleaseGPUBuffer(device, geometry->buffer);
|
|
239
283
|
geometry->buffer = nullptr;
|
|
240
284
|
}
|
|
285
|
+
if (geometry->staging != nullptr) {
|
|
286
|
+
SDL_ReleaseGPUTransferBuffer(device, geometry->staging);
|
|
287
|
+
geometry->staging = nullptr;
|
|
288
|
+
}
|
|
289
|
+
geometry->staging_capacity = 0;
|
|
241
290
|
geometry->capacity_bytes = 0;
|
|
242
291
|
geometry->vertex_count = 0;
|
|
243
292
|
geometry->dirty = true;
|
|
244
293
|
}
|
|
245
294
|
|
|
246
295
|
void xt_gui_geometry_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
247
|
-
const xtgui::DisplayList &list) {
|
|
296
|
+
const xtgui::DisplayList &list, XtGuiUploadBatch *batch) {
|
|
248
297
|
using namespace xtgui::renderer_detail;
|
|
249
|
-
std::vector<Vertex> verts;
|
|
298
|
+
std::vector<Vertex> &verts = g_shape_staging;
|
|
299
|
+
verts.clear();
|
|
250
300
|
verts.reserve(list.rects.size() * 6);
|
|
251
301
|
geometry->op_counts.assign(list.rects.size(), 0);
|
|
252
302
|
/* Walk painter order so each rectangle carries its op's clip path. */
|
|
@@ -256,7 +306,7 @@ void xt_gui_geometry_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
|
256
306
|
pushShape(verts, list.rects[op.index], op.clip, list);
|
|
257
307
|
geometry->op_counts[op.index] = (uint32_t)verts.size() - before;
|
|
258
308
|
}
|
|
259
|
-
uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(Vertex));
|
|
309
|
+
uploadVertices(device, geometry, verts.data(), (uint32_t)verts.size(), sizeof(Vertex), batch);
|
|
260
310
|
}
|
|
261
311
|
|
|
262
312
|
void xt_gui_build_runs(XtGuiGeometry *shapes, XtGuiGeometry *texts, XtGuiGeometry *images,
|
|
@@ -310,6 +360,35 @@ void xt_gui_renderer_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass,
|
|
|
310
360
|
|
|
311
361
|
int target_width = (int)(viewport_width * pixel_density + 0.5f);
|
|
312
362
|
int target_height = (int)(viewport_height * pixel_density + 0.5f);
|
|
363
|
+
/* A run list alternates pipelines (background, text, background, …), so the
|
|
364
|
+
* same scissor rectangle and the same pipeline were re-bound for every run.
|
|
365
|
+
* Track what is bound and only issue the state change when it actually
|
|
366
|
+
* changes: a 1,000-row list has hundreds of runs. */
|
|
367
|
+
SDL_Rect bound_scissor;
|
|
368
|
+
bound_scissor.x = -1;
|
|
369
|
+
bound_scissor.y = -1;
|
|
370
|
+
bound_scissor.w = -1;
|
|
371
|
+
bound_scissor.h = -1;
|
|
372
|
+
int bound_pipeline = -1;
|
|
373
|
+
SDL_GPUTexture *bound_texture = nullptr;
|
|
374
|
+
auto bindPipeline = [&](int pipeline, SDL_GPUBuffer *buffer, SDL_GPUGraphicsPipeline *gpu) {
|
|
375
|
+
if (bound_pipeline == pipeline) return;
|
|
376
|
+
SDL_BindGPUGraphicsPipeline(pass, gpu);
|
|
377
|
+
SDL_GPUBufferBinding binding;
|
|
378
|
+
binding.buffer = buffer;
|
|
379
|
+
binding.offset = 0;
|
|
380
|
+
SDL_BindGPUVertexBuffers(pass, 0, &binding, 1);
|
|
381
|
+
bound_pipeline = pipeline;
|
|
382
|
+
bound_texture = nullptr; // a new pipeline invalidates the bound sampler
|
|
383
|
+
};
|
|
384
|
+
auto bindTexture = [&](SDL_GPUTexture *texture) {
|
|
385
|
+
if (bound_texture == texture) return;
|
|
386
|
+
SDL_GPUTextureSamplerBinding texture_binding;
|
|
387
|
+
texture_binding.texture = texture;
|
|
388
|
+
texture_binding.sampler = g_sampler;
|
|
389
|
+
SDL_BindGPUFragmentSamplers(pass, 0, &texture_binding, 1);
|
|
390
|
+
bound_texture = texture;
|
|
391
|
+
};
|
|
313
392
|
for (const XtGuiDrawRun &run : shapes->runs) {
|
|
314
393
|
SDL_Rect scissor;
|
|
315
394
|
scissor.x = 0;
|
|
@@ -330,42 +409,31 @@ void xt_gui_renderer_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass,
|
|
|
330
409
|
scissor.w = x1 > x0 ? x1 - x0 : 0;
|
|
331
410
|
scissor.h = y1 > y0 ? y1 - y0 : 0;
|
|
332
411
|
}
|
|
333
|
-
|
|
412
|
+
if (scissor.x != bound_scissor.x || scissor.y != bound_scissor.y ||
|
|
413
|
+
scissor.w != bound_scissor.w || scissor.h != bound_scissor.h) {
|
|
414
|
+
SDL_SetGPUScissor(pass, &scissor);
|
|
415
|
+
bound_scissor = scissor;
|
|
416
|
+
}
|
|
334
417
|
|
|
335
418
|
if (run.pipeline == XtGuiDrawRun::Shape) {
|
|
336
419
|
if (g_pipeline == nullptr || shapes->buffer == nullptr) continue;
|
|
337
|
-
|
|
338
|
-
SDL_GPUBufferBinding binding;
|
|
339
|
-
binding.buffer = shapes->buffer;
|
|
340
|
-
binding.offset = 0;
|
|
341
|
-
SDL_BindGPUVertexBuffers(pass, 0, &binding, 1);
|
|
420
|
+
bindPipeline(XtGuiDrawRun::Shape, shapes->buffer, g_pipeline);
|
|
342
421
|
SDL_DrawGPUPrimitives(pass, run.count, 1, run.first, 0);
|
|
422
|
+
xtgui::g_perf_frame.drawCalls += 1;
|
|
343
423
|
} else if (run.pipeline == XtGuiDrawRun::Text) {
|
|
344
424
|
if (!g_text_ok || g_atlas_texture == nullptr || texts->buffer == nullptr) continue;
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
binding.buffer = texts->buffer;
|
|
348
|
-
binding.offset = 0;
|
|
349
|
-
SDL_BindGPUVertexBuffers(pass, 0, &binding, 1);
|
|
350
|
-
SDL_GPUTextureSamplerBinding atlas_binding;
|
|
351
|
-
atlas_binding.texture = g_atlas_texture;
|
|
352
|
-
atlas_binding.sampler = g_sampler;
|
|
353
|
-
SDL_BindGPUFragmentSamplers(pass, 0, &atlas_binding, 1);
|
|
425
|
+
bindPipeline(XtGuiDrawRun::Text, texts->buffer, g_text_pipeline);
|
|
426
|
+
bindTexture(g_atlas_texture);
|
|
354
427
|
SDL_DrawGPUPrimitives(pass, run.count, 1, run.first, 0);
|
|
428
|
+
xtgui::g_perf_frame.drawCalls += 1;
|
|
355
429
|
} else {
|
|
356
430
|
if (g_image_pipeline == nullptr || g_sampler == nullptr || images->buffer == nullptr ||
|
|
357
431
|
run.texture == nullptr)
|
|
358
432
|
continue;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
binding.buffer = images->buffer;
|
|
362
|
-
binding.offset = 0;
|
|
363
|
-
SDL_BindGPUVertexBuffers(pass, 0, &binding, 1);
|
|
364
|
-
SDL_GPUTextureSamplerBinding texture_binding;
|
|
365
|
-
texture_binding.texture = run.texture;
|
|
366
|
-
texture_binding.sampler = g_sampler;
|
|
367
|
-
SDL_BindGPUFragmentSamplers(pass, 0, &texture_binding, 1);
|
|
433
|
+
bindPipeline(XtGuiDrawRun::Image, images->buffer, g_image_pipeline);
|
|
434
|
+
bindTexture(run.texture);
|
|
368
435
|
SDL_DrawGPUPrimitives(pass, run.count, 1, run.first, 0);
|
|
436
|
+
xtgui::g_perf_frame.drawCalls += 1;
|
|
369
437
|
}
|
|
370
438
|
}
|
|
371
439
|
|
|
@@ -50,6 +50,10 @@ struct XtGuiGeometry {
|
|
|
50
50
|
uint32_t capacity_bytes = 0;
|
|
51
51
|
uint32_t vertex_count = 0;
|
|
52
52
|
bool dirty = true;
|
|
53
|
+
/** Reusable upload staging buffer (grown on demand), so a repaint does not
|
|
54
|
+
* create and destroy a transfer buffer for every vertex array. */
|
|
55
|
+
SDL_GPUTransferBuffer *staging = nullptr;
|
|
56
|
+
uint32_t staging_capacity = 0;
|
|
53
57
|
/** Vertex count contributed by each shape of this pipeline's kind, aligned
|
|
54
58
|
* with the display list's payload vector (used to build the run list). */
|
|
55
59
|
std::vector<uint32_t> op_counts;
|
|
@@ -61,6 +65,20 @@ struct XtGuiGeometry {
|
|
|
61
65
|
std::vector<XtGuiDrawRun> runs;
|
|
62
66
|
};
|
|
63
67
|
|
|
68
|
+
/** One GPU command buffer shared by every upload a frame performs (shape, text,
|
|
69
|
+
* glyph atlas and image geometry), so a dirty frame submits its copy passes
|
|
70
|
+
* once instead of once per buffer. Uploads recorded into a batch must be
|
|
71
|
+
* finished by `xt_gui_upload_end` before the render pass is recorded. */
|
|
72
|
+
struct XtGuiUploadBatch {
|
|
73
|
+
SDL_GPUDevice *device = nullptr;
|
|
74
|
+
SDL_GPUCommandBuffer *cmd = nullptr;
|
|
75
|
+
int recorded = 0;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
void xt_gui_upload_begin(XtGuiUploadBatch *batch, SDL_GPUDevice *device);
|
|
79
|
+
/** Submit the batch if anything was recorded (no-op otherwise). */
|
|
80
|
+
void xt_gui_upload_end(XtGuiUploadBatch *batch);
|
|
81
|
+
|
|
64
82
|
/** Create the shared pipelines if needed. Returns false when the backend has no
|
|
65
83
|
* shader format we support (the caller then skips geometry). */
|
|
66
84
|
bool xt_gui_renderer_ensure(SDL_GPUDevice *device, SDL_Window *reference);
|
|
@@ -68,9 +86,11 @@ bool xt_gui_renderer_ensure(SDL_GPUDevice *device, SDL_Window *reference);
|
|
|
68
86
|
void xt_gui_renderer_destroy(SDL_GPUDevice *device);
|
|
69
87
|
/** Release a window's vertex buffer (after SDL_WaitForGPUIdle). */
|
|
70
88
|
void xt_gui_geometry_destroy(SDL_GPUDevice *device, XtGuiGeometry *geometry);
|
|
71
|
-
/** Upload the rectangle geometry from `list`
|
|
89
|
+
/** Upload the rectangle geometry from `list`. With a `batch` the copy pass is
|
|
90
|
+
* recorded into the frame's shared command buffer; otherwise it is submitted
|
|
91
|
+
* immediately. */
|
|
72
92
|
void xt_gui_geometry_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
73
|
-
const xtgui::DisplayList &list);
|
|
93
|
+
const xtgui::DisplayList &list, XtGuiUploadBatch *batch = nullptr);
|
|
74
94
|
/** Draw `geometry` inside an active render pass. */
|
|
75
95
|
void xt_gui_renderer_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass,
|
|
76
96
|
XtGuiGeometry *shapes, XtGuiGeometry *texts, XtGuiGeometry *images,
|
|
@@ -78,13 +98,15 @@ void xt_gui_renderer_draw(SDL_GPUCommandBuffer *cmd, SDL_GPURenderPass *pass,
|
|
|
78
98
|
/** Shape `list.texts`, ensure their glyphs are in the atlas, and upload the
|
|
79
99
|
* text geometry. `scale` is the device pixel density (1.0 = logical pixels). */
|
|
80
100
|
void xt_gui_text_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
81
|
-
const xtgui::DisplayList &list, float scale
|
|
101
|
+
const xtgui::DisplayList &list, float scale,
|
|
102
|
+
XtGuiUploadBatch *batch = nullptr);
|
|
82
103
|
/** Decode/upload `list.images` and build the image quad geometry (one batch per
|
|
83
104
|
* texture). Textures are cached by source path and pixel size. `scale` is the
|
|
84
105
|
* device pixel density (1.0 = logical pixels) used to pick the rasterisation
|
|
85
106
|
* size of a vector source (SVG); raster sources decode at their intrinsic size. */
|
|
86
107
|
void xt_gui_image_upload(SDL_GPUDevice *device, XtGuiGeometry *geometry,
|
|
87
|
-
const xtgui::DisplayList &list, float scale
|
|
108
|
+
const xtgui::DisplayList &list, float scale,
|
|
109
|
+
XtGuiUploadBatch *batch = nullptr);
|
|
88
110
|
/** Release the image texture cache (after SDL_WaitForGPUIdle). */
|
|
89
111
|
void xt_gui_image_textures_destroy(SDL_GPUDevice *device);
|
|
90
112
|
/** Build the painter-order run list from the display list, using the per-op
|
|
@@ -94,14 +116,16 @@ void xt_gui_build_runs(XtGuiGeometry *shapes, XtGuiGeometry *texts, XtGuiGeometr
|
|
|
94
116
|
const xtgui::DisplayList &list);
|
|
95
117
|
/** Re-upload the current decoded frame of every live `<video>` texture. Called
|
|
96
118
|
* once per frame, before the render command buffer, so the texture sampled by
|
|
97
|
-
* the draw already holds that frame.
|
|
98
|
-
|
|
119
|
+
* the draw already holds that frame. Returns true when a texture was uploaded
|
|
120
|
+
* (the frame loop then presents even without a DOM change). */
|
|
121
|
+
bool xt_gui_media_upload_frames(SDL_GPUDevice *device, XtGuiUploadBatch *batch = nullptr);
|
|
99
122
|
/** Release one media texture (when a `<video>` is removed or navigated away). */
|
|
100
123
|
void xt_gui_media_texture_release(SDL_GPUDevice *device, uint64_t media_id);
|
|
101
|
-
/** Re-upload the
|
|
124
|
+
/** Re-upload the dirty region of every live `<canvas>` texture. Called once
|
|
102
125
|
* per frame, before the render command buffer, so a canvas animated from
|
|
103
|
-
* `requestAnimationFrame` reaches the screen without a relayout.
|
|
104
|
-
|
|
126
|
+
* `requestAnimationFrame` reaches the screen without a relayout. Returns true
|
|
127
|
+
* when a texture was uploaded. */
|
|
128
|
+
bool xt_gui_canvas_upload_frames(SDL_GPUDevice *device, XtGuiUploadBatch *batch = nullptr);
|
|
105
129
|
/** Release one canvas texture (when the canvas is dropped). */
|
|
106
130
|
void xt_gui_canvas_texture_release(SDL_GPUDevice *device, uint64_t canvas_id);
|
|
107
131
|
|