xbintsc 0.5.38 → 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/driver/version.d.ts +1 -1
- package/dist/src/driver/version.js +1 -1
- package/dist/src/extensions/gui/html.js +9 -2
- package/dist/src/extensions/gui/html.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.js +9 -1
- package/dist/tests/e2e/gui-script-import-order.test.js.map +1 -1
- 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/extensions/gui.test.js +23 -0
- 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 +38 -19
- package/doc/gui.md +33 -1
- 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 +27 -5
- package/doc/zh-CN/gui.md +25 -2
- 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 +19 -9
- 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 +30 -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/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_scan.cpp +3 -8
- 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 +22 -30
- package/runtime/ext_gui/webgl_webgl2.cpp +36 -0
- package/runtime/ext_gui/window.cpp +56 -1
- package/src/codegen/generator/module.ts +22 -7
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/html.ts +9 -2
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — prepared WebGL draws.
|
|
3
|
+
*
|
|
4
|
+
* Every draw needs the same three things: the pipeline for the current
|
|
5
|
+
* fixed-function state, the vertex layout of the program's active attributes,
|
|
6
|
+
* and the GPU buffer handles behind them. Building that per draw was the
|
|
7
|
+
* dominant CPU cost of a multi-element scene, so it is built once per
|
|
8
|
+
* (program, layout version, state) and cached in `draw_setups_`.
|
|
9
|
+
*
|
|
10
|
+
* A setup is invalidated by bumping one of the context's state versions:
|
|
11
|
+
* `attribs_version_` for anything that changes the vertex layout (attribute
|
|
12
|
+
* pointers, enables, VAO loads), `gpu_version_` for buffer handle changes, and
|
|
13
|
+
* `framebuffer_version_` for attachment-format changes.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include "webgl.h"
|
|
17
|
+
|
|
18
|
+
#include <cstring>
|
|
19
|
+
#include <utility>
|
|
20
|
+
#include <vector>
|
|
21
|
+
|
|
22
|
+
#include "gui_internal.h"
|
|
23
|
+
|
|
24
|
+
namespace xtgui {
|
|
25
|
+
namespace {
|
|
26
|
+
|
|
27
|
+
int components_of_type(const std::string &type) {
|
|
28
|
+
if (!type.empty() && type.back() >= '2' && type.back() <= '4') return type.back() - '0';
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
int matrix_slots(const std::string &type) {
|
|
33
|
+
if (type == "mat2") return 2;
|
|
34
|
+
if (type == "mat3") return 3;
|
|
35
|
+
if (type == "mat4") return 4;
|
|
36
|
+
return 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
SDL_GPUVertexElementFormat float_format(int size) {
|
|
40
|
+
switch (size) {
|
|
41
|
+
case 1:
|
|
42
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT;
|
|
43
|
+
case 2:
|
|
44
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2;
|
|
45
|
+
case 3:
|
|
46
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
|
|
47
|
+
default:
|
|
48
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
SDL_GPUVertexElementFormat format_of(int size, int type, bool normalized) {
|
|
53
|
+
if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
54
|
+
if (type == GL_FLOAT) return float_format(size);
|
|
55
|
+
if (type == GL_UNSIGNED_BYTE || type == GL_BYTE) {
|
|
56
|
+
const bool is_byte = type == GL_BYTE;
|
|
57
|
+
if (size == 2) {
|
|
58
|
+
return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2_NORM
|
|
59
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2_NORM)
|
|
60
|
+
: (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2
|
|
61
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2);
|
|
62
|
+
}
|
|
63
|
+
if (size == 4) {
|
|
64
|
+
return normalized ? (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4_NORM
|
|
65
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4_NORM)
|
|
66
|
+
: (is_byte ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE4
|
|
67
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4);
|
|
68
|
+
}
|
|
69
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
70
|
+
}
|
|
71
|
+
if (type == GL_UNSIGNED_SHORT || type == GL_SHORT) {
|
|
72
|
+
const bool is_short = type == GL_SHORT;
|
|
73
|
+
if (size == 2) {
|
|
74
|
+
return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2_NORM
|
|
75
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT2_NORM)
|
|
76
|
+
: (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2
|
|
77
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT2);
|
|
78
|
+
}
|
|
79
|
+
if (size == 4) {
|
|
80
|
+
return normalized ? (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4_NORM
|
|
81
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4_NORM)
|
|
82
|
+
: (is_short ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT4
|
|
83
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4);
|
|
84
|
+
}
|
|
85
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
86
|
+
}
|
|
87
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
SDL_GPUVertexElementFormat int_format_of(int size, int type) {
|
|
91
|
+
if (size < 1 || size > 4) return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
92
|
+
if (type == GL_INT) {
|
|
93
|
+
switch (size) {
|
|
94
|
+
case 1:
|
|
95
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT;
|
|
96
|
+
case 2:
|
|
97
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT2;
|
|
98
|
+
case 3:
|
|
99
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT3;
|
|
100
|
+
default:
|
|
101
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INT4;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (type == GL_UNSIGNED_INT) {
|
|
105
|
+
switch (size) {
|
|
106
|
+
case 1:
|
|
107
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT;
|
|
108
|
+
case 2:
|
|
109
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT2;
|
|
110
|
+
case 3:
|
|
111
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT3;
|
|
112
|
+
default:
|
|
113
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_UINT4;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (type == GL_SHORT && (size == 2 || size == 4)) {
|
|
117
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_SHORT2 : SDL_GPU_VERTEXELEMENTFORMAT_SHORT4;
|
|
118
|
+
}
|
|
119
|
+
if (type == GL_UNSIGNED_SHORT && (size == 2 || size == 4)) {
|
|
120
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_USHORT2
|
|
121
|
+
: SDL_GPU_VERTEXELEMENTFORMAT_USHORT4;
|
|
122
|
+
}
|
|
123
|
+
if (type == GL_BYTE && (size == 2 || size == 4)) {
|
|
124
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_BYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_BYTE4;
|
|
125
|
+
}
|
|
126
|
+
if (type == GL_UNSIGNED_BYTE && (size == 2 || size == 4)) {
|
|
127
|
+
return size == 2 ? SDL_GPU_VERTEXELEMENTFORMAT_UBYTE2 : SDL_GPU_VERTEXELEMENTFORMAT_UBYTE4;
|
|
128
|
+
}
|
|
129
|
+
return SDL_GPU_VERTEXELEMENTFORMAT_INVALID;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
int type_size(int type) {
|
|
133
|
+
switch (type) {
|
|
134
|
+
case GL_BYTE:
|
|
135
|
+
case GL_UNSIGNED_BYTE:
|
|
136
|
+
return 1;
|
|
137
|
+
case GL_SHORT:
|
|
138
|
+
case GL_UNSIGNED_SHORT:
|
|
139
|
+
return 2;
|
|
140
|
+
default:
|
|
141
|
+
return 4;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
} // namespace
|
|
146
|
+
|
|
147
|
+
void WebGLContext::draw_state_hash(uint64_t *first, uint64_t *second) const {
|
|
148
|
+
uint64_t h1 = 1469598103934665603ull;
|
|
149
|
+
uint64_t h2 = 0x9e3779b97f4a7c15ull;
|
|
150
|
+
auto mix = [&h1, &h2](uint64_t value) {
|
|
151
|
+
h1 ^= value;
|
|
152
|
+
h1 *= 1099511628211ull;
|
|
153
|
+
h1 ^= h1 >> 32;
|
|
154
|
+
h2 += value + 0x9e3779b97f4a7c15ull;
|
|
155
|
+
h2 = (h2 << 27) | (h2 >> 37);
|
|
156
|
+
h2 *= 0xbf58476d1ce4e5b9ull;
|
|
157
|
+
};
|
|
158
|
+
auto mix_face = [&mix](const WebGLStencilFace &face) {
|
|
159
|
+
/* `ref` is a per-pass dynamic value, not part of the pipeline. */
|
|
160
|
+
mix((uint64_t)(uint32_t)face.func);
|
|
161
|
+
mix(face.value_mask);
|
|
162
|
+
mix(face.write_mask);
|
|
163
|
+
mix((uint64_t)(uint32_t)face.fail);
|
|
164
|
+
mix((uint64_t)(uint32_t)face.zfail);
|
|
165
|
+
mix((uint64_t)(uint32_t)face.zpass);
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
mix(state_.blend ? 1u : 0u);
|
|
169
|
+
mix((uint64_t)(uint32_t)state_.blend_src_rgb);
|
|
170
|
+
mix((uint64_t)(uint32_t)state_.blend_dst_rgb);
|
|
171
|
+
mix((uint64_t)(uint32_t)state_.blend_src_alpha);
|
|
172
|
+
mix((uint64_t)(uint32_t)state_.blend_dst_alpha);
|
|
173
|
+
mix((uint64_t)(uint32_t)state_.blend_eq_rgb);
|
|
174
|
+
mix((uint64_t)(uint32_t)state_.blend_eq_alpha);
|
|
175
|
+
mix(state_.depth_test ? 1u : 0u);
|
|
176
|
+
mix(state_.depth_write ? 1u : 0u);
|
|
177
|
+
mix((uint64_t)(uint32_t)state_.depth_func);
|
|
178
|
+
mix(state_.stencil ? 1u : 0u);
|
|
179
|
+
mix_face(state_.stencil_front);
|
|
180
|
+
mix_face(state_.stencil_back);
|
|
181
|
+
mix(state_.cull ? 1u : 0u);
|
|
182
|
+
mix((uint64_t)(uint32_t)state_.cull_face);
|
|
183
|
+
mix((uint64_t)(uint32_t)state_.front_face);
|
|
184
|
+
for (bool channel : state_.color_mask) mix(channel ? 1u : 0u);
|
|
185
|
+
mix((uint64_t)(uint32_t)state_.color_target_count);
|
|
186
|
+
for (int i = 0; i < state_.color_target_count; i++) {
|
|
187
|
+
mix((uint64_t)(uint32_t)state_.color_formats[i]);
|
|
188
|
+
}
|
|
189
|
+
mix((uint64_t)(uint32_t)state_.depth_format);
|
|
190
|
+
|
|
191
|
+
*first = h1;
|
|
192
|
+
*second = h2;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
void WebGLContext::clear_draw_cache() {
|
|
196
|
+
draw_setups_.clear();
|
|
197
|
+
last_setup_ = nullptr;
|
|
198
|
+
last_pipeline_ = nullptr;
|
|
199
|
+
last_setup_pass_ = 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const WebGLDrawSetup *WebGLContext::prepare_draw(const WebGLDrawKey &key) {
|
|
203
|
+
auto found = draw_setups_.find(key);
|
|
204
|
+
if (found != draw_setups_.end()) return &found->second;
|
|
205
|
+
WebGLProgram *program_ = program(key.program);
|
|
206
|
+
if (program_ == nullptr) {
|
|
207
|
+
set_error(GL_INVALID_OPERATION);
|
|
208
|
+
return nullptr;
|
|
209
|
+
}
|
|
210
|
+
/* A page that cycles through many states would otherwise grow the table
|
|
211
|
+
* without bound; clearing only costs one rebuild per live state. */
|
|
212
|
+
if (draw_setups_.size() >= 256) clear_draw_cache();
|
|
213
|
+
|
|
214
|
+
WebGLDrawSetup setup;
|
|
215
|
+
setup.attributes.reserve(program_->draw_attribs.size());
|
|
216
|
+
setup.buffers.reserve(program_->draw_attribs.size());
|
|
217
|
+
setup.bindings.reserve(program_->draw_attribs.size());
|
|
218
|
+
|
|
219
|
+
for (const WebGLDrawAttribPlan &plan : program_->draw_attribs) {
|
|
220
|
+
if (plan.location < 0 || plan.location >= kWebGLMaxAttribs) continue;
|
|
221
|
+
WebGLAttribState &attrib = attribs_[plan.location];
|
|
222
|
+
const int slots = matrix_slots(plan.type);
|
|
223
|
+
const int type_components = components_of_type(plan.type);
|
|
224
|
+
const int components = slots > 1 ? slots : (type_components > 4 ? 4 : type_components);
|
|
225
|
+
const uint32_t slot = (uint32_t)setup.buffers.size();
|
|
226
|
+
|
|
227
|
+
SDL_GPUVertexBufferDescription description;
|
|
228
|
+
memset(&description, 0, sizeof(description));
|
|
229
|
+
description.slot = slot;
|
|
230
|
+
description.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
231
|
+
SDL_GPUBufferBinding binding;
|
|
232
|
+
memset(&binding, 0, sizeof(binding));
|
|
233
|
+
|
|
234
|
+
if (!attrib.enabled) {
|
|
235
|
+
/* A disabled attribute is a constant read from a persistent 16-byte
|
|
236
|
+
* buffer, not a fresh GPU allocation per draw. */
|
|
237
|
+
SDL_GPUBuffer *constant = constant_attrib_buffer(plan.location);
|
|
238
|
+
if (constant == nullptr) return nullptr;
|
|
239
|
+
binding.buffer = constant;
|
|
240
|
+
description.pitch = 0;
|
|
241
|
+
for (int column = 0; column < slots; column++) {
|
|
242
|
+
SDL_GPUVertexAttribute attribute;
|
|
243
|
+
memset(&attribute, 0, sizeof(attribute));
|
|
244
|
+
attribute.location = (Uint32)(plan.location + column);
|
|
245
|
+
attribute.buffer_slot = slot;
|
|
246
|
+
attribute.format = float_format(components);
|
|
247
|
+
attribute.offset = 0;
|
|
248
|
+
setup.attributes.push_back(attribute);
|
|
249
|
+
}
|
|
250
|
+
setup.buffers.push_back(description);
|
|
251
|
+
setup.bindings.push_back(binding);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
WebGLBuffer *buffer_ = buffer(attrib.buffer);
|
|
256
|
+
if (buffer_ == nullptr || buffer_->data.empty()) {
|
|
257
|
+
set_error(GL_INVALID_OPERATION);
|
|
258
|
+
return nullptr;
|
|
259
|
+
}
|
|
260
|
+
SDL_GPUVertexElementFormat format = attrib.integer
|
|
261
|
+
? int_format_of(attrib.size, attrib.type)
|
|
262
|
+
: format_of(attrib.size, attrib.type, attrib.normalized);
|
|
263
|
+
if (format == SDL_GPU_VERTEXELEMENTFORMAT_INVALID) {
|
|
264
|
+
set_error(GL_INVALID_OPERATION);
|
|
265
|
+
return nullptr;
|
|
266
|
+
}
|
|
267
|
+
description.input_rate = attrib.divisor > 0 ? SDL_GPU_VERTEXINPUTRATE_INSTANCE
|
|
268
|
+
: SDL_GPU_VERTEXINPUTRATE_VERTEX;
|
|
269
|
+
const int stride =
|
|
270
|
+
attrib.stride > 0 ? attrib.stride : components * type_size(attrib.type) * slots;
|
|
271
|
+
description.pitch = (Uint32)stride;
|
|
272
|
+
SDL_GPUBuffer *gpu = ensure_buffer_gpu(buffer_);
|
|
273
|
+
if (gpu == nullptr) return nullptr;
|
|
274
|
+
binding.buffer = gpu;
|
|
275
|
+
for (int column = 0; column < slots; column++) {
|
|
276
|
+
SDL_GPUVertexAttribute attribute;
|
|
277
|
+
memset(&attribute, 0, sizeof(attribute));
|
|
278
|
+
attribute.location = (Uint32)(plan.location + column);
|
|
279
|
+
attribute.buffer_slot = slot;
|
|
280
|
+
attribute.format = format;
|
|
281
|
+
attribute.offset = (Uint32)(attrib.offset + column * components * type_size(attrib.type));
|
|
282
|
+
setup.attributes.push_back(attribute);
|
|
283
|
+
}
|
|
284
|
+
setup.buffers.push_back(description);
|
|
285
|
+
setup.bindings.push_back(binding);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (key.index_size > 0 && key.element_buffer != 0) {
|
|
289
|
+
WebGLBuffer *element = buffer(key.element_buffer);
|
|
290
|
+
if (element == nullptr || element->data.empty()) {
|
|
291
|
+
set_error(GL_INVALID_OPERATION);
|
|
292
|
+
return nullptr;
|
|
293
|
+
}
|
|
294
|
+
setup.index_buffer = ensure_buffer_gpu(element);
|
|
295
|
+
if (setup.index_buffer == nullptr) return nullptr;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* The pipeline depends on the vertex layout and fixed-function state, not on
|
|
299
|
+
* which GPU buffer happens to hold the data (a buffer can be recreated after
|
|
300
|
+
* a grow) nor on the element-buffer binding. Normalise those fields out so a
|
|
301
|
+
* dynamic buffer does not create a fresh pipeline. */
|
|
302
|
+
WebGLDrawKey pipeline_key = key;
|
|
303
|
+
pipeline_key.gpu_version = 0;
|
|
304
|
+
pipeline_key.element_buffer = 0;
|
|
305
|
+
auto cached = program_->pipeline_cache.find(pipeline_key);
|
|
306
|
+
if (cached != program_->pipeline_cache.end()) {
|
|
307
|
+
setup.pipeline = cached->second;
|
|
308
|
+
} else {
|
|
309
|
+
setup.pipeline = create_pipeline(program_, key.mode, (int)setup.attributes.size(),
|
|
310
|
+
(int)setup.buffers.size(), setup.attributes.data(),
|
|
311
|
+
setup.buffers.data());
|
|
312
|
+
if (setup.pipeline == nullptr) return nullptr;
|
|
313
|
+
program_->pipeline_cache[pipeline_key] = setup.pipeline;
|
|
314
|
+
program_->pipelines.push_back(setup.pipeline);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
auto inserted = draw_setups_.emplace(key, std::move(setup));
|
|
318
|
+
return &inserted.first->second;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — the fixed-function WebGL state a pipeline depends on.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `webgl.h` to keep that header under the repository's
|
|
5
|
+
* file-length budget.
|
|
6
|
+
*/
|
|
7
|
+
#ifndef XT_GUI_WEBGL_DRAW_STATE_H
|
|
8
|
+
#define XT_GUI_WEBGL_DRAW_STATE_H
|
|
9
|
+
|
|
10
|
+
#include <cstddef>
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
#include <SDL3/SDL.h>
|
|
16
|
+
|
|
17
|
+
#include "webgl_constants.h"
|
|
18
|
+
|
|
19
|
+
namespace xtgui {
|
|
20
|
+
|
|
21
|
+
/** One face's stencil test and update state. */
|
|
22
|
+
struct WebGLStencilFace {
|
|
23
|
+
int func = GL_ALWAYS;
|
|
24
|
+
int ref = 0;
|
|
25
|
+
uint32_t value_mask = 0xFFFFFFFFu; // compare mask
|
|
26
|
+
uint32_t write_mask = 0xFFFFFFFFu;
|
|
27
|
+
int fail = GL_KEEP;
|
|
28
|
+
int zfail = GL_KEEP;
|
|
29
|
+
int zpass = GL_KEEP;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** The fixed-function state a pipeline depends on. */
|
|
33
|
+
struct WebGLDrawState {
|
|
34
|
+
bool blend = false;
|
|
35
|
+
int blend_src_rgb = GL_ONE;
|
|
36
|
+
int blend_dst_rgb = GL_ZERO;
|
|
37
|
+
int blend_src_alpha = GL_ONE;
|
|
38
|
+
int blend_dst_alpha = GL_ZERO;
|
|
39
|
+
int blend_eq_rgb = GL_FUNC_ADD;
|
|
40
|
+
int blend_eq_alpha = GL_FUNC_ADD;
|
|
41
|
+
bool depth_test = false;
|
|
42
|
+
bool depth_write = true;
|
|
43
|
+
int depth_func = GL_LESS;
|
|
44
|
+
bool stencil = false;
|
|
45
|
+
WebGLStencilFace stencil_front;
|
|
46
|
+
WebGLStencilFace stencil_back;
|
|
47
|
+
bool cull = false;
|
|
48
|
+
int cull_face = GL_BACK;
|
|
49
|
+
int front_face = GL_CCW;
|
|
50
|
+
bool color_mask[4] = {true, true, true, true};
|
|
51
|
+
/** Attachment formats of the bound target; pipelines are format-specific. */
|
|
52
|
+
int color_formats[4] = {
|
|
53
|
+
SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
|
|
54
|
+
SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM};
|
|
55
|
+
int color_target_count = 1;
|
|
56
|
+
int depth_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT_S8_UINT;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Identity of one prepared draw. Everything a draw's pipeline, vertex layout
|
|
61
|
+
* and GPU buffer handles depend on is either an exact integer here or folds
|
|
62
|
+
* into `state_hash`/`state_hash2` (a 128-bit hash of `WebGLDrawState`). Two
|
|
63
|
+
* independent hashes keep a collision in the same place a 128-bit hash would
|
|
64
|
+
* have it — the state struct has no padding-sensitive fields to compare.
|
|
65
|
+
*/
|
|
66
|
+
struct WebGLDrawKey {
|
|
67
|
+
uint32_t program = 0;
|
|
68
|
+
int mode = 0; // GL primitive mode
|
|
69
|
+
int index_size = 0; // 0 = drawArrays, otherwise index element bytes
|
|
70
|
+
uint32_t element_buffer = 0; // bound GL_ELEMENT_ARRAY_BUFFER, 0 = none
|
|
71
|
+
uint64_t attribs_version = 0;
|
|
72
|
+
uint64_t gpu_version = 0;
|
|
73
|
+
uint64_t framebuffer_version = 0;
|
|
74
|
+
uint64_t state_hash = 0;
|
|
75
|
+
uint64_t state_hash2 = 0;
|
|
76
|
+
|
|
77
|
+
bool operator==(const WebGLDrawKey &other) const {
|
|
78
|
+
return program == other.program && mode == other.mode && index_size == other.index_size &&
|
|
79
|
+
element_buffer == other.element_buffer && attribs_version == other.attribs_version &&
|
|
80
|
+
gpu_version == other.gpu_version &&
|
|
81
|
+
framebuffer_version == other.framebuffer_version && state_hash == other.state_hash &&
|
|
82
|
+
state_hash2 == other.state_hash2;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
struct WebGLDrawKeyHash {
|
|
87
|
+
size_t operator()(const WebGLDrawKey &key) const {
|
|
88
|
+
uint64_t hash = 1469598103934665603ull;
|
|
89
|
+
auto mix = [&hash](uint64_t value) {
|
|
90
|
+
hash ^= value;
|
|
91
|
+
hash *= 1099511628211ull;
|
|
92
|
+
hash ^= hash >> 29;
|
|
93
|
+
};
|
|
94
|
+
mix(key.program);
|
|
95
|
+
mix((uint64_t)(uint32_t)key.mode);
|
|
96
|
+
mix((uint64_t)(uint32_t)key.index_size);
|
|
97
|
+
mix(key.element_buffer);
|
|
98
|
+
mix(key.attribs_version);
|
|
99
|
+
mix(key.gpu_version);
|
|
100
|
+
mix(key.framebuffer_version);
|
|
101
|
+
mix(key.state_hash);
|
|
102
|
+
mix(key.state_hash2);
|
|
103
|
+
return (size_t)hash;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* One active vertex attribute, resolved once at link time: `location` is the
|
|
109
|
+
* base attribute location and `type` the GLSL type name the draw needs to size
|
|
110
|
+
* the vertex layout. Keeping this out of the draw path removes the per-draw
|
|
111
|
+
* `attribs` scan and the `name -> location` string hash lookup.
|
|
112
|
+
*/
|
|
113
|
+
struct WebGLDrawAttribPlan {
|
|
114
|
+
int location = -1;
|
|
115
|
+
std::string type;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** A pipeline and the vertex-layout/binding set the draw prepared for it. A
|
|
119
|
+
* cache hit is a bind (when it changed) and a draw. */
|
|
120
|
+
struct WebGLDrawSetup {
|
|
121
|
+
SDL_GPUGraphicsPipeline *pipeline = nullptr;
|
|
122
|
+
std::vector<SDL_GPUVertexAttribute> attributes;
|
|
123
|
+
std::vector<SDL_GPUVertexBufferDescription> buffers;
|
|
124
|
+
std::vector<SDL_GPUBufferBinding> bindings;
|
|
125
|
+
SDL_GPUBuffer *index_buffer = nullptr;
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
} // namespace xtgui
|
|
129
|
+
|
|
130
|
+
#endif /* XT_GUI_WEBGL_DRAW_STATE_H */
|
|
@@ -425,14 +425,9 @@ void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info) {
|
|
|
425
425
|
info->legacy_fragment_output = true;
|
|
426
426
|
continue;
|
|
427
427
|
}
|
|
428
|
-
/*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
if (inactive == 0 && fragment && token.kind == Token::Ident &&
|
|
432
|
-
(token.text == "gl_FragDepth" || token.text == "gl_FragDepthEXT")) {
|
|
433
|
-
info->unsupported = "gl_FragDepth is not supported";
|
|
434
|
-
continue;
|
|
435
|
-
}
|
|
428
|
+
/* `gl_FragDepth`/`gl_FragDepthEXT`: the Vulkan SPIR-V path emits
|
|
429
|
+
* `DepthReplacing`, and SPIRV-Cross turns that into `[[depth(any)]]` for
|
|
430
|
+
* Metal, so a fragment shader may write the depth attachment directly. */
|
|
436
431
|
/* Declarations inside a definitively false preprocessor branch never reach
|
|
437
432
|
* the compiler; rewriting them would move their types/macros (and array
|
|
438
433
|
* sizes such as `MORPHTARGETS_COUNT`) outside that branch. */
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — WebGL object records.
|
|
3
|
+
*
|
|
4
|
+
* Handles are integer ids, not pointers: a `deleteBuffer`/`deleteTexture` call
|
|
5
|
+
* must make an old JavaScript handle a no-op rather than a dangling pointer.
|
|
6
|
+
* Every record keeps its CPU-side data (buffer bytes, texture parameters) and
|
|
7
|
+
* the GPU handle it was last uploaded into.
|
|
8
|
+
*
|
|
9
|
+
* Split out of `webgl.h` to keep the context header under the repository's
|
|
10
|
+
* file-length budget; the context owns the tables of these records.
|
|
11
|
+
*/
|
|
12
|
+
#ifndef XT_GUI_WEBGL_OBJECTS_H
|
|
13
|
+
#define XT_GUI_WEBGL_OBJECTS_H
|
|
14
|
+
|
|
15
|
+
#include <cstdint>
|
|
16
|
+
#include <vector>
|
|
17
|
+
|
|
18
|
+
#include <SDL3/SDL.h>
|
|
19
|
+
|
|
20
|
+
#include "webgl2_constants.h"
|
|
21
|
+
#include "webgl_constants.h"
|
|
22
|
+
|
|
23
|
+
namespace xtgui {
|
|
24
|
+
|
|
25
|
+
constexpr int kWebGLMaxAttribs = 16;
|
|
26
|
+
constexpr int kWebGLMaxTextureUnits = 16;
|
|
27
|
+
constexpr int kWebGLMaxDrawBuffers = 4;
|
|
28
|
+
|
|
29
|
+
struct WebGLBuffer {
|
|
30
|
+
uint32_t id = 0;
|
|
31
|
+
std::vector<uint8_t> data;
|
|
32
|
+
SDL_GPUBuffer *gpu = nullptr;
|
|
33
|
+
uint32_t capacity = 0;
|
|
34
|
+
bool dirty = true;
|
|
35
|
+
/** Half-open byte range of `data` that changed since the last GPU upload. */
|
|
36
|
+
uint32_t dirty_lo = 0;
|
|
37
|
+
uint32_t dirty_hi = 0;
|
|
38
|
+
/** `bufferData` usage hint, reported by `getBufferParameter`. */
|
|
39
|
+
int usage = GL_STATIC_DRAW;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
struct WebGLTexture {
|
|
43
|
+
uint32_t id = 0;
|
|
44
|
+
int width = 0;
|
|
45
|
+
int height = 0;
|
|
46
|
+
int levels = 1;
|
|
47
|
+
/** The binding target this texture was created for. */
|
|
48
|
+
int target = GL_TEXTURE_2D;
|
|
49
|
+
/** Layers for a cube/2D-array texture, depth for a 3D texture. */
|
|
50
|
+
int layers = 1;
|
|
51
|
+
SDL_GPUTexture *gpu = nullptr;
|
|
52
|
+
SDL_GPUTextureFormat format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
|
53
|
+
/** Depth(-stencil) formats can only be depth attachments. */
|
|
54
|
+
bool depth = false;
|
|
55
|
+
/** Block-compressed textures are sample-only, with one mip level. */
|
|
56
|
+
bool compressed = false;
|
|
57
|
+
/** Usage flags the current `gpu` texture was created with. */
|
|
58
|
+
uint32_t usage = 0;
|
|
59
|
+
bool as_target = false; // bound as a colour attachment
|
|
60
|
+
bool as_depth_target = false; // bound as a depth attachment
|
|
61
|
+
bool has_mipmaps = false;
|
|
62
|
+
int min_filter = 0;
|
|
63
|
+
int mag_filter = 0;
|
|
64
|
+
int wrap_s = 0;
|
|
65
|
+
int wrap_t = 0;
|
|
66
|
+
SDL_GPUSampler *sampler = nullptr;
|
|
67
|
+
/** Comparison sampler for a `sampler2DShadow` binding. */
|
|
68
|
+
SDL_GPUSampler *compare_sampler = nullptr;
|
|
69
|
+
bool compare_mode = false;
|
|
70
|
+
int compare_func = GL_LEQUAL;
|
|
71
|
+
bool dirty = false;
|
|
72
|
+
bool defined = false;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
struct WebGLRenderbuffer {
|
|
76
|
+
uint32_t id = 0;
|
|
77
|
+
int width = 0;
|
|
78
|
+
int height = 0;
|
|
79
|
+
bool stencil = false;
|
|
80
|
+
SDL_GPUTexture *depth = nullptr;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
struct WebGLFramebuffer {
|
|
84
|
+
uint32_t id = 0;
|
|
85
|
+
uint32_t color_textures[kWebGLMaxDrawBuffers] = {};
|
|
86
|
+
/** Layer rendered to for an array/cube colour attachment. */
|
|
87
|
+
int color_layers[kWebGLMaxDrawBuffers] = {};
|
|
88
|
+
/** `COLOR_ATTACHMENTi` or `NONE` per draw-buffer slot. */
|
|
89
|
+
int draw_buffers[kWebGLMaxDrawBuffers] = {GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE, GL_NONE};
|
|
90
|
+
uint32_t depth_texture = 0;
|
|
91
|
+
uint32_t depth_renderbuffer = 0;
|
|
92
|
+
int width = 0;
|
|
93
|
+
int height = 0;
|
|
94
|
+
SDL_GPUTexture *depth = nullptr; // owned when no renderbuffer/texture supplies one
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/** Per-attribute array state. */
|
|
98
|
+
struct WebGLAttribState {
|
|
99
|
+
bool enabled = false;
|
|
100
|
+
bool integer = false; // `vertexAttribIPointer` rather than `vertexAttribPointer`
|
|
101
|
+
uint32_t buffer = 0;
|
|
102
|
+
int size = 4;
|
|
103
|
+
int type = GL_FLOAT;
|
|
104
|
+
bool normalized = false;
|
|
105
|
+
int stride = 0;
|
|
106
|
+
int offset = 0;
|
|
107
|
+
int divisor = 0; // 0 = per vertex, 1 = per instance
|
|
108
|
+
float current[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
|
109
|
+
/** GPU buffer holding `current[]` while this attribute is disabled. It is
|
|
110
|
+
* created lazily and re-uploaded only when `attrib_value` changes, so a draw
|
|
111
|
+
* never creates a GPU buffer just to supply a constant attribute. */
|
|
112
|
+
SDL_GPUBuffer *constant_gpu = nullptr;
|
|
113
|
+
uint32_t constant_bytes = 0;
|
|
114
|
+
bool constant_dirty = true;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/** A WebGL 2 vertex-array object; binding one restores this state. */
|
|
118
|
+
struct WebGLVertexArray {
|
|
119
|
+
uint32_t id = 0;
|
|
120
|
+
WebGLAttribState attribs[kWebGLMaxAttribs];
|
|
121
|
+
uint32_t element_buffer = 0;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/** A WebGL 2 sampler object, bound to a texture unit with `bindSampler`. */
|
|
125
|
+
struct WebGLSampler {
|
|
126
|
+
uint32_t id = 0;
|
|
127
|
+
int min_filter = 0;
|
|
128
|
+
int mag_filter = 0;
|
|
129
|
+
int wrap_s = 0;
|
|
130
|
+
int wrap_t = 0;
|
|
131
|
+
/** `TEXTURE_COMPARE_MODE`/`TEXTURE_COMPARE_FUNC` (WebGL 2 sampler objects
|
|
132
|
+
* carry them too). */
|
|
133
|
+
bool compare_mode = false;
|
|
134
|
+
int compare_func = GL_LEQUAL;
|
|
135
|
+
SDL_GPUSampler *gpu = nullptr;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
struct WebGLQuery {
|
|
139
|
+
uint32_t id = 0;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
struct WebGLSync {
|
|
143
|
+
uint32_t id = 0;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
} // namespace xtgui
|
|
147
|
+
|
|
148
|
+
#endif /* XT_GUI_WEBGL_OBJECTS_H */
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
#include <vector>
|
|
17
17
|
|
|
18
18
|
#include "gui_internal.h"
|
|
19
|
+
#include "perf.h"
|
|
19
20
|
|
|
20
21
|
namespace xtgui {
|
|
21
22
|
namespace {
|
|
@@ -251,10 +252,8 @@ SDL_GPUBuffer *WebGLContext::upload_temp_buffer(const void *data, uint32_t size,
|
|
|
251
252
|
}
|
|
252
253
|
|
|
253
254
|
SDL_GPUGraphicsPipeline *WebGLContext::create_pipeline(
|
|
254
|
-
WebGLProgram *program, int mode, int
|
|
255
|
-
const SDL_GPUVertexAttribute *attrs, const SDL_GPUVertexBufferDescription *buffers
|
|
256
|
-
const std::string &key) {
|
|
257
|
-
(void)index_size;
|
|
255
|
+
WebGLProgram *program, int mode, int attribute_count, int buffer_count,
|
|
256
|
+
const SDL_GPUVertexAttribute *attrs, const SDL_GPUVertexBufferDescription *buffers) {
|
|
258
257
|
SDL_GPUColorTargetDescription color_targets[kWebGLMaxDrawBuffers];
|
|
259
258
|
const int color_target_count =
|
|
260
259
|
state_.color_target_count > 0 ? state_.color_target_count : 1;
|
|
@@ -318,9 +317,10 @@ SDL_GPUGraphicsPipeline *WebGLContext::create_pipeline(
|
|
|
318
317
|
set_error(GL_INVALID_OPERATION);
|
|
319
318
|
return nullptr;
|
|
320
319
|
}
|
|
321
|
-
program
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
320
|
+
/* Ownership stays with the caller: a program draw pushes the pipeline into
|
|
321
|
+
* its own list, an internal helper draw keeps it in the context. Releasing
|
|
322
|
+
* both would free it twice. */
|
|
323
|
+
g_perf_frame.webglPipelineMisses += 1;
|
|
324
|
+
return pipeline;}
|
|
325
325
|
|
|
326
326
|
} // namespace xtgui
|
|
@@ -10,6 +10,41 @@
|
|
|
10
10
|
namespace xtgui {
|
|
11
11
|
namespace webgl_detail {
|
|
12
12
|
|
|
13
|
+
/** The GL enum reported for a GLSL uniform type (`getActiveUniform`). */
|
|
14
|
+
inline int gl_type_of(const std::string &type) {
|
|
15
|
+
if (type == "float") return GL_FLOAT;
|
|
16
|
+
if (type == "vec2") return GL_FLOAT_VEC2;
|
|
17
|
+
if (type == "vec3") return GL_FLOAT_VEC3;
|
|
18
|
+
if (type == "vec4") return GL_FLOAT_VEC4;
|
|
19
|
+
if (type == "int" || type == "uint") return GL_INT;
|
|
20
|
+
if (type == "ivec2" || type == "uvec2") return GL_INT_VEC2;
|
|
21
|
+
if (type == "ivec3" || type == "uvec3") return GL_INT_VEC3;
|
|
22
|
+
if (type == "ivec4" || type == "uvec4") return GL_INT_VEC4;
|
|
23
|
+
if (type == "bool") return GL_BOOL;
|
|
24
|
+
if (type == "bvec2") return GL_BOOL_VEC2;
|
|
25
|
+
if (type == "bvec3") return GL_BOOL_VEC3;
|
|
26
|
+
if (type == "bvec4") return GL_BOOL_VEC4;
|
|
27
|
+
if (type == "mat2") return GL_FLOAT_MAT2;
|
|
28
|
+
if (type == "mat3") return GL_FLOAT_MAT3;
|
|
29
|
+
if (type == "mat4") return GL_FLOAT_MAT4;
|
|
30
|
+
if (type == "sampler2D") return GL_SAMPLER_2D;
|
|
31
|
+
if (type == "samplerCube") return GL_SAMPLER_CUBE;
|
|
32
|
+
if (type == "sampler3D") return GL_SAMPLER_3D;
|
|
33
|
+
if (type == "sampler2DArray") return GL_SAMPLER_2D_ARRAY;
|
|
34
|
+
if (type == "sampler2DShadow") return GL_SAMPLER_2D_SHADOW;
|
|
35
|
+
if (type == "samplerCubeShadow") return GL_SAMPLER_CUBE_SHADOW;
|
|
36
|
+
if (type == "sampler2DArrayShadow") return GL_SAMPLER_2D_ARRAY_SHADOW;
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** How many consecutive attribute/varying locations a type consumes. */
|
|
41
|
+
inline int location_slots(const std::string &type) {
|
|
42
|
+
if (type == "mat2") return 2;
|
|
43
|
+
if (type == "mat3") return 3;
|
|
44
|
+
if (type == "mat4") return 4;
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
13
48
|
/** Bytes a std140 block member occupies (the whole array for an array). */
|
|
14
49
|
int member_bytes(const GlslBlockMember &member);
|
|
15
50
|
|