diff --git a/main.cpp b/main.cpp index f0660bea..3039d988 100644 --- a/main.cpp +++ b/main.cpp @@ -565,6 +565,7 @@ struct CLIArguments bool msl_arrayed_subpass_input = false; uint32_t msl_r32ui_linear_texture_alignment = 4; uint32_t msl_r32ui_alignment_constant_id = 65535; + bool msl_texture_1d_as_2d = false; bool glsl_emit_push_constant_as_ubo = false; bool glsl_emit_ubo_as_plain_uniforms = false; bool glsl_force_flattened_io_blocks = false; @@ -774,7 +775,9 @@ static void print_help_msl() "\t[--msl-r32ui-linear-texture-align ]:\n\t\tThe required alignment of linear textures of format MTLPixelFormatR32Uint.\n" "\t\tThis is used to align the row stride for atomic accesses to such images.\n" "\t[--msl-r32ui-linear-texture-align-constant-id ]:\n\t\tThe function constant ID to use for the linear texture alignment.\n" - "\t\tOn MSL 1.2 or later, you can override the alignment by setting this function constant.\n"); + "\t\tOn MSL 1.2 or later, you can override the alignment by setting this function constant.\n" + "\t[--msl-texture-1d-as-2d]:\n\t\tEmit Image variables of dimension Dim1D as texture2d.\n" + "\t\tIn Metal, 1D textures do not support all features that 2D textures do. Use this option if your code relies on these features.\n"); // clang-format on } @@ -1015,6 +1018,7 @@ static string compile_iteration(const CLIArguments &args, std::vector msl_opts.arrayed_subpass_input = args.msl_arrayed_subpass_input; msl_opts.r32ui_linear_texture_alignment = args.msl_r32ui_linear_texture_alignment; msl_opts.r32ui_alignment_constant_id = args.msl_r32ui_alignment_constant_id; + msl_opts.texture_1D_as_2D = args.msl_texture_1d_as_2d; msl_comp->set_msl_options(msl_opts); for (auto &v : args.msl_discrete_descriptor_sets) msl_comp->add_discrete_descriptor_set(v); @@ -1439,6 +1443,7 @@ static int main_inner(int argc, char *argv[]) [&args](CLIParser &parser) { args.msl_r32ui_linear_texture_alignment = parser.next_uint(); }); cbs.add("--msl-r32ui-linear-texture-align-constant-id", [&args](CLIParser &parser) { args.msl_r32ui_alignment_constant_id = parser.next_uint(); }); + cbs.add("--msl-texture-1d-as-2d", [&args](CLIParser &) { args.msl_texture_1d_as_2d = true; }); cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); }); cbs.add("--rename-entry-point", [&args](CLIParser &parser) { auto old_name = parser.next_string(); diff --git a/reference/opt/shaders-msl/frag/bitcasting.1d-as-2d.frag b/reference/opt/shaders-msl/frag/bitcasting.1d-as-2d.frag new file mode 100644 index 00000000..d341397f --- /dev/null +++ b/reference/opt/shaders-msl/frag/bitcasting.1d-as-2d.frag @@ -0,0 +1,26 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor0 [[color(0)]]; + float4 FragColor1 [[color(1)]]; +}; + +struct main0_in +{ + float4 VertGeom [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], texture2d TextureBase [[texture(0)]], texture2d TextureDetail [[texture(1)]], sampler TextureBaseSmplr [[sampler(0)]], sampler TextureDetailSmplr [[sampler(1)]]) +{ + main0_out out = {}; + float4 _22 = TextureBase.sample(TextureBaseSmplr, float2(in.VertGeom.x, 0.5)); + float4 _30 = TextureDetail.sample(TextureDetailSmplr, float2(in.VertGeom.x, 0.5), int2(3, 0)); + out.FragColor0 = as_type(as_type(_22)) * as_type(as_type(_30)); + out.FragColor1 = as_type(as_type(_22)) * as_type(as_type(_30)); + return out; +} + diff --git a/reference/opt/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag b/reference/opt/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag new file mode 100644 index 00000000..70278b12 --- /dev/null +++ b/reference/opt/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag @@ -0,0 +1,22 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float vTex [[user(locn0), flat]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], texture2d uSampler [[texture(0)]], sampler uSamplerSmplr [[sampler(0)]]) +{ + main0_out out = {}; + out.FragColor += ((uSampler.sample(uSamplerSmplr, float2(in.vTex, 0.5), bias(2.0)) + uSampler.sample(uSamplerSmplr, float2(in.vTex, 0.5), level(3.0))) + uSampler.sample(uSamplerSmplr, float2(in.vTex, 0.5), gradient2d(5.0, 8.0))); + return out; +} + diff --git a/reference/opt/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag b/reference/opt/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag new file mode 100644 index 00000000..98b9bb7e --- /dev/null +++ b/reference/opt/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag @@ -0,0 +1,18 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +fragment main0_out main0(texture2d uTexture [[texture(0)]], texture2d uTexture2 [[texture(1)]], sampler uTextureSmplr [[sampler(0)]], sampler uTexture2Smplr [[sampler(1)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + out.FragColor = uTexture.read(uint2(int2(gl_FragCoord.xy)) + uint2(int2(1)), 0); + out.FragColor += uTexture2.read(uint2(uint(int(gl_FragCoord.x)), 0) + uint2(uint(-1), 0), 0); + return out; +} + diff --git a/reference/shaders-msl/frag/bitcasting.1d-as-2d.frag b/reference/shaders-msl/frag/bitcasting.1d-as-2d.frag new file mode 100644 index 00000000..ea49c067 --- /dev/null +++ b/reference/shaders-msl/frag/bitcasting.1d-as-2d.frag @@ -0,0 +1,30 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor0 [[color(0)]]; + float4 FragColor1 [[color(1)]]; +}; + +struct main0_in +{ + float4 VertGeom [[user(locn0)]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], texture2d TextureBase [[texture(0)]], texture2d TextureDetail [[texture(1)]], sampler TextureBaseSmplr [[sampler(0)]], sampler TextureDetailSmplr [[sampler(1)]]) +{ + main0_out out = {}; + float4 texSample0 = TextureBase.sample(TextureBaseSmplr, float2(in.VertGeom.x, 0.5)); + float4 texSample1 = TextureDetail.sample(TextureDetailSmplr, float2(in.VertGeom.x, 0.5), int2(3, 0)); + int4 iResult0 = as_type(texSample0); + int4 iResult1 = as_type(texSample1); + out.FragColor0 = as_type(iResult0) * as_type(iResult1); + uint4 uResult0 = as_type(texSample0); + uint4 uResult1 = as_type(texSample1); + out.FragColor1 = as_type(uResult0) * as_type(uResult1); + return out; +} + diff --git a/reference/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag b/reference/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag new file mode 100644 index 00000000..70278b12 --- /dev/null +++ b/reference/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag @@ -0,0 +1,22 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +struct main0_in +{ + float vTex [[user(locn0), flat]]; +}; + +fragment main0_out main0(main0_in in [[stage_in]], texture2d uSampler [[texture(0)]], sampler uSamplerSmplr [[sampler(0)]]) +{ + main0_out out = {}; + out.FragColor += ((uSampler.sample(uSamplerSmplr, float2(in.vTex, 0.5), bias(2.0)) + uSampler.sample(uSamplerSmplr, float2(in.vTex, 0.5), level(3.0))) + uSampler.sample(uSamplerSmplr, float2(in.vTex, 0.5), gradient2d(5.0, 8.0))); + return out; +} + diff --git a/reference/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag b/reference/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag new file mode 100644 index 00000000..98b9bb7e --- /dev/null +++ b/reference/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag @@ -0,0 +1,18 @@ +#include +#include + +using namespace metal; + +struct main0_out +{ + float4 FragColor [[color(0)]]; +}; + +fragment main0_out main0(texture2d uTexture [[texture(0)]], texture2d uTexture2 [[texture(1)]], sampler uTextureSmplr [[sampler(0)]], sampler uTexture2Smplr [[sampler(1)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + out.FragColor = uTexture.read(uint2(int2(gl_FragCoord.xy)) + uint2(int2(1)), 0); + out.FragColor += uTexture2.read(uint2(uint(int(gl_FragCoord.x)), 0) + uint2(uint(-1), 0), 0); + return out; +} + diff --git a/shaders-msl/frag/bitcasting.1d-as-2d.frag b/shaders-msl/frag/bitcasting.1d-as-2d.frag new file mode 100644 index 00000000..adaa749f --- /dev/null +++ b/shaders-msl/frag/bitcasting.1d-as-2d.frag @@ -0,0 +1,23 @@ +#version 450 + +layout(binding = 0) uniform sampler1D TextureBase; +layout(binding = 1) uniform sampler1D TextureDetail; + +layout(location = 0) in vec4 VertGeom; + +layout(location = 0) out vec4 FragColor0; +layout(location = 1) out vec4 FragColor1; + +void main() +{ + vec4 texSample0 = texture(TextureBase, VertGeom.x); + vec4 texSample1 = textureOffset(TextureDetail, VertGeom.x, 3); + + ivec4 iResult0 = floatBitsToInt(texSample0); + ivec4 iResult1 = floatBitsToInt(texSample1); + FragColor0 = (intBitsToFloat(iResult0) * intBitsToFloat(iResult1)); + + uvec4 uResult0 = floatBitsToUint(texSample0); + uvec4 uResult1 = floatBitsToUint(texSample1); + FragColor1 = (uintBitsToFloat(uResult0) * uintBitsToFloat(uResult1)); +} diff --git a/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag b/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag new file mode 100644 index 00000000..f4526f39 --- /dev/null +++ b/shaders-msl/frag/sampler-1d-lod.1d-as-2d.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(location = 0) out vec4 FragColor; +layout(location = 0) flat in float vTex; +layout(binding = 0) uniform sampler1D uSampler; + +void main() +{ + FragColor += texture(uSampler, vTex, 2.0) + + textureLod(uSampler, vTex, 3.0) + + textureGrad(uSampler, vTex, 5.0, 8.0); +} diff --git a/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag b/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag new file mode 100644 index 00000000..8e15e36e --- /dev/null +++ b/shaders-msl/frag/texel-fetch-offset.1d-as-2d.frag @@ -0,0 +1,10 @@ +#version 450 +layout(location = 0) out vec4 FragColor; +layout(binding = 0) uniform sampler2D uTexture; +layout(binding = 1) uniform sampler1D uTexture2; + +void main() +{ + FragColor = texelFetchOffset(uTexture, ivec2(gl_FragCoord.xy), 0, ivec2(1, 1)); + FragColor += texelFetchOffset(uTexture2, int(gl_FragCoord.x), 0, int(-1)); +} diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 629b873f..3763fb48 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -8265,25 +8265,26 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool break; } - if (args.base.is_fetch && args.offset) + if (args.base.is_fetch && (args.offset || args.coffset)) { + uint32_t offset_expr = args.offset ? args.offset : args.coffset; // Fetch offsets must be applied directly to the coordinate. - forward = forward && should_forward(args.offset); - auto &type = expression_type(args.offset); - if (type.basetype != SPIRType::UInt) - tex_coords += " + " + bitcast_expression(SPIRType::UInt, args.offset); + forward = forward && should_forward(offset_expr); + auto &type = expression_type(offset_expr); + if (imgtype.image.dim == Dim1D && msl_options.texture_1D_as_2D) + { + if (type.basetype != SPIRType::UInt) + tex_coords += join(" + uint2(", bitcast_expression(SPIRType::UInt, offset_expr), ", 0)"); + else + tex_coords += join(" + uint2(", to_enclosed_expression(offset_expr), ", 0)"); + } else - tex_coords += " + " + to_enclosed_expression(args.offset); - } - else if (args.base.is_fetch && args.coffset) - { - // Fetch offsets must be applied directly to the coordinate. - forward = forward && should_forward(args.coffset); - auto &type = expression_type(args.coffset); - if (type.basetype != SPIRType::UInt) - tex_coords += " + " + bitcast_expression(SPIRType::UInt, args.coffset); - else - tex_coords += " + " + to_enclosed_expression(args.coffset); + { + if (type.basetype != SPIRType::UInt) + tex_coords += " + " + bitcast_expression(SPIRType::UInt, offset_expr); + else + tex_coords += " + " + to_enclosed_expression(offset_expr); + } } // If projection, use alt coord as divisor @@ -8454,6 +8455,7 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool string grad_opt; switch (imgtype.image.dim) { + case Dim1D: case Dim2D: grad_opt = "2d"; break; @@ -8489,30 +8491,42 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool // Add offsets string offset_expr; + const SPIRType *offset_type = nullptr; if (args.coffset && !args.base.is_fetch) { forward = forward && should_forward(args.coffset); offset_expr = to_expression(args.coffset); + offset_type = &expression_type(args.coffset); } else if (args.offset && !args.base.is_fetch) { forward = forward && should_forward(args.offset); offset_expr = to_expression(args.offset); + offset_type = &expression_type(args.offset); } if (!offset_expr.empty()) { switch (imgtype.image.dim) { + case Dim1D: + if (!msl_options.texture_1D_as_2D) + break; + if (offset_type->vecsize > 1) + offset_expr = enclose_expression(offset_expr) + ".x"; + + farg_str += join(", int2(", offset_expr, ", 0)"); + break; + case Dim2D: - if (coord_type.vecsize > 2) + if (offset_type->vecsize > 2) offset_expr = enclose_expression(offset_expr) + ".xy"; farg_str += ", " + offset_expr; break; case Dim3D: - if (coord_type.vecsize > 3) + if (offset_type->vecsize > 3) offset_expr = enclose_expression(offset_expr) + ".xyz"; farg_str += ", " + offset_expr; diff --git a/test_shaders.py b/test_shaders.py index 95099073..451fc00f 100755 --- a/test_shaders.py +++ b/test_shaders.py @@ -306,6 +306,8 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths): msl_args.append('0x00000022') if '.arrayed-subpass.' in shader: msl_args.append('--msl-arrayed-subpass-input') + if '.1d-as-2d.' in shader: + msl_args.append('--msl-texture-1d-as-2d') subprocess.check_call(msl_args)