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.
Files changed (166) hide show
  1. package/dist/src/cli/help.d.ts +1 -1
  2. package/dist/src/codegen/generator/module.js +23 -7
  3. package/dist/src/codegen/generator/module.js.map +1 -1
  4. package/dist/src/codegen/generator/state.js +1 -0
  5. package/dist/src/codegen/generator/state.js.map +1 -1
  6. package/dist/src/codegen/generator/tables.js +1 -0
  7. package/dist/src/codegen/generator/tables.js.map +1 -1
  8. package/dist/src/driver/bundler/deferred.d.ts +63 -0
  9. package/dist/src/driver/bundler/deferred.js +279 -0
  10. package/dist/src/driver/bundler/deferred.js.map +1 -0
  11. package/dist/src/driver/bundler/merge.js +214 -2
  12. package/dist/src/driver/bundler/merge.js.map +1 -1
  13. package/dist/src/driver/runtime-objects.d.ts +1 -1
  14. package/dist/src/driver/runtime-objects.js +1 -0
  15. package/dist/src/driver/runtime-objects.js.map +1 -1
  16. package/dist/src/driver/version.d.ts +1 -1
  17. package/dist/src/driver/version.js +1 -1
  18. package/dist/src/extensions/gui/html.js +98 -15
  19. package/dist/src/extensions/gui/html.js.map +1 -1
  20. package/dist/src/extensions/gui/index.js +1 -0
  21. package/dist/src/extensions/gui/index.js.map +1 -1
  22. package/dist/src/extensions/gui/three.d.ts +4 -3
  23. package/dist/src/extensions/gui/three.js +4 -3
  24. package/dist/src/extensions/gui/three.js.map +1 -1
  25. package/dist/tests/codegen/closures.test.js +7 -0
  26. package/dist/tests/codegen/closures.test.js.map +1 -1
  27. package/dist/tests/e2e/compile-objects-classes.test.js +31 -0
  28. package/dist/tests/e2e/compile-objects-classes.test.js.map +1 -1
  29. package/dist/tests/e2e/gui-canvas-state.test.d.ts +9 -0
  30. package/dist/tests/e2e/gui-canvas-state.test.js +297 -0
  31. package/dist/tests/e2e/gui-canvas-state.test.js.map +1 -0
  32. package/dist/tests/e2e/gui-draw-perf.test.d.ts +22 -0
  33. package/dist/tests/e2e/gui-draw-perf.test.js +405 -0
  34. package/dist/tests/e2e/gui-draw-perf.test.js.map +1 -0
  35. package/dist/tests/e2e/gui-perf.test.d.ts +23 -0
  36. package/dist/tests/e2e/gui-perf.test.js +283 -0
  37. package/dist/tests/e2e/gui-perf.test.js.map +1 -0
  38. package/dist/tests/e2e/gui-script-import-order.test.d.ts +10 -0
  39. package/dist/tests/e2e/gui-script-import-order.test.js +169 -0
  40. package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -0
  41. package/dist/tests/e2e/gui-webgl.test.js +4 -4
  42. package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
  43. package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.d.ts +8 -0
  44. package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js +336 -0
  45. package/dist/tests/e2e/gui-webgl2-shadow-sampler.test.js.map +1 -0
  46. package/dist/tests/e2e/gui-webgl2-shadow.test.d.ts +10 -0
  47. package/dist/tests/e2e/gui-webgl2-shadow.test.js +108 -0
  48. package/dist/tests/e2e/gui-webgl2-shadow.test.js.map +1 -0
  49. package/dist/tests/e2e/url.test.d.ts +6 -0
  50. package/dist/tests/e2e/url.test.js +114 -0
  51. package/dist/tests/e2e/url.test.js.map +1 -0
  52. package/dist/tests/extensions/gui.test.js +45 -10
  53. package/dist/tests/extensions/gui.test.js.map +1 -1
  54. package/doc/gui/api.md +28 -2
  55. package/doc/gui/canvas.md +110 -27
  56. package/doc/gui/known-issues.md +32 -10
  57. package/doc/gui/rendering.md +77 -0
  58. package/doc/gui/runtime.md +18 -3
  59. package/doc/gui/webgl.md +58 -29
  60. package/doc/gui-scripts.md +19 -19
  61. package/doc/gui.md +43 -9
  62. package/doc/implemented/fetch.md +5 -0
  63. package/doc/implemented/modules.md +13 -0
  64. package/doc/implemented/stdlib.md +17 -0
  65. package/doc/unimplemented/deviations.md +1 -0
  66. package/doc/zh-CN/gui/api.md +25 -2
  67. package/doc/zh-CN/gui/canvas.md +95 -26
  68. package/doc/zh-CN/gui/known-issues.md +21 -4
  69. package/doc/zh-CN/gui/rendering.md +59 -0
  70. package/doc/zh-CN/gui/runtime.md +13 -3
  71. package/doc/zh-CN/gui/webgl.md +30 -8
  72. package/doc/zh-CN/gui-scripts.md +14 -13
  73. package/doc/zh-CN/gui.md +32 -8
  74. package/doc/zh-CN/implemented/fetch.md +4 -0
  75. package/doc/zh-CN/implemented/modules.md +10 -0
  76. package/doc/zh-CN/implemented/stdlib.md +15 -0
  77. package/doc/zh-CN/unimplemented/deviations.md +1 -0
  78. package/package.json +7 -7
  79. package/runtime/ext_gui/browser.cpp +3 -1
  80. package/runtime/ext_gui/canvas.cpp +135 -89
  81. package/runtime/ext_gui/canvas.h +116 -0
  82. package/runtime/ext_gui/canvas_clip.cpp +143 -0
  83. package/runtime/ext_gui/canvas_composite.cpp +241 -0
  84. package/runtime/ext_gui/canvas_coverage.cpp +241 -0
  85. package/runtime/ext_gui/canvas_gradient.cpp +41 -4
  86. package/runtime/ext_gui/canvas_image_data.cpp +4 -0
  87. package/runtime/ext_gui/canvas_internal.h +34 -9
  88. package/runtime/ext_gui/canvas_raster.cpp +207 -178
  89. package/runtime/ext_gui/canvas_shadow.cpp +161 -0
  90. package/runtime/ext_gui/canvas_stroke.cpp +37 -9
  91. package/runtime/ext_gui/canvas_style.cpp +59 -0
  92. package/runtime/ext_gui/canvas_text.cpp +140 -0
  93. package/runtime/ext_gui/css.h +7 -0
  94. package/runtime/ext_gui/css_sheet.cpp +22 -0
  95. package/runtime/ext_gui/document.cpp +25 -1
  96. package/runtime/ext_gui/document.h +8 -0
  97. package/runtime/ext_gui/dom_api_canvas.cpp +16 -1
  98. package/runtime/ext_gui/dom_api_canvas_image.cpp +9 -0
  99. package/runtime/ext_gui/dom_api_canvas_state.cpp +217 -0
  100. package/runtime/ext_gui/dom_api_internal.h +36 -37
  101. package/runtime/ext_gui/dom_api_offscreen.cpp +213 -0
  102. package/runtime/ext_gui/dom_api_proto.cpp +18 -0
  103. package/runtime/ext_gui/dom_api_webgl.cpp +29 -9
  104. package/runtime/ext_gui/dom_api_webgl2.cpp +33 -1
  105. package/runtime/ext_gui/dom_api_webgl_internal.h +58 -0
  106. package/runtime/ext_gui/dom_api_webgl_source.cpp +18 -0
  107. package/runtime/ext_gui/gradient_values.cpp +12 -1
  108. package/runtime/ext_gui/gui.cpp +5 -0
  109. package/runtime/ext_gui/gui_canvas.cpp +4 -0
  110. package/runtime/ext_gui/gui_engine.h +32 -0
  111. package/runtime/ext_gui/gui_events.cpp +182 -58
  112. package/runtime/ext_gui/gui_media.cpp +3 -0
  113. package/runtime/ext_gui/image.cpp +69 -0
  114. package/runtime/ext_gui/image_bitmap_browser.cpp +11 -0
  115. package/runtime/ext_gui/layout.cpp +4 -0
  116. package/runtime/ext_gui/paint.cpp +19 -0
  117. package/runtime/ext_gui/paint_background.cpp +18 -1
  118. package/runtime/ext_gui/perf.cpp +171 -0
  119. package/runtime/ext_gui/perf.h +127 -0
  120. package/runtime/ext_gui/renderer.cpp +109 -41
  121. package/runtime/ext_gui/renderer.h +33 -9
  122. package/runtime/ext_gui/renderer_image.cpp +135 -65
  123. package/runtime/ext_gui/renderer_internal.h +15 -3
  124. package/runtime/ext_gui/renderer_text.cpp +24 -12
  125. package/runtime/ext_gui/script.cpp +31 -0
  126. package/runtime/ext_gui/style.cpp +101 -30
  127. package/runtime/ext_gui/style.h +6 -3
  128. package/runtime/ext_gui/style_print.cpp +7 -1
  129. package/runtime/ext_gui/text.cpp +23 -4
  130. package/runtime/ext_gui/text.h +29 -0
  131. package/runtime/ext_gui/text_cache.cpp +118 -0
  132. package/runtime/ext_gui/text_glyph_cache.cpp +100 -0
  133. package/runtime/ext_gui/webgl.h +48 -146
  134. package/runtime/ext_gui/webgl_blit.cpp +12 -1
  135. package/runtime/ext_gui/webgl_blit_depth.cpp +270 -0
  136. package/runtime/ext_gui/webgl_buffer.cpp +59 -1
  137. package/runtime/ext_gui/webgl_buffer_objects.cpp +106 -9
  138. package/runtime/ext_gui/webgl_clear.cpp +3 -0
  139. package/runtime/ext_gui/webgl_context.cpp +29 -3
  140. package/runtime/ext_gui/webgl_draw.cpp +75 -270
  141. package/runtime/ext_gui/webgl_draw_buffers.cpp +1 -0
  142. package/runtime/ext_gui/webgl_draw_setup.cpp +321 -0
  143. package/runtime/ext_gui/webgl_draw_state.h +130 -0
  144. package/runtime/ext_gui/webgl_glsl.h +3 -0
  145. package/runtime/ext_gui/webgl_glsl_scan.cpp +3 -8
  146. package/runtime/ext_gui/webgl_glsl_unroll.cpp +283 -0
  147. package/runtime/ext_gui/webgl_msl.cpp +4 -0
  148. package/runtime/ext_gui/webgl_objects.h +148 -0
  149. package/runtime/ext_gui/webgl_pipeline.cpp +8 -8
  150. package/runtime/ext_gui/webgl_program_internal.h +35 -0
  151. package/runtime/ext_gui/webgl_shader.cpp +34 -36
  152. package/runtime/ext_gui/webgl_webgl2.cpp +36 -0
  153. package/runtime/ext_gui/window.cpp +56 -1
  154. package/runtime/rt.h +3 -0
  155. package/runtime/xt_fetch/async.inc +60 -0
  156. package/runtime/xt_url_object.c +463 -0
  157. package/src/codegen/generator/module.ts +22 -7
  158. package/src/codegen/generator/state.ts +1 -0
  159. package/src/codegen/generator/tables.ts +1 -0
  160. package/src/driver/bundler/deferred.ts +351 -0
  161. package/src/driver/bundler/merge.ts +219 -2
  162. package/src/driver/runtime-objects.ts +1 -0
  163. package/src/driver/version.ts +1 -1
  164. package/src/extensions/gui/html.ts +100 -17
  165. package/src/extensions/gui/index.ts +1 -0
  166. package/src/extensions/gui/three.ts +4 -3
