diff options
| author | 2018-10-10 11:51:29 -0400 | |
|---|---|---|
| committer | 2018-10-10 11:51:29 -0400 | |
| commit | ee1b20474963f639015497bea7fbb0d9e6ff9f7f (patch) | |
| tree | 1446a0f404450336162aecb27d8b7965afba4f58 | |
| parent | Merge pull request #1469 from lioncash/ptr (diff) | |
| parent | gl_shader_decompiler: Move position varying location from 15 to 0 and apply a... (diff) | |
| download | yuzu-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.h | 112 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 40 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 34 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.h | 46 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 296 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 84 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 6 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.h | 7 | ||||
| -rw-r--r-- | src/video_core/utils.h | 24 |
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 | ||
| 317 | enum class IsberdMode : u64 { | ||
| 318 | None = 0, | ||
| 319 | Patch = 1, | ||
| 320 | Prim = 2, | ||
| 321 | Attr = 3, | ||
| 322 | }; | ||
| 323 | |||
| 324 | enum class IsberdShift : u64 { None = 0, U16 = 1, B32 = 2 }; | ||
| 325 | |||
| 317 | enum class IpaInterpMode : u64 { | 326 | enum 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 | ||
| 352 | enum 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 | |||
| 343 | union Instruction { | 433 | union 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 | ||
| 258 | void RasterizerOpenGL::SetupShaders() { | 258 | void 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 | ||
| 324 | std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { | 335 | std::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 | ||
| 721 | u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader, | 732 | u32 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 | ||
| 790 | u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, u32 current_unit) { | 801 | u32 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 | ||
| 90 | GLuint CachedShader::GetProgramResourceIndex(const GLShader::ConstBufferEntry& buffer) { | 99 | GLuint 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 | ||
| 122 | GLuint 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 | |||
| 113 | Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { | 137 | Shader 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 | ||
| 51 | private: | 75 | private: |
| 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; | |||
| 29 | constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; | 30 | constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH; |
| 30 | constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header); | 31 | constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header); |
| 31 | 32 | ||
| 33 | enum : u32 { POSITION_VARYING_LOCATION = 0, GENERIC_VARYING_START_LOCATION = 1 }; | ||
| 34 | |||
| 35 | constexpr u32 MAX_GEOMETRY_BUFFERS = 6; | ||
| 36 | constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested | ||
| 37 | |||
| 32 | class DecompileFail : public std::runtime_error { | 38 | class DecompileFail : public std::runtime_error { |
| 33 | public: | 39 | public: |
| 34 | using std::runtime_error::runtime_error; | 40 | using std::runtime_error::runtime_error; |
| 35 | }; | 41 | }; |
| 36 | 42 | ||
| 43 | /// Translate topology | ||
| 44 | static 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. |
| 38 | enum class ExitMethod { | 60 | enum 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 { | |||
| 253 | class GLSLRegisterManager { | 275 | class GLSLRegisterManager { |
| 254 | public: | 276 | public: |
| 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 | |||
| 530 | private: | ||
| 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 | ||
| 532 | private: | ||
| 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 | ||
| 713 | class GLSLGenerator { | 843 | class 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"( | ||
| 22 | out gl_PerVertex { | ||
| 23 | vec4 gl_Position; | ||
| 24 | }; | ||
| 25 | |||
| 26 | layout(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 | |||
| 33 | out gl_PerVertex { | ||
| 34 | vec4 gl_Position; | ||
| 35 | }; | ||
| 36 | 43 | ||
| 37 | out 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 | ||
| 39 | layout (std140) uniform vs_config { | 52 | out += R"( |
| 40 | vec4 viewport_flip; | ||
| 41 | uvec4 instance_id; | ||
| 42 | }; | ||
| 43 | 53 | ||
| 44 | void main() { | 54 | void 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()) { | 84 | ProgramResult 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"( | ||
| 95 | out gl_PerVertex { | ||
| 96 | vec4 gl_Position; | ||
| 97 | }; | ||
| 75 | 98 | ||
| 99 | layout (std140) uniform gs_config { | ||
| 100 | vec4 viewport_flip; | ||
| 101 | uvec4 instance_id; | ||
| 102 | uvec4 flip_stage; | ||
| 103 | }; | ||
| 104 | |||
| 105 | void 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"( |
| 90 | in vec4 position; | ||
| 91 | layout(location = 0) out vec4 FragColor0; | 125 | layout(location = 0) out vec4 FragColor0; |
| 92 | layout(location = 1) out vec4 FragColor1; | 126 | layout(location = 1) out vec4 FragColor1; |
| 93 | layout(location = 2) out vec4 FragColor2; | 127 | layout(location = 2) out vec4 FragColor2; |
| @@ -100,6 +134,7 @@ layout(location = 7) out vec4 FragColor7; | |||
| 100 | layout (std140) uniform fs_config { | 134 | layout (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 | ||
| 105 | void main() { | 140 | void 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: | |||
| 196 | ProgramResult GenerateVertexShader(const ShaderSetup& setup); | 196 | ProgramResult 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 | */ | ||
| 202 | ProgramResult 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 | }; |
| 25 | static_assert(sizeof(MaxwellUniformData) == 32, "MaxwellUniformData structure size is incorrect"); | 26 | static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect"); |
| 26 | static_assert(sizeof(MaxwellUniformData) < 16384, | 27 | static_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 | } |