Merge pull request #165 from KhronosGroup/hlsl-separate-image-sampler
HLSL: Support for separate image/samplers.
This commit is contained in:
commit
95d4cbcd8c
@ -0,0 +1,44 @@
|
||||
Texture2D<float4> uSampler;
|
||||
SamplerState _uSampler_sampler;
|
||||
Texture2D<float4> uSamplerShadow;
|
||||
SamplerComparisonState _uSamplerShadow_sampler;
|
||||
|
||||
static float FragColor;
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float FragColor : SV_Target0;
|
||||
};
|
||||
|
||||
float4 samp2(Texture2D<float4> s, SamplerState _s_sampler)
|
||||
{
|
||||
return s.Sample(_s_sampler, float2(1.0f, 1.0f)) + s.Load(int3(int2(10, 10), 0));
|
||||
}
|
||||
|
||||
float4 samp3(Texture2D<float4> s, SamplerState _s_sampler)
|
||||
{
|
||||
return samp2(s, _s_sampler);
|
||||
}
|
||||
|
||||
float samp4(Texture2D<float4> s, SamplerComparisonState _s_sampler)
|
||||
{
|
||||
return s.SampleCmp(_s_sampler, float3(1.0f, 1.0f, 1.0f).xy, float3(1.0f, 1.0f, 1.0f).z);
|
||||
}
|
||||
|
||||
float samp(Texture2D<float4> s0, SamplerState _s0_sampler, Texture2D<float4> s1, SamplerComparisonState _s1_sampler)
|
||||
{
|
||||
return samp3(s0, _s0_sampler).x + samp4(s1, _s1_sampler);
|
||||
}
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
FragColor = samp(uSampler, _uSampler_sampler, uSamplerShadow, _uSamplerShadow_sampler);
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main()
|
||||
{
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.FragColor = FragColor;
|
||||
return stage_output;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
Texture2D<float4> uDepth;
|
||||
SamplerComparisonState uSampler;
|
||||
SamplerState uSampler1;
|
||||
|
||||
static float FragColor;
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float FragColor : SV_Target0;
|
||||
};
|
||||
|
||||
float samp2(Texture2D<float4> t, SamplerComparisonState s)
|
||||
{
|
||||
return t.SampleCmp(s, float3(1.0f, 1.0f, 1.0f).xy, float3(1.0f, 1.0f, 1.0f).z);
|
||||
}
|
||||
|
||||
float samp3(Texture2D<float4> t, SamplerState s)
|
||||
{
|
||||
return t.Sample(s, float2(1.0f, 1.0f)).x;
|
||||
}
|
||||
|
||||
float samp(Texture2D<float4> t, SamplerComparisonState s, SamplerState s1)
|
||||
{
|
||||
float r0 = samp2(t, s);
|
||||
float r1 = samp3(t, s1);
|
||||
return r0 + r1;
|
||||
}
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
FragColor = samp(uDepth, uSampler, uSampler1);
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main()
|
||||
{
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.FragColor = FragColor;
|
||||
return stage_output;
|
||||
}
|
@ -18,6 +18,10 @@ Texture2DArray<float4> tex2dArray;
|
||||
SamplerState _tex2dArray_sampler;
|
||||
TextureCubeArray<float4> texCubeArray;
|
||||
SamplerState _texCubeArray_sampler;
|
||||
Texture2D<float4> separateTex2d;
|
||||
SamplerState samplerNonDepth;
|
||||
Texture2D<float4> separateTex2dDepth;
|
||||
SamplerComparisonState samplerDepth;
|
||||
|
||||
static float texCoord1d;
|
||||
static float2 texCoord2d;
|
||||
@ -87,6 +91,8 @@ void frag_main()
|
||||
texcolor += texCubeArray.Sample(_texCubeArray_sampler, texCoord4d);
|
||||
texcolor += tex2d.Gather(_tex2d_sampler, texCoord2d, 0);
|
||||
texcolor += tex2d.Load(int3(int2(1, 2), 0));
|
||||
texcolor += separateTex2d.Sample(samplerNonDepth, texCoord2d);
|
||||
texcolor.w += separateTex2dDepth.SampleCmp(samplerDepth, texCoord3d.xy, texCoord3d.z);
|
||||
FragColor = texcolor;
|
||||
}
|
||||
|
||||
|
@ -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 samp(thread const texture2d<float> t, thread const sampler s)
|
||||
{
|
||||
return t.sample(s, float2(0.5));
|
||||
}
|
||||
|
||||
fragment main0_out main0(texture2d<float> uDepth [[texture(0)]], sampler uSampler [[sampler(0)]])
|
||||
{
|
||||
main0_out out = {};
|
||||
out.FragColor = samp(uDepth, uSampler);
|
||||
return out;
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
uniform mediump sampler2DShadow SPIRV_Cross_CombineduDepthuSampler;
|
||||
uniform mediump sampler2D SPIRV_Cross_CombineduDepthuSampler1;
|
||||
|
||||
layout(location = 0) out float FragColor;
|
||||
|
||||
float samp2(mediump sampler2DShadow SPIRV_Cross_Combinedts)
|
||||
{
|
||||
return texture(SPIRV_Cross_Combinedts, vec3(vec3(1.0).xy, vec3(1.0).z));
|
||||
}
|
||||
|
||||
float samp3(mediump sampler2D SPIRV_Cross_Combinedts)
|
||||
{
|
||||
return texture(SPIRV_Cross_Combinedts, vec2(1.0)).x;
|
||||
}
|
||||
|
||||
float samp(mediump sampler2DShadow SPIRV_Cross_Combinedts, mediump sampler2D SPIRV_Cross_Combinedts1)
|
||||
{
|
||||
float r0 = samp2(SPIRV_Cross_Combinedts);
|
||||
float r1 = samp3(SPIRV_Cross_Combinedts1);
|
||||
return r0 + r1;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = samp(SPIRV_Cross_CombineduDepthuSampler, SPIRV_Cross_CombineduDepthuSampler1);
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
precision highp int;
|
||||
|
||||
layout(set = 0, binding = 2) uniform mediump texture2D uDepth;
|
||||
layout(set = 0, binding = 0) uniform mediump samplerShadow uSampler;
|
||||
layout(set = 0, binding = 1) uniform mediump sampler uSampler1;
|
||||
|
||||
layout(location = 0) out float FragColor;
|
||||
|
||||
float samp2(mediump texture2D t, mediump samplerShadow s)
|
||||
{
|
||||
return texture(sampler2DShadow(t, s), vec3(vec3(1.0).xy, vec3(1.0).z));
|
||||
}
|
||||
|
||||
float samp3(mediump texture2D t, mediump sampler s)
|
||||
{
|
||||
return texture(sampler2D(t, s), vec2(1.0)).x;
|
||||
}
|
||||
|
||||
float samp(mediump texture2D t, mediump samplerShadow s, mediump sampler s1)
|
||||
{
|
||||
float r0 = samp2(t, s);
|
||||
float r1 = samp3(t, s1);
|
||||
return r0 + r1;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = samp(uDepth, uSampler, uSampler1);
|
||||
}
|
||||
|
31
shaders-hlsl/frag/combined-texture-sampler-parameter.frag
Normal file
31
shaders-hlsl/frag/combined-texture-sampler-parameter.frag
Normal file
@ -0,0 +1,31 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(set = 0, binding = 1) uniform mediump sampler2D uSampler;
|
||||
layout(set = 0, binding = 1) uniform mediump sampler2DShadow uSamplerShadow;
|
||||
layout(location = 0) out float FragColor;
|
||||
|
||||
vec4 samp2(sampler2D s)
|
||||
{
|
||||
return texture(s, vec2(1.0)) + texelFetch(s, ivec2(10), 0);
|
||||
}
|
||||
|
||||
vec4 samp3(sampler2D s)
|
||||
{
|
||||
return samp2(s);
|
||||
}
|
||||
|
||||
float samp4(mediump sampler2DShadow s)
|
||||
{
|
||||
return texture(s, vec3(1.0));
|
||||
}
|
||||
|
||||
float samp(sampler2D s0, mediump sampler2DShadow s1)
|
||||
{
|
||||
return samp3(s0).x + samp4(s1);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = samp(uSampler, uSamplerShadow);
|
||||
}
|
29
shaders-hlsl/frag/combined-texture-sampler-shadow.frag
Normal file
29
shaders-hlsl/frag/combined-texture-sampler-shadow.frag
Normal file
@ -0,0 +1,29 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(set = 0, binding = 0) uniform mediump samplerShadow uSampler;
|
||||
layout(set = 0, binding = 1) uniform mediump sampler uSampler1;
|
||||
layout(set = 0, binding = 2) uniform texture2D uDepth;
|
||||
layout(location = 0) out float FragColor;
|
||||
|
||||
float samp2(texture2D t, mediump samplerShadow s)
|
||||
{
|
||||
return texture(sampler2DShadow(t, s), vec3(1.0));
|
||||
}
|
||||
|
||||
float samp3(texture2D t, mediump sampler s)
|
||||
{
|
||||
return texture(sampler2D(t, s), vec2(1.0)).x;
|
||||
}
|
||||
|
||||
float samp(texture2D t, mediump samplerShadow s, mediump sampler s1)
|
||||
{
|
||||
float r0 = samp2(t, s);
|
||||
float r1 = samp3(t, s1);
|
||||
return r0 + r1;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = samp(uDepth, uSampler, uSampler1);
|
||||
}
|
@ -13,6 +13,11 @@ uniform sampler1DArray tex1dArray;
|
||||
uniform sampler2DArray tex2dArray;
|
||||
uniform samplerCubeArray texCubeArray;
|
||||
|
||||
uniform samplerShadow samplerDepth;
|
||||
uniform sampler samplerNonDepth;
|
||||
uniform texture2D separateTex2d;
|
||||
uniform texture2D separateTex2dDepth;
|
||||
|
||||
in float texCoord1d;
|
||||
in vec2 texCoord2d;
|
||||
in vec3 texCoord3d;
|
||||
@ -59,5 +64,8 @@ void main()
|
||||
|
||||
texcolor += texelFetch(tex2d, ivec2(1, 2), 0);
|
||||
|
||||
texcolor += texture(sampler2D(separateTex2d, samplerNonDepth), texCoord2d);
|
||||
texcolor.a += texture(sampler2DShadow(separateTex2dDepth, samplerDepth), texCoord3d);
|
||||
|
||||
FragColor = texcolor;
|
||||
}
|
||||
|
16
shaders-msl/frag/separate-image-sampler-argument.frag
Normal file
16
shaders-msl/frag/separate-image-sampler-argument.frag
Normal file
@ -0,0 +1,16 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(set = 0, binding = 0) uniform mediump sampler uSampler;
|
||||
layout(set = 0, binding = 1) uniform mediump texture2D uDepth;
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
vec4 samp(texture2D t, mediump sampler s)
|
||||
{
|
||||
return texture(sampler2D(t, s), vec2(0.5));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = samp(uDepth, uSampler);
|
||||
}
|
29
shaders/vulkan/frag/combined-texture-sampler-shadow.vk.frag
Normal file
29
shaders/vulkan/frag/combined-texture-sampler-shadow.vk.frag
Normal file
@ -0,0 +1,29 @@
|
||||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(set = 0, binding = 0) uniform mediump samplerShadow uSampler;
|
||||
layout(set = 0, binding = 1) uniform mediump sampler uSampler1;
|
||||
layout(set = 0, binding = 2) uniform texture2D uDepth;
|
||||
layout(location = 0) out float FragColor;
|
||||
|
||||
float samp2(texture2D t, mediump samplerShadow s)
|
||||
{
|
||||
return texture(sampler2DShadow(t, s), vec3(1.0));
|
||||
}
|
||||
|
||||
float samp3(texture2D t, mediump sampler s)
|
||||
{
|
||||
return texture(sampler2D(t, s), vec2(1.0)).x;
|
||||
}
|
||||
|
||||
float samp(texture2D t, mediump samplerShadow s, mediump sampler s1)
|
||||
{
|
||||
float r0 = samp2(t, s);
|
||||
float r1 = samp3(t, s1);
|
||||
return r0 + r1;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
FragColor = samp(uDepth, uSampler, uSampler1);
|
||||
}
|
@ -186,6 +186,7 @@ enum Types
|
||||
TypeExtension,
|
||||
TypeExpression,
|
||||
TypeConstantOp,
|
||||
TypeCombinedImageSampler,
|
||||
TypeUndef
|
||||
};
|
||||
|
||||
@ -202,6 +203,25 @@ struct SPIRUndef : IVariant
|
||||
uint32_t basetype;
|
||||
};
|
||||
|
||||
// This type is only used by backends which need to access the combined image and sampler IDs separately after
|
||||
// the OpSampledImage opcode.
|
||||
struct SPIRCombinedImageSampler : IVariant
|
||||
{
|
||||
enum
|
||||
{
|
||||
type = TypeCombinedImageSampler
|
||||
};
|
||||
SPIRCombinedImageSampler(uint32_t type_, uint32_t image_, uint32_t sampler_)
|
||||
: combined_type(type_)
|
||||
, image(image_)
|
||||
, sampler(sampler_)
|
||||
{
|
||||
}
|
||||
uint32_t combined_type;
|
||||
uint32_t image;
|
||||
uint32_t sampler;
|
||||
};
|
||||
|
||||
struct SPIRConstantOp : IVariant
|
||||
{
|
||||
enum
|
||||
@ -555,6 +575,7 @@ struct SPIRFunction : IVariant
|
||||
uint32_t sampler_id;
|
||||
bool global_image;
|
||||
bool global_sampler;
|
||||
bool depth;
|
||||
};
|
||||
|
||||
uint32_t return_type;
|
||||
|
@ -355,6 +355,9 @@ const SPIRType &Compiler::expression_type(uint32_t id) const
|
||||
case TypeUndef:
|
||||
return get<SPIRType>(get<SPIRUndef>(id).basetype);
|
||||
|
||||
case TypeCombinedImageSampler:
|
||||
return get<SPIRType>(get<SPIRCombinedImageSampler>(id).combined_type);
|
||||
|
||||
default:
|
||||
SPIRV_CROSS_THROW("Cannot resolve expression type.");
|
||||
}
|
||||
@ -2570,7 +2573,7 @@ bool Compiler::CombinedImageSamplerHandler::end_function_scope(const uint32_t *a
|
||||
if (s)
|
||||
sampler_id = s->self;
|
||||
|
||||
register_combined_image_sampler(caller, image_id, sampler_id);
|
||||
register_combined_image_sampler(caller, image_id, sampler_id, param.depth);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2578,13 +2581,13 @@ bool Compiler::CombinedImageSamplerHandler::end_function_scope(const uint32_t *a
|
||||
}
|
||||
|
||||
void Compiler::CombinedImageSamplerHandler::register_combined_image_sampler(SPIRFunction &caller, uint32_t image_id,
|
||||
uint32_t sampler_id)
|
||||
uint32_t sampler_id, bool depth)
|
||||
{
|
||||
// We now have a texture ID and a sampler ID which will either be found as a global
|
||||
// or a parameter in our own function. If both are global, they will not need a parameter,
|
||||
// otherwise, add it to our list.
|
||||
SPIRFunction::CombinedImageSamplerParameter param = {
|
||||
0u, image_id, sampler_id, true, true,
|
||||
0u, image_id, sampler_id, true, true, depth,
|
||||
};
|
||||
|
||||
auto texture_itr = find_if(begin(caller.arguments), end(caller.arguments),
|
||||
@ -2628,6 +2631,7 @@ void Compiler::CombinedImageSamplerHandler::register_combined_image_sampler(SPIR
|
||||
type.basetype = SPIRType::SampledImage;
|
||||
type.pointer = false;
|
||||
type.storage = StorageClassGeneric;
|
||||
type.image.depth = depth;
|
||||
|
||||
ptr_type = type;
|
||||
ptr_type.pointer = true;
|
||||
@ -2694,11 +2698,12 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar
|
||||
bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
|
||||
bool separate_sampler = type.basetype == SPIRType::Sampler;
|
||||
if (separate_image)
|
||||
SPIRV_CROSS_THROW(
|
||||
"Attempting to use arrays of separate images. This is not possible to statically remap to plain GLSL.");
|
||||
SPIRV_CROSS_THROW("Attempting to use arrays or structs of separate images. This is not possible to "
|
||||
"statically remap to plain GLSL.");
|
||||
if (separate_sampler)
|
||||
SPIRV_CROSS_THROW("Attempting to use arrays of separate samplers. This is not possible to statically "
|
||||
"remap to plain GLSL.");
|
||||
SPIRV_CROSS_THROW(
|
||||
"Attempting to use arrays or structs of separate samplers. This is not possible to statically "
|
||||
"remap to plain GLSL.");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2731,7 +2736,8 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar
|
||||
if (sampler)
|
||||
sampler_id = sampler->self;
|
||||
|
||||
register_combined_image_sampler(callee, image_id, sampler_id);
|
||||
auto &combined_type = compiler.get<SPIRType>(args[0]);
|
||||
register_combined_image_sampler(callee, image_id, sampler_id, combined_type.image.depth);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3348,3 +3354,73 @@ void Compiler::update_active_builtins()
|
||||
ActiveBuiltinHandler handler(*this);
|
||||
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
|
||||
}
|
||||
|
||||
void Compiler::analyze_sampler_comparison_states()
|
||||
{
|
||||
CombinedImageSamplerUsageHandler handler(*this);
|
||||
traverse_all_reachable_opcodes(get<SPIRFunction>(entry_point), handler);
|
||||
comparison_samplers = move(handler.comparison_samplers);
|
||||
}
|
||||
|
||||
bool Compiler::CombinedImageSamplerUsageHandler::begin_function_scope(const uint32_t *args, uint32_t length)
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
|
||||
auto &func = compiler.get<SPIRFunction>(args[2]);
|
||||
const auto *arg = &args[3];
|
||||
length -= 3;
|
||||
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
auto &argument = func.arguments[i];
|
||||
dependency_hierarchy[argument.id].insert(arg[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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.
|
||||
comparison_samplers.insert(sampler);
|
||||
for (auto &samp : dependency_hierarchy[sampler])
|
||||
add_hierarchy_to_comparison_samplers(samp);
|
||||
}
|
||||
|
||||
bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_t *args, uint32_t length)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
case OpAccessChain:
|
||||
case OpInBoundsAccessChain:
|
||||
case OpLoad:
|
||||
{
|
||||
if (length < 3)
|
||||
return false;
|
||||
dependency_hierarchy[args[1]].insert(args[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
case OpSampledImage:
|
||||
{
|
||||
if (length < 4)
|
||||
return false;
|
||||
|
||||
uint32_t result_type = args[0];
|
||||
auto &type = compiler.get<SPIRType>(result_type);
|
||||
if (type.image.depth)
|
||||
{
|
||||
// This sampler must be a SamplerComparisionState, and not a regular SamplerState.
|
||||
uint32_t sampler = args[3];
|
||||
add_hierarchy_to_comparison_samplers(sampler);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -582,7 +582,8 @@ protected:
|
||||
uint32_t remap_parameter(uint32_t id);
|
||||
void push_remap_parameters(const SPIRFunction &func, const uint32_t *args, uint32_t length);
|
||||
void pop_remap_parameters();
|
||||
void register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id, uint32_t sampler_id);
|
||||
void register_combined_image_sampler(SPIRFunction &caller, uint32_t texture_id, uint32_t sampler_id,
|
||||
bool depth);
|
||||
};
|
||||
|
||||
struct ActiveBuiltinHandler : OpcodeHandler
|
||||
@ -619,6 +620,29 @@ protected:
|
||||
void analyze_parameter_preservation(
|
||||
SPIRFunction &entry, const CFG &cfg,
|
||||
const std::unordered_map<uint32_t, std::unordered_set<uint32_t>> &variable_to_blocks);
|
||||
|
||||
// If a variable ID or parameter ID is found in this set, a sampler is actually a shadow/comparison sampler.
|
||||
// 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.
|
||||
std::unordered_set<uint32_t> comparison_samplers;
|
||||
void analyze_sampler_comparison_states();
|
||||
struct CombinedImageSamplerUsageHandler : OpcodeHandler
|
||||
{
|
||||
CombinedImageSamplerUsageHandler(Compiler &compiler_)
|
||||
: compiler(compiler_)
|
||||
{
|
||||
}
|
||||
|
||||
bool begin_function_scope(const uint32_t *args, uint32_t length) override;
|
||||
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
|
||||
Compiler &compiler;
|
||||
|
||||
std::unordered_map<uint32_t, std::unordered_set<uint32_t>> dependency_hierarchy;
|
||||
std::unordered_set<uint32_t> comparison_samplers;
|
||||
|
||||
void add_hierarchy_to_comparison_samplers(uint32_t sampler);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -311,6 +311,7 @@ string CompilerGLSL::compile()
|
||||
find_static_extensions();
|
||||
fixup_image_load_store_access();
|
||||
update_active_builtins();
|
||||
analyze_sampler_comparison_states();
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
@ -1837,6 +1838,14 @@ string CompilerGLSL::to_expression(uint32_t id)
|
||||
}
|
||||
}
|
||||
|
||||
case TypeCombinedImageSampler:
|
||||
// This type should never be taken the expression of directly.
|
||||
// The intention is that texture sampling functions will extract the image and samplers
|
||||
// separately and take their expressions as needed.
|
||||
// GLSL does not use this type because OpSampledImage immediately creates a combined image sampler
|
||||
// expression ala sampler2D(texture, sampler).
|
||||
SPIRV_CROSS_THROW("Combined image samplers have no default expression representation.");
|
||||
|
||||
default:
|
||||
return to_name(id);
|
||||
}
|
||||
@ -5803,7 +5812,6 @@ string CompilerGLSL::to_qualifiers_glsl(uint32_t id)
|
||||
string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
|
||||
{
|
||||
// glslangValidator seems to make all arguments pointer no matter what which is rather bizarre ...
|
||||
// Not sure if argument being pointer type should make the argument inout.
|
||||
auto &type = expression_type(arg.id);
|
||||
const char *direction = "";
|
||||
|
||||
@ -5815,14 +5823,37 @@ string CompilerGLSL::argument_decl(const SPIRFunction::Parameter &arg)
|
||||
direction = "out ";
|
||||
}
|
||||
|
||||
return join(direction, to_qualifiers_glsl(arg.id), variable_decl(type, to_name(arg.id)));
|
||||
// We need some special consideration for samplers.
|
||||
// The shadow qualifier for a sampler does not exist in SPIR-V, so the type might depend on which variable this is.
|
||||
SPIRType fake_type;
|
||||
const auto *tmp_type = &type;
|
||||
if (type.basetype == SPIRType::Sampler)
|
||||
{
|
||||
tmp_type = &fake_type;
|
||||
fake_type = type;
|
||||
fake_type.image.depth = comparison_samplers.count(arg.id) != 0;
|
||||
}
|
||||
|
||||
return join(direction, to_qualifiers_glsl(arg.id), variable_decl(*tmp_type, to_name(arg.id)));
|
||||
}
|
||||
|
||||
string CompilerGLSL::variable_decl(const SPIRVariable &variable)
|
||||
{
|
||||
// Ignore the pointer type since GLSL doesn't have pointers.
|
||||
auto &type = get<SPIRType>(variable.basetype);
|
||||
auto res = join(to_qualifiers_glsl(variable.self), variable_decl(type, to_name(variable.self)));
|
||||
|
||||
// We need some special consideration for samplers.
|
||||
// The shadow qualifier for a sampler does not exist in SPIR-V, so the type might depend on which variable this is.
|
||||
SPIRType fake_type;
|
||||
const auto *tmp_type = &type;
|
||||
if (type.basetype == SPIRType::Sampler)
|
||||
{
|
||||
tmp_type = &fake_type;
|
||||
fake_type = type;
|
||||
fake_type.image.depth = comparison_samplers.count(variable.self) != 0;
|
||||
}
|
||||
|
||||
auto res = join(to_qualifiers_glsl(variable.self), variable_decl(*tmp_type, to_name(variable.self)));
|
||||
if (variable.loop_variable)
|
||||
res += join(" = ", to_expression(variable.static_expression));
|
||||
else if (variable.initializer)
|
||||
@ -6002,7 +6033,11 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type)
|
||||
return image_type_glsl(type);
|
||||
|
||||
case SPIRType::Sampler:
|
||||
return "sampler";
|
||||
// This is a hacky workaround. The sampler type in SPIR-V doesn't actually signal this distinction,
|
||||
// but in higher level code we need it.
|
||||
// The depth field is set by calling code based on the variable ID of the sampler, effectively reintroducing
|
||||
// this distinction into the type system.
|
||||
return type.image.depth ? "samplerShadow" : "sampler";
|
||||
|
||||
case SPIRType::Void:
|
||||
return "void";
|
||||
|
@ -366,7 +366,7 @@ protected:
|
||||
uint64_t combined_decoration_for_member(const SPIRType &type, uint32_t index);
|
||||
std::string layout_for_variable(const SPIRVariable &variable);
|
||||
std::string to_combined_image_sampler(uint32_t image_id, uint32_t samp_id);
|
||||
bool skip_argument(uint32_t id) const;
|
||||
virtual bool skip_argument(uint32_t id) const;
|
||||
|
||||
bool ssbo_is_std430_packing(const SPIRType &type);
|
||||
uint32_t type_to_std430_base_size(const SPIRType &type);
|
||||
|
216
spirv_hlsl.cpp
216
spirv_hlsl.cpp
@ -43,7 +43,39 @@ static bool opcode_is_sign_invariant(Op opcode)
|
||||
}
|
||||
}
|
||||
|
||||
string CompilerHLSL::image_type_hlsl(const SPIRType &type)
|
||||
string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type)
|
||||
{
|
||||
auto &imagetype = get<SPIRType>(type.image.type);
|
||||
const char *dim = nullptr;
|
||||
switch (type.image.dim)
|
||||
{
|
||||
case Dim1D:
|
||||
dim = "1D";
|
||||
break;
|
||||
case Dim2D:
|
||||
dim = "2D";
|
||||
break;
|
||||
case Dim3D:
|
||||
dim = "3D";
|
||||
break;
|
||||
case DimCube:
|
||||
dim = "Cube";
|
||||
break;
|
||||
case DimRect:
|
||||
SPIRV_CROSS_THROW("Rectangle texture support is not yet implemented for HLSL"); // TODO
|
||||
case DimBuffer:
|
||||
// Buffer/RWBuffer.
|
||||
SPIRV_CROSS_THROW("Buffer/RWBuffer support is not yet implemented for HLSL"); // TODO
|
||||
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
|
||||
}
|
||||
uint32_t components = 4;
|
||||
const char *arrayed = type.image.arrayed ? "Array" : "";
|
||||
return join("Texture", dim, arrayed, "<", type_to_glsl(imagetype), components, ">");
|
||||
}
|
||||
|
||||
string CompilerHLSL::image_type_hlsl_legacy(const SPIRType &type)
|
||||
{
|
||||
auto &imagetype = get<SPIRType>(type.image.type);
|
||||
string res;
|
||||
@ -105,17 +137,21 @@ string CompilerHLSL::image_type_hlsl(const SPIRType &type)
|
||||
if (type.image.ms)
|
||||
res += "MS";
|
||||
if (type.image.arrayed)
|
||||
{
|
||||
if (is_legacy_desktop())
|
||||
require_extension("GL_EXT_texture_array");
|
||||
res += "Array";
|
||||
}
|
||||
if (type.image.depth)
|
||||
res += "Shadow";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
string CompilerHLSL::image_type_hlsl(const SPIRType &type)
|
||||
{
|
||||
if (options.shader_model <= 30)
|
||||
return image_type_hlsl_legacy(type);
|
||||
else
|
||||
return image_type_hlsl_modern(type);
|
||||
}
|
||||
|
||||
string CompilerHLSL::type_to_glsl(const SPIRType &type)
|
||||
{
|
||||
// Ignore the pointer type since GLSL doesn't have pointers.
|
||||
@ -134,7 +170,7 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type)
|
||||
return image_type_hlsl(type);
|
||||
|
||||
case SPIRType::Sampler:
|
||||
return "sampler";
|
||||
return type.image.depth ? "SamplerComparisonState" : "SamplerState";
|
||||
|
||||
case SPIRType::Void:
|
||||
return "void";
|
||||
@ -856,6 +892,39 @@ void CompilerHLSL::emit_push_constant_block(const SPIRVariable &)
|
||||
statement("constant block");
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_sampler_expression(uint32_t id)
|
||||
{
|
||||
return join("_", to_expression(id), "_sampler");
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id)
|
||||
{
|
||||
set<SPIRCombinedImageSampler>(result_id, result_type, image_id, samp_id);
|
||||
}
|
||||
|
||||
string CompilerHLSL::to_func_call_arg(uint32_t id)
|
||||
{
|
||||
string arg_str = CompilerGLSL::to_func_call_arg(id);
|
||||
|
||||
if (options.shader_model <= 30)
|
||||
return arg_str;
|
||||
|
||||
// Manufacture automatic sampler arg if the arg is a SampledImage texture and we're in modern HLSL.
|
||||
auto *var = maybe_get<SPIRVariable>(id);
|
||||
if (var)
|
||||
{
|
||||
auto &type = get<SPIRType>(var->basetype);
|
||||
|
||||
// We don't have to consider combined image samplers here via OpSampledImage because
|
||||
// those variables cannot be passed as arguments to functions.
|
||||
// Only global SampledImage variables may be used as arguments.
|
||||
if (type.basetype == SPIRType::SampledImage)
|
||||
arg_str += ", " + to_sampler_expression(id);
|
||||
}
|
||||
|
||||
return arg_str;
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_flags)
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
@ -894,6 +963,18 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, uint64_t return_f
|
||||
add_local_variable_name(arg.id);
|
||||
|
||||
decl += argument_decl(arg);
|
||||
|
||||
// Flatten a combined sampler to two separate arguments in modern HLSL.
|
||||
auto &arg_type = get<SPIRType>(arg.type);
|
||||
if (options.shader_model > 30 && arg_type.basetype == SPIRType::SampledImage)
|
||||
{
|
||||
// Manufacture automatic sampler arg for SampledImage texture
|
||||
decl += ", ";
|
||||
if (arg_type.basetype == SPIRType::SampledImage)
|
||||
decl += join(arg_type.image.depth ? "SamplerComparisonState " : "SamplerState ",
|
||||
to_sampler_expression(arg.id));
|
||||
}
|
||||
|
||||
if (&arg != &func.arguments.back())
|
||||
decl += ", ";
|
||||
|
||||
@ -1127,6 +1208,8 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
bool gather = false;
|
||||
bool proj = false;
|
||||
const uint32_t *opt = nullptr;
|
||||
auto *combined_image = maybe_get<SPIRCombinedImageSampler>(img);
|
||||
auto img_expr = to_expression(combined_image ? combined_image->image : img);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
@ -1244,7 +1327,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
{
|
||||
SPIRV_CROSS_THROW("texelFetch is not supported in HLSL shader model 2/3.");
|
||||
}
|
||||
texop += to_expression(img);
|
||||
texop += img_expr;
|
||||
texop += ".Load";
|
||||
}
|
||||
else
|
||||
@ -1257,7 +1340,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
|
||||
if (options.shader_model >= 40)
|
||||
{
|
||||
texop += to_expression(img);
|
||||
texop += img_expr;
|
||||
|
||||
if (imgtype.image.depth)
|
||||
texop += ".SampleCmp";
|
||||
@ -1311,21 +1394,17 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
|
||||
expr += texop;
|
||||
expr += "(";
|
||||
if (op != OpImageFetch)
|
||||
if (op != OpImageFetch && (options.shader_model >= 40))
|
||||
{
|
||||
if (options.shader_model >= 40)
|
||||
{
|
||||
expr += "_";
|
||||
}
|
||||
expr += to_expression(img);
|
||||
if (options.shader_model >= 40)
|
||||
{
|
||||
expr += "_sampler";
|
||||
}
|
||||
string sampler_expr;
|
||||
if (combined_image)
|
||||
sampler_expr = to_expression(combined_image->sampler);
|
||||
else
|
||||
sampler_expr = to_sampler_expression(img);
|
||||
expr += sampler_expr;
|
||||
}
|
||||
|
||||
bool swizz_func = backend.swizzle_is_function;
|
||||
auto swizzle = [swizz_func](uint32_t comps, uint32_t in_comps) -> const char * {
|
||||
auto swizzle = [](uint32_t comps, uint32_t in_comps) -> const char * {
|
||||
if (comps == in_comps)
|
||||
return "";
|
||||
|
||||
@ -1334,9 +1413,9 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
case 1:
|
||||
return ".x";
|
||||
case 2:
|
||||
return swizz_func ? ".xy()" : ".xy";
|
||||
return ".xy";
|
||||
case 3:
|
||||
return swizz_func ? ".xyz()" : ".xyz";
|
||||
return ".xyz";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
@ -1382,9 +1461,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
if (op == OpImageFetch)
|
||||
{
|
||||
auto &coordtype = expression_type(coord);
|
||||
stringstream str;
|
||||
str << coordtype.vecsize + 1;
|
||||
coord_expr = "int" + str.str() + "(" + coord_expr + ", " + to_expression(lod) + ")";
|
||||
coord_expr = join("int", coordtype.vecsize + 1, "(", coord_expr, ", ", to_expression(lod), ")");
|
||||
}
|
||||
|
||||
if (op != OpImageFetch)
|
||||
@ -1455,46 +1532,62 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
emit_op(result_type, id, expr, forward, false);
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_modern_uniform(const SPIRVariable &var)
|
||||
{
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
switch (type.basetype)
|
||||
{
|
||||
case SPIRType::SampledImage:
|
||||
case SPIRType::Image:
|
||||
{
|
||||
statement(image_type_hlsl_modern(type), " ", to_name(var.self), ";");
|
||||
|
||||
if (type.basetype == SPIRType::SampledImage)
|
||||
{
|
||||
// For combined image samplers, also emit a combined image sampler.
|
||||
if (type.image.depth)
|
||||
statement("SamplerComparisonState ", to_sampler_expression(var.self), ";");
|
||||
else
|
||||
statement("SamplerState ", to_sampler_expression(var.self), ";");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SPIRType::Sampler:
|
||||
if (comparison_samplers.count(var.self))
|
||||
statement("SamplerComparisonState ", to_name(var.self), ";");
|
||||
else
|
||||
statement("SamplerState ", to_name(var.self), ";");
|
||||
break;
|
||||
|
||||
default:
|
||||
statement(variable_decl(var), ";");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_legacy_uniform(const SPIRVariable &var)
|
||||
{
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
switch (type.basetype)
|
||||
{
|
||||
case SPIRType::Sampler:
|
||||
case SPIRType::Image:
|
||||
SPIRV_CROSS_THROW("Separate image and samplers not supported in legacy HLSL.");
|
||||
|
||||
default:
|
||||
statement(variable_decl(var), ";");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_uniform(const SPIRVariable &var)
|
||||
{
|
||||
add_resource_name(var.self);
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
if (options.shader_model >= 40 && type.basetype == SPIRType::SampledImage)
|
||||
{
|
||||
auto &imagetype = get<SPIRType>(type.image.type);
|
||||
string dim;
|
||||
switch (type.image.dim)
|
||||
{
|
||||
case Dim1D:
|
||||
dim = "1D";
|
||||
break;
|
||||
case Dim2D:
|
||||
dim = "2D";
|
||||
break;
|
||||
case Dim3D:
|
||||
dim = "3D";
|
||||
break;
|
||||
case DimCube:
|
||||
dim = "Cube";
|
||||
break;
|
||||
case DimRect:
|
||||
case DimBuffer:
|
||||
case DimSubpassData:
|
||||
SPIRV_CROSS_THROW("Buffer texture support is not yet implemented for HLSL"); // TODO
|
||||
}
|
||||
string arrayed = type.image.arrayed ? "Array" : "";
|
||||
statement("Texture", dim, arrayed, "<", type_to_glsl(imagetype), "4> ", to_name(var.self), ";");
|
||||
if (type.image.depth)
|
||||
statement("SamplerComparisonState _", to_name(var.self), "_sampler;");
|
||||
else
|
||||
statement("SamplerState _", to_name(var.self), "_sampler;");
|
||||
}
|
||||
if (options.shader_model >= 40)
|
||||
emit_modern_uniform(var);
|
||||
else
|
||||
{
|
||||
statement(variable_decl(var), ";");
|
||||
}
|
||||
|
||||
// TODO: Separate samplers/images
|
||||
emit_legacy_uniform(var);
|
||||
}
|
||||
|
||||
string CompilerHLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
|
||||
@ -1845,6 +1938,7 @@ string CompilerHLSL::compile()
|
||||
backend.boolean_mix_support = false;
|
||||
|
||||
update_active_builtins();
|
||||
analyze_sampler_comparison_states();
|
||||
|
||||
uint32_t pass_count = 0;
|
||||
do
|
||||
|
@ -61,6 +61,8 @@ public:
|
||||
private:
|
||||
std::string type_to_glsl(const SPIRType &type) override;
|
||||
std::string image_type_hlsl(const SPIRType &type);
|
||||
std::string image_type_hlsl_modern(const SPIRType &type);
|
||||
std::string image_type_hlsl_legacy(const SPIRType &type);
|
||||
void emit_function_prototype(SPIRFunction &func, uint64_t return_flags) override;
|
||||
void emit_hlsl_entry_point();
|
||||
void emit_header() override;
|
||||
@ -76,9 +78,14 @@ private:
|
||||
void emit_buffer_block(const SPIRVariable &type) override;
|
||||
void emit_push_constant_block(const SPIRVariable &var) override;
|
||||
void emit_uniform(const SPIRVariable &var) override;
|
||||
void emit_modern_uniform(const SPIRVariable &var);
|
||||
void emit_legacy_uniform(const SPIRVariable &var);
|
||||
std::string layout_for_member(const SPIRType &type, uint32_t index) override;
|
||||
std::string to_interpolation_qualifiers(uint64_t flags) override;
|
||||
std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override;
|
||||
std::string to_func_call_arg(uint32_t id) override;
|
||||
std::string to_sampler_expression(uint32_t id);
|
||||
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
|
||||
|
||||
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;
|
||||
|
||||
|
@ -2198,6 +2198,11 @@ size_t CompilerMSL::get_declared_type_alignment(uint32_t type_id, uint64_t dec_m
|
||||
}
|
||||
}
|
||||
|
||||
bool CompilerMSL::skip_argument(uint32_t) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t * /*args*/, uint32_t /*length*/)
|
||||
{
|
||||
switch (opcode)
|
||||
|
@ -196,6 +196,7 @@ protected:
|
||||
void align_struct(SPIRType &ib_type);
|
||||
bool is_member_packable(SPIRType &ib_type, uint32_t index);
|
||||
MSLStructMemberKey get_struct_member_key(uint32_t type_id, uint32_t index);
|
||||
bool skip_argument(uint32_t id) const override;
|
||||
|
||||
Options options;
|
||||
std::unordered_map<std::string, std::string> func_name_overrides;
|
||||
|
Loading…
Reference in New Issue
Block a user