xbintsc 0.5.32 → 0.5.37
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/README.md +10 -7
- package/README.zh-CN.md +10 -8
- package/dist/scripts/check-version.d.ts +27 -0
- package/dist/scripts/check-version.js +71 -0
- package/dist/scripts/check-version.js.map +1 -0
- package/dist/scripts/package-platform.d.ts +58 -0
- package/dist/scripts/package-platform.js +142 -0
- package/dist/scripts/package-platform.js.map +1 -0
- package/dist/scripts/verify-platform-package.d.ts +34 -0
- package/dist/scripts/verify-platform-package.js +161 -0
- package/dist/scripts/verify-platform-package.js.map +1 -0
- package/dist/src/cli/help.d.ts +1 -1
- package/dist/src/cli/main.js +3 -1
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/driver/runtime-lib.d.ts +29 -4
- package/dist/src/driver/runtime-lib.js +68 -10
- package/dist/src/driver/runtime-lib.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/index.js +18 -5
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/media/index.js +4 -3
- package/dist/src/extensions/media/index.js.map +1 -1
- package/dist/src/parser/context.d.ts +41 -0
- package/dist/src/parser/context.js +89 -4
- package/dist/src/parser/context.js.map +1 -1
- package/dist/src/parser/literals.js +6 -12
- package/dist/src/parser/literals.js.map +1 -1
- package/dist/tests/driver/platform-package.test.d.ts +1 -0
- package/dist/tests/driver/platform-package.test.js +49 -0
- package/dist/tests/driver/platform-package.test.js.map +1 -0
- package/dist/tests/driver/runtime-lib.test.js +51 -4
- package/dist/tests/driver/runtime-lib.test.js.map +1 -1
- package/dist/tests/e2e/gui-audio.test.d.ts +14 -0
- package/dist/tests/e2e/gui-audio.test.js +287 -0
- package/dist/tests/e2e/gui-audio.test.js.map +1 -0
- package/dist/tests/e2e/gui-browser.test.js +65 -0
- package/dist/tests/e2e/gui-browser.test.js.map +1 -1
- package/dist/tests/e2e/gui-canvas-args.test.d.ts +6 -0
- package/dist/tests/e2e/gui-canvas-args.test.js +217 -0
- package/dist/tests/e2e/gui-canvas-args.test.js.map +1 -0
- package/dist/tests/e2e/gui-canvas.test.js.map +1 -1
- package/dist/tests/e2e/gui-dom.test.js +215 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -1
- package/dist/tests/e2e/gui-events.test.js +112 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -1
- package/dist/tests/e2e/gui-helpers.d.ts +7 -0
- package/dist/tests/e2e/gui-helpers.js +1 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -1
- package/dist/tests/e2e/gui-media.test.js +78 -0
- package/dist/tests/e2e/gui-media.test.js.map +1 -1
- package/dist/tests/e2e/gui-style.test.js +55 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl.test.js +258 -0
- package/dist/tests/e2e/gui-webgl.test.js.map +1 -1
- package/dist/tests/e2e/gui-webgl2-3d.test.d.ts +4 -0
- package/dist/tests/e2e/gui-webgl2-3d.test.js +264 -0
- package/dist/tests/e2e/gui-webgl2-3d.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.d.ts +10 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.js +262 -0
- package/dist/tests/e2e/gui-webgl2-blit.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.d.ts +6 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.js +395 -0
- package/dist/tests/e2e/gui-webgl2-formats.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.d.ts +4 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.js +105 -0
- package/dist/tests/e2e/gui-webgl2-mrt.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.d.ts +8 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.js +112 -0
- package/dist/tests/e2e/gui-webgl2-ubo.test.js.map +1 -0
- package/dist/tests/e2e/gui-webgl2.test.js +45 -1
- package/dist/tests/e2e/gui-webgl2.test.js.map +1 -1
- package/dist/tests/extensions/gui-index.test.js +1 -0
- package/dist/tests/extensions/gui-index.test.js.map +1 -1
- package/dist/tests/extensions/media.test.js +1 -0
- package/dist/tests/extensions/media.test.js.map +1 -1
- package/dist/tests/parser/expressions.test.js +30 -0
- package/dist/tests/parser/expressions.test.js.map +1 -1
- package/dist/tests/platform-tarball.test.d.ts +1 -0
- package/dist/tests/platform-tarball.test.js +111 -0
- package/dist/tests/platform-tarball.test.js.map +1 -0
- package/dist/tests/version.test.js +6 -0
- package/dist/tests/version.test.js.map +1 -1
- package/doc/ai/contributing.md +11 -0
- package/doc/ai/extensions.md +7 -4
- package/doc/ai/troubleshooting.md +7 -5
- package/doc/ai/zh-CN/contributing.md +9 -0
- package/doc/ai/zh-CN/extensions.md +4 -2
- package/doc/ai/zh-CN/troubleshooting.md +5 -3
- package/doc/gui/api.md +99 -22
- package/doc/gui/build.md +11 -4
- package/doc/gui/canvas.md +49 -18
- package/doc/gui/dom.md +57 -7
- package/doc/gui/media.md +4 -0
- package/doc/gui/webgl.md +105 -46
- package/doc/gui.md +7 -3
- package/doc/npm-package.md +55 -27
- package/doc/requirements.md +6 -2
- package/doc/zh-CN/gui/api.md +84 -14
- package/doc/zh-CN/gui/build.md +7 -2
- package/doc/zh-CN/gui/canvas.md +44 -19
- package/doc/zh-CN/gui/dom.md +48 -4
- package/doc/zh-CN/gui/media.md +3 -0
- package/doc/zh-CN/gui/webgl.md +22 -16
- package/doc/zh-CN/gui.md +3 -2
- package/doc/zh-CN/npm-package.md +44 -23
- package/doc/zh-CN/requirements.md +4 -1
- package/package.json +17 -1
- package/runtime/ext_gui/audio.cpp +365 -153
- package/runtime/ext_gui/audio_buffer.cpp +166 -0
- package/runtime/ext_gui/audio_buffer.h +37 -0
- package/runtime/ext_gui/audio_decode.cpp +219 -0
- package/runtime/ext_gui/audio_decode.h +39 -0
- package/runtime/ext_gui/audio_device.cpp +87 -0
- package/runtime/ext_gui/audio_effects.cpp +163 -0
- package/runtime/ext_gui/audio_effects.h +25 -0
- package/runtime/ext_gui/audio_internal.h +30 -0
- package/runtime/ext_gui/audio_mixer.cpp +494 -0
- package/runtime/ext_gui/audio_mixer.h +238 -0
- package/runtime/ext_gui/audio_param.cpp +104 -0
- package/runtime/ext_gui/audio_param_object.cpp +155 -0
- package/runtime/ext_gui/browser.cpp +45 -50
- package/runtime/ext_gui/browser_abort.cpp +249 -0
- package/runtime/ext_gui/browser_dialogs.cpp +76 -0
- package/runtime/ext_gui/browser_media.cpp +176 -0
- package/runtime/ext_gui/browser_navigation.cpp +130 -0
- package/runtime/ext_gui/canvas.cpp +88 -30
- package/runtime/ext_gui/canvas.h +74 -9
- package/runtime/ext_gui/canvas_image_data.cpp +143 -0
- package/runtime/ext_gui/canvas_internal.h +8 -5
- package/runtime/ext_gui/canvas_pattern.cpp +90 -0
- package/runtime/ext_gui/canvas_raster.cpp +31 -9
- package/runtime/ext_gui/canvas_style.cpp +4 -2
- package/runtime/ext_gui/css_selector.cpp +21 -3
- package/runtime/ext_gui/dom.h +4 -0
- package/runtime/ext_gui/dom_api.cpp +1 -0
- package/runtime/ext_gui/dom_api_canvas.cpp +120 -114
- package/runtime/ext_gui/dom_api_canvas_extra.cpp +57 -2
- package/runtime/ext_gui/dom_api_canvas_image.cpp +239 -0
- package/runtime/ext_gui/dom_api_canvas_paths.cpp +179 -0
- package/runtime/ext_gui/dom_api_computed_style.cpp +124 -0
- package/runtime/ext_gui/dom_api_dataset.cpp +154 -0
- package/runtime/ext_gui/dom_api_document.cpp +58 -5
- package/runtime/ext_gui/dom_api_events.cpp +93 -17
- package/runtime/ext_gui/dom_api_internal.h +71 -2
- package/runtime/ext_gui/dom_api_mutation.cpp +159 -0
- package/runtime/ext_gui/dom_api_node.cpp +40 -19
- package/runtime/ext_gui/dom_api_node_read.cpp +37 -1
- package/runtime/ext_gui/dom_api_path2d.cpp +358 -0
- package/runtime/ext_gui/dom_api_proto.cpp +35 -0
- package/runtime/ext_gui/dom_api_style.cpp +223 -13
- package/runtime/ext_gui/dom_api_webgl.cpp +7 -0
- package/runtime/ext_gui/dom_api_webgl2.cpp +151 -36
- package/runtime/ext_gui/dom_api_webgl2_draw.cpp +3 -3
- package/runtime/ext_gui/dom_api_webgl_buffer.cpp +6 -2
- package/runtime/ext_gui/dom_api_webgl_compressed.cpp +167 -0
- package/runtime/ext_gui/dom_api_webgl_framebuffer.cpp +160 -0
- package/runtime/ext_gui/dom_api_webgl_shader.cpp +4 -4
- package/runtime/ext_gui/dom_api_webgl_source.cpp +161 -0
- package/runtime/ext_gui/dom_api_webgl_state.cpp +169 -23
- package/runtime/ext_gui/dom_api_webgl_texture.cpp +276 -236
- package/runtime/ext_gui/dom_api_webgl_ubo.cpp +81 -0
- package/runtime/ext_gui/gui.cpp +103 -14
- package/runtime/ext_gui/gui_engine.h +56 -4
- package/runtime/ext_gui/gui_events.cpp +80 -9
- package/runtime/ext_gui/image_bitmap.cpp +28 -0
- package/runtime/ext_gui/image_bitmap.h +26 -0
- package/runtime/ext_gui/image_bitmap_browser.cpp +136 -0
- package/runtime/ext_gui/listener_options.h +43 -0
- package/runtime/ext_gui/media.cpp +32 -0
- package/runtime/ext_gui/media.h +13 -0
- package/runtime/ext_gui/media_api.h +23 -0
- package/runtime/ext_gui/paint.cpp +28 -0
- package/runtime/ext_gui/paint.h +4 -0
- package/runtime/ext_gui/webgl.h +152 -18
- package/runtime/ext_gui/webgl_blit.cpp +95 -0
- package/runtime/ext_gui/webgl_buffer.cpp +178 -263
- package/runtime/ext_gui/webgl_buffer_objects.cpp +270 -0
- package/runtime/ext_gui/webgl_clear.cpp +142 -0
- package/runtime/ext_gui/webgl_compressed.cpp +180 -0
- package/runtime/ext_gui/webgl_context.cpp +241 -156
- package/runtime/ext_gui/webgl_draw.cpp +68 -3
- package/runtime/ext_gui/webgl_draw_buffers.cpp +75 -0
- package/runtime/ext_gui/webgl_glsl.h +40 -0
- package/runtime/ext_gui/webgl_glsl_compile.cpp +6 -0
- package/runtime/ext_gui/webgl_glsl_rewrite.cpp +18 -0
- package/runtime/ext_gui/webgl_glsl_scan.cpp +20 -11
- package/runtime/ext_gui/webgl_glsl_scan_block.cpp +126 -0
- package/runtime/ext_gui/webgl_glsl_tokens.h +28 -0
- package/runtime/ext_gui/webgl_pipeline.cpp +71 -19
- package/runtime/ext_gui/webgl_program_blocks.cpp +58 -0
- package/runtime/ext_gui/webgl_program_internal.h +6 -0
- package/runtime/ext_gui/webgl_shader.cpp +13 -1
- package/runtime/ext_gui/webgl_state.cpp +228 -0
- package/runtime/ext_gui/webgl_texture.cpp +144 -17
- package/runtime/ext_gui/webgl_texture_3d.cpp +215 -0
- package/runtime/ext_gui/webgl_uniform_block.h +31 -0
- package/runtime/ext_gui/webgl_webgl2.cpp +58 -5
- package/runtime/ext_gui/window.cpp +14 -65
- package/runtime/ext_gui/window_events.cpp +125 -0
- package/runtime/ext_media/decode_audio.cpp +308 -0
- package/runtime/ext_media/media_bridge.c +2 -0
- package/runtime/rt.h +43 -0
- package/runtime/rt_internal.h +4 -0
- package/runtime/xt_array_buffer.c +30 -0
- package/runtime/xt_builtins.c +0 -21
- package/runtime/xt_containers/access.inc +94 -2
- package/runtime/xt_containers/objects.inc +29 -31
- package/runtime/xt_typed_array/elements.inc +13 -0
- package/scripts/build-media.ts +14 -6
- package/scripts/build-runtime.ts +21 -16
- package/scripts/check-version.ts +39 -9
- package/scripts/package-platform.ts +183 -0
- package/scripts/set-platform-version.ts +62 -0
- package/scripts/verify-platform-package.ts +182 -0
- package/src/cli/main.ts +5 -1
- package/src/driver/runtime-lib.ts +73 -9
- package/src/driver/version.ts +1 -1
- package/src/extensions/gui/index.ts +18 -5
- package/src/extensions/media/index.ts +4 -3
- package/src/parser/context.ts +99 -4
- package/src/parser/literals.ts +6 -12
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — WebGL 2 draw/read buffers and multiple render targets.
|
|
3
|
+
*
|
|
4
|
+
* The framebuffer stores up to four colour attachments and the draw-buffer
|
|
5
|
+
* table that maps pipeline slot N to one of them. `begin_pass` and
|
|
6
|
+
* `create_pipeline` consume the same slots, so a fragment shader's `out`
|
|
7
|
+
* variables land in the attachments the page selected with `drawBuffers`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "webgl.h"
|
|
11
|
+
|
|
12
|
+
#include "gui_internal.h"
|
|
13
|
+
|
|
14
|
+
namespace xtgui {
|
|
15
|
+
|
|
16
|
+
SDL_GPUTexture *WebGLContext::draw_color_texture(int slot) {
|
|
17
|
+
if (slot < 0 || slot >= kWebGLMaxDrawBuffers) return nullptr;
|
|
18
|
+
if (bound_framebuffer_ == 0) {
|
|
19
|
+
ensure_default_target();
|
|
20
|
+
return slot == 0 && default_draw_buffers_[0] == GL_BACK ? color_ : nullptr;
|
|
21
|
+
}
|
|
22
|
+
WebGLFramebuffer *framebuffer = this->framebuffer(bound_framebuffer_);
|
|
23
|
+
if (framebuffer == nullptr) return nullptr;
|
|
24
|
+
const int buffer = framebuffer->draw_buffers[slot];
|
|
25
|
+
const int index = buffer - GL_COLOR_ATTACHMENT0;
|
|
26
|
+
if (index < 0 || index >= kWebGLMaxDrawBuffers) return nullptr;
|
|
27
|
+
if (framebuffer->color_textures[index] == 0) return nullptr;
|
|
28
|
+
WebGLTexture *texture = this->texture(framebuffer->color_textures[index]);
|
|
29
|
+
return texture != nullptr ? ensure_texture_gpu(texture, true) : nullptr;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
int WebGLContext::draw_color_format(int slot) {
|
|
33
|
+
if (bound_framebuffer_ == 0) return SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
|
34
|
+
WebGLFramebuffer *framebuffer = this->framebuffer(bound_framebuffer_);
|
|
35
|
+
if (framebuffer == nullptr) return SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
|
36
|
+
const int index = framebuffer->draw_buffers[slot] - GL_COLOR_ATTACHMENT0;
|
|
37
|
+
if (index < 0 || index >= kWebGLMaxDrawBuffers) {
|
|
38
|
+
return SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
|
39
|
+
}
|
|
40
|
+
WebGLTexture *texture = this->texture(framebuffer->color_textures[index]);
|
|
41
|
+
return texture != nullptr ? (int)texture->format : SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
int WebGLContext::draw_color_layer(int slot) {
|
|
45
|
+
if (slot < 0 || slot >= kWebGLMaxDrawBuffers || bound_framebuffer_ == 0) return 0;
|
|
46
|
+
WebGLFramebuffer *framebuffer = this->framebuffer(bound_framebuffer_);
|
|
47
|
+
if (framebuffer == nullptr) return 0;
|
|
48
|
+
const int index = framebuffer->draw_buffers[slot] - GL_COLOR_ATTACHMENT0;
|
|
49
|
+
if (index < 0 || index >= kWebGLMaxDrawBuffers) return 0;
|
|
50
|
+
return framebuffer->color_layers[index];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
void WebGLContext::draw_buffers(int count, const int *buffers) {
|
|
54
|
+
if (count < 0) count = 0;
|
|
55
|
+
if (count > kWebGLMaxDrawBuffers) count = kWebGLMaxDrawBuffers;
|
|
56
|
+
int *target = default_draw_buffers_;
|
|
57
|
+
if (bound_framebuffer_ != 0) {
|
|
58
|
+
WebGLFramebuffer *framebuffer = this->framebuffer(bound_framebuffer_);
|
|
59
|
+
if (framebuffer == nullptr) return;
|
|
60
|
+
target = framebuffer->draw_buffers;
|
|
61
|
+
}
|
|
62
|
+
for (int i = 0; i < kWebGLMaxDrawBuffers; i++) {
|
|
63
|
+
target[i] = (i < count && buffers != nullptr) ? buffers[i] : GL_NONE;
|
|
64
|
+
}
|
|
65
|
+
end_pass();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
int WebGLContext::draw_buffer_value(int index) {
|
|
69
|
+
if (index < 0 || index >= kWebGLMaxDrawBuffers) return GL_NONE;
|
|
70
|
+
if (bound_framebuffer_ == 0) return default_draw_buffers_[index];
|
|
71
|
+
WebGLFramebuffer *framebuffer = this->framebuffer(bound_framebuffer_);
|
|
72
|
+
return framebuffer != nullptr ? framebuffer->draw_buffers[index] : GL_NONE;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
} // namespace xtgui
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
|
|
23
23
|
#include <cstdint>
|
|
24
24
|
#include <string>
|
|
25
|
+
|
|
26
|
+
#include "webgl_glsl_tokens.h"
|
|
25
27
|
#include <unordered_map>
|
|
26
28
|
#include <utility>
|
|
27
29
|
#include <vector>
|
|
@@ -40,6 +42,32 @@ struct GlslUniformDecl {
|
|
|
40
42
|
std::string extra;
|
|
41
43
|
};
|
|
42
44
|
|
|
45
|
+
/** One member of a user-declared uniform block. */
|
|
46
|
+
struct GlslBlockMemberDecl {
|
|
47
|
+
std::string type;
|
|
48
|
+
std::string name;
|
|
49
|
+
std::string array;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** A user-declared `uniform Block { … } instance;`. The rewriter merges its
|
|
53
|
+
* members into the engine block under `__ub_<instance>_<member>` names and
|
|
54
|
+
* rewrites references, because SDL_GPU has no bindable uniform buffers. */
|
|
55
|
+
struct GlslUniformBlock {
|
|
56
|
+
std::string name;
|
|
57
|
+
std::string instance;
|
|
58
|
+
std::vector<GlslBlockMemberDecl> members;
|
|
59
|
+
size_t begin = 0;
|
|
60
|
+
size_t end = 0;
|
|
61
|
+
bool conditional = false;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** One `instance.member` reference to rename. */
|
|
65
|
+
struct GlslRename {
|
|
66
|
+
size_t begin = 0;
|
|
67
|
+
size_t end = 0;
|
|
68
|
+
std::string text;
|
|
69
|
+
};
|
|
70
|
+
|
|
43
71
|
/** Where one declaration sits in the source text, and what it declares. */
|
|
44
72
|
struct GlslDeclSite {
|
|
45
73
|
enum Kind { Uniform, Sampler, Attribute, Varying, FragmentOut };
|
|
@@ -53,6 +81,14 @@ struct GlslDeclSite {
|
|
|
53
81
|
};
|
|
54
82
|
|
|
55
83
|
/** The declarations a shader contributes to a program. */
|
|
84
|
+
struct GlslShaderInfo;
|
|
85
|
+
|
|
86
|
+
/** Parse a user uniform block at `uniform_index`, merging its members. Returns
|
|
87
|
+
* true when a block declaration was consumed; `after` is the next token. */
|
|
88
|
+
bool scan_uniform_block(const std::vector<GlslToken> &tokens, size_t uniform_index,
|
|
89
|
+
size_t pending_layout, bool conditional, GlslShaderInfo *info,
|
|
90
|
+
size_t *after, size_t *first_uniform_any);
|
|
91
|
+
|
|
56
92
|
struct GlslShaderInfo {
|
|
57
93
|
std::vector<GlslUniformDecl> uniforms; // non-sampler
|
|
58
94
|
std::vector<GlslUniformDecl> samplers;
|
|
@@ -65,6 +101,10 @@ struct GlslShaderInfo {
|
|
|
65
101
|
std::vector<std::pair<size_t, size_t>> structs;
|
|
66
102
|
/** The text of those definitions, shared across stages at link time. */
|
|
67
103
|
std::vector<std::string> struct_definitions;
|
|
104
|
+
/** User uniform blocks, merged into the single engine block at link time. */
|
|
105
|
+
std::vector<GlslUniformBlock> blocks;
|
|
106
|
+
/** References the rewriter must spell with the prefixed member name. */
|
|
107
|
+
std::vector<GlslRename> renames;
|
|
68
108
|
/** True when the source writes `gl_FragColor` / `gl_FragData[0]`. */
|
|
69
109
|
bool legacy_fragment_output = false;
|
|
70
110
|
/** True when the source declared its own `out` variable (ES 3.00). */
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
#include "webgl_glsl.h"
|
|
12
12
|
|
|
13
|
+
#include <cstdio>
|
|
14
|
+
#include <cstdlib>
|
|
13
15
|
#include <cstring>
|
|
14
16
|
#include <string>
|
|
15
17
|
#include <unordered_map>
|
|
@@ -347,6 +349,10 @@ bool compile_glsl(const std::string &source, bool fragment, std::vector<uint32_t
|
|
|
347
349
|
}
|
|
348
350
|
const EShLanguage stage = fragment ? EShLangFragment : EShLangVertex;
|
|
349
351
|
glslang::TShader shader(stage);
|
|
352
|
+
if (getenv("XT_WEBGL_DUMP_GLSL") != nullptr) {
|
|
353
|
+
fprintf(stderr, "--- GLSL %s ---\n%s\n---\n", fragment ? "fragment" : "vertex",
|
|
354
|
+
source.c_str());
|
|
355
|
+
}
|
|
350
356
|
const char *text = source.c_str();
|
|
351
357
|
shader.setStrings(&text, 1);
|
|
352
358
|
shader.setEntryPoint("main");
|
|
@@ -213,6 +213,24 @@ std::string rewrite_glsl(const std::string &source, bool fragment, const GlslLin
|
|
|
213
213
|
edits.push_back(block_edit);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
/* Drop user uniform-block declarations (their members are already part of
|
|
217
|
+
* the generated block) and spell `instance.member` with the prefixed name. */
|
|
218
|
+
for (const GlslUniformBlock &block_decl : info.blocks) {
|
|
219
|
+
Edit remove;
|
|
220
|
+
remove.begin = block_decl.begin;
|
|
221
|
+
remove.end = block_decl.end;
|
|
222
|
+
remove.order = 1;
|
|
223
|
+
edits.push_back(remove);
|
|
224
|
+
}
|
|
225
|
+
for (const GlslRename &rename : info.renames) {
|
|
226
|
+
Edit edit;
|
|
227
|
+
edit.begin = rename.begin;
|
|
228
|
+
edit.end = rename.end;
|
|
229
|
+
edit.text = rename.text;
|
|
230
|
+
edit.order = 1;
|
|
231
|
+
edits.push_back(edit);
|
|
232
|
+
}
|
|
233
|
+
|
|
216
234
|
int fragment_output = 0;
|
|
217
235
|
for (const GlslDeclSite &site : info.sites) {
|
|
218
236
|
Edit edit;
|
|
@@ -17,12 +17,7 @@
|
|
|
17
17
|
namespace xtgui {
|
|
18
18
|
namespace {
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
enum Kind { Ident, Number, Punct, Directive } kind = Punct;
|
|
22
|
-
std::string text;
|
|
23
|
-
size_t begin = 0;
|
|
24
|
-
size_t end = 0;
|
|
25
|
-
};
|
|
20
|
+
using Token = GlslToken;
|
|
26
21
|
|
|
27
22
|
bool is_ident_start(char c) {
|
|
28
23
|
return std::isalpha((unsigned char)c) != 0 || c == '_';
|
|
@@ -100,11 +95,6 @@ std::vector<Token> tokenize(const std::string &source) {
|
|
|
100
95
|
return tokens;
|
|
101
96
|
}
|
|
102
97
|
|
|
103
|
-
bool is_qualifier(const std::string &text) {
|
|
104
|
-
return text == "highp" || text == "mediump" || text == "lowp" || text == "flat" ||
|
|
105
|
-
text == "smooth" || text == "centroid" || text == "invariant" || text == "precise" ||
|
|
106
|
-
text == "noperspective" || text == "sample" || text == "const";
|
|
107
|
-
}
|
|
108
98
|
|
|
109
99
|
bool is_sampler_type(const std::string &type) {
|
|
110
100
|
return type.rfind("sampler", 0) == 0 || type == "atomic_uint";
|
|
@@ -435,6 +425,14 @@ void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info) {
|
|
|
435
425
|
info->legacy_fragment_output = true;
|
|
436
426
|
continue;
|
|
437
427
|
}
|
|
428
|
+
/* SDL_GPU render targets carry no writable depth attachment, so there is
|
|
429
|
+
* no place for a shader-written depth value; reject it with a clear log
|
|
430
|
+
* instead of failing later inside glslang. */
|
|
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
|
+
}
|
|
438
436
|
/* Declarations inside a definitively false preprocessor branch never reach
|
|
439
437
|
* the compiler; rewriting them would move their types/macros (and array
|
|
440
438
|
* sizes such as `MORPHTARGETS_COUNT`) outside that branch. */
|
|
@@ -503,6 +501,17 @@ void scan_glsl(const std::string &source, bool fragment, GlslShaderInfo *info) {
|
|
|
503
501
|
continue;
|
|
504
502
|
}
|
|
505
503
|
|
|
504
|
+
if (kind == GlslDeclSite::Uniform) {
|
|
505
|
+
size_t after = i;
|
|
506
|
+
if (scan_uniform_block(tokens, i, pending_layout, !condition_stack.empty(), info, &after,
|
|
507
|
+
&first_uniform_any)) {
|
|
508
|
+
pending_layout = std::string::npos;
|
|
509
|
+
pending_location = -1;
|
|
510
|
+
i = after;
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
506
515
|
/* Find the terminating semicolon at bracket/paren depth 0. */
|
|
507
516
|
size_t semicolon = i + 1;
|
|
508
517
|
int brackets = 0;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — GLSL user uniform-block scanner.
|
|
3
|
+
*
|
|
4
|
+
* The block's members are merged into the engine's single std140 block under
|
|
5
|
+
* `xt_ub_<instance>_<member>` names; `instance.member` references are renamed
|
|
6
|
+
* by the rewriter. SDL_GPU has no bindable uniform buffers, so the draw path
|
|
7
|
+
* copies the bound buffer into these members instead.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "webgl_glsl.h"
|
|
11
|
+
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <vector>
|
|
14
|
+
|
|
15
|
+
namespace xtgui {
|
|
16
|
+
|
|
17
|
+
bool scan_uniform_block(const std::vector<GlslToken> &tokens, size_t uniform_index,
|
|
18
|
+
size_t pending_layout, bool conditional, GlslShaderInfo *info,
|
|
19
|
+
size_t *after, size_t *first_uniform_any) {
|
|
20
|
+
size_t brace = uniform_index + 1;
|
|
21
|
+
while (brace < tokens.size() && tokens[brace].text != "{" && tokens[brace].text != ";") {
|
|
22
|
+
brace++;
|
|
23
|
+
}
|
|
24
|
+
if (brace >= tokens.size() || tokens[brace].text != "{") return false;
|
|
25
|
+
|
|
26
|
+
std::string block_name;
|
|
27
|
+
for (size_t t = uniform_index + 1; t < brace; t++) {
|
|
28
|
+
if (tokens[t].kind == GlslToken::Ident) block_name = tokens[t].text;
|
|
29
|
+
}
|
|
30
|
+
size_t close = brace;
|
|
31
|
+
int braces = 0;
|
|
32
|
+
for (; close < tokens.size(); close++) {
|
|
33
|
+
if (tokens[close].text == "{") braces++;
|
|
34
|
+
if (tokens[close].text == "}") {
|
|
35
|
+
braces--;
|
|
36
|
+
if (braces == 0) break;
|
|
37
|
+
}
|
|
38
|
+
if (tokens[close].kind == GlslToken::Directive) {
|
|
39
|
+
info->unsupported = "preprocessor directives inside uniform blocks are not supported";
|
|
40
|
+
*after = close;
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (close + 2 >= tokens.size() || tokens[close + 1].kind != GlslToken::Ident ||
|
|
45
|
+
tokens[close + 2].text != ";") {
|
|
46
|
+
info->unsupported = "uniform blocks without an instance name are not supported";
|
|
47
|
+
*after = close;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
GlslUniformBlock block;
|
|
52
|
+
block.name = block_name;
|
|
53
|
+
block.instance = tokens[close + 1].text;
|
|
54
|
+
block.begin = pending_layout != std::string::npos ? tokens[pending_layout].begin
|
|
55
|
+
: tokens[uniform_index].begin;
|
|
56
|
+
block.end = tokens[close + 2].end;
|
|
57
|
+
block.conditional = conditional;
|
|
58
|
+
bool valid = !block.instance.empty();
|
|
59
|
+
size_t member_start = brace + 1;
|
|
60
|
+
int inner_braces = 0;
|
|
61
|
+
for (size_t t = brace + 1; t < close && valid; t++) {
|
|
62
|
+
if (tokens[t].text == "{") inner_braces++;
|
|
63
|
+
if (tokens[t].text == "}") inner_braces--;
|
|
64
|
+
if (!(tokens[t].text == ";" && inner_braces == 0)) continue;
|
|
65
|
+
size_t at = member_start;
|
|
66
|
+
while (at < t && tokens[at].kind == GlslToken::Ident && is_qualifier(tokens[at].text)) at++;
|
|
67
|
+
if (at + 1 >= t || tokens[at].kind != GlslToken::Ident ||
|
|
68
|
+
tokens[at + 1].kind != GlslToken::Ident) {
|
|
69
|
+
valid = false;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
GlslBlockMemberDecl member;
|
|
73
|
+
member.type = tokens[at].text;
|
|
74
|
+
member.name = tokens[at + 1].text;
|
|
75
|
+
size_t array_at = at + 2;
|
|
76
|
+
if (array_at < t && tokens[array_at].text == "[") {
|
|
77
|
+
std::string array;
|
|
78
|
+
for (size_t k = array_at; k < t; k++) array += tokens[k].text;
|
|
79
|
+
member.array = array;
|
|
80
|
+
}
|
|
81
|
+
if (member.type.rfind("sampler", 0) == 0 || member.type == "atomic_uint" ||
|
|
82
|
+
member.type == "struct") {
|
|
83
|
+
valid = false;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
block.members.push_back(member);
|
|
87
|
+
member_start = t + 1;
|
|
88
|
+
}
|
|
89
|
+
if (!valid || block.members.empty()) {
|
|
90
|
+
info->unsupported = "unsupported uniform block declaration";
|
|
91
|
+
*after = close;
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (size_t t = 0; t + 2 < tokens.size(); t++) {
|
|
96
|
+
if (tokens[t].kind != GlslToken::Ident || tokens[t].text != block.instance) continue;
|
|
97
|
+
if (tokens[t + 1].text != "." || tokens[t + 2].kind != GlslToken::Ident) continue;
|
|
98
|
+
if (tokens[t].begin >= block.begin && tokens[t].begin < block.end) continue;
|
|
99
|
+
bool is_member = false;
|
|
100
|
+
for (const GlslBlockMemberDecl &member : block.members) {
|
|
101
|
+
if (member.name == tokens[t + 2].text) is_member = true;
|
|
102
|
+
}
|
|
103
|
+
if (!is_member) continue;
|
|
104
|
+
GlslRename rename;
|
|
105
|
+
rename.begin = tokens[t].begin;
|
|
106
|
+
rename.end = tokens[t + 2].end;
|
|
107
|
+
rename.text = "xt_ub_" + block.instance + "_" + tokens[t + 2].text;
|
|
108
|
+
info->renames.push_back(rename);
|
|
109
|
+
}
|
|
110
|
+
for (const GlslBlockMemberDecl &member : block.members) {
|
|
111
|
+
GlslUniformDecl decl;
|
|
112
|
+
decl.type = member.type;
|
|
113
|
+
decl.name = "xt_ub_" + block.instance + "_" + member.name;
|
|
114
|
+
decl.array = member.array;
|
|
115
|
+
info->uniforms.push_back(decl);
|
|
116
|
+
}
|
|
117
|
+
if (*first_uniform_any == std::string::npos) *first_uniform_any = block.begin;
|
|
118
|
+
if (!block.conditional && info->first_uniform_offset == std::string::npos) {
|
|
119
|
+
info->first_uniform_offset = block.begin;
|
|
120
|
+
}
|
|
121
|
+
info->blocks.push_back(block);
|
|
122
|
+
*after = close + 2;
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} // namespace xtgui
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — shared GLSL token type for the scanner and block parser.
|
|
3
|
+
*/
|
|
4
|
+
#ifndef XT_GUI_WEBGL_GLSL_TOKENS_H
|
|
5
|
+
#define XT_GUI_WEBGL_GLSL_TOKENS_H
|
|
6
|
+
|
|
7
|
+
#include <cstddef>
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
namespace xtgui {
|
|
11
|
+
|
|
12
|
+
struct GlslToken {
|
|
13
|
+
enum Kind { Ident, Number, Punct, Directive } kind = Punct;
|
|
14
|
+
std::string text;
|
|
15
|
+
size_t begin = 0;
|
|
16
|
+
size_t end = 0;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
inline bool is_qualifier(const std::string &text) {
|
|
20
|
+
return text == "const" || text == "uniform" || text == "attribute" || text == "varying" ||
|
|
21
|
+
text == "in" || text == "out" || text == "inout" || text == "highp" ||
|
|
22
|
+
text == "mediump" || text == "lowp" || text == "flat" || text == "smooth" ||
|
|
23
|
+
text == "centroid" || text == "invariant" || text == "precision";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
} // namespace xtgui
|
|
27
|
+
|
|
28
|
+
#endif /* XT_GUI_WEBGL_GLSL_TOKENS_H */
|
|
@@ -87,6 +87,46 @@ SDL_GPUCompareOp compare_op(int func) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
SDL_GPUStencilOp stencil_op(int op) {
|
|
91
|
+
switch (op) {
|
|
92
|
+
case GL_ZERO:
|
|
93
|
+
return SDL_GPU_STENCILOP_ZERO;
|
|
94
|
+
case GL_REPLACE:
|
|
95
|
+
return SDL_GPU_STENCILOP_REPLACE;
|
|
96
|
+
case GL_INCR:
|
|
97
|
+
return SDL_GPU_STENCILOP_INCREMENT_AND_CLAMP;
|
|
98
|
+
case GL_INCR_WRAP:
|
|
99
|
+
return SDL_GPU_STENCILOP_INCREMENT_AND_WRAP;
|
|
100
|
+
case GL_DECR:
|
|
101
|
+
return SDL_GPU_STENCILOP_DECREMENT_AND_CLAMP;
|
|
102
|
+
case GL_DECR_WRAP:
|
|
103
|
+
return SDL_GPU_STENCILOP_DECREMENT_AND_WRAP;
|
|
104
|
+
case GL_INVERT:
|
|
105
|
+
return SDL_GPU_STENCILOP_INVERT;
|
|
106
|
+
default:
|
|
107
|
+
return SDL_GPU_STENCILOP_KEEP;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** SDL 3.2 has no per-pipeline stencil write mask. A mask of 0 means "write
|
|
112
|
+
* nothing", which every op can express as KEEP; a partial mask cannot be
|
|
113
|
+
* represented, so the op applies to all bits. */
|
|
114
|
+
SDL_GPUStencilOpState stencil_face_state(const WebGLStencilFace &face) {
|
|
115
|
+
SDL_GPUStencilOpState state;
|
|
116
|
+
memset(&state, 0, sizeof(state));
|
|
117
|
+
if (face.write_mask == 0) {
|
|
118
|
+
state.fail_op = SDL_GPU_STENCILOP_KEEP;
|
|
119
|
+
state.pass_op = SDL_GPU_STENCILOP_KEEP;
|
|
120
|
+
state.depth_fail_op = SDL_GPU_STENCILOP_KEEP;
|
|
121
|
+
} else {
|
|
122
|
+
state.fail_op = stencil_op(face.fail);
|
|
123
|
+
state.pass_op = stencil_op(face.zpass);
|
|
124
|
+
state.depth_fail_op = stencil_op(face.zfail);
|
|
125
|
+
}
|
|
126
|
+
state.compare_op = compare_op(face.func);
|
|
127
|
+
return state;
|
|
128
|
+
}
|
|
129
|
+
|
|
90
130
|
SDL_GPUPrimitiveType primitive_of(int mode) {
|
|
91
131
|
switch (mode) {
|
|
92
132
|
case GL_POINTS:
|
|
@@ -215,22 +255,27 @@ SDL_GPUGraphicsPipeline *WebGLContext::create_pipeline(
|
|
|
215
255
|
const SDL_GPUVertexAttribute *attrs, const SDL_GPUVertexBufferDescription *buffers,
|
|
216
256
|
const std::string &key) {
|
|
217
257
|
(void)index_size;
|
|
218
|
-
SDL_GPUColorTargetDescription
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
258
|
+
SDL_GPUColorTargetDescription color_targets[kWebGLMaxDrawBuffers];
|
|
259
|
+
const int color_target_count =
|
|
260
|
+
state_.color_target_count > 0 ? state_.color_target_count : 1;
|
|
261
|
+
for (int i = 0; i < color_target_count; i++) {
|
|
262
|
+
SDL_GPUColorTargetDescription &color_target = color_targets[i];
|
|
263
|
+
memset(&color_target, 0, sizeof(color_target));
|
|
264
|
+
color_target.format = (SDL_GPUTextureFormat)state_.color_formats[i];
|
|
265
|
+
color_target.blend_state.enable_blend = state_.blend;
|
|
266
|
+
color_target.blend_state.src_color_blendfactor = blend_factor(state_.blend_src_rgb);
|
|
267
|
+
color_target.blend_state.dst_color_blendfactor = blend_factor(state_.blend_dst_rgb);
|
|
268
|
+
color_target.blend_state.color_blend_op = blend_op(state_.blend_eq_rgb);
|
|
269
|
+
color_target.blend_state.src_alpha_blendfactor = blend_factor(state_.blend_src_alpha);
|
|
270
|
+
color_target.blend_state.dst_alpha_blendfactor = blend_factor(state_.blend_dst_alpha);
|
|
271
|
+
color_target.blend_state.alpha_blend_op = blend_op(state_.blend_eq_alpha);
|
|
272
|
+
color_target.blend_state.enable_color_write_mask = true;
|
|
273
|
+
color_target.blend_state.color_write_mask =
|
|
274
|
+
(state_.color_mask[0] ? SDL_GPU_COLORCOMPONENT_R : 0) |
|
|
275
|
+
(state_.color_mask[1] ? SDL_GPU_COLORCOMPONENT_G : 0) |
|
|
276
|
+
(state_.color_mask[2] ? SDL_GPU_COLORCOMPONENT_B : 0) |
|
|
277
|
+
(state_.color_mask[3] ? SDL_GPU_COLORCOMPONENT_A : 0);
|
|
278
|
+
}
|
|
234
279
|
|
|
235
280
|
SDL_GPUGraphicsPipelineCreateInfo info;
|
|
236
281
|
memset(&info, 0, sizeof(info));
|
|
@@ -255,9 +300,16 @@ SDL_GPUGraphicsPipeline *WebGLContext::create_pipeline(
|
|
|
255
300
|
info.depth_stencil_state.enable_depth_test = state_.depth_test;
|
|
256
301
|
info.depth_stencil_state.enable_depth_write = state_.depth_write;
|
|
257
302
|
info.depth_stencil_state.compare_op = compare_op(state_.depth_func);
|
|
258
|
-
info.
|
|
259
|
-
info.
|
|
260
|
-
info.
|
|
303
|
+
info.depth_stencil_state.enable_stencil_test = state_.stencil;
|
|
304
|
+
info.depth_stencil_state.front_stencil_state = stencil_face_state(state_.stencil_front);
|
|
305
|
+
info.depth_stencil_state.back_stencil_state = stencil_face_state(state_.stencil_back);
|
|
306
|
+
/* SDL_GPU has one compare/write mask for both faces; use the front-face
|
|
307
|
+
* values (WebGL's default sets both faces alike). */
|
|
308
|
+
info.depth_stencil_state.compare_mask = (Uint8)(state_.stencil_front.value_mask & 0xFF);
|
|
309
|
+
info.depth_stencil_state.write_mask = (Uint8)(state_.stencil_front.write_mask & 0xFF);
|
|
310
|
+
info.target_info.color_target_descriptions = color_targets;
|
|
311
|
+
info.target_info.num_color_targets = (Uint32)color_target_count;
|
|
312
|
+
info.target_info.depth_stencil_format = (SDL_GPUTextureFormat)state_.depth_format;
|
|
261
313
|
info.target_info.has_depth_stencil_target = true;
|
|
262
314
|
|
|
263
315
|
SDL_GPUGraphicsPipeline *pipeline = SDL_CreateGPUGraphicsPipeline(guidev::g_device, &info);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — user uniform blocks reflected from the merged block.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
#include "webgl.h"
|
|
6
|
+
|
|
7
|
+
#include <algorithm>
|
|
8
|
+
#include <vector>
|
|
9
|
+
|
|
10
|
+
#include "webgl_program_internal.h"
|
|
11
|
+
|
|
12
|
+
namespace xtgui {
|
|
13
|
+
namespace webgl_detail {
|
|
14
|
+
|
|
15
|
+
void build_uniform_blocks(WebGLProgram *record, const std::vector<GlslUniformBlock> &vertex_blocks,
|
|
16
|
+
const std::vector<GlslUniformBlock> &fragment_blocks,
|
|
17
|
+
const std::vector<GlslBlockMember> &members) {
|
|
18
|
+
if (record == nullptr) return;
|
|
19
|
+
/* Build the user-facing uniform-block table. Members were merged into the
|
|
20
|
+
* engine block as `__ub_<instance>_<member>`, so their reflected offsets give
|
|
21
|
+
* the block's base and size without a second descriptor set. */
|
|
22
|
+
auto add_blocks = [&](const std::vector<GlslUniformBlock> &blocks) {
|
|
23
|
+
for (const GlslUniformBlock &decl : blocks) {
|
|
24
|
+
bool exists = false;
|
|
25
|
+
for (const WebGLUniformBlock &existing : record->blocks) {
|
|
26
|
+
if (existing.instance == decl.instance) exists = true;
|
|
27
|
+
}
|
|
28
|
+
if (exists) continue;
|
|
29
|
+
WebGLUniformBlock block;
|
|
30
|
+
block.name = decl.name;
|
|
31
|
+
block.instance = decl.instance;
|
|
32
|
+
int base = -1;
|
|
33
|
+
int end = 0;
|
|
34
|
+
int count = 0;
|
|
35
|
+
for (const GlslBlockMemberDecl &member : decl.members) {
|
|
36
|
+
const std::string name = "xt_ub_" + decl.instance + "_" + member.name;
|
|
37
|
+
for (const GlslBlockMember &reflected : members) {
|
|
38
|
+
if (reflected.name != name && reflected.name != name + "[0]") continue;
|
|
39
|
+
if (base < 0 || reflected.offset < base) base = reflected.offset;
|
|
40
|
+
end = std::max(end, reflected.offset + webgl_detail::member_bytes(reflected));
|
|
41
|
+
count++;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (base < 0 || count == 0) continue;
|
|
46
|
+
block.base_offset = base;
|
|
47
|
+
block.data_size = ((end - base) + 15) & ~15;
|
|
48
|
+
block.member_count = count;
|
|
49
|
+
record->blocks.push_back(block);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
add_blocks(vertex_blocks);
|
|
53
|
+
add_blocks(fragment_blocks);
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
} // namespace webgl_detail
|
|
58
|
+
} // namespace xtgui
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#ifndef XT_GUI_WEBGL_PROGRAM_INTERNAL_H
|
|
5
5
|
#define XT_GUI_WEBGL_PROGRAM_INTERNAL_H
|
|
6
6
|
|
|
7
|
+
#include "webgl.h"
|
|
7
8
|
#include "webgl_glsl.h"
|
|
8
9
|
|
|
9
10
|
namespace xtgui {
|
|
@@ -12,6 +13,11 @@ namespace webgl_detail {
|
|
|
12
13
|
/** Bytes a std140 block member occupies (the whole array for an array). */
|
|
13
14
|
int member_bytes(const GlslBlockMember &member);
|
|
14
15
|
|
|
16
|
+
/** Fill `record->blocks` from the user blocks merged into the engine block. */
|
|
17
|
+
void build_uniform_blocks(WebGLProgram *record, const std::vector<GlslUniformBlock> &vertex_blocks,
|
|
18
|
+
const std::vector<GlslUniformBlock> &fragment_blocks,
|
|
19
|
+
const std::vector<GlslBlockMember> &members);
|
|
20
|
+
|
|
15
21
|
} // namespace webgl_detail
|
|
16
22
|
} // namespace xtgui
|
|
17
23
|
|
|
@@ -40,6 +40,8 @@ int gl_type_of(const std::string &type) {
|
|
|
40
40
|
if (type == "mat4") return GL_FLOAT_MAT4;
|
|
41
41
|
if (type == "sampler2D") return GL_SAMPLER_2D;
|
|
42
42
|
if (type == "samplerCube") return GL_SAMPLER_CUBE;
|
|
43
|
+
if (type == "sampler3D") return GL_SAMPLER_3D;
|
|
44
|
+
if (type == "sampler2DArray") return GL_SAMPLER_2D_ARRAY;
|
|
43
45
|
return 0;
|
|
44
46
|
}
|
|
45
47
|
|
|
@@ -380,7 +382,15 @@ bool WebGLContext::link_program(uint32_t id) {
|
|
|
380
382
|
reflect_uniform_block(vs_spirv, &members);
|
|
381
383
|
std::vector<GlslBlockMember> fragment_members;
|
|
382
384
|
reflect_uniform_block(fs_spirv, &fragment_members);
|
|
383
|
-
|
|
385
|
+
/* Keep members declared by either stage: a uniform block may only be read by
|
|
386
|
+
* the fragment shader while the vertex stage contributes other uniforms. */
|
|
387
|
+
for (const GlslBlockMember &member : fragment_members) {
|
|
388
|
+
bool present = false;
|
|
389
|
+
for (const GlslBlockMember &existing : members) {
|
|
390
|
+
if (existing.name == member.name) present = true;
|
|
391
|
+
}
|
|
392
|
+
if (!present) members.push_back(member);
|
|
393
|
+
}
|
|
384
394
|
|
|
385
395
|
record->uniforms.clear();
|
|
386
396
|
record->uniform_index.clear();
|
|
@@ -445,6 +455,8 @@ bool WebGLContext::link_program(uint32_t id) {
|
|
|
445
455
|
for (const GlslUniformDecl &decl : vs_info.samplers) add_sampler(record, &record->vs_sampler_uniforms, decl);
|
|
446
456
|
for (const GlslUniformDecl &decl : fs_info.samplers) add_sampler(record, &record->fs_sampler_uniforms, decl);
|
|
447
457
|
|
|
458
|
+
webgl_detail::build_uniform_blocks(record, vs_info.blocks, fs_info.blocks, members);
|
|
459
|
+
|
|
448
460
|
/* (Re)create the SDL shaders. */
|
|
449
461
|
if (guidev::g_device == nullptr) {
|
|
450
462
|
record->log = "no GPU device";
|