diff options
Diffstat (limited to 'src/video_core/renderer_opengl/gl_shader_cache.cpp')
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 167 |
1 files changed, 90 insertions, 77 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index ac8a9e6b7..f9b2b03a0 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -103,15 +103,22 @@ constexpr std::tuple<const char*, const char*, u32> GetPrimitiveDescription(GLen /// Calculates the size of a program stream std::size_t CalculateProgramSize(const GLShader::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; std::size_t size = start_offset * sizeof(u64); while (offset < program.size()) { const u64 instruction = program[offset]; if (!IsSchedInstruction(offset, start_offset)) { - if (instruction == 0 || (instruction >> 52) == 0x50b) { + if ((instruction & mask) == self_jumping_branch) { // End on Maxwell's "nop" instruction break; } + if (instruction == 0) { + break; + } } size += sizeof(u64); offset++; @@ -168,8 +175,12 @@ GLShader::ProgramResult CreateProgram(const Device& device, Maxwell::ShaderProgr } CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEntries& entries, - Maxwell::ShaderProgram program_type, BaseBindings base_bindings, - GLenum primitive_mode, bool hint_retrievable = false) { + Maxwell::ShaderProgram program_type, const ProgramVariant& variant, + bool hint_retrievable = false) { + auto base_bindings{variant.base_bindings}; + const auto primitive_mode{variant.primitive_mode}; + const auto texture_buffer_usage{variant.texture_buffer_usage}; + std::string source = "#version 430 core\n" "#extension GL_ARB_separate_shader_objects : enable\n\n"; source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++); @@ -186,6 +197,18 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn source += fmt::format("#define SAMPLER_BINDING_{} {}\n", sampler.GetIndex(), base_bindings.sampler++); } + for (const auto& image : entries.images) { + source += + fmt::format("#define IMAGE_BINDING_{} {}\n", image.GetIndex(), base_bindings.image++); + } + + // Transform 1D textures to texture samplers by declaring its preprocessor macros. + for (std::size_t i = 0; i < texture_buffer_usage.size(); ++i) { + if (!texture_buffer_usage.test(i)) { + continue; + } + source += fmt::format("#define SAMPLER_{}_IS_BUFFER", i); + } if (program_type == Maxwell::ShaderProgram::Geometry) { const auto [glsl_topology, debug_name, max_vertices] = @@ -221,60 +244,51 @@ std::set<GLenum> GetSupportedFormats() { } // Anonymous namespace -CachedShader::CachedShader(const Device& device, VAddr cpu_addr, u64 unique_identifier, - Maxwell::ShaderProgram program_type, ShaderDiskCacheOpenGL& disk_cache, - const PrecompiledPrograms& precompiled_programs, - ProgramCode&& program_code, ProgramCode&& program_code_b, u8* host_ptr) - : RasterizerCacheObject{host_ptr}, host_ptr{host_ptr}, cpu_addr{cpu_addr}, - unique_identifier{unique_identifier}, program_type{program_type}, disk_cache{disk_cache}, - precompiled_programs{precompiled_programs} { - const std::size_t code_size{CalculateProgramSize(program_code)}; - const std::size_t code_size_b{program_code_b.empty() ? 0 - : CalculateProgramSize(program_code_b)}; - GLShader::ProgramResult program_result{ - CreateProgram(device, program_type, program_code, program_code_b)}; - if (program_result.first.empty()) { +CachedShader::CachedShader(const ShaderParameters& params, Maxwell::ShaderProgram 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}, + disk_cache{params.disk_cache}, precompiled_programs{params.precompiled_programs}, + entries{result.second}, code{std::move(result.first)}, shader_length{entries.shader_length} {} + +Shader CachedShader::CreateStageFromMemory(const ShaderParameters& params, + Maxwell::ShaderProgram program_type, + ProgramCode&& program_code, + 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)}; + if (result.first.empty()) { // TODO(Rodrigo): Unimplemented shader stages hit here, avoid using these for now - return; + return {}; } - code = program_result.first; - entries = program_result.second; - shader_length = entries.shader_length; + 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))); - const ShaderDiskCacheRaw raw(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)); - disk_cache.SaveRaw(raw); + return std::shared_ptr<CachedShader>(new CachedShader(params, program_type, std::move(result))); } -CachedShader::CachedShader(VAddr cpu_addr, u64 unique_identifier, - Maxwell::ShaderProgram program_type, ShaderDiskCacheOpenGL& disk_cache, - const PrecompiledPrograms& precompiled_programs, - GLShader::ProgramResult result, u8* host_ptr) - : RasterizerCacheObject{host_ptr}, cpu_addr{cpu_addr}, unique_identifier{unique_identifier}, - program_type{program_type}, disk_cache{disk_cache}, precompiled_programs{ - precompiled_programs} { - code = std::move(result.first); - entries = result.second; - shader_length = entries.shader_length; +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))); } -std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive_mode, - BaseBindings base_bindings) { +std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(const ProgramVariant& variant) { GLuint handle{}; if (program_type == Maxwell::ShaderProgram::Geometry) { - handle = GetGeometryShader(primitive_mode, base_bindings); + handle = GetGeometryShader(variant); } else { - const auto [entry, is_cache_miss] = programs.try_emplace(base_bindings); + const auto [entry, is_cache_miss] = programs.try_emplace(variant); auto& program = entry->second; if (is_cache_miss) { - program = TryLoadProgram(primitive_mode, base_bindings); + program = TryLoadProgram(variant); if (!program) { - program = - SpecializeShader(code, entries, program_type, base_bindings, primitive_mode); - disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings)); + program = SpecializeShader(code, entries, program_type, variant); + disk_cache.SaveUsage(GetUsage(variant)); } LabelGLObject(GL_PROGRAM, program->handle, cpu_addr); @@ -283,6 +297,7 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive handle = program->handle; } + auto base_bindings{variant.base_bindings}; base_bindings.cbuf += static_cast<u32>(entries.const_buffers.size()) + RESERVED_UBOS; base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size()); base_bindings.sampler += static_cast<u32>(entries.samplers.size()); @@ -290,43 +305,42 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetProgramHandle(GLenum primitive return {handle, base_bindings}; } -GLuint CachedShader::GetGeometryShader(GLenum primitive_mode, BaseBindings base_bindings) { - const auto [entry, is_cache_miss] = geometry_programs.try_emplace(base_bindings); +GLuint CachedShader::GetGeometryShader(const ProgramVariant& variant) { + const auto [entry, is_cache_miss] = geometry_programs.try_emplace(variant); auto& programs = entry->second; - switch (primitive_mode) { + switch (variant.primitive_mode) { case GL_POINTS: - return LazyGeometryProgram(programs.points, base_bindings, primitive_mode); + return LazyGeometryProgram(programs.points, variant); case GL_LINES: case GL_LINE_STRIP: - return LazyGeometryProgram(programs.lines, base_bindings, primitive_mode); + return LazyGeometryProgram(programs.lines, variant); case GL_LINES_ADJACENCY: case GL_LINE_STRIP_ADJACENCY: - return LazyGeometryProgram(programs.lines_adjacency, base_bindings, primitive_mode); + return LazyGeometryProgram(programs.lines_adjacency, variant); case GL_TRIANGLES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: - return LazyGeometryProgram(programs.triangles, base_bindings, primitive_mode); + return LazyGeometryProgram(programs.triangles, variant); case GL_TRIANGLES_ADJACENCY: case GL_TRIANGLE_STRIP_ADJACENCY: - return LazyGeometryProgram(programs.triangles_adjacency, base_bindings, primitive_mode); + return LazyGeometryProgram(programs.triangles_adjacency, variant); default: UNREACHABLE_MSG("Unknown primitive mode."); - return LazyGeometryProgram(programs.points, base_bindings, primitive_mode); + return LazyGeometryProgram(programs.points, variant); } } -GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBindings base_bindings, - GLenum primitive_mode) { +GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, + const ProgramVariant& variant) { if (target_program) { return target_program->handle; } - const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(primitive_mode); - target_program = TryLoadProgram(primitive_mode, base_bindings); + const auto [glsl_name, debug_name, vertices] = GetPrimitiveDescription(variant.primitive_mode); + target_program = TryLoadProgram(variant); if (!target_program) { - target_program = - SpecializeShader(code, entries, program_type, base_bindings, primitive_mode); - disk_cache.SaveUsage(GetUsage(primitive_mode, base_bindings)); + target_program = SpecializeShader(code, entries, program_type, variant); + disk_cache.SaveUsage(GetUsage(variant)); } LabelGLObject(GL_PROGRAM, target_program->handle, cpu_addr, debug_name); @@ -334,18 +348,19 @@ GLuint CachedShader::LazyGeometryProgram(CachedProgram& target_program, BaseBind return target_program->handle; }; -CachedProgram CachedShader::TryLoadProgram(GLenum primitive_mode, - BaseBindings base_bindings) const { - const auto found = precompiled_programs.find(GetUsage(primitive_mode, base_bindings)); +CachedProgram CachedShader::TryLoadProgram(const ProgramVariant& variant) const { + const auto found = precompiled_programs.find(GetUsage(variant)); if (found == precompiled_programs.end()) { return {}; } return found->second; } -ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode, - BaseBindings base_bindings) const { - return {unique_identifier, base_bindings, primitive_mode}; +ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant) const { + ShaderDiskCacheUsage usage; + usage.unique_identifier = unique_identifier; + usage.variant = variant; + return usage; } ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system, @@ -411,8 +426,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading, } if (!shader) { shader = SpecializeShader(unspecialized.code, unspecialized.entries, - unspecialized.program_type, usage.bindings, - usage.primitive, true); + unspecialized.program_type, usage.variant, true); } std::scoped_lock lock(mutex); @@ -570,18 +584,17 @@ Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) { memory_manager.GetPointer(program_addr_b)); } - const u64 unique_identifier = GetUniqueIdentifier(program, program_code, program_code_b); - const VAddr cpu_addr{*memory_manager.GpuToCpuAddress(program_addr)}; + const auto unique_identifier = GetUniqueIdentifier(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}; + const auto found = precompiled_shaders.find(unique_identifier); - if (found != precompiled_shaders.end()) { - // Create a shader from the cache - shader = std::make_shared<CachedShader>(cpu_addr, unique_identifier, program, disk_cache, - precompiled_programs, found->second, host_ptr); + if (found == precompiled_shaders.end()) { + shader = CachedShader::CreateStageFromMemory(params, program, std::move(program_code), + std::move(program_code_b)); } else { - // Create a shader from guest memory - shader = std::make_shared<CachedShader>( - device, cpu_addr, unique_identifier, program, disk_cache, precompiled_programs, - std::move(program_code), std::move(program_code_b), host_ptr); + shader = CachedShader::CreateStageFromCache(params, program, found->second); } Register(shader); |