GLSL: Add support for transform_feedback3 geometry streams.

This commit is contained in:
Hans-Kristian Arntzen 2020-09-30 13:01:35 +02:00
parent 7a99d1cb72
commit e0c9aad934
6 changed files with 191 additions and 10 deletions

View File

@ -0,0 +1,26 @@
#version 450
layout(points) in;
layout(max_vertices = 2, points) out;
layout(xfb_buffer = 1, xfb_stride = 20, stream = 1) out gl_PerVertex
{
layout(xfb_offset = 4) vec4 gl_Position;
float gl_PointSize;
};
layout(location = 0, xfb_buffer = 2, xfb_stride = 32, xfb_offset = 16, stream = 1) out vec4 vFoo;
layout(xfb_buffer = 3, xfb_stride = 16, stream = 2) out VertOut
{
layout(location = 1, xfb_offset = 0) vec4 vBar;
} _23;
void main()
{
gl_Position = vec4(1.0);
vFoo = vec4(3.0);
EmitStreamVertex(1);
_23.vBar = vec4(5.0);
EmitStreamVertex(2);
}

View File

@ -0,0 +1,26 @@
#version 450
layout(points) in;
layout(max_vertices = 2, points) out;
layout(xfb_buffer = 1, xfb_stride = 20, stream = 1) out gl_PerVertex
{
layout(xfb_offset = 4) vec4 gl_Position;
float gl_PointSize;
};
layout(location = 0, xfb_buffer = 2, xfb_stride = 32, xfb_offset = 16, stream = 1) out vec4 vFoo;
layout(xfb_buffer = 3, xfb_stride = 16, stream = 2) out VertOut
{
layout(location = 1, xfb_offset = 0) vec4 vBar;
} _23;
void main()
{
gl_Position = vec4(1.0);
vFoo = vec4(3.0);
EmitStreamVertex(1);
_23.vBar = vec4(5.0);
EmitStreamVertex(2);
}

View File

@ -0,0 +1,24 @@
#version 450
layout(max_vertices = 2, points) out;
layout(points) in;
layout(stream = 1, xfb_stride = 32, xfb_offset = 16, xfb_buffer = 2, location = 0) out vec4 vFoo;
layout(stream = 1, xfb_buffer = 1, xfb_stride = 20) out gl_PerVertex
{
layout(xfb_offset = 4) vec4 gl_Position;
float gl_PointSize;
};
layout(stream = 2, xfb_buffer = 3) out VertOut
{
layout(xfb_stride = 16, xfb_offset = 0, location = 1) vec4 vBar;
};
void main()
{
gl_Position = vec4(1.0);
vFoo = vec4(3.0);
EmitStreamVertex(1);
vBar = vec4(5.0);
EmitStreamVertex(2);
}

View File

@ -1634,6 +1634,7 @@ struct Meta
uint32_t offset = 0;
uint32_t xfb_buffer = 0;
uint32_t xfb_stride = 0;
uint32_t stream = 0;
uint32_t array_stride = 0;
uint32_t matrix_stride = 0;
uint32_t input_attachment = 0;

View File

@ -388,6 +388,10 @@ void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
dec.xfb_stride = argument;
break;
case DecorationStream:
dec.stream = argument;
break;
case DecorationArrayStride:
dec.array_stride = argument;
break;
@ -467,6 +471,10 @@ void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decor
dec.xfb_stride = argument;
break;
case DecorationStream:
dec.stream = argument;
break;
case DecorationSpecId:
dec.spec_id = argument;
break;
@ -584,6 +592,8 @@ uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
return dec.xfb_buffer;
case DecorationXfbStride:
return dec.xfb_stride;
case DecorationStream:
return dec.stream;
case DecorationBinding:
return dec.binding;
case DecorationDescriptorSet:
@ -656,6 +666,10 @@ void ParsedIR::unset_decoration(ID id, Decoration decoration)
dec.xfb_stride = 0;
break;
case DecorationStream:
dec.stream = 0;
break;
case DecorationBinding:
dec.binding = 0;
break;
@ -730,6 +744,8 @@ uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration d
return dec.xfb_buffer;
case DecorationXfbStride:
return dec.xfb_stride;
case DecorationStream:
return dec.stream;
case DecorationSpecId:
return dec.spec_id;
case DecorationIndex:
@ -826,6 +842,10 @@ void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration dec
dec.xfb_stride = 0;
break;
case DecorationStream:
dec.stream = 0;
break;
case DecorationSpecId:
dec.spec_id = 0;
break;

View File

