diff --git a/src/shader_recompiler/backend/glsl/emit_context.cpp b/src/shader_recompiler/backend/glsl/emit_context.cpp index 2a5ec7414..923060386 100644 --- a/src/shader_recompiler/backend/glsl/emit_context.cpp +++ b/src/shader_recompiler/backend/glsl/emit_context.cpp @@ -21,6 +21,15 @@ std::string_view InterpDecorator(Interpolation interp) { throw InvalidArgument("Invalid interpolation {}", interp); } +std::string_view ArrayDecorator(Stage stage) { + switch (stage) { + case Stage::Geometry: + return "[1]"; + default: + return ""; + } +} + std::string_view SamplerType(TextureType type, bool is_depth) { if (is_depth) { switch (type) { @@ -64,6 +73,33 @@ std::string_view SamplerType(TextureType type, bool is_depth) { } } +std::string_view InputPrimitive(InputTopology topology) { + switch (topology) { + case InputTopology::Points: + return "points"; + case InputTopology::Lines: + return "lines"; + case InputTopology::LinesAdjacency: + return "lines_adjacency"; + case InputTopology::Triangles: + return "triangles"; + case InputTopology::TrianglesAdjacency: + return "triangles_adjacency"; + } + throw InvalidArgument("Invalid input topology {}", topology); +} + +std::string_view OutputPrimitive(OutputTopology topology) { + switch (topology) { + case OutputTopology::PointList: + return "points"; + case OutputTopology::LineStrip: + return "line_strip"; + case OutputTopology::TriangleStrip: + return "triangle_strip"; + } + throw InvalidArgument("Invalid output topology {}", topology); +} } // namespace EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_, @@ -85,6 +121,9 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile break; case Stage::Geometry: stage_name = "gs"; + header += fmt::format("layout({})in;layout({}, max_vertices={})out;\n", + InputPrimitive(runtime_info.input_topology), + OutputPrimitive(program.output_topology), program.output_vertices); break; case Stage::Fragment: stage_name = "fs"; @@ -99,8 +138,9 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile for (size_t index = 0; index < info.input_generics.size(); ++index) { const auto& generic{info.input_generics[index]}; if (generic.used) { - header += fmt::format("layout(location={}) {} in vec4 in_attr{};", index, - InterpDecorator(generic.interpolation), index); + header += + fmt::format("layout(location={}){} in vec4 in_attr{}{};", index, + InterpDecorator(generic.interpolation), index, ArrayDecorator(stage)); } } for (size_t index = 0; index < info.stores_frag_color.size(); ++index) { @@ -126,8 +166,6 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile void EmitContext::SetupExtensions(std::string&) { // TODO: track this usage header += "#extension GL_ARB_sparse_texture2 : enable\n"; - header += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; - header += "#extension GL_NV_viewport_array2 : enable\n"; header += "#extension GL_EXT_texture_shadow_lod : enable\n"; if (info.uses_int64) { header += "#extension GL_ARB_gpu_shader_int64 : enable\n"; @@ -157,6 +195,10 @@ void EmitContext::SetupExtensions(std::string&) { header += "#extension GL_ARB_gpu_shader_int64 : enable\n"; } } + if (info.stores_viewport_index) { + header += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; + header += "#extension GL_NV_viewport_array2 : enable\n"; + } } void EmitContext::DefineConstantBuffers(Bindings& bindings) { diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp index 19cf4e46b..f467d978c 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp @@ -162,7 +162,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) { break; default: fmt::print("{}", node.type); - throw NotImplementedException("{}", node.type); + throw NotImplementedException("AbstractSyntaxNode::Type {}", node.type); break; } } diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index c66b4b282..28e89a0a6 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp @@ -19,6 +19,15 @@ u32 CbufIndex(u32 offset) { char OffsetSwizzle(u32 offset) { return SWIZZLE[CbufIndex(offset)]; } + +bool IsInputArray(Stage stage) { + return stage == Stage::Geometry || stage == Stage::TessellationControl || + stage == Stage::TessellationEval; +} + +std::string VertexIndex(EmitContext& ctx, std::string_view vertex) { + return IsInputArray(ctx.stage) ? fmt::format("[{}]", vertex) : ""; +} } // namespace void EmitGetCbufU8([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst, @@ -128,7 +137,7 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, const char swizzle{"xyzw"[element]}; if (IR::IsGeneric(attr)) { const u32 index{IR::GenericAttributeIndex(attr)}; - ctx.AddF32("{}=in_attr{}.{};", inst, index, swizzle); + ctx.AddF32("{}=in_attr{}{}.{};", inst, index, VertexIndex(ctx, vertex), swizzle); return; } switch (attr) { @@ -139,9 +148,11 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, switch (ctx.stage) { case Stage::VertexA: case Stage::VertexB: - case Stage::Geometry: ctx.AddF32("{}=gl_Position.{};", inst, swizzle); break; + case Stage::Geometry: + ctx.AddF32("{}=gl_in[{}].gl_Position.{};", inst, vertex, swizzle); + break; case Stage::Fragment: ctx.AddF32("{}=gl_FragCoord.{};", inst, swizzle); break; diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp index e3d0b15ba..9e5715605 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp @@ -103,11 +103,11 @@ void EmitEpilogue(EmitContext& ctx) { } void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) { - NotImplemented(); + ctx.Add("EmitStreamVertex(int({}));", ctx.var_alloc.Consume(stream)); } void EmitEndPrimitive(EmitContext& ctx, const IR::Value& stream) { - NotImplemented(); + ctx.Add("EndStreamPrimitive(int({}));", ctx.var_alloc.Consume(stream)); } void EmitGetRegister(EmitContext& ctx) {