Browse Source
shader/memory_util: Deduplicate code
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.pull/15/merge
9 changed files with 153 additions and 159 deletions
-
2src/video_core/CMakeLists.txt
-
82src/video_core/renderer_opengl/gl_shader_cache.cpp
-
69src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
-
8src/video_core/renderer_vulkan/vk_pipeline_cache.h
-
12src/video_core/shader/control_flow.cpp
-
12src/video_core/shader/decode.cpp
-
77src/video_core/shader/memory_util.cpp
-
47src/video_core/shader/memory_util.h
-
3src/video_core/shader/shader_ir.h
@ -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
|
|||
@ -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 |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue