summaryrefslogtreecommitdiff
path: root/src/video_core
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2018-12-24 02:24:38 -0300
committerGravatar ReinUsesLisp2019-01-15 17:54:53 -0300
commite1fea1e0c594cc7c5a404e7006a4b4b2f29200ae (patch)
tree269b0a3512d9ee97bbe7ef1e0df9ec8697056939 /src/video_core
parentshader_decode: Implement VMAD and VSETP (diff)
downloadyuzu-e1fea1e0c594cc7c5a404e7006a4b4b2f29200ae.tar.gz
yuzu-e1fea1e0c594cc7c5a404e7006a4b4b2f29200ae.tar.xz
yuzu-e1fea1e0c594cc7c5a404e7006a4b4b2f29200ae.zip
video_core: Implement IR based geometry shaders
Diffstat (limited to 'src/video_core')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp14
-rw-r--r--src/video_core/shader/decode/other.cpp25
-rw-r--r--src/video_core/shader/glsl_decompiler.cpp70
-rw-r--r--src/video_core/shader/shader_ir.h3
4 files changed, 102 insertions, 10 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 59f45cde3..743a9c90e 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -80,16 +80,11 @@ ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
80 // Version is intentionally skipped in shader generation, it's added by the lazy compilation. 80 // Version is intentionally skipped in shader generation, it's added by the lazy compilation.
81 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); 81 const std::string id = fmt::format("{:016x}", setup.program.unique_identifier);
82 82
83 std::string out = out += "// Shader Unique Id: GS" + id + '\n'; 83 std::string out = "// Shader Unique Id: GS" + id + '\n';
84 out += "#extension GL_ARB_separate_shader_objects : enable\n"; 84 out += "#extension GL_ARB_separate_shader_objects : enable\n";
85 out += GetCommonDeclarations(); 85 out += GetCommonDeclarations();
86 86
87 ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET); 87 out += R"(out gl_PerVertex {
88 ProgramResult program =
89 Decompile(program_ir, Maxwell3D::Regs::ShaderStage::Geometry, "geometry");
90
91 out += R"(
92out gl_PerVertex {
93 vec4 gl_Position; 88 vec4 gl_Position;
94}; 89};
95 90
@@ -103,9 +98,12 @@ layout (std140) uniform gs_config {
103}; 98};
104)"; 99)";
105 100
101 ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
102 ProgramResult program =
103 Decompile(program_ir, Maxwell3D::Regs::ShaderStage::Geometry, "geometry");
106 out += program.first; 104 out += program.first;
107 105
108 out = R"( 106 out += R"(
109void main() { 107void main() {
110 execute_geometry(); 108 execute_geometry();
111};)"; 109};)";
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp
index 9630ef831..1918762b8 100644
--- a/src/video_core/shader/decode/other.cpp
+++ b/src/video_core/shader/decode/other.cpp
@@ -12,6 +12,7 @@ namespace VideoCommon::Shader {
12using Tegra::Shader::ConditionCode; 12using Tegra::Shader::ConditionCode;
13using Tegra::Shader::Instruction; 13using Tegra::Shader::Instruction;
14using Tegra::Shader::OpCode; 14using Tegra::Shader::OpCode;
15using Tegra::Shader::Register;
15 16
16u32 ShaderIR::DecodeOther(BasicBlock& bb, u32 pc) { 17u32 ShaderIR::DecodeOther(BasicBlock& bb, u32 pc) {
17 const Instruction instr = {program_code[pc]}; 18 const Instruction instr = {program_code[pc]};
@@ -140,6 +141,30 @@ u32 ShaderIR::DecodeOther(BasicBlock& bb, u32 pc) {
140 SetRegister(bb, instr.gpr0, value); 141 SetRegister(bb, instr.gpr0, value);
141 break; 142 break;
142 } 143 }
144 case OpCode::Id::OUT_R: {
145 UNIMPLEMENTED_IF_MSG(instr.gpr20.Value() != Register::ZeroIndex,
146 "Stream buffer is not supported");
147
148 if (instr.out.emit) {
149 // gpr0 is used to store the next address and gpr8 contains the address to emit.
150 // Hardware uses pointers here but we just ignore it
151 bb.push_back(Operation(OperationCode::EmitVertex));
152 SetRegister(bb, instr.gpr0, Immediate(0));
153 }
154 if (instr.out.cut) {
155 bb.push_back(Operation(OperationCode::EndPrimitive));
156 }
157 break;
158 }
159 case OpCode::Id::ISBERD: {
160 UNIMPLEMENTED_IF(instr.isberd.o != 0);
161 UNIMPLEMENTED_IF(instr.isberd.skew != 0);
162 UNIMPLEMENTED_IF(instr.isberd.shift != Tegra::Shader::IsberdShift::None);
163 UNIMPLEMENTED_IF(instr.isberd.mode != Tegra::Shader::IsberdMode::None);
164 LOG_WARNING(HW_GPU, "ISBERD instruction is incomplete");
165 SetRegister(bb, instr.gpr0, GetRegister(instr.gpr8));
166 break;
167 }
143 case OpCode::Id::DEPBAR: { 168 case OpCode::Id::DEPBAR: {
144 LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed"); 169 LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed");
145 break; 170 break;
diff --git a/src/video_core/shader/glsl_decompiler.cpp b/src/video_core/shader/glsl_decompiler.cpp
index 2e9323df7..9b443e61a 100644
--- a/src/video_core/shader/glsl_decompiler.cpp
+++ b/src/video_core/shader/glsl_decompiler.cpp
@@ -89,6 +89,22 @@ static std::string GetSwizzle(u32 elem) {
89 return swizzle; 89 return swizzle;
90} 90}
91 91
92/// Translate topology
93static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) {
94 switch (topology) {
95 case Tegra::Shader::OutputTopology::PointList:
96 return "points";
97 case Tegra::Shader::OutputTopology::LineStrip:
98 return "line_strip";
99 case Tegra::Shader::OutputTopology::TriangleStrip:
100 return "triangle_strip";
101 default:
102 UNIMPLEMENTED_MSG("Unknown output topology: {}", static_cast<u32>(topology));
103 return "points";
104 }
105}
106
107/// Returns true if an object has to be treated as precise
92static bool IsPrecise(Operation operand) { 108static bool IsPrecise(Operation operand) {
93 const auto& meta = operand.GetMeta(); 109 const auto& meta = operand.GetMeta();
94 110
@@ -115,6 +131,7 @@ public:
115 131
116 void Decompile() { 132 void Decompile() {
117 DeclareVertex(); 133 DeclareVertex();
134 DeclareGeometry();
118 DeclareRegisters(); 135 DeclareRegisters();
119 DeclarePredicates(); 136 DeclarePredicates();
120 DeclareLocalMemory(); 137 DeclareLocalMemory();
@@ -212,6 +229,16 @@ private:
212 code.AddNewLine(); 229 code.AddNewLine();
213 } 230 }
214 231
232 void DeclareGeometry() {
233 if (stage != ShaderStage::Geometry)
234 return;
235
236 const auto topology = GetTopologyName(header.common3.output_topology);
237 const auto max_vertices = std::to_string(header.common4.max_output_vertices);
238 code.AddLine("layout (" + topology + ", max_vertices = " + max_vertices + ") out;");
239 code.AddNewLine();
240 }
241
215 void DeclareRegisters() { 242 void DeclareRegisters() {
216 const auto& registers = ir.GetRegisters(); 243 const auto& registers = ir.GetRegisters();
217 for (const u32 gpr : registers) { 244 for (const u32 gpr : registers) {
@@ -419,9 +446,24 @@ private:
419 const auto attribute = abuf->GetIndex(); 446 const auto attribute = abuf->GetIndex();
420 const auto element = abuf->GetElement(); 447 const auto element = abuf->GetElement();
421 448
449 const auto GeometryPass = [&](const std::string& name) {
450 if (stage == ShaderStage::Geometry && abuf->GetBuffer()) {
451 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
452 // set an 0x80000000 index for those and the shader fails to build. Find out why
453 // this happens and what's its intent.
454 return "gs_" + name + "[ftou(" + Visit(abuf->GetBuffer()) +
455 ") % MAX_VERTEX_INPUT]";
456 }
457 return name;
458 };
459
422 switch (attribute) { 460 switch (attribute) {
423 case Attribute::Index::Position: 461 case Attribute::Index::Position:
424 return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element); 462 if (stage != ShaderStage::Fragment) {
463 return GeometryPass("position") + GetSwizzle(element);
464 } else {
465 return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element);
466 }
425 case Attribute::Index::PointCoord: 467 case Attribute::Index::PointCoord:
426 switch (element) { 468 switch (element) {
427 case 0: 469 case 0:
@@ -460,7 +502,7 @@ private:
460 default: 502 default:
461 if (attribute >= Attribute::Index::Attribute_0 && 503 if (attribute >= Attribute::Index::Attribute_0 &&
462 attribute <= Attribute::Index::Attribute_31) { 504 attribute <= Attribute::Index::Attribute_31) {
463 return GetInputAttribute(attribute) + GetSwizzle(abuf->GetElement()); 505 return GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element);
464 } 506 }
465 break; 507 break;
466 } 508 }
@@ -1226,6 +1268,27 @@ private:
1226 return {}; 1268 return {};
1227 } 1269 }
1228 1270
1271 std::string EmitVertex(Operation operation) {
1272 ASSERT_MSG(stage == ShaderStage::Geometry,
1273 "EmitVertex is expected to be used in a geometry shader.");
1274
1275 // If a geometry shader is attached, it will always flip (it's the last stage before
1276 // fragment). For more info about flipping, refer to gl_shader_gen.cpp.
1277 code.AddLine("position.xy *= viewport_flip.xy;");
1278 code.AddLine("gl_Position = position;");
1279 code.AddLine("position.w = 1.0;");
1280 code.AddLine("EmitVertex();");
1281 return {};
1282 }
1283
1284 std::string EndPrimitive(Operation operation) {
1285 ASSERT_MSG(stage == ShaderStage::Geometry,
1286 "EndPrimitive is expected to be used in a geometry shader.");
1287
1288 code.AddLine("EndPrimitive();");
1289 return {};
1290 }
1291
1229 std::string YNegate(Operation operation) { 1292 std::string YNegate(Operation operation) {
1230 // Config pack's third value is Y_NEGATE's state. 1293 // Config pack's third value is Y_NEGATE's state.
1231 return "uintBitsToFloat(config_pack[2])"; 1294 return "uintBitsToFloat(config_pack[2])";
@@ -1361,6 +1424,9 @@ private:
1361 &Exit, 1424 &Exit,
1362 &Kil, 1425 &Kil,
1363 1426
1427 &EmitVertex,
1428 &EndPrimitive,
1429
1364 &YNegate, 1430 &YNegate,
1365 }; 1431 };
1366 1432
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index 0ea2df6bd..5676d32a9 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -172,6 +172,9 @@ enum class OperationCode {
172 Exit, /// () -> void 172 Exit, /// () -> void
173 Kil, /// () -> void 173 Kil, /// () -> void
174 174
175 EmitVertex, /// () -> void
176 EndPrimitive, /// () -> void
177
175 YNegate, /// () -> float 178 YNegate, /// () -> float
176 179
177 Amount, 180 Amount,