@@ -3,22 +3,24 @@
3
3
  *
4
4
  * SDL_GPU has no dynamic state for blend/depth/rasterisation: those live in a
5
5
  * `SDL_GPUGraphicsPipeline`. WebGL changes them with `glEnable`/`glDepthFunc`,
6
- * so a pipeline is built lazily per (program, vertex layout, the subset of
7
- * fixed-function state that matters) and cached on the program.
6
+ * so a pipeline is built lazily per (program, vertex layout, state) and cached.
8
7
  *
9
- * A matrix attribute consumes several consecutive vertex locations; the
10
- * pipeline spells out one `SDL_GPUVertexAttribute` per column, all reading the
11
- * same vertex buffer binding.
8
+ * A draw is mostly a cache lookup: `prepare_draw` returns the pipeline plus the
9
+ * vertex-layout bindings for the current state, and a repeated draw in the same
10
+ * render pass is one pipeline bind (when it changed) and one `SDL_Draw*` call.
11
+ * Everything that needs a GPU upload (buffer/texture data, an expanded index
12
+ * list, a constant attribute) records that upload *before* `begin_pass`, so an
13
+ * unchanged sequence of draws never ends the pass it is recording into.
12
14
  */
13
15
 
14
16
  #include "webgl.h"
15
17
 
