Shader compilation failure under MoltenVK with polar scalers
STR:
- Build libplacebo 32837eb1 on macOS with Vulkan support via MoltenVK.
- Play a file using a polar scaler (e.g. EWA Jinc).
Observe error (log truncated to critical components):
Spent 49.106 ms translating SPIR-V
[mvk-error] VK_ERROR_INITIALIZATION_FAILED: Shader library compile failed (Error code 3):
program_source:101:28: error: zero-length arrays are not permitted in C++
threadgroup float _250[_247];
^~~~
program_source:102:28: error: zero-length arrays are not permitted in C++
threadgroup float _262[_259];
^~~~
.
[mvk-error] VK_ERROR_INVALID_SHADER_NV: Compute shader function could not be compiled into pipeline. See previous logged error.
vk_recreate_pipelines(vk, pass, has_spec, NULL, pipe): VK_ERROR_INVALID_SHADER_NV (../src/vulkan/gpu_pass.c:615)
compute shader source:
[ 1] #version 450
…
[ 33] layout(constant_id=0) const int _iw_12_4 = 0;
[ 34] layout(constant_id=1) const int _ih_13_4 = 0;
…
[ 59] shared float _in_11_40[_ih_13_4 * _iw_12_4];
[ 60] shared float _in_11_41[_ih_13_4 * _iw_12_4];
Note that _in_11_40
is being declared as an array of size 0 * 0
, which ultimately makes it through to the MSL generated and compiled by MoltenVK; MSL doesn't support setting array sizes based on function constants (the Metal equivalent of specialization constants). See https://github.com/KhronosGroup/Vulkan-Portability/issues/10 for details.
This comes from this code in src/shaders/sampling.c
:
ident_t iw_c = sh_const(sh, (struct pl_shader_const) {
.type = PL_VAR_SINT,
.compile_time = true,
.name ="iw",
.data = &iw,
});
ident_t ih_c = sh_const(sh, (struct pl_shader_const) {
.type = PL_VAR_SINT,
.compile_time = true,
.name = "ih",
.data = &ih,
});
Which calls sh_const
in src/shaders.c
, with the shader code ultimately being generated by this code in src/dispatch.c
:
const struct pl_shader_const *sc = &res->constants[i];
ADD(pre, "layout(constant_id=%"PRIu32") const %s %s = 0; \n",
pass_params->constants[i].id, types[sc->type], sc->name);
I'm currently working around this using this patch:
diff --git a/src/shaders.c b/src/shaders.c
index 4e684a5..a526399 100644
--- a/src/shaders.c
+++ b/src/shaders.c
@@ -258,7 +258,7 @@ ident_t sh_const(pl_shader sh, struct pl_shader_const sc)
sc.name = sh_fresh(sh, sc.name);
pl_gpu gpu = SH_GPU(sh);
- if (gpu && gpu->limits.max_constants) {
+ if (gpu && gpu->limits.max_constants && 0) {
sc.data = pl_memdup(SH_TMP(sh), sc.data, pl_var_type_size(sc.type));
PL_ARRAY_APPEND(sh, sh->consts, sc);
return (ident_t) sc.name;
It seems to me that the most appropriate solution would be:
- Detect that the driver exposes
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
- Give
pl_shader_const
an extra arg indicating that the value will be used to compute an array size - If the driver has
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
and the array-size arg is set, skip theif (gpu && gpu->limits.max_constants)
path and use the fallback one