diff options
-rw-r--r-- | CONTRIBUTING.md | 2 | ||||
m--------- | externals/fmt | 0 | ||||
-rw-r--r-- | src/common/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/common/param_package.cpp | 18 | ||||
-rw-r--r-- | src/common/param_package.h | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/client_port.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/kernel/client_port.h | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/server_port.h | 1 | ||||
-rw-r--r-- | src/core/hle/service/sm/sm.h | 19 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 19 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 2 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 262 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 14 | ||||
-rw-r--r-- | src/video_core/renderer_opengl/maxwell_to_gl.h | 25 | ||||
-rw-r--r-- | src/video_core/textures/texture.h | 13 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_input.cpp | 87 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_input.h | 3 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_input.ui | 28 |
18 files changed, 413 insertions, 90 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 008dc5b50..1b2056885 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ If clang format is found, then cmake will add a custom build target that can be * Don't ever introduce new external dependencies into Core * Don't use any platform specific code in Core * Use namespaces often -* Avoid the use of C-style casts and instead prefer C++-style `static_cast` and `reinterpret_cast`. Try to avoid using `dynamic_cast`. Never use `const_cast`. The only exception to this rule is for casting between two numeric types, where C-style casts are encouraged for brevity and readability. +* Avoid the use of C-style casts and instead prefer C++-style `static_cast` and `reinterpret_cast`. Try to avoid using `dynamic_cast`. Never use `const_cast`. ### Naming Rules * Functions: `PascalCase` diff --git a/externals/fmt b/externals/fmt -Subproject 62010520edc734df16c48f9dbb238143279abd7 +Subproject 3e75ad9822980e41bc591938f26548f24eb8890 diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 8985e4367..d0e506689 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -29,7 +29,7 @@ if ($ENV{CI}) if (BUILD_VERSION) # This leaves a trailing space on the last word, but we actually want that # because of how it's styled in the title bar. - set(BUILD_FULLNAME "${REPO_NAME} #${BUILD_VERSION} ") + set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ") else() set(BUILD_FULLNAME "") endif() diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp index 9526ca0c6..b916b4866 100644 --- a/src/common/param_package.cpp +++ b/src/common/param_package.cpp @@ -20,7 +20,15 @@ constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0"; constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1"; constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2"; +/// A placeholder for empty param packages to avoid empty strings +/// (they may be recognized as "not set" by some frontend libraries like qt) +constexpr char EMPTY_PLACEHOLDER[] = "[empty]"; + ParamPackage::ParamPackage(const std::string& serialized) { + if (serialized == EMPTY_PLACEHOLDER) { + return; + } + std::vector<std::string> pairs; Common::SplitString(serialized, PARAM_SEPARATOR, pairs); @@ -46,7 +54,7 @@ ParamPackage::ParamPackage(std::initializer_list<DataType::value_type> list) : d std::string ParamPackage::Serialize() const { if (data.empty()) - return ""; + return EMPTY_PLACEHOLDER; std::string result; @@ -120,4 +128,12 @@ bool ParamPackage::Has(const std::string& key) const { return data.find(key) != data.end(); } +void ParamPackage::Erase(const std::string& key) { + data.erase(key); +} + +void ParamPackage::Clear() { + data.clear(); +} + } // namespace Common diff --git a/src/common/param_package.h b/src/common/param_package.h index 7842cd4ef..6a0a9b656 100644 --- a/src/common/param_package.h +++ b/src/common/param_package.h @@ -32,6 +32,8 @@ public: void Set(const std::string& key, int value); void Set(const std::string& key, float value); bool Has(const std::string& key) const; + void Erase(const std::string& key); + void Clear(); private: DataType data; diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp index 873d6c516..d4c91d529 100644 --- a/src/core/hle/kernel/client_port.cpp +++ b/src/core/hle/kernel/client_port.cpp @@ -17,6 +17,10 @@ namespace Kernel { ClientPort::ClientPort(KernelCore& kernel) : Object{kernel} {} ClientPort::~ClientPort() = default; +SharedPtr<ServerPort> ClientPort::GetServerPort() const { + return server_port; +} + ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() { // Note: Threads do not wait for the server endpoint to call // AcceptSession before returning from this call. diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h index f3dfebbb1..6cd607206 100644 --- a/src/core/hle/kernel/client_port.h +++ b/src/core/hle/kernel/client_port.h @@ -30,6 +30,8 @@ public: return HANDLE_TYPE; } + SharedPtr<ServerPort> GetServerPort() const; + /** * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's * list of pending sessions, and signals the ServerPort, causing any threads diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h index 62fb51349..e52f8245f 100644 --- a/src/core/hle/kernel/server_port.h +++ b/src/core/hle/kernel/server_port.h @@ -11,6 +11,7 @@ #include "common/common_types.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/wait_object.h" +#include "core/hle/result.h" namespace Kernel { diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index da2c51082..4f8145dda 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -6,9 +6,12 @@ #include <memory> #include <string> +#include <type_traits> #include <unordered_map> +#include "core/hle/kernel/client_port.h" #include "core/hle/kernel/object.h" +#include "core/hle/kernel/server_port.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -48,6 +51,22 @@ public: ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); + template <typename T> + std::shared_ptr<T> GetService(const std::string& service_name) const { + static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>, + "Not a base of ServiceFrameworkBase"); + auto service = registered_services.find(service_name); + if (service == registered_services.end()) { + LOG_DEBUG(Service, "Can't find service: {}", service_name); + return nullptr; + } + auto port = service->second->GetServerPort(); + if (port == nullptr) { + return nullptr; + } + return std::static_pointer_cast<T>(port->hle_handler); + } + void InvokeControlRequest(Kernel::HLERequestContext& context); private: diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a3a14efd9..209bdf181 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -252,6 +252,7 @@ DrawParameters RasterizerOpenGL::SetupDraw() { params.count = regs.vertex_buffer.count; params.vertex_first = regs.vertex_buffer.first; } + return params; } void RasterizerOpenGL::SetupShaders() { @@ -657,10 +658,13 @@ void RasterizerOpenGL::SamplerInfo::Create() { sampler.Create(); mag_filter = min_filter = Tegra::Texture::TextureFilter::Linear; wrap_u = wrap_v = wrap_p = Tegra::Texture::WrapMode::Wrap; + uses_depth_compare = false; + depth_compare_func = Tegra::Texture::DepthCompareFunc::Never; // default is GL_LINEAR_MIPMAP_LINEAR glSamplerParameteri(sampler.handle, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Other attributes have correct defaults + glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER); } void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) { @@ -688,6 +692,21 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr glSamplerParameteri(s, GL_TEXTURE_WRAP_R, MaxwellToGL::WrapMode(wrap_p)); } + if (uses_depth_compare != (config.depth_compare_enabled == 1)) { + uses_depth_compare = (config.depth_compare_enabled == 1); + if (uses_depth_compare) { + glSamplerParameteri(s, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + } else { + glSamplerParameteri(s, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + } + + if (depth_compare_func != config.depth_compare_func) { + depth_compare_func = config.depth_compare_func; + glSamplerParameteri(s, GL_TEXTURE_COMPARE_FUNC, + MaxwellToGL::DepthCompareFunc(depth_compare_func)); + } + if (wrap_u == Tegra::Texture::WrapMode::Border || wrap_v == Tegra::Texture::WrapMode::Border || wrap_p == Tegra::Texture::WrapMode::Border) { const GLvec4 new_border_color = {{config.border_color_r, config.border_color_g, diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 8b6b62241..0dab2018b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -96,6 +96,8 @@ private: Tegra::Texture::WrapMode wrap_u; Tegra::Texture::WrapMode wrap_v; Tegra::Texture::WrapMode wrap_p; + bool uses_depth_compare; + Tegra::Texture::DepthCompareFunc depth_compare_func; GLvec4 border_color; }; diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 579a78702..7e57de78a 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -508,7 +508,7 @@ public: /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if /// necessary. std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, - bool is_array) { + bool is_array, bool is_shadow) { const std::size_t offset = static_cast<std::size_t>(sampler.index.Value()); // If this sampler has already been used, return the existing mapping. @@ -517,13 +517,14 @@ public: [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); if (itr != used_samplers.end()) { - ASSERT(itr->GetType() == type && itr->IsArray() == is_array); + ASSERT(itr->GetType() == type && itr->IsArray() == is_array && + itr->IsShadow() == is_shadow); return itr->GetName(); } // Otherwise create a new mapping for this sampler const std::size_t next_index = used_samplers.size(); - const SamplerEntry entry{stage, offset, next_index, type, is_array}; + const SamplerEntry entry{stage, offset, next_index, type, is_array, is_shadow}; used_samplers.emplace_back(entry); return entry.GetName(); } @@ -747,8 +748,9 @@ private: } /// Generates code representing a texture sampler. - std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) { - return regs.AccessSampler(sampler, type, is_array); + std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array, + bool is_shadow) { + return regs.AccessSampler(sampler, type, is_array, is_shadow); } /** @@ -1002,6 +1004,24 @@ private: shader.AddLine('}'); } + static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { + switch (texture_type) { + case Tegra::Shader::TextureType::Texture1D: { + return 1; + } + case Tegra::Shader::TextureType::Texture2D: { + return 2; + } + case Tegra::Shader::TextureType::TextureCube: { + return 3; + } + default: + LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", static_cast<u32>(texture_type)); + UNREACHABLE(); + return 0; + } + } + /* * Emits code to push the input target address to the SSY address stack, incrementing the stack * top. @@ -1896,24 +1916,35 @@ private: "NODEP is not implemented"); ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), "AOFFI is not implemented"); - ASSERT_MSG(!instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), - "DC is not implemented"); - switch (texture_type) { - case Tegra::Shader::TextureType::Texture1D: { + const bool depth_compare = + instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); + u32 num_coordinates = TextureCoordinates(texture_type); + if (depth_compare) + num_coordinates += 1; + + switch (num_coordinates) { + case 1: { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); coord = "float coords = " + x + ';'; break; } - case Tegra::Shader::TextureType::Texture2D: { + case 2: { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); coord = "vec2 coords = vec2(" + x + ", " + y + ");"; break; } + case 3: { + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + const std::string z = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + break; + } default: - LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", - static_cast<u32>(texture_type)); + LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}", + static_cast<u32>(num_coordinates)); UNREACHABLE(); // Fallback to interpreting as a 2D texture for now @@ -1924,9 +1955,10 @@ private: } // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias // or lod. - const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20); + std::string op_c; - const std::string sampler = GetSampler(instr.sampler, texture_type, false); + const std::string sampler = + GetSampler(instr.sampler, texture_type, false, depth_compare); // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. @@ -1935,7 +1967,7 @@ private: shader.AddLine(coord); std::string texture; - switch (instr.tex.process_mode) { + switch (instr.tex.GetTextureProcessMode()) { case Tegra::Shader::TextureProcessMode::None: { texture = "texture(" + sampler + ", coords)"; break; @@ -1946,12 +1978,22 @@ private: } case Tegra::Shader::TextureProcessMode::LB: case Tegra::Shader::TextureProcessMode::LBA: { + if (num_coordinates <= 2) { + op_c = regs.GetRegisterAsFloat(instr.gpr20); + } else { + op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); + } // TODO: Figure if A suffix changes the equation at all. texture = "texture(" + sampler + ", coords, " + op_c + ')'; break; } case Tegra::Shader::TextureProcessMode::LL: case Tegra::Shader::TextureProcessMode::LLA: { + if (num_coordinates <= 2) { + op_c = regs.GetRegisterAsFloat(instr.gpr20); + } else { + op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); + } // TODO: Figure if A suffix changes the equation at all. texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; break; @@ -1959,18 +2001,22 @@ private: default: { texture = "texture(" + sampler + ", coords)"; LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", - static_cast<u32>(instr.tex.process_mode.Value())); + static_cast<u32>(instr.tex.GetTextureProcessMode())); UNREACHABLE(); } } - std::size_t dest_elem{}; - for (std::size_t elem = 0; elem < 4; ++elem) { - if (!instr.tex.IsComponentEnabled(elem)) { - // Skip disabled components - continue; + if (!depth_compare) { + std::size_t dest_elem{}; + for (std::size_t elem = 0; elem < 4; ++elem) { + if (!instr.tex.IsComponentEnabled(elem)) { + // Skip disabled components + continue; + } + regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); + ++dest_elem; } - regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); - ++dest_elem; + } else { + regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); } --shader.scope; shader.AddLine("}"); @@ -1983,11 +2029,15 @@ private: ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), "NODEP is not implemented"); - ASSERT_MSG(!instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), - "DC is not implemented"); - switch (texture_type) { - case Tegra::Shader::TextureType::Texture2D: { + const bool depth_compare = + instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); + u32 num_coordinates = TextureCoordinates(texture_type); + if (depth_compare) + num_coordinates += 1; + + switch (num_coordinates) { + case 2: { if (is_array) { const std::string index = regs.GetRegisterAsInteger(instr.gpr8); const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); @@ -2000,17 +2050,25 @@ private: } break; } - case Tegra::Shader::TextureType::TextureCube: { - ASSERT_MSG(!is_array, "Unimplemented"); - std::string x = regs.GetRegisterAsFloat(instr.gpr8); - std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); - std::string z = regs.GetRegisterAsFloat(instr.gpr20); - coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + case 3: { + if (is_array) { + UNIMPLEMENTED_MSG("3-coordinate arrays not fully implemented"); + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + texture_type = Tegra::Shader::TextureType::Texture2D; + is_array = false; + } else { + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + const std::string z = regs.GetRegisterAsFloat(instr.gpr20); + coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + } break; } default: - LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", - static_cast<u32>(texture_type)); + LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}", + static_cast<u32>(num_coordinates)); UNREACHABLE(); // Fallback to interpreting as a 2D texture for now @@ -2020,9 +2078,35 @@ private: texture_type = Tegra::Shader::TextureType::Texture2D; is_array = false; } - const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); - const std::string texture = "texture(" + sampler + ", coords)"; - WriteTexsInstruction(instr, coord, texture); + const std::string sampler = + GetSampler(instr.sampler, texture_type, is_array, depth_compare); + std::string texture; + switch (instr.texs.GetTextureProcessMode()) { + case Tegra::Shader::TextureProcessMode::None: { + texture = "texture(" + sampler + ", coords)"; + break; + } + case Tegra::Shader::TextureProcessMode::LZ: { + texture = "textureLod(" + sampler + ", coords, 0.0)"; + break; + } + case Tegra::Shader::TextureProcessMode::LL: { + const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); + texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; + break; + } + default: { + texture = "texture(" + sampler + ", coords)"; + LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", + static_cast<u32>(instr.texs.GetTextureProcessMode())); + UNREACHABLE(); + } + } + if (!depth_compare) { + WriteTexsInstruction(instr, coord, texture); + } else { + WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); + } break; } case OpCode::Id::TLDS: { @@ -2062,9 +2146,26 @@ private: static_cast<u32>(texture_type)); UNREACHABLE(); } - - const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); - const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; + const std::string sampler = + GetSampler(instr.sampler, texture_type, is_array, false); + std::string texture = "texelFetch(" + sampler + ", coords, 0)"; + const std::string op_c = regs.GetRegisterAsInteger(instr.gpr20.Value() + 1); + switch (instr.tlds.GetTextureProcessMode()) { + case Tegra::Shader::TextureProcessMode::LZ: { + texture = "texelFetch(" + sampler + ", coords, 0)"; + break; + } + case Tegra::Shader::TextureProcessMode::LL: { + texture = "texelFetch(" + sampler + ", coords, " + op_c + ')'; + break; + } + default: { + texture = "texelFetch(" + sampler + ", coords, 0)"; + LOG_CRITICAL(HW_GPU, "Unhandled texture process mode {}", + static_cast<u32>(instr.tlds.GetTextureProcessMode())); + UNREACHABLE(); + } + } WriteTexsInstruction(instr, coord, texture); break; } @@ -2077,28 +2178,43 @@ private: "NODEP is not implemented"); ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), "AOFFI is not implemented"); - ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), - "DC is not implemented"); ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), "NDV is not implemented"); ASSERT_MSG(!instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::PTP), "PTP is not implemented"); - - switch (instr.tld4.texture_type) { - case Tegra::Shader::TextureType::Texture2D: { + const bool depth_compare = + instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); + auto texture_type = instr.tld4.texture_type.Value(); + u32 num_coordinates = TextureCoordinates(texture_type); + if (depth_compare) + num_coordinates += 1; + + switch (num_coordinates) { + case 2: { const std::string x = regs.GetRegisterAsFloat(instr.gpr8); const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); coord = "vec2 coords = vec2(" + x + ", " + y + ");"; break; } + case 3: { + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); + coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; + break; + } default: - LOG_CRITICAL(HW_GPU, "Unhandled texture type {}", - static_cast<u32>(instr.tld4.texture_type.Value())); + LOG_CRITICAL(HW_GPU, "Unhandled coordinates number {}", + static_cast<u32>(num_coordinates)); UNREACHABLE(); + const std::string x = regs.GetRegisterAsFloat(instr.gpr8); + const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec2 coords = vec2(" + x + ", " + y + ");"; + texture_type = Tegra::Shader::TextureType::Texture2D; } const std::string sampler = - GetSampler(instr.sampler, instr.tld4.texture_type, false); + GetSampler(instr.sampler, texture_type, false, depth_compare); // Add an extra scope and declare the texture coords inside to prevent // overwriting them in case they are used as outputs of the texs instruction. shader.AddLine("{"); @@ -2106,15 +2222,18 @@ private: shader.AddLine(coord); const std::string texture = "textureGather(" + sampler + ", coords, " + std::to_string(instr.tld4.component) + ')'; - - std::size_t dest_elem{}; - for (std::size_t elem = 0; elem < 4; ++elem) { - if (!instr.tex.IsComponentEnabled(elem)) { - // Skip disabled components - continue; + if (!depth_compare) { + std::size_t dest_elem{}; + for (std::size_t elem = 0; elem < 4; ++elem) { + if (!instr.tex.IsComponentEnabled(elem)) { + // Skip disabled components + continue; + } + regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); + ++dest_elem; } - regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); - ++dest_elem; + } else { + regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); } --shader.scope; shader.AddLine("}"); @@ -2125,18 +2244,30 @@ private: "NODEP is not implemented"); ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), "AOFFI is not implemented"); - ASSERT_MSG(!instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC), - "DC is not implemented"); + const bool depth_compare = + instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. - const std::string sampler = - GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); - const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; + const std::string sampler = GetSampler( + instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); + std::string coord; + if (!depth_compare) { + coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; + } else { + // Note: TLD4S coordinate encoding works just like TEXS's + const std::string op_c = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); + coord = "vec3 coords = vec3(" + op_a + ", " + op_c + ", " + op_b + ");"; + } const std::string texture = "textureGather(" + sampler + ", coords, " + std::to_string(instr.tld4s.component) + ')'; - WriteTexsInstruction(instr, coord, texture); + + if (!depth_compare) { + WriteTexsInstruction(instr, coord, texture); + } else { + WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); + } break; } case OpCode::Id::TXQ: { @@ -2147,7 +2278,7 @@ private: // Sadly, not all texture instructions specify the type of texture their sampler // uses. This must be fixed at a later instance. const std::string sampler = - GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false); + GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); switch (instr.txq.query_type) { case Tegra::Shader::TextureQueryType::Dimension: { const std::string texture = "textureQueryLevels(" + sampler + ')'; @@ -2172,7 +2303,8 @@ private: const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); const bool is_array = instr.tmml.array != 0; auto texture_type = instr.tmml.texture_type.Value(); - const std::string sampler = GetSampler(instr.sampler, texture_type, is_array); + const std::string sampler = + GetSampler(instr.sampler, texture_type, is_array, false); // TODO: add coordinates for different samplers once other texture types are // implemented. diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index d53b93ad5..e56f39e78 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -75,8 +75,9 @@ class SamplerEntry { public: SamplerEntry(Maxwell::ShaderStage stage, std::size_t offset, std::size_t index, - Tegra::Shader::TextureType type, bool is_array) - : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {} + Tegra::Shader::TextureType type, bool is_array, bool is_shadow) + : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array), + is_shadow(is_shadow) {} std::size_t GetOffset() const { return offset; @@ -117,6 +118,8 @@ public: } if (is_array) glsl_type += "Array"; + if (is_shadow) + glsl_type += "Shadow"; return glsl_type; } @@ -128,6 +131,10 @@ public: return is_array; } + bool IsShadow() const { + return is_shadow; + } + u32 GetHash() const { return (static_cast<u32>(stage) << 16) | static_cast<u32>(sampler_index); } @@ -147,7 +154,8 @@ private: Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. std::size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc) - bool is_array; ///< Whether the texture is being sampled as an array texture or not. + bool is_array; ///< Whether the texture is being sampled as an array texture or not. + bool is_shadow; ///< Whether the texture is being sampled as a depth texture or not. }; struct ShaderEntries { diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 67273e164..3c3bcaae4 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h @@ -159,6 +159,31 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { return {}; } +inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { + switch (func) { + case Tegra::Texture::DepthCompareFunc::Never: + return GL_NEVER; + case Tegra::Texture::DepthCompareFunc::Less: + return GL_LESS; + case Tegra::Texture::DepthCompareFunc::LessEqual: + return GL_LEQUAL; + case Tegra::Texture::DepthCompareFunc::Equal: + return GL_EQUAL; + case Tegra::Texture::DepthCompareFunc::NotEqual: + return GL_NOTEQUAL; + case Tegra::Texture::DepthCompareFunc::Greater: + return GL_GREATER; + case Tegra::Texture::DepthCompareFunc::GreaterEqual: + return GL_GEQUAL; + case Tegra::Texture::DepthCompareFunc::Always: + return GL_ALWAYS; + } + LOG_CRITICAL(Render_OpenGL, "Unimplemented texture depth compare function ={}", + static_cast<u32>(func)); + UNREACHABLE(); + return {}; +} + inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { switch (equation) { case Maxwell::Blend::Equation::Add: diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 14aea4838..8f31d825a 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -227,6 +227,17 @@ enum class WrapMode : u32 { MirrorOnceClampOGL = 7, }; +enum class DepthCompareFunc : u32 { + Never = 0, + Less = 1, + Equal = 2, + LessEqual = 3, + Greater = 4, + NotEqual = 5, + GreaterEqual = 6, + Always = 7, +}; + enum class TextureFilter : u32 { Nearest = 1, Linear = 2, @@ -244,7 +255,7 @@ struct TSCEntry { BitField<3, 3, WrapMode> wrap_v; BitField<6, 3, WrapMode> wrap_p; BitField<9, 1, u32> depth_compare_enabled; - BitField<10, 3, u32> depth_compare_func; + BitField<10, 3, DepthCompareFunc> depth_compare_func; }; union { BitField<0, 2, TextureFilter> mag_filter; diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 473937ea9..94789c064 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -5,6 +5,7 @@ #include <algorithm> #include <memory> #include <utility> +#include <QMenu> #include <QMessageBox> #include <QTimer> #include "common/param_package.h" @@ -128,28 +129,63 @@ ConfigureInput::ConfigureInput(QWidget* parent) analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog}; for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { - if (button_map[button_id]) - connect(button_map[button_id], &QPushButton::released, [=]() { - handleClick( - button_map[button_id], - [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, - InputCommon::Polling::DeviceType::Button); - }); + if (!button_map[button_id]) + continue; + button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu); + connect(button_map[button_id], &QPushButton::released, [=]() { + handleClick( + button_map[button_id], + [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, + InputCommon::Polling::DeviceType::Button); + }); + connect(button_map[button_id], &QPushButton::customContextMenuRequested, + [=](const QPoint& menu_location) { + QMenu context_menu; + context_menu.addAction(tr("Clear"), [&] { + buttons_param[button_id].Clear(); + button_map[button_id]->setText(tr("[not set]")); + }); + context_menu.addAction(tr("Restore Default"), [&] { + buttons_param[button_id] = Common::ParamPackage{ + InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; + button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); + }); + context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); + }); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { - if (analog_map_buttons[analog_id][sub_button_id] != nullptr) { - connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, - [=]() { - handleClick(analog_map_buttons[analog_id][sub_button_id], - [=](const Common::ParamPackage& params) { - SetAnalogButton(params, analogs_param[analog_id], - analog_sub_buttons[sub_button_id]); - }, - InputCommon::Polling::DeviceType::Button); + if (!analog_map_buttons[analog_id][sub_button_id]) + continue; + analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy( + Qt::CustomContextMenu); + connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() { + handleClick(analog_map_buttons[analog_id][sub_button_id], + [=](const Common::ParamPackage& params) { + SetAnalogButton(params, analogs_param[analog_id], + analog_sub_buttons[sub_button_id]); + }, + InputCommon::Polling::DeviceType::Button); + }); + connect(analog_map_buttons[analog_id][sub_button_id], + &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { + QMenu context_menu; + context_menu.addAction(tr("Clear"), [&] { + analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); + analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); }); - } + context_menu.addAction(tr("Restore Default"), [&] { + Common::ParamPackage params{InputCommon::GenerateKeyboardParam( + Config::default_analogs[analog_id][sub_button_id])}; + SetAnalogButton(params, analogs_param[analog_id], + analog_sub_buttons[sub_button_id]); + analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( + analogs_param[analog_id], analog_sub_buttons[sub_button_id])); + }); + context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( + menu_location)); + }); } connect(analog_map_stick[analog_id], &QPushButton::released, [=]() { QMessageBox::information(this, tr("Information"), @@ -162,6 +198,7 @@ ConfigureInput::ConfigureInput(QWidget* parent) }); } + connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); }); connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); }); timeout_timer->setSingleShot(true); @@ -215,7 +252,21 @@ void ConfigureInput::restoreDefaults() { } } updateButtonLabels(); - applyConfiguration(); +} + +void ConfigureInput::ClearAll() { + for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { + if (button_map[button_id] && button_map[button_id]->isEnabled()) + buttons_param[button_id].Clear(); + } + for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) { + if (analog_map_buttons[analog_id][sub_button_id] && + analog_map_buttons[analog_id][sub_button_id]->isEnabled()) + analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); + } + } + updateButtonLabels(); } void ConfigureInput::updateButtonLabels() { diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index a0bef86d5..d1198db81 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h @@ -72,6 +72,9 @@ private: void loadConfiguration(); /// Restore all buttons to their default values. void restoreDefaults(); + /// Clear all input configuration + void ClearAll(); + /// Update UI to reflect current configuration. void updateButtonLabels(); diff --git a/src/yuzu/configuration/configure_input.ui b/src/yuzu/configuration/configure_input.ui index 8bfa5df62..8a019a693 100644 --- a/src/yuzu/configuration/configure_input.ui +++ b/src/yuzu/configuration/configure_input.ui @@ -695,6 +695,34 @@ Capture:</string> </spacer> </item> <item> + <widget class="QPushButton" name="buttonClearAll"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="sizeIncrement"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="baseSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="text"> + <string>Clear All</string> + </property> + </widget> + </item> + <item> <widget class="QPushButton" name="buttonRestoreDefaults"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> |