Skip to content

Commit

Permalink
Merge pull request #2391 from KhronosGroup/hlsl-barycentrics
Browse files Browse the repository at this point in the history
HLSL: Implement SV_Barycentrics.
  • Loading branch information
HansKristian-Work authored Oct 14, 2024
2 parents 12ca15d + 0c24391 commit 36e5456
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 4 deletions.
25 changes: 25 additions & 0 deletions reference/opt/shaders/frag/barycentric-khr-io-block.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#version 450
#extension GL_EXT_fragment_shader_barycentric : require

layout(location = 0) out vec2 value;
layout(location = 0) pervertexEXT in vec2 vUV[3];
layout(location = 1) pervertexEXT in vec2 vUV2[3];
layout(location = 2) pervertexEXT in Foo
{
vec2 a;
vec2 b;
} foo[3];


void main()
{
value = ((vUV[0] * gl_BaryCoordEXT.x) + (vUV[1] * gl_BaryCoordEXT.y)) + (vUV[2] * gl_BaryCoordEXT.z);
value += (((vUV2[0] * gl_BaryCoordNoPerspEXT.x) + (vUV2[1] * gl_BaryCoordNoPerspEXT.y)) + (vUV2[2] * gl_BaryCoordNoPerspEXT.z));
value += (foo[0].a * gl_BaryCoordEXT.x);
value += (foo[0].b * gl_BaryCoordEXT.y);
value += (foo[1].a * gl_BaryCoordEXT.z);
value += (foo[1].b * gl_BaryCoordEXT.x);
value += (foo[2].a * gl_BaryCoordEXT.y);
value += (foo[2].b * gl_BaryCoordEXT.z);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
static float3 gl_BaryCoordNoPerspEXT;
static float2 value;
static float2 vUV2[3];

struct SPIRV_Cross_Input
{
nointerpolation float2 vUV2 : TEXCOORD1;
noperspective float3 gl_BaryCoordNoPerspEXT : SV_Barycentrics;
};

struct SPIRV_Cross_Output
{
float2 value : SV_Target0;
};

void frag_main()
{
value = ((vUV2[0] * gl_BaryCoordNoPerspEXT.x) + (vUV2[1] * gl_BaryCoordNoPerspEXT.y)) + (vUV2[2] * gl_BaryCoordNoPerspEXT.z);
}

SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
gl_BaryCoordNoPerspEXT = stage_input.gl_BaryCoordNoPerspEXT;
vUV2[0] = GetAttributeAtVertex(stage_input.vUV2, 0);
vUV2[1] = GetAttributeAtVertex(stage_input.vUV2, 1);
vUV2[2] = GetAttributeAtVertex(stage_input.vUV2, 2);
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.value = value;
return stage_output;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
static float3 gl_BaryCoordEXT;
static float2 value;
static float2 vUV[3];

struct SPIRV_Cross_Input
{
nointerpolation float2 vUV : TEXCOORD0;
float3 gl_BaryCoordEXT : SV_Barycentrics;
};

struct SPIRV_Cross_Output
{
float2 value : SV_Target0;
};

void frag_main()
{
value = ((vUV[0] * gl_BaryCoordEXT.x) + (vUV[1] * gl_BaryCoordEXT.y)) + (vUV[2] * gl_BaryCoordEXT.z);
}

SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
gl_BaryCoordEXT = stage_input.gl_BaryCoordEXT;
vUV[0] = GetAttributeAtVertex(stage_input.vUV, 0);
vUV[1] = GetAttributeAtVertex(stage_input.vUV, 1);
vUV[2] = GetAttributeAtVertex(stage_input.vUV, 2);
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.value = value;
return stage_output;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
struct Foo
{
float2 a;
float2 b;
};

static float3 gl_BaryCoordEXT;
static float3 gl_BaryCoordNoPerspEXT;
static float2 value;
static float2 vUV[3];
static float2 vUV2[3];
static Foo foo[3];

struct SPIRV_Cross_Input
{
nointerpolation float2 vUV : TEXCOORD0;
nointerpolation float2 vUV2 : TEXCOORD1;
nointerpolation float2 Foo_a : TEXCOORD2;
nointerpolation float2 Foo_b : TEXCOORD3;
float3 gl_BaryCoordEXT : SV_Barycentrics0;
noperspective float3 gl_BaryCoordNoPerspEXT : SV_Barycentrics1;
};

struct SPIRV_Cross_Output
{
float2 value : SV_Target0;
};

void frag_main()
{
value = ((vUV[0] * gl_BaryCoordEXT.x) + (vUV[1] * gl_BaryCoordEXT.y)) + (vUV[2] * gl_BaryCoordEXT.z);
value += (((vUV2[0] * gl_BaryCoordNoPerspEXT.x) + (vUV2[1] * gl_BaryCoordNoPerspEXT.y)) + (vUV2[2] * gl_BaryCoordNoPerspEXT.z));
value += (foo[0].a * gl_BaryCoordEXT.x);
value += (foo[0].b * gl_BaryCoordEXT.y);
value += (foo[1].a * gl_BaryCoordEXT.z);
value += (foo[1].b * gl_BaryCoordEXT.x);
value += (foo[2].a * gl_BaryCoordEXT.y);
value += (foo[2].b * gl_BaryCoordEXT.z);
}

SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
gl_BaryCoordEXT = stage_input.gl_BaryCoordEXT;
gl_BaryCoordNoPerspEXT = stage_input.gl_BaryCoordNoPerspEXT;
vUV[0] = GetAttributeAtVertex(stage_input.vUV, 0);
vUV[1] = GetAttributeAtVertex(stage_input.vUV, 1);
vUV[2] = GetAttributeAtVertex(stage_input.vUV, 2);
vUV2[0] = GetAttributeAtVertex(stage_input.vUV2, 0);
vUV2[1] = GetAttributeAtVertex(stage_input.vUV2, 1);
vUV2[2] = GetAttributeAtVertex(stage_input.vUV2, 2);
foo[0].a = GetAttributeAtVertex(stage_input.Foo_a, 0);
foo[1].a = GetAttributeAtVertex(stage_input.Foo_a, 1);
foo[2].a = GetAttributeAtVertex(stage_input.Foo_a, 2);
foo[0].b = GetAttributeAtVertex(stage_input.Foo_b, 0);
foo[1].b = GetAttributeAtVertex(stage_input.Foo_b, 1);
foo[2].b = GetAttributeAtVertex(stage_input.Foo_b, 2);
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.value = value;
return stage_output;
}
25 changes: 25 additions & 0 deletions reference/shaders/frag/barycentric-khr-io-block.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#version 450
#extension GL_EXT_fragment_shader_barycentric : require

