Merge pull request #442 from KhronosGroup/fix-435
Implement subpassLoad in HLSL and MSL.
This commit is contained in:
commit
7be30aadbd
32
reference/opt/shaders-hlsl/frag/input-attachment-ms.frag
Normal file
32
reference/opt/shaders-hlsl/frag/input-attachment-ms.frag
Normal file
@ -0,0 +1,32 @@
|
||||
Texture2DMS<float4> uSubpass0 : register(t0);
|
||||
Texture2DMS<float4> uSubpass1 : register(t1);
|
||||
|
||||
static float4 gl_FragCoord;
|
||||
static int gl_SampleID;
|
||||
static float4 FragColor;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float4 gl_FragCoord : SV_Position;
|
||||
uint gl_SampleID : SV_SampleIndex;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 FragColor : SV_Target0;
|
||||
};
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
FragColor = (uSubpass0.Load(int2(gl_FragCoord.xy), 1) + uSubpass1.Load(int2(gl_FragCoord.xy), 2)) + uSubpass0.Load(int2(gl_FragCoord.xy), gl_SampleID);
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
gl_FragCoord = stage_input.gl_FragCoord;
|
||||
gl_SampleID = stage_input.gl_SampleID;
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.FragColor = FragColor;
|
||||
return stage_output;
|
||||
}
|
29
reference/opt/shaders-hlsl/frag/input-attachment.frag
Normal file
29
reference/opt/shaders-hlsl/frag/input-attachment.frag
Normal file
@ -0,0 +1,29 @@
|
||||
Texture2D<float4> uSubpass0 : register(t0);
|
||||
Texture2D<float4> uSubpass1 : register(t1);
|
||||
|
||||
static float4 gl_FragCoord;
|
||||
static float4 FragColor;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float4 gl_FragCoord : SV_Position;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 FragColor : SV_Target0;
|
||||
};
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
FragColor = uSubpass0.Load(int3(int2(gl_FragCoord.xy), 0)) + uSubpass1.Load(int3(int2(gl_FragCoord.xy), 0));
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
gl_FragCoord = stage_input.gl_FragCoord;
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.FragColor = FragColor;
|
||||
return stage_output;
|
||||
}
|
17
reference/opt/shaders-msl/frag/input-attachment-ms.frag
Normal file
17
reference/opt/shaders-msl/frag/input-attachment-ms.frag
Normal file
@ -0,0 +1,17 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
fragment main0_out main0(texture2d_ms<float> uSubpass0 [[texture(0)]], texture2d_ms<float> uSubpass1 [[texture(1)]], uint gl_SampleID [[sample_id]], float4 gl_FragCoord [[position]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.FragColor = (uSubpass0.read(uint2(gl_FragCoord.xy), 1) + uSubpass1.read(uint2(gl_FragCoord.xy), 2)) + uSubpass0.read(uint2(gl_FragCoord.xy), gl_SampleID);
|
||||
return out;
|
||||
}
|
||||
|
17
reference/opt/shaders-msl/frag/input-attachment.frag
Normal file
17
reference/opt/shaders-msl/frag/input-attachment.frag
Normal file
@ -0,0 +1,17 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
fragment main0_out main0(texture2d<float> uSubpass0 [[texture(0)]], texture2d<float> uSubpass1 [[texture(1)]], float4 gl_FragCoord [[position]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.FragColor = uSubpass0.read(uint2(gl_FragCoord.xy), 0) + uSubpass1.read(uint2(gl_FragCoord.xy), 0);
|
||||
return out;
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
fragment main0_out main0(depth2d<float> uDepth [[texture(0)]], texture2d<float> uColor [[texture(1)]], sampler uSamplerShadow [[sampler(0)]], sampler uSampler [[sampler(1)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.FragColor = uDepth.sample_compare(uSamplerShadow, float3(0.5).xy, 0.5) + uColor.sample(uSampler, float2(0.5)).x;
|
||||
return out;
|
||||
}
|
||||
|
37
reference/shaders-hlsl/frag/input-attachment-ms.frag
Normal file
37
reference/shaders-hlsl/frag/input-attachment-ms.frag
Normal file
@ -0,0 +1,37 @@
|
||||
Texture2DMS<float4> uSubpass0 : register(t0);
|
||||
Texture2DMS<float4> uSubpass1 : register(t1);
|
||||
|
||||
static float4 gl_FragCoord;
|
||||
static int gl_SampleID;
|
||||
static float4 FragColor;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float4 gl_FragCoord : SV_Position;
|
||||
uint gl_SampleID : SV_SampleIndex;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 FragColor : SV_Target0;
|
||||
};
|
||||
|
||||
float4 load_subpasses(Texture2DMS<float4> uInput)
|
||||
{
|
||||
return uInput.Load(int2(gl_FragCoord.xy), gl_SampleID);
|
||||
}
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
FragColor = (uSubpass0.Load(int2(gl_FragCoord.xy), 1) + uSubpass1.Load(int2(gl_FragCoord.xy), 2)) + load_subpasses(uSubpass0);
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
gl_FragCoord = stage_input.gl_FragCoord;
|
||||
gl_SampleID = stage_input.gl_SampleID;
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.FragColor = FragColor;
|
||||
return stage_output;
|
||||
}
|
34
reference/shaders-hlsl/frag/input-attachment.frag
Normal file
34
reference/shaders-hlsl/frag/input-attachment.frag
Normal file
@ -0,0 +1,34 @@
|
||||
Texture2D<float4> uSubpass0 : register(t0);
|
||||
Texture2D<float4> uSubpass1 : register(t1);
|
||||
|
||||
static float4 gl_FragCoord;
|
||||
static float4 FragColor;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float4 gl_FragCoord : SV_Position;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 FragColor : SV_Target0;
|
||||
};
|
||||
|
||||
float4 load_subpasses(Texture2D<float4> uInput)
|
||||
{
|
||||
return uInput.Load(int3(int2(gl_FragCoord.xy), 0));
|
||||
}
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
FragColor = uSubpass0.Load(int3(int2(gl_FragCoord.xy), 0)) + load_subpasses(uSubpass1);
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
gl_FragCoord = stage_input.gl_FragCoord;
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.FragColor = FragColor;
|
||||
return stage_output;
|
||||
}
|
24
reference/shaders-msl/frag/input-attachment-ms.frag
Normal file
24
reference/shaders-msl/frag/input-attachment-ms.frag
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
float4 load_subpasses(thread const texture2d_ms<float> uInput, thread uint& gl_SampleID, thread float4& gl_FragCoord)
|
||||
{
|
||||
return uInput.read(uint2(gl_FragCoord.xy), gl_SampleID);
|
||||
}
|
||||
|
||||
fragment main0_out main0(texture2d_ms<float> uSubpass0 [[texture(0)]], texture2d_ms<float> uSubpass1 [[texture(1)]], uint gl_SampleID [[sample_id]], float4 gl_FragCoord [[position]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.FragColor = (uSubpass0.read(uint2(gl_FragCoord.xy), 1) + uSubpass1.read(uint2(gl_FragCoord.xy), 2)) + load_subpasses(uSubpass0, gl_SampleID, gl_FragCoord);
|
||||
return out;
|
||||
}
|
||||
|
24
reference/shaders-msl/frag/input-attachment.frag
Normal file
24
reference/shaders-msl/frag/input-attachment.frag
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float4 FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
float4 load_subpasses(thread const texture2d<float> uInput, thread float4& gl_FragCoord)
|
||||
{
|
||||
return uInput.read(uint2(gl_FragCoord.xy), 0);
|
||||
}
|
||||
|
||||
fragment main0_out main0(texture2d<float> uSubpass0 [[texture(0)]], texture2d<float> uSubpass1 [[texture(1)]], float4 gl_FragCoord [[position]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.FragColor = uSubpass0.read(uint2(gl_FragCoord.xy), 0) + load_subpasses(uSubpass1, gl_FragCoord);
|
||||
return out;
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
|
||||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
float FragColor [[color(0)]];
|
||||
};
|
||||
|
||||
float sample_depth_from_function(thread const depth2d<float> uT, thread const sampler uS)
|
||||
{
|
||||
return uT.sample_compare(uS, float3(0.5).xy, float3(0.5).z);
|
||||
}
|
||||
|
||||
float sample_color_from_function(thread const texture2d<float> uT, thread const sampler uS)
|
||||
{
|
||||
return uT.sample(uS, float2(0.5)).x;
|
||||
}
|
||||
|
||||
fragment main0_out main0(depth2d<float> uDepth [[texture(0)]], texture2d<float> uColor [[texture(1)]], sampler uSamplerShadow [[sampler(0)]], sampler uSampler [[sampler(1)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.FragColor = sample_depth_from_function(uDepth, uSamplerShadow) + sample_color_from_function(uColor, uSampler);
|
||||
return out;
|
||||
}
|
||||
|
15
shaders-hlsl/frag/input-attachment-ms.frag
Normal file
15
shaders-hlsl/frag/input-attachment-ms.frag
Normal file
@ -0,0 +1,15 @@
|
||||
#version 450
|
||||
|
||||
layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInputMS uSubpass0;
|
||||
layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInputMS uSubpass1;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 load_subpasses(mediump subpassInputMS uInput)
|
||||
{
|
||||
return subpassLoad(uInput, gl_SampleID);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = subpassLoad(uSubpass0, 1) + subpassLoad(uSubpass1, 2) + load_subpasses(uSubpass0);
|
||||
}
|
16
shaders-hlsl/frag/input-attachment.frag
Normal file
16
shaders-hlsl/frag/input-attachment.frag
Normal file
@ -0,0 +1,16 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(input_attachment_index = 0, set = 0, binding = 0) uniform mediump subpassInput uSubpass0;
|
||||
layout(input_attachment_index = 1, set = 0, binding = 1) uniform mediump subpassInput uSubpass1;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 load_subpasses(mediump subpassInput uInput)
|
||||
{
|
||||
return subpassLoad(uInput);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = subpassLoad(uSubpass0) + load_subpasses(uSubpass1);
|
||||
}
|
15
shaders-msl/frag/input-attachment-ms.frag
Normal file
15
shaders-msl/frag/input-attachment-ms.frag
Normal file
@ -0,0 +1,15 @@
|
||||
#version 450
|
||||
|
||||
layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInputMS uSubpass0;
|
||||
layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInputMS uSubpass1;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 load_subpasses(mediump subpassInputMS uInput)
|
||||
{
|
||||
return subpassLoad(uInput, gl_SampleID);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = subpassLoad(uSubpass0, 1) + subpassLoad(uSubpass1, 2) + load_subpasses(uSubpass0);
|
||||
}
|
16
shaders-msl/frag/input-attachment.frag
Normal file
16
shaders-msl/frag/input-attachment.frag
Normal file
@ -0,0 +1,16 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(input_attachment_index = 0, set = 0, binding = 0) uniform mediump subpassInput uSubpass0;
|
||||
layout(input_attachment_index = 1, set = 0, binding = 1) uniform mediump subpassInput uSubpass1;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 load_subpasses(mediump subpassInput uInput)
|
||||
{
|
||||
return subpassLoad(uInput);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = subpassLoad(uSubpass0) + load_subpasses(uSubpass1);
|
||||
}
|
22
shaders-msl/frag/sample-depth-separate-image-sampler.frag
Normal file
22
shaders-msl/frag/sample-depth-separate-image-sampler.frag
Normal file
@ -0,0 +1,22 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0) uniform texture2D uDepth;
|
||||
layout(set = 0, binding = 1) uniform texture2D uColor;
|
||||
layout(set = 0, binding = 2) uniform sampler uSampler;
|
||||
layout(set = 0, binding = 3) uniform samplerShadow uSamplerShadow;
|
||||
layout(location = 0) out float FragColor;
|
||||
|
||||
float sample_depth_from_function(texture2D uT, samplerShadow uS)
|
||||
{
|
||||
return texture(sampler2DShadow(uT, uS), vec3(0.5));
|
||||
}
|
||||
|
||||
float sample_color_from_function(texture2D uT, sampler uS)
|
||||
{
|
||||
return texture(sampler2D(uT, uS), vec2(0.5)).x;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = sample_depth_from_function(uDepth, uSamplerShadow) + sample_color_from_function(uColor, uSampler);
|
||||
}
|
@ -3752,11 +3752,13 @@ bool Compiler::has_active_builtin(BuiltIn builtin, StorageClass storage)
|
||||
return flags & (1ull << builtin);
|
||||
}
|
||||
|
||||
void Compiler::analyze_sampler_comparison_states()
|
||||
void Compiler::analyze_image_and_sampler_usage()
|
||||
{
|
||||
CombinedImageSamplerUsageHandler handler(*this);
|
||||
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
|
||||
comparison_samplers = move(handler.comparison_samplers);
|
||||
comparison_images = move(handler.comparison_images);
|
||||
need_subpass_input = handler.need_subpass_input;
|
||||
}
|
||||
|
||||
bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint32_t *args, uint32_t length)
|
||||
@ -3777,6 +3779,14 @@ bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint
|
||||
return true;
|
||||
}
|
||||
|
||||
void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_images(uint32_t image)
|
||||
{
|
||||
// Traverse the variable dependency hierarchy and tag everything in its path with comparison images.
|
||||
comparison_images.insert(image);
|
||||
for (auto &img : dependency_hierarchy[image])
|
||||
add_hierarchy_to_comparison_images(img);
|
||||
}
|
||||
|
||||
void Compiler::CombinedImageSamplerUsageHandler::add_hierarchy_to_comparison_samplers(uint32_t sampler)
|
||||
{
|
||||
// Traverse the variable dependency hierarchy and tag everything in its path with comparison samplers.
|
||||
@ -3796,6 +3806,12 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_
|
||||
if (length < 3)
|
||||
return false;
|
||||
dependency_hierarchy[args[1]].insert(args[2]);
|
||||
|
||||
// Ideally defer this to OpImageRead, but then we'd need to track loaded IDs.
|
||||
// If we load an image, we're going to use it and there is little harm in declaring an unused gl_FragCoord.
|
||||
auto &type = compiler.get<SPIRType>(args[0]);
|
||||
if (type.image.dim == DimSubpassData)
|
||||
need_subpass_input = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -3808,6 +3824,10 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_
|
||||
auto &type = compiler.get<SPIRType>(result_type);
|
||||
if (type.image.depth)
|
||||
{
|
||||
// This image must be a depth image.
|
||||
uint32_t image = args[2];
|
||||
add_hierarchy_to_comparison_images(image);
|
||||
|
||||
// This sampler must be a SamplerComparisionState, and not a regular SamplerState.
|
||||
uint32_t sampler = args[3];
|
||||
add_hierarchy_to_comparison_samplers(sampler);
|
||||
|
@ -720,8 +720,12 @@ protected:
|
||||
// SPIR-V does not support this distinction, so we must keep track of this information outside the type system.
|
||||
// There might be unrelated IDs found in this set which do not correspond to actual variables.
|
||||
// This set should only be queried for the existence of samplers which are already known to be variables or parameter IDs.
|
||||
// Similar is implemented for images, as well as if subpass inputs are needed.
|
||||
std::unordered_set<uint32_t> comparison_samplers;
|
||||
void analyze_sampler_comparison_states();
|
||||
std::unordered_set<uint32_t> comparison_images;
|
||||
bool need_subpass_input = false;
|
||||
|
||||
void analyze_image_and_sampler_usage();
|
||||
struct CombinedImageSamplerUsageHandler : OpcodeHandler
|
||||
{
|
||||
CombinedImageSamplerUsageHandler(Compiler &compiler_)
|
||||
@ -734,9 +738,12 @@ protected:
|
||||
Compiler &compiler;
|
||||
|
||||
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> dependency_hierarchy;
|
||||
std::unordered_set<uint32_t> comparison_images;
|
||||
std::unordered_set<uint32_t> comparison_samplers;
|
||||
|
||||
void add_hierarchy_to_comparison_samplers(uint32_t sampler);
|
||||
void add_hierarchy_to_comparison_images(uint32_t sampler);
|
||||
bool need_subpass_input = false;
|
||||
};
|
||||
|
||||
void make_constant_null(uint32_t id, uint32_t type);
|
||||
|
@ -376,7 +376,7 @@ string CompilerGLSL::compile()
|
||||
find_static_extensions();
|
||||
fixup_image_load_store_access();
|
||||
update_active_builtins();
|
||||
analyze_sampler_comparison_states();
|
||||
analyze_image_and_sampler_usage();
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
@ -7419,7 +7419,9 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t /* id */)
|
||||
require_extension("GL_EXT_texture_array");
|
||||
res += "Array";
|
||||
}
|
||||
if (type.image.depth)
|
||||
|
||||
// "Shadow" state in GLSL only exists for samplers and combined image samplers.
|
||||
if (((type.basetype == SPIRType::SampledImage) || (type.basetype == SPIRType::Sampler)) && type.image.depth)
|
||||
res += "Shadow";
|
||||
|
||||
return res;
|
||||
|
@ -260,8 +260,9 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type)
|
||||
else
|
||||
SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime.");
|
||||
case DimSubpassData:
|
||||
// This should be implemented same way as desktop GL. Fetch on a 2D texture based on int2(SV_Position).
|
||||
SPIRV_CROSS_THROW("Subpass data support is not yet implemented for HLSL"); // TODO
|
||||
dim = "2D";
|
||||
typed_load = false;
|
||||
break;
|
||||
default:
|
||||
SPIRV_CROSS_THROW("Invalid dimension.");
|
||||
}
|
||||
@ -2402,7 +2403,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
||||
break;
|
||||
|
||||
case SPIRType::Image:
|
||||
if (type.image.sampled == 2)
|
||||
if (type.image.sampled == 2 && type.image.dim != DimSubpassData)
|
||||
space = 'u'; // UAV
|
||||
else
|
||||
space = 't'; // SRV
|
||||
@ -3483,21 +3484,52 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
||||
uint32_t result_type = ops[0];
|
||||
uint32_t id = ops[1];
|
||||
auto *var = maybe_get_backing_variable(ops[2]);
|
||||
auto imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]");
|
||||
auto &type = expression_type(ops[2]);
|
||||
bool subpass_data = type.image.dim == DimSubpassData;
|
||||
bool pure = false;
|
||||
|
||||
// The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4",
|
||||
// except that the underlying type changes how the data is interpreted.
|
||||
if (var)
|
||||
imgexpr = remap_swizzle(get<SPIRType>(result_type),
|
||||
image_format_to_components(get<SPIRType>(var->basetype).image.format), imgexpr);
|
||||
string imgexpr;
|
||||
|
||||
if (subpass_data)
|
||||
{
|
||||
if (options.shader_model < 40)
|
||||
SPIRV_CROSS_THROW("Subpass loads are not supported in HLSL shader model 2/3.");
|
||||
|
||||
// Similar to GLSL, implement subpass loads using texelFetch.
|
||||
if (type.image.ms)
|
||||
{
|
||||
uint32_t operands = ops[4];
|
||||
if (operands != ImageOperandsSampleMask || instruction.length != 6)
|
||||
SPIRV_CROSS_THROW("Multisampled image used in OpImageRead, but unexpected operand mask was used.");
|
||||
uint32_t sample = ops[5];
|
||||
imgexpr = join(to_expression(ops[2]), ".Load(int2(gl_FragCoord.xy), ", to_expression(sample), ")");
|
||||
}
|
||||
else
|
||||
imgexpr = join(to_expression(ops[2]), ".Load(int3(int2(gl_FragCoord.xy), 0))");
|
||||
|
||||
pure = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]");
|
||||
// The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4",
|
||||
// except that the underlying type changes how the data is interpreted.
|
||||
if (var && !subpass_data)
|
||||
imgexpr = remap_swizzle(get<SPIRType>(result_type),
|
||||
image_format_to_components(get<SPIRType>(var->basetype).image.format), imgexpr);
|
||||
}
|
||||
|
||||
if (var && var->forwardable)
|
||||
{
|
||||
bool forward = forced_temporaries.find(id) == end(forced_temporaries);
|
||||
auto &e = emit_op(result_type, id, imgexpr, forward);
|
||||
e.loaded_from = var->self;
|
||||
if (forward)
|
||||
var->dependees.push_back(id);
|
||||
|
||||
if (!pure)
|
||||
{
|
||||
e.loaded_from = var->self;
|
||||
if (forward)
|
||||
var->dependees.push_back(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
emit_op(result_type, id, imgexpr, false);
|
||||
@ -3826,7 +3858,11 @@ string CompilerHLSL::compile()
|
||||
backend.can_return_array = false;
|
||||
|
||||
update_active_builtins();
|
||||
analyze_sampler_comparison_states();
|
||||
analyze_image_and_sampler_usage();
|
||||
|
||||
// Subpass input needs SV_Position.
|
||||
if (need_subpass_input)
|
||||
active_input_builtins |= 1ull << BuiltInFragCoord;
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace spv;
|
||||
using namespace spirv_cross;
|
||||
@ -52,6 +53,57 @@ CompilerMSL::CompilerMSL(const uint32_t *ir, size_t word_count, MSLVertexAttr *p
|
||||
resource_bindings.push_back(&p_res_bindings[i]);
|
||||
}
|
||||
|
||||
void CompilerMSL::build_implicit_builtins()
|
||||
{
|
||||
if (need_subpass_input)
|
||||
{
|
||||
bool has_frag_coord = false;
|
||||
|
||||
for (auto &id : ids)
|
||||
{
|
||||
if (id.get_type() != TypeVariable)
|
||||
continue;
|
||||
|
||||
auto &var = id.get<SPIRVariable>();
|
||||
|
||||
if (var.storage == StorageClassInput &&
|
||||
meta[var.self].decoration.builtin &&
|
||||
meta[var.self].decoration.builtin_type == BuiltInFragCoord)
|
||||
{
|
||||
builtin_frag_coord_id = var.self;
|
||||
has_frag_coord = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_frag_coord)
|
||||
{
|
||||
uint32_t offset = increase_bound_by(3);
|
||||
uint32_t type_id = offset;
|
||||
uint32_t type_ptr_id = offset + 1;
|
||||
uint32_t var_id = offset + 2;
|
||||
|
||||
// Create gl_FragCoord.
|
||||
SPIRType vec4_type;
|
||||
vec4_type.basetype = SPIRType::Float;
|
||||
vec4_type.vecsize = 4;
|
||||
set<SPIRType>(type_id, vec4_type);
|
||||
|
||||
SPIRType vec4_type_ptr;
|
||||
vec4_type_ptr = vec4_type;
|
||||
vec4_type_ptr.pointer = true;
|
||||
vec4_type_ptr.parent_type = type_id;
|
||||
vec4_type_ptr.storage = StorageClassInput;
|
||||
auto &ptr_type = set<SPIRType>(type_ptr_id, vec4_type_ptr);
|
||||
ptr_type.self = type_id;
|
||||
|
||||
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
||||
set_decoration(var_id, DecorationBuiltIn, BuiltInFragCoord);
|
||||
builtin_frag_coord_id = var_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string CompilerMSL::compile()
|
||||
{
|
||||
// Force a classic "C" locale, reverts when function returns
|
||||
@ -60,7 +112,7 @@ string CompilerMSL::compile()
|
||||
// Do not deal with GLES-isms like precision, older extensions and such.
|
||||
CompilerGLSL::options.vulkan_semantics = true;
|
||||
CompilerGLSL::options.es = false;
|
||||
CompilerGLSL::options.version = 120;
|
||||
CompilerGLSL::options.version = 450;
|
||||
backend.float_literal_suffix = false;
|
||||
backend.uint32_t_literal_suffix = true;
|
||||
backend.basic_int_type = "int";
|
||||
@ -74,6 +126,7 @@ string CompilerMSL::compile()
|
||||
backend.flexible_member_array_supported = false;
|
||||
backend.can_declare_arrays_inline = false;
|
||||
backend.can_return_array = false;
|
||||
backend.boolean_mix_support = false;
|
||||
|
||||
replace_illegal_names();
|
||||
|
||||
@ -81,6 +134,9 @@ string CompilerMSL::compile()
|
||||
struct_member_padding.clear();
|
||||
|
||||
update_active_builtins();
|
||||
analyze_image_and_sampler_usage();
|
||||
build_implicit_builtins();
|
||||
|
||||
fixup_image_load_store_access();
|
||||
|
||||
set_enabled_interface_variables(get_active_interface_variables());
|
||||
@ -273,12 +329,21 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::
|
||||
switch (op)
|
||||
{
|
||||
case OpLoad:
|
||||
case OpInBoundsAccessChain:
|
||||
case OpAccessChain:
|
||||
{
|
||||
uint32_t base_id = ops[2];
|
||||
if (global_var_ids.find(base_id) != global_var_ids.end())
|
||||
added_arg_ids.insert(base_id);
|
||||
|
||||
auto &type = get<SPIRType>(ops[0]);
|
||||
if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
|
||||
{
|
||||
// Implicitly reads gl_FragCoord.
|
||||
assert(builtin_frag_coord_id != 0);
|
||||
added_arg_ids.insert(builtin_frag_coord_id);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case OpFunctionCall:
|
||||
@ -1462,11 +1527,15 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
|
||||
{
|
||||
// Mark that this shader reads from this image
|
||||
uint32_t img_id = ops[2];
|
||||
auto *p_var = maybe_get_backing_variable(img_id);
|
||||
if (p_var && has_decoration(p_var->self, DecorationNonReadable))
|
||||
auto &type = expression_type(img_id);
|
||||
if (type.image.dim != DimSubpassData)
|
||||
{
|
||||
unset_decoration(p_var->self, DecorationNonReadable);
|
||||
force_recompile = true;
|
||||
auto *p_var = maybe_get_backing_variable(img_id);
|
||||
if (p_var && has_decoration(p_var->self, DecorationNonReadable))
|
||||
{
|
||||
unset_decoration(p_var->self, DecorationNonReadable);
|
||||
force_recompile = true;
|
||||
}
|
||||
}
|
||||
|
||||
emit_texture_op(instruction);
|
||||
@ -2141,6 +2210,13 @@ string CompilerMSL::to_function_args(uint32_t img, const SPIRType &imgtype, bool
|
||||
|
||||
break;
|
||||
|
||||
case DimSubpassData:
|
||||
if (imgtype.image.ms)
|
||||
tex_coords = "uint2(gl_FragCoord.xy)";
|
||||
else
|
||||
tex_coords = join("uint2(gl_FragCoord.xy), 0");
|
||||
break;
|
||||
|
||||
case Dim2D:
|
||||
if (coord_type.vecsize > 2)
|
||||
tex_coords += ".xy";
|
||||
@ -2959,7 +3035,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
||||
if (is_array(type))
|
||||
{
|
||||
decl += " (&";
|
||||
decl += to_name(var.self);
|
||||
decl += to_expression(var.self);
|
||||
decl += ")";
|
||||
decl += type_to_array_glsl(type);
|
||||
}
|
||||
@ -2967,12 +3043,12 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
||||
{
|
||||
decl += "&";
|
||||
decl += " ";
|
||||
decl += to_name(var.self);
|
||||
decl += to_expression(var.self);
|
||||
}
|
||||
else
|
||||
{
|
||||
decl += " ";
|
||||
decl += to_name(var.self);
|
||||
decl += to_expression(var.self);
|
||||
}
|
||||
|
||||
return decl;
|
||||
@ -3161,8 +3237,9 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
|
||||
|
||||
// Bypass pointers because we need the real image struct
|
||||
auto &img_type = get<SPIRType>(type.self).image;
|
||||
bool shadow_image = comparison_images.count(id) != 0;
|
||||
|
||||
if (img_type.depth)
|
||||
if (img_type.depth || shadow_image)
|
||||
{
|
||||
switch (img_type.dim)
|
||||
{
|
||||
@ -3192,6 +3269,7 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
|
||||
break;
|
||||
case DimBuffer:
|
||||
case Dim2D:
|
||||
case DimSubpassData:
|
||||
img_type_name += (img_type.ms ? "texture2d_ms" : (img_type.arrayed ? "texture2d_array" : "texture2d"));
|
||||
break;
|
||||
case Dim3D:
|
||||
@ -3213,7 +3291,7 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
|
||||
// For unsampled images, append the sample/read/write access qualifier.
|
||||
// For kernel images, the access qualifier my be supplied directly by SPIR-V.
|
||||
// Otherwise it may be set based on whether the image is read from or written to within the shader.
|
||||
if (type.basetype == SPIRType::Image && type.image.sampled == 2)
|
||||
if (type.basetype == SPIRType::Image && type.image.sampled == 2 && type.image.dim != DimSubpassData)
|
||||
{
|
||||
switch (img_type.access)
|
||||
{
|
||||
|
@ -267,6 +267,8 @@ protected:
|
||||
void add_pragma_line(const std::string &line);
|
||||
void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem);
|
||||
void emit_array_copy(const std::string &lhs, uint32_t rhs_id) override;
|
||||
void build_implicit_builtins();
|
||||
uint32_t builtin_frag_coord_id = 0;
|
||||
|
||||
Options options;
|
||||
std::set<SPVFuncImpl> spv_function_implementations;
|
||||
|
Loading…
Reference in New Issue
Block a user