summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2018-10-10 11:51:29 -0400
committerGravatar GitHub2018-10-10 11:51:29 -0400
commitee1b20474963f639015497bea7fbb0d9e6ff9f7f (patch)
tree1446a0f404450336162aecb27d8b7965afba4f58
parentMerge pull request #1469 from lioncash/ptr (diff)
parentgl_shader_decompiler: Move position varying location from 15 to 0 and apply a... (diff)
downloadyuzu-ee1b20474963f639015497bea7fbb0d9e6ff9f7f.tar.gz
yuzu-ee1b20474963f639015497bea7fbb0d9e6ff9f7f.tar.xz
yuzu-ee1b20474963f639015497bea7fbb0d9e6ff9f7f.zip
Merge pull request #1425 from ReinUsesLisp/geometry-shaders
gl_shader_decompiler: Implement geometry shaders
Diffstat (limited to '')
-rw-r--r--src/video_core/engines/shader_bytecode.h112
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp40
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp34
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h46
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp296
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp84
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h7
-rw-r--r--src/video_core/utils.h24
11 files changed, 543 insertions, 120 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index b1f137b9c..550ab1148 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -314,6 +314,15 @@ enum class TextureMiscMode : u64 {
314 PTP, 314 PTP,
315}; 315};
316 316
317enum class IsberdMode : u64 {
318 None = 0,
319 Patch = 1,
320 Prim = 2,
321 Attr = 3,
322};
323
324enum class IsberdShift : u64 { None = 0, U16 = 1, B32 = 2 };
325
317enum class IpaInterpMode : u64 { 326enum class IpaInterpMode : u64 {
318 Linear = 0, 327 Linear = 0,
319 Perspective = 1, 328 Perspective = 1,
@@ -340,6 +349,87 @@ struct IpaMode {
340 } 349 }
341}; 350};
342 351
352enum class SystemVariable : u64 {
353 LaneId = 0x00,
354 VirtCfg = 0x02,
355 VirtId = 0x03,
356 Pm0 = 0x04,
357 Pm1 = 0x05,
358 Pm2 = 0x06,
359 Pm3 = 0x07,
360 Pm4 = 0x08,
361 Pm5 = 0x09,
362 Pm6 = 0x0a,
363 Pm7 = 0x0b,
364 OrderingTicket = 0x0f,
365 PrimType = 0x10,
366 InvocationId = 0x11,
367 Ydirection = 0x12,
368 ThreadKill = 0x13,
369 ShaderType = 0x14,
370 DirectBeWriteAddressLow = 0x15,
371 DirectBeWriteAddressHigh = 0x16,
372 DirectBeWriteEnabled = 0x17,
373 MachineId0 = 0x18,
374 MachineId1 = 0x19,
375 MachineId2 = 0x1a,
376 MachineId3 = 0x1b,
377 Affinity = 0x1c,
378 InvocationInfo = 0x1d,
379 WscaleFactorXY = 0x1e,
380 WscaleFactorZ = 0x1f,
381 Tid = 0x20,
382 TidX = 0x21,
383 TidY = 0x22,
384 TidZ = 0x23,
385 CtaParam = 0x24,
386 CtaIdX = 0x25,
387 CtaIdY = 0x26,
388 CtaIdZ = 0x27,
389 NtId = 0x28,
390 CirQueueIncrMinusOne = 0x29,
391 Nlatc = 0x2a,
392 SmSpaVersion = 0x2c,
393 MultiPassShaderInfo = 0x2d,
394 LwinHi = 0x2e,
395 SwinHi = 0x2f,
396 SwinLo = 0x30,
397 SwinSz = 0x31,
398 SmemSz = 0x32,
399 SmemBanks = 0x33,
400 LwinLo = 0x34,
401 LwinSz = 0x35,
402 LmemLosz = 0x36,
403 LmemHioff = 0x37,
404 EqMask = 0x38,
405 LtMask = 0x39,
406 LeMask = 0x3a,
407 GtMask = 0x3b,
408 GeMask = 0x3c,
409 RegAlloc = 0x3d,
410 CtxAddr = 0x3e, // .fmask = F_SM50
411 BarrierAlloc = 0x3e, // .fmask = F_SM60
412 GlobalErrorStatus = 0x40,
413 WarpErrorStatus = 0x42,
414 WarpErrorStatusClear = 0x43,
415 PmHi0 = 0x48,
416 PmHi1 = 0x49,
417 PmHi2 = 0x4a,
418 PmHi3 = 0x4b,
419 PmHi4 = 0x4c,
420 PmHi5 = 0x4d,
421 PmHi6 = 0x4e,
422 PmHi7 = 0x4f,
423 ClockLo = 0x50,
424 ClockHi = 0x51,
425 GlobalTimerLo = 0x52,
426 GlobalTimerHi = 0x53,
427 HwTaskId = 0x60,
428 CircularQueueEntryIndex = 0x61,
429 CircularQueueEntryAddressLow = 0x62,
430 CircularQueueEntryAddressHigh = 0x63,
431};
432
343union Instruction { 433union Instruction {
344 Instruction& operator=(const Instruction& instr) { 434 Instruction& operator=(const Instruction& instr) {
345 value = instr.value; 435 value = instr.value;
@@ -915,6 +1005,18 @@ union Instruction {
915 } bra; 1005 } bra;
916 1006
917 union { 1007 union {
1008 BitField<39, 1, u64> emit; // EmitVertex
1009 BitField<40, 1, u64> cut; // EndPrimitive
1010 } out;
1011
1012 union {
1013 BitField<31, 1, u64> skew;
1014 BitField<32, 1, u64> o;
1015 BitField<33, 2, IsberdMode> mode;
1016 BitField<47, 2, IsberdShift> shift;
1017 } isberd;
1018
1019 union {
918 BitField<20, 16, u64> imm20_16; 1020 BitField<20, 16, u64> imm20_16;
919 BitField<36, 1, u64> product_shift_left; 1021 BitField<36, 1, u64> product_shift_left;
920 BitField<37, 1, u64> merge_37; 1022 BitField<37, 1, u64> merge_37;
@@ -936,6 +1038,10 @@ union Instruction {
936 BitField<36, 5, u64> index; 1038 BitField<36, 5, u64> index;
937 } cbuf36; 1039 } cbuf36;
938 1040
1041 // Unsure about the size of this one.
1042 // It's always used with a gpr0, so any size should be fine.
1043 BitField<20, 8, SystemVariable> sys20;
1044
939 BitField<47, 1, u64> generates_cc; 1045 BitField<47, 1, u64> generates_cc;
940 BitField<61, 1, u64> is_b_imm; 1046 BitField<61, 1, u64> is_b_imm;
941 BitField<60, 1, u64> is_b_gpr; 1047 BitField<60, 1, u64> is_b_gpr;
@@ -975,6 +1081,8 @@ public:
975 TMML, // Texture Mip Map Level 1081 TMML, // Texture Mip Map Level
976 EXIT, 1082 EXIT,
977 IPA, 1083 IPA,
1084 OUT_R, // Emit vertex/primitive
1085 ISBERD,
978 FFMA_IMM, // Fused Multiply and Add 1086 FFMA_IMM, // Fused Multiply and Add
979 FFMA_CR, 1087 FFMA_CR,
980 FFMA_RC, 1088 FFMA_RC,
@@ -1034,6 +1142,7 @@ public:
1034 MOV_C, 1142 MOV_C,
1035 MOV_R, 1143 MOV_R,
1036 MOV_IMM, 1144 MOV_IMM,
1145 MOV_SYS,
1037 MOV32_IMM, 1146 MOV32_IMM,
1038 SHL_C, 1147 SHL_C,
1039 SHL_R, 1148 SHL_R,
@@ -1209,6 +1318,8 @@ private:
1209 INST("1101111101011---", Id::TMML, Type::Memory, "TMML"), 1318 INST("1101111101011---", Id::TMML, Type::Memory, "TMML"),
1210 INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"), 1319 INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"),
1211 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), 1320 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
1321 INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
1322 INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"),
1212 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"), 1323 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
1213 INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"), 1324 INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"),
1214 INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"), 1325 INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"),
@@ -1255,6 +1366,7 @@ private:
1255 INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"), 1366 INST("0100110010011---", Id::MOV_C, Type::Arithmetic, "MOV_C"),
1256 INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), 1367 INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"),
1257 INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), 1368 INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"),
1369 INST("1111000011001---", Id::MOV_SYS, Type::Trivial, "MOV_SYS"),
1258 INST("000000010000----", Id::MOV32_IMM, Type::ArithmeticImmediate, "MOV32_IMM"), 1370 INST("000000010000----", Id::MOV32_IMM, Type::ArithmeticImmediate, "MOV32_IMM"),
1259 INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), 1371 INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"),
1260 INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), 1372 INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"),
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 209bdf181..b7215448c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -255,7 +255,7 @@ DrawParameters RasterizerOpenGL::SetupDraw() {
255 return params; 255 return params;
256} 256}
257 257
258void RasterizerOpenGL::SetupShaders() { 258void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
259 MICROPROFILE_SCOPE(OpenGL_Shader); 259 MICROPROFILE_SCOPE(OpenGL_Shader);
260 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); 260 const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
261 261
@@ -270,6 +270,11 @@ void RasterizerOpenGL::SetupShaders() {
270 270
271 // Skip stages that are not enabled 271 // Skip stages that are not enabled
272 if (!gpu.regs.IsShaderConfigEnabled(index)) { 272 if (!gpu.regs.IsShaderConfigEnabled(index)) {
273 switch (program) {
274 case Maxwell::ShaderProgram::Geometry:
275 shader_program_manager->UseTrivialGeometryShader();
276 break;
277 }
273 continue; 278 continue;
274 } 279 }
275 280
@@ -288,11 +293,18 @@ void RasterizerOpenGL::SetupShaders() {
288 switch (program) { 293 switch (program) {
289 case Maxwell::ShaderProgram::VertexA: 294 case Maxwell::ShaderProgram::VertexA:
290 case Maxwell::ShaderProgram::VertexB: { 295 case Maxwell::ShaderProgram::VertexB: {
291 shader_program_manager->UseProgrammableVertexShader(shader->GetProgramHandle()); 296 shader_program_manager->UseProgrammableVertexShader(
297 shader->GetProgramHandle(primitive_mode));
298 break;
299 }
300 case Maxwell::ShaderProgram::Geometry: {
301 shader_program_manager->UseProgrammableGeometryShader(
302 shader->GetProgramHandle(primitive_mode));
292 break; 303 break;
293 } 304 }
294 case Maxwell::ShaderProgram::Fragment: { 305 case Maxwell::ShaderProgram::Fragment: {
295 shader_program_manager->UseProgrammableFragmentShader(shader->GetProgramHandle()); 306 shader_program_manager->UseProgrammableFragmentShader(
307 shader->GetProgramHandle(primitive_mode));
296 break; 308 break;
297 } 309 }
298 default: 310 default:
@@ -302,12 +314,13 @@ void RasterizerOpenGL::SetupShaders() {
302 } 314 }
303 315
304 // Configure the const buffers for this shader stage. 316 // Configure the const buffers for this shader stage.
305 current_constbuffer_bindpoint = SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), 317 current_constbuffer_bindpoint =
306 shader, current_constbuffer_bindpoint); 318 SetupConstBuffers(static_cast<Maxwell::ShaderStage>(stage), shader, primitive_mode,
319 current_constbuffer_bindpoint);
307 320
308 // Configure the textures for this shader stage. 321 // Configure the textures for this shader stage.
309 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader, 322 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
310 current_texture_bindpoint); 323 primitive_mode, current_texture_bindpoint);
311 324
312 // When VertexA is enabled, we have dual vertex shaders 325 // When VertexA is enabled, we have dual vertex shaders
313 if (program == Maxwell::ShaderProgram::VertexA) { 326 if (program == Maxwell::ShaderProgram::VertexA) {
@@ -317,8 +330,6 @@ void RasterizerOpenGL::SetupShaders() {
317 } 330 }
318 331
319 state.Apply(); 332 state.Apply();
320
321 shader_program_manager->UseTrivialGeometryShader();
322} 333}
323 334
324std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 335std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
@@ -580,7 +591,7 @@ void RasterizerOpenGL::DrawArrays() {
580 591
581 SetupVertexArrays(); 592 SetupVertexArrays();
582 DrawParameters params = SetupDraw(); 593 DrawParameters params = SetupDraw();
583 SetupShaders(); 594 SetupShaders(params.primitive_mode);
584 595
585 buffer_cache.Unmap(); 596 buffer_cache.Unmap();
586 597
@@ -719,7 +730,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr
719} 730}
720 731
721u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, 732u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader,
722 u32 current_bindpoint) { 733 GLenum primitive_mode, u32 current_bindpoint) {
723 MICROPROFILE_SCOPE(OpenGL_UBO); 734 MICROPROFILE_SCOPE(OpenGL_UBO);
724 const auto& gpu = Core::System::GetInstance().GPU(); 735 const auto& gpu = Core::System::GetInstance().GPU();
725 const auto& maxwell3d = gpu.Maxwell3D(); 736 const auto& maxwell3d = gpu.Maxwell3D();
@@ -771,7 +782,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
771 buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment)); 782 buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
772 783
773 // Now configure the bindpoint of the buffer inside the shader 784 // Now configure the bindpoint of the buffer inside the shader
774 glUniformBlockBinding(shader->GetProgramHandle(), 785 glUniformBlockBinding(shader->GetProgramHandle(primitive_mode),
775 shader->GetProgramResourceIndex(used_buffer), 786 shader->GetProgramResourceIndex(used_buffer),
776 current_bindpoint + bindpoint); 787 current_bindpoint + bindpoint);
777 788
@@ -787,7 +798,8 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
787 return current_bindpoint + static_cast<u32>(entries.size()); 798 return current_bindpoint + static_cast<u32>(entries.size());
788} 799}
789 800
790u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, u32 current_unit) { 801u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
802 GLenum primitive_mode, u32 current_unit) {
791 MICROPROFILE_SCOPE(OpenGL_Texture); 803 MICROPROFILE_SCOPE(OpenGL_Texture);
792 const auto& gpu = Core::System::GetInstance().GPU(); 804 const auto& gpu = Core::System::GetInstance().GPU();
793 const auto& maxwell3d = gpu.Maxwell3D(); 805 const auto& maxwell3d = gpu.Maxwell3D();
@@ -802,8 +814,8 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
802 814
803 // Bind the uniform to the sampler. 815 // Bind the uniform to the sampler.
804 816
805 glProgramUniform1i(shader->GetProgramHandle(), shader->GetUniformLocation(entry), 817 glProgramUniform1i(shader->GetProgramHandle(primitive_mode),
806 current_bindpoint); 818 shader->GetUniformLocation(entry), current_bindpoint);
807 819
808 const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset()); 820 const auto texture = maxwell3d.GetStageTexture(entry.GetStage(), entry.GetOffset());
809 821
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 0dab2018b..8de831468 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -120,7 +120,7 @@ private:
120 * @returns The next available bindpoint for use in the next shader stage. 120 * @returns The next available bindpoint for use in the next shader stage.
121 */ 121 */
122 u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, 122 u32 SetupConstBuffers(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
123 u32 current_bindpoint); 123 GLenum primitive_mode, u32 current_bindpoint);
124 124
125 /* 125 /*
126 * Configures the current textures to use for the draw command. 126 * Configures the current textures to use for the draw command.
@@ -130,7 +130,7 @@ private:
130 * @returns The next available bindpoint for use in the next shader stage. 130 * @returns The next available bindpoint for use in the next shader stage.
131 */ 131 */
132 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader, 132 u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
133 u32 current_unit); 133 GLenum primitive_mode, u32 current_unit);
134 134
135 /// Syncs the viewport to match the guest state 135 /// Syncs the viewport to match the guest state
136 void SyncViewport(); 136 void SyncViewport();
@@ -207,7 +207,7 @@ private:
207 207
208 DrawParameters SetupDraw(); 208 DrawParameters SetupDraw();
209 209
210 void SetupShaders(); 210 void SetupShaders(GLenum primitive_mode);
211 211
212 enum class AccelDraw { Disabled, Arrays, Indexed }; 212 enum class AccelDraw { Disabled, Arrays, Indexed };
213 AccelDraw accelerate_draw = AccelDraw::Disabled; 213 AccelDraw accelerate_draw = AccelDraw::Disabled;
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 7cd8f91e4..1a03a677f 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -68,6 +68,10 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
68 program_result = GLShader::GenerateVertexShader(setup); 68 program_result = GLShader::GenerateVertexShader(setup);
69 gl_type = GL_VERTEX_SHADER; 69 gl_type = GL_VERTEX_SHADER;
70 break; 70 break;
71 case Maxwell::ShaderProgram::Geometry:
72 program_result = GLShader::GenerateGeometryShader(setup);
73 gl_type = GL_GEOMETRY_SHADER;
74 break;
71 case Maxwell::ShaderProgram::Fragment: 75 case Maxwell::ShaderProgram::Fragment:
72 program_result = GLShader::GenerateFragmentShader(setup); 76 program_result = GLShader::GenerateFragmentShader(setup);
73 gl_type = GL_FRAGMENT_SHADER; 77 gl_type = GL_FRAGMENT_SHADER;
@@ -80,11 +84,16 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type)
80 84
81 entries = program_result.second; 85 entries = program_result.second;
82 86
83 OGLShader shader; 87 if (program_type != Maxwell::ShaderProgram::Geometry) {
84 shader.Create(program_result.first.c_str(), gl_type); 88 OGLShader shader;
85 program.Create(true, shader.handle); 89 shader.Create(program_result.first.c_str(), gl_type);
86 SetShaderUniformBlockBindings(program.handle); 90 program.Create(true, shader.handle);
87 VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr); 91 SetShaderUniformBlockBindings(program.handle);
92 VideoCore::LabelGLObject(GL_PROGRAM, program.handle, addr);
93 } else {
94 // Store shader's code to lazily build it on draw
95 geometry_programs.code = program_result.first;
96 }
88} 97}
89 98
90GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { 99GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) {
@@ -110,6 +119,21 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
110 return search->second; 119 return search->second;
111} 120}
112 121
122GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
123 const std::string& glsl_topology,
124 const std::string& debug_name) {
125 if (target_program.handle != 0) {
126 return target_program.handle;
127 }
128 const std::string source{geometry_programs.code + "layout (" + glsl_topology + ") in;\n"};
129 OGLShader shader;
130 shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
131 target_program.Create(true, shader.handle);
132 SetShaderUniformBlockBindings(target_program.handle);
133 VideoCore::LabelGLObject(GL_PROGRAM, target_program.handle, addr, debug_name);
134 return target_program.handle;
135};
136
113Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { 137Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
114 const VAddr program_addr{GetShaderAddress(program)}; 138 const VAddr program_addr{GetShaderAddress(program)};
115 139
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 9bafe43a9..7bb287f56 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -7,6 +7,7 @@
7#include <map> 7#include <map>
8#include <memory> 8#include <memory>
9 9
10#include "common/assert.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "video_core/rasterizer_cache.h" 12#include "video_core/rasterizer_cache.h"
12#include "video_core/renderer_opengl/gl_resource_manager.h" 13#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -38,8 +39,31 @@ public:
38 } 39 }
39 40
40 /// Gets the GL program handle for the shader 41 /// Gets the GL program handle for the shader
41 GLuint GetProgramHandle() const { 42 GLuint GetProgramHandle(GLenum primitive_mode) {
42 return program.handle; 43 if (program_type != Maxwell::ShaderProgram::Geometry) {
44 return program.handle;
45 }
46 switch (primitive_mode) {
47 case GL_POINTS:
48 return LazyGeometryProgram(geometry_programs.points, "points", "ShaderPoints");
49 case GL_LINES:
50 case GL_LINE_STRIP:
51 return LazyGeometryProgram(geometry_programs.lines, "lines", "ShaderLines");
52 case GL_LINES_ADJACENCY:
53 case GL_LINE_STRIP_ADJACENCY:
54 return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency",
55 "ShaderLinesAdjacency");
56 case GL_TRIANGLES:
57 case GL_TRIANGLE_STRIP:
58 case GL_TRIANGLE_FAN:
59 return LazyGeometryProgram(geometry_programs.triangles, "triangles", "ShaderTriangles");
60 case GL_TRIANGLES_ADJACENCY:
61 case GL_TRIANGLE_STRIP_ADJACENCY:
62 return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency",
63 "ShaderLines");
64 default:
65 UNREACHABLE_MSG("Unknown primitive mode.");
66 }
43 } 67 }
44 68
45 /// Gets the GL program resource location for the specified resource, caching as needed 69 /// Gets the GL program resource location for the specified resource, caching as needed
@@ -49,12 +73,30 @@ public:
49 GLint GetUniformLocation(const GLShader::SamplerEntry& sampler); 73 GLint GetUniformLocation(const GLShader::SamplerEntry& sampler);
50 74
51private: 75private:
76 /// Generates a geometry shader or returns one that already exists.
77 GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
78 const std::string& debug_name);
79
52 VAddr addr; 80 VAddr addr;
53 Maxwell::ShaderProgram program_type; 81 Maxwell::ShaderProgram program_type;
54 GLShader::ShaderSetup setup; 82 GLShader::ShaderSetup setup;
55 GLShader::ShaderEntries entries; 83 GLShader::ShaderEntries entries;
84
85 // Non-geometry program.
56 OGLProgram program; 86 OGLProgram program;
57 87
88 // Geometry programs. These are needed because GLSL needs an input topology but it's not
89 // declared by the hardware. Workaround this issue by generating a different shader per input
90 // topology class.
91 struct {
92 std::string code;
93 OGLProgram points;
94 OGLProgram lines;
95 OGLProgram lines_adjacency;
96 OGLProgram triangles;
97 OGLProgram triangles_adjacency;
98 } geometry_programs;
99
58 std::map<u32, GLuint> resource_cache; 100 std::map<u32, GLuint> resource_cache;
59 std::map<u32, GLint> uniform_cache; 101 std::map<u32, GLint> uniform_cache;
60}; 102};
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 85c668ca1..c82a0dcfa 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -7,6 +7,7 @@
7#include <string> 7#include <string>
8#include <string_view> 8#include <string_view>
9 9
10#include <boost/optional.hpp>
10#include <fmt/format.h> 11#include <fmt/format.h>
11 12
12#include "common/assert.h" 13#include "common/assert.h"
@@ -29,11 +30,32 @@ using Tegra::Shader::SubOp;
29constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; 30constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
30constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header); 31constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header);
31 32
33enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 };
34
35constexpr u32 MAX_GEOMETRY_BUFFERS = 6;
36constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested
37
32class DecompileFail : public std::runtime_error { 38class DecompileFail : public std::runtime_error {
33public: 39public:
34 using std::runtime_error::runtime_error; 40 using std::runtime_error::runtime_error;
35}; 41};
36 42
43/// Translate topology
44static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) {
45 switch (topology) {
46 case Tegra::Shader::OutputTopology::PointList:
47 return "points";
48 case Tegra::Shader::OutputTopology::LineStrip:
49 return "line_strip";
50 case Tegra::Shader::OutputTopology::TriangleStrip:
51 return "triangle_strip";
52 default:
53 LOG_CRITICAL(Render_OpenGL, "Unknown output topology {}", static_cast<u32>(topology));
54 UNREACHABLE();
55 return "points";
56 }
57}
58
37/// Describes the behaviour of code path of a given entry point and a return point. 59/// Describes the behaviour of code path of a given entry point and a return point.
38enum class ExitMethod { 60enum class ExitMethod {
39 Undetermined, ///< Internal value. Only occur when analyzing JMP loop. 61 Undetermined, ///< Internal value. Only occur when analyzing JMP loop.
@@ -253,8 +275,9 @@ enum class InternalFlag : u64 {
253class GLSLRegisterManager { 275class GLSLRegisterManager {
254public: 276public:
255 GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations, 277 GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations,
256 const Maxwell3D::Regs::ShaderStage& stage, const std::string& suffix) 278 const Maxwell3D::Regs::ShaderStage& stage, const std::string& suffix,
257 : shader{shader}, declarations{declarations}, stage{stage}, suffix{suffix} { 279 const Tegra::Shader::Header& header)
280 : shader{shader}, declarations{declarations}, stage{stage}, suffix{suffix}, header{header} {
258 BuildRegisterList(); 281 BuildRegisterList();
259 BuildInputList(); 282 BuildInputList();
260 } 283 }
@@ -358,11 +381,13 @@ public:
358 * @param reg The destination register to use. 381 * @param reg The destination register to use.
359 * @param elem The element to use for the operation. 382 * @param elem The element to use for the operation.
360 * @param attribute The input attribute to use as the source value. 383 * @param attribute The input attribute to use as the source value.
384 * @param vertex The register that decides which vertex to read from (used in GS).
361 */ 385 */
362 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute, 386 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute,
363 const Tegra::Shader::IpaMode& input_mode) { 387 const Tegra::Shader::IpaMode& input_mode,
388 boost::optional<Register> vertex = {}) {
364 const std::string dest = GetRegisterAsFloat(reg); 389 const std::string dest = GetRegisterAsFloat(reg);
365 const std::string src = GetInputAttribute(attribute, input_mode) + GetSwizzle(elem); 390 const std::string src = GetInputAttribute(attribute, input_mode, vertex) + GetSwizzle(elem);
366 shader.AddLine(dest + " = " + src + ';'); 391 shader.AddLine(dest + " = " + src + ';');
367 } 392 }
368 393
@@ -391,16 +416,29 @@ public:
391 * are stored as floats, so this may require conversion. 416 * are stored as floats, so this may require conversion.
392 * @param attribute The destination output attribute. 417 * @param attribute The destination output attribute.
393 * @param elem The element to use for the operation. 418 * @param elem The element to use for the operation.
394 * @param reg The register to use as the source value. 419 * @param val_reg The register to use as the source value.
420 * @param buf_reg The register that tells which buffer to write to (used in geometry shaders).
395 */ 421 */
396 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { 422 void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& val_reg,
423 const Register& buf_reg) {
397 const std::string dest = GetOutputAttribute(attribute); 424 const std::string dest = GetOutputAttribute(attribute);
398 const std::string src = GetRegisterAsFloat(reg); 425 const std::string src = GetRegisterAsFloat(val_reg);
399 426
400 if (!dest.empty()) { 427 if (!dest.empty()) {
401 // Can happen with unknown/unimplemented output attributes, in which case we ignore the 428 // Can happen with unknown/unimplemented output attributes, in which case we ignore the
402 // instruction for now. 429 // instruction for now.
403 shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';'); 430 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
431 // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
432 // shader. These instructions use a dirty register as buffer index. To avoid some
433 // drivers from complaining for the out of boundary writes, guard them.
434 const std::string buf_index{"min(" + GetRegisterAsInteger(buf_reg) + ", " +
435 std::to_string(MAX_GEOMETRY_BUFFERS - 1) + ')'};
436 shader.AddLine("amem[" + buf_index + "][" +
437 std::to_string(static_cast<u32>(attribute)) + ']' +
438 GetSwizzle(elem) + " = " + src + ';');
439 } else {
440 shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';');
441 }
404 } 442 }
405 } 443 }
406 444
@@ -441,41 +479,123 @@ public:
441 } 479 }
442 } 480 }
443 481
444 /// Add declarations for registers 482 /// Add declarations.
445 void GenerateDeclarations(const std::string& suffix) { 483 void GenerateDeclarations(const std::string& suffix) {
484 GenerateRegisters(suffix);
485 GenerateInternalFlags();
486 GenerateInputAttrs();
487 GenerateOutputAttrs();
488 GenerateConstBuffers();
489 GenerateSamplers();
490 GenerateGeometry();
491 }
492
493 /// Returns a list of constant buffer declarations.
494 std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const {
495 std::vector<ConstBufferEntry> result;
496 std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(),
497 std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
498 return result;
499 }
500
501 /// Returns a list of samplers used in the shader.
502 const std::vector<SamplerEntry>& GetSamplers() const {
503 return used_samplers;
504 }
505
506 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
507 /// necessary.
508 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
509 bool is_array, bool is_shadow) {
510 const auto offset = static_cast<std::size_t>(sampler.index.Value());
511
512 // If this sampler has already been used, return the existing mapping.
513 const auto itr =
514 std::find_if(used_samplers.begin(), used_samplers.end(),
515 [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
516
517 if (itr != used_samplers.end()) {
518 ASSERT(itr->GetType() == type && itr->IsArray() == is_array &&
519 itr->IsShadow() == is_shadow);
520 return itr->GetName();
521 }
522
523 // Otherwise create a new mapping for this sampler
524 const std::size_t next_index = used_samplers.size();
525 const SamplerEntry entry{stage, offset, next_index, type, is_array, is_shadow};
526 used_samplers.emplace_back(entry);
527 return entry.GetName();
528 }
529
530private:
531 /// Generates declarations for registers.
532 void GenerateRegisters(const std::string& suffix) {
446 for (const auto& reg : regs) { 533 for (const auto& reg : regs) {
447 declarations.AddLine(GLSLRegister::GetTypeString() + ' ' + reg.GetPrefixString() + 534 declarations.AddLine(GLSLRegister::GetTypeString() + ' ' + reg.GetPrefixString() +
448 std::to_string(reg.GetIndex()) + '_' + suffix + " = 0;"); 535 std::to_string(reg.GetIndex()) + '_' + suffix + " = 0;");
449 } 536 }
450 declarations.AddNewLine(); 537 declarations.AddNewLine();
538 }
451 539
540 /// Generates declarations for internal flags.
541 void GenerateInternalFlags() {
452 for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { 542 for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) {
453 const InternalFlag code = static_cast<InternalFlag>(ii); 543 const InternalFlag code = static_cast<InternalFlag>(ii);
454 declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); 544 declarations.AddLine("bool " + GetInternalFlag(code) + " = false;");
455 } 545 }
456 declarations.AddNewLine(); 546 declarations.AddNewLine();
547 }
548
549 /// Generates declarations for input attributes.
550 void GenerateInputAttrs() {
551 if (stage != Maxwell3D::Regs::ShaderStage::Vertex) {
552 const std::string attr =
553 stage == Maxwell3D::Regs::ShaderStage::Geometry ? "gs_position[]" : "position";
554 declarations.AddLine("layout (location = " + std::to_string(POSITION_VARYING_LOCATION) +
555 ") in vec4 " + attr + ';');
556 }
457 557
458 for (const auto element : declr_input_attribute) { 558 for (const auto element : declr_input_attribute) {
459 // TODO(bunnei): Use proper number of elements for these 559 // TODO(bunnei): Use proper number of elements for these
460 u32 idx = 560 u32 idx =
461 static_cast<u32>(element.first) - static_cast<u32>(Attribute::Index::Attribute_0); 561 static_cast<u32>(element.first) - static_cast<u32>(Attribute::Index::Attribute_0);
462 declarations.AddLine("layout(location = " + std::to_string(idx) + ")" + 562 if (stage != Maxwell3D::Regs::ShaderStage::Vertex) {
463 GetInputFlags(element.first) + "in vec4 " + 563 // If inputs are varyings, add an offset
464 GetInputAttribute(element.first, element.second) + ';'); 564 idx += GENERIC_VARYING_START_LOCATION;
565 }
566
567 std::string attr{GetInputAttribute(element.first, element.second)};
568 if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
569 attr = "gs_" + attr + "[]";
570 }
571 declarations.AddLine("layout (location = " + std::to_string(idx) + ") " +
572 GetInputFlags(element.first) + "in vec4 " + attr + ';');
465 } 573 }
574
466 declarations.AddNewLine(); 575 declarations.AddNewLine();
576 }
467 577
578 /// Generates declarations for output attributes.
579 void GenerateOutputAttrs() {
580 if (stage != Maxwell3D::Regs::ShaderStage::Fragment) {
581 declarations.AddLine("layout (location = " + std::to_string(POSITION_VARYING_LOCATION) +
582 ") out vec4 position;");
583 }
468 for (const auto& index : declr_output_attribute) { 584 for (const auto& index : declr_output_attribute) {
469 // TODO(bunnei): Use proper number of elements for these 585 // TODO(bunnei): Use proper number of elements for these
470 declarations.AddLine("layout(location = " + 586 const u32 idx = static_cast<u32>(index) -
471 std::to_string(static_cast<u32>(index) - 587 static_cast<u32>(Attribute::Index::Attribute_0) +
472 static_cast<u32>(Attribute::Index::Attribute_0)) + 588 GENERIC_VARYING_START_LOCATION;
473 ") out vec4 " + GetOutputAttribute(index) + ';'); 589 declarations.AddLine("layout (location = " + std::to_string(idx) + ") out vec4 " +
590 GetOutputAttribute(index) + ';');
474 } 591 }
475 declarations.AddNewLine(); 592 declarations.AddNewLine();
593 }
476 594
595 /// Generates declarations for constant buffers.
596 void GenerateConstBuffers() {
477 for (const auto& entry : GetConstBuffersDeclarations()) { 597 for (const auto& entry : GetConstBuffersDeclarations()) {
478 declarations.AddLine("layout(std140) uniform " + entry.GetName()); 598 declarations.AddLine("layout (std140) uniform " + entry.GetName());
479 declarations.AddLine('{'); 599 declarations.AddLine('{');
480 declarations.AddLine(" vec4 c" + std::to_string(entry.GetIndex()) + 600 declarations.AddLine(" vec4 c" + std::to_string(entry.GetIndex()) +
481 "[MAX_CONSTBUFFER_ELEMENTS];"); 601 "[MAX_CONSTBUFFER_ELEMENTS];");
@@ -483,7 +603,10 @@ public:
483 declarations.AddNewLine(); 603 declarations.AddNewLine();
484 } 604 }
485 declarations.AddNewLine(); 605 declarations.AddNewLine();
606 }
486 607
608 /// Generates declarations for samplers.
609 void GenerateSamplers() {
487 const auto& samplers = GetSamplers(); 610 const auto& samplers = GetSamplers();
488 for (const auto& sampler : samplers) { 611 for (const auto& sampler : samplers) {
489 declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() + 612 declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() +
@@ -492,44 +615,42 @@ public:
492 declarations.AddNewLine(); 615 declarations.AddNewLine();
493 } 616 }
494 617
495 /// Returns a list of constant buffer declarations 618 /// Generates declarations used for geometry shaders.
496 std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const { 619 void GenerateGeometry() {
497 std::vector<ConstBufferEntry> result; 620 if (stage != Maxwell3D::Regs::ShaderStage::Geometry)
498 std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(), 621 return;
499 std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
500 return result;
501 }
502
503 /// Returns a list of samplers used in the shader
504 const std::vector<SamplerEntry>& GetSamplers() const {
505 return used_samplers;
506 }
507
508 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
509 /// necessary.
510 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
511 bool is_array, bool is_shadow) {
512 const std::size_t offset = static_cast<std::size_t>(sampler.index.Value());
513 622
514 // If this sampler has already been used, return the existing mapping. 623 declarations.AddLine(
515 const auto itr = 624 "layout (" + GetTopologyName(header.common3.output_topology) +
516 std::find_if(used_samplers.begin(), used_samplers.end(), 625 ", max_vertices = " + std::to_string(header.common4.max_output_vertices) + ") out;");
517 [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); 626 declarations.AddNewLine();
518 627
519 if (itr != used_samplers.end()) { 628 declarations.AddLine("vec4 amem[" + std::to_string(MAX_GEOMETRY_BUFFERS) + "][" +
520 ASSERT(itr->GetType() == type && itr->IsArray() == is_array && 629 std::to_string(MAX_ATTRIBUTES) + "];");
521 itr->IsShadow() == is_shadow); 630 declarations.AddNewLine();
522 return itr->GetName();
523 }
524 631
525 // Otherwise create a new mapping for this sampler 632 constexpr char buffer[] = "amem[output_buffer]";
526 const std::size_t next_index = used_samplers.size(); 633 declarations.AddLine("void emit_vertex(uint output_buffer) {");
527 const SamplerEntry entry{stage, offset, next_index, type, is_array, is_shadow}; 634 ++declarations.scope;
528 used_samplers.emplace_back(entry); 635 for (const auto element : declr_output_attribute) {
529 return entry.GetName(); 636 declarations.AddLine(GetOutputAttribute(element) + " = " + buffer + '[' +
637 std::to_string(static_cast<u32>(element)) + "];");
638 }
639
640 declarations.AddLine("position = " + std::string(buffer) + '[' +
641 std::to_string(static_cast<u32>(Attribute::Index::Position)) + "];");
642
643 // If a geometry shader is attached, it will always flip (it's the last stage before
644 // fragment). For more info about flipping, refer to gl_shader_gen.cpp.
645 declarations.AddLine("position.xy *= viewport_flip.xy;");
646 declarations.AddLine("gl_Position = position;");
647 declarations.AddLine("position.w = 1.0;");
648 declarations.AddLine("EmitVertex();");
649 --declarations.scope;
650 declarations.AddLine('}');
651 declarations.AddNewLine();
530 } 652 }
531 653
532private:
533 /// Generates code representing a temporary (GPR) register. 654 /// Generates code representing a temporary (GPR) register.
534 std::string GetRegister(const Register& reg, unsigned elem) { 655 std::string GetRegister(const Register& reg, unsigned elem) {
535 if (reg == Register::ZeroIndex) { 656 if (reg == Register::ZeroIndex) {
@@ -586,11 +707,19 @@ private:
586 707
587 /// Generates code representing an input attribute register. 708 /// Generates code representing an input attribute register.
588 std::string GetInputAttribute(Attribute::Index attribute, 709 std::string GetInputAttribute(Attribute::Index attribute,
589 const Tegra::Shader::IpaMode& input_mode) { 710 const Tegra::Shader::IpaMode& input_mode,
711 boost::optional<Register> vertex = {}) {
712 auto GeometryPass = [&](const std::string& name) {
713 if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) {
714 return "gs_" + name + '[' + GetRegisterAsInteger(vertex.value(), 0, false) + ']';
715 }
716 return name;
717 };
718
590 switch (attribute) { 719 switch (attribute) {
591 case Attribute::Index::Position: 720 case Attribute::Index::Position:
592 if (stage != Maxwell3D::Regs::ShaderStage::Fragment) { 721 if (stage != Maxwell3D::Regs::ShaderStage::Fragment) {
593 return "position"; 722 return GeometryPass("position");
594 } else { 723 } else {
595 return "vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 1.0)"; 724 return "vec4(gl_FragCoord.x, gl_FragCoord.y, gl_FragCoord.z, 1.0)";
596 } 725 }
@@ -619,7 +748,7 @@ private:
619 UNREACHABLE(); 748 UNREACHABLE();
620 } 749 }
621 } 750 }
622 return "input_attribute_" + std::to_string(index); 751 return GeometryPass("input_attribute_" + std::to_string(index));
623 } 752 }
624 753
625 LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", static_cast<u32>(attribute)); 754 LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", static_cast<u32>(attribute));
@@ -672,7 +801,7 @@ private:
672 return out; 801 return out;
673 } 802 }
674 803
675 /// Generates code representing an output attribute register. 804 /// Generates code representing the declaration name of an output attribute register.
676 std::string GetOutputAttribute(Attribute::Index attribute) { 805 std::string GetOutputAttribute(Attribute::Index attribute) {
677 switch (attribute) { 806 switch (attribute) {
678 case Attribute::Index::Position: 807 case Attribute::Index::Position:
@@ -708,6 +837,7 @@ private:
708 std::vector<SamplerEntry> used_samplers; 837 std::vector<SamplerEntry> used_samplers;
709 const Maxwell3D::Regs::ShaderStage& stage; 838 const Maxwell3D::Regs::ShaderStage& stage;
710 const std::string& suffix; 839 const std::string& suffix;
840 const Tegra::Shader::Header& header;
711}; 841};
712 842
713class GLSLGenerator { 843class GLSLGenerator {
@@ -1103,8 +1233,8 @@ private:
1103 return offset + 1; 1233 return offset + 1;
1104 } 1234 }
1105 1235
1106 shader.AddLine("// " + std::to_string(offset) + ": " + opcode->GetName() + " (" + 1236 shader.AddLine(
1107 std::to_string(instr.value) + ')'); 1237 fmt::format("// {}: {} (0x{:016x})", offset, opcode->GetName(), instr.value));
1108 1238
1109 using Tegra::Shader::Pred; 1239 using Tegra::Shader::Pred;
1110 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute, 1240 ASSERT_MSG(instr.pred.full_pred != Pred::NeverExecute,
@@ -1826,7 +1956,7 @@ private:
1826 const auto LoadNextElement = [&](u32 reg_offset) { 1956 const auto LoadNextElement = [&](u32 reg_offset) {
1827 regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element, 1957 regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element,
1828 static_cast<Attribute::Index>(next_index), 1958 static_cast<Attribute::Index>(next_index),
1829 input_mode); 1959 input_mode, instr.gpr39.Value());
1830 1960
1831 // Load the next attribute element into the following register. If the element 1961 // Load the next attribute element into the following register. If the element
1832 // to load goes beyond the vec4 size, load the first element of the next 1962 // to load goes beyond the vec4 size, load the first element of the next
@@ -1890,8 +2020,8 @@ private:
1890 2020
1891 const auto StoreNextElement = [&](u32 reg_offset) { 2021 const auto StoreNextElement = [&](u32 reg_offset) {
1892 regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index), 2022 regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index),
1893 next_element, 2023 next_element, instr.gpr0.Value() + reg_offset,
1894 instr.gpr0.Value() + reg_offset); 2024 instr.gpr39.Value());
1895 2025
1896 // Load the next attribute element into the following register. If the element 2026 // Load the next attribute element into the following register. If the element
1897 // to load goes beyond the vec4 size, load the first element of the next 2027 // to load goes beyond the vec4 size, load the first element of the next
@@ -2734,6 +2864,52 @@ private:
2734 2864
2735 break; 2865 break;
2736 } 2866 }
2867 case OpCode::Id::OUT_R: {
2868 ASSERT(instr.gpr20.Value() == Register::ZeroIndex);
2869 ASSERT_MSG(stage == Maxwell3D::Regs::ShaderStage::Geometry,
2870 "OUT is expected to be used in a geometry shader.");
2871
2872 if (instr.out.emit) {
2873 // gpr0 is used to store the next address. Hardware returns a pointer but
2874 // we just return the next index with a cyclic cap.
2875 const std::string current{regs.GetRegisterAsInteger(instr.gpr8, 0, false)};
2876 const std::string next = "((" + current + " + 1" + ") % " +
2877 std::to_string(MAX_GEOMETRY_BUFFERS) + ')';
2878 shader.AddLine("emit_vertex(" + current + ");");
2879 regs.SetRegisterToInteger(instr.gpr0, false, 0, next, 1, 1);
2880 }
2881 if (instr.out.cut) {
2882 shader.AddLine("EndPrimitive();");
2883 }
2884
2885 break;
2886 }
2887 case OpCode::Id::MOV_SYS: {
2888 switch (instr.sys20) {
2889 case Tegra::Shader::SystemVariable::InvocationInfo: {
2890 LOG_WARNING(HW_GPU, "MOV_SYS instruction with InvocationInfo is incomplete");
2891 regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1);
2892 break;
2893 }
2894 default: {
2895 LOG_CRITICAL(HW_GPU, "Unhandled system move: {}",
2896 static_cast<u32>(instr.sys20.Value()));
2897 UNREACHABLE();
2898 }
2899 }
2900 break;
2901 }
2902 case OpCode::Id::ISBERD: {
2903 ASSERT(instr.isberd.o == 0);
2904 ASSERT(instr.isberd.skew == 0);
2905 ASSERT(instr.isberd.shift == Tegra::Shader::IsberdShift::None);
2906 ASSERT(instr.isberd.mode == Tegra::Shader::IsberdMode::None);
2907 ASSERT_MSG(stage == Maxwell3D::Regs::ShaderStage::Geometry,
2908 "ISBERD is expected to be used in a geometry shader.");
2909 LOG_WARNING(HW_GPU, "ISBERD instruction is incomplete");
2910 regs.SetRegisterToFloat(instr.gpr0, 0, regs.GetRegisterAsFloat(instr.gpr8), 1, 1);
2911 break;
2912 }
2737 case OpCode::Id::BRA: { 2913 case OpCode::Id::BRA: {
2738 ASSERT_MSG(instr.bra.constant_buffer == 0, 2914 ASSERT_MSG(instr.bra.constant_buffer == 0,
2739 "BRA with constant buffers are not implemented"); 2915 "BRA with constant buffers are not implemented");
@@ -2907,7 +3083,7 @@ private:
2907 3083
2908 ShaderWriter shader; 3084 ShaderWriter shader;
2909 ShaderWriter declarations; 3085 ShaderWriter declarations;
2910 GLSLRegisterManager regs{shader, declarations, stage, suffix}; 3086 GLSLRegisterManager regs{shader, declarations, stage, suffix, header};
2911 3087
2912 // Declarations 3088 // Declarations
2913 std::set<std::string> declr_predicates; 3089 std::set<std::string> declr_predicates;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index b0466c18f..1e5eb32df 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -17,7 +17,18 @@ ProgramResult GenerateVertexShader(const ShaderSetup& setup) {
17 std::string out = "#version 430 core\n"; 17 std::string out = "#version 430 core\n";
18 out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; 18 out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
19 out += Decompiler::GetCommonDeclarations(); 19 out += Decompiler::GetCommonDeclarations();
20 out += "bool exec_vertex();\n"; 20
21 out += R"(
22out gl_PerVertex {
23 vec4 gl_Position;
24};
25
26layout(std140) uniform vs_config {
27 vec4 viewport_flip;
28 uvec4 instance_id;
29 uvec4 flip_stage;
30};
31)";
21 32
22 if (setup.IsDualProgram()) { 33 if (setup.IsDualProgram()) {
23 out += "bool exec_vertex_b();\n"; 34 out += "bool exec_vertex_b();\n";
@@ -28,18 +39,17 @@ ProgramResult GenerateVertexShader(const ShaderSetup& setup) {
28 Maxwell3D::Regs::ShaderStage::Vertex, "vertex") 39 Maxwell3D::Regs::ShaderStage::Vertex, "vertex")
29 .get_value_or({}); 40 .get_value_or({});
30 41
31 out += R"( 42 out += program.first;
32
33out gl_PerVertex {
34 vec4 gl_Position;
35};
36 43
37out vec4 position; 44 if (setup.IsDualProgram()) {
45 ProgramResult program_b =
46 Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET,
47 Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b")
48 .get_value_or({});
49 out += program_b.first;
50 }
38 51
39layout (std140) uniform vs_config { 52 out += R"(
40 vec4 viewport_flip;
41 uvec4 instance_id;
42};
43 53
44void main() { 54void main() {
45 position = vec4(0.0, 0.0, 0.0, 0.0); 55 position = vec4(0.0, 0.0, 0.0, 0.0);
@@ -52,27 +62,52 @@ void main() {
52 62
53 out += R"( 63 out += R"(
54 64
55 // Viewport can be flipped, which is unsupported by glViewport 65 // Check if the flip stage is VertexB
56 position.xy *= viewport_flip.xy; 66 if (flip_stage[0] == 1) {
67 // Viewport can be flipped, which is unsupported by glViewport
68 position.xy *= viewport_flip.xy;
69 }
57 gl_Position = position; 70 gl_Position = position;
58 71
59 // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 72 // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0
60 // For now, this is here to bring order in lieu of proper emulation 73 // For now, this is here to bring order in lieu of proper emulation
61 position.w = 1.0; 74 if (flip_stage[0] == 1) {
75 position.w = 1.0;
76 }
62} 77}
63 78
64)"; 79)";
65 80
66 out += program.first; 81 return {out, program.second};
82}
67 83
68 if (setup.IsDualProgram()) { 84ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
69 ProgramResult program_b = 85 std::string out = "#version 430 core\n";
70 Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET, 86 out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
71 Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b") 87 out += Decompiler::GetCommonDeclarations();
72 .get_value_or({}); 88 out += "bool exec_geometry();\n";
73 out += program_b.first; 89
74 } 90 ProgramResult program =
91 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
92 Maxwell3D::Regs::ShaderStage::Geometry, "geometry")
93 .get_value_or({});
94 out += R"(
95out gl_PerVertex {
96 vec4 gl_Position;
97};
75 98
99layout (std140) uniform gs_config {
100 vec4 viewport_flip;
101 uvec4 instance_id;
102 uvec4 flip_stage;
103};
104
105void main() {
106 exec_geometry();
107}
108
109)";
110 out += program.first;
76 return {out, program.second}; 111 return {out, program.second};
77} 112}
78 113
@@ -87,7 +122,6 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup) {
87 Maxwell3D::Regs::ShaderStage::Fragment, "fragment") 122 Maxwell3D::Regs::ShaderStage::Fragment, "fragment")
88 .get_value_or({}); 123 .get_value_or({});
89 out += R"( 124 out += R"(
90in vec4 position;
91layout(location = 0) out vec4 FragColor0; 125layout(location = 0) out vec4 FragColor0;
92layout(location = 1) out vec4 FragColor1; 126layout(location = 1) out vec4 FragColor1;
93layout(location = 2) out vec4 FragColor2; 127layout(location = 2) out vec4 FragColor2;
@@ -100,6 +134,7 @@ layout(location = 7) out vec4 FragColor7;
100layout (std140) uniform fs_config { 134layout (std140) uniform fs_config {
101 vec4 viewport_flip; 135 vec4 viewport_flip;
102 uvec4 instance_id; 136 uvec4 instance_id;
137 uvec4 flip_stage;
103}; 138};
104 139
105void main() { 140void main() {
@@ -110,5 +145,4 @@ void main() {
110 out += program.first; 145 out += program.first;
111 return {out, program.second}; 146 return {out, program.second};
112} 147}
113 148} // namespace OpenGL::GLShader \ No newline at end of file
114} // namespace OpenGL::GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index e56f39e78..79596087a 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -196,6 +196,12 @@ private:
196ProgramResult GenerateVertexShader(const ShaderSetup& setup); 196ProgramResult GenerateVertexShader(const ShaderSetup& setup);
197 197
198/** 198/**
199 * Generates the GLSL geometry shader program source code for the given GS program
200 * @returns String of the shader source code
201 */
202ProgramResult GenerateGeometryShader(const ShaderSetup& setup);
203
204/**
199 * Generates the GLSL fragment shader program source code for the given FS program 205 * Generates the GLSL fragment shader program source code for the given FS program
200 * @returns String of the shader source code 206 * @returns String of the shader source code
201 */ 207 */
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 022d32a86..010857ec6 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -18,6 +18,14 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
18 18
19 // We only assign the instance to the first component of the vector, the rest is just padding. 19 // We only assign the instance to the first component of the vector, the rest is just padding.
20 instance_id[0] = state.current_instance; 20 instance_id[0] = state.current_instance;
21
22 // Assign in which stage the position has to be flipped
23 // (the last stage before the fragment shader).
24 if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) {
25 flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry);
26 } else {
27 flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB);
28 }
21} 29}
22 30
23} // namespace OpenGL::GLShader 31} // namespace OpenGL::GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 3de15ba9b..b3a191cf2 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -21,8 +21,9 @@ struct MaxwellUniformData {
21 void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); 21 void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage);
22 alignas(16) GLvec4 viewport_flip; 22 alignas(16) GLvec4 viewport_flip;
23 alignas(16) GLuvec4 instance_id; 23 alignas(16) GLuvec4 instance_id;
24 alignas(16) GLuvec4 flip_stage;
24}; 25};
25static_assert(sizeof(MaxwellUniformData) == 32, "MaxwellUniformData structure size is incorrect"); 26static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect");
26static_assert(sizeof(MaxwellUniformData) < 16384, 27static_assert(sizeof(MaxwellUniformData) < 16384,
27 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); 28 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
28 29
@@ -36,6 +37,10 @@ public:
36 vs = program; 37 vs = program;
37 } 38 }
38 39
40 void UseProgrammableGeometryShader(GLuint program) {
41 gs = program;
42 }
43
39 void UseProgrammableFragmentShader(GLuint program) { 44 void UseProgrammableFragmentShader(GLuint program) {
40 fs = program; 45 fs = program;
41 } 46 }
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index 681919ae3..237cc1307 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -169,16 +169,20 @@ static void LabelGLObject(GLenum identifier, GLuint handle, VAddr addr,
169 const std::string nice_addr = fmt::format("0x{:016x}", addr); 169 const std::string nice_addr = fmt::format("0x{:016x}", addr);
170 std::string object_label; 170 std::string object_label;
171 171
172 switch (identifier) { 172 if (extra_info.empty()) {
173 case GL_TEXTURE: 173 switch (identifier) {
174 object_label = extra_info + "@" + nice_addr; 174 case GL_TEXTURE:
175 break; 175 object_label = "Texture@" + nice_addr;
176 case GL_PROGRAM: 176 break;
177 object_label = "ShaderProgram@" + nice_addr; 177 case GL_PROGRAM:
178 break; 178 object_label = "Shader@" + nice_addr;
179 default: 179 break;
180 object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr); 180 default:
181 break; 181 object_label = fmt::format("Object(0x{:x})@{}", identifier, nice_addr);
182 break;
183 }
184 } else {
185 object_label = extra_info + '@' + nice_addr;
182 } 186 }
183 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str())); 187 glObjectLabel(identifier, handle, -1, static_cast<const GLchar*>(object_label.c_str()));
184} 188}