16
18
  #include <algorithm>
17
19
  #include <cstring>
18
- #include <string>
19
20
  #include <vector>
20
21
 
21
22
  #include "gui_internal.h"
23
+ #include "perf.h"
22
24
 
23
25
  namespace xtgui {
24
26
  namespace {
@@ -36,150 +38,6 @@ int type_size(int type) {
36
38
  }
37
39
  }
38
40
 
39
- int components_of_type(const std::string &type) {
40
- if (!type.empty() && type.back() >= '2' && type.back() <= '4') return type.back() - '0';
41
- return 1;
42
- }
43
-
44
- SDL_GPUVertexElementFormat float_format(int size) {
45
- switch (size) {
46
- case 1:
47
- return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT;
48
- case 2:
49
- return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
50
- case 3:
51
- return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
52
- default:
53
- return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4;
54
- }
55
- }
56
-
57
- SDL_GPUVertexElementFormat format_of(int size, int type, bool normalized) {
58
- if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
59
- if (type == GL_FLOAT) return float_format(size);
60
- if (type == GL_UNSIGNED_BYTE || type == GL_BYTE) {
61
- const bool is_byte = type == GL_BYTE;
62
- if (size == 2) {
63
- return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2_NORM
64
- : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2_NORM)
65
- : (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2
66
- : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2);
67
- }
68
- if (size == 4) {
69
- return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4_NORM
70
- : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM)
71
- : (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4
72
- : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4);
73
- }
74
- return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
75
- }
76
- if (type == GL_UNSIGNED_SHORT || type == GL_SHORT) {
77
- const bool is_short = type == GL_SHORT;
78
- if (size == 2) {
79
- return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2_NORM
80
- : SDL_GPU_VERTEXELEMENTFORMAT_USHORT2_NORM)
81
- : (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2
82
- : SDL_GPU_VERTEXELEMENTFORMAT_USHORT2);
83
- }
84
- if (size == 4) {
85
- return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4_NORM
86
- : SDL_GPU_VERTEXELEMENTFORMAT_USHORT4_NORM)
87
- : (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4
88
- : SDL_GPU_VERTEXELEMENTFORMAT_USHORT4);
89
- }
90
- return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
91
- }
92
- return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
93
- }
94
-
95
- /** `vertexAttribIPointer` formats: integer attributes keep their integer type
96
- * in the shader (`in ivec3 …`). SDL has no 1- or 3-component byte/short
97
- * integer formats, so only the sizes it can express are accepted. */
98
- SDL_GPUVertexElementFormat int_format_of(int size, int type) {
99
- if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
100
- if (type == GL_INT) {
101
- switch (size) {
102
- case 1:
103
- return SDL_GPU_VERTEXELEMENTFORMAT_INT;
104
- case 2:
105
- return SDL_GPU_VERTEXELEMENTFORMAT_INT2;
106
- case 3:
107
- return SDL_GPU_VERTEXELEMENTFORMAT_INT3;
108
- default:
109
- return SDL_GPU_VERTEXELEMENTFORMAT_INT4;
110
- }
111
- }
112
- if (type == GL_UNSIGNED_INT) {
113
- switch (size) {
114
- case 1:
115
- return SDL_GPU_VERTEXELEMENTFORMAT_UINT;
116
- case 2:
117
- return SDL_GPU_VERTEXELEMENTFORMAT_UINT2;
118
- case 3:
119
- return SDL_GPU_VERTEXELEMENTFORMAT_UINT3;
120
- default:
121
- return SDL_GPU_VERTEXELEMENTFORMAT_UINT4;
122
- }
123
- }
124
- if (type == GL_SHORT && (size == 2 || size == 4)) {
125
- return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2 : SDL_GPU_VERTEXELEMENTFORMAT_SHORT4;
126
- }
127
- if (type == GL_UNSIGNED_SHORT && (size == 2 || size == 4)) {
128
- return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_USHORT2
129
- : SDL_GPU_VERTEXELEMENTFORMAT_USHORT4;
130
- }
131
- if (type == GL_BYTE && (size == 2 || size == 4)) {
132
- return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_BYTE4;
133
- }
134
- if (type == GL_UNSIGNED_BYTE && (size == 2 || size == 4)) {
135
- return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4;
136
- }
137
- return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
138
- }
139
-
140
- /** A cache key covering everything (other than the program) that a
141
- * `SDL_GPUGraphicsPipeline` bakes in. */
142
- std::string pipeline_key(int mode, int index_size,
143
- const std::vector<SDL_GPUVertexAttribute> &attrs,
144
- const std::vector<SDL_GPUVertexBufferDescription> &buffers,
145
- const WebGLDrawState &state) {
146
- std::string key = std::to_string(mode) + "/" + std::to_string(index_size);
147
- key += "/f" + std::to_string(state.color_target_count) + ":";
148
- for (int i = 0; i < state.color_target_count; i++) {
149
- key += std::to_string(state.color_formats[i]) + ",";
150
- }
151
- key += ":" + std::to_string(state.depth_format);
152
- for (const SDL_GPUVertexAttribute &attr : attrs) {
153
- key += "/" + std::to_string(attr.location) + ":" + std::to_string(attr.buffer_slot) + ":" +
154
- std::to_string((int)attr.format) + ":" + std::to_string(attr.offset);
155
- }
156
- for (const SDL_GPUVertexBufferDescription &buffer : buffers) {
157
- key += "|" + std::to_string(buffer.slot) + ":" + std::to_string(buffer.pitch) + ":" +
158
- std::to_string((int)buffer.input_rate);
159
- }
160
- char state_key[256];
161
- snprintf(state_key, sizeof(state_key), "|%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
162
- (int)state.blend, state.blend_src_rgb, state.blend_dst_rgb, state.blend_src_alpha,
163
- state.blend_dst_alpha, state.blend_eq_rgb, state.blend_eq_alpha, (int)state.depth_test,
164
- (int)state.depth_write, state.depth_func, (int)state.cull, state.cull_face,
165
- state.front_face, (int)state.color_mask[0]);
166
- key += state_key;
167
- key += std::to_string((int)state.color_mask[1]);
168
- key += std::to_string((int)state.color_mask[2]);
169
- key += std::to_string((int)state.color_mask[3]);
170
- char stencil_key[224];
171
- snprintf(stencil_key, sizeof(stencil_key), "|s%d,%d,%d,%d,%d,%u,%d,%d,%d,%d,%u,%u,%u",
172
- (int)state.stencil, state.stencil_front.func, state.stencil_front.fail,
173
- state.stencil_front.zfail, state.stencil_front.zpass,
174
- (unsigned)state.stencil_front.write_mask, state.stencil_back.func,
175
- state.stencil_back.fail, state.stencil_back.zfail, state.stencil_back.zpass,
176
- (unsigned)state.stencil_back.write_mask,
177
- (unsigned)state.stencil_front.value_mask,
178
- (unsigned)state.stencil_front.write_mask);
179
- key += stencil_key;
180
- return key;
181
- }
182
-
183
41
  } // namespace
