Implement subpass input support in HLSL.

This commit is contained in:
Hans-Kristian Arntzen 2018-02-09 10:26:20 +01:00
Родитель f4bce688d5
Коммит 18a594a76b
10 изменённых файлов: 242 добавлений и 16 удалений

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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 samplers.
comparison_images.insert(image);
for (auto &img : dependency_hierarchy[image])
add_hierarchy_to_comparison_samplers(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

Просмотреть файл

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