layout(location = 0) out vec2 value;
layout(location = 0) pervertexEXT in vec2 vUV[3];
layout(location = 1) pervertexEXT in vec2 vUV2[3];
layout(location = 2) pervertexEXT in Foo
{
vec2 a;
vec2 b;
} foo[3];


void main()
{
value = ((vUV[0] * gl_BaryCoordEXT.x) + (vUV[1] * gl_BaryCoordEXT.y)) + (vUV[2] * gl_BaryCoordEXT.z);
value += (((vUV2[0] * gl_BaryCoordNoPerspEXT.x) + (vUV2[1] * gl_BaryCoordNoPerspEXT.y)) + (vUV2[2] * gl_BaryCoordNoPerspEXT.z));
value += (foo[0].a * gl_BaryCoordEXT.x);
value += (foo[0].b * gl_BaryCoordEXT.y);
value += (foo[1].a * gl_BaryCoordEXT.z);
value += (foo[1].b * gl_BaryCoordEXT.x);
value += (foo[2].a * gl_BaryCoordEXT.y);
value += (foo[2].b * gl_BaryCoordEXT.z);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#version 450
#extension GL_EXT_fragment_shader_barycentric : require

layout(location = 0) out vec2 value;
layout(location = 1) pervertexEXT in vec2 vUV2[3];

void main () {
value = gl_BaryCoordNoPerspEXT.x * vUV2[0] + gl_BaryCoordNoPerspEXT.y * vUV2[1] + gl_BaryCoordNoPerspEXT.z * vUV2[2];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#version 450
#extension GL_EXT_fragment_shader_barycentric : require

layout(location = 0) out vec2 value;
layout(location = 0) pervertexEXT in vec2 vUV[3];

void main () {
value = gl_BaryCoordEXT.x * vUV[0] + gl_BaryCoordEXT.y * vUV[1] + gl_BaryCoordEXT.z * vUV[2];
}
23 changes: 23 additions & 0 deletions shaders-hlsl-no-opt/frag/barycentric-khr.sm61.fxconly.nofxc.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#version 450
#extension GL_EXT_fragment_shader_barycentric : require

layout(location = 0) out vec2 value;
layout(location = 0) pervertexEXT in vec2 vUV[3];
layout(location = 1) pervertexEXT in vec2 vUV2[3];

layout(location = 2) pervertexEXT in Foo
{
vec2 a;
vec2 b;
} foo[3];

void main () {
value = gl_BaryCoordEXT.x * vUV[0] + gl_BaryCoordEXT.y * vUV[1] + gl_BaryCoordEXT.z * vUV[2];
value += gl_BaryCoordNoPerspEXT.x * vUV2[0] + gl_BaryCoordNoPerspEXT.y * vUV2[1] + gl_BaryCoordNoPerspEXT.z * vUV2[2];
value += gl_BaryCoordEXT.x * foo[0].a;
value += gl_BaryCoordEXT.y * foo[0].b;
value += gl_BaryCoordEXT.z * foo[1].a;
value += gl_BaryCoordEXT.x * foo[1].b;
value += gl_BaryCoordEXT.y * foo[2].a;
value += gl_BaryCoordEXT.z * foo[2].b;
}
23 changes: 23 additions & 0 deletions shaders/frag/barycentric-khr-io-block.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#version 450
#extension GL_EXT_fragment_shader_barycentric : require

layout(location = 0) out vec2 value;
layout(location = 0) pervertexEXT in vec2 vUV[3];
layout(location = 1) pervertexEXT in vec2 vUV2[3];

layout(location = 2) pervertexEXT in Foo
{
vec2 a;
vec2 b;
} foo[3];

void main () {
value = gl_BaryCoordEXT.x * vUV[0] + gl_BaryCoordEXT.y * vUV[1] + gl_BaryCoordEXT.z * vUV[2];
value += gl_BaryCoordNoPerspEXT.x * vUV2[0] + gl_BaryCoordNoPerspEXT.y * vUV2[1] + gl_BaryCoordNoPerspEXT.z * vUV2[2];
value += gl_BaryCoordEXT.x * foo[0].a;
value += gl_BaryCoordEXT.y * foo[0].b;
value += gl_BaryCoordEXT.z * foo[1].a;
value += gl_BaryCoordEXT.x * foo[1].b;
value += gl_BaryCoordEXT.y * foo[2].a;
value += gl_BaryCoordEXT.z * foo[2].b;
}
2 changes: 2 additions & 0 deletions spirv_glsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2764,6 +2764,8 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var)
block_qualifier = "patch ";
else if (has_decoration(var.self, DecorationPerPrimitiveEXT))
block_qualifier = "perprimitiveEXT ";
else if (has_decoration(var.self, DecorationPerVertexKHR))
block_qualifier = "pervertexEXT ";
else
block_qualifier = "";

Expand Down
48 changes: 44 additions & 4 deletions spirv_hlsl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,17 @@ void CompilerHLSL::emit_builtin_inputs_in_struct()
semantic = "SV_RenderTargetArrayIndex";
break;

case BuiltInBaryCoordKHR:
case BuiltInBaryCoordNoPerspKHR:
if (hlsl_options.shader_model < 61)
SPIRV_CROSS_THROW("SM 6.1 is required for barycentrics.");
type = builtin == BuiltInBaryCoordNoPerspKHR ? "noperspective float3" : "float3";
if (active_input_builtins.get(BuiltInBaryCoordKHR) && active_input_builtins.get(BuiltInBaryCoordNoPerspKHR))
semantic = builtin == BuiltInBaryCoordKHR ? "SV_Barycentrics0" : "SV_Barycentrics1";
else
semantic = "SV_Barycentrics";
break;

default:
SPIRV_CROSS_THROW("Unsupported builtin in HLSL.");
}
Expand Down Expand Up @@ -958,7 +969,7 @@ string CompilerHLSL::to_interpolation_qualifiers(const Bitset &flags)
string res;
//if (flags & (1ull << DecorationSmooth))
// res += "linear ";
if (flags.get(DecorationFlat))
if (flags.get(DecorationFlat) || flags.get(DecorationPerVertexKHR))
res += "nointerpolation ";
if (flags.get(DecorationNoPerspective))
res += "noperspective ";
Expand Down Expand Up @@ -1014,7 +1025,11 @@ void CompilerHLSL::emit_interface_block_member_in_struct(const SPIRVariable &var
auto mbr_name = join(to_name(type.self), "_", to_member_name(type, member_index));
auto &mbr_type = get<SPIRType>(type.member_types[member_index]);

statement(to_interpolation_qualifiers(get_member_decoration_bitset(type.self, member_index)),
Bitset member_decorations = get_member_decoration_bitset(type.self, member_index);
if (has_decoration(var.self, DecorationPerVertexKHR))
member_decorations.set(DecorationPerVertexKHR);

statement(to_interpolation_qualifiers(member_decorations),
type_to_glsl(mbr_type),
" ", mbr_name, type_to_array_glsl(mbr_type, var.self),
" : ", semantic, ";");
Expand Down Expand Up @@ -1102,7 +1117,7 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord
else
{
auto decl_type = type;
if (execution.model == ExecutionModelMeshEXT)
if (execution.model == ExecutionModelMeshEXT || has_decoration(var.self, DecorationPerVertexKHR))
{
decl_type.array.erase(decl_type.array.begin());
decl_type.array_size_literal.erase(decl_type.array_size_literal.begin());
Expand Down Expand Up @@ -1341,6 +1356,13 @@ void CompilerHLSL::emit_builtin_variables()
type = "uint";
break;

case BuiltInBaryCoordKHR:
case BuiltInBaryCoordNoPerspKHR:
if (hlsl_options.shader_model < 61)
SPIRV_CROSS_THROW("Need SM 6.1 for barycentrics.");
type = "float3";
break;

default:
SPIRV_CROSS_THROW(join("Unsupported builtin in HLSL: ", unsigned(builtin)));
}
Expand Down Expand Up @@ -3298,11 +3320,23 @@ void CompilerHLSL::emit_hlsl_entry_point()
{
auto type_name = to_name(type.self);
auto var_name = to_name(var.self);
bool is_per_vertex = has_decoration(var.self, DecorationPerVertexKHR);
uint32_t array_size = is_per_vertex ? to_array_size_literal(type) : 0;

for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(type.member_types.size()); mbr_idx++)
{
auto mbr_name = to_member_name(type, mbr_idx);
auto flat_name = join(type_name, "_", mbr_name);
statement(var_name, ".", mbr_name, " = stage_input.", flat_name, ";");

if (is_per_vertex)
{
for (uint32_t i = 0; i < array_size; i++)
statement(var_name, "[", i, "].", mbr_name, " = GetAttributeAtVertex(stage_input.", flat_name, ", ", i, ");");
}
else
{
statement(var_name, ".", mbr_name, " = stage_input.", flat_name, ";");
}
}
}
else
Expand All @@ -3315,6 +3349,12 @@ void CompilerHLSL::emit_hlsl_entry_point()
for (uint32_t col = 0; col < mtype.columns; col++)
statement(name, "[", col, "] = stage_input.", name, "_", col, ";");
}
else if (has_decoration(var.self, DecorationPerVertexKHR))
{
uint32_t array_size = to_array_size_literal(type);
for (uint32_t i = 0; i < array_size; i++)
statement(name, "[", i, "]", " = GetAttributeAtVertex(stage_input.", name, ", ", i, ");");
}
else
{
statement(name, " = stage_input.", name, ";");
Expand Down
2 changes: 2 additions & 0 deletions test_shaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,8 @@ def validate_shader_hlsl(shader, force_no_external_validation, paths):
def shader_to_sm(shader):
if '.sm62.' in shader:
return '62'
elif '.sm61.' in shader:
return '61'
elif '.sm60.' in shader:
return '60'
elif '.sm68.' in shader:
Expand Down

0 comments on commit 36e5456

Please sign in to comment.