Make use of explicit locations in HLSL.
This commit is contained in:
Родитель
2ebe1a87a1
Коммит
61c31c6054
|
@ -0,0 +1,31 @@
|
|||
static float4 RT0;
|
||||
static float4 RT1;
|
||||
static float4 RT2;
|
||||
static float4 RT3;
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 RT0 : COLOR0;
|
||||
float4 RT1 : COLOR1;
|
||||
float4 RT2 : COLOR2;
|
||||
float4 RT3 : COLOR3;
|
||||
};
|
||||
|
||||
void frag_main()
|
||||
{
|
||||
RT0 = float4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
RT1 = float4(2.0f, 2.0f, 2.0f, 2.0f);
|
||||
RT2 = float4(3.0f, 3.0f, 3.0f, 3.0f);
|
||||
RT3 = float4(4.0f, 4.0f, 4.0f, 4.0f);
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main()
|
||||
{
|
||||
frag_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.RT0 = RT0;
|
||||
stage_output.RT1 = RT1;
|
||||
stage_output.RT2 = RT2;
|
||||
stage_output.RT3 = RT3;
|
||||
return stage_output;
|
||||
}
|
|
@ -23,7 +23,7 @@ struct SPIRV_Cross_Input
|
|||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 gl_Position : POSITION;
|
||||
float3 vNormal : TEXCOORD2;
|
||||
float3 vNormal : TEXCOORD0;
|
||||
};
|
||||
|
||||
void vert_main()
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
struct Foo
|
||||
{
|
||||
float3 a;
|
||||
float3 b;
|
||||
float3 c;
|
||||
};
|
||||
|
||||
uniform float4 gl_HalfPixel;
|
||||
|
||||
static float4 gl_Position;
|
||||
static float4 Input2;
|
||||
static float4 Input4;
|
||||
static float4 Input0;
|
||||
static float vLocation0;
|
||||
static float vLocation1;
|
||||
static float vLocation2[2];
|
||||
static Foo vLocation4;
|
||||
static float vLocation7;
|
||||
|
||||
struct SPIRV_Cross_Input
|
||||
{
|
||||
float4 Input2 : TEXCOORD2;
|
||||
float4 Input4 : TEXCOORD4;
|
||||
float4 Input0 : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct SPIRV_Cross_Output
|
||||
{
|
||||
float4 gl_Position : POSITION;
|
||||
float vLocation0 : TEXCOORD0;
|
||||
float vLocation1 : TEXCOORD1;
|
||||
float vLocation2[2] : TEXCOORD2;
|
||||
Foo vLocation4 : TEXCOORD4;
|
||||
float vLocation7 : TEXCOORD7;
|
||||
};
|
||||
|
||||
void vert_main()
|
||||
{
|
||||
gl_Position = ((float4(1.0f, 1.0f, 1.0f, 1.0f) + Input2) + Input4) + Input0;
|
||||
vLocation0 = 0.0f;
|
||||
vLocation1 = 1.0f;
|
||||
vLocation2[0] = 2.0f;
|
||||
vLocation2[1] = 2.0f;
|
||||
Foo foo;
|
||||
foo.a = float3(1.0f, 1.0f, 1.0f);
|
||||
foo.b = float3(1.0f, 1.0f, 1.0f);
|
||||
foo.c = float3(1.0f, 1.0f, 1.0f);
|
||||
vLocation4 = foo;
|
||||
vLocation7 = 7.0f;
|
||||
}
|
||||
|
||||
SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
|
||||
{
|
||||
Input2 = stage_input.Input2;
|
||||
Input4 = stage_input.Input4;
|
||||
Input0 = stage_input.Input0;
|
||||
vert_main();
|
||||
SPIRV_Cross_Output stage_output;
|
||||
stage_output.gl_Position = gl_Position;
|
||||
stage_output.vLocation0 = vLocation0;
|
||||
stage_output.vLocation1 = vLocation1;
|
||||
stage_output.vLocation2 = vLocation2;
|
||||
stage_output.vLocation4 = vLocation4;
|
||||
stage_output.vLocation7 = vLocation7;
|
||||
stage_output.gl_Position.x = stage_output.gl_Position.x - gl_HalfPixel.x * stage_output.gl_Position.w;
|
||||
stage_output.gl_Position.y = stage_output.gl_Position.y + gl_HalfPixel.y * stage_output.gl_Position.w;
|
||||
return stage_output;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
#version 310 es
|
||||
precision mediump float;
|
||||
|
||||
layout(location = 0) out vec4 RT0;
|
||||
layout(location = 1) out vec4 RT1;
|
||||
layout(location = 2) out vec4 RT2;
|
||||
layout(location = 3) out vec4 RT3;
|
||||
|
||||
void main()
|
||||
{
|
||||
RT0 = vec4(1.0);
|
||||
RT1 = vec4(2.0);
|
||||
RT2 = vec4(3.0);
|
||||
RT3 = vec4(4.0);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#version 310 es
|
||||
|
||||
struct Foo
|
||||
{
|
||||
vec3 a;
|
||||
vec3 b;
|
||||
vec3 c;
|
||||
};
|
||||
|
||||
layout(location = 2) in vec4 Input2;
|
||||
layout(location = 4) in vec4 Input4;
|
||||
in vec4 Input0;
|
||||
|
||||
layout(location = 0) out float vLocation0;
|
||||
layout(location = 1) out float vLocation1;
|
||||
out float vLocation2[2];
|
||||
out Foo vLocation4;
|
||||
out float vLocation7;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = vec4(1.0) + Input2 + Input4 + Input0;
|
||||
vLocation0 = 0.0;
|
||||
vLocation1 = 1.0;
|
||||
vLocation2[0] = 2.0;
|
||||
vLocation2[1] = 2.0;
|
||||
Foo foo;
|
||||
foo.a = vec3(1.0);
|
||||
foo.b = vec3(1.0);
|
||||
foo.c = vec3(1.0);
|
||||
vLocation4 = foo;
|
||||
vLocation7 = 7.0;
|
||||
}
|
|
@ -136,7 +136,7 @@ bool Compiler::block_is_pure(const SPIRBlock &block)
|
|||
return true;
|
||||
}
|
||||
|
||||
string Compiler::to_name(uint32_t id, bool allow_alias)
|
||||
string Compiler::to_name(uint32_t id, bool allow_alias) const
|
||||
{
|
||||
if (allow_alias && ids.at(id).get_type() == TypeType)
|
||||
{
|
||||
|
|
|
@ -411,7 +411,7 @@ protected:
|
|||
std::unordered_set<uint32_t> selection_merge_targets;
|
||||
std::unordered_set<uint32_t> multiselect_merge_targets;
|
||||
|
||||
virtual std::string to_name(uint32_t id, bool allow_alias = true);
|
||||
virtual std::string to_name(uint32_t id, bool allow_alias = true) const;
|
||||
bool is_builtin_variable(const SPIRVariable &var) const;
|
||||
bool is_hidden_variable(const SPIRVariable &var, bool include_builtins = false) const;
|
||||
bool is_immutable(uint32_t id) const;
|
||||
|
|
161
spirv_hlsl.cpp
161
spirv_hlsl.cpp
|
@ -22,39 +22,6 @@ using namespace spv;
|
|||
using namespace spirv_cross;
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
struct VariableComparator
|
||||
{
|
||||
VariableComparator(const CompilerHLSL &compiler_)
|
||||
: compiler(compiler_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(SPIRVariable *var1, SPIRVariable *var2)
|
||||
{
|
||||
if (compiler.get_decoration_mask(var1->self) & compiler.get_decoration_mask(var2->self) &
|
||||
(1ull << DecorationLocation))
|
||||
return compiler.get_decoration(var1->self, DecorationLocation) <
|
||||
compiler.get_decoration(var2->self, DecorationLocation);
|
||||
|
||||
auto &name1 = compiler.get_name(var1->self);
|
||||
auto &name2 = compiler.get_name(var2->self);
|
||||
|
||||
if (name1.empty() && name2.empty())
|
||||
return var1->self < var2->self;
|
||||
if (name1.empty())
|
||||
return true;
|
||||
else if (name2.empty())
|
||||
return false;
|
||||
|
||||
return name1.compare(name2) < 0;
|
||||
}
|
||||
|
||||
const CompilerHLSL &compiler;
|
||||
};
|
||||
}
|
||||
|
||||
string CompilerHLSL::type_to_glsl(const SPIRType &type)
|
||||
{
|
||||
// Ignore the pointer type since GLSL doesn't have pointers.
|
||||
|
@ -163,21 +130,8 @@ void CompilerHLSL::emit_header()
|
|||
|
||||
void CompilerHLSL::emit_interface_block_globally(const SPIRVariable &var)
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
|
||||
add_resource_name(var.self);
|
||||
|
||||
if (execution.model == ExecutionModelVertex && var.storage == StorageClassInput && is_builtin_variable(var))
|
||||
{
|
||||
}
|
||||
else if (execution.model == ExecutionModelVertex && var.storage == StorageClassOutput && is_builtin_variable(var))
|
||||
{
|
||||
statement("static float4 gl_Position;");
|
||||
}
|
||||
else
|
||||
{
|
||||
statement("static ", variable_decl(var), ";");
|
||||
}
|
||||
statement("static ", variable_decl(var), ";");
|
||||
}
|
||||
|
||||
const char *CompilerHLSL::to_storage_qualifiers_glsl(const SPIRVariable &var)
|
||||
|
@ -249,12 +203,37 @@ void CompilerHLSL::emit_builtin_inputs_in_struct()
|
|||
}
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, uint32_t &binding_number)
|
||||
uint32_t CompilerHLSL::type_to_consumed_locations(const SPIRType &type) const
|
||||
{
|
||||
// TODO: Need to verify correctness.
|
||||
uint32_t elements = 0;
|
||||
|
||||
if (type.basetype == SPIRType::Struct)
|
||||
{
|
||||
for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++)
|
||||
elements += type_to_consumed_locations(get<SPIRType>(type.member_types[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t array_multiplier = 1;
|
||||
for (uint32_t i = 0; i < uint32_t(type.array.size()); i++)
|
||||
{
|
||||
if (type.array_size_literal[i])
|
||||
array_multiplier *= type.array[i];
|
||||
else
|
||||
array_multiplier *= get<SPIRConstant>(type.array[i]).scalar();
|
||||
}
|
||||
elements += array_multiplier * type.columns;
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unordered_set<uint32_t> &active_locations)
|
||||
{
|
||||
auto &execution = get_entry_point();
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
|
||||
string binding = "TEXCOORD";
|
||||
string binding;
|
||||
bool use_binding_number = true;
|
||||
bool legacy = options.shader_model <= 30;
|
||||
if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput)
|
||||
|
@ -263,27 +242,52 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, uint3
|
|||
use_binding_number = false;
|
||||
}
|
||||
|
||||
const auto get_vacant_location = [&]() -> uint32_t {
|
||||
for (uint32_t i = 0; i < 64; i++)
|
||||
if (!active_locations.count(i))
|
||||
return i;
|
||||
SPIRV_CROSS_THROW("All locations from 0 to 63 are exhausted.");
|
||||
};
|
||||
|
||||
auto &m = meta[var.self].decoration;
|
||||
auto name = to_name(var.self);
|
||||
if (use_binding_number)
|
||||
{
|
||||
uint32_t binding_number;
|
||||
|
||||
// If an explicit location exists, use it with TEXCOORD[N] semantic.
|
||||
// Otherwise, pick a vacant location.
|
||||
if (m.decoration_flags & (1ull << DecorationLocation))
|
||||
binding_number = m.location;
|
||||
else
|
||||
binding_number = get_vacant_location();
|
||||
|
||||
if (type.columns > 1)
|
||||
{
|
||||
if (!type.array.empty())
|
||||
SPIRV_CROSS_THROW("Arrays of matrices used as input/output. This is not supported.");
|
||||
|
||||
// Unroll matrices.
|
||||
for (uint32_t i = 0; i < type.columns; i++)
|
||||
{
|
||||
SPIRType newtype = type;
|
||||
newtype.columns = 1;
|
||||
statement(variable_decl(newtype, join(m.alias, "_", i)), " : ", binding, binding_number++, ";");
|
||||
statement(variable_decl(newtype, join(name, "_", i)), " : TEXCOORD", binding_number, ";");
|
||||
active_locations.insert(binding_number++);
|
||||
}
|
||||
--binding_number;
|
||||
}
|
||||
else
|
||||
statement(variable_decl(type, m.alias), " : ", binding, binding_number, ";");
|
||||
{
|
||||
statement(variable_decl(type, name), " : TEXCOORD", binding_number, ";");
|
||||
|
||||
// Structs and arrays should consume more locations.
|
||||
uint32_t consumed_locations = type_to_consumed_locations(type);
|
||||
for (uint32_t i = 0; i < consumed_locations; i++)
|
||||
active_locations.insert(binding_number + i);
|
||||
}
|
||||
}
|
||||
else
|
||||
statement(variable_decl(type, m.alias), " : ", binding, ";");
|
||||
|
||||
if (use_binding_number)
|
||||
binding_number++;
|
||||
statement(variable_decl(type, name), " : ", binding, ";");
|
||||
}
|
||||
|
||||
void CompilerHLSL::emit_builtin_variables()
|
||||
|
@ -423,7 +427,8 @@ void CompilerHLSL::emit_resources()
|
|||
statement("");
|
||||
emitted = false;
|
||||
|
||||
uint32_t binding_number = 0;
|
||||
unordered_set<uint32_t> active_inputs;
|
||||
unordered_set<uint32_t> active_outputs;
|
||||
vector<SPIRVariable *> input_variables;
|
||||
vector<SPIRVariable *> output_variables;
|
||||
for (auto &id : ids)
|
||||
|
@ -445,17 +450,49 @@ void CompilerHLSL::emit_resources()
|
|||
}
|
||||
}
|
||||
|
||||
const auto variable_compare = [&](const SPIRVariable *a, const SPIRVariable *b) -> bool {
|
||||
// Sort input and output variables based on, from more robust to less robust:
|
||||
// - Location
|
||||
// - Variable has a location
|
||||
// - Name comparison
|
||||
// - Variable has a name
|
||||
// - Fallback: ID
|
||||
bool has_location_a = (get_decoration_mask(a->self) & (1ull << DecorationLocation)) != 0;
|
||||
bool has_location_b = (get_decoration_mask(b->self) & (1ull << DecorationLocation)) != 0;
|
||||
|
||||
if (has_location_a && has_location_b)
|
||||
{
|
||||
return get_decoration(a->self, DecorationLocation) <
|
||||
get_decoration(b->self, DecorationLocation);
|
||||
}
|
||||
else if (has_location_a && !has_location_b)
|
||||
return true;
|
||||
else if (!has_location_a && has_location_b)
|
||||
return false;
|
||||
|
||||
const auto &name1 = to_name(a->self);
|
||||
const auto &name2 = to_name(b->self);
|
||||
|
||||
if (name1.empty() && name2.empty())
|
||||
return a->self < b->self;
|
||||
else if (name1.empty())
|
||||
return true;
|
||||
else if (name2.empty())
|
||||
return false;
|
||||
|
||||
return name1.compare(name2) < 0;
|
||||
};
|
||||
|
||||
if (!input_variables.empty() || active_input_builtins)
|
||||
{
|
||||
require_input = true;
|
||||
statement("struct SPIRV_Cross_Input");
|
||||
|
||||
begin_scope();
|
||||
// FIXME: Use locations properly if they exist.
|
||||
sort(input_variables.begin(), input_variables.end(), VariableComparator(*this));
|
||||
sort(input_variables.begin(), input_variables.end(), variable_compare);
|
||||
emit_builtin_inputs_in_struct();
|
||||
for (auto var : input_variables)
|
||||
emit_interface_block_in_struct(*var, binding_number);
|
||||
emit_interface_block_in_struct(*var, active_inputs);
|
||||
end_scope_decl();
|
||||
statement("");
|
||||
}
|
||||
|
@ -469,10 +506,10 @@ void CompilerHLSL::emit_resources()
|
|||
|
||||
begin_scope();
|
||||
// FIXME: Use locations properly if they exist.
|
||||
sort(output_variables.begin(), output_variables.end(), VariableComparator(*this));
|
||||
sort(output_variables.begin(), output_variables.end(), variable_compare);
|
||||
emit_builtin_outputs_in_struct();
|
||||
for (auto var : output_variables)
|
||||
emit_interface_block_in_struct(*var, binding_number);
|
||||
emit_interface_block_in_struct(*var, active_outputs);
|
||||
end_scope_decl();
|
||||
statement("");
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ private:
|
|||
void emit_header() override;
|
||||
void emit_resources();
|
||||
void emit_interface_block_globally(const SPIRVariable &type);
|
||||
void emit_interface_block_in_struct(const SPIRVariable &type, uint32_t &binding_number);
|
||||
void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
|
||||
void emit_builtin_inputs_in_struct();
|
||||
void emit_builtin_outputs_in_struct();
|
||||
void emit_texture_op(const Instruction &i) override;
|
||||
|
@ -76,6 +76,8 @@ private:
|
|||
void emit_builtin_variables();
|
||||
bool require_output = false;
|
||||
bool require_input = false;
|
||||
|
||||
uint32_t type_to_consumed_locations(const SPIRType &type) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1794,7 +1794,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
|||
|
||||
// If we're currently in the entry point function, and the object
|
||||
// has a qualified name, use it, otherwise use the standard name.
|
||||
string CompilerMSL::to_name(uint32_t id, bool allow_alias)
|
||||
string CompilerMSL::to_name(uint32_t id, bool allow_alias) const
|
||||
{
|
||||
if (current_function && (current_function->self == entry_point))
|
||||
{
|
||||
|
|
|
@ -136,7 +136,7 @@ protected:
|
|||
std::string constant_expression(const SPIRConstant &c) override;
|
||||
size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const override;
|
||||
std::string to_func_call_arg(uint32_t id) override;
|
||||
std::string to_name(uint32_t id, bool allow_alias = true) override;
|
||||
std::string to_name(uint32_t id, bool allow_alias = true) const override;
|
||||
std::string to_function_name(uint32_t img, const SPIRType &imgtype, bool is_fetch, bool is_gather, bool is_proj,
|
||||
bool has_array_offsets, bool has_offset, bool has_grad, bool has_lod,
|
||||
bool has_dref) override;
|
||||
|
|
Загрузка…
Ссылка в новой задаче