diff options
| author | 2020-04-24 01:44:14 -0300 | |
|---|---|---|
| committer | 2020-04-26 01:38:51 -0300 | |
| commit | ddd82ef42b7bb7bea4c80edeb96bca8512580df3 (patch) | |
| tree | b2b09f597fe519128d065f034d51103f478e6776 /src/video_core/shader | |
| parent | Merge pull request #3768 from H27CK/cmd-title-fmt (diff) | |
| download | yuzu-ddd82ef42b7bb7bea4c80edeb96bca8512580df3.tar.gz yuzu-ddd82ef42b7bb7bea4c80edeb96bca8512580df3.tar.xz yuzu-ddd82ef42b7bb7bea4c80edeb96bca8512580df3.zip | |
shader/memory_util: Deduplicate code
Deduplicate code shared between vk_pipeline_cache and gl_shader_cache as
well as shader decoder code.
While we are at it, fix a bug in gl_shader_cache where compute shaders
had an start offset of a stage shader.
Diffstat (limited to 'src/video_core/shader')
| -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 |
5 files changed, 127 insertions, 24 deletions
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 { |