diff --git a/reference/opt/shaders-msl/frag/gather-compare-const-offsets.frag b/reference/opt/shaders-msl/frag/gather-compare-const-offsets.frag index 212d9a9e..1e2d08f0 100644 --- a/reference/opt/shaders-msl/frag/gather-compare-const-offsets.frag +++ b/reference/opt/shaders-msl/frag/gather-compare-const-offsets.frag @@ -56,7 +56,31 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } -// Wrapper function that processes a texture gather with a constant offset array. +// Wrapper function that processes a device texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherCompareConstOffsets(const device Tex& t, sampler s, Toff coffsets, Tp... params) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + rslts[i] = t.gather_compare(s, spvForward(params)..., coffsets[i]); + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a constant texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherCompareConstOffsets(const constant Tex& t, sampler s, Toff coffsets, Tp... params) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + rslts[i] = t.gather_compare(s, spvForward(params)..., coffsets[i]); + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a thread texture gather with a constant offset array. template class Tex, typename Toff, typename... Tp> inline vec spvGatherCompareConstOffsets(const thread Tex& t, sampler s, Toff coffsets, Tp... params) { diff --git a/reference/opt/shaders-msl/frag/gather-const-offsets.frag b/reference/opt/shaders-msl/frag/gather-const-offsets.frag index 871125f6..d529aad8 100644 --- a/reference/opt/shaders-msl/frag/gather-const-offsets.frag +++ b/reference/opt/shaders-msl/frag/gather-const-offsets.frag @@ -56,7 +56,59 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } -// Wrapper function that processes a texture gather with a constant offset array. +// Wrapper function that processes a device texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherConstOffsets(const device Tex& t, sampler s, Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + switch (c) + { + case component::x: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::x); + break; + case component::y: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::y); + break; + case component::z: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::z); + break; + case component::w: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::w); + break; + } + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a constant texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherConstOffsets(const constant Tex& t, sampler s, Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + switch (c) + { + case component::x: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::x); + break; + case component::y: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::y); + break; + case component::z: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::z); + break; + case component::w: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::w); + break; + } + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a thread texture gather with a constant offset array. template class Tex, typename Toff, typename... Tp> inline vec spvGatherConstOffsets(const thread Tex& t, sampler s, Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c) { diff --git a/reference/shaders-msl/frag/gather-compare-const-offsets.frag b/reference/shaders-msl/frag/gather-compare-const-offsets.frag index 212d9a9e..1e2d08f0 100644 --- a/reference/shaders-msl/frag/gather-compare-const-offsets.frag +++ b/reference/shaders-msl/frag/gather-compare-const-offsets.frag @@ -56,7 +56,31 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } -// Wrapper function that processes a texture gather with a constant offset array. +// Wrapper function that processes a device texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherCompareConstOffsets(const device Tex& t, sampler s, Toff coffsets, Tp... params) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + rslts[i] = t.gather_compare(s, spvForward(params)..., coffsets[i]); + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a constant texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherCompareConstOffsets(const constant Tex& t, sampler s, Toff coffsets, Tp... params) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + rslts[i] = t.gather_compare(s, spvForward(params)..., coffsets[i]); + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a thread texture gather with a constant offset array. template class Tex, typename Toff, typename... Tp> inline vec spvGatherCompareConstOffsets(const thread Tex& t, sampler s, Toff coffsets, Tp... params) { diff --git a/reference/shaders-msl/frag/gather-const-offsets.frag b/reference/shaders-msl/frag/gather-const-offsets.frag index 871125f6..d529aad8 100644 --- a/reference/shaders-msl/frag/gather-const-offsets.frag +++ b/reference/shaders-msl/frag/gather-const-offsets.frag @@ -56,7 +56,59 @@ template inline constexpr thread T&& spvForward(thread typename spvR return static_cast(x); } -// Wrapper function that processes a texture gather with a constant offset array. +// Wrapper function that processes a device texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherConstOffsets(const device Tex& t, sampler s, Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + switch (c) + { + case component::x: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::x); + break; + case component::y: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::y); + break; + case component::z: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::z); + break; + case component::w: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::w); + break; + } + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a constant texture gather with a constant offset array. +template class Tex, typename Toff, typename... Tp> +inline vec spvGatherConstOffsets(const constant Tex& t, sampler s, Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c) +{ + vec rslts[4]; + for (uint i = 0; i < 4; i++) + { + switch (c) + { + case component::x: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::x); + break; + case component::y: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::y); + break; + case component::z: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::z); + break; + case component::w: + rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::w); + break; + } + } + return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w); +} + +// Wrapper function that processes a thread texture gather with a constant offset array. template class Tex, typename Toff, typename... Tp> inline vec spvGatherConstOffsets(const thread Tex& t, sampler s, Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c) { diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 0682caf6..ffce7fab 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -5615,6 +5615,10 @@ void CompilerMSL::emit_custom_templates() // otherwise they will cause problems when linked together in a single Metallib. void CompilerMSL::emit_custom_functions() { + // Use when outputting overloaded functions to cover different address spaces. + static const char *texture_addr_spaces[] = { "device", "constant", "thread" }; + static uint32_t texture_addr_space_count = sizeof(texture_addr_spaces) / sizeof(char*); + if (spv_function_implementations.count(SPVFuncImplArrayCopyMultidim)) spv_function_implementations.insert(SPVFuncImplArrayCopy); @@ -6264,54 +6268,62 @@ void CompilerMSL::emit_custom_functions() break; case SPVFuncImplGatherConstOffsets: - statement("// Wrapper function that processes a texture gather with a constant offset array."); - statement("template class Tex, " - "typename Toff, typename... Tp>"); - statement("inline vec spvGatherConstOffsets(const thread Tex& t, sampler s, " - "Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c)"); - begin_scope(); - statement("vec rslts[4];"); - statement("for (uint i = 0; i < 4; i++)"); - begin_scope(); - statement("switch (c)"); - begin_scope(); - // Work around texture::gather() requiring its component parameter to be a constant expression - statement("case component::x:"); - statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::x);"); - statement(" break;"); - statement("case component::y:"); - statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::y);"); - statement(" break;"); - statement("case component::z:"); - statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::z);"); - statement(" break;"); - statement("case component::w:"); - statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::w);"); - statement(" break;"); - end_scope(); - end_scope(); - // Pull all values from the i0j0 component of each gather footprint - statement("return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w);"); - end_scope(); - statement(""); + // Because we are passing a texture reference, we have to output an overloaded version of this function for each address space. + for (uint32_t i = 0; i < texture_addr_space_count; i++) + { + statement("// Wrapper function that processes a ", texture_addr_spaces[i], " texture gather with a constant offset array."); + statement("template class Tex, " + "typename Toff, typename... Tp>"); + statement("inline vec spvGatherConstOffsets(const ", texture_addr_spaces[i], " Tex& t, sampler s, " + "Toff coffsets, component c, Tp... params) METAL_CONST_ARG(c)"); + begin_scope(); + statement("vec rslts[4];"); + statement("for (uint i = 0; i < 4; i++)"); + begin_scope(); + statement("switch (c)"); + begin_scope(); + // Work around texture::gather() requiring its component parameter to be a constant expression + statement("case component::x:"); + statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::x);"); + statement(" break;"); + statement("case component::y:"); + statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::y);"); + statement(" break;"); + statement("case component::z:"); + statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::z);"); + statement(" break;"); + statement("case component::w:"); + statement(" rslts[i] = t.gather(s, spvForward(params)..., coffsets[i], component::w);"); + statement(" break;"); + end_scope(); + end_scope(); + // Pull all values from the i0j0 component of each gather footprint + statement("return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w);"); + end_scope(); + statement(""); + } break; case SPVFuncImplGatherCompareConstOffsets: - statement("// Wrapper function that processes a texture gather with a constant offset array."); - statement("template class Tex, " - "typename Toff, typename... Tp>"); - statement("inline vec spvGatherCompareConstOffsets(const thread Tex& t, sampler s, " - "Toff coffsets, Tp... params)"); - begin_scope(); - statement("vec rslts[4];"); - statement("for (uint i = 0; i < 4; i++)"); - begin_scope(); - statement(" rslts[i] = t.gather_compare(s, spvForward(params)..., coffsets[i]);"); - end_scope(); - // Pull all values from the i0j0 component of each gather footprint - statement("return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w);"); - end_scope(); - statement(""); + // Because we are passing a texture reference, we have to output an overloaded version of this function for each address space. + for (uint32_t i = 0; i < texture_addr_space_count; i++) + { + statement("// Wrapper function that processes a ", texture_addr_spaces[i], " texture gather with a constant offset array."); + statement("template class Tex, " + "typename Toff, typename... Tp>"); + statement("inline vec spvGatherCompareConstOffsets(const ", texture_addr_spaces[i], " Tex& t, sampler s, " + "Toff coffsets, Tp... params)"); + begin_scope(); + statement("vec rslts[4];"); + statement("for (uint i = 0; i < 4; i++)"); + begin_scope(); + statement(" rslts[i] = t.gather_compare(s, spvForward(params)..., coffsets[i]);"); + end_scope(); + // Pull all values from the i0j0 component of each gather footprint + statement("return vec(rslts[0].w, rslts[1].w, rslts[2].w, rslts[3].w);"); + end_scope(); + statement(""); + } break; case SPVFuncImplSubgroupBroadcast: