MSL: Handle Offset and Grad operands for 1D-as-2D textures.

This commit is contained in:
Chip Davis 2020-10-14 20:48:52 -05:00
parent 0db1569e97
commit 5845e009ea
12 changed files with 221 additions and 19 deletions

View File

@ -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 <alignment>]:\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 <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<uint32_t>
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();

View File

@ -0,0 +1,26 @@
#include <metal_stdlib>
#include <simd/simd.h>
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<float> TextureBase [[texture(0)]], texture2d<float> 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<float4>(as_type<int4>(_22)) * as_type<float4>(as_type<int4>(_30));
out.FragColor1 = as_type<float4>(as_type<uint4>(_22)) * as_type<float4>(as_type<uint4>(_30));
return out;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
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<float> 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;
}

View File

@ -0,0 +1,18 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 FragColor [[color(0)]];
};
fragment main0_out main0(texture2d<float> uTexture [[texture(0)]], texture2d<float> 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;
}

View File

@ -0,0 +1,30 @@
#include <metal_stdlib>
#include <simd/simd.h>
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<float> TextureBase [[texture(0)]], texture2d<float> 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<int4>(texSample0);
int4 iResult1 = as_type<int4>(texSample1);
out.FragColor0 = as_type<float4>(iResult0) * as_type<float4>(iResult1);
uint4 uResult0 = as_type<uint4>(texSample0);
uint4 uResult1 = as_type<uint4>(texSample1);
out.FragColor1 = as_type<float4>(uResult0) * as_type<float4>(uResult1);
return out;
}

View File

@ -0,0 +1,22 @@
#include <metal_stdlib>
#include <simd/simd.h>
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<float> 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;
}

View File

@ -0,0 +1,18 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 FragColor [[color(0)]];
};
fragment main0_out main0(texture2d<float> uTexture [[texture(0)]], texture2d<float> 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;
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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);
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 += " + " + bitcast_expression(SPIRType::UInt, args.offset);
tex_coords += join(" + uint2(", bitcast_expression(SPIRType::UInt, offset_expr), ", 0)");
else
tex_coords += " + " + to_enclosed_expression(args.offset);
tex_coords += join(" + uint2(", to_enclosed_expression(offset_expr), ", 0)");
}
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;

View File

@ -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)