diff options
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r-- | src/video_core/renderer_opengl/gl_device.cpp | 22 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_device.h | 5 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_cache.cpp | 16 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 446 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.h | 1 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | 50 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_disk_cache.h | 5 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 16 |
8 files changed, 375 insertions, 186 deletions
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 4f59a87b4..64de7e425 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -2,8 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <algorithm> #include <array> #include <cstddef> +#include <vector> #include <glad/glad.h> #include "common/logging/log.h" @@ -30,9 +32,27 @@ bool TestProgram(const GLchar* glsl) { return link_status == GL_TRUE; } +std::vector<std::string_view> GetExtensions() { + GLint num_extensions; + glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions); + std::vector<std::string_view> extensions; + extensions.reserve(num_extensions); + for (GLint index = 0; index < num_extensions; ++index) { + extensions.push_back( + reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, static_cast<GLuint>(index)))); + } + return extensions; +} + +bool HasExtension(const std::vector<std::string_view>& images, std::string_view extension) { + return std::find(images.begin(), images.end(), extension) != images.end(); +} + } // Anonymous namespace Device::Device() { + const std::vector extensions = GetExtensions(); + uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT); max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); @@ -40,6 +60,7 @@ Device::Device() { has_warp_intrinsics = GLAD_GL_NV_gpu_shader5 && GLAD_GL_NV_shader_thread_group && GLAD_GL_NV_shader_thread_shuffle; has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array; + has_image_load_formatted = HasExtension(extensions, "GL_EXT_shader_image_load_formatted"); has_variable_aoffi = TestVariableAoffi(); has_component_indexing_bug = TestComponentIndexingBug(); has_precise_bug = TestPreciseBug(); @@ -55,6 +76,7 @@ Device::Device(std::nullptr_t) { max_varyings = 15; has_warp_intrinsics = true; has_vertex_viewport_layer = true; + has_image_load_formatted = true; has_variable_aoffi = true; has_component_indexing_bug = false; has_precise_bug = false; diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index ba6dcd3be..bb273c3d6 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h @@ -38,6 +38,10 @@ public: return has_vertex_viewport_layer; } + bool HasImageLoadFormatted() const { + return has_image_load_formatted; + } + bool HasVariableAoffi() const { return has_variable_aoffi; } @@ -61,6 +65,7 @@ private: u32 max_varyings{}; bool has_warp_intrinsics{}; bool has_vertex_viewport_layer{}; + bool has_image_load_formatted{}; bool has_variable_aoffi{}; bool has_component_indexing_bug{}; bool has_precise_bug{}; diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index 0dbc4c02f..42ca3b1bd 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp @@ -211,14 +211,14 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn 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" - "#extension GL_NV_gpu_shader5 : enable\n" - "#extension GL_NV_shader_thread_group : enable\n" - "#extension GL_NV_shader_thread_shuffle : enable\n"; - if (entries.shader_viewport_layer_array) { - source += "#extension GL_ARB_shader_viewport_layer_array : enable\n"; - } + std::string source = R"(#version 430 core +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shader_viewport_layer_array : enable +#extension GL_EXT_shader_image_load_formatted : enable +#extension GL_NV_gpu_shader5 : enable +#extension GL_NV_shader_thread_group : enable +#extension GL_NV_shader_thread_shuffle : enable +)"; if (program_type == ProgramType::Compute) { source += "#extension GL_ARB_compute_variable_group_size : require\n"; } diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 74cb59bc1..6a610a3bc 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -19,6 +19,8 @@ #include "video_core/renderer_opengl/gl_device.h" #include "video_core/renderer_opengl/gl_rasterizer.h" #include "video_core/renderer_opengl/gl_shader_decompiler.h" +#include "video_core/shader/ast.h" +#include "video_core/shader/node.h" #include "video_core/shader/shader_ir.h" namespace OpenGL::GLShader { @@ -241,6 +243,26 @@ constexpr const char* GetTypeString(Type type) { } } +constexpr const char* GetImageTypeDeclaration(Tegra::Shader::ImageType image_type) { + switch (image_type) { + case Tegra::Shader::ImageType::Texture1D: + return "1D"; + case Tegra::Shader::ImageType::TextureBuffer: + return "Buffer"; + case Tegra::Shader::ImageType::Texture1DArray: + return "1DArray"; + case Tegra::Shader::ImageType::Texture2D: + return "2D"; + case Tegra::Shader::ImageType::Texture2DArray: + return "2DArray"; + case Tegra::Shader::ImageType::Texture3D: + return "3D"; + default: + UNREACHABLE(); + return "1D"; + } +} + /// Generates code to use for a swizzle operation. constexpr const char* GetSwizzle(u32 element) { constexpr std::array swizzle = {".x", ".y", ".z", ".w"}; @@ -313,39 +335,24 @@ constexpr bool IsVertexShader(ProgramType stage) { return stage == ProgramType::VertexA || stage == ProgramType::VertexB; } +class ASTDecompiler; +class ExprDecompiler; + class GLSLDecompiler final { public: explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ProgramType stage, std::string suffix) : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} - void Decompile() { - DeclareVertex(); - DeclareGeometry(); - DeclareRegisters(); - DeclarePredicates(); - DeclareLocalMemory(); - DeclareSharedMemory(); - DeclareInternalFlags(); - DeclareInputAttributes(); - DeclareOutputAttributes(); - DeclareConstantBuffers(); - DeclareGlobalMemory(); - DeclareSamplers(); - DeclarePhysicalAttributeReader(); - DeclareImages(); - - code.AddLine("void execute_{}() {{", suffix); - ++code.scope; - + void DecompileBranchMode() { // VM's program counter const auto first_address = ir.GetBasicBlocks().begin()->first; code.AddLine("uint jmp_to = {}U;", first_address); // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems // unlikely that shaders will use 20 nested SSYs and PBKs. + constexpr u32 FLOW_STACK_SIZE = 20; if (!ir.IsFlowStackDisabled()) { - constexpr u32 FLOW_STACK_SIZE = 20; for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); code.AddLine("uint {} = 0U;", FlowStackTopName(stack)); @@ -371,10 +378,37 @@ public: code.AddLine("default: return;"); code.AddLine("}}"); - for (std::size_t i = 0; i < 2; ++i) { - --code.scope; - code.AddLine("}}"); + --code.scope; + code.AddLine("}}"); + } + + void DecompileAST(); + + void Decompile() { + DeclareVertex(); + DeclareGeometry(); + DeclareRegisters(); + DeclarePredicates(); + DeclareLocalMemory(); + DeclareInternalFlags(); + DeclareInputAttributes(); + DeclareOutputAttributes(); + DeclareConstantBuffers(); + DeclareGlobalMemory(); + DeclareSamplers(); + DeclarePhysicalAttributeReader(); + + code.AddLine("void execute_{}() {{", suffix); + ++code.scope; + + if (ir.IsDecompiled()) { + DecompileAST(); + } else { + DecompileBranchMode(); } + + --code.scope; + code.AddLine("}}"); } std::string GetResult() { @@ -398,13 +432,14 @@ public: usage.is_read, usage.is_written); } entries.clip_distances = ir.GetClipDistances(); - entries.shader_viewport_layer_array = - IsVertexShader(stage) && (ir.UsesLayer() || ir.UsesViewportIndex()); entries.shader_length = ir.GetLength(); return entries; } private: + friend class ASTDecompiler; + friend class ExprDecompiler; + void DeclareVertex() { if (!IsVertexShader(stage)) return; @@ -722,42 +757,6 @@ private: void DeclareImages() { const auto& images{ir.GetImages()}; for (const auto& [offset, image] : images) { - const char* image_type = [&] { - switch (image.GetType()) { - case Tegra::Shader::ImageType::Texture1D: - return "image1D"; - case Tegra::Shader::ImageType::TextureBuffer: - return "imageBuffer"; - case Tegra::Shader::ImageType::Texture1DArray: - return "image1DArray"; - case Tegra::Shader::ImageType::Texture2D: - return "image2D"; - case Tegra::Shader::ImageType::Texture2DArray: - return "image2DArray"; - case Tegra::Shader::ImageType::Texture3D: - return "image3D"; - default: - UNREACHABLE(); - return "image1D"; - } - }(); - - const auto [type_prefix, format] = [&]() -> std::pair<const char*, const char*> { - if (!image.IsSizeKnown()) { - return {"", ""}; - } - switch (image.GetSize()) { - case Tegra::Shader::ImageAtomicSize::U32: - return {"u", "r32ui, "}; - case Tegra::Shader::ImageAtomicSize::S32: - return {"i", "r32i, "}; - default: - UNIMPLEMENTED_MSG("Unimplemented atomic size={}", - static_cast<u32>(image.GetSize())); - return {"", ""}; - } - }(); - std::string qualifier = "coherent volatile"; if (image.IsRead() && !image.IsWritten()) { qualifier += " readonly"; @@ -765,9 +764,10 @@ private: qualifier += " writeonly"; } - code.AddLine("layout (binding = IMAGE_BINDING_{}) {} uniform " - "{} {};", - image.GetIndex(), qualifier, image_type, GetImage(image)); + const char* format = image.IsAtomic() ? "r32ui, " : ""; + const char* type_declaration = GetImageTypeDeclaration(image.GetType()); + code.AddLine("layout ({}binding = IMAGE_BINDING_{}) {} uniform uimage{} {};", format, + image.GetIndex(), qualifier, type_declaration, GetImage(image)); } if (!images.empty()) { code.AddNewLine(); @@ -1234,28 +1234,13 @@ private: } std::string BuildImageValues(Operation operation) { + constexpr std::array constructors{"uint", "uvec2", "uvec3", "uvec4"}; const auto meta{std::get<MetaImage>(operation.GetMeta())}; - const auto [constructors, type] = [&]() -> std::pair<std::array<const char*, 4>, Type> { - constexpr std::array float_constructors{"float", "vec2", "vec3", "vec4"}; - if (!meta.image.IsSizeKnown()) { - return {float_constructors, Type::Float}; - } - switch (meta.image.GetSize()) { - case Tegra::Shader::ImageAtomicSize::U32: - return {{"uint", "uvec2", "uvec3", "uvec4"}, Type::Uint}; - case Tegra::Shader::ImageAtomicSize::S32: - return {{"int", "ivec2", "ivec3", "ivec4"}, Type::Uint}; - default: - UNIMPLEMENTED_MSG("Unimplemented image size={}", - static_cast<u32>(meta.image.GetSize())); - return {float_constructors, Type::Float}; - } - }(); const std::size_t values_count{meta.values.size()}; std::string expr = fmt::format("{}(", constructors.at(values_count - 1)); for (std::size_t i = 0; i < values_count; ++i) { - expr += Visit(meta.values.at(i)).As(type); + expr += Visit(meta.values.at(i)).AsUint(); if (i + 1 < values_count) { expr += ", "; } @@ -1264,29 +1249,6 @@ private: return expr; } - Expression AtomicImage(Operation operation, const char* opname) { - constexpr std::array constructors{"int(", "ivec2(", "ivec3(", "ivec4("}; - const auto meta{std::get<MetaImage>(operation.GetMeta())}; - ASSERT(meta.values.size() == 1); - ASSERT(meta.image.IsSizeKnown()); - - const auto type = [&]() { - switch (const auto size = meta.image.GetSize()) { - case Tegra::Shader::ImageAtomicSize::U32: - return Type::Uint; - case Tegra::Shader::ImageAtomicSize::S32: - return Type::Int; - default: - UNIMPLEMENTED_MSG("Unimplemented image size={}", static_cast<u32>(size)); - return Type::Uint; - } - }(); - - return {fmt::format("{}({}, {}, {})", opname, GetImage(meta.image), - BuildIntegerCoordinates(operation), Visit(meta.values[0]).As(type)), - type}; - } - Expression Assign(Operation operation) { const Node& dest = operation[0]; const Node& src = operation[1]; @@ -1545,6 +1507,8 @@ private: case Tegra::Shader::HalfType::H1_H1: return {fmt::format("vec2({}[1])", operand.AsHalfFloat()), Type::HalfFloat}; } + UNREACHABLE(); + return {"0", Type::Int}; } Expression HMergeF32(Operation operation) { @@ -1809,6 +1773,19 @@ private: return {tmp, Type::Float}; } + Expression ImageLoad(Operation operation) { + if (!device.HasImageLoadFormatted()) { + LOG_ERROR(Render_OpenGL, + "Device lacks GL_EXT_shader_image_load_formatted, stubbing image load"); + return {"0", Type::Int}; + } + + const auto meta{std::get<MetaImage>(operation.GetMeta())}; + return {fmt::format("imageLoad({}, {}){}", GetImage(meta.image), + BuildIntegerCoordinates(operation), GetSwizzle(meta.element)), + Type::Uint}; + } + Expression ImageStore(Operation operation) { const auto meta{std::get<MetaImage>(operation.GetMeta())}; code.AddLine("imageStore({}, {}, {});", GetImage(meta.image), @@ -1816,31 +1793,14 @@ private: return {}; } - Expression AtomicImageAdd(Operation operation) { - return AtomicImage(operation, "imageAtomicAdd"); - } - - Expression AtomicImageMin(Operation operation) { - return AtomicImage(operation, "imageAtomicMin"); - } - - Expression AtomicImageMax(Operation operation) { - return AtomicImage(operation, "imageAtomicMax"); - } - Expression AtomicImageAnd(Operation operation) { - return AtomicImage(operation, "imageAtomicAnd"); - } - - Expression AtomicImageOr(Operation operation) { - return AtomicImage(operation, "imageAtomicOr"); - } - - Expression AtomicImageXor(Operation operation) { - return AtomicImage(operation, "imageAtomicXor"); - } + template <const std::string_view& opname> + Expression AtomicImage(Operation operation) { + const auto meta{std::get<MetaImage>(operation.GetMeta())}; + ASSERT(meta.values.size() == 1); - Expression AtomicImageExchange(Operation operation) { - return AtomicImage(operation, "imageAtomicExchange"); + return {fmt::format("imageAtomic{}({}, {}, {})", opname, GetImage(meta.image), + BuildIntegerCoordinates(operation), Visit(meta.values[0]).AsUint()), + Type::Uint}; } Expression Branch(Operation operation) { @@ -1877,10 +1837,9 @@ private: return {}; } - Expression Exit(Operation operation) { + void PreExit() { if (stage != ProgramType::Fragment) { - code.AddLine("return;"); - return {}; + return; } const auto& used_registers = ir.GetRegisters(); const auto SafeGetRegister = [&](u32 reg) -> Expression { @@ -1912,7 +1871,10 @@ private: // already contains one past the last color register. code.AddLine("gl_FragDepth = {};", SafeGetRegister(current_reg + 1).AsFloat()); } + } + Expression Exit(Operation operation) { + PreExit(); code.AddLine("return;"); return {}; } @@ -2035,6 +1997,12 @@ private: Func() = delete; ~Func() = delete; + static constexpr std::string_view Add = "Add"; + static constexpr std::string_view And = "And"; + static constexpr std::string_view Or = "Or"; + static constexpr std::string_view Xor = "Xor"; + static constexpr std::string_view Exchange = "Exchange"; + static constexpr std::string_view ShuffleIndexed = "shuffleNV"; static constexpr std::string_view ShuffleUp = "shuffleUpNV"; static constexpr std::string_view ShuffleDown = "shuffleDownNV"; @@ -2172,14 +2140,14 @@ private: &GLSLDecompiler::TextureQueryLod, &GLSLDecompiler::TexelFetch, + &GLSLDecompiler::ImageLoad, &GLSLDecompiler::ImageStore, - &GLSLDecompiler::AtomicImageAdd, - &GLSLDecompiler::AtomicImageMin, - &GLSLDecompiler::AtomicImageMax, - &GLSLDecompiler::AtomicImageAnd, - &GLSLDecompiler::AtomicImageOr, - &GLSLDecompiler::AtomicImageXor, - &GLSLDecompiler::AtomicImageExchange, + + &GLSLDecompiler::AtomicImage<Func::Add>, + &GLSLDecompiler::AtomicImage<Func::And>, + &GLSLDecompiler::AtomicImage<Func::Or>, + &GLSLDecompiler::AtomicImage<Func::Xor>, + &GLSLDecompiler::AtomicImage<Func::Exchange>, &GLSLDecompiler::Branch, &GLSLDecompiler::BranchIndirect, @@ -2303,6 +2271,208 @@ private: ShaderWriter code; }; +static constexpr std::string_view flow_var = "flow_var_"; + +std::string GetFlowVariable(u32 i) { + return fmt::format("{}{}", flow_var, i); +} + +class ExprDecompiler { +public: + explicit ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} + + void operator()(VideoCommon::Shader::ExprAnd& expr) { + inner += "( "; + std::visit(*this, *expr.operand1); + inner += " && "; + std::visit(*this, *expr.operand2); + inner += ')'; + } + + void operator()(VideoCommon::Shader::ExprOr& expr) { + inner += "( "; + std::visit(*this, *expr.operand1); + inner += " || "; + std::visit(*this, *expr.operand2); + inner += ')'; + } + + void operator()(VideoCommon::Shader::ExprNot& expr) { + inner += '!'; + std::visit(*this, *expr.operand1); + } + + void operator()(VideoCommon::Shader::ExprPredicate& expr) { + const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate); + inner += decomp.GetPredicate(pred); + } + + void operator()(VideoCommon::Shader::ExprCondCode& expr) { + const Node cc = decomp.ir.GetConditionCode(expr.cc); + std::string target; + + if (const auto pred = std::get_if<PredicateNode>(&*cc)) { + const auto index = pred->GetIndex(); + switch (index) { + case Tegra::Shader::Pred::NeverExecute: + target = "false"; + case Tegra::Shader::Pred::UnusedIndex: + target = "true"; + default: + target = decomp.GetPredicate(index); + } + } else if (const auto flag = std::get_if<InternalFlagNode>(&*cc)) { + target = decomp.GetInternalFlag(flag->GetFlag()); + } else { + UNREACHABLE(); + } + inner += target; + } + + void operator()(VideoCommon::Shader::ExprVar& expr) { + inner += GetFlowVariable(expr.var_index); + } + + void operator()(VideoCommon::Shader::ExprBoolean& expr) { + inner += expr.value ? "true" : "false"; + } + + std::string& GetResult() { + return inner; + } + +private: + std::string inner; + GLSLDecompiler& decomp; +}; + +class ASTDecompiler { +public: + explicit ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} + + void operator()(VideoCommon::Shader::ASTProgram& ast) { + ASTNode current = ast.nodes.GetFirst(); + while (current) { + Visit(current); + current = current->GetNext(); + } + } + + void operator()(VideoCommon::Shader::ASTIfThen& ast) { + ExprDecompiler expr_parser{decomp}; + std::visit(expr_parser, *ast.condition); + decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); + decomp.code.scope++; + ASTNode current = ast.nodes.GetFirst(); + while (current) { + Visit(current); + current = current->GetNext(); + } + decomp.code.scope--; + decomp.code.AddLine("}}"); + } + + void operator()(VideoCommon::Shader::ASTIfElse& ast) { + decomp.code.AddLine("else {{"); + decomp.code.scope++; + ASTNode current = ast.nodes.GetFirst(); + while (current) { + Visit(current); + current = current->GetNext(); + } + decomp.code.scope--; + decomp.code.AddLine("}}"); + } + + void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) { + UNREACHABLE(); + } + + void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) { + decomp.VisitBlock(ast.nodes); + } + + void operator()(VideoCommon::Shader::ASTVarSet& ast) { + ExprDecompiler expr_parser{decomp}; + std::visit(expr_parser, *ast.condition); + decomp.code.AddLine("{} = {};", GetFlowVariable(ast.index), expr_parser.GetResult()); + } + + void operator()(VideoCommon::Shader::ASTLabel& ast) { + decomp.code.AddLine("// Label_{}:", ast.index); + } + + void operator()(VideoCommon::Shader::ASTGoto& ast) { + UNREACHABLE(); + } + + void operator()(VideoCommon::Shader::ASTDoWhile& ast) { + ExprDecompiler expr_parser{decomp}; + std::visit(expr_parser, *ast.condition); + decomp.code.AddLine("do {{"); + decomp.code.scope++; + ASTNode current = ast.nodes.GetFirst(); + while (current) { + Visit(current); + current = current->GetNext(); + } + decomp.code.scope--; + decomp.code.AddLine("}} while({});", expr_parser.GetResult()); + } + + void operator()(VideoCommon::Shader::ASTReturn& ast) { + const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); + if (!is_true) { + ExprDecompiler expr_parser{decomp}; + std::visit(expr_parser, *ast.condition); + decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); + decomp.code.scope++; + } + if (ast.kills) { + decomp.code.AddLine("discard;"); + } else { + decomp.PreExit(); + decomp.code.AddLine("return;"); + } + if (!is_true) { + decomp.code.scope--; + decomp.code.AddLine("}}"); + } + } + + void operator()(VideoCommon::Shader::ASTBreak& ast) { + const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); + if (!is_true) { + ExprDecompiler expr_parser{decomp}; + std::visit(expr_parser, *ast.condition); + decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); + decomp.code.scope++; + } + decomp.code.AddLine("break;"); + if (!is_true) { + decomp.code.scope--; + decomp.code.AddLine("}}"); + } + } + + void Visit(VideoCommon::Shader::ASTNode& node) { + std::visit(*this, *node->GetInnerData()); + } + +private: + GLSLDecompiler& decomp; +}; + +void GLSLDecompiler::DecompileAST() { + const u32 num_flow_variables = ir.GetASTNumVariables(); + for (u32 i = 0; i < num_flow_variables; i++) { + code.AddLine("bool {} = false;", GetFlowVariable(i)); + } + ASTDecompiler decompiler{*this}; + VideoCommon::Shader::ASTNode program = ir.GetASTProgram(); + decompiler.Visit(program); +} + } // Anonymous namespace std::string GetCommonDeclarations() { diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 2ea02f5bf..e538dc001 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h @@ -90,7 +90,6 @@ struct ShaderEntries { std::vector<ImageEntry> images; std::vector<GlobalMemoryEntry> global_memory_entries; std::array<bool, Maxwell::NumClipDistances> clip_distances{}; - bool shader_viewport_layer_array{}; std::size_t shader_length{}; }; diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index f141c4e3b..74cc33476 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp @@ -112,14 +112,15 @@ std::optional<std::pair<std::vector<ShaderDiskCacheRaw>, std::vector<ShaderDiskC ShaderDiskCacheOpenGL::LoadTransferable() { // Skip games without title id const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0; - if (!Settings::values.use_disk_shader_cache || !has_title_id) + if (!Settings::values.use_disk_shader_cache || !has_title_id) { return {}; - tried_to_load = true; + } FileUtil::IOFile file(GetTransferablePath(), "rb"); if (!file.IsOpen()) { LOG_INFO(Render_OpenGL, "No transferable shader cache found for game with title id={}", GetTitleID()); + is_usable = true; return {}; } @@ -135,6 +136,7 @@ ShaderDiskCacheOpenGL::LoadTransferable() { LOG_INFO(Render_OpenGL, "Transferable shader cache is old - removing"); file.Close(); InvalidateTransferable(); + is_usable = true; return {}; } if (version > NativeVersion) { @@ -180,13 +182,15 @@ ShaderDiskCacheOpenGL::LoadTransferable() { } } - return {{raws, usages}}; + is_usable = true; + return {{std::move(raws), std::move(usages)}}; } std::pair<std::unordered_map<u64, ShaderDiskCacheDecompiled>, ShaderDumpsMap> ShaderDiskCacheOpenGL::LoadPrecompiled() { - if (!IsUsable()) + if (!is_usable) { return {}; + } FileUtil::IOFile file(GetPrecompiledPath(), "rb"); if (!file.IsOpen()) { @@ -343,20 +347,17 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn u8 is_bindless{}; u8 is_written{}; u8 is_read{}; - u8 is_size_known{}; - u32 size{}; + u8 is_atomic{}; if (!LoadObjectFromPrecompiled(offset) || !LoadObjectFromPrecompiled(index) || !LoadObjectFromPrecompiled(type) || !LoadObjectFromPrecompiled(is_bindless) || !LoadObjectFromPrecompiled(is_written) || !LoadObjectFromPrecompiled(is_read) || - !LoadObjectFromPrecompiled(is_size_known) || !LoadObjectFromPrecompiled(size)) { + !LoadObjectFromPrecompiled(is_atomic)) { return {}; } entry.entries.images.emplace_back( static_cast<std::size_t>(offset), static_cast<std::size_t>(index), static_cast<Tegra::Shader::ImageType>(type), is_bindless != 0, is_written != 0, - is_read != 0, - is_size_known ? std::make_optional(static_cast<Tegra::Shader::ImageAtomicSize>(size)) - : std::nullopt); + is_read != 0, is_atomic != 0); } u32 global_memory_count{}; @@ -382,12 +383,6 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn } } - bool shader_viewport_layer_array{}; - if (!LoadObjectFromPrecompiled(shader_viewport_layer_array)) { - return {}; - } - entry.entries.shader_viewport_layer_array = shader_viewport_layer_array; - u64 shader_length{}; if (!LoadObjectFromPrecompiled(shader_length)) { return {}; @@ -435,14 +430,13 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: return false; } for (const auto& image : entries.images) { - const u32 size = image.IsSizeKnown() ? static_cast<u32>(image.GetSize()) : 0U; if (!SaveObjectToPrecompiled(static_cast<u64>(image.GetOffset())) || !SaveObjectToPrecompiled(static_cast<u64>(image.GetIndex())) || !SaveObjectToPrecompiled(static_cast<u32>(image.GetType())) || !SaveObjectToPrecompiled(static_cast<u8>(image.IsBindless() ? 1 : 0)) || !SaveObjectToPrecompiled(static_cast<u8>(image.IsWritten() ? 1 : 0)) || !SaveObjectToPrecompiled(static_cast<u8>(image.IsRead() ? 1 : 0)) || - !SaveObjectToPrecompiled(image.IsSizeKnown()) || !SaveObjectToPrecompiled(size)) { + !SaveObjectToPrecompiled(static_cast<u8>(image.IsAtomic() ? 1 : 0))) { return false; } } @@ -464,10 +458,6 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std: } } - if (!SaveObjectToPrecompiled(entries.shader_viewport_layer_array)) { - return false; - } - if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) { return false; } @@ -493,8 +483,9 @@ void ShaderDiskCacheOpenGL::InvalidatePrecompiled() { } void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { - if (!IsUsable()) + if (!is_usable) { return; + } const u64 id = entry.GetUniqueIdentifier(); if (transferable.find(id) != transferable.end()) { @@ -515,8 +506,9 @@ void ShaderDiskCacheOpenGL::SaveRaw(const ShaderDiskCacheRaw& entry) { } void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) { - if (!IsUsable()) + if (!is_usable) { return; + } const auto it = transferable.find(usage.unique_identifier); ASSERT_MSG(it != transferable.end(), "Saving shader usage without storing raw previously"); @@ -542,8 +534,9 @@ void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) { void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::string& code, const GLShader::ShaderEntries& entries) { - if (!IsUsable()) + if (!is_usable) { return; + } if (precompiled_cache_virtual_file.GetSize() == 0) { SavePrecompiledHeaderToVirtualPrecompiledCache(); @@ -557,8 +550,9 @@ void ShaderDiskCacheOpenGL::SaveDecompiled(u64 unique_identifier, const std::str } void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint program) { - if (!IsUsable()) + if (!is_usable) { return; + } GLint binary_length{}; glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binary_length); @@ -579,10 +573,6 @@ void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint p } } -bool ShaderDiskCacheOpenGL::IsUsable() const { - return tried_to_load && Settings::values.use_disk_shader_cache; -} - FileUtil::IOFile ShaderDiskCacheOpenGL::AppendTransferableFile() const { if (!EnsureDirectories()) return {}; diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.h b/src/video_core/renderer_opengl/gl_shader_disk_cache.h index cc8bbd61e..9595bd71b 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.h @@ -224,9 +224,6 @@ private: bool SaveDecompiledFile(u64 unique_identifier, const std::string& code, const GLShader::ShaderEntries& entries); - /// Returns if the cache can be used - bool IsUsable() const; - /// Opens current game's transferable file and write it's header if it doesn't exist FileUtil::IOFile AppendTransferableFile() const; @@ -297,7 +294,7 @@ private: std::unordered_map<u64, std::unordered_set<ShaderDiskCacheUsage>> transferable; // The cache has been loaded at boot - bool tried_to_load{}; + bool is_usable{}; }; } // namespace OpenGL diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 3a8d9e1da..b5a43e79e 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -11,12 +11,16 @@ namespace OpenGL::GLShader { using Tegra::Engines::Maxwell3D; +using VideoCommon::Shader::CompileDepth; +using VideoCommon::Shader::CompilerSettings; using VideoCommon::Shader::ProgramCode; using VideoCommon::Shader::ShaderIR; static constexpr u32 PROGRAM_OFFSET = 10; static constexpr u32 COMPUTE_OFFSET = 0; +static constexpr CompilerSettings settings{CompileDepth::NoFlowStack, true}; + ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setup) { const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); @@ -31,13 +35,14 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); const auto stage = setup.IsDualProgram() ? ProgramType::VertexA : ProgramType::VertexB; ProgramResult program = Decompile(device, program_ir, stage, "vertex"); out += program.first; if (setup.IsDualProgram()) { - const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET, setup.program.size_b); + const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET, setup.program.size_b, + settings); ProgramResult program_b = Decompile(device, program_ir_b, ProgramType::VertexB, "vertex_b"); out += program_b.first; } @@ -80,7 +85,7 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Geometry, "geometry"); out += program.first; @@ -114,7 +119,8 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { }; )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); + + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Fragment, "fragment"); out += program.first; @@ -133,7 +139,7 @@ ProgramResult GenerateComputeShader(const Device& device, const ShaderSetup& set std::string out = "// Shader Unique Id: CS" + id + "\n\n"; out += GetCommonDeclarations(); - const ShaderIR program_ir(setup.program.code, COMPUTE_OFFSET, setup.program.size_a); + const ShaderIR program_ir(setup.program.code, COMPUTE_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Compute, "compute"); out += program.first; |