mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #3784 from ReinUsesLisp/shader-memory-util
shader/memory_util: Deduplicate code
This commit is contained in:
		
						commit
						72b73d22ab
					
				@ -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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -230,9 +182,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);
 | 
				
			||||||
@ -288,11 +240,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 {
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,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"
 | 
				
			||||||
@ -46,8 +47,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;
 | 
				
			||||||
    RenderPassParams renderpass_params;
 | 
					    RenderPassParams renderpass_params;
 | 
				
			||||||
@ -108,7 +107,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 {
 | 
				
			||||||
@ -140,7 +140,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…
	
		Reference in New Issue
	
	Block a user