diff options
Diffstat (limited to '')
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 150 |
1 files changed, 117 insertions, 33 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 456ba0403..1c90facc3 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -23,13 +23,13 @@ namespace OpenGL { using VideoCommon::Shader::ProgramCode; -// One UBO is always reserved for emulation values -constexpr u32 RESERVED_UBOS = 1; +// One UBO is always reserved for emulation values on staged shaders +constexpr u32 STAGE_RESERVED_UBOS = 1; struct UnspecializedShader { std::string code; GLShader::ShaderEntries entries; - Maxwell::ShaderProgram program_type; + ProgramType program_type; }; namespace { @@ -55,15 +55,17 @@ ProgramCode GetShaderCode(Tegra::MemoryManager& memory_manager, const GPUVAddr g } /// Gets the shader type from a Maxwell program type -constexpr GLenum GetShaderType(Maxwell::ShaderProgram program_type) { +constexpr GLenum GetShaderType(ProgramType program_type) { switch (program_type) { - case Maxwell::ShaderProgram::VertexA: - case Maxwell::ShaderProgram::VertexB: + case ProgramType::VertexA: + case ProgramType::VertexB: return GL_VERTEX_SHADER; - case Maxwell::ShaderProgram::Geometry: + case ProgramType::Geometry: return GL_GEOMETRY_SHADER; - case Maxwell::ShaderProgram::Fragment: + case ProgramType::Fragment: return GL_FRAGMENT_SHADER; + case ProgramType::Compute: + return GL_COMPUTE_SHADER; default: return GL_NONE; } @@ -100,6 +102,25 @@ constexpr std::tuple<const char*, const char*, u32> GetPrimitiveDescription(GLen } } +ProgramType GetProgramType(Maxwell::ShaderProgram program) { + switch (program) { + case Maxwell::ShaderProgram::VertexA: + return ProgramType::VertexA; + case Maxwell::ShaderProgram::VertexB: + return ProgramType::VertexB; + case Maxwell::ShaderProgram::TesselationControl: + return ProgramType::TessellationControl; + case Maxwell::ShaderProgram::TesselationEval: + return ProgramType::TessellationEval; + case Maxwell::ShaderProgram::Geometry: + return ProgramType::Geometry; + case Maxwell::ShaderProgram::Fragment: + return ProgramType::Fragment; + } + UNREACHABLE(); + return {}; +} + /// Calculates the size of a program stream std::size_t CalculateProgramSize(const GLShader::ProgramCode& program) { constexpr std::size_t start_offset = 10; @@ -128,13 +149,13 @@ std::size_t CalculateProgramSize(const GLShader::ProgramCode& program) { } /// Hashes one (or two) program streams -u64 GetUniqueIdentifier(Maxwell::ShaderProgram program_type, const ProgramCode& code, +u64 GetUniqueIdentifier(ProgramType program_type, const ProgramCode& code, const ProgramCode& code_b, std::size_t size_a = 0, std::size_t size_b = 0) { if (size_a == 0) { size_a = CalculateProgramSize(code); } u64 unique_identifier = Common::CityHash64(reinterpret_cast<const char*>(code.data()), size_a); - if (program_type != Maxwell::ShaderProgram::VertexA) { + if (program_type != ProgramType::VertexA) { return unique_identifier; } // VertexA programs include two programs @@ -152,12 +173,12 @@ u64 GetUniqueIdentifier(Maxwell::ShaderProgram program_type, const ProgramCode& } /// Creates an unspecialized program from code streams -GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgram program_type, +GLShader::ProgramResult CreateProgram(const Device& device, ProgramType program_type, ProgramCode program_code, ProgramCode program_code_b) { GLShader::ShaderSetup setup(program_code); setup.program.size_a = CalculateProgramSize(program_code); setup.program.size_b = 0; - if (program_type == Maxwell::ShaderProgram::VertexA) { + if (program_type == ProgramType::VertexA) { // VertexB is always enabled, so when VertexA is enabled, we have two vertex shaders. // Conventional HW does not support this, so we combine VertexA and VertexB into one // stage here. @@ -168,22 +189,23 @@ GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgr program_type, program_code, program_code_b, setup.program.size_a, setup.program.size_b); switch (program_type) { - case Maxwell::ShaderProgram::VertexA: - case Maxwell::ShaderProgram::VertexB: + case ProgramType::VertexA: + case ProgramType::VertexB: return GLShader::GenerateVertexShader(device, setup); - case Maxwell::ShaderProgram::Geometry: + case ProgramType::Geometry: return GLShader::GenerateGeometryShader(device, setup); - case Maxwell::ShaderProgram::Fragment: + case ProgramType::Fragment: return GLShader::GenerateFragmentShader(device, setup); + case ProgramType::Compute: + return GLShader::GenerateComputeShader(device, setup); default: - LOG_CRITICAL(HW_GPU, "Unimplemented program_type={}", static_cast<u32>(program_type)); - UNREACHABLE(); + UNIMPLEMENTED_MSG("Unimplemented program_type={}", static_cast<u32>(program_type)); return {}; } } CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries, - Maxwell::ShaderProgram program_type, const ProgramVariant& variant, + ProgramType program_type, const ProgramVariant& variant, bool hint_retrievable = false) { auto base_bindings{variant.base_bindings}; const auto primitive_mode{variant.primitive_mode}; @@ -194,7 +216,14 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn if (entries.shader_viewport_layer_array) { source += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; } - source += fmt::format("\n#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); + if (program_type == ProgramType::Compute) { + source += "#extension GL_ARB_compute_variable_group_size : require\n"; + } + source += '\n'; + + if (program_type != ProgramType::Compute) { + source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); + } for (const auto& cbuf : entries.const_buffers) { source += @@ -221,13 +250,16 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn source += fmt::format("#define SAMPLER_{}_IS_BUFFER", i); } - if (program_type == Maxwell::ShaderProgram::Geometry) { + if (program_type == ProgramType::Geometry) { const auto [glsl_topology, debug_name, max_vertices] = GetPrimitiveDescription(primitive_mode); source += "layout (" + std::string(glsl_topology) + ") in;\n"; source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n'; } + if (program_type == ProgramType::Compute) { + source += "layout (local_size_variable) in;\n"; + } source += code; @@ -255,7 +287,7 @@ std::set<GLenum> GetSupportedFormats() { } // Anonymous namespace -CachedShader::CachedShader(const ShaderParameters& params, Maxwell::ShaderProgram program_type, +CachedShader::CachedShader(const ShaderParameters& params, ProgramType program_type, GLShader::ProgramResult result) : RasterizerCacheObject{params.host_ptr}, host_ptr{params.host_ptr}, cpu_addr{params.cpu_addr}, unique_identifier{params.unique_identifier}, program_type{program_type}, @@ -268,29 +300,50 @@ Shader CachedShader::CreateStageFromMemory(const ShaderParameters& params, ProgramCode&& program_code_b) { const auto code_size{CalculateProgramSize(program_code)}; const auto code_size_b{CalculateProgramSize(program_code_b)}; - auto result{CreateProgram(params.device, program_type, program_code, program_code_b)}; + auto result{ + CreateProgram(params.device, GetProgramType(program_type), program_code, program_code_b)}; if (result.first.empty()) { // TODO(Rodrigo): Unimplemented shader stages hit here, avoid using these for now return {}; } params.disk_cache.SaveRaw(ShaderDiskCacheRaw( - params.unique_identifier, program_type, static_cast<u32>(code_size / sizeof(u64)), - static_cast<u32>(code_size_b / sizeof(u64)), std::move(program_code), - std::move(program_code_b))); + params.unique_identifier, GetProgramType(program_type), + static_cast<u32>(code_size / sizeof(u64)), static_cast<u32>(code_size_b / sizeof(u64)), + std::move(program_code), std::move(program_code_b))); - return std::shared_ptr<CachedShader>(new CachedShader(params, program_type, std::move(result))); + return std::shared_ptr<CachedShader>( + new CachedShader(params, GetProgramType(program_type), std::move(result))); } Shader CachedShader::CreateStageFromCache(const ShaderParameters& params, Maxwell::ShaderProgram program_type, GLShader::ProgramResult result) { - return std::shared_ptr<CachedShader>(new CachedShader(params, program_type, std::move(result))); + return std::shared_ptr<CachedShader>( + new CachedShader(params, GetProgramType(program_type), std::move(result))); +} + +Shader CachedShader::CreateKernelFromMemory(const ShaderParameters& params, ProgramCode&& code) { + auto result{CreateProgram(params.device, ProgramType::Compute, code, {})}; + + const auto code_size{CalculateProgramSize(code)}; + params.disk_cache.SaveRaw(ShaderDiskCacheRaw(params.unique_identifier, ProgramType::Compute, + static_cast<u32>(code_size / sizeof(u64)), 0, + std::move(code), {})); + + return std::shared_ptr<CachedShader>( + new CachedShader(params, ProgramType::Compute, std::move(result))); +} + +Shader CachedShader::CreateKernelFromCache(const ShaderParameters& params, + GLShader::ProgramResult result) { + return std::shared_ptr<CachedShader>( + new CachedShader(params, ProgramType::Compute, std::move(result))); } std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) { GLuint handle{}; - if (program_type == Maxwell::ShaderProgram::Geometry) { + if (program_type == ProgramType::Geometry) { handle = GetGeometryShader(variant); } else { const auto [entry, is_cache_miss] = programs.try_emplace(variant); @@ -308,8 +361,11 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVar handle = program->handle; } - auto base_bindings{variant.base_bindings}; - base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + RESERVED_UBOS; + auto base_bindings = variant.base_bindings; + base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()); + if (program_type != ProgramType::Compute) { + base_bindings.cbuf += STAGE_RESERVED_UBOS; + } base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size()); base_bindings.sampler += static_cast<u32>(entries.samplers.size()); @@ -589,13 +645,15 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { // No shader found - create a new one ProgramCode program_code{GetShaderCode(memory_manager, program_addr, host_ptr)}; ProgramCode program_code_b; - if (program == Maxwell::ShaderProgram::VertexA) { + const bool is_program_a{program == Maxwell::ShaderProgram::VertexA}; + if (is_program_a) { const GPUVAddr program_addr_b{GetShaderAddress(system, Maxwell::ShaderProgram::VertexB)}; program_code_b = GetShaderCode(memory_manager, program_addr_b, memory_manager.GetPointer(program_addr_b)); } - const auto unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b); + const auto unique_identifier = + GetUniqueIdentifier(GetProgramType(program), program_code, program_code_b); const auto cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)}; const ShaderParameters params{disk_cache, precompiled_programs, device, cpu_addr, host_ptr, unique_identifier}; @@ -612,4 +670,30 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { return last_shaders[static_cast<std::size_t>(program)] = shader; } +Shader ShaderCacheOpenGL::GetComputeKernel(GPUVAddr code_addr) { + auto& memory_manager{system.GPU().MemoryManager()}; + const auto host_ptr{memory_manager.GetPointer(code_addr)}; + auto kernel = TryGet(host_ptr); + if (kernel) { + return kernel; + } + + // No kernel found - create a new one + auto code{GetShaderCode(memory_manager, code_addr, host_ptr)}; + const auto unique_identifier{GetUniqueIdentifier(ProgramType::Compute, code, {})}; + const auto cpu_addr{*memory_manager.GpuToCpuAddress(code_addr)}; + const ShaderParameters params{disk_cache, precompiled_programs, device, cpu_addr, + host_ptr, unique_identifier}; + + const auto found = precompiled_shaders.find(unique_identifier); + if (found == precompiled_shaders.end()) { + kernel = CachedShader::CreateKernelFromMemory(params, std::move(code)); + } else { + kernel = CachedShader::CreateKernelFromCache(params, found->second); + } + + Register(kernel); + return kernel; +} + } // namespace OpenGL |