184
42
 
185
43
  void WebGLContext::draw_arrays(int mode, int first, int count) {
@@ -233,6 +91,7 @@ void WebGLContext::draw_range_elements(int mode, int start, int end, int count,
233
91
  void WebGLContext::draw(int mode, int first, int count, int index_type, int offset,
234
92
  int instances) {
235
93
  if (count <= 0) return;
94
+ g_perf_frame.webglDraws += 1;
236
95
  WebGLProgram *program_ = program(current_program_);
237
96
  if (program_ == nullptr || !program_->linked || program_->vs_shader == nullptr) {
238
97
  set_error(GL_INVALID_OPERATION);
@@ -244,13 +103,14 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
244
103
  return;
245
104
  }
246
105
  ensure_fallback();
247
- end_pass();
248
106
  ensure_command();
107
+ if (cmd_ == nullptr) return;
249
108
 
250
109
  /* Expand source indices when the draw needs a primitive SDL_GPU lacks or a
251
- * byte-sized index type. */
110
+ * byte-sized index type. These are per-draw temporary buffers: they change
111
+ * the index buffer, not the pipeline, so they stay out of the setup cache. */
252
112
  std::vector<uint32_t> expanded;
253
- SDL_GPUBuffer *index_gpu = nullptr;
113
+ SDL_GPUBuffer *expanded_gpu = nullptr;
254
114
  int index_size = 0;
255
115
  int first_index = 0;
256
116
  int draw_mode = mode;
@@ -302,10 +162,10 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
302
162
  }
303
163
  index_size = 4;
304
164
  if (!expanded.empty()) {
305
- index_gpu = upload_temp_buffer(expanded.data(),
306
- (uint32_t)(expanded.size() * sizeof(uint32_t)),
307
- SDL_GPU_BUFFERUSAGE_INDEX);
308
- if (index_gpu == nullptr) return;
165
+ expanded_gpu = upload_temp_buffer(expanded.data(),
166
+ (uint32_t)(expanded.size() * sizeof(uint32_t)),
167
+ SDL_GPU_BUFFERUSAGE_INDEX);
168
+ if (expanded_gpu == nullptr) return;
309
169
  }
310
170
  } else if (index_type != 0) {
311
171
  WebGLBuffer *element = buffer(bound_element_);
@@ -313,8 +173,6 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
313
173
  set_error(GL_INVALID_OPERATION);
314
174
  return;
315
175
  }
316
- index_gpu = ensure_buffer_gpu(element);
317
- if (index_gpu == nullptr) return;
318
176
  index_size = type_size(index_type) == 4 ? 4 : 2;
319
177
  first_index = offset / index_size;
320
178
  }
