Merge pull request #971 from KhronosGroup/msl-array-texture-swizzle
MSL: Deal with texture swizzle on arrays of images.
This commit is contained in:
commit
fce83b7e8b
@ -0,0 +1,151 @@
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct spvAux
|
||||
{
|
||||
uint swizzleConst[1];
|
||||
};
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
struct main0_in
|
||||
{
|
||||
float2 vUV [[user(locn0)]];
|
||||
};
|
||||
|
||||
enum class spvSwizzle : uint
|
||||
{
|
||||
none = 0,
|
||||
zero,
|
||||
one,
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha
|
||||
};
|
||||
|
||||
template<typename T> struct spvRemoveReference { typedef T type; };
|
||||
template<typename T> struct spvRemoveReference<thread T&> { typedef T type; };
|
||||
template<typename T> struct spvRemoveReference<thread T&&> { typedef T type; };
|
||||
template<typename T> inline constexpr thread T&& spvForward(thread typename spvRemoveReference<T>::type& x)
|
||||
{
|
||||
return static_cast<thread T&&>(x);
|
||||
}
|
||||
template<typename T> inline constexpr thread T&& spvForward(thread typename spvRemoveReference<T>::type&& x)
|
||||
{
|
||||
return static_cast<thread T&&>(x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T spvGetSwizzle(vec<T, 4> x, T c, spvSwizzle s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case spvSwizzle::none:
|
||||
return c;
|
||||
case spvSwizzle::zero:
|
||||
return 0;
|
||||
case spvSwizzle::one:
|
||||
return 1;
|
||||
case spvSwizzle::red:
|
||||
return x.r;
|
||||
case spvSwizzle::green:
|
||||
return x.g;
|
||||
case spvSwizzle::blue:
|
||||
return x.b;
|
||||
case spvSwizzle::alpha:
|
||||
return x.a;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper function that swizzles texture samples and fetches.
|
||||
template<typename T>
|
||||
inline vec<T, 4> spvTextureSwizzle(vec<T, 4> x, uint s)
|
||||
{
|
||||
if (!s)
|
||||
return x;
|
||||
return vec<T, 4>(spvGetSwizzle(x, x.r, spvSwizzle((s >> 0) & 0xFF)), spvGetSwizzle(x, x.g, spvSwizzle((s >> 8) & 0xFF)), spvGetSwizzle(x, x.b, spvSwizzle((s >> 16) & 0xFF)), spvGetSwizzle(x, x.a, spvSwizzle((s >> 24) & 0xFF)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T spvTextureSwizzle(T x, uint s)
|
||||
{
|
||||
return spvTextureSwizzle(vec<T, 4>(x, 0, 0, 1), s).x;
|
||||
}
|
||||
|
||||
// Wrapper function that swizzles texture gathers.
|
||||
template<typename T, typename Tex, typename... Ts>
|
||||
inline vec<T, 4> spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c)
|
||||
{
|
||||
if (sw)
|
||||
{
|
||||
switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF))
|
||||
{
|
||||
case spvSwizzle::none:
|
||||
break;
|
||||
case spvSwizzle::zero:
|
||||
return vec<T, 4>(0, 0, 0, 0);
|
||||
case spvSwizzle::one:
|
||||
return vec<T, 4>(1, 1, 1, 1);
|
||||
case spvSwizzle::red:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::x);
|
||||
case spvSwizzle::green:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::y);
|
||||
case spvSwizzle::blue:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::z);
|
||||
case spvSwizzle::alpha:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::w);
|
||||
}
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
case component::x:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::x);
|
||||
case component::y:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::y);
|
||||
case component::z:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::z);
|
||||
case component::w:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::w);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper function that swizzles depth texture gathers.
|
||||
template<typename T, typename Tex, typename... Ts>
|
||||
inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw)
|
||||
{
|
||||
if (sw)
|
||||
{
|
||||
switch (spvSwizzle(sw & 0xFF))
|
||||
{
|
||||
case spvSwizzle::none:
|
||||
case spvSwizzle::red:
|
||||
break;
|
||||
case spvSwizzle::zero:
|
||||
case spvSwizzle::green:
|
||||
case spvSwizzle::blue:
|
||||
case spvSwizzle::alpha:
|
||||
return vec<T, 4>(0, 0, 0, 0);
|
||||
case spvSwizzle::one:
|
||||
return vec<T, 4>(1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
return t.gather_compare(s, spvForward<Ts>(params)...);
|
||||
}
|
||||
|
||||
fragment main0_out main0(main0_in in [[stage_in]], constant spvAux& spvAuxBuffer [[buffer(30)]], array<texture2d<float>, 4> uSampler [[texture(0)]], array<sampler, 4> uSamplerSmplr [[sampler(0)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
constant uint32_t* uSamplerSwzl = &spvAuxBuffer.swizzleConst[0];
|
||||
out.FragColor = spvTextureSwizzle(uSampler[2].sample(uSamplerSmplr[2], in.vUV), uSamplerSwzl[2]);
|
||||
out.FragColor += spvTextureSwizzle(uSampler[1].sample(uSamplerSmplr[1], in.vUV), uSamplerSwzl[1]);
|
||||
return out;
|
||||
}
|
||||
|
@ -0,0 +1,161 @@
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct spvAux
|
||||
{
|
||||
uint swizzleConst[1];
|
||||
};
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
struct main0_in
|
||||
{
|
||||
float2 vUV [[user(locn0)]];
|
||||
};
|
||||
|
||||
enum class spvSwizzle : uint
|
||||
{
|
||||
none = 0,
|
||||
zero,
|
||||
one,
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
alpha
|
||||
};
|
||||
|
||||
template<typename T> struct spvRemoveReference { typedef T type; };
|
||||
template<typename T> struct spvRemoveReference<thread T&> { typedef T type; };
|
||||
template<typename T> struct spvRemoveReference<thread T&&> { typedef T type; };
|
||||
template<typename T> inline constexpr thread T&& spvForward(thread typename spvRemoveReference<T>::type& x)
|
||||
{
|
||||
return static_cast<thread T&&>(x);
|
||||
}
|
||||
template<typename T> inline constexpr thread T&& spvForward(thread typename spvRemoveReference<T>::type&& x)
|
||||
{
|
||||
return static_cast<thread T&&>(x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T spvGetSwizzle(vec<T, 4> x, T c, spvSwizzle s)
|
||||
{
|
||||
switch (s)
|
||||
{
|
||||
case spvSwizzle::none:
|
||||
return c;
|
||||
case spvSwizzle::zero:
|
||||
return 0;
|
||||
case spvSwizzle::one:
|
||||
return 1;
|
||||
case spvSwizzle::red:
|
||||
return x.r;
|
||||
case spvSwizzle::green:
|
||||
return x.g;
|
||||
case spvSwizzle::blue:
|
||||
return x.b;
|
||||
case spvSwizzle::alpha:
|
||||
return x.a;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper function that swizzles texture samples and fetches.
|
||||
template<typename T>
|
||||
inline vec<T, 4> spvTextureSwizzle(vec<T, 4> x, uint s)
|
||||
{
|
||||
if (!s)
|
||||
return x;
|
||||
return vec<T, 4>(spvGetSwizzle(x, x.r, spvSwizzle((s >> 0) & 0xFF)), spvGetSwizzle(x, x.g, spvSwizzle((s >> 8) & 0xFF)), spvGetSwizzle(x, x.b, spvSwizzle((s >> 16) & 0xFF)), spvGetSwizzle(x, x.a, spvSwizzle((s >> 24) & 0xFF)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T spvTextureSwizzle(T x, uint s)
|
||||
{
|
||||
return spvTextureSwizzle(vec<T, 4>(x, 0, 0, 1), s).x;
|
||||
}
|
||||
|
||||
// Wrapper function that swizzles texture gathers.
|
||||
template<typename T, typename Tex, typename... Ts>
|
||||
inline vec<T, 4> spvGatherSwizzle(sampler s, const thread Tex& t, Ts... params, component c, uint sw) METAL_CONST_ARG(c)
|
||||
{
|
||||
if (sw)
|
||||
{
|
||||
switch (spvSwizzle((sw >> (uint(c) * 8)) & 0xFF))
|
||||
{
|
||||
case spvSwizzle::none:
|
||||
break;
|
||||
case spvSwizzle::zero:
|
||||
return vec<T, 4>(0, 0, 0, 0);
|
||||
case spvSwizzle::one:
|
||||
return vec<T, 4>(1, 1, 1, 1);
|
||||
case spvSwizzle::red:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::x);
|
||||
case spvSwizzle::green:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::y);
|
||||
case spvSwizzle::blue:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::z);
|
||||
case spvSwizzle::alpha:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::w);
|
||||
}
|
||||
}
|
||||
switch (c)
|
||||
{
|
||||
case component::x:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::x);
|
||||
case component::y:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::y);
|
||||
case component::z:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::z);
|
||||
case component::w:
|
||||
return t.gather(s, spvForward<Ts>(params)..., component::w);
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper function that swizzles depth texture gathers.
|
||||
template<typename T, typename Tex, typename... Ts>
|
||||
inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... params, uint sw)
|
||||
{
|
||||
if (sw)
|
||||
{
|
||||
switch (spvSwizzle(sw & 0xFF))
|
||||
{
|
||||
case spvSwizzle::none:
|
||||
case spvSwizzle::red:
|
||||
break;
|
||||
case spvSwizzle::zero:
|
||||
case spvSwizzle::green:
|
||||
case spvSwizzle::blue:
|
||||
case spvSwizzle::alpha:
|
||||
return vec<T, 4>(0, 0, 0, 0);
|
||||
case spvSwizzle::one:
|
||||
return vec<T, 4>(1, 1, 1, 1);
|
||||
}
|
||||
}
|
||||
return t.gather_compare(s, spvForward<Ts>(params)...);
|
||||
}
|
||||
|
||||
float4 sample_in_func(thread const array<texture2d<float>, 4> uSampler, thread const array<sampler, 4> uSamplerSmplr, constant uint32_t* uSamplerSwzl, thread float2& vUV)
|
||||
{
|
||||
return spvTextureSwizzle(uSampler[2].sample(uSamplerSmplr[2], vUV), uSamplerSwzl[2]);
|
||||
}
|
||||
|
||||
float4 sample_single_in_func(thread const texture2d<float> s, thread const sampler sSmplr, constant uint32_t& sSwzl, thread float2& vUV)
|
||||
{
|
||||
return spvTextureSwizzle(s.sample(sSmplr, vUV), sSwzl);
|
||||
}
|
||||
|
||||
fragment main0_out main0(main0_in in [[stage_in]], constant spvAux& spvAuxBuffer [[buffer(30)]], array<texture2d<float>, 4> uSampler [[texture(0)]], array<sampler, 4> uSamplerSmplr [[sampler(0)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
constant uint32_t* uSamplerSwzl = &spvAuxBuffer.swizzleConst[0];
|
||||
out.FragColor = sample_in_func(uSampler, uSamplerSmplr, uSamplerSwzl, in.vUV);
|
||||
out.FragColor += sample_single_in_func(uSampler[1], uSamplerSmplr[1], uSamplerSwzl[1], in.vUV);
|
||||
return out;
|
||||
}
|
||||
|
23
shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag
Normal file
23
shaders-msl/frag/array-of-texture-swizzle.msl2.swizzle.frag
Normal file
@ -0,0 +1,23 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D uSampler[4];
|
||||
layout(set = 0, binding = 1) uniform sampler2D uSamp;
|
||||
layout(location = 0) in vec2 vUV;
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 sample_in_func()
|
||||
{
|
||||
return texture(uSampler[2], vUV);
|
||||
}
|
||||
|
||||
vec4 sample_single_in_func(sampler2D s)
|
||||
{
|
||||
return texture(s, vUV);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = sample_in_func();
|
||||
FragColor += sample_single_in_func(uSampler[1]);
|
||||
}
|
@ -4373,7 +4373,10 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &)
|
||||
|
||||
// Manufacture automatic swizzle arg.
|
||||
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(arg_type))
|
||||
decl += join(", constant uint32_t& ", to_swizzle_expression(arg.id));
|
||||
{
|
||||
bool arg_is_array = !arg_type.array.empty();
|
||||
decl += join(", constant uint32_t", arg_is_array ? "* " : "& ", to_swizzle_expression(arg.id));
|
||||
}
|
||||
|
||||
if (&arg != &func.arguments.back())
|
||||
decl += ", ";
|
||||
@ -5847,9 +5850,13 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
|
||||
if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type))
|
||||
{
|
||||
auto &entry_func = this->get<SPIRFunction>(ir.default_entry_point);
|
||||
entry_func.fixup_hooks_in.push_back([this, &var, var_id]() {
|
||||
entry_func.fixup_hooks_in.push_back([this, &type, &var, var_id]() {
|
||||
auto &aux_type = expression_type(aux_buffer_id);
|
||||
statement("constant uint32_t& ", to_swizzle_expression(var_id), " = ", to_name(aux_buffer_id), ".",
|
||||
bool is_array_type = !type.array.empty();
|
||||
|
||||
// If we have an array of images, we need to be able to index into it, so take a pointer instead.
|
||||
statement("constant uint32_t", is_array_type ? "* " : "& ", to_swizzle_expression(var_id),
|
||||
is_array_type ? " = &" : " = ", to_name(aux_buffer_id), ".",
|
||||
to_member_name(aux_type, k_aux_mbr_idx_swizzle_const), "[",
|
||||
convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];");
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user