@ -1590,7 +1590,8 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
uint32_t member_count = uint32_t(type.member_types.size());
bool have_xfb_buffer_stride = false;
bool have_any_xfb_offset = false;
uint32_t xfb_stride = 0, xfb_buffer = 0;
bool have_geom_stream = false;
uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride))
{
@ -1599,9 +1600,24 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
xfb_stride = get_decoration(var.self, DecorationXfbStride);
}
if (flags.get(DecorationStream))
{
have_geom_stream = true;
geom_stream = get_decoration(var.self, DecorationStream);
}
// Verify that none of the members violate our assumption.
for (uint32_t i = 0; i < member_count; i++)
{
if (has_member_decoration(type.self, i, DecorationStream))
{
uint32_t member_geom_stream = get_member_decoration(type.self, i, DecorationStream);
if (have_geom_stream && member_geom_stream != geom_stream)
SPIRV_CROSS_THROW("IO block member Stream mismatch.");
have_geom_stream = true;
geom_stream = member_geom_stream;
}
// Only members with an Offset decoration participate in XFB.
if (!has_member_decoration(type.self, i, DecorationOffset))
continue;
@ -1632,15 +1648,40 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
attr.push_back(join("xfb_stride = ", xfb_stride));
uses_enhanced_layouts = true;
}
if (have_geom_stream)
{
if (get_execution_model() != ExecutionModelGeometry)
SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
if (options.es)
SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
if (options.version < 400)
require_extension_internal("GL_ARB_transform_feedback3");
attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
}
}
else if (var.storage == StorageClassOutput && flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) &&
flags.get(DecorationOffset))
else if (var.storage == StorageClassOutput)
{
// XFB for standalone variables, we can emit all decorations.
attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer)));
attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride)));
attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset)));
uses_enhanced_layouts = true;
if (flags.get(DecorationXfbBuffer) && flags.get(DecorationXfbStride) &&
flags.get(DecorationOffset))
{
// XFB for standalone variables, we can emit all decorations.
attr.push_back(join("xfb_buffer = ", get_decoration(var.self, DecorationXfbBuffer)));
attr.push_back(join("xfb_stride = ", get_decoration(var.self, DecorationXfbStride)));
attr.push_back(join("xfb_offset = ", get_decoration(var.self, DecorationOffset)));
uses_enhanced_layouts = true;
}
if (flags.get(DecorationStream))
{
if (get_execution_model() != ExecutionModelGeometry)
SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
if (options.es)
SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
if (options.version < 400)
require_extension_internal("GL_ARB_transform_feedback3");
attr.push_back(join("stream = ", get_decoration(var.self, DecorationStream)));
}
}
// Can only declare Component if we can declare location.
@ -2700,8 +2741,9 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo
uint32_t clip_distance_size = 0;
bool have_xfb_buffer_stride = false;
bool have_geom_stream = false;
bool have_any_xfb_offset = false;
uint32_t xfb_stride = 0, xfb_buffer = 0;
uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0;
std::unordered_map<uint32_t, uint32_t> builtin_xfb_offsets;
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
@ -2727,6 +2769,15 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo
have_any_xfb_offset = true;
builtin_xfb_offsets[m.builtin_type] = m.offset;
}
if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
{
uint32_t stream = m.stream;
if (have_geom_stream && geom_stream != stream)
SPIRV_CROSS_THROW("IO block member Stream mismatch.");
have_geom_stream = true;
geom_stream = stream;
}
}
index++;
}
@ -2744,6 +2795,15 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo
xfb_buffer = buffer_index;
xfb_stride = stride;
}
if (storage == StorageClassOutput && has_decoration(var.self, DecorationStream))
{
uint32_t stream = get_decoration(var.self, DecorationStream);
if (have_geom_stream && geom_stream != stream)
SPIRV_CROSS_THROW("IO block member Stream mismatch.");
have_geom_stream = true;
geom_stream = stream;
}
}
else if (var.storage == storage && !block && is_builtin_variable(var))
{
@ -2772,6 +2832,15 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo
xfb_buffer = buffer_index;
xfb_stride = stride;
}
if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationStream))
{
uint32_t stream = get_decoration(var.self, DecorationStream);
if (have_geom_stream && geom_stream != stream)
SPIRV_CROSS_THROW("IO block member Stream mismatch.");
have_geom_stream = true;
geom_stream = stream;
}
}
}
@ -2801,9 +2870,9 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo
if (storage == StorageClassOutput)
{
SmallVector<string> attr;
if (have_xfb_buffer_stride && have_any_xfb_offset)
{
statement("layout(xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride, ") out gl_PerVertex");
if (!options.es)
{
if (options.version < 440 && options.version >= 140)
@ -2815,7 +2884,22 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo
}
else if (options.es)
SPIRV_CROSS_THROW("Need GL_ARB_enhanced_layouts for xfb_stride or xfb_buffer.");
attr.push_back(join("xfb_buffer = ", xfb_buffer, ", xfb_stride = ", xfb_stride));
}
if (have_geom_stream)
{
if (get_execution_model() != ExecutionModelGeometry)
SPIRV_CROSS_THROW("Geometry streams can only be used in geometry shaders.");
if (options.es)
SPIRV_CROSS_THROW("Multiple geometry streams not supported in ESSL.");
if (options.version < 400)
require_extension_internal("GL_ARB_transform_feedback3");
attr.push_back(join("stream = ", geom_stream));
}
if (!attr.empty())
statement("layout(", merge(attr), ") out gl_PerVertex");
else
statement("out gl_PerVertex");
}