@@ -333,77 +191,18 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
333
191
  if (state_.color_target_count == 0) state_.color_target_count = 1;
334
192
  state_.depth_format = target_depth_format();
335
193
 
336
- std::vector<SDL_GPUVertexAttribute> attributes;
337
- std::vector<SDL_GPUVertexBufferDescription> buffers;
338
- std::vector<SDL_GPUBufferBinding> bindings;
194
+ WebGLDrawKey key;
195
+ key.program = current_program_;
196
+ key.mode = draw_mode;
197
+ key.index_size = index_size;
198
+ key.element_buffer = !needs_expand && index_size > 0 ? bound_element_ : 0;
199
+ key.attribs_version = attribs_version_;
200
+ key.gpu_version = gpu_version_;
201
+ key.framebuffer_version = framebuffer_version_;
202
+ draw_state_hash(&key.state_hash, &key.state_hash2);
339
203
 
340
- for (const GlslUniformDecl &decl : program_->attribs) {
341
- auto location_it = program_->attrib_locations.find(decl.name);
342
- if (location_it == program_->attrib_locations.end()) continue;
343
- const int base_location = location_it->second;
344
- if (base_location < 0 || base_location >= kWebGLMaxAttribs) continue;
345
- WebGLAttribState &attrib = attribs_[base_location];
346
- const int slots = decl.type == "mat2" ? 2 : (decl.type == "mat3" ? 3 : (decl.type == "mat4" ? 4 : 1));
347
- const int components = slots > 1 ? slots : (components_of_type(decl.type) > 4 ? 4
348
- : components_of_type(decl.type));
349
- const uint32_t slot = (uint32_t)buffers.size();
350
- SDL_GPUVertexBufferDescription description;
351
- memset(&description, 0, sizeof(description));
352
- description.slot = slot;
353
- description.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
354
- SDL_GPUBufferBinding binding;
355
- memset(&binding, 0, sizeof(binding));
356
- if (!attrib.enabled) {
357
- float values[4] = {attrib.current[0], attrib.current[1], attrib.current[2], attrib.current[3]};
358
- binding.buffer = upload_temp_buffer(values, sizeof(values), SDL_GPU_BUFFERUSAGE_VERTEX);
359
- description.pitch = 0;
360
- if (binding.buffer == nullptr) continue;
361
- for (int column = 0; column < slots; column++) {
362
- SDL_GPUVertexAttribute attribute;
363
- memset(&attribute, 0, sizeof(attribute));
364
- attribute.location = (Uint32)(base_location + column);
365
- attribute.buffer_slot = slot;
366
- attribute.format = float_format(components);
367
- attribute.offset = 0;
368
- attributes.push_back(attribute);
369
- }
370
- buffers.push_back(description);
371
- bindings.push_back(binding);
372
- continue;
373
- }
374
- WebGLBuffer *buffer_ = buffer(attrib.buffer);
375
- if (buffer_ == nullptr || buffer_->data.empty()) {
376
- set_error(GL_INVALID_OPERATION);
377
- return;
378
- }
379
- SDL_GPUVertexElementFormat format = attrib.integer
380
- ? int_format_of(attrib.size, attrib.type)
381
- : format_of(attrib.size, attrib.type, attrib.normalized);
382
- if (format == SDL_GPU_VERTEXELEMENTFORMAT_INVALID) {
383
- set_error(GL_INVALID_OPERATION);
384
- return;
385
- }
386
- description.input_rate = attrib.divisor > 0 ? SDL_GPU_VERTEXINPUTRATE_INSTANCE
387
- : SDL_GPU_VERTEXINPUTRATE_VERTEX;
388
- const int stride =
389
- attrib.stride > 0 ? attrib.stride : components * type_size(attrib.type) * slots;
390
- description.pitch = (Uint32)stride;
391
- SDL_GPUBuffer *gpu = ensure_buffer_gpu(buffer_);
392
- if (gpu == nullptr) return;
393
- binding.buffer = gpu;
394
- binding.offset = 0;
395
- for (int column = 0; column < slots; column++) {
396
- SDL_GPUVertexAttribute attribute;
397
- memset(&attribute, 0, sizeof(attribute));
398
- attribute.location = (Uint32)(base_location + column);
399
- attribute.buffer_slot = slot;
400
- attribute.format = format;
401
- attribute.offset = (Uint32)(attrib.offset + column * components * type_size(attrib.type));
402
- attributes.push_back(attribute);
403
- }
404
- buffers.push_back(description);
405
- bindings.push_back(binding);
406
- }
204
+ const WebGLDrawSetup *setup = prepare_draw(key);
205
+ if (setup == nullptr) return;
407
206
 
