diff --git a/.gitignore b/.gitignore index 02dc0915c5..ae718af172 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,7 @@ *.wav /build - +/bin /libs /ipch /rpcs3/Debug @@ -44,6 +44,7 @@ /bin/rpcs3.iobj /bin/FragmentProgram.txt /bin/VertexProgram.txt +/bin/*.hlsl /bin/BreakPoints.dat /bin/textures /bin/*.lib diff --git a/rpcs3.sln b/rpcs3.sln index f685b141d7..00c151cc46 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -183,15 +183,23 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "copy_setup_h", "rpcs3\copy_ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug - DX12|x64 = Debug - DX12|x64 + Debug - LLVM DX12|x64 = Debug - LLVM DX12|x64 Debug - LLVM|x64 = Debug - LLVM|x64 Debug - MemLeak|x64 = Debug - MemLeak|x64 Debug|x64 = Debug|x64 DLL Debug|x64 = DLL Debug|x64 DLL Release|x64 = DLL Release|x64 + Release - DX12|x64 = Release - DX12|x64 + Release - LLVM DX12|x64 = Release - LLVM DX12|x64 Release - LLVM|x64 = Release - LLVM|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - DX12|x64.ActiveCfg = Debug - DX12|x64 + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - DX12|x64.Build.0 = Debug - DX12|x64 + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM DX12|x64.ActiveCfg = Debug - DX12|x64 + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM DX12|x64.Build.0 = Debug - DX12|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - LLVM|x64.Build.0 = Debug|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64 @@ -202,10 +210,18 @@ Global {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Debug|x64.Build.0 = Debug|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.ActiveCfg = Release|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.Build.0 = Release|x64 + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - DX12|x64.ActiveCfg = Release - DX12|x64 + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - DX12|x64.Build.0 = Release - DX12|x64 + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM DX12|x64.ActiveCfg = Release - DX12|x64 + {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM DX12|x64.Build.0 = Release - DX12|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.ActiveCfg = Release|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.Build.0 = Release|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.ActiveCfg = Release|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.Build.0 = Release|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - DX12|x64.Build.0 = Debug|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - LLVM|x64.Build.0 = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -216,10 +232,18 @@ Global {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Debug|x64.Build.0 = DLL Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.ActiveCfg = DLL Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.Build.0 = DLL Release|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - DX12|x64.ActiveCfg = Release|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - DX12|x64.Build.0 = Release|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM DX12|x64.Build.0 = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.ActiveCfg = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.Build.0 = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.ActiveCfg = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.Build.0 = Release|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - DX12|x64.Build.0 = Debug|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - LLVM|x64.Build.0 = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -230,10 +254,18 @@ Global {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Debug|x64.Build.0 = DLL Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.ActiveCfg = DLL Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.Build.0 = DLL Release|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - DX12|x64.ActiveCfg = Release|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - DX12|x64.Build.0 = Release|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM DX12|x64.Build.0 = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.ActiveCfg = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.Build.0 = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release|x64.ActiveCfg = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release|x64.Build.0 = Release|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - DX12|x64.Build.0 = Debug|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - LLVM|x64.Build.0 = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -244,10 +276,18 @@ Global {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Debug|x64.Build.0 = DLL Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.ActiveCfg = DLL Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.Build.0 = DLL Release|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - DX12|x64.ActiveCfg = Release|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - DX12|x64.Build.0 = Release|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM DX12|x64.Build.0 = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.ActiveCfg = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.Build.0 = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.Build.0 = Release|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - DX12|x64.Build.0 = Debug|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - LLVM|x64.Build.0 = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -258,10 +298,18 @@ Global {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Debug|x64.Build.0 = DLL Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.ActiveCfg = DLL Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.Build.0 = DLL Release|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - DX12|x64.ActiveCfg = Release|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - DX12|x64.Build.0 = Release|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM DX12|x64.Build.0 = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.ActiveCfg = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.Build.0 = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.ActiveCfg = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.Build.0 = Release|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - DX12|x64.Build.0 = Debug|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - LLVM|x64.Build.0 = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -272,10 +320,18 @@ Global {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Debug|x64.Build.0 = DLL Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.ActiveCfg = DLL Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.Build.0 = DLL Release|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - DX12|x64.ActiveCfg = Release|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - DX12|x64.Build.0 = Release|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM DX12|x64.Build.0 = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.ActiveCfg = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.Build.0 = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release|x64.ActiveCfg = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release|x64.Build.0 = Release|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - DX12|x64.Build.0 = Debug|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - LLVM|x64.Build.0 = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -286,10 +342,18 @@ Global {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Debug|x64.Build.0 = DLL Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.ActiveCfg = DLL Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.Build.0 = DLL Release|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - DX12|x64.ActiveCfg = Release|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - DX12|x64.Build.0 = Release|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM DX12|x64.Build.0 = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.ActiveCfg = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.Build.0 = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release|x64.ActiveCfg = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release|x64.Build.0 = Release|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - DX12|x64.Build.0 = Debug|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM|x64.Build.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -301,10 +365,18 @@ Global {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Debug|x64.Build.0 = DLL Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.ActiveCfg = DLL Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.Build.0 = DLL Release|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - DX12|x64.ActiveCfg = Release|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - DX12|x64.Build.0 = Release|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM DX12|x64.Build.0 = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.ActiveCfg = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.Build.0 = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release|x64.ActiveCfg = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release|x64.Build.0 = Release|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - DX12|x64.Build.0 = Debug|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - LLVM|x64.Build.0 = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -315,10 +387,18 @@ Global {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Debug|x64.Build.0 = DLL Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.ActiveCfg = DLL Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.Build.0 = DLL Release|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - DX12|x64.ActiveCfg = Release|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - DX12|x64.Build.0 = Release|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM DX12|x64.Build.0 = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.ActiveCfg = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.Build.0 = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release|x64.ActiveCfg = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release|x64.Build.0 = Release|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - DX12|x64.Build.0 = Debug|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - LLVM|x64.Build.0 = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -329,10 +409,18 @@ Global {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Debug|x64.Build.0 = DLL Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.ActiveCfg = DLL Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.Build.0 = DLL Release|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - DX12|x64.ActiveCfg = Release|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - DX12|x64.Build.0 = Release|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM DX12|x64.Build.0 = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.ActiveCfg = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.Build.0 = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release|x64.ActiveCfg = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release|x64.Build.0 = Release|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - DX12|x64.Build.0 = Debug|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - LLVM|x64.Build.0 = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -343,10 +431,18 @@ Global {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Debug|x64.Build.0 = DLL Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.ActiveCfg = DLL Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.Build.0 = DLL Release|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - DX12|x64.ActiveCfg = Release|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - DX12|x64.Build.0 = Release|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM DX12|x64.Build.0 = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.ActiveCfg = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.Build.0 = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release|x64.ActiveCfg = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release|x64.Build.0 = Release|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - DX12|x64.Build.0 = Debug|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - LLVM|x64.Build.0 = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -357,10 +453,18 @@ Global {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Debug|x64.Build.0 = DLL Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.ActiveCfg = DLL Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.Build.0 = DLL Release|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - DX12|x64.ActiveCfg = Release|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - DX12|x64.Build.0 = Release|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM DX12|x64.Build.0 = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.ActiveCfg = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.Build.0 = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release|x64.ActiveCfg = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release|x64.Build.0 = Release|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - DX12|x64.Build.0 = Debug|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - LLVM|x64.Build.0 = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -371,10 +475,18 @@ Global {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Debug|x64.Build.0 = DLL Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.ActiveCfg = DLL Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.Build.0 = DLL Release|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - DX12|x64.ActiveCfg = Release|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - DX12|x64.Build.0 = Release|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM DX12|x64.Build.0 = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.ActiveCfg = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.Build.0 = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release|x64.ActiveCfg = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release|x64.Build.0 = Release|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - DX12|x64.Build.0 = Debug|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - LLVM|x64.Build.0 = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -385,10 +497,18 @@ Global {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Debug|x64.Build.0 = DLL Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.ActiveCfg = DLL Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.Build.0 = DLL Release|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - DX12|x64.ActiveCfg = Release|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - DX12|x64.Build.0 = Release|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM DX12|x64.Build.0 = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.ActiveCfg = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.Build.0 = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release|x64.ActiveCfg = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release|x64.Build.0 = Release|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - DX12|x64.Build.0 = Debug|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - LLVM|x64.Build.0 = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -399,10 +519,18 @@ Global {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Debug|x64.Build.0 = DLL Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.ActiveCfg = DLL Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.Build.0 = DLL Release|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - DX12|x64.ActiveCfg = Release|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - DX12|x64.Build.0 = Release|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM DX12|x64.Build.0 = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.ActiveCfg = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.Build.0 = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release|x64.ActiveCfg = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release|x64.Build.0 = Release|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - DX12|x64.Build.0 = Debug|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - LLVM|x64.Build.0 = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -413,10 +541,18 @@ Global {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Debug|x64.Build.0 = DLL Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.ActiveCfg = DLL Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.Build.0 = DLL Release|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - DX12|x64.ActiveCfg = Release|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - DX12|x64.Build.0 = Release|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM DX12|x64.Build.0 = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.ActiveCfg = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.Build.0 = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release|x64.ActiveCfg = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release|x64.Build.0 = Release|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - DX12|x64.Build.0 = Debug|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - LLVM|x64.Build.0 = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -427,10 +563,18 @@ Global {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Debug|x64.Build.0 = DLL Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.ActiveCfg = DLL Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.Build.0 = DLL Release|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - DX12|x64.ActiveCfg = Release|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - DX12|x64.Build.0 = Release|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM DX12|x64.Build.0 = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.ActiveCfg = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.Build.0 = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release|x64.ActiveCfg = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release|x64.Build.0 = Release|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - DX12|x64.Build.0 = Debug|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - LLVM|x64.Build.0 = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -441,10 +585,18 @@ Global {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Debug|x64.Build.0 = DLL Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.ActiveCfg = DLL Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.Build.0 = DLL Release|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - DX12|x64.ActiveCfg = Release|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - DX12|x64.Build.0 = Release|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM DX12|x64.Build.0 = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.ActiveCfg = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.Build.0 = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release|x64.ActiveCfg = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release|x64.Build.0 = Release|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - DX12|x64.Build.0 = Debug|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - LLVM|x64.Build.0 = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -455,10 +607,18 @@ Global {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Debug|x64.Build.0 = DLL Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.ActiveCfg = DLL Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.Build.0 = DLL Release|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - DX12|x64.ActiveCfg = Release|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - DX12|x64.Build.0 = Release|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM DX12|x64.Build.0 = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.ActiveCfg = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.Build.0 = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release|x64.ActiveCfg = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release|x64.Build.0 = Release|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - DX12|x64.Build.0 = Debug|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - LLVM|x64.Build.0 = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -469,10 +629,18 @@ Global {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Debug|x64.Build.0 = DLL Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.ActiveCfg = DLL Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.Build.0 = DLL Release|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - DX12|x64.ActiveCfg = Release|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - DX12|x64.Build.0 = Release|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM DX12|x64.Build.0 = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.ActiveCfg = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.Build.0 = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release|x64.ActiveCfg = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release|x64.Build.0 = Release|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - DX12|x64.Build.0 = Debug|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - LLVM|x64.Build.0 = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -483,10 +651,18 @@ Global {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Debug|x64.Build.0 = DLL Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.ActiveCfg = DLL Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.Build.0 = DLL Release|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - DX12|x64.ActiveCfg = Release|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - DX12|x64.Build.0 = Release|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM DX12|x64.Build.0 = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.ActiveCfg = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.Build.0 = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release|x64.ActiveCfg = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release|x64.Build.0 = Release|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - DX12|x64.Build.0 = Debug|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - LLVM|x64.Build.0 = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -497,10 +673,18 @@ Global {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Debug|x64.Build.0 = DLL Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.ActiveCfg = DLL Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.Build.0 = DLL Release|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - DX12|x64.ActiveCfg = Release|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - DX12|x64.Build.0 = Release|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM DX12|x64.Build.0 = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.ActiveCfg = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.Build.0 = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release|x64.ActiveCfg = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release|x64.Build.0 = Release|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - DX12|x64.Build.0 = Debug|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - LLVM|x64.Build.0 = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -511,10 +695,18 @@ Global {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Debug|x64.Build.0 = DLL Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.ActiveCfg = DLL Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.Build.0 = DLL Release|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - DX12|x64.ActiveCfg = Release|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - DX12|x64.Build.0 = Release|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM DX12|x64.Build.0 = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.ActiveCfg = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.Build.0 = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.ActiveCfg = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.Build.0 = Release|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - DX12|x64.Build.0 = Debug|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - LLVM|x64.Build.0 = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -525,10 +717,18 @@ Global {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.Build.0 = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.ActiveCfg = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.Build.0 = Release|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - DX12|x64.ActiveCfg = Release|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - DX12|x64.Build.0 = Release|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM DX12|x64.Build.0 = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.Build.0 = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.ActiveCfg = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.Build.0 = Release|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - DX12|x64.ActiveCfg = Debug - DX12|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - DX12|x64.Build.0 = Debug - DX12|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM DX12|x64.ActiveCfg = Debug - LLVM DX12|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM DX12|x64.Build.0 = Debug - LLVM DX12|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64 @@ -539,10 +739,17 @@ Global {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Debug|x64.Build.0 = Debug|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.ActiveCfg = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.Build.0 = Release|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - DX12|x64.ActiveCfg = Release - DX12|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - DX12|x64.Build.0 = Release - DX12|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM DX12|x64.ActiveCfg = Release - LLVM DX12|x64 + {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM DX12|x64.Build.0 = Release - LLVM DX12|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64 + {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.Build.0 = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -551,9 +758,16 @@ Global {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Debug|x64.Build.0 = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.ActiveCfg = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.Build.0 = Release|x64 + {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - DX12|x64.ActiveCfg = Release|x64 + {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM DX12|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.ActiveCfg = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.Build.0 = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release|x64.ActiveCfg = Release|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - DX12|x64.Build.0 = Debug|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.Build.0 = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -564,10 +778,18 @@ Global {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Debug|x64.Build.0 = DLL Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.ActiveCfg = DLL Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.Build.0 = DLL Release|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - DX12|x64.ActiveCfg = Release|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - DX12|x64.Build.0 = Release|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM DX12|x64.Build.0 = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.Build.0 = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.Build.0 = Release|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - DX12|x64.ActiveCfg = Debug|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - DX12|x64.Build.0 = Debug|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - LLVM DX12|x64.ActiveCfg = Debug|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - LLVM DX12|x64.Build.0 = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - LLVM|x64.Build.0 = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 @@ -578,6 +800,10 @@ Global {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Debug|x64.Build.0 = DLL Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.ActiveCfg = DLL Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.Build.0 = DLL Release|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Release - DX12|x64.ActiveCfg = Release|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Release - DX12|x64.Build.0 = Release|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM DX12|x64.ActiveCfg = Release|x64 + {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM DX12|x64.Build.0 = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.ActiveCfg = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.Build.0 = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release|x64.ActiveCfg = Release|x64 diff --git a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp index 7a457bb15d..5bf8341ba5 100644 --- a/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/FragmentProgramDecompiler.cpp @@ -92,7 +92,7 @@ std::string FragmentProgramDecompiler::GetMask() std::string FragmentProgramDecompiler::AddReg(u32 index, int fp16) { - return m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string(fp16 ? "h" : "r") + std::to_string(index), getFloatTypeName(4) + "(0.0)"); + return m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string(fp16 ? "h" : "r") + std::to_string(index), getFloatTypeName(4) + "(0., 0., 0., 0.)"); } bool FragmentProgramDecompiler::HasReg(u32 index, int fp16) diff --git a/rpcs3/Emu/RSX/Common/ProgramStateCache.h b/rpcs3/Emu/RSX/Common/ProgramStateCache.h index 5466b2d87f..6a732e7bd7 100644 --- a/rpcs3/Emu/RSX/Common/ProgramStateCache.h +++ b/rpcs3/Emu/RSX/Common/ProgramStateCache.h @@ -2,6 +2,7 @@ #include "Emu/RSX/RSXFragmentProgram.h" #include "Emu/RSX/RSXVertexProgram.h" +#include "Utilities/Log.h" enum class SHADER_TYPE diff --git a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp index 3c8792611c..b3a8c0a9c7 100644 --- a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp @@ -152,7 +152,7 @@ void VertexProgramDecompiler::SetDST(bool is_sca, std::string value) if (d0.cond_update_enable_0 && d0.cond_update_enable_1) { - dest = m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), "cc" + std::to_string(d0.cond_reg_sel_1), getFloatTypeName(4) + "(0.0)") + mask; + dest = m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), "cc" + std::to_string(d0.cond_reg_sel_1), getFloatTypeName(4) + "(0., 0., 0., 0.)") + mask; } else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f)) { diff --git a/rpcs3/Emu/RSX/D3D12/D3D12.h b/rpcs3/Emu/RSX/D3D12/D3D12.h new file mode 100644 index 0000000000..a139297b1c --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12.h @@ -0,0 +1,307 @@ +#pragma once +#if defined(DX12_SUPPORT) + +#include +#include +#include "utilities/Log.h" +#include "Emu/Memory/vm.h" +#include "Emu/RSX/GCM.h" + +#pragma comment (lib, "dxgi.lib") + +#define SAFE_RELEASE(x) if (x) x->Release(); + +inline +void check(HRESULT hr) +{ + if (hr != 0) + abort(); +} + +/** + * Send data to dst pointer without polluting cache. + * Usefull to write to mapped memory from upload heap. + */ +inline +void streamToBuffer(void* dst, void* src, size_t sizeInBytes) +{ +#pragma omp parallel for + for (int i = 0; i < sizeInBytes / 16; i++) + { + const __m128i &srcPtr = _mm_loadu_si128((__m128i*) ((char*)src + i * 16)); + _mm_stream_si128((__m128i*)((char*)dst + i * 16), srcPtr); + } +} + +/** +* copy src to dst pointer without polluting cache. +* Usefull to write to mapped memory from upload heap. +*/ +inline +void streamBuffer(void* dst, void* src, size_t sizeInBytes) +{ + // Assume 64 bytes cache line + int offset = 0; + bool isAligned = !((size_t)src & 15); + #pragma omp parallel for + for (offset = 0; offset < sizeInBytes - 64; offset += 64) + { + char *line = (char*)src + offset; + char *dstline = (char*)dst + offset; + // prefetch next line + _mm_prefetch(line + 16, _MM_HINT_NTA); + __m128i srcPtr = isAligned ? _mm_load_si128((__m128i *)line) : _mm_loadu_si128((__m128i *)line); + _mm_stream_si128((__m128i*)dstline, srcPtr); + srcPtr = isAligned ? _mm_load_si128((__m128i *)(line + 16)) : _mm_loadu_si128((__m128i *)(line + 16)); + _mm_stream_si128((__m128i*)(dstline + 16), srcPtr); + srcPtr = isAligned ? _mm_load_si128((__m128i *)(line + 32)) : _mm_loadu_si128((__m128i *)(line + 32)); + _mm_stream_si128((__m128i*)(dstline + 32), srcPtr); + srcPtr = isAligned ? _mm_load_si128((__m128i *)(line + 48)) : _mm_loadu_si128((__m128i *)(line + 48)); + _mm_stream_si128((__m128i*)(dstline + 48), srcPtr); + } + memcpy((char*)dst + offset, (char*)src + offset, sizeInBytes - offset); +} + +inline +D3D12_RESOURCE_DESC getBufferResourceDesc(size_t sizeInByte) +{ + D3D12_RESOURCE_DESC BufferDesc = {}; + BufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + BufferDesc.Width = (UINT)sizeInByte; + BufferDesc.Height = 1; + BufferDesc.DepthOrArraySize = 1; + BufferDesc.SampleDesc.Count = 1; + BufferDesc.MipLevels = 1; + BufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + return BufferDesc; +} + +inline +D3D12_RESOURCE_DESC getTexture2DResourceDesc(size_t width, size_t height, DXGI_FORMAT dxgiFormat, size_t mipmapLevels) +{ + D3D12_RESOURCE_DESC result; + result = {}; + result.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + result.Width = (UINT)width; + result.Height = (UINT)height; + result.Format = dxgiFormat; + result.DepthOrArraySize = 1; + result.SampleDesc.Count = 1; + result.MipLevels = (UINT16)mipmapLevels; + return result; +} + +inline +D3D12_RESOURCE_BARRIER getResourceBarrierTransition(ID3D12Resource *res, D3D12_RESOURCE_STATES stateBefore, D3D12_RESOURCE_STATES stateAfter) +{ + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = res; + barrier.Transition.StateBefore = stateBefore; + barrier.Transition.StateAfter = stateAfter; + return barrier; +} + +/** + * Convert GCM blend operator code to D3D12 one + */ +inline D3D12_BLEND_OP getBlendOp(u16 op) +{ + switch (op) + { + case CELL_GCM_FUNC_ADD: return D3D12_BLEND_OP_ADD; + case CELL_GCM_FUNC_SUBTRACT: return D3D12_BLEND_OP_SUBTRACT; + case CELL_GCM_FUNC_REVERSE_SUBTRACT: return D3D12_BLEND_OP_REV_SUBTRACT; + case CELL_GCM_MIN: return D3D12_BLEND_OP_MIN; + case CELL_GCM_MAX: return D3D12_BLEND_OP_MAX; + default: + case CELL_GCM_FUNC_ADD_SIGNED: + case CELL_GCM_FUNC_REVERSE_ADD_SIGNED: + case CELL_GCM_FUNC_REVERSE_SUBTRACT_SIGNED: + LOG_WARNING(RSX, "Unsupported Blend Op %d", op); + return D3D12_BLEND_OP(); + } +} + +/** + * Convert GCM blend factor code to D3D12 one + */ +inline D3D12_BLEND getBlendFactor(u16 factor) +{ + switch (factor) + { + case CELL_GCM_ZERO: return D3D12_BLEND_ZERO; + case CELL_GCM_ONE: return D3D12_BLEND_ONE; + case CELL_GCM_SRC_COLOR: return D3D12_BLEND_SRC_COLOR; + case CELL_GCM_ONE_MINUS_SRC_COLOR: return D3D12_BLEND_INV_SRC_COLOR; + case CELL_GCM_SRC_ALPHA: return D3D12_BLEND_SRC_ALPHA; + case CELL_GCM_ONE_MINUS_SRC_ALPHA: return D3D12_BLEND_INV_SRC_ALPHA; + case CELL_GCM_DST_ALPHA: return D3D12_BLEND_DEST_ALPHA; + case CELL_GCM_ONE_MINUS_DST_ALPHA: return D3D12_BLEND_INV_DEST_ALPHA; + case CELL_GCM_DST_COLOR: return D3D12_BLEND_DEST_COLOR; + case CELL_GCM_ONE_MINUS_DST_COLOR: return D3D12_BLEND_INV_DEST_COLOR; + case CELL_GCM_SRC_ALPHA_SATURATE: return D3D12_BLEND_SRC_ALPHA_SAT; + default: + case CELL_GCM_CONSTANT_COLOR: + case CELL_GCM_ONE_MINUS_CONSTANT_COLOR: + case CELL_GCM_CONSTANT_ALPHA: + case CELL_GCM_ONE_MINUS_CONSTANT_ALPHA: + LOG_WARNING(RSX, "Unsupported Blend Factor %d", factor); + return D3D12_BLEND(); + } +} + +/** + * Convert GCM logic op code to D3D12 one + */ +inline D3D12_LOGIC_OP getLogicOp(u32 op) +{ + switch (op) + { + default: + LOG_WARNING(RSX, "Unsupported Logic Op %d", op); + return D3D12_LOGIC_OP(); + case CELL_GCM_CLEAR: return D3D12_LOGIC_OP_CLEAR; + case CELL_GCM_AND: return D3D12_LOGIC_OP_AND; + case CELL_GCM_AND_REVERSE: return D3D12_LOGIC_OP_AND_REVERSE; + case CELL_GCM_COPY: return D3D12_LOGIC_OP_COPY; + case CELL_GCM_AND_INVERTED: return D3D12_LOGIC_OP_AND_INVERTED; + case CELL_GCM_NOOP: return D3D12_LOGIC_OP_NOOP; + case CELL_GCM_XOR: return D3D12_LOGIC_OP_XOR; + case CELL_GCM_OR: return D3D12_LOGIC_OP_OR; + case CELL_GCM_NOR: return D3D12_LOGIC_OP_NOR; + case CELL_GCM_EQUIV: return D3D12_LOGIC_OP_EQUIV; + case CELL_GCM_INVERT: return D3D12_LOGIC_OP_INVERT; + case CELL_GCM_OR_REVERSE: return D3D12_LOGIC_OP_OR_REVERSE; + case CELL_GCM_COPY_INVERTED: return D3D12_LOGIC_OP_COPY_INVERTED; + case CELL_GCM_OR_INVERTED: return D3D12_LOGIC_OP_OR_INVERTED; + case CELL_GCM_NAND: return D3D12_LOGIC_OP_NAND; + } +} + +/** + * Convert GCM stencil op code to D3D12 one + */ +inline D3D12_STENCIL_OP getStencilOp(u32 op) +{ + switch (op) + { + case CELL_GCM_KEEP: return D3D12_STENCIL_OP_KEEP; + case CELL_GCM_ZERO: return D3D12_STENCIL_OP_ZERO; + case CELL_GCM_REPLACE: return D3D12_STENCIL_OP_REPLACE; + case CELL_GCM_INCR: return D3D12_STENCIL_OP_INCR; + case CELL_GCM_DECR: return D3D12_STENCIL_OP_DECR; + default: + case CELL_GCM_INCR_WRAP: + case CELL_GCM_DECR_WRAP: + LOG_WARNING(RSX, "Unsupported Stencil Op %d", op); + return D3D12_STENCIL_OP(); + } +} + +/** + * Convert GCM comparison function code to D3D12 one. + */ +inline D3D12_COMPARISON_FUNC getCompareFunc(u32 op) +{ + switch (op) + { + case CELL_GCM_NEVER: return D3D12_COMPARISON_FUNC_NEVER; + case CELL_GCM_LESS: return D3D12_COMPARISON_FUNC_LESS; + case CELL_GCM_EQUAL: return D3D12_COMPARISON_FUNC_EQUAL; + case CELL_GCM_LEQUAL: return D3D12_COMPARISON_FUNC_LESS_EQUAL; + case CELL_GCM_GREATER: return D3D12_COMPARISON_FUNC_GREATER; + case CELL_GCM_NOTEQUAL: return D3D12_COMPARISON_FUNC_NOT_EQUAL; + case CELL_GCM_GEQUAL: return D3D12_COMPARISON_FUNC_GREATER_EQUAL; + case CELL_GCM_ALWAYS: return D3D12_COMPARISON_FUNC_ALWAYS; + default: + LOG_WARNING(RSX, "Unsupported Compare Function %d", op); + return D3D12_COMPARISON_FUNC(); + } +} + +/** + * Convert GCM texture format to an equivalent one supported by D3D12. + * Destination format may require a byte swap or data conversion. + */ +inline DXGI_FORMAT getTextureDXGIFormat(int format) +{ + switch (format) + { + case CELL_GCM_TEXTURE_Y16_X16_FLOAT: + case CELL_GCM_TEXTURE_COMPRESSED_HILO8: + case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + default: + LOG_ERROR(RSX, "Unimplemented Texture format : %x", format); + return DXGI_FORMAT(); + case CELL_GCM_TEXTURE_B8: + return DXGI_FORMAT_R8_UNORM; + case CELL_GCM_TEXTURE_A1R5G5B5: + return DXGI_FORMAT_B5G5R5A1_UNORM; + case CELL_GCM_TEXTURE_A4R4G4B4: + return DXGI_FORMAT_B4G4R4A4_UNORM; + case CELL_GCM_TEXTURE_R5G6B5: + return DXGI_FORMAT_B5G6R5_UNORM; + case CELL_GCM_TEXTURE_A8R8G8B8: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + return DXGI_FORMAT_BC1_UNORM; + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + return DXGI_FORMAT_BC2_UNORM; + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + return DXGI_FORMAT_BC3_UNORM; + case CELL_GCM_TEXTURE_G8B8: + return DXGI_FORMAT_G8R8_G8B8_UNORM; + case CELL_GCM_TEXTURE_R6G5B5: + // Not native + return DXGI_FORMAT_R8G8B8A8_UNORM; + case CELL_GCM_TEXTURE_DEPTH24_D8: + return DXGI_FORMAT_R32_UINT; + case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: + return DXGI_FORMAT_R32_FLOAT; + case CELL_GCM_TEXTURE_DEPTH16: + return DXGI_FORMAT_R16_UNORM; + case CELL_GCM_TEXTURE_DEPTH16_FLOAT: + return DXGI_FORMAT_R16_FLOAT; + case CELL_GCM_TEXTURE_X16: + return DXGI_FORMAT_R16_UNORM; + case CELL_GCM_TEXTURE_Y16_X16: + return DXGI_FORMAT_R16G16_UNORM; + case CELL_GCM_TEXTURE_R5G5B5A1: + return DXGI_FORMAT_B5G5R5A1_UNORM; + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + case CELL_GCM_TEXTURE_X32_FLOAT: + return DXGI_FORMAT_R32_FLOAT; + case CELL_GCM_TEXTURE_D1R5G5B5: + return DXGI_FORMAT_B5G5R5A1_UNORM; + case CELL_GCM_TEXTURE_D8R8G8B8: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + return DXGI_FORMAT_G8R8_G8B8_UNORM; + case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + return DXGI_FORMAT_R8G8_B8G8_UNORM; + } +} + +inline +D3D12_CPU_DESCRIPTOR_HANDLE getCPUDescriptorHandle(ID3D12DescriptorHeap *descriptors, size_t offset) +{ + D3D12_CPU_DESCRIPTOR_HANDLE result = descriptors->GetCPUDescriptorHandleForHeapStart(); + result.ptr += offset; + return result; +} + +inline +D3D12_GPU_DESCRIPTOR_HANDLE getGPUDescriptorHandle(ID3D12DescriptorHeap *descriptors, size_t offset) +{ + D3D12_GPU_DESCRIPTOR_HANDLE result = descriptors->GetGPUDescriptorHandleForHeapStart(); + result.ptr += offset; + return result; +} + +#endif diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp new file mode 100644 index 0000000000..bfa2364f89 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.cpp @@ -0,0 +1,621 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "D3D12Buffer.h" +#include "Utilities/Log.h" + +#include "D3D12GSRender.h" + +const int g_vertexCount = 32; + +// Where are these type defined ??? +static +DXGI_FORMAT getFormat(u8 type, u8 size) +{ + /*static const u32 gl_types[] = + { + GL_SHORT, + GL_FLOAT, + GL_HALF_FLOAT, + GL_UNSIGNED_BYTE, + GL_SHORT, + GL_FLOAT, // Needs conversion + GL_UNSIGNED_BYTE, + }; + + static const bool gl_normalized[] = + { + GL_TRUE, + GL_FALSE, + GL_FALSE, + GL_TRUE, + GL_FALSE, + GL_TRUE, + GL_FALSE, + };*/ + static const DXGI_FORMAT typeX1[] = + { + DXGI_FORMAT_R16_SNORM, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R16_FLOAT, + DXGI_FORMAT_R8_UNORM, + DXGI_FORMAT_R16_SINT, + DXGI_FORMAT_R32_FLOAT, + DXGI_FORMAT_R8_UINT + }; + static const DXGI_FORMAT typeX2[] = + { + DXGI_FORMAT_R16G16_SNORM, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R16G16_FLOAT, + DXGI_FORMAT_R8G8_UNORM, + DXGI_FORMAT_R16G16_SINT, + DXGI_FORMAT_R32G32_FLOAT, + DXGI_FORMAT_R8G8_UINT + }; + static const DXGI_FORMAT typeX3[] = + { + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R32G32B32_FLOAT, + DXGI_FORMAT_R8G8B8A8_UINT + }; + static const DXGI_FORMAT typeX4[] = + { + DXGI_FORMAT_R16G16B16A16_SNORM, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R16G16B16A16_FLOAT, + DXGI_FORMAT_R8G8B8A8_UNORM, + DXGI_FORMAT_R16G16B16A16_SINT, + DXGI_FORMAT_R32G32B32A32_FLOAT, + DXGI_FORMAT_R8G8B8A8_UINT + }; + + switch (size) + { + case 1: + return typeX1[type]; + case 2: + return typeX2[type]; + case 3: + return typeX3[type]; + case 4: + return typeX4[type]; + default: + LOG_ERROR(RSX, "Wrong size for vertex attrib : %d", size); + return DXGI_FORMAT(); + } +} + +struct VertexBufferFormat +{ + std::pair range; + std::vector attributeId; + size_t elementCount; + size_t stride; +}; + +std::vector getIALayout(ID3D12Device *device, const std::vector &vertexBufferFormat, const RSXVertexData *m_vertex_data) +{ + std::vector result; + + for (size_t inputSlot = 0; inputSlot < vertexBufferFormat.size(); inputSlot++) + { + for (size_t attributeId : vertexBufferFormat[inputSlot].attributeId) + { + const RSXVertexData &vertexData = m_vertex_data[attributeId]; + D3D12_INPUT_ELEMENT_DESC IAElement = {}; + IAElement.SemanticName = "TEXCOORD"; + IAElement.SemanticIndex = (UINT)attributeId; + IAElement.InputSlot = (UINT)inputSlot; + IAElement.Format = getFormat(vertexData.type - 1, vertexData.size); + IAElement.AlignedByteOffset = (UINT)(vertexData.addr - vertexBufferFormat[inputSlot].range.first); + IAElement.InputSlotClass = (vertexData.addr > 0) ? D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA : D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA; + IAElement.InstanceDataStepRate = (vertexData.addr > 0) ? 0 : 0; + result.push_back(IAElement); + } + } + return result; +} + +template +void expandIndexedQuads(DstType *dst, const SrcType *src, size_t indexCount) +{ + IndexType *typedDst = reinterpret_cast(dst); + const IndexType *typedSrc = reinterpret_cast(src); + for (unsigned i = 0; i < indexCount / 4; i++) + { + // First triangle + typedDst[6 * i] = typedSrc[4 * i]; + typedDst[6 * i + 1] = typedSrc[4 * i + 1]; + typedDst[6 * i + 2] = typedSrc[4 * i + 2]; + // Second triangle + typedDst[6 * i + 3] = typedSrc[4 * i + 2]; + typedDst[6 * i + 4] = typedSrc[4 * i + 3]; + typedDst[6 * i + 5] = typedSrc[4 * i]; + } +} + + + +// D3D12GS member handling buffers + + + +#define MIN2(x, y) ((x) < (y)) ? (x) : (y) +#define MAX2(x, y) ((x) > (y)) ? (x) : (y) + +static +bool overlaps(const std::pair &range1, const std::pair &range2) +{ + return !(range1.second < range2.first || range2.second < range1.first); +} + +static +std::vector FormatVertexData(const RSXVertexData *m_vertex_data) +{ + std::vector Result; + for (size_t i = 0; i < 32; ++i) + { + const RSXVertexData &vertexData = m_vertex_data[i]; + if (!vertexData.IsEnabled()) continue; + + size_t elementCount = vertexData.data.size() / (vertexData.size * vertexData.GetTypeSize()); + // If there is a single element, stride is 0, use the size of element instead + size_t stride = vertexData.stride; + size_t elementSize = vertexData.GetTypeSize(); + std::pair range = std::make_pair(vertexData.addr, vertexData.addr + elementSize * vertexData.size + (elementCount - 1) * stride - 1); + bool isMerged = false; + + for (VertexBufferFormat &vbf : Result) + { + if (overlaps(vbf.range, range) && vbf.stride == stride) + { + // Extend buffer if necessary + vbf.range.first = MIN2(vbf.range.first, range.first); + vbf.range.second = MAX2(vbf.range.second, range.second); + vbf.elementCount = MAX2(vbf.elementCount, elementCount); + + vbf.attributeId.push_back(i); + isMerged = true; + break; + } + } + if (isMerged) + continue; + VertexBufferFormat newRange = { range, std::vector{ i }, elementCount, stride }; + Result.emplace_back(newRange); + } + return Result; +} + +/** + * Create a new vertex buffer with attributes from vbf using vertexIndexHeap as storage heap. + */ +static +ID3D12Resource *createVertexBuffer(const VertexBufferFormat &vbf, const RSXVertexData *vertexData, ID3D12Device *device, DataHeap &vertexIndexHeap) +{ + size_t subBufferSize = vbf.range.second - vbf.range.first + 1; + // Make multiple of stride + if (vbf.stride) + subBufferSize = ((subBufferSize + vbf.stride - 1) / vbf.stride) * vbf.stride; + assert(vertexIndexHeap.canAlloc(subBufferSize)); + size_t heapOffset = vertexIndexHeap.alloc(subBufferSize); + + ID3D12Resource *vertexBuffer; + check(device->CreatePlacedResource( + vertexIndexHeap.m_heap, + heapOffset, + &getBufferResourceDesc(subBufferSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&vertexBuffer) + )); + void *bufferMap; + check(vertexBuffer->Map(0, nullptr, (void**)&bufferMap)); + memset(bufferMap, -1, subBufferSize); + #pragma omp parallel for + for (int vertex = 0; vertex < vbf.elementCount; vertex++) + { + for (size_t attributeId : vbf.attributeId) + { + if (!vertexData[attributeId].addr) + { + memcpy(bufferMap, vertexData[attributeId].data.data(), vertexData[attributeId].data.size()); + continue; + } + size_t baseOffset = (size_t)vertexData[attributeId].addr - vbf.range.first; + size_t tsize = vertexData[attributeId].GetTypeSize(); + size_t size = vertexData[attributeId].size; + auto src = vm::get_ptr(vertexData[attributeId].addr + (int)vbf.stride * vertex); + char* dst = (char*)bufferMap + baseOffset + vbf.stride * vertex; + + switch (tsize) + { + case 1: + { + memcpy(dst, src, size); + break; + } + + case 2: + { + const u16* c_src = (const u16*)src; + u16* c_dst = (u16*)dst; + for (u32 j = 0; j < size; ++j) *c_dst++ = _byteswap_ushort(*c_src++); + break; + } + + case 4: + { + const u32* c_src = (const u32*)src; + u32* c_dst = (u32*)dst; + for (u32 j = 0; j < size; ++j) *c_dst++ = _byteswap_ulong(*c_src++); + break; + } + } + } + } + + vertexBuffer->Unmap(0, nullptr); + vertexIndexHeap.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, subBufferSize, vertexBuffer)); + return vertexBuffer; +} + +static bool +isContained(const std::vector > &ranges, const std::pair &range) +{ + for (auto &r : ranges) + { + if (r == range) + return true; + } + return false; +} + +std::vector D3D12GSRender::UploadVertexBuffers(bool indexed_draw) +{ + std::vector result; + const std::vector &vertexBufferFormat = FormatVertexData(m_vertex_data); + m_IASet = getIALayout(m_device, vertexBufferFormat, m_vertex_data); + + const u32 data_offset = indexed_draw ? 0 : m_draw_array_first; + + for (size_t buffer = 0; buffer < vertexBufferFormat.size(); buffer++) + { + const VertexBufferFormat &vbf = vertexBufferFormat[buffer]; + // Make multiple of stride + size_t subBufferSize = vbf.range.second - vbf.range.first + 1; + if (vbf.stride) + subBufferSize = ((subBufferSize + vbf.stride - 1) / vbf.stride) * vbf.stride; + + u64 key = vbf.range.first; + key = key << 32; + key = key | vbf.range.second; + auto It = m_vertexCache.find(key); + + ID3D12Resource *vertexBuffer; + if (vbf.range.first != 0 && // Attribute is stored in a buffer, not inline in command buffer + It != m_vertexCache.end()) + vertexBuffer = It->second; + else + { + vertexBuffer = createVertexBuffer(vbf, m_vertex_data, m_device, m_vertexIndexData); + m_vertexCache[key] = vertexBuffer; + } + + D3D12_VERTEX_BUFFER_VIEW vertexBufferView = {}; + vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress(); + vertexBufferView.SizeInBytes = (UINT)subBufferSize; + vertexBufferView.StrideInBytes = (UINT)vbf.stride; + result.push_back(vertexBufferView); + } + + return result; +} + +D3D12_INDEX_BUFFER_VIEW D3D12GSRender::uploadIndexBuffers(bool indexed_draw) +{ + D3D12_INDEX_BUFFER_VIEW indexBufferView = {}; + // Only handle quads and triangle fan now + bool forcedIndexBuffer = false; + switch (m_draw_mode - 1) + { + default: + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_QUAD_STRIP: + case GL_POLYGON: + forcedIndexBuffer = false; + break; + case GL_TRIANGLE_FAN: + case GL_QUADS: + forcedIndexBuffer = true; + break; + } + + // No need for index buffer + if (!indexed_draw && !forcedIndexBuffer) + { + m_renderingInfo.m_indexed = false; + m_renderingInfo.m_count = m_draw_array_count; + m_renderingInfo.m_baseVertex = m_draw_array_first; + return indexBufferView; + } + + m_renderingInfo.m_indexed = true; + + // Index type + size_t indexSize; + if (!indexed_draw) + { + indexBufferView.Format = DXGI_FORMAT_R16_UINT; + indexSize = 2; + } + else + { + switch (m_indexed_array.m_type) + { + default: abort(); + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: + indexBufferView.Format = DXGI_FORMAT_R16_UINT; + indexSize = 2; + break; + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: + indexBufferView.Format = DXGI_FORMAT_R32_UINT; + indexSize = 4; + break; + } + } + + // Index count + if (indexed_draw && !forcedIndexBuffer) + m_renderingInfo.m_count = m_indexed_array.m_data.size() / indexSize; + else if (indexed_draw && forcedIndexBuffer) + m_renderingInfo.m_count = 6 * m_indexed_array.m_data.size() / (4 * indexSize); + else + { + switch (m_draw_mode - 1) + { + case GL_TRIANGLE_FAN: + m_renderingInfo.m_count = (m_draw_array_count - 2) * 3; + break; + case GL_QUADS: + m_renderingInfo.m_count = m_draw_array_count * 6 / 4; + break; + } + } + + // Base vertex + if (!indexed_draw && forcedIndexBuffer) + m_renderingInfo.m_baseVertex = m_draw_array_first; + else + m_renderingInfo.m_baseVertex = 0; + + // Alloc + size_t subBufferSize = align(m_renderingInfo.m_count * indexSize, 64); + + assert(m_vertexIndexData.canAlloc(subBufferSize)); + size_t heapOffset = m_vertexIndexData.alloc(subBufferSize); + + ID3D12Resource *indexBuffer; + check(m_device->CreatePlacedResource( + m_vertexIndexData.m_heap, + heapOffset, + &getBufferResourceDesc(subBufferSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&indexBuffer) + )); + + void *bufferMap; + check(indexBuffer->Map(0, nullptr, (void**)&bufferMap)); + if (indexed_draw && !forcedIndexBuffer) + streamBuffer(bufferMap, m_indexed_array.m_data.data(), subBufferSize); + else if (indexed_draw && forcedIndexBuffer) + { + // Only quads supported now + switch (m_indexed_array.m_type) + { + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: + expandIndexedQuads(bufferMap, m_indexed_array.m_data.data(), m_indexed_array.m_data.size() / 4); + break; + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: + expandIndexedQuads(bufferMap, m_indexed_array.m_data.data(), m_indexed_array.m_data.size() / 2); + break; + } + } + else + { + unsigned short *typedDst = static_cast(bufferMap); + switch (m_draw_mode - 1) + { + case GL_TRIANGLE_FAN: + for (unsigned i = 0; i < (m_draw_array_count - 2); i++) + { + typedDst[3 * i] = 0; + typedDst[3 * i + 1] = i + 2 - 1; + typedDst[3 * i + 2] = i + 2; + } + break; + case GL_QUADS: + for (unsigned i = 0; i < m_draw_array_count / 4; i++) + { + // First triangle + typedDst[6 * i] = 4 * i; + typedDst[6 * i + 1] = 4 * i + 1; + typedDst[6 * i + 2] = 4 * i + 2; + // Second triangle + typedDst[6 * i + 3] = 4 * i + 2; + typedDst[6 * i + 4] = 4 * i + 3; + typedDst[6 * i + 5] = 4 * i; + } + break; + } + + } + indexBuffer->Unmap(0, nullptr); + m_vertexIndexData.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, subBufferSize, indexBuffer)); + + indexBufferView.SizeInBytes = (UINT)subBufferSize; + indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress(); + return indexBufferView; +} + +void D3D12GSRender::setScaleOffset() +{ + float scaleOffsetMat[16] = + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + // Scale + scaleOffsetMat[0] *= (float&)methodRegisters[NV4097_SET_VIEWPORT_SCALE + (0x4 * 0)] / (m_surface_clip_w / 2.f); + scaleOffsetMat[5] *= (float&)methodRegisters[NV4097_SET_VIEWPORT_SCALE + (0x4 * 1)] / (m_surface_clip_h / 2.f); + scaleOffsetMat[10] = (float&)methodRegisters[NV4097_SET_VIEWPORT_SCALE + (0x4 * 2)]; + + // Offset + scaleOffsetMat[3] = (float&)methodRegisters[NV4097_SET_VIEWPORT_OFFSET + (0x4 * 0)] - (m_surface_clip_w / 2.f); + scaleOffsetMat[7] = -((float&)methodRegisters[NV4097_SET_VIEWPORT_OFFSET + (0x4 * 1)] - (m_surface_clip_h / 2.f)); + scaleOffsetMat[11] = (float&)methodRegisters[NV4097_SET_VIEWPORT_OFFSET + (0x4 * 2)]; + + scaleOffsetMat[3] /= m_surface_clip_w / 2.f; + scaleOffsetMat[7] /= m_surface_clip_h / 2.f; + + assert(m_constantsData.canAlloc(256)); + size_t heapOffset = m_constantsData.alloc(256); + + // Scale offset buffer + // Separate constant buffer + D3D12_RANGE range = { heapOffset, heapOffset + 256 }; + + void *scaleOffsetMap; + check(m_constantsData.m_heap->Map(0, &range, &scaleOffsetMap)); + streamToBuffer((char*)scaleOffsetMap + heapOffset, scaleOffsetMat, 16 * sizeof(float)); + int isAlphaTested = m_set_alpha_test; + memcpy((char*)scaleOffsetMap + heapOffset + 16 * sizeof(float), &isAlphaTested, sizeof(int)); + memcpy((char*)scaleOffsetMap + heapOffset + 17 * sizeof(float), &m_alpha_ref, sizeof(float)); + m_constantsData.m_heap->Unmap(0, &range); + + D3D12_CONSTANT_BUFFER_VIEW_DESC constantBufferViewDesc = {}; + constantBufferViewDesc.BufferLocation = m_constantsData.m_heap->GetGPUVirtualAddress() + heapOffset; + constantBufferViewDesc.SizeInBytes = (UINT)256; + D3D12_CPU_DESCRIPTOR_HANDLE Handle = getCurrentResourceStorage().m_scaleOffsetDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); + Handle.ptr += getCurrentResourceStorage().m_currentScaleOffsetBufferIndex * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + m_device->CreateConstantBufferView(&constantBufferViewDesc, Handle); + m_constantsData.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, 256, nullptr)); +} + +void D3D12GSRender::FillVertexShaderConstantsBuffer() +{ + for (const RSXTransformConstant& c : m_transform_constants) + { + size_t offset = c.id * 4 * sizeof(float); + m_vertexConstants[offset] = c; + } + + size_t bufferSize = 512 * 4 * sizeof(float); + + assert(m_constantsData.canAlloc(bufferSize)); + size_t heapOffset = m_constantsData.alloc(bufferSize); + + D3D12_RANGE range = { heapOffset, heapOffset + bufferSize }; + + void *constantsBufferMap; + check(m_constantsData.m_heap->Map(0, &range, &constantsBufferMap)); + for (const auto &vertexConstants : m_vertexConstants) + { + float data[4] = { + vertexConstants.second.x, + vertexConstants.second.y, + vertexConstants.second.z, + vertexConstants.second.w + }; + streamToBuffer((char*)constantsBufferMap + heapOffset + vertexConstants.first, data, 4 * sizeof(float)); + } + m_constantsData.m_heap->Unmap(0, &range); + + D3D12_CONSTANT_BUFFER_VIEW_DESC constantBufferViewDesc = {}; + constantBufferViewDesc.BufferLocation = m_constantsData.m_heap->GetGPUVirtualAddress() + heapOffset; + constantBufferViewDesc.SizeInBytes = (UINT)bufferSize; + D3D12_CPU_DESCRIPTOR_HANDLE Handle = getCurrentResourceStorage().m_constantsBufferDescriptorsHeap->GetCPUDescriptorHandleForHeapStart(); + Handle.ptr += getCurrentResourceStorage().m_constantsBufferIndex * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + m_device->CreateConstantBufferView(&constantBufferViewDesc, Handle); + m_constantsData.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, bufferSize, nullptr)); +} + +void D3D12GSRender::FillPixelShaderConstantsBuffer() +{ + // Get constant from fragment program + const std::vector &fragmentOffset = m_cachePSO.getFragmentConstantOffsetsCache(m_cur_fragment_prog); + size_t bufferSize = fragmentOffset.size() * 4 * sizeof(float) + 1; + // Multiple of 256 never 0 + bufferSize = (bufferSize + 255) & ~255; + + assert(m_constantsData.canAlloc(bufferSize)); + size_t heapOffset = m_constantsData.alloc(bufferSize); + + D3D12_RANGE range = { heapOffset, heapOffset + bufferSize }; + + size_t offset = 0; + void *constantsBufferMap; + check(m_constantsData.m_heap->Map(0, &range, &constantsBufferMap)); + for (size_t offsetInFP : fragmentOffset) + { + u32 vector[4]; + // Is it assigned by color register in command buffer ? + // TODO : we loop every iteration, we might do better... + bool isCommandBufferSetConstant = false; + for (const RSXTransformConstant& c : m_fragment_constants) + { + size_t fragmentId = c.id - m_cur_fragment_prog->offset; + if (fragmentId == offsetInFP) + { + isCommandBufferSetConstant = true; + vector[0] = (u32&)c.x; + vector[1] = (u32&)c.y; + vector[2] = (u32&)c.z; + vector[3] = (u32&)c.w; + break; + } + } + if (!isCommandBufferSetConstant) + { + auto data = vm::ptr::make(m_cur_fragment_prog->addr + (u32)offsetInFP); + + u32 c0 = (data[0] >> 16 | data[0] << 16); + u32 c1 = (data[1] >> 16 | data[1] << 16); + u32 c2 = (data[2] >> 16 | data[2] << 16); + u32 c3 = (data[3] >> 16 | data[3] << 16); + + vector[0] = c0; + vector[1] = c1; + vector[2] = c2; + vector[3] = c3; + } + + streamToBuffer((char*)constantsBufferMap + heapOffset + offset, vector, 4 * sizeof(u32)); + offset += 4 * sizeof(u32); + } + m_constantsData.m_heap->Unmap(0, &range); + + D3D12_CONSTANT_BUFFER_VIEW_DESC constantBufferViewDesc = {}; + constantBufferViewDesc.BufferLocation = m_constantsData.m_heap->GetGPUVirtualAddress() + heapOffset; + constantBufferViewDesc.SizeInBytes = (UINT)bufferSize; + D3D12_CPU_DESCRIPTOR_HANDLE Handle = getCurrentResourceStorage().m_constantsBufferDescriptorsHeap->GetCPUDescriptorHandleForHeapStart(); + Handle.ptr += getCurrentResourceStorage().m_constantsBufferIndex * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + m_device->CreateConstantBufferView(&constantBufferViewDesc, Handle); + m_constantsData.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, bufferSize, nullptr)); +} + + +#endif diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Buffer.h b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.h new file mode 100644 index 0000000000..cb363e0f6d --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12Buffer.h @@ -0,0 +1,9 @@ +#pragma once +#if defined(DX12_SUPPORT) +#include +#include "Emu/Memory/vm.h" +#include "Emu/RSX/RSXThread.h" + +std::vector getIALayout(ID3D12Device *device, bool indexedDraw, const RSXVertexData *vertexData); + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp new file mode 100644 index 0000000000..813f6b5f0b --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "D3D12CommonDecompiler.h" + +std::string getFloatTypeNameImp(size_t elementCount) +{ + switch (elementCount) + { + default: + abort(); + case 1: + return "float"; + case 2: + return "float2"; + case 3: + return "float3"; + case 4: + return "float4"; + } +} + +std::string getFunctionImp(FUNCTION f) +{ + switch (f) + { + default: + abort(); + case FUNCTION::FUNCTION_DP2: + return "dot($0.xy, $1.xy).xxxx"; + case FUNCTION::FUNCTION_DP2A: + return "(dot($0.xy, $1.xy) + $2.x).xxxx"; + case FUNCTION::FUNCTION_DP3: + return "dot($0.xyz, $1.xyz).xxxx"; + case FUNCTION::FUNCTION_DP4: + return "dot($0, $1).xxxx"; + case FUNCTION::FUNCTION_DPH: + return "dot(float4($0.xyz, 1.0), $1).xxxx"; + case FUNCTION::FUNCTION_SFL: + return "float4(0., 0., 0., 0.)"; + case FUNCTION::FUNCTION_STR: + return "float4(1., 1., 1., 1.)"; + case FUNCTION::FUNCTION_FRACT: + return "frac($0)"; + case FUNCTION::FUNCTION_TEXTURE_SAMPLE: + return "$t.Sample($tsampler, $0.xy)"; + case FUNCTION::FUNCTION_DFDX: + return "ddx($0)"; + case FUNCTION::FUNCTION_DFDY: + return "ddy($0)"; + } +} + +std::string compareFunctionImp(COMPARE f, const std::string &Op0, const std::string &Op1) +{ + switch (f) + { + default: + abort(); + case COMPARE::FUNCTION_SEQ: + return "(" + Op0 + " == " + Op1 + ")"; + case COMPARE::FUNCTION_SGE: + return "(" + Op0 + " >= " + Op1 + ")"; + case COMPARE::FUNCTION_SGT: + return "(" + Op0 + " > " + Op1 + ")"; + case COMPARE::FUNCTION_SLE: + return "(" + Op0 + " <= " + Op1 + ")"; + case COMPARE::FUNCTION_SLT: + return "(" + Op0 + " < " + Op1 + ")"; + case COMPARE::FUNCTION_SNE: + return "(" + Op0 + " != " + Op1 + ")"; + } +} \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h new file mode 100644 index 0000000000..fd9cfd9589 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12CommonDecompiler.h @@ -0,0 +1,6 @@ +#pragma once +#include "../Common/ShaderParam.h" + +std::string getFloatTypeNameImp(size_t elementCount); +std::string getFunctionImp(FUNCTION f); +std::string compareFunctionImp(COMPARE f, const std::string &Op0, const std::string &Op1); \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp new file mode 100644 index 0000000000..13a97cda55 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.cpp @@ -0,0 +1,153 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "D3D12FragmentProgramDecompiler.h" +#include "D3D12CommonDecompiler.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" + +D3D12FragmentDecompiler::D3D12FragmentDecompiler(u32 addr, u32& size, u32 ctrl) : + FragmentProgramDecompiler(addr, size, ctrl) +{ + +} + +std::string D3D12FragmentDecompiler::getFloatTypeName(size_t elementCount) +{ + return getFloatTypeNameImp(elementCount); +} + +std::string D3D12FragmentDecompiler::getFunction(enum class FUNCTION f) +{ + return getFunctionImp(f); +} + +std::string D3D12FragmentDecompiler::saturate(const std::string & code) +{ + return "saturate(" + code + ")"; +} + +std::string D3D12FragmentDecompiler::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1) +{ + return compareFunctionImp(f, Op0, Op1); +} + +void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS) +{ + OS << "cbuffer SCALE_OFFSET : register(b0)" << std::endl; + OS << "{" << std::endl; + OS << " float4x4 scaleOffsetMat;" << std::endl; + OS << " int isAlphaTested;" << std::endl; + OS << " float alphaRef;" << std::endl; + OS << "};" << std::endl; +} + +void D3D12FragmentDecompiler::insertIntputs(std::stringstream & OS) +{ + OS << "struct PixelInput" << std::endl; + OS << "{" << std::endl; + OS << " float4 Position : SV_POSITION;" << std::endl; + OS << " float4 diff_color : COLOR0;" << std::endl; + OS << " float4 spec_color : COLOR1;" << std::endl; + OS << " float4 dst_reg3 : COLOR2;" << std::endl; + OS << " float4 dst_reg4 : COLOR3;" << std::endl; + OS << " float fogc : FOG;" << std::endl; + OS << " float4 dummy : COLOR4;" << std::endl; + OS << " float4 tc0 : TEXCOORD0;" << std::endl; + OS << " float4 tc1 : TEXCOORD1;" << std::endl; + OS << " float4 tc2 : TEXCOORD2;" << std::endl; + OS << " float4 tc3 : TEXCOORD3;" << std::endl; + OS << " float4 tc4 : TEXCOORD4;" << std::endl; + OS << " float4 tc5 : TEXCOORD5;" << std::endl; + OS << " float4 tc6 : TEXCOORD6;" << std::endl; + OS << " float4 tc7 : TEXCOORD7;" << std::endl; + OS << " float4 tc8 : TEXCOORD8;" << std::endl; + OS << "};" << std::endl; +} + +void D3D12FragmentDecompiler::insertOutputs(std::stringstream & OS) +{ + OS << "struct PixelOutput" << std::endl; + OS << "{" << std::endl; + const std::pair table[] = + { + { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, + { "ocol1", m_ctrl & 0x40 ? "r2" : "h4" }, + { "ocol2", m_ctrl & 0x40 ? "r3" : "h6" }, + { "ocol3", m_ctrl & 0x40 ? "r4" : "h8" }, + }; + + for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) + { + if (m_parr.HasParam(PF_PARAM_NONE, "float4", table[i].second)) + OS << " " << "float4" << " " << table[i].first << " : SV_TARGET" << i << ";" << std::endl; + } + OS << "};" << std::endl; +} + +void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS) +{ + OS << "cbuffer CONSTANT : register(b2)" << std::endl; + OS << "{" << std::endl; + for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (PT.type == "sampler2D") + continue; + for (ParamItem PI : PT.items) + OS << " " << PT.type << " " << PI.name << ";" << std::endl; + } + OS << "};" << std::endl << std::endl; + + for (ParamType PT : m_parr.params[PF_PARAM_UNIFORM]) + { + if (PT.type != "sampler2D") + continue; + for (ParamItem PI : PT.items) + { + size_t textureIndex = atoi(PI.name.data() + 3); + OS << "Texture2D " << PI.name << " : register(t" << textureIndex << ");" << std::endl; + OS << "sampler " << PI.name << "sampler : register(s" << textureIndex << ");" << std::endl; + textureIndex++; + } + } +} + +void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS) +{ + OS << "PixelOutput main(PixelInput In)" << std::endl; + OS << "{" << std::endl; + for (ParamType PT : m_parr.params[PF_PARAM_IN]) + { + for (ParamItem PI : PT.items) + OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl; + } + // Declare output + for (ParamType PT : m_parr.params[PF_PARAM_NONE]) + { + for (ParamItem PI : PT.items) + OS << " " << PT.type << " " << PI.name << " = float4(0., 0., 0., 0.);" << std::endl; + } +} + +void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS) +{ + const std::pair table[] = + { + { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, + { "ocol1", m_ctrl & 0x40 ? "r2" : "h4" }, + { "ocol2", m_ctrl & 0x40 ? "r3" : "h6" }, + { "ocol3", m_ctrl & 0x40 ? "r4" : "h8" }, + }; + + OS << " PixelOutput Out;" << std::endl; + for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) + { + if (m_parr.HasParam(PF_PARAM_NONE, "float4", table[i].second)) + OS << " Out." << table[i].first << " = " << table[i].second << ";" << std::endl; + } + OS << " if (isAlphaTested && Out.ocol0.a <= alphaRef) discard;" << std::endl; + OS << " return Out;" << std::endl; + OS << "}" << std::endl; +} + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.h b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.h new file mode 100644 index 0000000000..70b151a73f --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12FragmentProgramDecompiler.h @@ -0,0 +1,26 @@ +#pragma once +#if defined(DX12_SUPPORT) +#include "Emu/RSX/RSXFragmentProgram.h" +#include + +#include "../Common/FragmentProgramDecompiler.h" + +class D3D12FragmentDecompiler : public FragmentProgramDecompiler +{ +protected: + virtual std::string getFloatTypeName(size_t elementCount) override; + virtual std::string getFunction(enum class FUNCTION) override; + virtual std::string saturate(const std::string &code) override; + virtual std::string compareFunction(enum class COMPARE, const std::string &, const std::string &) override; + + virtual void insertHeader(std::stringstream &OS) override; + virtual void insertIntputs(std::stringstream &OS) override; + virtual void insertOutputs(std::stringstream &OS) override; + virtual void insertConstants(std::stringstream &OS) override; + virtual void insertMainStart(std::stringstream &OS) override; + virtual void insertMainEnd(std::stringstream &OS) override; +public: + D3D12FragmentDecompiler(u32 addr, u32& size, u32 ctrl); +}; + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp new file mode 100644 index 0000000000..05367e9f94 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -0,0 +1,1386 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "D3D12GSRender.h" +#include +#include +#include +#include +#include + +PFN_D3D12_CREATE_DEVICE wrapD3D12CreateDevice; +PFN_D3D12_GET_DEBUG_INTERFACE wrapD3D12GetDebugInterface; +PFN_D3D12_SERIALIZE_ROOT_SIGNATURE wrapD3D12SerializeRootSignature; + +static HMODULE D3D12Module; + +static void loadD3D12FunctionPointers() +{ + D3D12Module = LoadLibrary(L"d3d12.dll"); + wrapD3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(D3D12Module, "D3D12CreateDevice"); + wrapD3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(D3D12Module, "D3D12GetDebugInterface"); + wrapD3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)GetProcAddress(D3D12Module, "D3D12SerializeRootSignature"); +} + +static void unloadD3D12FunctionPointers() +{ + FreeLibrary(D3D12Module); +} + +GetGSFrameCb2 GetGSFrame = nullptr; + +void SetGetD3DGSFrameCallback(GetGSFrameCb2 value) +{ + GetGSFrame = value; +} + +GarbageCollectionThread::GarbageCollectionThread() +{ + m_askForTermination = false; + m_worker = std::thread([this]() { + std::unique_lock lock(m_mutex); + while (!m_askForTermination) + { + if (!lock) + { + lock.lock(); + continue; + } + + if (!m_queue.empty()) + { + auto func = std::move(m_queue.front()); + + m_queue.pop(); + + if (lock) lock.unlock(); + + func(); + + continue; + } + cv.wait(lock); + } + }); +} + +GarbageCollectionThread::~GarbageCollectionThread() +{ + { + std::unique_lock lock(m_mutex); + m_askForTermination = true; + cv.notify_one(); + } + m_worker.join(); +} + +void GarbageCollectionThread::pushWork(std::function&& f) +{ + { + std::unique_lock lock(m_mutex); + m_queue.push(f); + } + cv.notify_one(); +} + +void GarbageCollectionThread::waitForCompletion() +{ + pushWork([]() {}); + while (true) + { + std::this_thread::yield(); + std::unique_lock lock(m_mutex); + if (m_queue.empty()) + return; + } +} + +void D3D12GSRender::ResourceStorage::Reset() +{ + m_constantsBufferIndex = 0; + m_currentScaleOffsetBufferIndex = 0; + m_currentTextureIndex = 0; + m_frameFinishedFence = nullptr; + m_frameFinishedHandle = 0; + m_currentSamplerIndex = 0; + m_samplerDescriptorHeapIndex = 0; + + m_commandAllocator->Reset(); + m_textureUploadCommandAllocator->Reset(); + m_downloadCommandAllocator->Reset(); + for (ID3D12GraphicsCommandList *gfxCommandList : m_inflightCommandList) + gfxCommandList->Release(); + m_inflightCommandList.clear(); +} + +void D3D12GSRender::ResourceStorage::Init(ID3D12Device *device) +{ + m_RAMFramebuffer = nullptr; + m_frameFinishedHandle = 0; + // Create a global command allocator + device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator)); + device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_textureUploadCommandAllocator)); + check(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&m_downloadCommandAllocator))); + + D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {}; + descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + descriptorHeapDesc.NumDescriptors = 10000; // For safety + descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + check(device->CreateDescriptorHeap(&descriptorHeapDesc, IID_PPV_ARGS(&m_constantsBufferDescriptorsHeap))); + + + descriptorHeapDesc = {}; + descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + descriptorHeapDesc.NumDescriptors = 10000; // For safety + descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + check(device->CreateDescriptorHeap(&descriptorHeapDesc, IID_PPV_ARGS(&m_scaleOffsetDescriptorHeap))); + + D3D12_DESCRIPTOR_HEAP_DESC textureDescriptorDesc = {}; + textureDescriptorDesc.NumDescriptors = 10000; // For safety + textureDescriptorDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + textureDescriptorDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + check(device->CreateDescriptorHeap(&textureDescriptorDesc, IID_PPV_ARGS(&m_textureDescriptorsHeap))); + + textureDescriptorDesc.NumDescriptors = 2048; // For safety + textureDescriptorDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + check(device->CreateDescriptorHeap(&textureDescriptorDesc, IID_PPV_ARGS(&m_samplerDescriptorHeap[0]))); + check(device->CreateDescriptorHeap(&textureDescriptorDesc, IID_PPV_ARGS(&m_samplerDescriptorHeap[1]))); +} + +void D3D12GSRender::ResourceStorage::Release() +{ + // NOTE: Should be released only if no command are in flight ! + m_constantsBufferDescriptorsHeap->Release(); + m_scaleOffsetDescriptorHeap->Release(); + m_textureDescriptorsHeap->Release(); + m_samplerDescriptorHeap[0]->Release(); + m_samplerDescriptorHeap[1]->Release(); + for (auto &tmp : m_inflightCommandList) + tmp->Release(); + m_commandAllocator->Release(); + m_textureUploadCommandAllocator->Release(); + m_downloadCommandAllocator->Release(); + if (m_frameFinishedHandle) + CloseHandle(m_frameFinishedHandle); + if (m_frameFinishedFence) + m_frameFinishedFence->Release(); +} + + +void D3D12GSRender::Shader::Release() +{ + m_PSO->Release(); + m_rootSignature->Release(); + m_vertexBuffer->Release(); + m_textureDescriptorHeap->Release(); + m_samplerDescriptorHeap->Release(); +} + +extern std::function gfxHandler; + +bool D3D12GSRender::invalidateTexture(u32 addr) +{ + bool handled = false; + auto It = m_protectedTextures.begin(), E = m_protectedTextures.end(); + for (; It != E;) + { + auto currentIt = It; + ++It; + auto protectedTexture = *currentIt; + u32 protectedRangeStart = std::get<1>(protectedTexture), protectedRangeSize = std::get<2>(protectedTexture); + if (addr - protectedRangeStart < protectedRangeSize) + { + std::lock_guard lock(mut); + u32 texadrr = std::get<0>(protectedTexture); + ID3D12Resource *texToErase = m_texturesCache[texadrr]; + m_texturesCache.erase(texadrr); + m_texToClean.push_back(texToErase); + + vm::page_protect(protectedRangeStart, protectedRangeSize, 0, vm::page_writable, 0); + m_protectedTextures.erase(currentIt); + handled = true; + } + } + return handled; +} + +D3D12GSRender::D3D12GSRender() + : GSRender(), m_PSO(nullptr) +{ + gfxHandler = [this](u32 addr) { + bool result = invalidateTexture(addr); + if (result) + LOG_WARNING(RSX, "Reporting Cell writing to %x", addr); + return result; + }; + loadD3D12FunctionPointers(); + if (Ini.GSDebugOutputEnable.GetValue()) + { + Microsoft::WRL::ComPtr debugInterface; + wrapD3D12GetDebugInterface(IID_PPV_ARGS(&debugInterface)); + debugInterface->EnableDebugLayer(); + } + + Microsoft::WRL::ComPtr dxgiFactory; + check(CreateDXGIFactory(IID_PPV_ARGS(&dxgiFactory))); + // Create adapter + IDXGIAdapter* adaptater = nullptr; + switch (Ini.GSD3DAdaptater.GetValue()) + { + case 0: // WARP + check(dxgiFactory->EnumWarpAdapter(IID_PPV_ARGS(&adaptater))); + break; + case 1: // Default + dxgiFactory->EnumAdapters(0, &adaptater); + break; + default: // Adaptater 0, 1, ... + dxgiFactory->EnumAdapters(Ini.GSD3DAdaptater.GetValue() - 2,&adaptater); + break; + } + check(wrapD3D12CreateDevice(adaptater, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device))); + + // Queues + D3D12_COMMAND_QUEUE_DESC copyQueueDesc = {}, graphicQueueDesc = {}; + copyQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY; + graphicQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + check(m_device->CreateCommandQueue(©QueueDesc, IID_PPV_ARGS(&m_commandQueueCopy))); + check(m_device->CreateCommandQueue(&graphicQueueDesc, IID_PPV_ARGS(&m_commandQueueGraphic))); + + g_descriptorStrideSRVCBVUAV = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + g_descriptorStrideDSV = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV); + g_descriptorStrideRTV = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + g_descriptorStrideSamplers = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + + m_frame = GetGSFrame(); + DXGI_ADAPTER_DESC adaptaterDesc; + adaptater->GetDesc(&adaptaterDesc); + m_frame->SetAdaptaterName(adaptaterDesc.Description); + + // Create swap chain and put them in a descriptor heap as rendertarget + DXGI_SWAP_CHAIN_DESC swapChain = {}; + swapChain.BufferCount = 2; + swapChain.Windowed = true; + swapChain.OutputWindow = m_frame->getHandle(); + swapChain.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + swapChain.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + swapChain.SampleDesc.Count = 1; + swapChain.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + swapChain.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + + check(dxgiFactory->CreateSwapChain(m_commandQueueGraphic, &swapChain, (IDXGISwapChain**)&m_swapChain)); + m_swapChain->GetBuffer(0, IID_PPV_ARGS(&m_backBuffer[0])); + m_swapChain->GetBuffer(1, IID_PPV_ARGS(&m_backBuffer[1])); + + D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; + heapDesc.NumDescriptors = 1; + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + D3D12_RENDER_TARGET_VIEW_DESC rttDesc = {}; + rttDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rttDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + m_device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_backbufferAsRendertarget[0])); + m_device->CreateRenderTargetView(m_backBuffer[0], &rttDesc, m_backbufferAsRendertarget[0]->GetCPUDescriptorHandleForHeapStart()); + m_device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_backbufferAsRendertarget[1])); + m_device->CreateRenderTargetView(m_backBuffer[1], &rttDesc, m_backbufferAsRendertarget[1]->GetCPUDescriptorHandleForHeapStart()); + + // Common root signatures + for (unsigned textureCount = 0; textureCount < 17; textureCount++) + { + D3D12_DESCRIPTOR_RANGE descriptorRange[4] = {}; + // Scale Offset data + descriptorRange[0].BaseShaderRegister = 0; + descriptorRange[0].NumDescriptors = 1; + descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + // Constants + descriptorRange[1].BaseShaderRegister = 1; + descriptorRange[1].NumDescriptors = 2; + descriptorRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + // Textures + descriptorRange[2].BaseShaderRegister = 0; + descriptorRange[2].NumDescriptors = textureCount; + descriptorRange[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + // Samplers + descriptorRange[3].BaseShaderRegister = 0; + descriptorRange[3].NumDescriptors = textureCount; + descriptorRange[3].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + D3D12_ROOT_PARAMETER RP[4] = {}; + RP[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP[0].DescriptorTable.pDescriptorRanges = &descriptorRange[0]; + RP[0].DescriptorTable.NumDescriptorRanges = 1; + RP[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP[1].DescriptorTable.pDescriptorRanges = &descriptorRange[1]; + RP[1].DescriptorTable.NumDescriptorRanges = 1; + RP[2].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP[2].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP[2].DescriptorTable.pDescriptorRanges = &descriptorRange[2]; + RP[2].DescriptorTable.NumDescriptorRanges = 1; + RP[3].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP[3].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP[3].DescriptorTable.pDescriptorRanges = &descriptorRange[3]; + RP[3].DescriptorTable.NumDescriptorRanges = 1; + + D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; + rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + rootSignatureDesc.NumParameters = (textureCount > 0) ? 4 : 2; + rootSignatureDesc.pParameters = RP; + + Microsoft::WRL::ComPtr rootSignatureBlob; + Microsoft::WRL::ComPtr errorBlob; + check(wrapD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob)); + + m_device->CreateRootSignature(0, + rootSignatureBlob->GetBufferPointer(), + rootSignatureBlob->GetBufferSize(), + IID_PPV_ARGS(&m_rootSignatures[textureCount])); + } + + m_perFrameStorage[0].Init(m_device); + m_perFrameStorage[0].Reset(); + m_perFrameStorage[1].Init(m_device); + m_perFrameStorage[1].Reset(); + + initConvertShader(); + m_outputScalingPass.Init(m_device); + + D3D12_HEAP_PROPERTIES hp = {}; + hp.Type = D3D12_HEAP_TYPE_DEFAULT; + check( + m_device->CreateCommittedResource( + &hp, + D3D12_HEAP_FLAG_NONE, + &getTexture2DResourceDesc(2, 2, DXGI_FORMAT_R8G8B8A8_UNORM, 1), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&m_dummyTexture)) + ); + + m_readbackResources.Init(m_device, 1024 * 1024 * 128, D3D12_HEAP_TYPE_READBACK, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS); + m_UAVHeap.Init(m_device, 1024 * 1024 * 128, D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES); + + m_rtts.Init(m_device); + + m_constantsData.Init(m_device, 1024 * 1024 * 64, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_NONE); + m_vertexIndexData.Init(m_device, 1024 * 1024 * 384, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS); + m_textureUploadData.Init(m_device, 1024 * 1024 * 256, D3D12_HEAP_TYPE_UPLOAD, D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS); +} + +D3D12GSRender::~D3D12GSRender() +{ + gfxHandler = [this](u32) { return false; }; + m_constantsData.Release(); + m_vertexIndexData.Release(); + m_textureUploadData.Release(); + m_UAVHeap.m_heap->Release(); + m_readbackResources.m_heap->Release(); + m_texturesRTTs.clear(); + m_dummyTexture->Release(); + m_convertPSO->Release(); + m_convertRootSignature->Release(); + m_perFrameStorage[0].Release(); + m_perFrameStorage[1].Release(); + m_commandQueueGraphic->Release(); + m_commandQueueCopy->Release(); + m_backbufferAsRendertarget[0]->Release(); + m_backBuffer[0]->Release(); + m_backbufferAsRendertarget[1]->Release(); + m_backBuffer[1]->Release(); + m_rtts.Release(); + for (unsigned i = 0; i < 17; i++) + m_rootSignatures[i]->Release(); + for (auto &tmp : m_texToClean) + tmp->Release(); + for (auto &tmp : m_texturesCache) + tmp.second->Release(); + m_swapChain->Release(); + m_outputScalingPass.Release(); + m_device->Release(); + unloadD3D12FunctionPointers(); +} + +void D3D12GSRender::Close() +{ + if (joinable()) + { + join(); + } + + if (m_frame->IsShown()) + { + m_frame->Hide(); + } +} + +void D3D12GSRender::OnInit() +{ + m_frame->Show(); +} + +void D3D12GSRender::OnInitThread() +{ +} + +void D3D12GSRender::OnExitThread() +{ +} + +void D3D12GSRender::OnReset() +{ +} + +void D3D12GSRender::Clear(u32 cmd) +{ + assert(cmd == NV4097_CLEAR_SURFACE); + + PrepareRenderTargets(); + + ID3D12GraphicsCommandList *commandList; + check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList))); + getCurrentResourceStorage().m_inflightCommandList.push_back(commandList); + +/* if (m_set_color_mask) + { + glColorMask(m_color_mask_r, m_color_mask_g, m_color_mask_b, m_color_mask_a); + checkForGlError("glColorMask"); + } + + if (m_set_scissor_horizontal && m_set_scissor_vertical) + { + glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); + checkForGlError("glScissor"); + }*/ + + // TODO: Merge depth and stencil clear when possible + if (m_clear_surface_mask & 0x1) + { + u32 max_depth_value = m_surface_depth_format == CELL_GCM_SURFACE_Z16 ? 0x0000ffff : 0x00ffffff; + commandList->ClearDepthStencilView(m_rtts.m_depthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, m_clear_surface_z / (float)max_depth_value, 0, 0, nullptr); + } + + if (m_clear_surface_mask & 0x2) + commandList->ClearDepthStencilView(m_rtts.m_depthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_STENCIL, 0.f, m_clear_surface_s, 0, nullptr); + + if (m_clear_surface_mask & 0xF0) + { + float clearColor[] = + { + m_clear_surface_color_r / 255.0f, + m_clear_surface_color_g / 255.0f, + m_clear_surface_color_b / 255.0f, + m_clear_surface_color_a / 255.0f + }; + + D3D12_CPU_DESCRIPTOR_HANDLE handle = m_rtts.m_renderTargetsDescriptorsHeap->GetCPUDescriptorHandleForHeapStart(); + size_t g_RTTIncrement = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + switch (m_surface_color_target) + { + case CELL_GCM_SURFACE_TARGET_NONE: break; + + case CELL_GCM_SURFACE_TARGET_0: + case CELL_GCM_SURFACE_TARGET_1: + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, 0), clearColor, 0, nullptr); + break; + case CELL_GCM_SURFACE_TARGET_MRT1: + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, 0), clearColor, 0, nullptr); + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, g_descriptorStrideRTV), clearColor, 0, nullptr); + break; + case CELL_GCM_SURFACE_TARGET_MRT2: + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, 0), clearColor, 0, nullptr); + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, g_descriptorStrideRTV), clearColor, 0, nullptr); + handle.ptr += g_RTTIncrement; + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, 2 * g_descriptorStrideRTV), clearColor, 0, nullptr); + break; + case CELL_GCM_SURFACE_TARGET_MRT3: + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, 0), clearColor, 0, nullptr); + handle.ptr += g_RTTIncrement; + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, g_descriptorStrideRTV), clearColor, 0, nullptr); + handle.ptr += g_RTTIncrement; + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, 2 * g_descriptorStrideRTV), clearColor, 0, nullptr); + handle.ptr += g_RTTIncrement; + commandList->ClearRenderTargetView(getCPUDescriptorHandle(m_rtts.m_renderTargetsDescriptorsHeap, 3 * g_descriptorStrideRTV), clearColor, 0, nullptr); + break; + default: + LOG_ERROR(RSX, "Bad surface color target: %d", m_surface_color_target); + } + } + + check(commandList->Close()); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**) &commandList); +} + +void D3D12GSRender::Draw() +{ + PrepareRenderTargets(); + + // Init vertex count + // TODO: Very hackish, clean this + if (m_indexed_array.m_count) + { + for (u32 i = 0; i < m_vertex_count; ++i) + { + if (!m_vertex_data[i].IsEnabled()) continue; + if (!m_vertex_data[i].addr) continue; + + const u32 tsize = m_vertex_data[i].GetTypeSize(); + m_vertex_data[i].data.resize((m_indexed_array.index_min + m_indexed_array.index_max - m_indexed_array.index_min + 1) * tsize * m_vertex_data[i].size); + } + } + else + { + for (u32 i = 0; i < m_vertex_count; ++i) + { + if (!m_vertex_data[i].IsEnabled()) continue; + if (!m_vertex_data[i].addr) continue; + + const u32 tsize = m_vertex_data[i].GetTypeSize(); + m_vertex_data[i].data.resize((m_draw_array_first + m_draw_array_count) * tsize * m_vertex_data[i].size); + } + } + + ID3D12GraphicsCommandList *commandList; + m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList)); + getCurrentResourceStorage().m_inflightCommandList.push_back(commandList); + + + std::chrono::time_point startVertexTime = std::chrono::system_clock::now(); + if (m_indexed_array.m_count || m_draw_array_count) + { + const std::vector &vertexBufferViews = UploadVertexBuffers(m_indexed_array.m_count ? true : false); + const D3D12_INDEX_BUFFER_VIEW &indexBufferView = uploadIndexBuffers(m_indexed_array.m_count ? true : false); + commandList->IASetVertexBuffers(0, (UINT)vertexBufferViews.size(), vertexBufferViews.data()); + if (m_renderingInfo.m_indexed) + commandList->IASetIndexBuffer(&indexBufferView); + } + std::chrono::time_point endVertexTime = std::chrono::system_clock::now(); + m_timers.m_vertexUploadDuration += std::chrono::duration_cast(endVertexTime - startVertexTime).count(); + + if (!LoadProgram()) + { + LOG_ERROR(RSX, "LoadProgram failed."); + Emu.Pause(); + return; + } + + commandList->SetGraphicsRootSignature(m_rootSignatures[m_PSO->second]); + commandList->OMSetStencilRef(m_stencil_func_ref); + + // Constants + setScaleOffset(); + commandList->SetDescriptorHeaps(1, &getCurrentResourceStorage().m_scaleOffsetDescriptorHeap); + commandList->SetGraphicsRootDescriptorTable(0, + getGPUDescriptorHandle(getCurrentResourceStorage().m_scaleOffsetDescriptorHeap, + getCurrentResourceStorage().m_currentScaleOffsetBufferIndex * g_descriptorStrideSRVCBVUAV) + ); + getCurrentResourceStorage().m_currentScaleOffsetBufferIndex++; + + size_t currentBufferIndex = getCurrentResourceStorage().m_constantsBufferIndex; + FillVertexShaderConstantsBuffer(); + getCurrentResourceStorage().m_constantsBufferIndex++; + FillPixelShaderConstantsBuffer(); + getCurrentResourceStorage().m_constantsBufferIndex++; + + commandList->SetDescriptorHeaps(1, &getCurrentResourceStorage().m_constantsBufferDescriptorsHeap); + commandList->SetGraphicsRootDescriptorTable(1, + getGPUDescriptorHandle(getCurrentResourceStorage().m_constantsBufferDescriptorsHeap, + currentBufferIndex * g_descriptorStrideSRVCBVUAV) + ); + commandList->SetPipelineState(m_PSO->first); + + if (m_PSO->second > 0) + { + std::chrono::time_point startTextureTime = std::chrono::system_clock::now(); + size_t usedTexture = UploadTextures(); + + // Fill empty slots + for (; usedTexture < m_PSO->second; usedTexture++) + { + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( + D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, + D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, + D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, + D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0); + m_device->CreateShaderResourceView(m_dummyTexture, &srvDesc, + getCPUDescriptorHandle(getCurrentResourceStorage().m_textureDescriptorsHeap, + (getCurrentResourceStorage().m_currentTextureIndex + usedTexture) * g_descriptorStrideSRVCBVUAV) + ); + + D3D12_SAMPLER_DESC samplerDesc = {}; + samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT; + samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + m_device->CreateSampler(&samplerDesc, + getCPUDescriptorHandle(getCurrentResourceStorage().m_samplerDescriptorHeap[getCurrentResourceStorage().m_samplerDescriptorHeapIndex], + (getCurrentResourceStorage().m_currentSamplerIndex + usedTexture) * g_descriptorStrideSamplers) + ); + } + + commandList->SetDescriptorHeaps(1, &getCurrentResourceStorage().m_textureDescriptorsHeap); + commandList->SetGraphicsRootDescriptorTable(2, + getGPUDescriptorHandle(getCurrentResourceStorage().m_textureDescriptorsHeap, + getCurrentResourceStorage().m_currentTextureIndex * g_descriptorStrideSRVCBVUAV) + ); + + commandList->SetDescriptorHeaps(1, &getCurrentResourceStorage().m_samplerDescriptorHeap[getCurrentResourceStorage().m_samplerDescriptorHeapIndex]); + commandList->SetGraphicsRootDescriptorTable(3, + getGPUDescriptorHandle(getCurrentResourceStorage().m_samplerDescriptorHeap[getCurrentResourceStorage().m_samplerDescriptorHeapIndex], + getCurrentResourceStorage().m_currentTextureIndex * g_descriptorStrideSamplers) + ); + + getCurrentResourceStorage().m_currentTextureIndex += usedTexture; + getCurrentResourceStorage().m_currentSamplerIndex += usedTexture; + std::chrono::time_point endTextureTime = std::chrono::system_clock::now(); + m_timers.m_textureUploadDuration += std::chrono::duration_cast(endTextureTime - startTextureTime).count(); + } + + size_t numRTT; + switch (m_surface_color_target) + { + case CELL_GCM_SURFACE_TARGET_NONE: break; + case CELL_GCM_SURFACE_TARGET_0: + case CELL_GCM_SURFACE_TARGET_1: + numRTT = 1; + break; + case CELL_GCM_SURFACE_TARGET_MRT1: + numRTT = 2; + break; + case CELL_GCM_SURFACE_TARGET_MRT2: + numRTT = 3; + break; + case CELL_GCM_SURFACE_TARGET_MRT3: + numRTT = 4; + break; + default: + LOG_ERROR(RSX, "Bad surface color target: %d", m_surface_color_target); + } + + commandList->OMSetRenderTargets((UINT)numRTT, &m_rtts.m_renderTargetsDescriptorsHeap->GetCPUDescriptorHandleForHeapStart(), true, + &getCPUDescriptorHandle(m_rtts.m_depthStencilDescriptorHeap, 0)); + + D3D12_VIEWPORT viewport = + { + 0.f, + 0.f, + (float)m_surface_clip_w, + (float)m_surface_clip_h, + -1.f, + 1.f + }; + commandList->RSSetViewports(1, &viewport); + + D3D12_RECT box = + { + 0, + 0, + (LONG)m_surface_clip_w, + (LONG)m_surface_clip_h, + }; + commandList->RSSetScissorRects(1, &box); + + switch (m_draw_mode - 1) + { + case GL_POINTS: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_POINTLIST); + break; + case GL_LINES: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST); + break; + case GL_LINE_LOOP: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ); + break; + case GL_LINE_STRIP: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_LINESTRIP); + break; + case GL_TRIANGLES: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + break; + case GL_TRIANGLE_STRIP: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + break; + case GL_TRIANGLE_FAN: + case GL_QUADS: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + break; + case GL_QUAD_STRIP: + case GL_POLYGON: + default: + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + LOG_ERROR(RSX, "Unsupported primitive type"); + break; + } + + if (m_renderingInfo.m_indexed) + commandList->DrawIndexedInstanced((UINT)m_renderingInfo.m_count, 1, 0, (UINT)m_renderingInfo.m_baseVertex, 0); + else + commandList->DrawInstanced((UINT)m_renderingInfo.m_count, 1, (UINT)m_renderingInfo.m_baseVertex, 0); + + check(commandList->Close()); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&commandList); + m_indexed_array.Reset(); +} + +static bool +isFlipSurfaceInLocalMemory(u32 surfaceColorTarget) +{ + switch (surfaceColorTarget) + { + case CELL_GCM_SURFACE_TARGET_0: + case CELL_GCM_SURFACE_TARGET_1: + case CELL_GCM_SURFACE_TARGET_MRT1: + case CELL_GCM_SURFACE_TARGET_MRT2: + case CELL_GCM_SURFACE_TARGET_MRT3: + return true; + case CELL_GCM_SURFACE_TARGET_NONE: + default: + return false; + } +} + +void D3D12GSRender::Flip() +{ + ID3D12GraphicsCommandList *commandList; + m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_commandAllocator, nullptr, IID_PPV_ARGS(&commandList)); + getCurrentResourceStorage().m_inflightCommandList.push_back(commandList); + + ID3D12Resource *resourceToFlip; + float viewport_w, viewport_h; + + if (!isFlipSurfaceInLocalMemory(m_surface_color_target)) + { + ResourceStorage &storage = getCurrentResourceStorage(); + assert(storage.m_RAMFramebuffer == nullptr); + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; + + size_t w = 0, h = 0, rowPitch = 0; + + ID3D12Resource *stagingTexture; + if (m_read_buffer) + { + CellGcmDisplayInfo* buffers = vm::get_ptr(m_gcm_buffers_addr); + u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL); + w = buffers[m_gcm_current_buffer].width; + h = buffers[m_gcm_current_buffer].height; + u8 *src_buffer = vm::get_ptr(addr); + + rowPitch = align(w * 4, 256); + size_t textureSize = rowPitch * h; // * 4 for mipmap levels + assert(m_textureUploadData.canAlloc(textureSize)); + size_t heapOffset = m_textureUploadData.alloc(textureSize); + + check(m_device->CreatePlacedResource( + m_textureUploadData.m_heap, + heapOffset, + &getBufferResourceDesc(textureSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&stagingTexture) + )); + m_textureUploadData.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, textureSize, stagingTexture)); + + void *dstBuffer; + check(stagingTexture->Map(0, nullptr, &dstBuffer)); + for (unsigned row = 0; row < h; row++) + memcpy((char*)dstBuffer + row * rowPitch, (char*)src_buffer + row * w * 4, w * 4); + stagingTexture->Unmap(0, nullptr); + } + + check( + m_device->CreateCommittedResource( + &heapProp, + D3D12_HEAP_FLAG_NONE, + &getTexture2DResourceDesc(w, h, DXGI_FORMAT_R8G8B8A8_UNORM, 1), + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&storage.m_RAMFramebuffer) + ) + ); + D3D12_TEXTURE_COPY_LOCATION src = {}, dst = {}; + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + dst.pResource = storage.m_RAMFramebuffer; + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.pResource = stagingTexture; + src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + src.PlacedFootprint.Footprint.Width = (UINT)w; + src.PlacedFootprint.Footprint.Height = (UINT)h; + src.PlacedFootprint.Footprint.Depth = (UINT)1; + src.PlacedFootprint.Footprint.RowPitch = (UINT)rowPitch; + commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + + commandList->ResourceBarrier(1, &getResourceBarrierTransition(storage.m_RAMFramebuffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ)); + resourceToFlip = storage.m_RAMFramebuffer; + viewport_w = (float)w, viewport_h = (float)h; + } + else + { + commandList->ResourceBarrier(1, &getResourceBarrierTransition(m_rtts.m_currentlyBoundRenderTargets[0], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); + resourceToFlip = m_rtts.m_currentlyBoundRenderTargets[0]; + } + + commandList->ResourceBarrier(1, &getResourceBarrierTransition(m_backBuffer[m_swapChain->GetCurrentBackBufferIndex()], D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); + + D3D12_VIEWPORT viewport = + { + 0.f, + 0.f, + (float)m_backBuffer[m_swapChain->GetCurrentBackBufferIndex()]->GetDesc().Width, + (float)m_backBuffer[m_swapChain->GetCurrentBackBufferIndex()]->GetDesc().Height, + 0.f, + 1.f + }; + commandList->RSSetViewports(1, &viewport); + + D3D12_RECT box = + { + 0, + 0, + (LONG)m_backBuffer[m_swapChain->GetCurrentBackBufferIndex()]->GetDesc().Width, + (LONG)m_backBuffer[m_swapChain->GetCurrentBackBufferIndex()]->GetDesc().Height, + }; + commandList->RSSetScissorRects(1, &box); + commandList->SetGraphicsRootSignature(m_outputScalingPass.m_rootSignature); + commandList->SetPipelineState(m_outputScalingPass.m_PSO); + D3D12_CPU_DESCRIPTOR_HANDLE CPUHandle; + CPUHandle = m_outputScalingPass.m_textureDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); + CPUHandle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) * m_swapChain->GetCurrentBackBufferIndex(); + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + // FIXME: Not always true + srvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = 1; + if (isFlipSurfaceInLocalMemory(m_surface_color_target)) + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + else + srvDesc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0 + ); + m_device->CreateShaderResourceView(resourceToFlip, &srvDesc, CPUHandle); + + D3D12_SAMPLER_DESC samplerDesc = {}; + samplerDesc.Filter = D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT; + samplerDesc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + samplerDesc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + samplerDesc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP; + CPUHandle = m_outputScalingPass.m_samplerDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); + CPUHandle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) * m_swapChain->GetCurrentBackBufferIndex(); + m_device->CreateSampler(&samplerDesc, CPUHandle); + + D3D12_GPU_DESCRIPTOR_HANDLE GPUHandle; + GPUHandle = m_outputScalingPass.m_textureDescriptorHeap->GetGPUDescriptorHandleForHeapStart(); + GPUHandle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) * m_swapChain->GetCurrentBackBufferIndex(); + commandList->SetDescriptorHeaps(1, &m_outputScalingPass.m_textureDescriptorHeap); + commandList->SetGraphicsRootDescriptorTable(0, GPUHandle); + GPUHandle = m_outputScalingPass.m_samplerDescriptorHeap->GetGPUDescriptorHandleForHeapStart(); + GPUHandle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) * m_swapChain->GetCurrentBackBufferIndex(); + commandList->SetDescriptorHeaps(1, &m_outputScalingPass.m_samplerDescriptorHeap); + commandList->SetGraphicsRootDescriptorTable(1, GPUHandle); + + CPUHandle = m_backbufferAsRendertarget[m_swapChain->GetCurrentBackBufferIndex()]->GetCPUDescriptorHandleForHeapStart(); + commandList->OMSetRenderTargets(1, &CPUHandle, true, nullptr); + D3D12_VERTEX_BUFFER_VIEW vbv = {}; + vbv.BufferLocation = m_outputScalingPass.m_vertexBuffer->GetGPUVirtualAddress(); + vbv.StrideInBytes = 4 * sizeof(float); + vbv.SizeInBytes = 16 * sizeof(float); + commandList->IASetVertexBuffers(0, 1, &vbv); + commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + + commandList->DrawInstanced(4, 1, 0, 0); + + commandList->ResourceBarrier(1, &getResourceBarrierTransition(m_backBuffer[m_swapChain->GetCurrentBackBufferIndex()], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); + if (isFlipSurfaceInLocalMemory(m_surface_color_target)) + commandList->ResourceBarrier(1, &getResourceBarrierTransition(m_rtts.m_currentlyBoundRenderTargets[0], D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET)); + check(commandList->Close()); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&commandList); + + check(m_swapChain->Present(Ini.GSVSyncEnable.GetValue() ? 1 : 0, 0)); + // Add an event signaling queue completion + + ResourceStorage &storage = getNonCurrentResourceStorage(); + + m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&storage.m_frameFinishedFence)); + storage.m_frameFinishedHandle = CreateEvent(0, 0, 0, 0); + storage.m_frameFinishedFence->SetEventOnCompletion(1, storage.m_frameFinishedHandle); + m_commandQueueGraphic->Signal(storage.m_frameFinishedFence, 1); + + // Flush + m_texturesRTTs.clear(); + m_vertexCache.clear(); + m_vertexConstants.clear(); + + std::vector > cleaningFunction = + { + m_constantsData.getCleaningFunction(), + m_vertexIndexData.getCleaningFunction(), + m_textureUploadData.getCleaningFunction(), + }; + + std::lock_guard lock(mut); + std::vector textoclean = m_texToClean; + m_texToClean.clear(); + + m_GC.pushWork([&, cleaningFunction, textoclean]() + { + WaitForSingleObject(storage.m_frameFinishedHandle, INFINITE); + CloseHandle(storage.m_frameFinishedHandle); + storage.m_frameFinishedFence->Release(); + + for (auto &cleanFunc : cleaningFunction) + cleanFunc(); + storage.Reset(); + + for (auto tmp : textoclean) + tmp->Release(); + + SAFE_RELEASE(storage.m_RAMFramebuffer); + storage.m_RAMFramebuffer = nullptr; + }); + + while (getCurrentResourceStorage().m_frameFinishedHandle) + std::this_thread::yield(); + m_frame->Flip(nullptr); + + // FIXME: Without this call Voodoo Chronicles + Warp trigger an error because + // index/vertex resources are released before being used. + m_GC.waitForCompletion(); + + ResetTimer(); +} + +void D3D12GSRender::ResetTimer() +{ + m_timers.m_textureUploadDuration = 0; + m_timers.m_vertexUploadDuration = 0; +} + +D3D12GSRender::ResourceStorage& D3D12GSRender::getCurrentResourceStorage() +{ + return m_perFrameStorage[m_swapChain->GetCurrentBackBufferIndex()]; +} + +D3D12GSRender::ResourceStorage& D3D12GSRender::getNonCurrentResourceStorage() +{ + return m_perFrameStorage[1 - m_swapChain->GetCurrentBackBufferIndex()]; +} + +ID3D12Resource * D3D12GSRender::writeColorBuffer(ID3D12Resource * RTT, ID3D12GraphicsCommandList * cmdlist) +{ + ID3D12Resource *Result; + size_t w = m_surface_clip_w, h = m_surface_clip_h; + DXGI_FORMAT dxgiFormat; + size_t rowPitch; + switch (m_surface_color_format) + { + case CELL_GCM_SURFACE_A8R8G8B8: + dxgiFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + rowPitch = align(w * 4, 256); + break; + case CELL_GCM_SURFACE_F_W16Z16Y16X16: + dxgiFormat = DXGI_FORMAT_R16G16B16A16_FLOAT; + rowPitch = align(w * 8, 256); + break; + } + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_READBACK; + D3D12_RESOURCE_DESC resdesc = getBufferResourceDesc(rowPitch * h); + + size_t sizeInByte = rowPitch * h; + assert(m_readbackResources.canAlloc(sizeInByte)); + size_t heapOffset = m_readbackResources.alloc(sizeInByte); + + resdesc = getBufferResourceDesc(sizeInByte); + check( + m_device->CreatePlacedResource( + m_readbackResources.m_heap, + heapOffset, + &resdesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&Result) + ) + ); + m_readbackResources.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, sizeInByte, Result)); + + cmdlist->ResourceBarrier(1, &getResourceBarrierTransition(RTT, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE)); + + D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; + src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.pResource = RTT; + dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst.pResource = Result; + dst.PlacedFootprint.Offset = 0; + dst.PlacedFootprint.Footprint.Depth = 1; + dst.PlacedFootprint.Footprint.Format = dxgiFormat; + dst.PlacedFootprint.Footprint.Height = (UINT)h; + dst.PlacedFootprint.Footprint.Width = (UINT)w; + dst.PlacedFootprint.Footprint.RowPitch = (UINT)rowPitch; + cmdlist->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + cmdlist->ResourceBarrier(1, &getResourceBarrierTransition(RTT, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); + return Result; +} + +static +void copyToCellRamAndRelease(void *dstAddress, ID3D12Resource *res, size_t dstPitch, size_t srcPitch, size_t width, size_t height) +{ + void *srcBuffer; + check(res->Map(0, nullptr, &srcBuffer)); + for (unsigned row = 0; row < height; row++) + memcpy((char*)dstAddress + row * dstPitch, (char*)srcBuffer + row * srcPitch, srcPitch); + res->Unmap(0, nullptr); + res->Release(); +} + +void D3D12GSRender::semaphorePGRAPHTextureReadRelease(u32 offset, u32 value) +{ + semaphorePGRAPHBackendRelease(offset, value); +} + +void D3D12GSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value) +{ + // Add all buffer write + // Cell can't make any assumption about readyness of color/depth buffer + // Except when a semaphore is written by RSX + + + ID3D12Fence *fence; + check( + m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)) + ); + HANDLE handle = CreateEvent(0, FALSE, FALSE, 0); + fence->SetEventOnCompletion(1, handle); + + ID3D12Resource *writeDest, *depthConverted; + ID3D12GraphicsCommandList *convertCommandList; + ID3D12DescriptorHeap *descriptorHeap; + size_t depthRowPitch = m_surface_clip_w; + depthRowPitch = (depthRowPitch + 255) & ~255; + + bool needTransfer = (m_set_context_dma_z && Ini.GSDumpDepthBuffer.GetValue()) || + ((m_set_context_dma_color_a || m_set_context_dma_color_b || m_set_context_dma_color_c || m_set_context_dma_color_d) && Ini.GSDumpColorBuffers.GetValue()); + + if (m_set_context_dma_z && Ini.GSDumpDepthBuffer.GetValue()) + { + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; + D3D12_RESOURCE_DESC resdesc = getTexture2DResourceDesc(m_surface_clip_w, m_surface_clip_h, DXGI_FORMAT_R8_UNORM, 1); + resdesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + size_t sizeInByte = m_surface_clip_w * m_surface_clip_h * 2; + assert(m_UAVHeap.canAlloc(sizeInByte)); + size_t heapOffset = m_UAVHeap.alloc(sizeInByte); + + check( + m_device->CreatePlacedResource( + m_UAVHeap.m_heap, + heapOffset, + &resdesc, + D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + nullptr, + IID_PPV_ARGS(&depthConverted) + ) + ); + m_UAVHeap.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, sizeInByte, depthConverted)); + + sizeInByte = depthRowPitch * m_surface_clip_h; + assert(m_readbackResources.canAlloc(sizeInByte)); + heapOffset = m_readbackResources.alloc(sizeInByte); + + resdesc = getBufferResourceDesc(sizeInByte); + check( + m_device->CreatePlacedResource( + m_readbackResources.m_heap, + heapOffset, + &resdesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&writeDest) + ) + ); + m_readbackResources.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, sizeInByte, writeDest)); + + check( + m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_commandAllocator, nullptr, IID_PPV_ARGS(&convertCommandList)) + ); + + D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {}; + descriptorHeapDesc.NumDescriptors = 2; + descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + descriptorHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + check( + m_device->CreateDescriptorHeap(&descriptorHeapDesc, IID_PPV_ARGS(&descriptorHeap)) + ); + D3D12_CPU_DESCRIPTOR_HANDLE Handle = descriptorHeap->GetCPUDescriptorHandleForHeapStart(); + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + switch (m_surface_depth_format) + { + case 0: + break; + case CELL_GCM_SURFACE_Z16: + srvDesc.Format = DXGI_FORMAT_R16_UNORM; + break; + case CELL_GCM_SURFACE_Z24S8: + srvDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS; + break; + default: + LOG_ERROR(RSX, "Bad depth format! (%d)", m_surface_depth_format); + assert(0); + } + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Texture2D.MipLevels = 1; + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + m_device->CreateShaderResourceView(m_rtts.m_currentlyBoundDepthStencil, &srvDesc, Handle); + Handle.ptr += m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + uavDesc.Format = DXGI_FORMAT_R8_UNORM; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D; + m_device->CreateUnorderedAccessView(depthConverted, nullptr, &uavDesc, Handle); + + // Convert + convertCommandList->ResourceBarrier(1, &getResourceBarrierTransition(m_rtts.m_currentlyBoundDepthStencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ)); + + convertCommandList->SetPipelineState(m_convertPSO); + convertCommandList->SetComputeRootSignature(m_convertRootSignature); + convertCommandList->SetDescriptorHeaps(1, &descriptorHeap); + convertCommandList->SetComputeRootDescriptorTable(0, descriptorHeap->GetGPUDescriptorHandleForHeapStart()); + convertCommandList->Dispatch(m_surface_clip_w / 8, m_surface_clip_h / 8, 1); + + // Flush UAV + D3D12_RESOURCE_BARRIER uavbarrier = {}; + uavbarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; + uavbarrier.UAV.pResource = depthConverted; + + D3D12_RESOURCE_BARRIER barriers[] = + { + getResourceBarrierTransition(m_rtts.m_currentlyBoundDepthStencil, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE), + uavbarrier, + }; + convertCommandList->ResourceBarrier(2, barriers); + convertCommandList->ResourceBarrier(1, &getResourceBarrierTransition(depthConverted, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE)); + + check(convertCommandList->Close()); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&convertCommandList); + } + + ID3D12GraphicsCommandList *downloadCommandList; + if (needTransfer) + { + check( + m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_commandAllocator, nullptr, IID_PPV_ARGS(&downloadCommandList)) + ); + } + + if (m_set_context_dma_z && Ini.GSDumpDepthBuffer.GetValue()) + { + // Copy + D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; + src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.pResource = depthConverted; + dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst.pResource = writeDest; + dst.PlacedFootprint.Offset = 0; + dst.PlacedFootprint.Footprint.Depth = 1; + dst.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8_UNORM; + dst.PlacedFootprint.Footprint.Height = m_surface_clip_h; + dst.PlacedFootprint.Footprint.Width = m_surface_clip_w; + dst.PlacedFootprint.Footprint.RowPitch = (UINT)depthRowPitch; + downloadCommandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + + invalidateTexture(GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000)); + } + + ID3D12Resource *rtt0, *rtt1, *rtt2, *rtt3; + if (Ini.GSDumpColorBuffers.GetValue()) + { + switch (m_surface_color_target) + { + case CELL_GCM_SURFACE_TARGET_NONE: + break; + + case CELL_GCM_SURFACE_TARGET_0: + if (m_context_dma_color_a) rtt0 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[0], downloadCommandList); + break; + + case CELL_GCM_SURFACE_TARGET_1: + if (m_context_dma_color_b) rtt1 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[0], downloadCommandList); + break; + + case CELL_GCM_SURFACE_TARGET_MRT1: + if (m_context_dma_color_a) rtt0 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[0], downloadCommandList); + if (m_context_dma_color_b) rtt1 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[1], downloadCommandList); + break; + + case CELL_GCM_SURFACE_TARGET_MRT2: + if (m_context_dma_color_a) rtt0 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[0], downloadCommandList); + if (m_context_dma_color_b) rtt1 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[1], downloadCommandList); + if (m_context_dma_color_c) rtt2 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[2], downloadCommandList); + break; + + case CELL_GCM_SURFACE_TARGET_MRT3: + if (m_context_dma_color_a) rtt0 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[0], downloadCommandList); + if (m_context_dma_color_b) rtt1 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[1], downloadCommandList); + if (m_context_dma_color_c) rtt2 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[2], downloadCommandList); + if (m_context_dma_color_d) rtt3 = writeColorBuffer(m_rtts.m_currentlyBoundRenderTargets[3], downloadCommandList); + break; + } + + invalidateTexture(GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000)); + invalidateTexture(GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000)); + invalidateTexture(GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000)); + invalidateTexture(GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000)); + } + if (needTransfer) + { + check(downloadCommandList->Close()); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&downloadCommandList); + } + + //Wait for result + m_commandQueueGraphic->Signal(fence, 1); + + + auto depthUAVCleaning = m_UAVHeap.getCleaningFunction(); + auto readbackCleaning = m_readbackResources.getCleaningFunction(); + + m_GC.pushWork([=]() { + WaitForSingleObject(handle, INFINITE); + CloseHandle(handle); + fence->Release(); + + if (m_set_context_dma_z && Ini.GSDumpDepthBuffer.GetValue()) + { + u32 address = GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000); + auto ptr = vm::get_ptr(address); + char *ptrAsChar = (char*)ptr; + unsigned char *writeDestPtr; + check(writeDest->Map(0, nullptr, (void**)&writeDestPtr)); + // TODO : this should be done by the gpu + for (unsigned row = 0; row < m_surface_clip_h; row++) + { + for (unsigned i = 0; i < m_surface_clip_w; i++) + { + unsigned char c = writeDestPtr[row * depthRowPitch + i]; + ptrAsChar[4 * (row * m_surface_clip_w + i)] = c; + ptrAsChar[4 * (row * m_surface_clip_w + i) + 1] = c; + ptrAsChar[4 * (row * m_surface_clip_w + i) + 2] = c; + ptrAsChar[4 * (row * m_surface_clip_w + i) + 3] = c; + } + } + writeDest->Release(); + depthConverted->Release(); + descriptorHeap->Release(); + convertCommandList->Release(); + depthUAVCleaning(); + } + + size_t srcPitch, dstPitch; + switch (m_surface_color_format) + { + case CELL_GCM_SURFACE_A8R8G8B8: + srcPitch = align(m_surface_clip_w * 4, 256); + dstPitch = m_surface_clip_w * 4; + break; + case CELL_GCM_SURFACE_F_W16Z16Y16X16: + srcPitch = align(m_surface_clip_w * 8, 256); + dstPitch = m_surface_clip_w * 8; + break; + } + + if (Ini.GSDumpColorBuffers.GetValue()) + { + switch (m_surface_color_target) + { + case CELL_GCM_SURFACE_TARGET_NONE: + break; + + case CELL_GCM_SURFACE_TARGET_0: + { + u32 address = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000); + void *dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + } + break; + + case CELL_GCM_SURFACE_TARGET_1: + { + u32 address = GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000); + void *dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + } + break; + + case CELL_GCM_SURFACE_TARGET_MRT1: + { + u32 address = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000); + void *dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + address = GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000); + dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + } + break; + + case CELL_GCM_SURFACE_TARGET_MRT2: + { + u32 address = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000); + void *dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + address = GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000); + dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + address = GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000); + dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt2, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + } + break; + + case CELL_GCM_SURFACE_TARGET_MRT3: + { + u32 address = GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000); + void *dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt0, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + address = GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000); + dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt1, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + address = GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000); + dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt2, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + address = GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000); + dstAddress = vm::get_ptr(address); + copyToCellRamAndRelease(dstAddress, rtt3, srcPitch, dstPitch, m_surface_clip_w, m_surface_clip_h); + } + break; + } + } + + if (needTransfer) + downloadCommandList->Release(); + readbackCleaning(); + + vm::write32(m_label_addr + offset, value); + }); + + m_GC.waitForCompletion(); +} + +void D3D12GSRender::semaphorePFIFOAcquire(u32 offset, u32 value) +{ + const std::chrono::time_point enterWait = std::chrono::system_clock::now(); + while (true) + { + volatile u32 val = vm::read32(m_label_addr + offset); + if (val == value) break; + std::chrono::time_point waitPoint = std::chrono::system_clock::now(); + long long elapsedTime = std::chrono::duration_cast(waitPoint - enterWait).count(); + if (elapsedTime > 0) + LOG_ERROR(RSX, "Has wait for more than a second for semaphore acquire"); + std::this_thread::yield(); + } +} +#endif diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h new file mode 100644 index 0000000000..87cdbabe62 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.h @@ -0,0 +1,421 @@ +#pragma once +#if defined(DX12_SUPPORT) + +#include "D3D12.h" +#include "rpcs3/Ini.h" +#include "Utilities/rPlatform.h" // only for rImage +#include "Utilities/File.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/RSX/GSRender.h" + +#include "D3D12RenderTargetSets.h" +#include "D3D12PipelineState.h" +#include "D3D12Buffer.h" + +// Some constants are the same between RSX and GL +#include + + +/** + * TODO: If you want to improve this backend, a small list of things that are unimplemented atm : + * - Vertex texture + * It requires adding the reading command in D3D12FragmentProgramDecompiler, + * generates corresponding root signatures and descriptor heap binding, and ensure that code in + * D3D12Textures.cpp doesn't contain pixel shader specific code. + * - MSAA + * There is no support in the gl backend for MSAA textures atm so it needs to be implemented from scratch. + * - Depth buffer read + * The depth buffer can be currently properly read, but for some reasons it needs a conversion from depth16/24 + * format to rgba8 format, which doesn't make sense since the PS3 doesn't make such conversion implicitly afaik. + * - Improve caching of vertex buffers and texture + * Vertex buffers are cached by range. This works but in some rare situation it may be wrong, for instance if 2 + * draw call use the same buffer, but the first one doesn't use all the attribute ; then the second one will use + * the cached version and not have updated attributes. Same for texture, if format/size does change, the caching + * system is ignoring it. + * - Fix vertex buffer in The Guided Paradox + * The vertex info in the guided paradox are wrong, leading to missing character parts ingame (like leg or torso). + * It's because some vertex position are incorrect. + * - Improve sync between cell and RSX + * A lot of optimisation can be gained from using Cell and RSX latency. Cell can't read RSX generated data without + * synchronisation. We currently only cover semaphore sync, but there are more (like implicit sync at flip) that + * are not currently correctly signaled which leads to deadlock. + */ + +class GSFrameBase2 +{ +public: + GSFrameBase2() {} + GSFrameBase2(const GSFrameBase2&) = delete; + virtual void Close() = 0; + + virtual bool IsShown() = 0; + virtual void Hide() = 0; + virtual void Show() = 0; + + virtual void* GetNewContext() = 0; + virtual void SetCurrent(void* ctx) = 0; + virtual void DeleteContext(void* ctx) = 0; + virtual void Flip(void* ctx) = 0; + virtual HWND getHandle() const = 0; + virtual void SetAdaptaterName(const wchar_t *) = 0; +}; + +typedef GSFrameBase2*(*GetGSFrameCb2)(); + +void SetGetD3DGSFrameCallback(GetGSFrameCb2 value); + +template +struct InitHeap +{ + static T* Init(ID3D12Device *device, size_t heapSize, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags); +}; + +template<> +struct InitHeap +{ + static ID3D12Heap* Init(ID3D12Device *device, size_t heapSize, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags) + { + ID3D12Heap *result; + D3D12_HEAP_DESC heapDesc = {}; + heapDesc.SizeInBytes = heapSize; + heapDesc.Properties.Type = type; + heapDesc.Flags = flags; + check(device->CreateHeap(&heapDesc, IID_PPV_ARGS(&result))); + return result; + } +}; + +template<> +struct InitHeap +{ + static ID3D12Resource* Init(ID3D12Device *device, size_t heapSize, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags) + { + ID3D12Resource *result; + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.Type = type; + check(device->CreateCommittedResource(&heapProperties, + flags, + &getBufferResourceDesc(heapSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&result)) + ); + + return result; + } +}; + + +/** + * Wrapper around a ID3D12Resource or a ID3D12Heap. + * Acts as a ring buffer : hold a get and put pointers, + * put pointer is used as storage space offset + * and get is used as beginning of in use data space. + * This wrapper checks that put pointer doesn't cross get one. + */ +template +struct DataHeap +{ + T *m_heap; + size_t m_size; + size_t m_putPos; // Start of free space + std::atomic m_getPos; // End of free space + std::vector > m_resourceStoredSinceLastSync; + + void Init(ID3D12Device *device, size_t heapSize, D3D12_HEAP_TYPE type, D3D12_HEAP_FLAGS flags) + { + m_size = heapSize; + m_heap = InitHeap::Init(device, heapSize, type, flags); + m_putPos = 0; + m_getPos = m_size - 1; + } + + /** + * Does alloc cross get position ? + */ + bool canAlloc(size_t size) const + { + size_t allocSize = align(size, Alignment); + size_t currentGetPos = m_getPos.load(); + if (m_putPos + allocSize < m_size) + { + // range before get + if (m_putPos + allocSize < m_getPos) + return true; + // range after get + if (m_putPos > m_getPos) + return true; + return false; + } + else + { + // ..]....[..get.. + if (m_putPos < m_getPos) + return false; + // ..get..]...[... + // Actually all resources extending beyond heap space starts at 0 + if (allocSize > m_getPos) + return false; + return true; + } + } + + size_t alloc(size_t size) + { + assert(canAlloc(size)); + size_t allocSize = align(size, Alignment); + if (m_putPos + allocSize < m_size) + { + size_t oldPutPos = m_putPos; + m_putPos += allocSize; + return oldPutPos; + } + else + { + m_putPos = allocSize; + return 0; + } + } + + void Release() + { + m_heap->Release(); + for (auto tmp : m_resourceStoredSinceLastSync) + { + SAFE_RELEASE(std::get<2>(tmp)); + } + } + + /** + * Get a function that cleans heaps. + * It's caller responsability to ensure data are not used when executed. + */ + std::function getCleaningFunction() + { + std::atomic& getPointer = m_getPos; + auto duplicatem_resourceStoredSinceLastSync = m_resourceStoredSinceLastSync; + m_resourceStoredSinceLastSync.clear(); + return [=, &getPointer]() { + for (auto tmp : duplicatem_resourceStoredSinceLastSync) + { + SAFE_RELEASE(std::get<2>(tmp)); + getPointer.exchange(std::get<0>(tmp)); + } + }; + } +}; + + +/** + * Wrapper for a worker thread that executes lambda functions + * in the order they were submitted during its lifetime. + * Used mostly to release data that are not needed anymore. + */ +struct GarbageCollectionThread +{ + std::atomic m_askForTermination; + std::mutex m_mutex; + std::condition_variable cv; + std::queue > m_queue; + std::thread m_worker; + + GarbageCollectionThread(); + ~GarbageCollectionThread(); + void pushWork(std::function&& f); + void waitForCompletion(); +}; + +class D3D12GSRender : public GSRender +{ +private: + /** + * Mutex protecting m_texturesCache and m_Textoclean access + * Memory protection fault catch can be generated by any thread and + * modifies these two members. + */ + std::mutex mut; + std::list > m_protectedTextures; // Texaddress, start of protected range, size of protected range + std::vector m_texToClean; + bool invalidateTexture(u32 addr); + + GarbageCollectionThread m_GC; + // Copy of RTT to be used as texture + std::unordered_map m_texturesRTTs; + + std::unordered_map m_texturesCache; + // std::vector m_post_draw_objs; + + // TODO: Use a tree structure to parse more efficiently + // Key is begin << 32 | end + std::unordered_map m_vertexCache; + + PipelineStateObjectCache m_cachePSO; + std::pair *m_PSO; + // m_rootSignatures[N] is RS with N texture/sample + ID3D12RootSignature *m_rootSignatures[17]; + + struct + { + size_t m_vertexUploadDuration; + size_t m_textureUploadDuration; + } m_timers; + + void ResetTimer(); + + struct Shader + { + ID3D12PipelineState *m_PSO; + ID3D12RootSignature *m_rootSignature; + ID3D12Resource *m_vertexBuffer; + ID3D12DescriptorHeap *m_textureDescriptorHeap; + ID3D12DescriptorHeap *m_samplerDescriptorHeap; + void Init(ID3D12Device *device); + void Release(); + }; + + /** + * Stores data related to the scaling pass that turns internal + * render targets into presented buffers. + */ + Shader m_outputScalingPass; + + /** + * Data used when depth buffer is converted to uchar textures. + */ + ID3D12PipelineState *m_convertPSO; + ID3D12RootSignature *m_convertRootSignature; + void initConvertShader(); + + + /** + * Stores data that are "ping ponged" between frame. + * For instance command allocator : maintains 2 command allocators and + * swap between them when frame is flipped. + */ + struct ResourceStorage + { + ID3D12Fence* m_frameFinishedFence; + HANDLE m_frameFinishedHandle; + ID3D12CommandAllocator *m_commandAllocator; + ID3D12CommandAllocator *m_downloadCommandAllocator; + std::list m_inflightCommandList; + + // Constants storage + ID3D12DescriptorHeap *m_constantsBufferDescriptorsHeap; + size_t m_constantsBufferIndex; + ID3D12DescriptorHeap *m_scaleOffsetDescriptorHeap; + size_t m_currentScaleOffsetBufferIndex; + + // Texture storage + ID3D12CommandAllocator *m_textureUploadCommandAllocator; + ID3D12DescriptorHeap *m_textureDescriptorsHeap; + ID3D12DescriptorHeap *m_samplerDescriptorHeap[2]; + size_t m_samplerDescriptorHeapIndex; + size_t m_currentSamplerIndex; + size_t m_currentTextureIndex; + + ID3D12Resource *m_RAMFramebuffer; + + void Reset(); + void Init(ID3D12Device *device); + void Release(); + }; + + ResourceStorage m_perFrameStorage[2]; + ResourceStorage &getCurrentResourceStorage(); + ResourceStorage &getNonCurrentResourceStorage(); + + // Constants storage + DataHeap m_constantsData; + // Vertex storage + DataHeap m_vertexIndexData; + // Texture storage + DataHeap m_textureUploadData; + DataHeap m_UAVHeap; + DataHeap m_readbackResources; + + struct + { + bool m_indexed; /* m_IASet; + ID3D12Device* m_device; + size_t g_descriptorStrideSRVCBVUAV; + size_t g_descriptorStrideDSV; + size_t g_descriptorStrideRTV; + size_t g_descriptorStrideSamplers; + ID3D12CommandQueue *m_commandQueueCopy; + ID3D12CommandQueue *m_commandQueueGraphic; + + // Used to fill unused texture slot + ID3D12Resource *m_dummyTexture; + + struct IDXGISwapChain3 *m_swapChain; + //BackBuffers + ID3D12Resource* m_backBuffer[2]; + ID3D12DescriptorHeap *m_backbufferAsRendertarget[2]; + + size_t m_lastWidth, m_lastHeight, m_lastDepth; +public: + GSFrameBase2 *m_frame; + u32 m_draw_frames; + u32 m_skip_frames; + + std::unordered_map m_vertexConstants; + + D3D12GSRender(); + virtual ~D3D12GSRender(); + + virtual void semaphorePGRAPHTextureReadRelease(u32 offset, u32 value) override; + virtual void semaphorePGRAPHBackendRelease(u32 offset, u32 value) override; + virtual void semaphorePFIFOAcquire(u32 offset, u32 value) override; + +private: + ID3D12Resource *writeColorBuffer(ID3D12Resource *RTT, ID3D12GraphicsCommandList *cmdlist); + virtual void Close() override; + + bool LoadProgram(); + + /** + * Create as little vertex buffer as possible to hold all vertex info (in upload heap), + * create corresponding IA layout that can be used for load program and + * returns a vector of vertex buffer view that can be passed to IASetVertexBufferView(). + */ + std::vector UploadVertexBuffers(bool indexed_draw = false); + + /** + * Create index buffer for indexed rendering and non native primitive format if nedded, and + * update m_renderingInfo member accordingly. If m_renderingInfo::m_indexed is true, + * returns an index buffer view that can be passed to a command list. + */ + D3D12_INDEX_BUFFER_VIEW uploadIndexBuffers(bool indexed_draw = false); + + + void setScaleOffset(); + void FillVertexShaderConstantsBuffer(); + void FillPixelShaderConstantsBuffer(); + /** + * Upload textures to Data heap if necessary and create necessary descriptor in the per frame storage struct. + * returns the number of texture uploaded + */ + size_t UploadTextures(); + + void PrepareRenderTargets(); +protected: + virtual void OnInit() override; + virtual void OnInitThread() override; + virtual void OnExitThread() override; + virtual void OnReset() override; + virtual void Clear(u32 cmd) override; + virtual void Draw() override; + virtual void Flip() override; +}; + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp new file mode 100644 index 0000000000..a02f5f9c76 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.cpp @@ -0,0 +1,295 @@ +#include "stdafx.h" +#if defined (DX12_SUPPORT) + +#include "D3D12PipelineState.h" +#include +#include "D3D12GSRender.h" + +#pragma comment (lib, "d3dcompiler.lib") + +#define TO_STRING(x) #x + +void Shader::Compile(const std::string &code, SHADER_TYPE st) +{ HRESULT hr; + Microsoft::WRL::ComPtr errorBlob; + switch (st) + { + case SHADER_TYPE::SHADER_TYPE_VERTEX: + hr = D3DCompile(code.c_str(), code.size(), "VertexProgram.hlsl", nullptr, nullptr, "main", "vs_5_0", 0, 0, &bytecode, errorBlob.GetAddressOf()); + if (hr != S_OK) + LOG_ERROR(RSX, "VS build failed:%s", errorBlob->GetBufferPointer()); + break; + case SHADER_TYPE::SHADER_TYPE_FRAGMENT: + hr = D3DCompile(code.c_str(), code.size(), "FragmentProgram.hlsl", nullptr, nullptr, "main", "ps_5_0", 0, 0, &bytecode, errorBlob.GetAddressOf()); + if (hr != S_OK) + LOG_ERROR(RSX, "FS build failed:%s", errorBlob->GetBufferPointer()); + break; + } +} + + + + +bool D3D12GSRender::LoadProgram() +{ + if (!m_cur_fragment_prog) + { + LOG_WARNING(RSX, "LoadProgram: m_cur_shader_prog == NULL"); + return false; + } + + m_cur_fragment_prog->ctrl = m_shader_ctrl; + + if (!m_cur_vertex_prog) + { + LOG_WARNING(RSX, "LoadProgram: m_cur_vertex_prog == NULL"); + return false; + } + + D3D12PipelineProperties prop = {}; + switch (m_draw_mode - 1) + { + case GL_POINTS: + prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + break; + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + break; + case GL_TRIANGLES: + case GL_TRIANGLE_STRIP: + case GL_TRIANGLE_FAN: + prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + break; + case GL_QUADS: + case GL_QUAD_STRIP: + case GL_POLYGON: + default: + // LOG_ERROR(RSX, "Unsupported primitive type"); + prop.Topology = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + break; + } + + static D3D12_BLEND_DESC CD3D12_BLEND_DESC = + { + FALSE, + FALSE, + { + FALSE,FALSE, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, + D3D12_LOGIC_OP_NOOP, + D3D12_COLOR_WRITE_ENABLE_ALL, + } + }; + prop.Blend = CD3D12_BLEND_DESC; + + if (m_set_blend) + { + prop.Blend.RenderTarget[0].BlendEnable = true; + + if (m_set_blend_mrt1) + prop.Blend.RenderTarget[1].BlendEnable = true; + if (m_set_blend_mrt2) + prop.Blend.RenderTarget[2].BlendEnable = true; + if (m_set_blend_mrt3) + prop.Blend.RenderTarget[3].BlendEnable = true; + } + + if (m_set_blend_equation) + { + prop.Blend.RenderTarget[0].BlendOp = getBlendOp(m_blend_equation_rgb); + prop.Blend.RenderTarget[0].BlendOpAlpha = getBlendOp(m_blend_equation_alpha); + + if (m_set_blend_mrt1) + { + prop.Blend.RenderTarget[1].BlendOp = getBlendOp(m_blend_equation_rgb); + prop.Blend.RenderTarget[1].BlendOpAlpha = getBlendOp(m_blend_equation_alpha); + } + + if (m_set_blend_mrt2) + { + prop.Blend.RenderTarget[2].BlendOp = getBlendOp(m_blend_equation_rgb); + prop.Blend.RenderTarget[2].BlendOpAlpha = getBlendOp(m_blend_equation_alpha); + } + + if (m_set_blend_mrt3) + { + prop.Blend.RenderTarget[3].BlendOp = getBlendOp(m_blend_equation_rgb); + prop.Blend.RenderTarget[3].BlendOpAlpha = getBlendOp(m_blend_equation_alpha); + } + } + + if (m_set_blend_sfactor && m_set_blend_dfactor) + { + prop.Blend.RenderTarget[0].SrcBlend = getBlendFactor(m_blend_sfactor_rgb); + prop.Blend.RenderTarget[0].DestBlend = getBlendFactor(m_blend_dfactor_rgb); + prop.Blend.RenderTarget[0].SrcBlendAlpha = getBlendFactor(m_blend_sfactor_alpha); + prop.Blend.RenderTarget[0].DestBlendAlpha = getBlendFactor(m_blend_dfactor_alpha); + + if (m_set_blend_mrt1) + { + prop.Blend.RenderTarget[1].SrcBlend = getBlendFactor(m_blend_sfactor_rgb); + prop.Blend.RenderTarget[1].DestBlend = getBlendFactor(m_blend_dfactor_rgb); + prop.Blend.RenderTarget[1].SrcBlendAlpha = getBlendFactor(m_blend_sfactor_alpha); + prop.Blend.RenderTarget[1].DestBlendAlpha = getBlendFactor(m_blend_dfactor_alpha); + } + + if (m_set_blend_mrt2) + { + prop.Blend.RenderTarget[2].SrcBlend = getBlendFactor(m_blend_sfactor_rgb); + prop.Blend.RenderTarget[2].DestBlend = getBlendFactor(m_blend_dfactor_rgb); + prop.Blend.RenderTarget[2].SrcBlendAlpha = getBlendFactor(m_blend_sfactor_alpha); + prop.Blend.RenderTarget[2].DestBlendAlpha = getBlendFactor(m_blend_dfactor_alpha); + } + + if (m_set_blend_mrt3) + { + prop.Blend.RenderTarget[3].SrcBlend = getBlendFactor(m_blend_sfactor_rgb); + prop.Blend.RenderTarget[3].DestBlend = getBlendFactor(m_blend_dfactor_rgb); + prop.Blend.RenderTarget[3].SrcBlendAlpha = getBlendFactor(m_blend_sfactor_alpha); + prop.Blend.RenderTarget[3].DestBlendAlpha = getBlendFactor(m_blend_dfactor_alpha); + } + } + + if (m_set_logic_op) + { + prop.Blend.RenderTarget[0].LogicOpEnable = true; + prop.Blend.RenderTarget[0].LogicOp = getLogicOp(m_logic_op); + } + + if (m_set_blend_color) + { + // glBlendColor(m_blend_color_r, m_blend_color_g, m_blend_color_b, m_blend_color_a); + // checkForGlError("glBlendColor"); + } + + switch (m_surface_depth_format) + { + case 0: + break; + case CELL_GCM_SURFACE_Z16: + prop.DepthStencilFormat = DXGI_FORMAT_D16_UNORM; + break; + case CELL_GCM_SURFACE_Z24S8: + prop.DepthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT; + break; + default: + LOG_ERROR(RSX, "Bad depth format! (%d)", m_surface_depth_format); + assert(0); + } + + switch (m_surface_color_format) + { + case CELL_GCM_SURFACE_A8R8G8B8: + prop.RenderTargetsFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case CELL_GCM_SURFACE_F_W16Z16Y16X16: + prop.RenderTargetsFormat = DXGI_FORMAT_R16G16B16A16_FLOAT; + break; + } + + switch (m_surface_color_target) + { + case CELL_GCM_SURFACE_TARGET_0: + case CELL_GCM_SURFACE_TARGET_1: + prop.numMRT = 1; + break; + case CELL_GCM_SURFACE_TARGET_MRT1: + prop.numMRT = 2; + break; + case CELL_GCM_SURFACE_TARGET_MRT2: + prop.numMRT = 3; + break; + case CELL_GCM_SURFACE_TARGET_MRT3: + prop.numMRT = 4; + break; + default: + LOG_ERROR(RSX, "Bad surface color target: %d", m_surface_color_target); + } + + prop.DepthStencil.DepthEnable = m_set_depth_test; + prop.DepthStencil.DepthWriteMask = m_depth_mask ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO; + prop.DepthStencil.DepthFunc = getCompareFunc(m_depth_func); + prop.DepthStencil.StencilEnable = m_set_stencil_test; + prop.DepthStencil.StencilReadMask = m_stencil_func_mask; + prop.DepthStencil.StencilWriteMask = m_stencil_mask; + prop.DepthStencil.FrontFace.StencilPassOp = getStencilOp(m_stencil_zpass); + prop.DepthStencil.FrontFace.StencilDepthFailOp = getStencilOp(m_stencil_zfail); + prop.DepthStencil.FrontFace.StencilFailOp = getStencilOp(m_stencil_fail); + prop.DepthStencil.FrontFace.StencilFunc = getCompareFunc(m_stencil_func); + + if (m_set_two_sided_stencil_test_enable) + { + prop.DepthStencil.BackFace.StencilFailOp = getStencilOp(m_back_stencil_fail); + prop.DepthStencil.BackFace.StencilFunc = getCompareFunc(m_back_stencil_func); + prop.DepthStencil.BackFace.StencilPassOp = getStencilOp(m_back_stencil_zpass); + prop.DepthStencil.BackFace.StencilDepthFailOp = getStencilOp(m_back_stencil_zfail); + } + else + { + prop.DepthStencil.BackFace.StencilPassOp = getStencilOp(m_stencil_zpass); + prop.DepthStencil.BackFace.StencilDepthFailOp = getStencilOp(m_stencil_zfail); + prop.DepthStencil.BackFace.StencilFailOp = getStencilOp(m_stencil_fail); + prop.DepthStencil.BackFace.StencilFunc = getCompareFunc(m_stencil_func); + } + + // Sensible default value + static D3D12_RASTERIZER_DESC CD3D12_RASTERIZER_DESC = + { + D3D12_FILL_MODE_SOLID, + D3D12_CULL_MODE_NONE, + FALSE, + D3D12_DEFAULT_DEPTH_BIAS, + D3D12_DEFAULT_DEPTH_BIAS_CLAMP, + D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS, + TRUE, + FALSE, + FALSE, + 0, + D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF, + }; + prop.Rasterization = CD3D12_RASTERIZER_DESC; + switch (m_set_cull_face) + { + case CELL_GCM_FRONT: + prop.Rasterization.CullMode = D3D12_CULL_MODE_FRONT; + break; + case CELL_GCM_BACK: + prop.Rasterization.CullMode = D3D12_CULL_MODE_BACK; + break; + default: + prop.Rasterization.CullMode = D3D12_CULL_MODE_NONE; + break; + } + + switch (m_front_face) + { + case CELL_GCM_CW: + prop.Rasterization.FrontCounterClockwise = FALSE; + break; + case CELL_GCM_CCW: + prop.Rasterization.FrontCounterClockwise = TRUE; + break; + } + + if (m_set_color_mask) + { + UINT8 mask = 0; + mask |= m_color_mask_r ? D3D12_COLOR_WRITE_ENABLE_RED : 0; + mask |= m_color_mask_g ? D3D12_COLOR_WRITE_ENABLE_GREEN : 0; + mask |= m_color_mask_b ? D3D12_COLOR_WRITE_ENABLE_BLUE : 0; + mask |= m_color_mask_a ? D3D12_COLOR_WRITE_ENABLE_ALPHA : 0; + for (unsigned i = 0; i < prop.numMRT; i++) + prop.Blend.RenderTarget[i].RenderTargetWriteMask = mask; + } + + prop.IASet = m_IASet; + + m_PSO = m_cachePSO.getGraphicPipelineState(m_cur_vertex_prog, m_cur_fragment_prog, prop, std::make_pair(m_device, m_rootSignatures)); + return m_PSO != nullptr; +} + + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h new file mode 100644 index 0000000000..4fe0e4734e --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12PipelineState.h @@ -0,0 +1,185 @@ +#pragma once +#if defined (DX12_SUPPORT) + +#include +#include +#include "../Common/ProgramStateCache.h" +#include "D3D12VertexProgramDecompiler.h" +#include "D3D12FragmentProgramDecompiler.h" +#include "Utilities/File.h" + + + +struct D3D12PipelineProperties +{ + D3D12_PRIMITIVE_TOPOLOGY_TYPE Topology; + DXGI_FORMAT DepthStencilFormat; + DXGI_FORMAT RenderTargetsFormat; + std::vector IASet; + D3D12_BLEND_DESC Blend; + unsigned numMRT : 3; + D3D12_DEPTH_STENCIL_DESC DepthStencil; + D3D12_RASTERIZER_DESC Rasterization; + + bool operator==(const D3D12PipelineProperties &in) const + { + if (IASet.size() != in.IASet.size()) + return false; + for (unsigned i = 0; i < IASet.size(); i++) + { + const D3D12_INPUT_ELEMENT_DESC &a = IASet[i], &b = in.IASet[i]; + if (a.AlignedByteOffset != b.AlignedByteOffset) + return false; + if (a.Format != b.Format) + return false; + if (a.InputSlot != b.InputSlot) + return false; + if (a.InstanceDataStepRate != b.InstanceDataStepRate) + return false; + if (a.SemanticIndex != b.SemanticIndex) + return false; + } + + if (memcmp(&DepthStencil, &in.DepthStencil, sizeof(D3D12_DEPTH_STENCIL_DESC))) + return false; + if (memcmp(&Blend, &in.Blend, sizeof(D3D12_BLEND_DESC))) + return false; + if (memcmp(&Rasterization, &in.Rasterization, sizeof(D3D12_RASTERIZER_DESC))) + return false; + return Topology == in.Topology && DepthStencilFormat == in.DepthStencilFormat && numMRT == in.numMRT && RenderTargetsFormat == in.RenderTargetsFormat; + } +}; + +/** Storage for a shader +* Embeds the D3DBlob +*/ +struct Shader +{ +public: + enum class SHADER_TYPE + { + SHADER_TYPE_VERTEX, + SHADER_TYPE_FRAGMENT + }; + + Shader() : bytecode(nullptr) {} + ~Shader() {} + + u32 id; + Microsoft::WRL::ComPtr bytecode; + std::vector FragmentConstantOffsetCache; + size_t m_textureCount; + + /** + * Decompile a fragment shader located in the PS3's Memory. This function operates synchronously. + * @param prog RSXShaderProgram specifying the location and size of the shader in memory + */ + // void Decompile(RSXFragmentProgram& prog) + + /** Compile the decompiled fragment shader into a format we can use with OpenGL. */ + void Compile(const std::string &code, enum class SHADER_TYPE st); +}; + +struct D3D12Traits +{ + typedef Shader VertexProgramData; + typedef Shader FragmentProgramData; + typedef std::pair PipelineData; + typedef D3D12PipelineProperties PipelineProperties; + typedef std::pair ExtraData; + + static + void RecompileFragmentProgram(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID) + { + D3D12FragmentDecompiler FS(RSXFP->addr, RSXFP->size, RSXFP->ctrl); + const std::string &shader = FS.Decompile(); + fragmentProgramData.Compile(shader, Shader::SHADER_TYPE::SHADER_TYPE_FRAGMENT); + fragmentProgramData.m_textureCount = 0; + for (const ParamType& PT : FS.m_parr.params[PF_PARAM_UNIFORM]) + { + for (const ParamItem PI : PT.items) + { + if (PT.type == "sampler2D") + { + fragmentProgramData.m_textureCount++; + continue; + } + size_t offset = atoi(PI.name.c_str() + 2); + fragmentProgramData.FragmentConstantOffsetCache.push_back(offset); + } + } + + // TODO: This shouldn't use current dir + std::string filename = "./FragmentProgram" + std::to_string(ID) + ".hlsl"; + fs::file(filename, o_write | o_create | o_trunc).write(shader.c_str(), shader.size()); + fragmentProgramData.id = (u32)ID; + } + + static + void RecompileVertexProgram(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID) + { + D3D12VertexProgramDecompiler VS(RSXVP->data); + std::string shaderCode = VS.Decompile(); + vertexProgramData.Compile(shaderCode, Shader::SHADER_TYPE::SHADER_TYPE_VERTEX); + + // TODO: This shouldn't use current dir + std::string filename = "./VertexProgram" + std::to_string(ID) + ".hlsl"; + fs::file(filename, o_write | o_create | o_trunc).write(shaderCode.c_str(), shaderCode.size()); + vertexProgramData.id = (u32)ID; + } + + static + PipelineData *BuildProgram(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData) + { + + std::pair *result = new std::pair(); + D3D12_GRAPHICS_PIPELINE_STATE_DESC graphicPipelineStateDesc = {}; + + if (vertexProgramData.bytecode == nullptr) + return nullptr; + graphicPipelineStateDesc.VS.BytecodeLength = vertexProgramData.bytecode->GetBufferSize(); + graphicPipelineStateDesc.VS.pShaderBytecode = vertexProgramData.bytecode->GetBufferPointer(); + + if (fragmentProgramData.bytecode == nullptr) + return nullptr; + graphicPipelineStateDesc.PS.BytecodeLength = fragmentProgramData.bytecode->GetBufferSize(); + graphicPipelineStateDesc.PS.pShaderBytecode = fragmentProgramData.bytecode->GetBufferPointer(); + + graphicPipelineStateDesc.pRootSignature = extraData.second[fragmentProgramData.m_textureCount]; + result->second = fragmentProgramData.m_textureCount; + + graphicPipelineStateDesc.BlendState = pipelineProperties.Blend; + graphicPipelineStateDesc.DepthStencilState = pipelineProperties.DepthStencil; + graphicPipelineStateDesc.RasterizerState = pipelineProperties.Rasterization; + graphicPipelineStateDesc.PrimitiveTopologyType = pipelineProperties.Topology; + + graphicPipelineStateDesc.NumRenderTargets = pipelineProperties.numMRT; + for (unsigned i = 0; i < pipelineProperties.numMRT; i++) + graphicPipelineStateDesc.RTVFormats[i] = pipelineProperties.RenderTargetsFormat; + graphicPipelineStateDesc.DSVFormat = pipelineProperties.DepthStencilFormat; + + graphicPipelineStateDesc.InputLayout.pInputElementDescs = pipelineProperties.IASet.data(); + graphicPipelineStateDesc.InputLayout.NumElements = (UINT)pipelineProperties.IASet.size(); + graphicPipelineStateDesc.SampleDesc.Count = 1; + graphicPipelineStateDesc.SampleMask = UINT_MAX; + graphicPipelineStateDesc.NodeMask = 1; + + extraData.first->CreateGraphicsPipelineState(&graphicPipelineStateDesc, IID_PPV_ARGS(&result->first)); + return result; + } + + static + void DeleteProgram(PipelineData *ptr) + { + ptr->first->Release(); + delete ptr; + } +}; + +class PipelineStateObjectCache : public ProgramStateCache +{ +}; + + + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp new file mode 100644 index 0000000000..f131d0b102 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -0,0 +1,282 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "D3D12RenderTargetSets.h" +#include "rpcs3/Ini.h" +#include "Utilities/rPlatform.h" // only for rImage +#include "Utilities/File.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/RSX/GSRender.h" + +#include "D3D12.h" +#include "D3D12GSRender.h" + +void D3D12GSRender::PrepareRenderTargets() +{ + // FBO location has changed, previous data might be copied + u32 address_a = m_set_context_dma_color_a ? GetAddress(m_surface_offset_a, m_context_dma_color_a - 0xfeed0000) : 0; + u32 address_b = m_set_context_dma_color_b ? GetAddress(m_surface_offset_b, m_context_dma_color_b - 0xfeed0000) : 0; + u32 address_c = m_set_context_dma_color_c ? GetAddress(m_surface_offset_c, m_context_dma_color_c - 0xfeed0000) : 0; + u32 address_d = m_set_context_dma_color_d ? GetAddress(m_surface_offset_d, m_context_dma_color_d - 0xfeed0000) : 0; + u32 address_z = m_set_context_dma_z ? GetAddress(m_surface_offset_z, m_context_dma_z - 0xfeed0000) : 0; + + ID3D12GraphicsCommandList *copycmdlist; + check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_commandAllocator, nullptr, IID_PPV_ARGS(©cmdlist))); + getCurrentResourceStorage().m_inflightCommandList.push_back(copycmdlist); + + // Make previous RTTs sampleable + for (unsigned i = 0; i < 4; i++) + { + if (m_rtts.m_currentlyBoundRenderTargets[i] == nullptr) + continue; + copycmdlist->ResourceBarrier(1, &getResourceBarrierTransition(m_rtts.m_currentlyBoundRenderTargets[i], D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_GENERIC_READ)); + } + // Same for depth buffer + if (m_rtts.m_currentlyBoundDepthStencil != nullptr) + copycmdlist->ResourceBarrier(1, &getResourceBarrierTransition(m_rtts.m_currentlyBoundDepthStencil, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ)); + + memset(m_rtts.m_currentlyBoundRenderTargetsAddress, 0, 4 * sizeof(u32)); + memset(m_rtts.m_currentlyBoundRenderTargets, 0, 4 * sizeof(ID3D12Resource *)); + m_rtts.m_currentlyBoundDepthStencil = nullptr; + m_rtts.m_currentlyBoundDepthStencilAddress = 0; + + + D3D12_CPU_DESCRIPTOR_HANDLE Handle = m_rtts.m_renderTargetsDescriptorsHeap->GetCPUDescriptorHandleForHeapStart(); + size_t g_RTTIncrement = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + + DXGI_FORMAT dxgiFormat; + switch (m_surface_color_format) + { + case CELL_GCM_SURFACE_A8R8G8B8: + dxgiFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case CELL_GCM_SURFACE_F_W16Z16Y16X16: + dxgiFormat = DXGI_FORMAT_R16G16B16A16_FLOAT; + break; + } + D3D12_RENDER_TARGET_VIEW_DESC rttViewDesc = {}; + rttViewDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + rttViewDesc.Format = dxgiFormat; + + switch (m_surface_color_target) + { + case CELL_GCM_SURFACE_TARGET_0: + { + ID3D12Resource *rttA = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 0, address_a, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttA, &rttViewDesc, Handle); + break; + } + case CELL_GCM_SURFACE_TARGET_1: + { + ID3D12Resource *rttB = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 0, address_b, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttB, &rttViewDesc, Handle); + break; + } + case CELL_GCM_SURFACE_TARGET_MRT1: + { + ID3D12Resource *rttA = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 0, address_a, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttA, &rttViewDesc, Handle); + Handle.ptr += g_RTTIncrement; + ID3D12Resource *rttB = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 1, address_b, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttB, &rttViewDesc, Handle); + } + break; + case CELL_GCM_SURFACE_TARGET_MRT2: + { + ID3D12Resource *rttA = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 0, address_a, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttA, &rttViewDesc, Handle); + Handle.ptr += g_RTTIncrement; + ID3D12Resource *rttB = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 1, address_b, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttB, &rttViewDesc, Handle); + Handle.ptr += g_RTTIncrement; + ID3D12Resource *rttC = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 2, address_c, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttC, &rttViewDesc, Handle); + break; + } + case CELL_GCM_SURFACE_TARGET_MRT3: + { + ID3D12Resource *rttA = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 0, address_a, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttA, &rttViewDesc, Handle); + Handle.ptr += g_RTTIncrement; + ID3D12Resource *rttB = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 1, address_b, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttB, &rttViewDesc, Handle); + Handle.ptr += g_RTTIncrement; + ID3D12Resource *rttC = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 2, address_c, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttC, &rttViewDesc, Handle); + Handle.ptr += g_RTTIncrement; + ID3D12Resource *rttD = m_rtts.bindAddressAsRenderTargets(m_device, copycmdlist, 3, address_d, m_surface_clip_w, m_surface_clip_h, m_surface_color_format, + m_clear_surface_color_r / 255.0f, m_clear_surface_color_g / 255.0f, m_clear_surface_color_b / 255.0f, m_clear_surface_color_a / 255.0f); + m_device->CreateRenderTargetView(rttD, &rttViewDesc, Handle); + break; + } + } + + ID3D12Resource *ds = m_rtts.bindAddressAsDepthStencil(m_device, copycmdlist, address_z, m_surface_clip_w, m_surface_clip_h, m_surface_depth_format, 1., 0); + + D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc = {}; + switch (m_surface_depth_format) + { + case 0: + break; + case CELL_GCM_SURFACE_Z16: + depthStencilViewDesc.Format = DXGI_FORMAT_D16_UNORM; + break; + case CELL_GCM_SURFACE_Z24S8: + depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + break; + default: + LOG_ERROR(RSX, "Bad depth format! (%d)", m_surface_depth_format); + assert(0); + } + depthStencilViewDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D; + m_device->CreateDepthStencilView(ds, &depthStencilViewDesc, m_rtts.m_depthStencilDescriptorHeap->GetCPUDescriptorHandleForHeapStart()); + + check(copycmdlist->Close()); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)©cmdlist); +} + +ID3D12Resource *RenderTargets::bindAddressAsRenderTargets(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, size_t slot, u32 address, + size_t width, size_t height, u8 surfaceColorFormat, float clearColorR, float clearColorG, float clearColorB, float clearColorA) +{ + ID3D12Resource* rtt; + auto It = m_renderTargets.find(address); + // TODO: Check if sizes match + if (It != m_renderTargets.end()) + { + rtt = It->second; + cmdList->ResourceBarrier(1, &getResourceBarrierTransition(rtt, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_RENDER_TARGET)); + } + else + { + LOG_WARNING(RSX, "Creating RTT"); + DXGI_FORMAT dxgiFormat; + switch (surfaceColorFormat) + { + case CELL_GCM_SURFACE_A8R8G8B8: + dxgiFormat = DXGI_FORMAT_R8G8B8A8_UNORM; + break; + case CELL_GCM_SURFACE_F_W16Z16Y16X16: + dxgiFormat = DXGI_FORMAT_R16G16B16A16_FLOAT; + break; + } + D3D12_CLEAR_VALUE clearColorValue = {}; + clearColorValue.Format = dxgiFormat; + clearColorValue.Color[0] = clearColorR; + clearColorValue.Color[1] = clearColorG; + clearColorValue.Color[2] = clearColorB; + clearColorValue.Color[3] = clearColorA; + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; + + D3D12_RESOURCE_DESC resourceDesc = getTexture2DResourceDesc(width, height, dxgiFormat, 1); + resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; + + device->CreateCommittedResource( + &heapProp, + D3D12_HEAP_FLAG_NONE, + &resourceDesc, + D3D12_RESOURCE_STATE_RENDER_TARGET, + &clearColorValue, + IID_PPV_ARGS(&rtt) + ); + m_renderTargets[address] = rtt; + } + m_currentlyBoundRenderTargetsAddress[slot] = address; + m_currentlyBoundRenderTargets[slot] = rtt; + return rtt; +} + +ID3D12Resource * RenderTargets::bindAddressAsDepthStencil(ID3D12Device * device, ID3D12GraphicsCommandList * cmdList, u32 address, size_t width, size_t height, u8 surfaceDepthFormat, float depthClear, u8 stencilClear) +{ + ID3D12Resource* ds; + auto It = m_depthStencil.find(address); + // TODO: Check if sizes and surface depth format match + + if (It != m_depthStencil.end()) + { + ds = It->second; + cmdList->ResourceBarrier(1, &getResourceBarrierTransition(ds, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_DEPTH_WRITE)); + } + else + { + D3D12_CLEAR_VALUE clearDepthValue = {}; + clearDepthValue.DepthStencil.Depth = depthClear; + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; + + DXGI_FORMAT dxgiFormat; + switch (surfaceDepthFormat) + { + case 0: + break; + case CELL_GCM_SURFACE_Z16: + dxgiFormat = DXGI_FORMAT_R16_TYPELESS; + clearDepthValue.Format = DXGI_FORMAT_D16_UNORM; + break; + case CELL_GCM_SURFACE_Z24S8: + dxgiFormat = DXGI_FORMAT_R24G8_TYPELESS; + clearDepthValue.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + break; + default: + LOG_ERROR(RSX, "Bad depth format! (%d)", surfaceDepthFormat); + assert(0); + } + + D3D12_RESOURCE_DESC resourceDesc = getTexture2DResourceDesc(width, height, dxgiFormat, 1); + resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; + + device->CreateCommittedResource( + &heapProp, + D3D12_HEAP_FLAG_NONE, + &resourceDesc, + D3D12_RESOURCE_STATE_DEPTH_WRITE, + &clearDepthValue, + IID_PPV_ARGS(&ds) + ); + m_depthStencil[address] = ds; + } + m_currentlyBoundDepthStencil = ds; + m_currentlyBoundDepthStencilAddress = address; + return ds; +} + +void RenderTargets::Init(ID3D12Device *device)//, u8 surfaceDepthFormat, size_t width, size_t height, float clearColor[4], float clearDepth) +{ + D3D12_DESCRIPTOR_HEAP_DESC descriptorHeapDesc = {}; + descriptorHeapDesc.NumDescriptors = 1; + descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV; + device->CreateDescriptorHeap(&descriptorHeapDesc, IID_PPV_ARGS(&m_depthStencilDescriptorHeap)); + + descriptorHeapDesc.NumDescriptors = 4; + descriptorHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + device->CreateDescriptorHeap(&descriptorHeapDesc, IID_PPV_ARGS(&m_renderTargetsDescriptorsHeap)); + + memset(m_currentlyBoundRenderTargetsAddress, 0, 4 * sizeof(u32)); + memset(m_currentlyBoundRenderTargets, 0, 4 * sizeof(ID3D12Resource*)); + m_currentlyBoundDepthStencil = nullptr; + m_currentlyBoundDepthStencilAddress = 0; +} + +void RenderTargets::Release() +{ + for (auto tmp : m_renderTargets) + tmp.second->Release(); + m_depthStencilDescriptorHeap->Release(); + m_renderTargetsDescriptorsHeap->Release(); + for (auto tmp : m_depthStencil) + tmp.second->Release(); +} +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h new file mode 100644 index 0000000000..719c189669 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.h @@ -0,0 +1,31 @@ +#pragma once + +#if defined(DX12_SUPPORT) +#include + +struct RenderTargets +{ + std::unordered_map m_renderTargets; + ID3D12Resource *m_currentlyBoundRenderTargets[4]; + u32 m_currentlyBoundRenderTargetsAddress[4]; + std::unordered_map m_depthStencil; + ID3D12Resource *m_currentlyBoundDepthStencil; + u32 m_currentlyBoundDepthStencilAddress; + ID3D12DescriptorHeap *m_renderTargetsDescriptorsHeap; + ID3D12DescriptorHeap *m_depthStencilDescriptorHeap; + + /** + * If render target already exists at address, issue state change operation on cmdList. + * Otherwise create one with width, height, clearColor info. + * returns the corresponding render target resource. + */ + ID3D12Resource *bindAddressAsRenderTargets(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, size_t slot, u32 address, + size_t width, size_t height, u8 surfaceColorFormat, float clearColorR, float clearColorG, float clearColorB, float clearColorA); + + ID3D12Resource *bindAddressAsDepthStencil(ID3D12Device *device, ID3D12GraphicsCommandList *cmdList, u32 address, + size_t width, size_t height, u8 surfaceDepthFormat, float depthClear, u8 stencilClear); + + void Init(ID3D12Device *device); + void Release(); +}; +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp new file mode 100644 index 0000000000..2038ec5b52 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -0,0 +1,900 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "D3D12GSRender.h" +// For clarity this code deals with texture but belongs to D3D12GSRender class + + +static +u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth) +{ + u32 offset = 0; + u32 shift_count = 0; + while (log2_width | log2_height | log2_depth) { + if (log2_width) + { + offset |= (x & 0x01) << shift_count; + x >>= 1; + ++shift_count; + --log2_width; + } + if (log2_height) + { + offset |= (y & 0x01) << shift_count; + y >>= 1; + ++shift_count; + --log2_height; + } + if (log2_depth) + { + offset |= (z & 0x01) << shift_count; + z >>= 1; + ++shift_count; + --log2_depth; + } + } + return offset; +} + +static +D3D12_COMPARISON_FUNC getSamplerCompFunc[] = +{ + D3D12_COMPARISON_FUNC_NEVER, + D3D12_COMPARISON_FUNC_LESS, + D3D12_COMPARISON_FUNC_EQUAL, + D3D12_COMPARISON_FUNC_LESS_EQUAL, + D3D12_COMPARISON_FUNC_GREATER, + D3D12_COMPARISON_FUNC_NOT_EQUAL, + D3D12_COMPARISON_FUNC_GREATER_EQUAL, + D3D12_COMPARISON_FUNC_ALWAYS +}; + +static +size_t getSamplerMaxAniso(size_t aniso) +{ + switch (aniso) + { + case CELL_GCM_TEXTURE_MAX_ANISO_1: return 1; + case CELL_GCM_TEXTURE_MAX_ANISO_2: return 2; + case CELL_GCM_TEXTURE_MAX_ANISO_4: return 4; + case CELL_GCM_TEXTURE_MAX_ANISO_6: return 6; + case CELL_GCM_TEXTURE_MAX_ANISO_8: return 8; + case CELL_GCM_TEXTURE_MAX_ANISO_10: return 10; + case CELL_GCM_TEXTURE_MAX_ANISO_12: return 12; + case CELL_GCM_TEXTURE_MAX_ANISO_16: return 16; + } + + return 1; +} + +static +D3D12_TEXTURE_ADDRESS_MODE getSamplerWrap(size_t wrap) +{ + switch (wrap) + { + case CELL_GCM_TEXTURE_WRAP: return D3D12_TEXTURE_ADDRESS_MODE_WRAP; + case CELL_GCM_TEXTURE_MIRROR: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; + case CELL_GCM_TEXTURE_CLAMP_TO_EDGE: return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + case CELL_GCM_TEXTURE_BORDER: return D3D12_TEXTURE_ADDRESS_MODE_BORDER; + case CELL_GCM_TEXTURE_CLAMP: return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + case CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP_TO_EDGE: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE; + case CELL_GCM_TEXTURE_MIRROR_ONCE_BORDER: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE; + case CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP: return D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE; + } + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; +} + +static +D3D12_FILTER getSamplerFilter(u32 minFilter, u32 magFilter) +{ + D3D12_FILTER_TYPE min, mag, mip; + switch (minFilter) + { + case CELL_GCM_TEXTURE_NEAREST: + min = D3D12_FILTER_TYPE_POINT; + mip = D3D12_FILTER_TYPE_POINT; + break; + case CELL_GCM_TEXTURE_LINEAR: + min = D3D12_FILTER_TYPE_LINEAR; + mip = D3D12_FILTER_TYPE_POINT; + break; + case CELL_GCM_TEXTURE_NEAREST_NEAREST: + min = D3D12_FILTER_TYPE_POINT; + mip = D3D12_FILTER_TYPE_POINT; + break; + case CELL_GCM_TEXTURE_LINEAR_NEAREST: + min = D3D12_FILTER_TYPE_LINEAR; + mip = D3D12_FILTER_TYPE_POINT; + break; + case CELL_GCM_TEXTURE_NEAREST_LINEAR: + min = D3D12_FILTER_TYPE_POINT; + mip = D3D12_FILTER_TYPE_LINEAR; + break; + case CELL_GCM_TEXTURE_LINEAR_LINEAR: + min = D3D12_FILTER_TYPE_LINEAR; + mip = D3D12_FILTER_TYPE_LINEAR; + break; + case CELL_GCM_TEXTURE_CONVOLUTION_MIN: + default: + LOG_ERROR(RSX, "Unknow min filter %x", minFilter); + } + + switch (magFilter) + { + case CELL_GCM_TEXTURE_NEAREST: + mag = D3D12_FILTER_TYPE_POINT; + break; + case CELL_GCM_TEXTURE_LINEAR: + mag = D3D12_FILTER_TYPE_LINEAR; + break; + default: + LOG_ERROR(RSX, "Unknow mag filter %x", magFilter); + } + + return D3D12_ENCODE_BASIC_FILTER(min, mag, mip, D3D12_FILTER_REDUCTION_TYPE_STANDARD); +} + +static +D3D12_SAMPLER_DESC getSamplerDesc(const RSXTexture &texture) +{ + D3D12_SAMPLER_DESC samplerDesc = {}; + samplerDesc.Filter = getSamplerFilter(texture.GetMinFilter(), texture.GetMagFilter()); + samplerDesc.AddressU = getSamplerWrap(texture.GetWrapS()); + samplerDesc.AddressV = getSamplerWrap(texture.GetWrapT()); + samplerDesc.AddressW = getSamplerWrap(texture.GetWrapR()); + samplerDesc.ComparisonFunc = getSamplerCompFunc[texture.GetZfunc()]; + samplerDesc.MaxAnisotropy = (UINT)getSamplerMaxAniso(texture.GetMaxAniso()); + samplerDesc.MipLODBias = texture.GetBias(); + samplerDesc.BorderColor[4] = (FLOAT)texture.GetBorderColor(); + samplerDesc.MinLOD = (FLOAT)(texture.GetMinLOD() >> 8); + samplerDesc.MaxLOD = (FLOAT)(texture.GetMaxLOD() >> 8); + return samplerDesc; +} + +struct MipmapLevelInfo +{ + size_t offset; + size_t width; + size_t height; + size_t rowPitch; +}; + +#define MAX2(a, b) ((a) > (b)) ? (a) : (b) + +/** + * Write data, assume src pixels are packed but not mipmaplevel + */ +static std::vector +writeTexelsGeneric(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount) +{ + std::vector Result; + size_t offsetInDst = 0, offsetInSrc = 0; + size_t currentHeight = heightInBlock, currentWidth = widthInBlock; + for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++) + { + size_t rowPitch = align(currentWidth * blockSize, 256); + + MipmapLevelInfo currentMipmapLevelInfo = {}; + currentMipmapLevelInfo.offset = offsetInDst; + currentMipmapLevelInfo.height = currentHeight; + currentMipmapLevelInfo.width = currentWidth; + currentMipmapLevelInfo.rowPitch = rowPitch; + Result.push_back(currentMipmapLevelInfo); + + for (unsigned row = 0; row < currentHeight; row++) + memcpy((char*)dst + offsetInDst + row * rowPitch, (char*)src + offsetInSrc + row * widthInBlock * blockSize, currentWidth * blockSize); + + offsetInDst += currentHeight * rowPitch; + offsetInDst = align(offsetInDst, 512); + offsetInSrc += currentHeight * widthInBlock * blockSize; + currentHeight = MAX2(currentHeight / 2, 1); + currentWidth = MAX2(currentWidth / 2, 1); + } + return Result; +} + +/** +* Write data, assume src pixels are swizzled and but not mipmaplevel +*/ +static std::vector +writeTexelsSwizzled(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount) +{ + std::vector Result; + size_t offsetInDst = 0, offsetInSrc = 0; + size_t currentHeight = heightInBlock, currentWidth = widthInBlock; + for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++) + { + size_t rowPitch = align(currentWidth * blockSize, 256); + + MipmapLevelInfo currentMipmapLevelInfo = {}; + currentMipmapLevelInfo.offset = offsetInDst; + currentMipmapLevelInfo.height = currentHeight; + currentMipmapLevelInfo.width = currentWidth; + currentMipmapLevelInfo.rowPitch = rowPitch; + Result.push_back(currentMipmapLevelInfo); + + u32 *castedSrc, *castedDst; + u32 log2width, log2height; + + castedSrc = (u32*)src + offsetInSrc; + castedDst = (u32*)dst + offsetInDst; + + log2width = (u32)(logf((float)currentWidth) / logf(2.f)); + log2height = (u32)(logf((float)currentHeight) / logf(2.f)); + +#pragma omp parallel for + for (int row = 0; row < currentHeight; row++) + for (int j = 0; j < currentWidth; j++) + castedDst[(row * rowPitch / 4) + j] = castedSrc[LinearToSwizzleAddress(j, row, 0, log2width, log2height, 0)]; + + offsetInDst += currentHeight * rowPitch; + offsetInSrc += currentHeight * widthInBlock * blockSize; + currentHeight = MAX2(currentHeight / 2, 1); + currentWidth = MAX2(currentWidth / 2, 1); + } + return Result; +} + + +/** +* Write data, assume compressed (DXTCn) format +*/ +static std::vector +writeCompressedTexel(const char *src, char *dst, size_t widthInBlock, size_t blockWidth, size_t heightInBlock, size_t blockHeight, size_t blockSize, size_t mipmapCount) +{ + std::vector Result; + size_t offsetInDst = 0, offsetInSrc = 0; + size_t currentHeight = heightInBlock, currentWidth = widthInBlock; + for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++) + { + size_t rowPitch = align(currentWidth * blockSize, 256); + + MipmapLevelInfo currentMipmapLevelInfo = {}; + currentMipmapLevelInfo.offset = offsetInDst; + currentMipmapLevelInfo.height = currentHeight * blockHeight; + currentMipmapLevelInfo.width = currentWidth * blockWidth; + currentMipmapLevelInfo.rowPitch = rowPitch; + Result.push_back(currentMipmapLevelInfo); + + for (unsigned row = 0; row < currentHeight; row++) + memcpy((char*)dst + offsetInDst + row * rowPitch, (char*)src + offsetInSrc + row * currentWidth * blockSize, currentWidth * blockSize); + + offsetInDst += currentHeight * rowPitch; + offsetInDst = align(offsetInDst, 512); + offsetInSrc += currentHeight * currentWidth * blockSize; + currentHeight = MAX2(currentHeight / 2, 1); + currentWidth = MAX2(currentWidth / 2, 1); + } + return Result; +} + + +/** +* Write 16 bytes pixel textures, assume src pixels are swizzled and but not mipmaplevel +*/ +static std::vector +write16bTexelsSwizzled(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount) +{ + std::vector Result; + size_t offsetInDst = 0, offsetInSrc = 0; + size_t currentHeight = heightInBlock, currentWidth = widthInBlock; + for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++) + { + size_t rowPitch = align(currentWidth * blockSize, 256); + + MipmapLevelInfo currentMipmapLevelInfo = {}; + currentMipmapLevelInfo.offset = offsetInDst; + currentMipmapLevelInfo.height = currentHeight; + currentMipmapLevelInfo.width = currentWidth; + currentMipmapLevelInfo.rowPitch = rowPitch; + Result.push_back(currentMipmapLevelInfo); + + u16 *castedSrc, *castedDst; + u16 log2width, log2height; + + castedSrc = (u16*)src + offsetInSrc; + castedDst = (u16*)dst + offsetInDst; + + log2width = (u32)(logf((float)currentWidth) / logf(2.f)); + log2height = (u32)(logf((float)currentHeight) / logf(2.f)); + +#pragma omp parallel for + for (int row = 0; row < currentHeight; row++) + for (int j = 0; j < currentWidth; j++) + castedDst[(row * rowPitch / 2) + j] = castedSrc[LinearToSwizzleAddress(j, row, 0, log2width, log2height, 0)]; + + offsetInDst += currentHeight * rowPitch; + offsetInSrc += currentHeight * widthInBlock * blockSize; + currentHeight = MAX2(currentHeight / 2, 1); + currentWidth = MAX2(currentWidth / 2, 1); + } + return Result; +} + +/** +* Write 16 bytes pixel textures, assume src pixels are packed but not mipmaplevel +*/ +static std::vector +write16bTexelsGeneric(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount) +{ + std::vector Result; + size_t offsetInDst = 0, offsetInSrc = 0; + size_t currentHeight = heightInBlock, currentWidth = widthInBlock; + size_t srcPitch = widthInBlock * blockSize; + for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++) + { + size_t rowPitch = align(currentWidth * blockSize, 256); + + MipmapLevelInfo currentMipmapLevelInfo = {}; + currentMipmapLevelInfo.offset = offsetInDst; + currentMipmapLevelInfo.height = currentHeight; + currentMipmapLevelInfo.width = currentWidth; + currentMipmapLevelInfo.rowPitch = rowPitch; + Result.push_back(currentMipmapLevelInfo); + + unsigned short *castedDst = (unsigned short *)dst, *castedSrc = (unsigned short *)src; + + for (unsigned row = 0; row < heightInBlock; row++) + for (int j = 0; j < currentWidth; j++) + { + u16 tmp = castedSrc[offsetInSrc / 2 + row * srcPitch / 2 + j]; + castedDst[offsetInDst / 2 + row * rowPitch / 2 + j] = (tmp >> 8) | (tmp << 8); + } + + offsetInDst += currentHeight * rowPitch; + offsetInSrc += currentHeight * widthInBlock * blockSize; + currentHeight = MAX2(currentHeight / 2, 1); + currentWidth = MAX2(currentWidth / 2, 1); + } + return Result; +} + +/** +* Write 16 bytes pixel textures, assume src pixels are packed but not mipmaplevel +*/ +static std::vector +write16bX4TexelsGeneric(const char *src, char *dst, size_t widthInBlock, size_t heightInBlock, size_t blockSize, size_t mipmapCount) +{ + std::vector Result; + size_t offsetInDst = 0, offsetInSrc = 0; + size_t currentHeight = heightInBlock, currentWidth = widthInBlock; + size_t srcPitch = widthInBlock * blockSize; + for (unsigned mipLevel = 0; mipLevel < mipmapCount; mipLevel++) + { + size_t rowPitch = align(currentWidth * blockSize, 256); + + MipmapLevelInfo currentMipmapLevelInfo = {}; + currentMipmapLevelInfo.offset = offsetInDst; + currentMipmapLevelInfo.height = currentHeight; + currentMipmapLevelInfo.width = currentWidth; + currentMipmapLevelInfo.rowPitch = rowPitch; + Result.push_back(currentMipmapLevelInfo); + + unsigned short *castedDst = (unsigned short *)dst, *castedSrc = (unsigned short *)src; + + for (unsigned row = 0; row < heightInBlock; row++) + for (int j = 0; j < currentWidth * 4; j++) + { + u16 tmp = castedSrc[offsetInSrc / 2 + row * srcPitch / 2 + j]; + castedDst[offsetInDst / 2 + row * rowPitch / 2 + j] = (tmp >> 8) | (tmp << 8); + } + + offsetInDst += currentHeight * rowPitch; + offsetInSrc += currentHeight * widthInBlock * blockSize; + currentHeight = MAX2(currentHeight / 2, 1); + currentWidth = MAX2(currentWidth / 2, 1); + } + return Result; +} + +/** + * Create a texture residing in default heap and generate uploads commands in commandList, + * using a temporary texture buffer. + */ +static +ID3D12Resource *uploadSingleTexture( + const RSXTexture &texture, + ID3D12Device *device, + ID3D12GraphicsCommandList *commandList, + DataHeap &textureBuffersHeap) +{ + ID3D12Resource *vramTexture; + size_t w = texture.GetWidth(), h = texture.GetHeight(); + + size_t blockSizeInByte, blockWidthInPixel, blockHeightInPixel; + int format = texture.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + DXGI_FORMAT dxgiFormat = getTextureDXGIFormat(format); + + const u32 texaddr = GetAddress(texture.GetOffset(), texture.GetLocation()); + + bool is_swizzled = !(texture.GetFormat() & CELL_GCM_TEXTURE_LN); + size_t srcPitch; + switch (format) + { + case CELL_GCM_TEXTURE_COMPRESSED_HILO8: + case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + default: + LOG_ERROR(RSX, "Unimplemented Texture format : %x", format); + break; + case CELL_GCM_TEXTURE_B8: + blockSizeInByte = 1; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w; + break; + case CELL_GCM_TEXTURE_A1R5G5B5: + blockSizeInByte = 2; + blockHeightInPixel = 1, blockWidthInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_A4R4G4B4: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_R5G6B5: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_A8R8G8B8: + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + blockSizeInByte = 8; + blockWidthInPixel = 4, blockHeightInPixel = 4; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + blockSizeInByte = 16; + blockWidthInPixel = 4, blockHeightInPixel = 4; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + blockSizeInByte = 16; + blockWidthInPixel = 4, blockHeightInPixel = 4; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_G8B8: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_R6G5B5: + // Not native + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_DEPTH24_D8: + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_DEPTH16: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_DEPTH16_FLOAT: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_X16: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_Y16_X16: + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_R5G5B5A1: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: + blockSizeInByte = 8; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 8; + break; + case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: + blockSizeInByte = 16; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 16; + break; + case CELL_GCM_TEXTURE_X32_FLOAT: + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_D1R5G5B5: + blockSizeInByte = 2; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 2; + break; + case CELL_GCM_TEXTURE_Y16_X16_FLOAT: + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_D8R8G8B8: + blockSizeInByte = 4; + blockWidthInPixel = 1, blockHeightInPixel = 1; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + blockSizeInByte = 4; + blockWidthInPixel = 2, blockHeightInPixel = 2; + srcPitch = w * 4; + break; + case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + blockSizeInByte = 4; + blockWidthInPixel = 2, blockHeightInPixel = 2; + srcPitch = w * 4; + break; + } + + size_t heightInBlocks = (h + blockHeightInPixel - 1) / blockHeightInPixel; + size_t widthInBlocks = (w + blockWidthInPixel - 1) / blockWidthInPixel; + // Multiple of 256 + size_t rowPitch = align(blockSizeInByte * widthInBlocks, 256); + + ID3D12Resource *Texture; + size_t textureSize = rowPitch * heightInBlocks * 2; // * 4 for mipmap levels + assert(textureBuffersHeap.canAlloc(textureSize)); + size_t heapOffset = textureBuffersHeap.alloc(textureSize); + + check(device->CreatePlacedResource( + textureBuffersHeap.m_heap, + heapOffset, + &getBufferResourceDesc(textureSize), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&Texture) + )); + textureBuffersHeap.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset, textureSize, Texture)); + + auto pixels = vm::get_ptr(texaddr); + void *textureData; + check(Texture->Map(0, nullptr, (void**)&textureData)); + std::vector mipInfos; + + switch (format) + { + case CELL_GCM_TEXTURE_A8R8G8B8: + { + if (is_swizzled) + mipInfos = writeTexelsSwizzled((char*)pixels, (char*)textureData, w, h, 4, texture.GetMipmap()); + else + mipInfos = writeTexelsGeneric((char*)pixels, (char*)textureData, w, h, 4, texture.GetMipmap()); + break; + } + case CELL_GCM_TEXTURE_A1R5G5B5: + case CELL_GCM_TEXTURE_A4R4G4B4: + case CELL_GCM_TEXTURE_R5G6B5: + { + if (is_swizzled) + mipInfos = write16bTexelsSwizzled((char*)pixels, (char*)textureData, w, h, 2, texture.GetMipmap()); + else + mipInfos = write16bTexelsGeneric((char*)pixels, (char*)textureData, w, h, 2, texture.GetMipmap()); + break; + } + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: + { + mipInfos = write16bX4TexelsGeneric((char*)pixels, (char*)textureData, w, h, 8, texture.GetMipmap()); + break; + } + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + { + mipInfos = writeCompressedTexel((char*)pixels, (char*)textureData, widthInBlocks, blockWidthInPixel, heightInBlocks, blockHeightInPixel, blockSizeInByte, texture.GetMipmap()); + break; + } + default: + { + mipInfos = writeTexelsGeneric((char*)pixels, (char*)textureData, w, h, blockSizeInByte, texture.GetMipmap()); + break; + } + } + Texture->Unmap(0, nullptr); + + D3D12_RESOURCE_DESC texturedesc = getTexture2DResourceDesc(w, h, dxgiFormat, texture.GetMipmap()); + textureSize = device->GetResourceAllocationInfo(0, 1, &texturedesc).SizeInBytes; + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; + + check(device->CreateCommittedResource( + &heapProp, + D3D12_HEAP_FLAG_NONE, + &texturedesc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&vramTexture) + )); + + size_t miplevel = 0; + for (const MipmapLevelInfo mli : mipInfos) + { + D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; + dst.pResource = vramTexture; + dst.SubresourceIndex = (UINT)miplevel; + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.PlacedFootprint.Offset = mli.offset; + src.pResource = Texture; + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.PlacedFootprint.Footprint.Depth = 1; + src.PlacedFootprint.Footprint.Width = (UINT)mli.width; + src.PlacedFootprint.Footprint.Height = (UINT)mli.height; + src.PlacedFootprint.Footprint.RowPitch = (UINT)mli.rowPitch; + src.PlacedFootprint.Footprint.Format = dxgiFormat; + + commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + miplevel++; + } + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = vramTexture; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; + commandList->ResourceBarrier(1, &barrier); + return vramTexture; +} + +/** + * Get number of bytes occupied by texture in RSX mem + */ +static +size_t getTextureSize(const RSXTexture &texture) +{ + size_t w = texture.GetWidth(), h = texture.GetHeight(); + + int format = texture.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + // TODO: Take mipmaps into account + switch (format) + { + case CELL_GCM_TEXTURE_COMPRESSED_HILO8: + case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + default: + LOG_ERROR(RSX, "Unimplemented Texture format : %x", format); + return 0; + case CELL_GCM_TEXTURE_B8: + return w * h; + case CELL_GCM_TEXTURE_A1R5G5B5: + return w * h * 2; + case CELL_GCM_TEXTURE_A4R4G4B4: + return w * h * 2; + case CELL_GCM_TEXTURE_R5G6B5: + return w * h * 2; + case CELL_GCM_TEXTURE_A8R8G8B8: + return w * h * 4; + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + return w * h / 6; + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + return w * h / 4; + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + return w * h / 4; + case CELL_GCM_TEXTURE_G8B8: + return w * h * 2; + case CELL_GCM_TEXTURE_R6G5B5: + return w * h * 2; + case CELL_GCM_TEXTURE_DEPTH24_D8: + return w * h * 4; + case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: + return w * h * 4; + case CELL_GCM_TEXTURE_DEPTH16: + return w * h * 2; + case CELL_GCM_TEXTURE_DEPTH16_FLOAT: + return w * h * 2; + case CELL_GCM_TEXTURE_X16: + return w * h * 2; + case CELL_GCM_TEXTURE_Y16_X16: + return w * h * 4; + case CELL_GCM_TEXTURE_R5G5B5A1: + return w * h * 2; + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: + return w * h * 8; + case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: + return w * h * 16; + case CELL_GCM_TEXTURE_X32_FLOAT: + return w * h * 4; + case CELL_GCM_TEXTURE_D1R5G5B5: + return w * h * 2; + case CELL_GCM_TEXTURE_Y16_X16_FLOAT: + return w * h * 4; + case CELL_GCM_TEXTURE_D8R8G8B8: + return w * h * 4; + case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + return w * h * 4; + case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + return w * h * 4; + } +} + +size_t D3D12GSRender::UploadTextures() +{ + std::lock_guard lock(mut); + size_t usedTexture = 0; + + for (u32 i = 0; i < m_textures_count; ++i) + { + if (!m_textures[i].IsEnabled()) continue; + size_t w = m_textures[i].GetWidth(), h = m_textures[i].GetHeight(); + if (!w || !h) continue; + + const u32 texaddr = GetAddress(m_textures[i].GetOffset(), m_textures[i].GetLocation()); + + int format = m_textures[i].GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); + DXGI_FORMAT dxgiFormat = getTextureDXGIFormat(format); + bool is_swizzled = !(m_textures[i].GetFormat() & CELL_GCM_TEXTURE_LN); + + ID3D12Resource *vramTexture; + std::unordered_map::const_iterator ItRTT = m_rtts.m_renderTargets.find(texaddr); + std::unordered_map::const_iterator ItCache = m_texturesCache.find(texaddr); + bool isRenderTarget = false; + if (ItRTT != m_rtts.m_renderTargets.end()) + { + vramTexture = ItRTT->second; + isRenderTarget = true; + } + else if (ItCache != m_texturesCache.end()) + { + vramTexture = ItCache->second; + } + else + { + // Upload at each iteration to take advantage of overlapping transfer + ID3D12GraphicsCommandList *commandList; + check(m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, getCurrentResourceStorage().m_textureUploadCommandAllocator, nullptr, IID_PPV_ARGS(&commandList))); + + vramTexture = uploadSingleTexture(m_textures[i], m_device, commandList, m_textureUploadData); + + check(commandList->Close()); + m_commandQueueGraphic->ExecuteCommandLists(1, (ID3D12CommandList**)&commandList); + getCurrentResourceStorage().m_inflightCommandList.push_back(commandList); + m_texturesCache[texaddr] = vramTexture; + + u32 s = (u32)align(getTextureSize(m_textures[i]), 4096); + LOG_WARNING(RSX, "PROTECTING %x of size %d", align(texaddr, 4096), s); + m_protectedTextures.push_back(std::make_tuple(texaddr, align(texaddr, 4096), s)); + vm::page_protect(align(texaddr, 4096), s, 0, 0, vm::page_writable); + } + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; + srvDesc.Format = dxgiFormat; + srvDesc.Texture2D.MipLevels = m_textures[i].GetMipmap(); + + switch (format) + { + case CELL_GCM_TEXTURE_COMPRESSED_HILO8: + case CELL_GCM_TEXTURE_COMPRESSED_HILO_S8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + case ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) & CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + default: + LOG_ERROR(RSX, "Unimplemented Texture format : %x", format); + break; + case CELL_GCM_TEXTURE_B8: + srvDesc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0); + break; + case CELL_GCM_TEXTURE_A1R5G5B5: + case CELL_GCM_TEXTURE_A4R4G4B4: + case CELL_GCM_TEXTURE_R5G6B5: + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + break; + case CELL_GCM_TEXTURE_A8R8G8B8: + { + const int RemapValue[4] = + { + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_0 + }; + + u8 remap_a = m_textures[i].GetRemap() & 0x3; + u8 remap_r = (m_textures[i].GetRemap() >> 2) & 0x3; + u8 remap_g = (m_textures[i].GetRemap() >> 4) & 0x3; + u8 remap_b = (m_textures[i].GetRemap() >> 6) & 0x3; + if (isRenderTarget) + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + else + srvDesc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( + RemapValue[remap_a], + RemapValue[remap_r], + RemapValue[remap_g], + RemapValue[remap_b]); + + break; + } + case CELL_GCM_TEXTURE_COMPRESSED_DXT1: + case CELL_GCM_TEXTURE_COMPRESSED_DXT23: + case CELL_GCM_TEXTURE_COMPRESSED_DXT45: + case CELL_GCM_TEXTURE_G8B8: + case CELL_GCM_TEXTURE_R6G5B5: + case CELL_GCM_TEXTURE_DEPTH24_D8: + case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: + case CELL_GCM_TEXTURE_DEPTH16: + case CELL_GCM_TEXTURE_DEPTH16_FLOAT: + case CELL_GCM_TEXTURE_X16: + case CELL_GCM_TEXTURE_Y16_X16: + case CELL_GCM_TEXTURE_R5G5B5A1: + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: + case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: + case CELL_GCM_TEXTURE_X32_FLOAT: + case CELL_GCM_TEXTURE_D1R5G5B5: + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + break; + case CELL_GCM_TEXTURE_D8R8G8B8: + { + const int RemapValue[4] = + { + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_1, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_2, + D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_3, + D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1 + }; + + u8 remap_a = m_textures[i].GetRemap() & 0x3; + u8 remap_r = (m_textures[i].GetRemap() >> 2) & 0x3; + u8 remap_g = (m_textures[i].GetRemap() >> 4) & 0x3; + u8 remap_b = (m_textures[i].GetRemap() >> 6) & 0x3; + + srvDesc.Shader4ComponentMapping = D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING( + RemapValue[remap_a], + RemapValue[remap_r], + RemapValue[remap_g], + RemapValue[remap_b]); + break; + } + case CELL_GCM_TEXTURE_Y16_X16_FLOAT: + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + break; + case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8: + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + break; + case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8: + srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; + break; + } + + D3D12_CPU_DESCRIPTOR_HANDLE Handle = getCurrentResourceStorage().m_textureDescriptorsHeap->GetCPUDescriptorHandleForHeapStart(); + Handle.ptr += (getCurrentResourceStorage().m_currentTextureIndex + usedTexture) * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + m_device->CreateShaderResourceView(vramTexture, &srvDesc, Handle); + + if (getCurrentResourceStorage().m_currentSamplerIndex + 16 > 2048) + { + getCurrentResourceStorage().m_samplerDescriptorHeapIndex = 1; + getCurrentResourceStorage().m_currentSamplerIndex = 0; + } + + Handle = getCurrentResourceStorage().m_samplerDescriptorHeap[getCurrentResourceStorage().m_samplerDescriptorHeapIndex]->GetCPUDescriptorHandleForHeapStart(); + Handle.ptr += (getCurrentResourceStorage().m_currentSamplerIndex + usedTexture) * m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER); + m_device->CreateSampler(&getSamplerDesc(m_textures[i]), Handle); + + usedTexture++; + } + + return usedTexture; +} + +#endif diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.h b/rpcs3/Emu/RSX/D3D12/D3D12Texture.h new file mode 100644 index 0000000000..6f70f09bee --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.h @@ -0,0 +1 @@ +#pragma once diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp new file mode 100644 index 0000000000..1e51d30ab1 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12Utils.cpp @@ -0,0 +1,248 @@ +/** +* Contains utility shaders +*/ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "D3D12GSRender.h" +#include +#define STRINGIFY(x) #x + +extern PFN_D3D12_SERIALIZE_ROOT_SIGNATURE wrapD3D12SerializeRootSignature; + + /** + * returns bytecode and root signature of a Compute Shader converting texture from + * one format to another + */ +static +std::pair compileF32toU8CS() +{ + const char *shaderCode = STRINGIFY( + Texture2D InputTexture : register(t0); \n + RWTexture2D OutputTexture : register(u0);\n + + [numthreads(8, 8, 1)]\n + void main(uint3 Id : SV_DispatchThreadID)\n + { \n + OutputTexture[Id.xy] = InputTexture.Load(uint3(Id.xy, 0));\n + } + ); + + ID3DBlob *bytecode; + Microsoft::WRL::ComPtr errorBlob; + HRESULT hr = D3DCompile(shaderCode, strlen(shaderCode), "test", nullptr, nullptr, "main", "cs_5_0", 0, 0, &bytecode, errorBlob.GetAddressOf()); + if (hr != S_OK) + { + const char *tmp = (const char*)errorBlob->GetBufferPointer(); + LOG_ERROR(RSX, tmp); + } + D3D12_DESCRIPTOR_RANGE descriptorRange[2] = {}; + // Textures + descriptorRange[0].BaseShaderRegister = 0; + descriptorRange[0].NumDescriptors = 1; + descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange[1].BaseShaderRegister = 0; + descriptorRange[1].NumDescriptors = 1; + descriptorRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + descriptorRange[1].OffsetInDescriptorsFromTableStart = 1; + D3D12_ROOT_PARAMETER RP[2] = {}; + RP[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP[0].DescriptorTable.pDescriptorRanges = &descriptorRange[0]; + RP[0].DescriptorTable.NumDescriptorRanges = 2; + + D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; + rootSignatureDesc.NumParameters = 1; + rootSignatureDesc.pParameters = RP; + + ID3DBlob *rootSignatureBlob; + + hr = wrapD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob); + if (hr != S_OK) + { + const char *tmp = (const char*)errorBlob->GetBufferPointer(); + LOG_ERROR(RSX, tmp); + } + + return std::make_pair(bytecode, rootSignatureBlob); +} + + +void D3D12GSRender::Shader::Init(ID3D12Device *device) +{ + const char *fsCode = STRINGIFY( + Texture2D InputTexture : register(t0); \n + sampler bilinearSampler : register(s0); \n + + struct PixelInput \n + { \n + float4 Pos : SV_POSITION; \n + float2 TexCoords : TEXCOORDS0; \n + }; \n + + float4 main(PixelInput In) : SV_TARGET \n + { \n + return InputTexture.Sample(bilinearSampler, In.TexCoords); \n + } + ); + + Microsoft::WRL::ComPtr fsBytecode; + Microsoft::WRL::ComPtr errorBlob; + HRESULT hr = D3DCompile(fsCode, strlen(fsCode), "test", nullptr, nullptr, "main", "ps_5_0", 0, 0, &fsBytecode, errorBlob.GetAddressOf()); + if (hr != S_OK) + { + const char *tmp = (const char*)errorBlob->GetBufferPointer(); + LOG_ERROR(RSX, tmp); + } + + const char *vsCode = STRINGIFY( + struct VertexInput \n + { \n + float2 Pos : POSITION; \n + float2 TexCoords : TEXCOORDS0; \n + }; \n + + struct PixelInput \n + { \n + float4 Pos : SV_POSITION; \n + float2 TexCoords : TEXCOORDS0; \n + }; \n + + PixelInput main(VertexInput In) \n + { \n + PixelInput Out; \n + Out.Pos = float4(In.Pos, 0., 1.); \n + Out.TexCoords = In.TexCoords; \n + return Out; \n + } + ); + + Microsoft::WRL::ComPtr vsBytecode; + hr = D3DCompile(vsCode, strlen(vsCode), "test", nullptr, nullptr, "main", "vs_5_0", 0, 0, &vsBytecode, errorBlob.GetAddressOf()); + if (hr != S_OK) + { + const char *tmp = (const char*)errorBlob->GetBufferPointer(); + LOG_ERROR(RSX, tmp); + } + + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + psoDesc.PS.BytecodeLength = fsBytecode->GetBufferSize(); + psoDesc.PS.pShaderBytecode = fsBytecode->GetBufferPointer(); + psoDesc.VS.BytecodeLength = vsBytecode->GetBufferSize(); + psoDesc.VS.pShaderBytecode = vsBytecode->GetBufferPointer(); + psoDesc.NumRenderTargets = 1; + psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; + psoDesc.SampleDesc.Count = 1; + psoDesc.SampleMask = UINT_MAX; + + D3D12_INPUT_ELEMENT_DESC IADesc[2] = {}; + IADesc[0].SemanticName = "POSITION"; + IADesc[0].Format = DXGI_FORMAT_R32G32_FLOAT; + IADesc[1].SemanticName = "TEXCOORDS"; + IADesc[1].Format = DXGI_FORMAT_R32G32_FLOAT; + IADesc[1].AlignedByteOffset = 2 * sizeof(float); + + psoDesc.InputLayout.NumElements = 2; + psoDesc.InputLayout.pInputElementDescs = IADesc; + + psoDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + psoDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + + D3D12_DESCRIPTOR_RANGE descriptorRange[2] = {}; + // Textures + descriptorRange[0].BaseShaderRegister = 0; + descriptorRange[0].NumDescriptors = 1; + descriptorRange[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + descriptorRange[1].BaseShaderRegister = 0; + descriptorRange[1].NumDescriptors = 1; + descriptorRange[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + D3D12_ROOT_PARAMETER RP[2] = {}; + RP[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP[0].DescriptorTable.pDescriptorRanges = &descriptorRange[0]; + RP[0].DescriptorTable.NumDescriptorRanges = 1; + RP[1].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + RP[1].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + RP[1].DescriptorTable.pDescriptorRanges = &descriptorRange[1]; + RP[1].DescriptorTable.NumDescriptorRanges = 1; + + D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = {}; + rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + rootSignatureDesc.NumParameters = 2; + rootSignatureDesc.pParameters = RP; + + Microsoft::WRL::ComPtr rootSignatureBlob; + + hr = wrapD3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &rootSignatureBlob, &errorBlob); + if (hr != S_OK) + { + const char *tmp = (const char*)errorBlob->GetBufferPointer(); + LOG_ERROR(RSX, tmp); + } + + hr = device->CreateRootSignature(0, rootSignatureBlob->GetBufferPointer(), rootSignatureBlob->GetBufferSize(), IID_PPV_ARGS(&m_rootSignature)); + + psoDesc.pRootSignature = m_rootSignature; + psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + psoDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + + check(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&m_PSO))); + + + float quadVertex[16] = { + -1., -1., 0., 1., + -1., 1., 0., 0., + 1., -1., 1., 1., + 1., 1., 1., 0., + }; + + D3D12_HEAP_PROPERTIES heapProp = {}; + heapProp.Type = D3D12_HEAP_TYPE_UPLOAD; + check( + device->CreateCommittedResource( + &heapProp, + D3D12_HEAP_FLAG_NONE, + &getBufferResourceDesc(16 * sizeof(float)), + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&m_vertexBuffer) + )); + + void *tmp; + m_vertexBuffer->Map(0, nullptr, &tmp); + memcpy(tmp, quadVertex, 16 * sizeof(float)); + m_vertexBuffer->Unmap(0, nullptr); + + D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {}; + heapDesc.NumDescriptors = 2; + heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + + check( + device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_textureDescriptorHeap)) + ); + heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER; + check( + device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_samplerDescriptorHeap)) + ); +} + +void D3D12GSRender::initConvertShader() +{ + const auto &p = compileF32toU8CS(); + check( + m_device->CreateRootSignature(0, p.second->GetBufferPointer(), p.second->GetBufferSize(), IID_PPV_ARGS(&m_convertRootSignature)) + ); + + D3D12_COMPUTE_PIPELINE_STATE_DESC computePipelineStateDesc = {}; + computePipelineStateDesc.CS.BytecodeLength = p.first->GetBufferSize(); + computePipelineStateDesc.CS.pShaderBytecode = p.first->GetBufferPointer(); + computePipelineStateDesc.pRootSignature = m_convertRootSignature; + + check( + m_device->CreateComputePipelineState(&computePipelineStateDesc, IID_PPV_ARGS(&m_convertPSO)) + ); + + p.first->Release(); + p.second->Release(); +} +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp new file mode 100644 index 0000000000..11d7ddf342 --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.cpp @@ -0,0 +1,161 @@ +#include "stdafx.h" +#if defined(DX12_SUPPORT) +#include "D3D12VertexProgramDecompiler.h" +#include "D3D12CommonDecompiler.h" +#include "Utilities/Log.h" +#include "Emu/System.h" + + +std::string D3D12VertexProgramDecompiler::getFloatTypeName(size_t elementCount) +{ + return getFloatTypeNameImp(elementCount); +} + +std::string D3D12VertexProgramDecompiler::getFunction(enum class FUNCTION f) +{ + return getFunctionImp(f); +} + +std::string D3D12VertexProgramDecompiler::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1) +{ + return compareFunctionImp(f, Op0, Op1); +} + +void D3D12VertexProgramDecompiler::insertHeader(std::stringstream &OS) +{ + OS << "cbuffer SCALE_OFFSET : register(b0)" << std::endl; + OS << "{" << std::endl; + OS << " float4x4 scaleOffsetMat;" << std::endl; + OS << " int isAlphaTested;" << std::endl; + OS << " float alphaRef;" << std::endl; + OS << "};" << std::endl; +} + +void D3D12VertexProgramDecompiler::insertInputs(std::stringstream & OS, const std::vector& inputs) +{ + OS << "struct VertexInput" << std::endl; + OS << "{" << std::endl; + for (const ParamType PT : inputs) + { + for (const ParamItem &PI : PT.items) + OS << " " << PT.type << " " << PI.name << ": TEXCOORD" << PI.location << ";" << std::endl; + } + OS << "};" << std::endl; +} + +void D3D12VertexProgramDecompiler::insertConstants(std::stringstream & OS, const std::vector & constants) +{ + OS << "cbuffer CONSTANT_BUFFER : register(b1)" << std::endl; + OS << "{" << std::endl; + for (const ParamType PT : constants) + { + for (const ParamItem &PI : PT.items) + OS << " " << PT.type << " " << PI.name << ";" << std::endl; + } + OS << "};" << std::endl; +} + +void D3D12VertexProgramDecompiler::insertOutputs(std::stringstream & OS, const std::vector & outputs) +{ + OS << "struct PixelInput" << std::endl; + OS << "{" << std::endl; + OS << " float4 dst_reg0 : SV_POSITION;" << std::endl; + OS << " float4 dst_reg1 : COLOR0;" << std::endl; + OS << " float4 dst_reg2 : COLOR1;" << std::endl; + OS << " float4 dst_reg3 : COLOR2;" << std::endl; + OS << " float4 dst_reg4 : COLOR3;" << std::endl; + OS << " float dst_reg5 : FOG;" << std::endl; + OS << " float4 dst_reg6 : COLOR4;" << std::endl; + OS << " float4 dst_reg7 : TEXCOORD0;" << std::endl; + OS << " float4 dst_reg8 : TEXCOORD1;" << std::endl; + OS << " float4 dst_reg9 : TEXCOORD2;" << std::endl; + OS << " float4 dst_reg10 : TEXCOORD3;" << std::endl; + OS << " float4 dst_reg11 : TEXCOORD4;" << std::endl; + OS << " float4 dst_reg12 : TEXCOORD5;" << std::endl; + OS << " float4 dst_reg13 : TEXCOORD6;" << std::endl; + OS << " float4 dst_reg14 : TEXCOORD7;" << std::endl; + OS << " float4 dst_reg15 : TEXCOORD8;" << std::endl; + OS << "};" << std::endl; +} + +struct reg_info +{ + std::string name; + bool need_declare; + std::string src_reg; + std::string src_reg_mask; + bool need_cast; +}; + +static const reg_info reg_table[] = +{ + { "gl_Position", false, "dst_reg0", "", false }, + { "diff_color", true, "dst_reg1", "", false }, + { "spec_color", true, "dst_reg2", "", false }, + { "front_diff_color", true, "dst_reg3", "", false }, + { "front_spec_color", true, "dst_reg4", "", false }, + { "fogc", true, "dst_reg5", ".x", true }, + { "gl_ClipDistance[0]", false, "dst_reg5", ".y", false }, + { "gl_ClipDistance[1]", false, "dst_reg5", ".z", false }, + { "gl_ClipDistance[2]", false, "dst_reg5", ".w", false }, + { "gl_PointSize", false, "dst_reg6", ".x", false }, + { "gl_ClipDistance[3]", false, "dst_reg6", ".y", false }, + { "gl_ClipDistance[4]", false, "dst_reg6", ".z", false }, + { "gl_ClipDistance[5]", false, "dst_reg6", ".w", false }, + { "tc0", true, "dst_reg7", "", false }, + { "tc1", true, "dst_reg8", "", false }, + { "tc2", true, "dst_reg9", "", false }, + { "tc3", true, "dst_reg10", "", false }, + { "tc4", true, "dst_reg11", "", false }, + { "tc5", true, "dst_reg12", "", false }, + { "tc6", true, "dst_reg13", "", false }, + { "tc7", true, "dst_reg14", "", false }, + { "tc8", true, "dst_reg15", "", false }, + { "tc9", true, "dst_reg6", "", false } // In this line, dst_reg6 is correct since dst_reg goes from 0 to 15. +}; + +void D3D12VertexProgramDecompiler::insertMainStart(std::stringstream & OS) +{ + OS << "PixelInput main(VertexInput In)" << std::endl; + OS << "{" << std::endl; + + // Declare inside main function + for (const ParamType PT : m_parr.params[PF_PARAM_NONE]) + { + for (const ParamItem &PI : PT.items) + { + OS << " " << PT.type << " " << PI.name; + if (!PI.value.empty()) + OS << " = " << PI.value; + OS << ";" << std::endl; + } + } + + for (const ParamType PT : m_parr.params[PF_PARAM_IN]) + { + for (const ParamItem &PI : PT.items) + OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";" << std::endl; + } +} + + +void D3D12VertexProgramDecompiler::insertMainEnd(std::stringstream & OS) +{ + OS << " PixelInput Out;" << std::endl; + // Declare inside main function + for (auto &i : reg_table) + { + if (m_parr.HasParam(PF_PARAM_NONE, "float4", i.src_reg)) + OS << " Out." << i.src_reg << " = " << i.src_reg << ";" << std::endl; + } + OS << " Out.dst_reg0 = mul(Out.dst_reg0, scaleOffsetMat);" << std::endl; + OS << " return Out;" << std::endl; + OS << "}" << std::endl; +} + +D3D12VertexProgramDecompiler::D3D12VertexProgramDecompiler(std::vector& data) : + VertexProgramDecompiler(data) +{ +} + +#endif diff --git a/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.h b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.h new file mode 100644 index 0000000000..d61642c18b --- /dev/null +++ b/rpcs3/Emu/RSX/D3D12/D3D12VertexProgramDecompiler.h @@ -0,0 +1,23 @@ +#pragma once +#if defined(DX12_SUPPORT) +#include +#include +#include "../Common/VertexProgramDecompiler.h" + +struct D3D12VertexProgramDecompiler : public VertexProgramDecompiler +{ +protected: + virtual std::string getFloatTypeName(size_t elementCount) override; + virtual std::string getFunction(enum class FUNCTION) override; + virtual std::string compareFunction(enum class COMPARE, const std::string &, const std::string &) override; + + virtual void insertHeader(std::stringstream &OS); + virtual void insertInputs(std::stringstream &OS, const std::vector &inputs); + virtual void insertConstants(std::stringstream &OS, const std::vector &constants); + virtual void insertOutputs(std::stringstream &OS, const std::vector &outputs); + virtual void insertMainStart(std::stringstream &OS); + virtual void insertMainEnd(std::stringstream &OS); +public: + D3D12VertexProgramDecompiler(std::vector& data); +}; +#endif \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GCM.h b/rpcs3/Emu/RSX/GCM.h index 71aa10ee82..72b753a12a 100644 --- a/rpcs3/Emu/RSX/GCM.h +++ b/rpcs3/Emu/RSX/GCM.h @@ -134,6 +134,87 @@ enum CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP_TO_EDGE = 6, CELL_GCM_TEXTURE_MIRROR_ONCE_BORDER = 7, CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP = 8, + + // Logic Op + CELL_GCM_CLEAR = 0x1500, + CELL_GCM_AND = 0x1501, + CELL_GCM_AND_REVERSE = 0x1502, + CELL_GCM_COPY = 0x1503, + CELL_GCM_AND_INVERTED = 0x1504, + CELL_GCM_NOOP = 0x1505, + CELL_GCM_XOR = 0x1506, + CELL_GCM_OR = 0x1507, + CELL_GCM_NOR = 0x1508, + CELL_GCM_EQUIV = 0x1509, + CELL_GCM_INVERT = 0x150A, + CELL_GCM_OR_REVERSE = 0x150B, + CELL_GCM_COPY_INVERTED = 0x150C, + CELL_GCM_OR_INVERTED = 0x150D, + CELL_GCM_NAND = 0x150E, + CELL_GCM_SET = 0x150F, + + // Blend Op + CELL_GCM_FUNC_ADD = 0x8006, + CELL_GCM_MIN = 0x8007, + CELL_GCM_MAX = 0x8008, + CELL_GCM_FUNC_SUBTRACT = 0x800A, + CELL_GCM_FUNC_REVERSE_SUBTRACT = 0x800B, + CELL_GCM_FUNC_REVERSE_SUBTRACT_SIGNED = 0x0000F005, + CELL_GCM_FUNC_ADD_SIGNED = 0x0000F006, + CELL_GCM_FUNC_REVERSE_ADD_SIGNED = 0x0000F007, + + // Blend Factor + CELL_GCM_ZERO = 0, + CELL_GCM_ONE = 1, + CELL_GCM_SRC_COLOR = 0x0300, + CELL_GCM_ONE_MINUS_SRC_COLOR = 0x0301, + CELL_GCM_SRC_ALPHA = 0x0302, + CELL_GCM_ONE_MINUS_SRC_ALPHA = 0x0303, + CELL_GCM_DST_ALPHA = 0x0304, + CELL_GCM_ONE_MINUS_DST_ALPHA = 0x0305, + CELL_GCM_DST_COLOR = 0x0306, + CELL_GCM_ONE_MINUS_DST_COLOR = 0x0307, + CELL_GCM_SRC_ALPHA_SATURATE = 0x0308, + CELL_GCM_CONSTANT_COLOR = 0x8001, + CELL_GCM_ONE_MINUS_CONSTANT_COLOR = 0x8002, + CELL_GCM_CONSTANT_ALPHA = 0x8003, + CELL_GCM_ONE_MINUS_CONSTANT_ALPHA = 0x8004, + + // Stencil/Depth Compare Function + CELL_GCM_NEVER = 0x0200, + CELL_GCM_LESS = 0x0201, + CELL_GCM_EQUAL = 0x0202, + CELL_GCM_LEQUAL = 0x0203, + CELL_GCM_GREATER = 0x0204, + CELL_GCM_NOTEQUAL = 0x0205, + CELL_GCM_GEQUAL = 0x0206, + CELL_GCM_ALWAYS = 0x0207, + + // Stencil Op + CELL_GCM_KEEP = 0x1E00, + CELL_GCM_REPLACE = 0x1E01, + CELL_GCM_INCR = 0x1E02, + CELL_GCM_DECR = 0x1E03, + CELL_GCM_INCR_WRAP = 0x8507, + CELL_GCM_DECR_WRAP = 0x8508, + + // Front Face + CELL_GCM_FRONT = 0x0404, + CELL_GCM_BACK = 0x0405, + CELL_GCM_FRONT_AND_BACK = 0x0408, + + // Cull Face + CELL_GCM_CW = 0x0900, + CELL_GCM_CCW = 0x0901, + + // Texture Filter + CELL_GCM_TEXTURE_NEAREST = 1, + CELL_GCM_TEXTURE_LINEAR = 2, + CELL_GCM_TEXTURE_NEAREST_NEAREST = 3, + CELL_GCM_TEXTURE_LINEAR_NEAREST = 4, + CELL_GCM_TEXTURE_NEAREST_LINEAR = 5, + CELL_GCM_TEXTURE_LINEAR_LINEAR = 6, + CELL_GCM_TEXTURE_CONVOLUTION_MIN = 7, }; // GCM Surface diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 50abd60569..5f6696c76e 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -155,6 +155,8 @@ void GLFragmentProgram::Decompile(RSXFragmentProgram& prog) { for (const ParamItem PI : PT.items) { + if (PT.type == "sampler2D") + continue; size_t offset = atoi(PI.name.c_str() + 2); FragmentConstantOffsetCache.push_back(offset); } diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 9b9ea7c484..c19e47b5b6 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -188,7 +188,7 @@ void GLTexture::Init(RSXTexture& tex) { for (int j = 0; j < tex.GetWidth(); j++) { - dst[(i*tex.GetHeight()) + j] = src[LinearToSwizzleAddress(j, i, 0, log2width, log2height, 0)]; + dst[(i*tex.GetWidth()) + j] = src[LinearToSwizzleAddress(j, i, 0, log2width, log2height, 0)]; } } } @@ -2165,33 +2165,3 @@ void GLGSRender::semaphorePFIFOAcquire(u32 offset, u32 value) { } - -u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth) -{ - u32 offset = 0; - u32 shift_count = 0; - while (log2_width | log2_height | log2_depth){ - if (log2_width) - { - offset |= (x & 0x01) << shift_count; - x >>= 1; - ++shift_count; - --log2_width; - } - if (log2_height) - { - offset |= (y & 0x01) << shift_count; - y >>= 1; - ++shift_count; - --log2_height; - } - if (log2_depth) - { - offset |= (z & 0x01) << shift_count; - z >>= 1; - ++shift_count; - --log2_depth; - } - } - return offset; -} diff --git a/rpcs3/Emu/RSX/GSManager.cpp b/rpcs3/Emu/RSX/GSManager.cpp index 1c3d02d2f7..cbddef535a 100644 --- a/rpcs3/Emu/RSX/GSManager.cpp +++ b/rpcs3/Emu/RSX/GSManager.cpp @@ -7,6 +7,9 @@ #include "GSManager.h" #include "Null/NullGSRender.h" #include "GL/GLGSRender.h" +#ifdef WIN32 +#include "D3D12/D3D12GSRender.h" +#endif void GSInfo::Init() { @@ -34,6 +37,9 @@ void GSManager::Init() default: case 0: m_render = new NullGSRender(); break; case 1: m_render = new GLGSRender(); break; +#if defined(DX12_SUPPORT) + case 2: m_render = new D3D12GSRender(); break; +#endif } //m_render->Init(GetInfo().outresolution.width, GetInfo().outresolution.height); } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 80cd1946f8..e89762f72c 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -23,6 +23,39 @@ extern u64 get_system_time(); u32 methodRegisters[0xffff]; +u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth) +{ + u32 offset = 0; + u32 shift_count = 0; + while (log2_width | log2_height | log2_depth) + { + if (log2_width) + { + offset |= (x & 0x01) << shift_count; + x >>= 1; + ++shift_count; + --log2_width; + } + + if (log2_height) + { + offset |= (y & 0x01) << shift_count; + y >>= 1; + ++shift_count; + --log2_height; + } + + if (log2_depth) + { + offset |= (z & 0x01) << shift_count; + z >>= 1; + ++shift_count; + --log2_depth; + } + } + return offset; +} + u32 GetAddress(u32 offset, u32 location) { u32 res = 0; @@ -118,7 +151,7 @@ void RSXVertexData::Load(u32 start, u32 count, u32 baseOffset, u32 baseIndex = 0 } } -u32 RSXVertexData::GetTypeSize() +u32 RSXVertexData::GetTypeSize() const { switch (type) { @@ -2045,6 +2078,20 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } + case NV3062_SET_PITCH: + { + if (count == 1) + { + m_color_format_src_pitch = ARGS(0); + m_color_format_dst_pitch = ARGS(0) >> 16; + } + else + { + LOG_ERROR(RSX, "NV3062_SET_PITCH: unknown arg count (%d)", count); + } + break; + } + // NV309E case NV309E_SET_CONTEXT_DMA_IMAGE: { @@ -2075,6 +2122,19 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } + case NV309E_SET_OFFSET: + { + if (count == 1) + { + m_swizzle_offset = ARGS(0); + } + else + { + LOG_ERROR(RSX, "NV309E_SET_OFFSET: unknown arg count (%d)", count); + } + break; + } + // NV308A case NV308A_POINT: { @@ -2162,39 +2222,98 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV3089_IMAGE_IN_SIZE: { - const u16 width = ARGS(0); - const u16 height = ARGS(0) >> 16; - const u16 pitch = ARGS(1); + if (count == 1) + { + m_img_in_size = ARGS(0); + + } + else + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown arg count (%d)", count); + } + break; + } + + case NV3089_IMAGE_IN_FORMAT: + { + if (count == 1) + { + m_img_in_format = ARGS(0); + + } + else + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown arg count (%d)", count); + } + break; + } + + case NV3089_IMAGE_IN_OFFSET: + { + if (count == 1) + { + m_src_offset = ARGS(0); + + } + else + { + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown arg count (%d)", count); + } + break; + } + + case NV3089_IMAGE_IN: + { + const u16 width = m_img_in_size; + const u16 height = m_img_in_size >> 16; + const u16 pitch = m_img_in_format; + const u8 origin = m_img_in_format >> 16; + const u8 inter = m_img_in_format >> 24; - const u8 origin = ARGS(1) >> 16; if (origin != 2 /* CELL_GCM_TRANSFER_ORIGIN_CORNER */) { LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown origin (%d)", origin); } - const u8 inter = ARGS(1) >> 24; if (inter != 0 /* CELL_GCM_TRANSFER_INTERPOLATOR_ZOH */ && inter != 1 /* CELL_GCM_TRANSFER_INTERPOLATOR_FOH */) { LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown inter (%d)", inter); } - const u32 offset = ARGS(2); + const u32 src_offset = m_src_offset; + const u32 src_dma = m_context_dma_img_src; - const u16 u = ARGS(3); // inX (currently ignored) - const u16 v = ARGS(3) >> 16; // inY (currently ignored) + u32 dst_offset; + u32 dst_dma = 0; - u8* pixels_src = vm::get_ptr(GetAddress(offset, m_context_dma_img_src - 0xfeed0000)); - u8* pixels_dst = vm::get_ptr(GetAddress(m_dst_offset, m_context_dma_img_dst - 0xfeed0000)); - - if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D) - { - LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: Swizzle2D not implemented"); - } - else if (m_context_surface != CELL_GCM_CONTEXT_SURFACE2D) + switch (m_context_surface) { + case CELL_GCM_CONTEXT_SURFACE2D: + dst_dma = m_context_dma_img_dst; + dst_offset = m_dst_offset; + break; + + case CELL_GCM_CONTEXT_SWIZZLE2D: + dst_dma = m_context_dma_img_src; + dst_offset = m_swizzle_offset; + break; + + default: LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_context_surface (0x%x)", m_context_surface); + break; } + if (!dst_dma) + break; + + LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: src = 0x%x, dst = 0x%x", src_offset, dst_offset); + + const u16 u = ARGS(0); // inX (currently ignored) + const u16 v = ARGS(0) >> 16; // inY (currently ignored) + + u8* pixels_src = vm::get_ptr(GetAddress(src_offset, src_dma)); + u8* pixels_dst = vm::get_ptr(GetAddress(dst_offset, dst_dma)); + if (m_color_format != 4 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 */ && m_color_format != 10 /* CELL_GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 */) { LOG_ERROR(RSX, "NV3089_IMAGE_IN_SIZE: unknown m_color_format (%d)", m_color_format); @@ -2206,11 +2325,42 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const s32 out_w = (s32)(u64(width) * (1 << 20) / m_color_conv_dsdx); const s32 out_h = (s32)(u64(height) * (1 << 20) / m_color_conv_dtdy); + if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D) + { + u8* linear_pixels = pixels_src; + u8* swizzled_pixels = new u8[in_bpp * width * height]; + + int sw_width = 1 << (int)log2(width); + int sw_height = 1 << (int)log2(height); + + for (int y = 0; y < sw_height; y++) + { + for (int x = 0; x < sw_width; x++) + { + switch (in_bpp) + { + case 1: + swizzled_pixels[LinearToSwizzleAddress(x, y, 0, sw_width, sw_height, 0)] = linear_pixels[y * sw_height + x]; + break; + case 2: + ((u16*)swizzled_pixels)[LinearToSwizzleAddress(x, y, 0, sw_width, sw_height, 0)] = ((u16*)linear_pixels)[y * sw_height + x]; + break; + case 4: + ((u32*)swizzled_pixels)[LinearToSwizzleAddress(x, y, 0, sw_width, sw_height, 0)] = ((u32*)linear_pixels)[y * sw_height + x]; + break; + } + + } + } + + pixels_src = swizzled_pixels; + } + LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: w=%d, h=%d, pitch=%d, offset=0x%x, inX=%f, inY=%f, scaleX=%f, scaleY=%f", - width, height, pitch, offset, double(u) / 16, double(v) / 16, double(1 << 20) / (m_color_conv_dsdx), double(1 << 20) / (m_color_conv_dtdy)); + width, height, pitch, src_offset, double(u) / 16, double(v) / 16, double(1 << 20) / (m_color_conv_dsdx), double(1 << 20) / (m_color_conv_dtdy)); std::unique_ptr temp; - + if (in_bpp != out_bpp && width != out_w && height != out_h) { // resize/convert if necessary @@ -2220,7 +2370,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const AVPixelFormat in_format = m_color_format == 4 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB; // ??? AVPixelFormat out_format = m_color_conv_fmt == 7 ? AV_PIX_FMT_RGB565BE : AV_PIX_FMT_ARGB; // ??? - std::unique_ptr sws(sws_getContext(width, height, in_format, out_w, out_h, out_format, inter ? SWS_FAST_BILINEAR : SWS_POINT, NULL, NULL, NULL), sws_freeContext); + std::unique_ptr sws(sws_getContext(width, height, in_format, out_w, out_h, out_format, + inter ? SWS_FAST_BILINEAR : SWS_POINT, NULL, NULL, NULL), sws_freeContext); int in_line = in_bpp * width; u8* out_ptr = temp.get(); @@ -2272,6 +2423,11 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const memcpy(pixels_dst, pixels_src, out_w * out_h * out_bpp); } + if (m_context_surface == CELL_GCM_CONTEXT_SWIZZLE2D) + { + delete[] pixels_src; + } + break; } @@ -2308,6 +2464,49 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } + case NV3089_SET_COLOR_FORMAT: + m_color_conv_fmt = ARGS(0); + if (m_color_conv_fmt != 3 /* CELL_GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8 */ && m_color_conv_fmt != 7 /* CELL_GCM_TRANSFER_SCALE_FORMAT_R5G6B5 */) + { + LOG_ERROR(RSX, "NV3089_SET_COLOR_FORMAT: unknown format (%d)", m_color_conv_fmt); + } + break; + + case NV3089_SET_OPERATION: + m_color_conv_op = ARGS(0); + if (m_color_conv_op != 3 /* CELL_GCM_TRANSFER_OPERATION_SRCCOPY */) + { + LOG_ERROR(RSX, "NV3089_SET_OPERATION: unknown color conv op (%d)", m_color_conv_op); + } + break; + case NV3089_CLIP_POINT: + m_color_conv_clip_x = ARGS(0); + m_color_conv_clip_y = ARGS(0) >> 16; + break; + + case NV3089_CLIP_SIZE: + m_color_conv_clip_w = ARGS(0); + m_color_conv_clip_h = ARGS(0) >> 16; + break; + + case NV3089_IMAGE_OUT_POINT: + m_color_conv_out_x = ARGS(0); + m_color_conv_out_y = ARGS(0) >> 16; + break; + + case NV3089_IMAGE_OUT_SIZE: + m_color_conv_out_w = ARGS(0); + m_color_conv_out_h = ARGS(0) >> 16; + break; + + case NV3089_DS_DX: + m_color_conv_dsdx = ARGS(0); + break; + + case NV3089_DT_DY: + m_color_conv_dtdy = ARGS(0); + break; + case GCM_SET_USER_COMMAND: { const u32 cause = ARGS(0); @@ -2353,7 +2552,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV3062_SET_OBJECT: case NV3062_SET_CONTEXT_DMA_NOTIFIES: case NV3062_SET_CONTEXT_DMA_IMAGE_SOURCE: - case NV3062_SET_PITCH: case NV3062_SET_OFFSET_SOURCE: { LOG_WARNING(RSX, "Unused NV3062 method 0x%x detected!", cmd); @@ -2381,7 +2579,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV309E_SET_OBJECT: case NV309E_SET_CONTEXT_DMA_NOTIFIES: - case NV309E_SET_OFFSET: { LOG_WARNING(RSX, "Unused NV309E method 0x%x detected!", cmd); break; @@ -2393,17 +2590,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV3089_SET_CONTEXT_ROP: case NV3089_SET_CONTEXT_BETA1: case NV3089_SET_CONTEXT_BETA4: - case NV3089_SET_COLOR_FORMAT: - case NV3089_SET_OPERATION: - case NV3089_CLIP_POINT: - case NV3089_CLIP_SIZE: - case NV3089_IMAGE_OUT_POINT: - case NV3089_IMAGE_OUT_SIZE: - case NV3089_DS_DX: - case NV3089_DT_DY: - case NV3089_IMAGE_IN_FORMAT: - case NV3089_IMAGE_IN_OFFSET: - case NV3089_IMAGE_IN: { LOG_WARNING(RSX, "Unused NV3089 methods 0x%x detected!", cmd); break; diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 6cacabc967..6dcf387b38 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -19,6 +19,7 @@ enum Method extern u32 methodRegisters[0xffff]; u32 GetAddress(u32 offset, u32 location); +u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth); struct RSXVertexData { @@ -37,7 +38,7 @@ struct RSXVertexData bool IsEnabled() const { return size > 0; } void Load(u32 start, u32 count, u32 baseOffset, u32 baseIndex); - u32 GetTypeSize(); + u32 GetTypeSize() const; }; struct RSXIndexArrayData @@ -407,6 +408,9 @@ public: u32 m_context_dma_buffer_in_src; u32 m_context_dma_buffer_in_dst; u32 m_dst_offset; + u32 m_src_offset; + u32 m_img_in_size; + u32 m_img_in_format; // Swizzle2D? u16 m_swizzle_format; diff --git a/rpcs3/Gui/D3DGSFrame.cpp b/rpcs3/Gui/D3DGSFrame.cpp new file mode 100644 index 0000000000..48d31e2237 --- /dev/null +++ b/rpcs3/Gui/D3DGSFrame.cpp @@ -0,0 +1,107 @@ +#include "stdafx_gui.h" +#if defined(DX12_SUPPORT) +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "D3DGSFrame.h" +#include "Utilities/Timer.h" + +D3DGSFrame::D3DGSFrame() + : GSFrame(nullptr, "GSFrame[DirectX 12]") + , m_frames(0) +{ + canvas = new wxWindow(this, wxID_ANY); + canvas->SetSize(GetClientSize()); + + canvas->Bind(wxEVT_LEFT_DCLICK, &GSFrame::OnLeftDclick, this); +} + +D3DGSFrame::~D3DGSFrame() +{ +} + +void D3DGSFrame::SetAdaptaterName(const wchar_t *name) +{ + AdaptaterName = name; +} + +void D3DGSFrame::Close() +{ + GSFrame::Close(); +} + +bool D3DGSFrame::IsShown() +{ + return GSFrame::IsShown(); +} + +void D3DGSFrame::Hide() +{ + GSFrame::Hide(); +} + +void D3DGSFrame::Show() +{ + GSFrame::Show(); +} + +void* D3DGSFrame::GetNewContext() +{ + return nullptr;//new wxGLContext(GetCanvas()); +} + +void D3DGSFrame::SetCurrent(void* ctx) +{ +// GetCanvas()->SetCurrent(*(wxGLContext*)ctx); +} + +void D3DGSFrame::DeleteContext(void* ctx) +{ +// delete (wxGLContext*)ctx; +} + +void D3DGSFrame::Flip(void* context) +{ + if (!canvas) return; +// canvas->SetCurrent(*(wxGLContext*)context); + + static Timer fps_t; +// canvas->SwapBuffers(); + m_frames++; + + const std::string sub_title = Emu.GetTitle() + (Emu.GetTitleID().length() ? " [" + Emu.GetTitleID() + "] | " : " | ") + AdaptaterName.ToStdString() + " | "; + + if (fps_t.GetElapsedTimeInSec() >= 0.5) + { + // can freeze on exit + SetTitle(wxString(sub_title.c_str(), wxConvUTF8) + wxString::Format("FPS: %.2f", (double)m_frames / fps_t.GetElapsedTimeInSec())); + m_frames = 0; + fps_t.Start(); + } +} + +void D3DGSFrame::OnSize(wxSizeEvent& event) +{ + if (canvas) canvas->SetSize(GetClientSize()); + event.Skip(); +} + +void D3DGSFrame::SetViewport(int x, int y, u32 w, u32 h) +{ + /* + //ConLog.Warning("SetViewport(x=%d, y=%d, w=%d, h=%d)", x, y, w, h); + + const wxSize client = GetClientSize(); + const wxSize viewport = AspectRatio(client, wxSize(w, h)); + + const int vx = (client.GetX() - viewport.GetX()) / 2; + const int vy = (client.GetY() - viewport.GetY()) / 2; + + glViewport(vx + x, vy + y, viewport.GetWidth(), viewport.GetHeight()); + */ +} + +HWND D3DGSFrame::getHandle() const +{ + return canvas->GetHandle(); +} +#endif \ No newline at end of file diff --git a/rpcs3/Gui/D3DGSFrame.h b/rpcs3/Gui/D3DGSFrame.h new file mode 100644 index 0000000000..fecd729d22 --- /dev/null +++ b/rpcs3/Gui/D3DGSFrame.h @@ -0,0 +1,38 @@ +#pragma once + +#if defined(DX12_SUPPORT) +#include "Emu/RSX/D3D12/D3D12GSRender.h" +#include "Gui/GSFrame.h" +#include "wx/window.h" + +struct D3DGSFrame : public GSFrame, public GSFrameBase2 +{ + wxWindow* canvas; + u32 m_frames; + wxString AdaptaterName; + + D3DGSFrame(); + ~D3DGSFrame(); + + virtual void Close() override; + + virtual bool IsShown() override; + virtual void Hide() override; + virtual void Show() override; + + virtual void* GetNewContext() override; + virtual void SetCurrent(void* ctx) override; + virtual void DeleteContext(void* ctx) override; + virtual void Flip(void* context) override; + + wxWindow* GetCanvas() const { return canvas; } + + virtual void SetViewport(int x, int y, u32 w, u32 h) override; + virtual HWND getHandle() const override; + virtual void SetAdaptaterName(const wchar_t *) override; + +private: + virtual void OnSize(wxSizeEvent& event); +}; + +#endif \ No newline at end of file diff --git a/rpcs3/Gui/GLGSFrame.cpp b/rpcs3/Gui/GLGSFrame.cpp index 899b2de32d..a5419f5c3f 100644 --- a/rpcs3/Gui/GLGSFrame.cpp +++ b/rpcs3/Gui/GLGSFrame.cpp @@ -3,6 +3,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "GLGSFrame.h" +#include "D3DGSFrame.h" #include "Utilities/Timer.h" GLGSFrame::GLGSFrame() diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 3016be4d22..7fcdc15da7 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -365,7 +365,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxDialog diag(this, wxID_ANY, "Settings", wxDefaultPosition); static const u32 width = 452; - static const u32 height = 460; + static const u32 height = 520; // Settings panels wxNotebook* nb_config = new wxNotebook(&diag, wxID_ANY, wxPoint(6,6), wxSize(width, height)); @@ -402,6 +402,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) // Graphics wxStaticBoxSizer* s_round_gs_render = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Render")); + wxStaticBoxSizer* s_round_gs_d3d_adaptater = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("D3D Adaptater")); wxStaticBoxSizer* s_round_gs_res = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Default resolution")); wxStaticBoxSizer* s_round_gs_aspect = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Default aspect ratio")); wxStaticBoxSizer* s_round_gs_frame_limit = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Frame limit")); @@ -429,6 +430,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxComboBox* cbox_cpu_decoder = new wxComboBox(p_core, wxID_ANY); wxComboBox* cbox_spu_decoder = new wxComboBox(p_core, wxID_ANY); wxComboBox* cbox_gs_render = new wxComboBox(p_graphics, wxID_ANY); + wxComboBox* cbox_gs_d3d_adaptater = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_gs_resolution = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_gs_aspect = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_gs_frame_limit = new wxComboBox(p_graphics, wxID_ANY); @@ -451,6 +453,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxCheckBox* chbox_gs_dump_color = new wxCheckBox(p_graphics, wxID_ANY, "Write Color Buffers"); wxCheckBox* chbox_gs_read_color = new wxCheckBox(p_graphics, wxID_ANY, "Read Color Buffer"); wxCheckBox* chbox_gs_vsync = new wxCheckBox(p_graphics, wxID_ANY, "VSync"); + wxCheckBox* chbox_gs_debug_output = new wxCheckBox(p_graphics, wxID_ANY, "Debug Output"); wxCheckBox* chbox_gs_3dmonitor = new wxCheckBox(p_graphics, wxID_ANY, "3D Monitor"); wxCheckBox* chbox_audio_dump = new wxCheckBox(p_audio, wxID_ANY, "Dump to file"); wxCheckBox* chbox_audio_conv = new wxCheckBox(p_audio, wxID_ANY, "Convert to 16 bit"); @@ -482,7 +485,15 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_gs_render->Append("Null"); cbox_gs_render->Append("OpenGL"); - //cbox_gs_render->Append("Software"); +#if defined(DX12_SUPPORT) + cbox_gs_render->Append("DirectX 12"); +#endif + + cbox_gs_d3d_adaptater->Append("WARP"); + cbox_gs_d3d_adaptater->Append("default"); + cbox_gs_d3d_adaptater->Append("renderer 0"); + cbox_gs_d3d_adaptater->Append("renderer 1"); + cbox_gs_d3d_adaptater->Append("renderer 2"); for(int i = 1; i < WXSIZEOF(ResolutionTable); ++i) { @@ -615,6 +626,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) chbox_gs_dump_color ->SetValue(Ini.GSDumpColorBuffers.GetValue()); chbox_gs_read_color ->SetValue(Ini.GSReadColorBuffer.GetValue()); chbox_gs_vsync ->SetValue(Ini.GSVSyncEnable.GetValue()); + chbox_gs_debug_output ->SetValue(Ini.GSDebugOutputEnable.GetValue()); chbox_gs_3dmonitor ->SetValue(Ini.GS3DTV.GetValue()); chbox_audio_dump ->SetValue(Ini.AudioDumpToFile.GetValue()); chbox_audio_conv ->SetValue(Ini.AudioConvertToU16.GetValue()); @@ -640,6 +652,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) txt_llvm_threshold ->SetValue(std::to_string(Ini.LLVMThreshold.GetValue())); cbox_spu_decoder ->SetSelection(Ini.SPUDecoderMode.GetValue() ? Ini.SPUDecoderMode.GetValue() : 0); cbox_gs_render ->SetSelection(Ini.GSRenderMode.GetValue()); + cbox_gs_d3d_adaptater->SetSelection(Ini.GSD3DAdaptater.GetValue()); cbox_gs_resolution ->SetSelection(ResolutionIdToNum(Ini.GSResolution.GetValue()) - 1); cbox_gs_aspect ->SetSelection(Ini.GSAspectRatio.GetValue() - 1); cbox_gs_frame_limit ->SetSelection(Ini.GSFrameLimit.GetValue()); @@ -666,6 +679,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) // Rendering s_round_gs_render->Add(cbox_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); + s_round_gs_d3d_adaptater->Add(cbox_gs_d3d_adaptater, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_res->Add(cbox_gs_resolution, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_aspect->Add(cbox_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_frame_limit->Add(cbox_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); @@ -696,6 +710,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) // Graphics s_subpanel_graphics->Add(s_round_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_graphics->Add(s_round_gs_d3d_adaptater, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_round_gs_res, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_round_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_round_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); @@ -704,6 +719,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) s_subpanel_graphics->Add(chbox_gs_dump_color, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_read_color, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_vsync, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_graphics->Add(chbox_gs_debug_output, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_3dmonitor, wxSizerFlags().Border(wxALL, 5).Expand()); // Input - Output @@ -774,6 +790,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) Ini.HookStFunc.SetValue(chbox_core_hook_stfunc->GetValue()); Ini.LoadLibLv2.SetValue(chbox_core_load_liblv2->GetValue()); Ini.GSRenderMode.SetValue(cbox_gs_render->GetSelection()); + Ini.GSD3DAdaptater.SetValue(cbox_gs_d3d_adaptater->GetSelection()); Ini.GSResolution.SetValue(ResolutionNumToId(cbox_gs_resolution->GetSelection() + 1)); Ini.GSAspectRatio.SetValue(cbox_gs_aspect->GetSelection() + 1); Ini.GSFrameLimit.SetValue(cbox_gs_frame_limit->GetSelection()); @@ -782,6 +799,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) Ini.GSDumpColorBuffers.SetValue(chbox_gs_dump_color->GetValue()); Ini.GSReadColorBuffer.SetValue(chbox_gs_read_color->GetValue()); Ini.GSVSyncEnable.SetValue(chbox_gs_vsync->GetValue()); + Ini.GSDebugOutputEnable.SetValue(chbox_gs_debug_output->GetValue()); Ini.GS3DTV.SetValue(chbox_gs_3dmonitor->GetValue()); Ini.PadHandlerMode.SetValue(cbox_pad_handler->GetSelection()); Ini.KeyboardHandlerMode.SetValue(cbox_keyboard_handler->GetSelection()); diff --git a/rpcs3/Ini.h b/rpcs3/Ini.h index c2ffb59e89..a274ace444 100644 --- a/rpcs3/Ini.h +++ b/rpcs3/Ini.h @@ -102,6 +102,7 @@ public: // Graphics IniEntry GSRenderMode; + IniEntry GSD3DAdaptater; IniEntry GSResolution; IniEntry GSAspectRatio; IniEntry GSFrameLimit; @@ -111,6 +112,7 @@ public: IniEntry GSReadColorBuffer; IniEntry GSVSyncEnable; IniEntry GS3DTV; + IniEntry GSDebugOutputEnable; // Audio IniEntry AudioOutMode; @@ -190,6 +192,7 @@ public: // Graphics GSRenderMode.Init("GS_RenderMode", path); + GSD3DAdaptater.Init("GS_D3DAdaptater", path); GSResolution.Init("GS_Resolution", path); GSAspectRatio.Init("GS_AspectRatio", path); GSFrameLimit.Init("GS_FrameLimit", path); @@ -198,6 +201,7 @@ public: GSDumpDepthBuffer.Init("GS_DumpDepthBuffer", path); GSReadColorBuffer.Init("GS_GSReadColorBuffer", path); GSVSyncEnable.Init("GS_VSyncEnable", path); + GSDebugOutputEnable.Init("GS_DebugOutputEnable", path); GS3DTV.Init("GS_3DTV", path); // Audio @@ -274,6 +278,7 @@ public: // Graphics GSRenderMode.Load(1); + GSD3DAdaptater.Load(1); GSResolution.Load(4); GSAspectRatio.Load(2); GSFrameLimit.Load(0); @@ -282,6 +287,7 @@ public: GSDumpDepthBuffer.Load(false); GSReadColorBuffer.Load(false); GSVSyncEnable.Load(false); + GSDebugOutputEnable.Load(false); GS3DTV.Load(false); // Audio @@ -358,6 +364,7 @@ public: // Graphics GSRenderMode.Save(); + GSD3DAdaptater.Save(); GSResolution.Save(); GSAspectRatio.Save(); GSFrameLimit.Save(); @@ -366,6 +373,7 @@ public: GSDumpDepthBuffer.Save(); GSReadColorBuffer.Save(); GSVSyncEnable.Save(); + GSDebugOutputEnable.Save(); GS3DTV.Save(); // Audio diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 2830b24d70..b519ddc057 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -1,6 +1,14 @@  + + Debug - DX12 + x64 + + + Debug - LLVM DX12 + x64 + Debug - LLVM x64 @@ -13,6 +21,14 @@ Debug x64 + + Release - DX12 + x64 + + + Release - LLVM DX12 + x64 + Release - LLVM x64 @@ -41,6 +57,15 @@ + + + + + + + + + @@ -61,9 +86,13 @@ NotUsing NotUsing + NotUsing NotUsing + NotUsing NotUsing + NotUsing NotUsing + NotUsing @@ -148,8 +177,10 @@ true + true true true + true @@ -324,15 +355,21 @@ true + true true true + true Create Create + Create Create + Create Create + Create Create + Create @@ -498,6 +535,15 @@ + + + + + + + + + @@ -627,6 +673,7 @@ {C4A10229-4712-4BD2-B63E-50D93C67A038} emucore + 10.0.10240.0 @@ -635,12 +682,24 @@ v140 Unicode + + StaticLibrary + true + v140 + Unicode + StaticLibrary true v140 Unicode + + StaticLibrary + true + v140 + Unicode + StaticLibrary true @@ -654,6 +713,13 @@ false Unicode + + StaticLibrary + false + v140 + false + Unicode + StaticLibrary false @@ -661,6 +727,13 @@ false Unicode + + StaticLibrary + false + v140 + false + Unicode + v140 @@ -670,18 +743,30 @@ + + + + + + + + + + + + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) @@ -689,12 +774,24 @@ $(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(ExcludePath) + + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) + $(Platform)\$(Configuration)\emucore\ + $(UniversalCRT_LibraryPath_x64);$(LibraryPath) + $(ExcludePath) + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) $(Platform)\$(Configuration)\emucore\ $(LibraryPath) $(ExcludePath) + + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) + $(Platform)\$(Configuration)\emucore\ + $(LibraryPath) + $(ExcludePath) + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) $(Platform)\$(Configuration)\emucore\ @@ -707,12 +804,24 @@ $(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(ExcludePath) + + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) + $(Platform)\$(Configuration)\emucore\ + $(UniversalCRT_LibraryPath_x64);$(LibraryPath) + $(ExcludePath) + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) $(Platform)\$(Configuration)\emucore\ $(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(ExcludePath) + + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include;$(UniversalCRT_IncludePath) + $(Platform)\$(Configuration)\emucore\ + $(UniversalCRT_LibraryPath_x64);$(LibraryPath) + $(ExcludePath) + Level3 @@ -731,6 +840,24 @@ true + + + Level3 + Disabled + false + Use + _UNICODE;UNICODE;DX12_SUPPORT;%(PreprocessorDefinitions) + stdafx.h + Async + true + + + false + + + true + + Level3 @@ -743,6 +870,29 @@ true + true + + + true + + + ..\llvm_build\Debug\lib + LLVMMCJIT.lib;LLVMRuntimeDyld.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib + + + + + Level3 + Disabled + false + Use + _UNICODE;UNICODE;LLVM_AVAILABLE;DX12_SUPPORT;%(PreprocessorDefinitions) + stdafx.h + Async + true + + + true true @@ -758,7 +908,7 @@ Disabled false Use - _UNICODE;UNICODE;MSVC_CRT_MEMLEAK_DETECTION;%(PreprocessorDefinitions) + _UNICODE;UNICODE;MSVC_CRT_MEMLEAK_DETECTION;%(PreprocessorDefinitions);DX12_SUPPORT stdafx.h Async true @@ -782,6 +932,29 @@ true + _UNICODE;UNICODE;%(PreprocessorDefinitions) + + + true + true + true + + + + + Level3 + MaxSpeed + true + true + false + Use + stdafx.h + Async + true + + + _UNICODE;UNICODE;DX12_SUPPORT;%(PreprocessorDefinitions) + true true @@ -814,6 +987,32 @@ LLVMMCJIT.lib;LLVMRuntimeDyld.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib + + + Level3 + MaxSpeed + true + true + false + Use + stdafx.h + Async + LLVM_AVAILABLE;DX12_SUPPORT;%(PreprocessorDefinitions) + true + + + true + + + true + true + true + + + ..\llvm_build\Release\lib + LLVMMCJIT.lib;LLVMRuntimeDyld.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMipa.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib + + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index e93306a72e..ee8cda35ba 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -90,6 +90,9 @@ {2a8841dc-bce0-41bb-9fcb-5bf1f8dda213} + + {25818cb6-10d5-4ae3-8c5e-9dd79c306e53} + @@ -965,6 +968,33 @@ Emu\SysCalls\Modules + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + @@ -1828,5 +1858,32 @@ Emu\SysCalls\Modules + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + + + Emu\GPU\RSX\D3D12 + \ No newline at end of file diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 20a5c9d01f..819e2aa7f4 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -26,6 +26,7 @@ #include "Gui/SaveDataDialog.h" #include "Gui/GLGSFrame.h" +#include "Gui/D3DGSFrame.h" #include #ifdef _WIN32 @@ -137,6 +138,13 @@ bool Rpcs3App::OnInit() return new GLGSFrame(); }); +#if defined(DX12_SUPPORT) + SetGetD3DGSFrameCallback([]() ->GSFrameBase2* + { + return new D3DGSFrame(); + }); +#endif + g_msg_dialog.reset(new MsgDialogFrame); g_savedata_dialog.reset(new SaveDataDialogFrame); diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index f2e3fd3df3..fc95cbed81 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -1,6 +1,10 @@  + + Debug - DX12 + x64 + Debug - MemLeak x64 @@ -9,6 +13,10 @@ Debug x64 + + Release - DX12 + x64 + Release x64 @@ -18,6 +26,7 @@ {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12} Win32Proj rpcs3 + 10.0.10240.0 @@ -26,6 +35,12 @@ Unicode v140 + + Application + true + Unicode + v140 + Application true @@ -40,18 +55,32 @@ v140 false + + Application + false + true + Unicode + v140 + false + + + + + + + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;.\OpenAL\include;$(IncludePath);..\asmjit\src\asmjit;$(UniversalCRT_IncludePath) @@ -59,6 +88,12 @@ ..\libs\$(Configuration)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) $(ProjectName)-dbg + + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;.\OpenAL\include;$(IncludePath);..\asmjit\src\asmjit;$(UniversalCRT_IncludePath) + $(SolutionDir)bin\ + ..\libs\Debug\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) + $(ProjectName)-dbg + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;.\OpenAL\include;$(UniversalCRT_IncludePath);$(IncludePath) $(SolutionDir)bin\ @@ -73,6 +108,14 @@ false false + + false + .\;..\wxWidgets\include;..\SDL-1.3.0-5538\include;..\SDL_image-1.2.10;..\pthreads-2.8.0;..\;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;.\OpenAL\include;$(IncludePath);..\asmjit\src\asmjit;$(UniversalCRT_IncludePath) + $(SolutionDir)bin\ + ..\libs\Release\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath) + false + false + Level3 @@ -83,13 +126,46 @@ Async stdafx_gui.h $(IntDir)$(TargetName)_gui.pch + _UNICODE;UNICODE;%(PreprocessorDefinitions) + true true - wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;libOpenAL32.dll.a;asmjit.lib;%(AdditionalDependencies) + wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;OpenAL32.lib;asmjit.lib;%(AdditionalDependencies) %(IgnoreSpecificDefaultLibraries) true - ..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib;..\OpenAL\Win64 + ..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib;..\OpenAL\libs\Win64 + 0x200000000 + true + false + + + "$(SolutionDir)\Utilities\git-version-gen.cmd" + Updating git-version.h + + + false + + + + + Level3 + Disabled + ProgramDatabase + Use + ..\wxWidgets\include\msvc + Async + stdafx_gui.h + $(IntDir)$(TargetName)_gui.pch + _UNICODE;UNICODE;DX12_SUPPORT;%(PreprocessorDefinitions) + true + + + true + wxmsw31ud_adv.lib;wxbase31ud.lib;wxmsw31ud_core.lib;wxmsw31ud_aui.lib;wxtiffd.lib;wxjpegd.lib;wxpngd.lib;wxzlibd.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;OpenAL32.lib;asmjit.lib;%(AdditionalDependencies) + %(IgnoreSpecificDefaultLibraries) + true + ..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib;..\OpenAL\libs\Win64 0x200000000 true false @@ -109,10 +185,11 @@ ProgramDatabase Use ..\wxWidgets\include\msvc - _UNICODE;UNICODE;MSVC_CRT_MEMLEAK_DETECTION;%(PreprocessorDefinitions) + _UNICODE;UNICODE;MSVC_CRT_MEMLEAK_DETECTION;%(PreprocessorDefinitions);DX12_SUPPORT Async stdafx_gui.h $(IntDir)$(TargetName)_gui.pch + true true @@ -149,6 +226,46 @@ true stdafx_gui.h $(IntDir)$(TargetName)_gui.pch + true + + + Windows + true + true + true + wxmsw31u_adv.lib;wxbase31u.lib;wxmsw31u_core.lib;wxmsw31u_aui.lib;odbc32.lib;odbccp32.lib;comctl32.lib;ws2_32.lib;shlwapi.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;rpcrt4.lib;wxtiff.lib;wxjpeg.lib;wxpng.lib;wxzlib.lib;wxregexu.lib;wxexpat.lib;wsock32.lib;wininet.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;OpenAL32.lib;asmjit.lib;%(AdditionalDependencies) + + + %(IgnoreSpecificDefaultLibraries) + true + ..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib;..\OpenAL\libs\Win64 + 0x200000000 + true + false + + + "$(SolutionDir)\Utilities\git-version-gen.cmd" + Updating git-version.h + + + + + Level3 + Full + true + true + ..\wxWidgets\include\msvc + MultiThreadedDLL + WIN32;NDEBUG;_WINDOWS;DX12_SUPPORT;%(PreprocessorDefinitions) + false + Use + Speed + Async + false + true + stdafx_gui.h + $(IntDir)$(TargetName)_gui.pch + true Windows @@ -177,6 +294,7 @@ + @@ -200,7 +318,9 @@ Create Create + Create Create + Create @@ -218,6 +338,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index f1b37ef93a..a5efe10e7e 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -102,6 +102,9 @@ Gui + + Gui + @@ -207,6 +210,9 @@ Gui + + Gui + diff --git a/rpcs3/rpcs3.vcxproj.user b/rpcs3/rpcs3.vcxproj.user index 130ca03334..96886c83a5 100644 --- a/rpcs3/rpcs3.vcxproj.user +++ b/rpcs3/rpcs3.vcxproj.user @@ -4,6 +4,10 @@ $(SolutionDir)bin\ WindowsLocalDebugger + + $(SolutionDir)bin\ + WindowsLocalDebugger + $(SolutionDir)bin\ WindowsLocalDebugger @@ -13,10 +17,18 @@ WindowsLocalDebugger 1> stdout.log 2> stderr.log + + $(SolutionDir)bin\ + WindowsLocalDebugger + $(SolutionDir)bin\ WindowsLocalDebugger + + $(SolutionDir)bin\ + WindowsLocalDebugger + $(SolutionDir)bin\ WindowsLocalDebugger @@ -25,6 +37,10 @@ $(SolutionDir)bin\ WindowsLocalDebugger + + $(SolutionDir)bin\ + WindowsLocalDebugger + false