diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 82 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | 69 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_pipeline_cache.h | 8 | ||||
| -rw-r--r-- | src/video_core/shader/control_flow.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/shader/decode.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/shader/memory_util.cpp | 77 | ||||
| -rw-r--r-- | src/video_core/shader/memory_util.h | 47 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 3 |
9 files changed, 153 insertions, 159 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 8ede4ba9b..ff53282c9 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -124,6 +124,8 @@ add_library(video_core STATIC | |||
| 124 | shader/decode.cpp | 124 | shader/decode.cpp |
| 125 | shader/expr.cpp | 125 | shader/expr.cpp |
| 126 | shader/expr.h | 126 | shader/expr.h |
| 127 | shader/memory_util.cpp | ||
| 128 | shader/memory_util.h | ||
| 127 | shader/node_helper.cpp | 129 | shader/node_helper.cpp |
| 128 | shader/node_helper.h | 130 | shader/node_helper.h |
| 129 | shader/node.h | 131 | shader/node.h |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index f63156b8d..9759a7078 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -10,8 +10,6 @@ | |||
| 10 | #include <thread> | 10 | #include <thread> |
| 11 | #include <unordered_set> | 11 | #include <unordered_set> |
| 12 | 12 | ||
| 13 | #include <boost/functional/hash.hpp> | ||
| 14 | |||
| 15 | #include "common/alignment.h" | 13 | #include "common/alignment.h" |
| 16 | #include "common/assert.h" | 14 | #include "common/assert.h" |
| 17 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| @@ -28,76 +26,26 @@ | |||
| 28 | #include "video_core/renderer_opengl/gl_shader_disk_cache.h" | 26 | #include "video_core/renderer_opengl/gl_shader_disk_cache.h" |
| 29 | #include "video_core/renderer_opengl/gl_state_tracker.h" | 27 | #include "video_core/renderer_opengl/gl_state_tracker.h" |
| 30 | #include "video_core/renderer_opengl/utils.h" | 28 | #include "video_core/renderer_opengl/utils.h" |
| 29 | #include "video_core/shader/memory_util.h" | ||
| 31 | #include "video_core/shader/registry.h" | 30 | #include "video_core/shader/registry.h" |
| 32 | #include "video_core/shader/shader_ir.h" | 31 | #include "video_core/shader/shader_ir.h" |
| 33 | 32 | ||
| 34 | namespace OpenGL { | 33 | namespace OpenGL { |
| 35 | 34 | ||
| 36 | using Tegra::Engines::ShaderType; | 35 | using Tegra::Engines::ShaderType; |
| 36 | using VideoCommon::Shader::GetShaderAddress; | ||
| 37 | using VideoCommon::Shader::GetShaderCode; | ||
| 38 | using VideoCommon::Shader::GetUniqueIdentifier; | ||
| 39 | using VideoCommon::Shader::KERNEL_MAIN_OFFSET; | ||
| 37 | using VideoCommon::Shader::ProgramCode; | 40 | using VideoCommon::Shader::ProgramCode; |
| 38 | using VideoCommon::Shader::Registry; | 41 | using VideoCommon::Shader::Registry; |
| 39 | using VideoCommon::Shader::ShaderIR; | 42 | using VideoCommon::Shader::ShaderIR; |
| 43 | using VideoCommon::Shader::STAGE_MAIN_OFFSET; | ||
| 40 | 44 | ||
| 41 | namespace { | 45 | namespace { |
| 42 | 46 | ||
| 43 | constexpr u32 STAGE_MAIN_OFFSET = 10; | ||
| 44 | constexpr u32 KERNEL_MAIN_OFFSET = 0; | ||
| 45 | |||
| 46 | constexpr VideoCommon::Shader::CompilerSettings COMPILER_SETTINGS{}; | 47 | constexpr VideoCommon::Shader::CompilerSettings COMPILER_SETTINGS{}; |
| 47 | 48 | ||
| 48 | /// Gets the address for the specified shader stage program | ||
| 49 | GPUVAddr GetShaderAddress(Core::System& system, Maxwell::ShaderProgram program) { | ||
| 50 | const auto& gpu{system.GPU().Maxwell3D()}; | ||
| 51 | const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]}; | ||
| 52 | return gpu.regs.code_address.CodeAddress() + shader_config.offset; | ||
| 53 | } | ||
| 54 | |||
| 55 | /// Gets if the current instruction offset is a scheduler instruction | ||
| 56 | constexpr bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) { | ||
| 57 | // Sched instructions appear once every 4 instructions. | ||
| 58 | constexpr std::size_t SchedPeriod = 4; | ||
| 59 | const std::size_t absolute_offset = offset - main_offset; | ||
| 60 | return (absolute_offset % SchedPeriod) == 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Calculates the size of a program stream | ||
| 64 | std::size_t CalculateProgramSize(const ProgramCode& program) { | ||
| 65 | constexpr std::size_t start_offset = 10; | ||
| 66 | // This is the encoded version of BRA that jumps to itself. All Nvidia | ||
| 67 | // shaders end with one. | ||
| 68 | constexpr u64 self_jumping_branch = 0xE2400FFFFF07000FULL; | ||
| 69 | constexpr u64 mask = 0xFFFFFFFFFF7FFFFFULL; | ||
| 70 | std::size_t offset = start_offset; | ||
| 71 | while (offset < program.size()) { | ||
| 72 | const u64 instruction = program[offset]; | ||
| 73 | if (!IsSchedInstruction(offset, start_offset)) { | ||
| 74 | if ((instruction & mask) == self_jumping_branch) { | ||
| 75 | // End on Maxwell's "nop" instruction | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | if (instruction == 0) { | ||
| 79 | break; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | offset++; | ||
| 83 | } | ||
| 84 | // The last instruction is included in the program size | ||
| 85 | return std::min(offset + 1, program.size()); | ||
| 86 | } | ||
| 87 | |||
| 88 | /// Gets the shader program code from memory for the specified address | ||
| 89 | ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, const GPUVAddr gpu_addr, | ||
| 90 | const u8* host_ptr) { | ||
| 91 | ProgramCode code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); | ||
| 92 | ASSERT_OR_EXECUTE(host_ptr != nullptr, { | ||
| 93 | std::fill(code.begin(), code.end(), 0); | ||
| 94 | return code; | ||
| 95 | }); | ||
| 96 | memory_manager.ReadBlockUnsafe(gpu_addr, code.data(), code.size() * sizeof(u64)); | ||
| 97 | code.resize(CalculateProgramSize(code)); | ||
| 98 | return code; | ||
| 99 | } | ||
| 100 | |||
| 101 | /// Gets the shader type from a Maxwell program type | 49 | /// Gets the shader type from a Maxwell program type |
| 102 | constexpr GLenum GetGLShaderType(ShaderType shader_type) { | 50 | constexpr GLenum GetGLShaderType(ShaderType shader_type) { |
| 103 | switch (shader_type) { | 51 | switch (shader_type) { |
| @@ -114,17 +62,6 @@ constexpr GLenum GetGLShaderType(ShaderType shader_type) { | |||
| 114 | } | 62 | } |
| 115 | } | 63 | } |
| 116 | 64 | ||
| 117 | /// Hashes one (or two) program streams | ||
| 118 | u64 GetUniqueIdentifier(ShaderType shader_type, bool is_a, const ProgramCode& code, | ||
| 119 | const ProgramCode& code_b = {}) { | ||
| 120 | u64 unique_identifier = boost::hash_value(code); | ||
| 121 | if (is_a) { | ||
| 122 | // VertexA programs include two programs | ||
| 123 | boost::hash_combine(unique_identifier, boost::hash_value(code_b)); | ||
| 124 | } | ||
| 125 | return unique_identifier; | ||
| 126 | } | ||
| 127 | |||
| 128 | constexpr const char* GetShaderTypeName(ShaderType shader_type) { | 65 | constexpr const char* GetShaderTypeName(ShaderType shader_type) { |
| 129 | switch (shader_type) { | 66 | switch (shader_type) { |
| 130 | case ShaderType::Vertex: | 67 | case ShaderType::Vertex: |
| @@ -456,11 +393,12 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { | |||
| 456 | const auto host_ptr{memory_manager.GetPointer(address)}; | 393 | const auto host_ptr{memory_manager.GetPointer(address)}; |
| 457 | 394 | ||
| 458 | // No shader found - create a new one | 395 | // No shader found - create a new one |
| 459 | ProgramCode code{GetShaderCode(memory_manager, address, host_ptr)}; | 396 | ProgramCode code{GetShaderCode(memory_manager, address, host_ptr, false)}; |
| 460 | ProgramCode code_b; | 397 | ProgramCode code_b; |
| 461 | if (program == Maxwell::ShaderProgram::VertexA) { | 398 | if (program == Maxwell::ShaderProgram::VertexA) { |
| 462 | const GPUVAddr address_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)}; | 399 | const GPUVAddr address_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)}; |
| 463 | code_b = GetShaderCode(memory_manager, address_b, memory_manager.GetPointer(address_b)); | 400 | const u8* host_ptr_b = memory_manager.GetPointer(address_b); |
| 401 | code_b = GetShaderCode(memory_manager, address_b, host_ptr_b, false); | ||
| 464 | } | 402 | } |
| 465 | 403 | ||
| 466 | const auto unique_identifier = GetUniqueIdentifier( | 404 | const auto unique_identifier = GetUniqueIdentifier( |
| @@ -498,7 +436,7 @@ Shader ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) { | |||
| 498 | 436 | ||
| 499 | const auto host_ptr{memory_manager.GetPointer(code_addr)}; | 437 | const auto host_ptr{memory_manager.GetPointer(code_addr)}; |
| 500 | // No kernel found, create a new one | 438 | // No kernel found, create a new one |
| 501 | auto code{GetShaderCode(memory_manager, code_addr, host_ptr)}; | 439 | auto code{GetShaderCode(memory_manager, code_addr, host_ptr, true)}; |
| 502 | const auto unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)}; | 440 | const auto unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)}; |
| 503 | 441 | ||
| 504 | const ShaderParameters params{system, disk_cache, device, | 442 | const ShaderParameters params{system, disk_cache, device, |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index e6d4adc92..9b703a2f0 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -27,12 +27,18 @@ | |||
| 27 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | 27 | #include "video_core/renderer_vulkan/vk_update_descriptor.h" |
| 28 | #include "video_core/renderer_vulkan/wrapper.h" | 28 | #include "video_core/renderer_vulkan/wrapper.h" |
| 29 | #include "video_core/shader/compiler_settings.h" | 29 | #include "video_core/shader/compiler_settings.h" |
| 30 | #include "video_core/shader/memory_util.h" | ||
| 30 | 31 | ||
| 31 | namespace Vulkan { | 32 | namespace Vulkan { |
| 32 | 33 | ||
| 33 | MICROPROFILE_DECLARE(Vulkan_PipelineCache); | 34 | MICROPROFILE_DECLARE(Vulkan_PipelineCache); |
| 34 | 35 | ||
| 35 | using Tegra::Engines::ShaderType; | 36 | using Tegra::Engines::ShaderType; |
| 37 | using VideoCommon::Shader::GetShaderAddress; | ||
| 38 | using VideoCommon::Shader::GetShaderCode; | ||
| 39 | using VideoCommon::Shader::KERNEL_MAIN_OFFSET; | ||
| 40 | using VideoCommon::Shader::ProgramCode; | ||
| 41 | using VideoCommon::Shader::STAGE_MAIN_OFFSET; | ||
| 36 | 42 | ||
| 37 | namespace { | 43 | namespace { |
| 38 | 44 | ||
| @@ -45,60 +51,6 @@ constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; | |||
| 45 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ | 51 | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ |
| 46 | VideoCommon::Shader::CompileDepth::FullDecompile}; | 52 | VideoCommon::Shader::CompileDepth::FullDecompile}; |
| 47 | 53 | ||
| 48 | /// Gets the address for the specified shader stage program | ||
| 49 | GPUVAddr GetShaderAddress(Core::System& system, Maxwell::ShaderProgram program) { | ||
| 50 | const auto& gpu{system.GPU().Maxwell3D()}; | ||
| 51 | const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]}; | ||
| 52 | return gpu.regs.code_address.CodeAddress() + shader_config.offset; | ||
| 53 | } | ||
| 54 | |||
| 55 | /// Gets if the current instruction offset is a scheduler instruction | ||
| 56 | constexpr bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) { | ||
| 57 | // Sched instructions appear once every 4 instructions. | ||
| 58 | constexpr std::size_t SchedPeriod = 4; | ||
| 59 | const std::size_t absolute_offset = offset - main_offset; | ||
| 60 | return (absolute_offset % SchedPeriod) == 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Calculates the size of a program stream | ||
| 64 | std::size_t CalculateProgramSize(const ProgramCode& program, bool is_compute) { | ||
| 65 | const std::size_t start_offset = is_compute ? 0 : 10; | ||
| 66 | // This is the encoded version of BRA that jumps to itself. All Nvidia | ||
| 67 | // shaders end with one. | ||
| 68 | constexpr u64 self_jumping_branch = 0xE2400FFFFF07000FULL; | ||
| 69 | constexpr u64 mask = 0xFFFFFFFFFF7FFFFFULL; | ||
| 70 | std::size_t offset = start_offset; | ||
| 71 | while (offset < program.size()) { | ||
| 72 | const u64 instruction = program[offset]; | ||
| 73 | if (!IsSchedInstruction(offset, start_offset)) { | ||
| 74 | if ((instruction & mask) == self_jumping_branch) { | ||
| 75 | // End on Maxwell's "nop" instruction | ||
| 76 | break; | ||
| 77 | } | ||
| 78 | if (instruction == 0) { | ||
| 79 | break; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | ++offset; | ||
| 83 | } | ||
| 84 | // The last instruction is included in the program size | ||
| 85 | return std::min(offset + 1, program.size()); | ||
| 86 | } | ||
| 87 | |||
| 88 | /// Gets the shader program code from memory for the specified address | ||
| 89 | ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, const GPUVAddr gpu_addr, | ||
| 90 | const u8* host_ptr, bool is_compute) { | ||
| 91 | ProgramCode program_code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); | ||
| 92 | ASSERT_OR_EXECUTE(host_ptr != nullptr, { | ||
| 93 | std::fill(program_code.begin(), program_code.end(), 0); | ||
| 94 | return program_code; | ||
| 95 | }); | ||
| 96 | memory_manager.ReadBlockUnsafe(gpu_addr, program_code.data(), | ||
| 97 | program_code.size() * sizeof(u64)); | ||
| 98 | program_code.resize(CalculateProgramSize(program_code, is_compute)); | ||
| 99 | return program_code; | ||
| 100 | } | ||
| 101 | |||
| 102 | constexpr std::size_t GetStageFromProgram(std::size_t program) { | 54 | constexpr std::size_t GetStageFromProgram(std::size_t program) { |
| 103 | return program == 0 ? 0 : program - 1; | 55 | return program == 0 ? 0 : program - 1; |
| 104 | } | 56 | } |
| @@ -230,9 +182,9 @@ std::array<Shader, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() { | |||
| 230 | const auto host_ptr{memory_manager.GetPointer(program_addr)}; | 182 | const auto host_ptr{memory_manager.GetPointer(program_addr)}; |
| 231 | 183 | ||
| 232 | // No shader found - create a new one | 184 | // No shader found - create a new one |
| 233 | constexpr u32 stage_offset = 10; | 185 | constexpr u32 stage_offset = STAGE_MAIN_OFFSET; |
| 234 | const auto stage = static_cast<Tegra::Engines::ShaderType>(index == 0 ? 0 : index - 1); | 186 | const auto stage = static_cast<Tegra::Engines::ShaderType>(index == 0 ? 0 : index - 1); |
| 235 | auto code = GetShaderCode(memory_manager, program_addr, host_ptr, false); | 187 | ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, false); |
| 236 | 188 | ||
| 237 | shader = std::make_shared<CachedShader>(system, stage, program_addr, *cpu_addr, | 189 | shader = std::make_shared<CachedShader>(system, stage, program_addr, *cpu_addr, |
| 238 | std::move(code), stage_offset); | 190 | std::move(code), stage_offset); |
| @@ -288,11 +240,10 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach | |||
| 288 | // No shader found - create a new one | 240 | // No shader found - create a new one |
| 289 | const auto host_ptr = memory_manager.GetPointer(program_addr); | 241 | const auto host_ptr = memory_manager.GetPointer(program_addr); |
| 290 | 242 | ||
| 291 | auto code = GetShaderCode(memory_manager, program_addr, host_ptr, true); | 243 | ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, true); |
| 292 | constexpr u32 kernel_main_offset = 0; | ||
| 293 | shader = std::make_shared<CachedShader>(system, Tegra::Engines::ShaderType::Compute, | 244 | shader = std::make_shared<CachedShader>(system, Tegra::Engines::ShaderType::Compute, |
| 294 | program_addr, *cpu_addr, std::move(code), | 245 | program_addr, *cpu_addr, std::move(code), |
| 295 | kernel_main_offset); | 246 | KERNEL_MAIN_OFFSET); |
| 296 | if (cpu_addr) { | 247 | if (cpu_addr) { |
| 297 | Register(shader); | 248 | Register(shader); |
| 298 | } else { | 249 | } else { |
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.h b/src/video_core/renderer_vulkan/vk_pipeline_cache.h index 84d26b822..ebddafb73 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.h +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.h | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | 24 | #include "video_core/renderer_vulkan/vk_resource_manager.h" |
| 25 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | 25 | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" |
| 26 | #include "video_core/renderer_vulkan/wrapper.h" | 26 | #include "video_core/renderer_vulkan/wrapper.h" |
| 27 | #include "video_core/shader/memory_util.h" | ||
| 27 | #include "video_core/shader/registry.h" | 28 | #include "video_core/shader/registry.h" |
| 28 | #include "video_core/shader/shader_ir.h" | 29 | #include "video_core/shader/shader_ir.h" |
| 29 | #include "video_core/surface.h" | 30 | #include "video_core/surface.h" |
| @@ -46,8 +47,6 @@ class CachedShader; | |||
| 46 | using Shader = std::shared_ptr<CachedShader>; | 47 | using Shader = std::shared_ptr<CachedShader>; |
| 47 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | 48 | using Maxwell = Tegra::Engines::Maxwell3D::Regs; |
| 48 | 49 | ||
| 49 | using ProgramCode = std::vector<u64>; | ||
| 50 | |||
| 51 | struct GraphicsPipelineCacheKey { | 50 | struct GraphicsPipelineCacheKey { |
| 52 | FixedPipelineState fixed_state; | 51 | FixedPipelineState fixed_state; |
| 53 | RenderPassParams renderpass_params; | 52 | RenderPassParams renderpass_params; |
| @@ -108,7 +107,8 @@ namespace Vulkan { | |||
| 108 | class CachedShader final : public RasterizerCacheObject { | 107 | class CachedShader final : public RasterizerCacheObject { |
| 109 | public: | 108 | public: |
| 110 | explicit CachedShader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, | 109 | explicit CachedShader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, |
| 111 | VAddr cpu_addr, ProgramCode program_code, u32 main_offset); | 110 | VAddr cpu_addr, VideoCommon::Shader::ProgramCode program_code, |
| 111 | u32 main_offset); | ||
| 112 | ~CachedShader(); | 112 | ~CachedShader(); |
| 113 | 113 | ||
| 114 | GPUVAddr GetGpuAddr() const { | 114 | GPUVAddr GetGpuAddr() const { |
| @@ -140,7 +140,7 @@ private: | |||
| 140 | Tegra::Engines::ShaderType stage); | 140 | Tegra::Engines::ShaderType stage); |
| 141 | 141 | ||
| 142 | GPUVAddr gpu_addr{}; | 142 | GPUVAddr gpu_addr{}; |
| 143 | ProgramCode program_code; | 143 | VideoCommon::Shader::ProgramCode program_code; |
| 144 | VideoCommon::Shader::Registry registry; | 144 | VideoCommon::Shader::Registry registry; |
| 145 | VideoCommon::Shader::ShaderIR shader_ir; | 145 | VideoCommon::Shader::ShaderIR shader_ir; |
| 146 | ShaderEntries entries; | 146 | ShaderEntries entries; |
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index e00a3fb70..8d86020f6 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "video_core/shader/ast.h" | 14 | #include "video_core/shader/ast.h" |
| 15 | #include "video_core/shader/control_flow.h" | 15 | #include "video_core/shader/control_flow.h" |
| 16 | #include "video_core/shader/memory_util.h" | ||
| 16 | #include "video_core/shader/registry.h" | 17 | #include "video_core/shader/registry.h" |
| 17 | #include "video_core/shader/shader_ir.h" | 18 | #include "video_core/shader/shader_ir.h" |
| 18 | 19 | ||
| @@ -115,17 +116,6 @@ Pred GetPredicate(u32 index, bool negated) { | |||
| 115 | return static_cast<Pred>(static_cast<u64>(index) + (negated ? 8ULL : 0ULL)); | 116 | return static_cast<Pred>(static_cast<u64>(index) + (negated ? 8ULL : 0ULL)); |
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | /** | ||
| 119 | * Returns whether the instruction at the specified offset is a 'sched' instruction. | ||
| 120 | * Sched instructions always appear before a sequence of 3 instructions. | ||
| 121 | */ | ||
| 122 | constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) { | ||
| 123 | constexpr u32 SchedPeriod = 4; | ||
| 124 | u32 absolute_offset = offset - main_offset; | ||
| 125 | |||
| 126 | return (absolute_offset % SchedPeriod) == 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | enum class ParseResult : u32 { | 119 | enum class ParseResult : u32 { |
| 130 | ControlCaught, | 120 | ControlCaught, |
| 131 | BlockEnd, | 121 | BlockEnd, |
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index 87ac9ac6c..1167ff4ec 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include "video_core/engines/shader_bytecode.h" | 13 | #include "video_core/engines/shader_bytecode.h" |
| 14 | #include "video_core/engines/shader_header.h" | 14 | #include "video_core/engines/shader_header.h" |
| 15 | #include "video_core/shader/control_flow.h" | 15 | #include "video_core/shader/control_flow.h" |
| 16 | #include "video_core/shader/memory_util.h" | ||
| 16 | #include "video_core/shader/node_helper.h" | 17 | #include "video_core/shader/node_helper.h" |
| 17 | #include "video_core/shader/shader_ir.h" | 18 | #include "video_core/shader/shader_ir.h" |
| 18 | 19 | ||
| @@ -23,17 +24,6 @@ using Tegra::Shader::OpCode; | |||
| 23 | 24 | ||
| 24 | namespace { | 25 | namespace { |
| 25 | 26 | ||
| 26 | /** | ||
| 27 | * Returns whether the instruction at the specified offset is a 'sched' instruction. | ||
| 28 | * Sched instructions always appear before a sequence of 3 instructions. | ||
| 29 | */ | ||
| 30 | constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) { | ||
| 31 | constexpr u32 SchedPeriod = 4; | ||
| 32 | u32 absolute_offset = offset - main_offset; | ||
| 33 | |||
| 34 | return (absolute_offset % SchedPeriod) == 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | void DeduceTextureHandlerSize(VideoCore::GuestDriverProfile& gpu_driver, | 27 | void DeduceTextureHandlerSize(VideoCore::GuestDriverProfile& gpu_driver, |
| 38 | const std::list<Sampler>& used_samplers) { | 28 | const std::list<Sampler>& used_samplers) { |
| 39 | if (gpu_driver.IsTextureHandlerSizeKnown() || used_samplers.size() <= 1) { | 29 | if (gpu_driver.IsTextureHandlerSizeKnown() || used_samplers.size() <= 1) { |
diff --git a/src/video_core/shader/memory_util.cpp b/src/video_core/shader/memory_util.cpp new file mode 100644 index 000000000..074f21691 --- /dev/null +++ b/src/video_core/shader/memory_util.cpp | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cstddef> | ||
| 7 | |||
| 8 | #include <boost/container_hash/hash.hpp> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/core.h" | ||
| 12 | #include "video_core/engines/maxwell_3d.h" | ||
| 13 | #include "video_core/memory_manager.h" | ||
| 14 | #include "video_core/shader/memory_util.h" | ||
| 15 | #include "video_core/shader/shader_ir.h" | ||
| 16 | |||
| 17 | namespace VideoCommon::Shader { | ||
| 18 | |||
| 19 | GPUVAddr GetShaderAddress(Core::System& system, | ||
| 20 | Tegra::Engines::Maxwell3D::Regs::ShaderProgram program) { | ||
| 21 | const auto& gpu{system.GPU().Maxwell3D()}; | ||
| 22 | const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]}; | ||
| 23 | return gpu.regs.code_address.CodeAddress() + shader_config.offset; | ||
| 24 | } | ||
| 25 | |||
| 26 | bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) { | ||
| 27 | // Sched instructions appear once every 4 instructions. | ||
| 28 | constexpr std::size_t SchedPeriod = 4; | ||
| 29 | const std::size_t absolute_offset = offset - main_offset; | ||
| 30 | return (absolute_offset % SchedPeriod) == 0; | ||
| 31 | } | ||
| 32 | |||
| 33 | std::size_t CalculateProgramSize(const ProgramCode& program, bool is_compute) { | ||
| 34 | // This is the encoded version of BRA that jumps to itself. All Nvidia | ||
| 35 | // shaders end with one. | ||
| 36 | static constexpr u64 SELF_JUMPING_BRANCH = 0xE2400FFFFF07000FULL; | ||
| 37 | static constexpr u64 MASK = 0xFFFFFFFFFF7FFFFFULL; | ||
| 38 | |||
| 39 | const std::size_t start_offset = is_compute ? KERNEL_MAIN_OFFSET : STAGE_MAIN_OFFSET; | ||
| 40 | std::size_t offset = start_offset; | ||
| 41 | while (offset < program.size()) { | ||
| 42 | const u64 instruction = program[offset]; | ||
| 43 | if (!IsSchedInstruction(offset, start_offset)) { | ||
| 44 | if ((instruction & MASK) == SELF_JUMPING_BRANCH) { | ||
| 45 | // End on Maxwell's "nop" instruction | ||
| 46 | break; | ||
| 47 | } | ||
| 48 | if (instruction == 0) { | ||
| 49 | break; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | ++offset; | ||
| 53 | } | ||
| 54 | // The last instruction is included in the program size | ||
| 55 | return std::min(offset + 1, program.size()); | ||
| 56 | } | ||
| 57 | |||
| 58 | ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, GPUVAddr gpu_addr, | ||
| 59 | const u8* host_ptr, bool is_compute) { | ||
| 60 | ProgramCode code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); | ||
| 61 | ASSERT_OR_EXECUTE(host_ptr != nullptr, { return code; }); | ||
| 62 | memory_manager.ReadBlockUnsafe(gpu_addr, code.data(), code.size() * sizeof(u64)); | ||
| 63 | code.resize(CalculateProgramSize(code, is_compute)); | ||
| 64 | return code; | ||
| 65 | } | ||
| 66 | |||
| 67 | u64 GetUniqueIdentifier(Tegra::Engines::ShaderType shader_type, bool is_a, const ProgramCode& code, | ||
| 68 | const ProgramCode& code_b) { | ||
| 69 | u64 unique_identifier = boost::hash_value(code); | ||
| 70 | if (is_a) { | ||
| 71 | // VertexA programs include two programs | ||
| 72 | boost::hash_combine(unique_identifier, boost::hash_value(code_b)); | ||
| 73 | } | ||
| 74 | return unique_identifier; | ||
| 75 | } | ||
| 76 | |||
| 77 | } // namespace VideoCommon::Shader | ||
diff --git a/src/video_core/shader/memory_util.h b/src/video_core/shader/memory_util.h new file mode 100644 index 000000000..be90d24fd --- /dev/null +++ b/src/video_core/shader/memory_util.h | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "video_core/engines/maxwell_3d.h" | ||
| 12 | #include "video_core/engines/shader_type.h" | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class System; | ||
| 16 | } | ||
| 17 | |||
| 18 | namespace Tegra { | ||
| 19 | class MemoryManager; | ||
| 20 | } | ||
| 21 | |||
| 22 | namespace VideoCommon::Shader { | ||
| 23 | |||
| 24 | using ProgramCode = std::vector<u64>; | ||
| 25 | |||
| 26 | constexpr u32 STAGE_MAIN_OFFSET = 10; | ||
| 27 | constexpr u32 KERNEL_MAIN_OFFSET = 0; | ||
| 28 | |||
| 29 | /// Gets the address for the specified shader stage program | ||
| 30 | GPUVAddr GetShaderAddress(Core::System& system, | ||
| 31 | Tegra::Engines::Maxwell3D::Regs::ShaderProgram program); | ||
| 32 | |||
| 33 | /// Gets if the current instruction offset is a scheduler instruction | ||
| 34 | bool IsSchedInstruction(std::size_t offset, std::size_t main_offset); | ||
| 35 | |||
| 36 | /// Calculates the size of a program stream | ||
| 37 | std::size_t CalculateProgramSize(const ProgramCode& program, bool is_compute); | ||
| 38 | |||
| 39 | /// Gets the shader program code from memory for the specified address | ||
| 40 | ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, GPUVAddr gpu_addr, | ||
| 41 | const u8* host_ptr, bool is_compute); | ||
| 42 | |||
| 43 | /// Hashes one (or two) program streams | ||
| 44 | u64 GetUniqueIdentifier(Tegra::Engines::ShaderType shader_type, bool is_a, const ProgramCode& code, | ||
| 45 | const ProgramCode& code_b = {}); | ||
| 46 | |||
| 47 | } // namespace VideoCommon::Shader | ||
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index c6e7bdf50..69de5e68b 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include "video_core/engines/shader_header.h" | 18 | #include "video_core/engines/shader_header.h" |
| 19 | #include "video_core/shader/ast.h" | 19 | #include "video_core/shader/ast.h" |
| 20 | #include "video_core/shader/compiler_settings.h" | 20 | #include "video_core/shader/compiler_settings.h" |
| 21 | #include "video_core/shader/memory_util.h" | ||
| 21 | #include "video_core/shader/node.h" | 22 | #include "video_core/shader/node.h" |
| 22 | #include "video_core/shader/registry.h" | 23 | #include "video_core/shader/registry.h" |
| 23 | 24 | ||
| @@ -25,8 +26,6 @@ namespace VideoCommon::Shader { | |||
| 25 | 26 | ||
| 26 | struct ShaderBlock; | 27 | struct ShaderBlock; |
| 27 | 28 | ||
| 28 | using ProgramCode = std::vector<u64>; | ||
| 29 | |||
| 30 | constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; | 29 | constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; |
| 31 | 30 | ||
| 32 | class ConstBuffer { | 31 | class ConstBuffer { |