408
207
  begin_pass(false, false, false);
409
208
  if (pass_ == nullptr) return;
@@ -443,18 +242,29 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
443
242
  if (scissor.h < 0) scissor.h = 0;
444
243
  SDL_SetGPUScissor(pass_, &scissor);
445
244
 
446
- const std::string key = pipeline_key(draw_mode, index_size, attributes, buffers, state_);
447
- SDL_GPUGraphicsPipeline *pipeline = nullptr;
448
- auto cached = program_->pipeline_cache.find(key);
449
- if (cached != program_->pipeline_cache.end()) {
450
- pipeline = cached->second;
451
- } else {
452
- pipeline = create_pipeline(program_, draw_mode, index_size, (int)attributes.size(),
453
- (int)buffers.size(), attributes.data(), buffers.data(), key);
245
+ /* Bindings belong to the render pass, so a setup reused across an upload (a
246
+ * new pass) must be bound again even though nothing about it changed. */
247
+ if (last_setup_ != setup || last_setup_pass_ != pass_serial_) {
248
+ SDL_BindGPUGraphicsPipeline(pass_, setup->pipeline);
249
+ if (!setup->bindings.empty()) {
250
+ SDL_BindGPUVertexBuffers(pass_, 0, setup->bindings.data(),
251
+ (Uint32)setup->bindings.size());
252
+ }
253
+ SDL_GPUBuffer *index_buffer = index_size > 0 ? (needs_expand ? expanded_gpu : setup->index_buffer)
254
+ : nullptr;
255
+ if (index_buffer != nullptr) {
256
+ SDL_GPUBufferBinding binding;
257
+ memset(&binding, 0, sizeof(binding));
258
+ binding.buffer = index_buffer;
259
+ binding.offset = 0;
260
+ SDL_BindGPUIndexBuffer(pass_, &binding,
261
+ index_size == 4 ? SDL_GPU_INDEXELEMENTSIZE_32BIT
262
+ : SDL_GPU_INDEXELEMENTSIZE_16BIT);
263
+ }
264
+ last_pipeline_ = setup->pipeline;
265
+ last_setup_ = setup;
266
+ last_setup_pass_ = pass_serial_;
454
267
  }
455
- if (pipeline == nullptr) return;
456
-
457
- SDL_BindGPUGraphicsPipeline(pass_, pipeline);
458
268
  if (state_.stencil) {
459
269
  SDL_SetGPUStencilReference(pass_, (Uint8)(stencil_reference() & 0xFF));
460
270
  }
@@ -466,17 +276,6 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
466
276
  constants.a = blend_color_[3];
467
277
  SDL_SetGPUBlendConstants(pass_, constants);
468
278
  }
