forked from eden-emu/eden
		
	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.
This commit is contained in:
		
							parent
							
								
									26f2820ae3
								
							
						
					
					
						commit
						ddd82ef42b
					
				
					 9 changed files with 153 additions and 159 deletions
				
			
		|  | @ -124,6 +124,8 @@ add_library(video_core STATIC | ||||||
|     shader/decode.cpp |     shader/decode.cpp | ||||||
|     shader/expr.cpp |     shader/expr.cpp | ||||||
|     shader/expr.h |     shader/expr.h | ||||||
|  |     shader/memory_util.cpp | ||||||
|  |     shader/memory_util.h | ||||||
|     shader/node_helper.cpp |     shader/node_helper.cpp | ||||||
|     shader/node_helper.h |     shader/node_helper.h | ||||||
|     shader/node.h |     shader/node.h | ||||||
|  |  | ||||||
|  | @ -10,8 +10,6 @@ | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <unordered_set> | #include <unordered_set> | ||||||
| 
 | 
 | ||||||
| #include <boost/functional/hash.hpp> |  | ||||||
| 
 |  | ||||||
| #include "common/alignment.h" | #include "common/alignment.h" | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/logging/log.h" | #include "common/logging/log.h" | ||||||
|  | @ -28,76 +26,26 @@ | ||||||
| #include "video_core/renderer_opengl/gl_shader_disk_cache.h" | #include "video_core/renderer_opengl/gl_shader_disk_cache.h" | ||||||
| #include "video_core/renderer_opengl/gl_state_tracker.h" | #include "video_core/renderer_opengl/gl_state_tracker.h" | ||||||
| #include "video_core/renderer_opengl/utils.h" | #include "video_core/renderer_opengl/utils.h" | ||||||
|  | #include "video_core/shader/memory_util.h" | ||||||
| #include "video_core/shader/registry.h" | #include "video_core/shader/registry.h" | ||||||
| #include "video_core/shader/shader_ir.h" | #include "video_core/shader/shader_ir.h" | ||||||
| 
 | 
 | ||||||
| namespace OpenGL { | namespace OpenGL { | ||||||
| 
 | 
 | ||||||
| using Tegra::Engines::ShaderType; | using Tegra::Engines::ShaderType; | ||||||
|  | using VideoCommon::Shader::GetShaderAddress; | ||||||
|  | using VideoCommon::Shader::GetShaderCode; | ||||||
|  | using VideoCommon::Shader::GetUniqueIdentifier; | ||||||
|  | using VideoCommon::Shader::KERNEL_MAIN_OFFSET; | ||||||
| using VideoCommon::Shader::ProgramCode; | using VideoCommon::Shader::ProgramCode; | ||||||
| using VideoCommon::Shader::Registry; | using VideoCommon::Shader::Registry; | ||||||
| using VideoCommon::Shader::ShaderIR; | using VideoCommon::Shader::ShaderIR; | ||||||
|  | using VideoCommon::Shader::STAGE_MAIN_OFFSET; | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
| 
 | 
 | ||||||
| constexpr u32 STAGE_MAIN_OFFSET = 10; |  | ||||||
| constexpr u32 KERNEL_MAIN_OFFSET = 0; |  | ||||||
| 
 |  | ||||||
| constexpr VideoCommon::Shader::CompilerSettings COMPILER_SETTINGS{}; | constexpr VideoCommon::Shader::CompilerSettings COMPILER_SETTINGS{}; | ||||||
| 
 | 
 | ||||||
| /// Gets the address for the specified shader stage program
 |  | ||||||
| GPUVAddr GetShaderAddress(Core::System& system, Maxwell::ShaderProgram program) { |  | ||||||
|     const auto& gpu{system.GPU().Maxwell3D()}; |  | ||||||
|     const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]}; |  | ||||||
|     return gpu.regs.code_address.CodeAddress() + shader_config.offset; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Gets if the current instruction offset is a scheduler instruction
 |  | ||||||
| constexpr bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) { |  | ||||||
|     // Sched instructions appear once every 4 instructions.
 |  | ||||||
|     constexpr std::size_t SchedPeriod = 4; |  | ||||||
|     const std::size_t absolute_offset = offset - main_offset; |  | ||||||
|     return (absolute_offset % SchedPeriod) == 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Calculates the size of a program stream
 |  | ||||||
| std::size_t CalculateProgramSize(const ProgramCode& program) { |  | ||||||
|     constexpr std::size_t start_offset = 10; |  | ||||||
|     // This is the encoded version of BRA that jumps to itself. All Nvidia
 |  | ||||||
|     // shaders end with one.
 |  | ||||||
|     constexpr u64 self_jumping_branch = 0xE2400FFFFF07000FULL; |  | ||||||
|     constexpr u64 mask = 0xFFFFFFFFFF7FFFFFULL; |  | ||||||
|     std::size_t offset = start_offset; |  | ||||||
|     while (offset < program.size()) { |  | ||||||
|         const u64 instruction = program[offset]; |  | ||||||
|         if (!IsSchedInstruction(offset, start_offset)) { |  | ||||||
|             if ((instruction & mask) == self_jumping_branch) { |  | ||||||
|                 // End on Maxwell's "nop" instruction
 |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|             if (instruction == 0) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         offset++; |  | ||||||
|     } |  | ||||||
|     // The last instruction is included in the program size
 |  | ||||||
|     return std::min(offset + 1, program.size()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Gets the shader program code from memory for the specified address
 |  | ||||||
| ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, const GPUVAddr gpu_addr, |  | ||||||
|                           const u8* host_ptr) { |  | ||||||
|     ProgramCode code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); |  | ||||||
|     ASSERT_OR_EXECUTE(host_ptr != nullptr, { |  | ||||||
|         std::fill(code.begin(), code.end(), 0); |  | ||||||
|         return code; |  | ||||||
|     }); |  | ||||||
|     memory_manager.ReadBlockUnsafe(gpu_addr, code.data(), code.size() * sizeof(u64)); |  | ||||||
|     code.resize(CalculateProgramSize(code)); |  | ||||||
|     return code; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Gets the shader type from a Maxwell program type
 | /// Gets the shader type from a Maxwell program type
 | ||||||
| constexpr GLenum GetGLShaderType(ShaderType shader_type) { | constexpr GLenum GetGLShaderType(ShaderType shader_type) { | ||||||
|     switch (shader_type) { |     switch (shader_type) { | ||||||
|  | @ -114,17 +62,6 @@ constexpr GLenum GetGLShaderType(ShaderType shader_type) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Hashes one (or two) program streams
 |  | ||||||
| u64 GetUniqueIdentifier(ShaderType shader_type, bool is_a, const ProgramCode& code, |  | ||||||
|                         const ProgramCode& code_b = {}) { |  | ||||||
|     u64 unique_identifier = boost::hash_value(code); |  | ||||||
|     if (is_a) { |  | ||||||
|         // VertexA programs include two programs
 |  | ||||||
|         boost::hash_combine(unique_identifier, boost::hash_value(code_b)); |  | ||||||
|     } |  | ||||||
|     return unique_identifier; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| constexpr const char* GetShaderTypeName(ShaderType shader_type) { | constexpr const char* GetShaderTypeName(ShaderType shader_type) { | ||||||
|     switch (shader_type) { |     switch (shader_type) { | ||||||
|     case ShaderType::Vertex: |     case ShaderType::Vertex: | ||||||
|  | @ -456,11 +393,12 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { | ||||||
|     const auto host_ptr{memory_manager.GetPointer(address)}; |     const auto host_ptr{memory_manager.GetPointer(address)}; | ||||||
| 
 | 
 | ||||||
|     // No shader found - create a new one
 |     // No shader found - create a new one
 | ||||||
|     ProgramCode code{GetShaderCode(memory_manager, address, host_ptr)}; |     ProgramCode code{GetShaderCode(memory_manager, address, host_ptr, false)}; | ||||||
|     ProgramCode code_b; |     ProgramCode code_b; | ||||||
|     if (program == Maxwell::ShaderProgram::VertexA) { |     if (program == Maxwell::ShaderProgram::VertexA) { | ||||||
|         const GPUVAddr address_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)}; |         const GPUVAddr address_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)}; | ||||||
|         code_b = GetShaderCode(memory_manager, address_b, memory_manager.GetPointer(address_b)); |         const u8* host_ptr_b = memory_manager.GetPointer(address_b); | ||||||
|  |         code_b = GetShaderCode(memory_manager, address_b, host_ptr_b, false); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const auto unique_identifier = GetUniqueIdentifier( |     const auto unique_identifier = GetUniqueIdentifier( | ||||||
|  | @ -498,7 +436,7 @@ Shader ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) { | ||||||
| 
 | 
 | ||||||
|     const auto host_ptr{memory_manager.GetPointer(code_addr)}; |     const auto host_ptr{memory_manager.GetPointer(code_addr)}; | ||||||
|     // No kernel found, create a new one
 |     // No kernel found, create a new one
 | ||||||
|     auto code{GetShaderCode(memory_manager, code_addr, host_ptr)}; |     auto code{GetShaderCode(memory_manager, code_addr, host_ptr, true)}; | ||||||
|     const auto unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)}; |     const auto unique_identifier{GetUniqueIdentifier(ShaderType::Compute, false, code)}; | ||||||
| 
 | 
 | ||||||
|     const ShaderParameters params{system,    disk_cache, device, |     const ShaderParameters params{system,    disk_cache, device, | ||||||
|  |  | ||||||
|  | @ -27,12 +27,18 @@ | ||||||
| #include "video_core/renderer_vulkan/vk_update_descriptor.h" | #include "video_core/renderer_vulkan/vk_update_descriptor.h" | ||||||
| #include "video_core/renderer_vulkan/wrapper.h" | #include "video_core/renderer_vulkan/wrapper.h" | ||||||
| #include "video_core/shader/compiler_settings.h" | #include "video_core/shader/compiler_settings.h" | ||||||
|  | #include "video_core/shader/memory_util.h" | ||||||
| 
 | 
 | ||||||
| namespace Vulkan { | namespace Vulkan { | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DECLARE(Vulkan_PipelineCache); | MICROPROFILE_DECLARE(Vulkan_PipelineCache); | ||||||
| 
 | 
 | ||||||
| using Tegra::Engines::ShaderType; | using Tegra::Engines::ShaderType; | ||||||
|  | using VideoCommon::Shader::GetShaderAddress; | ||||||
|  | using VideoCommon::Shader::GetShaderCode; | ||||||
|  | using VideoCommon::Shader::KERNEL_MAIN_OFFSET; | ||||||
|  | using VideoCommon::Shader::ProgramCode; | ||||||
|  | using VideoCommon::Shader::STAGE_MAIN_OFFSET; | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
| 
 | 
 | ||||||
|  | @ -45,60 +51,6 @@ constexpr VkDescriptorType STORAGE_IMAGE = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; | ||||||
| constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ | constexpr VideoCommon::Shader::CompilerSettings compiler_settings{ | ||||||
|     VideoCommon::Shader::CompileDepth::FullDecompile}; |     VideoCommon::Shader::CompileDepth::FullDecompile}; | ||||||
| 
 | 
 | ||||||
| /// Gets the address for the specified shader stage program
 |  | ||||||
| GPUVAddr GetShaderAddress(Core::System& system, Maxwell::ShaderProgram program) { |  | ||||||
|     const auto& gpu{system.GPU().Maxwell3D()}; |  | ||||||
|     const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]}; |  | ||||||
|     return gpu.regs.code_address.CodeAddress() + shader_config.offset; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Gets if the current instruction offset is a scheduler instruction
 |  | ||||||
| constexpr bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) { |  | ||||||
|     // Sched instructions appear once every 4 instructions.
 |  | ||||||
|     constexpr std::size_t SchedPeriod = 4; |  | ||||||
|     const std::size_t absolute_offset = offset - main_offset; |  | ||||||
|     return (absolute_offset % SchedPeriod) == 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Calculates the size of a program stream
 |  | ||||||
| std::size_t CalculateProgramSize(const ProgramCode& program, bool is_compute) { |  | ||||||
|     const std::size_t start_offset = is_compute ? 0 : 10; |  | ||||||
|     // This is the encoded version of BRA that jumps to itself. All Nvidia
 |  | ||||||
|     // shaders end with one.
 |  | ||||||
|     constexpr u64 self_jumping_branch = 0xE2400FFFFF07000FULL; |  | ||||||
|     constexpr u64 mask = 0xFFFFFFFFFF7FFFFFULL; |  | ||||||
|     std::size_t offset = start_offset; |  | ||||||
|     while (offset < program.size()) { |  | ||||||
|         const u64 instruction = program[offset]; |  | ||||||
|         if (!IsSchedInstruction(offset, start_offset)) { |  | ||||||
|             if ((instruction & mask) == self_jumping_branch) { |  | ||||||
|                 // End on Maxwell's "nop" instruction
 |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|             if (instruction == 0) { |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         ++offset; |  | ||||||
|     } |  | ||||||
|     // The last instruction is included in the program size
 |  | ||||||
|     return std::min(offset + 1, program.size()); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Gets the shader program code from memory for the specified address
 |  | ||||||
| ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, const GPUVAddr gpu_addr, |  | ||||||
|                           const u8* host_ptr, bool is_compute) { |  | ||||||
|     ProgramCode program_code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); |  | ||||||
|     ASSERT_OR_EXECUTE(host_ptr != nullptr, { |  | ||||||
|         std::fill(program_code.begin(), program_code.end(), 0); |  | ||||||
|         return program_code; |  | ||||||
|     }); |  | ||||||
|     memory_manager.ReadBlockUnsafe(gpu_addr, program_code.data(), |  | ||||||
|                                    program_code.size() * sizeof(u64)); |  | ||||||
|     program_code.resize(CalculateProgramSize(program_code, is_compute)); |  | ||||||
|     return program_code; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| constexpr std::size_t GetStageFromProgram(std::size_t program) { | constexpr std::size_t GetStageFromProgram(std::size_t program) { | ||||||
|     return program == 0 ? 0 : program - 1; |     return program == 0 ? 0 : program - 1; | ||||||
| } | } | ||||||
|  | @ -212,9 +164,9 @@ std::array<Shader, Maxwell::MaxShaderProgram> VKPipelineCache::GetShaders() { | ||||||
|             const auto host_ptr{memory_manager.GetPointer(program_addr)}; |             const auto host_ptr{memory_manager.GetPointer(program_addr)}; | ||||||
| 
 | 
 | ||||||
|             // No shader found - create a new one
 |             // No shader found - create a new one
 | ||||||
|             constexpr u32 stage_offset = 10; |             constexpr u32 stage_offset = STAGE_MAIN_OFFSET; | ||||||
|             const auto stage = static_cast<Tegra::Engines::ShaderType>(index == 0 ? 0 : index - 1); |             const auto stage = static_cast<Tegra::Engines::ShaderType>(index == 0 ? 0 : index - 1); | ||||||
|             auto code = GetShaderCode(memory_manager, program_addr, host_ptr, false); |             ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, false); | ||||||
| 
 | 
 | ||||||
|             shader = std::make_shared<CachedShader>(system, stage, program_addr, *cpu_addr, |             shader = std::make_shared<CachedShader>(system, stage, program_addr, *cpu_addr, | ||||||
|                                                     std::move(code), stage_offset); |                                                     std::move(code), stage_offset); | ||||||
|  | @ -270,11 +222,10 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach | ||||||
|         // No shader found - create a new one
 |         // No shader found - create a new one
 | ||||||
|         const auto host_ptr = memory_manager.GetPointer(program_addr); |         const auto host_ptr = memory_manager.GetPointer(program_addr); | ||||||
| 
 | 
 | ||||||
|         auto code = GetShaderCode(memory_manager, program_addr, host_ptr, true); |         ProgramCode code = GetShaderCode(memory_manager, program_addr, host_ptr, true); | ||||||
|         constexpr u32 kernel_main_offset = 0; |  | ||||||
|         shader = std::make_shared<CachedShader>(system, Tegra::Engines::ShaderType::Compute, |         shader = std::make_shared<CachedShader>(system, Tegra::Engines::ShaderType::Compute, | ||||||
|                                                 program_addr, *cpu_addr, std::move(code), |                                                 program_addr, *cpu_addr, std::move(code), | ||||||
|                                                 kernel_main_offset); |                                                 KERNEL_MAIN_OFFSET); | ||||||
|         if (cpu_addr) { |         if (cpu_addr) { | ||||||
|             Register(shader); |             Register(shader); | ||||||
|         } else { |         } else { | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ | ||||||
| #include "video_core/renderer_vulkan/vk_resource_manager.h" | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||||||
| #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | #include "video_core/renderer_vulkan/vk_shader_decompiler.h" | ||||||
| #include "video_core/renderer_vulkan/wrapper.h" | #include "video_core/renderer_vulkan/wrapper.h" | ||||||
|  | #include "video_core/shader/memory_util.h" | ||||||
| #include "video_core/shader/registry.h" | #include "video_core/shader/registry.h" | ||||||
| #include "video_core/shader/shader_ir.h" | #include "video_core/shader/shader_ir.h" | ||||||
| #include "video_core/surface.h" | #include "video_core/surface.h" | ||||||
|  | @ -47,8 +48,6 @@ class CachedShader; | ||||||
| using Shader = std::shared_ptr<CachedShader>; | using Shader = std::shared_ptr<CachedShader>; | ||||||
| using Maxwell = Tegra::Engines::Maxwell3D::Regs; | using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||||||
| 
 | 
 | ||||||
| using ProgramCode = std::vector<u64>; |  | ||||||
| 
 |  | ||||||
| struct GraphicsPipelineCacheKey { | struct GraphicsPipelineCacheKey { | ||||||
|     FixedPipelineState fixed_state; |     FixedPipelineState fixed_state; | ||||||
|     std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders; |     std::array<GPUVAddr, Maxwell::MaxShaderProgram> shaders; | ||||||
|  | @ -113,7 +112,8 @@ namespace Vulkan { | ||||||
| class CachedShader final : public RasterizerCacheObject { | class CachedShader final : public RasterizerCacheObject { | ||||||
| public: | public: | ||||||
|     explicit CachedShader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, |     explicit CachedShader(Core::System& system, Tegra::Engines::ShaderType stage, GPUVAddr gpu_addr, | ||||||
|                           VAddr cpu_addr, ProgramCode program_code, u32 main_offset); |                           VAddr cpu_addr, VideoCommon::Shader::ProgramCode program_code, | ||||||
|  |                           u32 main_offset); | ||||||
|     ~CachedShader(); |     ~CachedShader(); | ||||||
| 
 | 
 | ||||||
|     GPUVAddr GetGpuAddr() const { |     GPUVAddr GetGpuAddr() const { | ||||||
|  | @ -145,7 +145,7 @@ private: | ||||||
|                                                                  Tegra::Engines::ShaderType stage); |                                                                  Tegra::Engines::ShaderType stage); | ||||||
| 
 | 
 | ||||||
|     GPUVAddr gpu_addr{}; |     GPUVAddr gpu_addr{}; | ||||||
|     ProgramCode program_code; |     VideoCommon::Shader::ProgramCode program_code; | ||||||
|     VideoCommon::Shader::Registry registry; |     VideoCommon::Shader::Registry registry; | ||||||
|     VideoCommon::Shader::ShaderIR shader_ir; |     VideoCommon::Shader::ShaderIR shader_ir; | ||||||
|     ShaderEntries entries; |     ShaderEntries entries; | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "video_core/shader/ast.h" | #include "video_core/shader/ast.h" | ||||||
| #include "video_core/shader/control_flow.h" | #include "video_core/shader/control_flow.h" | ||||||
|  | #include "video_core/shader/memory_util.h" | ||||||
| #include "video_core/shader/registry.h" | #include "video_core/shader/registry.h" | ||||||
| #include "video_core/shader/shader_ir.h" | #include "video_core/shader/shader_ir.h" | ||||||
| 
 | 
 | ||||||
|  | @ -115,17 +116,6 @@ Pred GetPredicate(u32 index, bool negated) { | ||||||
|     return static_cast<Pred>(static_cast<u64>(index) + (negated ? 8ULL : 0ULL)); |     return static_cast<Pred>(static_cast<u64>(index) + (negated ? 8ULL : 0ULL)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * Returns whether the instruction at the specified offset is a 'sched' instruction. |  | ||||||
|  * Sched instructions always appear before a sequence of 3 instructions. |  | ||||||
|  */ |  | ||||||
| constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) { |  | ||||||
|     constexpr u32 SchedPeriod = 4; |  | ||||||
|     u32 absolute_offset = offset - main_offset; |  | ||||||
| 
 |  | ||||||
|     return (absolute_offset % SchedPeriod) == 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| enum class ParseResult : u32 { | enum class ParseResult : u32 { | ||||||
|     ControlCaught, |     ControlCaught, | ||||||
|     BlockEnd, |     BlockEnd, | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| #include "video_core/engines/shader_bytecode.h" | #include "video_core/engines/shader_bytecode.h" | ||||||
| #include "video_core/engines/shader_header.h" | #include "video_core/engines/shader_header.h" | ||||||
| #include "video_core/shader/control_flow.h" | #include "video_core/shader/control_flow.h" | ||||||
|  | #include "video_core/shader/memory_util.h" | ||||||
| #include "video_core/shader/node_helper.h" | #include "video_core/shader/node_helper.h" | ||||||
| #include "video_core/shader/shader_ir.h" | #include "video_core/shader/shader_ir.h" | ||||||
| 
 | 
 | ||||||
|  | @ -23,17 +24,6 @@ using Tegra::Shader::OpCode; | ||||||
| 
 | 
 | ||||||
| namespace { | namespace { | ||||||
| 
 | 
 | ||||||
| /**
 |  | ||||||
|  * Returns whether the instruction at the specified offset is a 'sched' instruction. |  | ||||||
|  * Sched instructions always appear before a sequence of 3 instructions. |  | ||||||
|  */ |  | ||||||
| constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) { |  | ||||||
|     constexpr u32 SchedPeriod = 4; |  | ||||||
|     u32 absolute_offset = offset - main_offset; |  | ||||||
| 
 |  | ||||||
|     return (absolute_offset % SchedPeriod) == 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DeduceTextureHandlerSize(VideoCore::GuestDriverProfile& gpu_driver, | void DeduceTextureHandlerSize(VideoCore::GuestDriverProfile& gpu_driver, | ||||||
|                               const std::list<Sampler>& used_samplers) { |                               const std::list<Sampler>& used_samplers) { | ||||||
|     if (gpu_driver.IsTextureHandlerSizeKnown() || used_samplers.size() <= 1) { |     if (gpu_driver.IsTextureHandlerSizeKnown() || used_samplers.size() <= 1) { | ||||||
|  |  | ||||||
							
								
								
									
										77
									
								
								src/video_core/shader/memory_util.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/video_core/shader/memory_util.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | ||||||
|  | // Copyright 2020 yuzu Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include <cstddef> | ||||||
|  | 
 | ||||||
|  | #include <boost/container_hash/hash.hpp> | ||||||
|  | 
 | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "video_core/engines/maxwell_3d.h" | ||||||
|  | #include "video_core/memory_manager.h" | ||||||
|  | #include "video_core/shader/memory_util.h" | ||||||
|  | #include "video_core/shader/shader_ir.h" | ||||||
|  | 
 | ||||||
|  | namespace VideoCommon::Shader { | ||||||
|  | 
 | ||||||
|  | GPUVAddr GetShaderAddress(Core::System& system, | ||||||
|  |                           Tegra::Engines::Maxwell3D::Regs::ShaderProgram program) { | ||||||
|  |     const auto& gpu{system.GPU().Maxwell3D()}; | ||||||
|  |     const auto& shader_config{gpu.regs.shader_config[static_cast<std::size_t>(program)]}; | ||||||
|  |     return gpu.regs.code_address.CodeAddress() + shader_config.offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool IsSchedInstruction(std::size_t offset, std::size_t main_offset) { | ||||||
|  |     // Sched instructions appear once every 4 instructions.
 | ||||||
|  |     constexpr std::size_t SchedPeriod = 4; | ||||||
|  |     const std::size_t absolute_offset = offset - main_offset; | ||||||
|  |     return (absolute_offset % SchedPeriod) == 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::size_t CalculateProgramSize(const ProgramCode& program, bool is_compute) { | ||||||
|  |     // This is the encoded version of BRA that jumps to itself. All Nvidia
 | ||||||
|  |     // shaders end with one.
 | ||||||
|  |     static constexpr u64 SELF_JUMPING_BRANCH = 0xE2400FFFFF07000FULL; | ||||||
|  |     static constexpr u64 MASK = 0xFFFFFFFFFF7FFFFFULL; | ||||||
|  | 
 | ||||||
|  |     const std::size_t start_offset = is_compute ? KERNEL_MAIN_OFFSET : STAGE_MAIN_OFFSET; | ||||||
|  |     std::size_t offset = start_offset; | ||||||
|  |     while (offset < program.size()) { | ||||||
|  |         const u64 instruction = program[offset]; | ||||||
|  |         if (!IsSchedInstruction(offset, start_offset)) { | ||||||
|  |             if ((instruction & MASK) == SELF_JUMPING_BRANCH) { | ||||||
|  |                 // End on Maxwell's "nop" instruction
 | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             if (instruction == 0) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         ++offset; | ||||||
|  |     } | ||||||
|  |     // The last instruction is included in the program size
 | ||||||
|  |     return std::min(offset + 1, program.size()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, GPUVAddr gpu_addr, | ||||||
|  |                           const u8* host_ptr, bool is_compute) { | ||||||
|  |     ProgramCode code(VideoCommon::Shader::MAX_PROGRAM_LENGTH); | ||||||
|  |     ASSERT_OR_EXECUTE(host_ptr != nullptr, { return code; }); | ||||||
|  |     memory_manager.ReadBlockUnsafe(gpu_addr, code.data(), code.size() * sizeof(u64)); | ||||||
|  |     code.resize(CalculateProgramSize(code, is_compute)); | ||||||
|  |     return code; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | u64 GetUniqueIdentifier(Tegra::Engines::ShaderType shader_type, bool is_a, const ProgramCode& code, | ||||||
|  |                         const ProgramCode& code_b) { | ||||||
|  |     u64 unique_identifier = boost::hash_value(code); | ||||||
|  |     if (is_a) { | ||||||
|  |         // VertexA programs include two programs
 | ||||||
|  |         boost::hash_combine(unique_identifier, boost::hash_value(code_b)); | ||||||
|  |     } | ||||||
|  |     return unique_identifier; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace VideoCommon::Shader
 | ||||||
							
								
								
									
										47
									
								
								src/video_core/shader/memory_util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/video_core/shader/memory_util.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | ||||||
|  | // Copyright 2020 yuzu Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <cstddef> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | #include "common/common_types.h" | ||||||
|  | #include "video_core/engines/maxwell_3d.h" | ||||||
|  | #include "video_core/engines/shader_type.h" | ||||||
|  | 
 | ||||||
|  | namespace Core { | ||||||
|  | class System; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace Tegra { | ||||||
|  | class MemoryManager; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace VideoCommon::Shader { | ||||||
|  | 
 | ||||||
|  | using ProgramCode = std::vector<u64>; | ||||||
|  | 
 | ||||||
|  | constexpr u32 STAGE_MAIN_OFFSET = 10; | ||||||
|  | constexpr u32 KERNEL_MAIN_OFFSET = 0; | ||||||
|  | 
 | ||||||
|  | /// Gets the address for the specified shader stage program
 | ||||||
|  | GPUVAddr GetShaderAddress(Core::System& system, | ||||||
|  |                           Tegra::Engines::Maxwell3D::Regs::ShaderProgram program); | ||||||
|  | 
 | ||||||
|  | /// Gets if the current instruction offset is a scheduler instruction
 | ||||||
|  | bool IsSchedInstruction(std::size_t offset, std::size_t main_offset); | ||||||
|  | 
 | ||||||
|  | /// Calculates the size of a program stream
 | ||||||
|  | std::size_t CalculateProgramSize(const ProgramCode& program, bool is_compute); | ||||||
|  | 
 | ||||||
|  | /// Gets the shader program code from memory for the specified address
 | ||||||
|  | ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, GPUVAddr gpu_addr, | ||||||
|  |                           const u8* host_ptr, bool is_compute); | ||||||
|  | 
 | ||||||
|  | /// Hashes one (or two) program streams
 | ||||||
|  | u64 GetUniqueIdentifier(Tegra::Engines::ShaderType shader_type, bool is_a, const ProgramCode& code, | ||||||
|  |                         const ProgramCode& code_b = {}); | ||||||
|  | 
 | ||||||
|  | } // namespace VideoCommon::Shader
 | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| #include "video_core/engines/shader_header.h" | #include "video_core/engines/shader_header.h" | ||||||
| #include "video_core/shader/ast.h" | #include "video_core/shader/ast.h" | ||||||
| #include "video_core/shader/compiler_settings.h" | #include "video_core/shader/compiler_settings.h" | ||||||
|  | #include "video_core/shader/memory_util.h" | ||||||
| #include "video_core/shader/node.h" | #include "video_core/shader/node.h" | ||||||
| #include "video_core/shader/registry.h" | #include "video_core/shader/registry.h" | ||||||
| 
 | 
 | ||||||
|  | @ -25,8 +26,6 @@ namespace VideoCommon::Shader { | ||||||
| 
 | 
 | ||||||
| struct ShaderBlock; | struct ShaderBlock; | ||||||
| 
 | 
 | ||||||
| using ProgramCode = std::vector<u64>; |  | ||||||
| 
 |  | ||||||
| constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; | constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; | ||||||
| 
 | 
 | ||||||
| class ConstBuffer { | class ConstBuffer { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 ReinUsesLisp
						ReinUsesLisp