469
- if (!bindings.empty()) {
470
- SDL_BindGPUVertexBuffers(pass_, 0, bindings.data(), (Uint32)bindings.size());
471
- }
472
- if (index_size > 0) {
473
- SDL_GPUBufferBinding binding;
474
- binding.buffer = index_gpu;
475
- binding.offset = 0;
476
- SDL_BindGPUIndexBuffer(pass_, &binding,
477
- index_size == 4 ? SDL_GPU_INDEXELEMENTSIZE_32BIT
478
- : SDL_GPU_INDEXELEMENTSIZE_16BIT);
479
- }
480
279
  /* User uniform blocks live in the same std140 block; refresh their members
481
280
  * from the CPU-side buffer bound to each block's binding point. */
482
281
  for (const WebGLUniformBlock &block : program_->blocks) {
@@ -485,17 +284,17 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
485
284
  if (binding.buffer == 0) continue;
486
285
  WebGLBuffer *uniform_buffer = buffer(binding.buffer);
487
286
  if (uniform_buffer == nullptr) continue;
488
- size_t offset = binding.offset;
287
+ size_t block_offset = binding.offset;
489
288
  size_t length = (size_t)block.data_size;
490
289
  if (binding.size > 0 && length > binding.size) length = binding.size;
491
- if (offset > uniform_buffer->data.size()) continue;
492
- if (length > uniform_buffer->data.size() - offset) {
493
- length = uniform_buffer->data.size() - offset;
290
+ if (block_offset > uniform_buffer->data.size()) continue;
291
+ if (length > uniform_buffer->data.size() - block_offset) {
292
+ length = uniform_buffer->data.size() - block_offset;
494
293
  }
495
294
  if (block.base_offset >= 0 &&
496
295
  block.base_offset + (int)length <= program_->block_size) {
497
296
  memcpy(program_->block.data() + block.base_offset,
498
- uniform_buffer->data.data() + offset, length);
297
+ uniform_buffer->data.data() + block_offset, length);
499
298
  }
500
299
  }
501
300
 
@@ -503,32 +302,38 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
503
302
  SDL_PushGPUVertexUniformData(cmd_, 0, program_->block.data(), (Uint32)program_->block.size());
504
303
  }
505
304
  if (program_->fs_has_block && program_->block_size > 0) {
506
- SDL_PushGPUFragmentUniformData(cmd_, 0, program_->block.data(), (Uint32)program_->block.size());
305
+ SDL_PushGPUFragmentUniformData(cmd_, 0, program_->block.data(),
306
+ (Uint32)program_->block.size());
507
307
  }
508
308
 
509
309
  auto bind_samplers = [&](const std::vector<int> &stage, bool vertex_stage) {
510
310
  if (stage.empty()) return;
511
- std::vector<SDL_GPUTextureSamplerBinding> sampler_bindings;
512
- sampler_bindings.reserve(stage.size());
311
+ sampler_bindings_.clear();
312
+ sampler_bindings_.reserve(stage.size());
513
313
  for (int uniform_index : stage) {
514
314
  const WebGLUniform &uniform = program_->uniforms[(size_t)uniform_index];
515
315
  const int unit =
516
316
  uniform.unit >= 0 && uniform.unit < kWebGLMaxTextureUnits ? uniform.unit : 0;
517
317
  uint32_t texture_id = bound_textures_[unit];
518
- if (uniform.layout.gl_type == GL_SAMPLER_CUBE) {
318
+ if (uniform.layout.gl_type == GL_SAMPLER_CUBE ||
319
+ uniform.layout.gl_type == GL_SAMPLER_CUBE_SHADOW) {
519
320
  texture_id = bound_cube_textures_[unit];
520
321
  } else if (uniform.layout.gl_type == GL_SAMPLER_3D) {
521
322
  texture_id = bound_3d_textures_[unit];
522
- } else if (uniform.layout.gl_type == GL_SAMPLER_2D_ARRAY) {
323
+ } else if (uniform.layout.gl_type == GL_SAMPLER_2D_ARRAY ||
324
+ uniform.layout.gl_type == GL_SAMPLER_2D_ARRAY_SHADOW) {
523
325
  texture_id = bound_array_textures_[unit];
524
326
  }
525
327
  WebGLTexture *sampled = texture(texture_id);
526
328
  SDL_GPUTexture *gpu = sampled != nullptr ? ensure_texture_gpu(sampled, sampled->as_target)
527
329
  : nullptr;
528
330
  WebGLSampler *sampler_object = this->sampler(bound_samplers_[unit]);
529
- SDL_GPUSampler *sampler = sampler_object != nullptr
530
- ? sampler_gpu(sampler_object)
531
- : (sampled != nullptr ? sampler_for(sampled) : nullptr);
331
+ SDL_GPUSampler *sampler = nullptr;
332
+ if (sampler_object != nullptr) {
333
+ sampler = sampler_gpu(sampler_object);
334
+ } else if (sampled != nullptr) {
335
+ sampler = uniform.compare ? sampler_for_compare(sampled) : sampler_for(sampled);
336
+ }
532
337
  if (gpu == nullptr || sampler == nullptr) {
533
338
  gpu = fallback_texture_;
534
339
  sampler = fallback_sampler_;
@@ -536,14 +341,14 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
536
341
  SDL_GPUTextureSamplerBinding texture_binding;
537
342
  texture_binding.texture = gpu;
538
343
  texture_binding.sampler = sampler;
539
- sampler_bindings.push_back(texture_binding);
344
+ sampler_bindings_.push_back(texture_binding);
540
345
  }
541
346
  if (vertex_stage) {
542
- SDL_BindGPUVertexSamplers(pass_, 0, sampler_bindings.data(),
543
- (Uint32)sampler_bindings.size());
347
+ SDL_BindGPUVertexSamplers(pass_, 0, sampler_bindings_.data(),
348
+ (Uint32)sampler_bindings_.size());
544
349
  } else {
545
- SDL_BindGPUFragmentSamplers(pass_, 0, sampler_bindings.data(),
546
- (Uint32)sampler_bindings.size());
350
+ SDL_BindGPUFragmentSamplers(pass_, 0, sampler_bindings_.data(),
351
+ (Uint32)sampler_bindings_.size());
547
352
  }
548
353
  };
549
354
  bind_samplers(program_->vs_sampler_uniforms, true);
@@ -557,4 +362,4 @@ void WebGLContext::draw(int mode, int first, int count, int index_type, int offs
557
362
  }
558
363
  }
559
364
 
560
- } // namespace xtgui
365
+ } // namespace xtgui
@@ -62,6 +62,7 @@ void WebGLContext::draw_buffers(int count, const int *buffers) {
62
62
  for (int i = 0; i < kWebGLMaxDrawBuffers; i++) {
63
63
  target[i] = (i < count && buffers != nullptr) ? buffers[i] : GL_NONE;
64
64
  }
65
+ framebuffer_version_ += 1;
65
66
  end_pass();
66
67
  }
67
68