diff options
Diffstat (limited to 'src')
41 files changed, 1326 insertions, 472 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index adf70eb8b..73bf626d4 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -58,6 +58,7 @@ add_library(common STATIC | |||
| 58 | div_ceil.h | 58 | div_ceil.h |
| 59 | dynamic_library.cpp | 59 | dynamic_library.cpp |
| 60 | dynamic_library.h | 60 | dynamic_library.h |
| 61 | elf.h | ||
| 61 | error.cpp | 62 | error.cpp |
| 62 | error.h | 63 | error.h |
| 63 | expected.h | 64 | expected.h |
diff --git a/src/common/elf.h b/src/common/elf.h new file mode 100644 index 000000000..14a5e9597 --- /dev/null +++ b/src/common/elf.h | |||
| @@ -0,0 +1,333 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <array> | ||
| 7 | #include <cstddef> | ||
| 8 | |||
| 9 | #include "common_types.h" | ||
| 10 | |||
| 11 | namespace Common { | ||
| 12 | namespace ELF { | ||
| 13 | |||
| 14 | /* Type for a 16-bit quantity. */ | ||
| 15 | using Elf32_Half = u16; | ||
| 16 | using Elf64_Half = u16; | ||
| 17 | |||
| 18 | /* Types for signed and unsigned 32-bit quantities. */ | ||
| 19 | using Elf32_Word = u32; | ||
| 20 | using Elf32_Sword = s32; | ||
| 21 | using Elf64_Word = u32; | ||
| 22 | using Elf64_Sword = s32; | ||
| 23 | |||
| 24 | /* Types for signed and unsigned 64-bit quantities. */ | ||
| 25 | using Elf32_Xword = u64; | ||
| 26 | using Elf32_Sxword = s64; | ||
| 27 | using Elf64_Xword = u64; | ||
| 28 | using Elf64_Sxword = s64; | ||
| 29 | |||
| 30 | /* Type of addresses. */ | ||
| 31 | using Elf32_Addr = u32; | ||
| 32 | using Elf64_Addr = u64; | ||
| 33 | |||
| 34 | /* Type of file offsets. */ | ||
| 35 | using Elf32_Off = u32; | ||
| 36 | using Elf64_Off = u64; | ||
| 37 | |||
| 38 | /* Type for section indices, which are 16-bit quantities. */ | ||
| 39 | using Elf32_Section = u16; | ||
| 40 | using Elf64_Section = u16; | ||
| 41 | |||
| 42 | /* Type for version symbol information. */ | ||
| 43 | using Elf32_Versym = Elf32_Half; | ||
| 44 | using Elf64_Versym = Elf64_Half; | ||
| 45 | |||
| 46 | constexpr size_t ElfIdentSize = 16; | ||
| 47 | |||
| 48 | /* The ELF file header. This appears at the start of every ELF file. */ | ||
| 49 | |||
| 50 | struct Elf32_Ehdr { | ||
| 51 | std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */ | ||
| 52 | Elf32_Half e_type; /* Object file type */ | ||
| 53 | Elf32_Half e_machine; /* Architecture */ | ||
| 54 | Elf32_Word e_version; /* Object file version */ | ||
| 55 | Elf32_Addr e_entry; /* Entry point virtual address */ | ||
| 56 | Elf32_Off e_phoff; /* Program header table file offset */ | ||
| 57 | Elf32_Off e_shoff; /* Section header table file offset */ | ||
| 58 | Elf32_Word e_flags; /* Processor-specific flags */ | ||
| 59 | Elf32_Half e_ehsize; /* ELF header size in bytes */ | ||
| 60 | Elf32_Half e_phentsize; /* Program header table entry size */ | ||
| 61 | Elf32_Half e_phnum; /* Program header table entry count */ | ||
| 62 | Elf32_Half e_shentsize; /* Section header table entry size */ | ||
| 63 | Elf32_Half e_shnum; /* Section header table entry count */ | ||
| 64 | Elf32_Half e_shstrndx; /* Section header string table index */ | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct Elf64_Ehdr { | ||
| 68 | std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */ | ||
| 69 | Elf64_Half e_type; /* Object file type */ | ||
| 70 | Elf64_Half e_machine; /* Architecture */ | ||
| 71 | Elf64_Word e_version; /* Object file version */ | ||
| 72 | Elf64_Addr e_entry; /* Entry point virtual address */ | ||
| 73 | Elf64_Off e_phoff; /* Program header table file offset */ | ||
| 74 | Elf64_Off e_shoff; /* Section header table file offset */ | ||
| 75 | Elf64_Word e_flags; /* Processor-specific flags */ | ||
| 76 | Elf64_Half e_ehsize; /* ELF header size in bytes */ | ||
| 77 | Elf64_Half e_phentsize; /* Program header table entry size */ | ||
| 78 | Elf64_Half e_phnum; /* Program header table entry count */ | ||
| 79 | Elf64_Half e_shentsize; /* Section header table entry size */ | ||
| 80 | Elf64_Half e_shnum; /* Section header table entry count */ | ||
| 81 | Elf64_Half e_shstrndx; /* Section header string table index */ | ||
| 82 | }; | ||
| 83 | |||
| 84 | constexpr u8 ElfClass32 = 1; /* 32-bit objects */ | ||
| 85 | constexpr u8 ElfClass64 = 2; /* 64-bit objects */ | ||
| 86 | constexpr u8 ElfData2Lsb = 1; /* 2's complement, little endian */ | ||
| 87 | constexpr u8 ElfVersionCurrent = 1; /* EV_CURRENT */ | ||
| 88 | constexpr u8 ElfOsAbiNone = 0; /* System V ABI */ | ||
| 89 | |||
| 90 | constexpr u16 ElfTypeNone = 0; /* No file type */ | ||
| 91 | constexpr u16 ElfTypeRel = 0; /* Relocatable file */ | ||
| 92 | constexpr u16 ElfTypeExec = 0; /* Executable file */ | ||
| 93 | constexpr u16 ElfTypeDyn = 0; /* Shared object file */ | ||
| 94 | |||
| 95 | constexpr u16 ElfMachineArm = 40; /* ARM */ | ||
| 96 | constexpr u16 ElfMachineAArch64 = 183; /* ARM AARCH64 */ | ||
| 97 | |||
| 98 | constexpr std::array<u8, ElfIdentSize> Elf32Ident{ | ||
| 99 | 0x7f, 'E', 'L', 'F', ElfClass32, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone}; | ||
| 100 | |||
| 101 | constexpr std::array<u8, ElfIdentSize> Elf64Ident{ | ||
| 102 | 0x7f, 'E', 'L', 'F', ElfClass64, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone}; | ||
| 103 | |||
| 104 | /* Section header. */ | ||
| 105 | |||
| 106 | struct Elf32_Shdr { | ||
| 107 | Elf32_Word sh_name; /* Section name (string tbl index) */ | ||
| 108 | Elf32_Word sh_type; /* Section type */ | ||
| 109 | Elf32_Word sh_flags; /* Section flags */ | ||
| 110 | Elf32_Addr sh_addr; /* Section virtual addr at execution */ | ||
| 111 | Elf32_Off sh_offset; /* Section file offset */ | ||
| 112 | Elf32_Word sh_size; /* Section size in bytes */ | ||
| 113 | Elf32_Word sh_link; /* Link to another section */ | ||
| 114 | Elf32_Word sh_info; /* Additional section information */ | ||
| 115 | Elf32_Word sh_addralign; /* Section alignment */ | ||
| 116 | Elf32_Word sh_entsize; /* Entry size if section holds table */ | ||
| 117 | }; | ||
| 118 | |||
| 119 | struct Elf64_Shdr { | ||
| 120 | Elf64_Word sh_name; /* Section name (string tbl index) */ | ||
| 121 | Elf64_Word sh_type; /* Section type */ | ||
| 122 | Elf64_Xword sh_flags; /* Section flags */ | ||
| 123 | Elf64_Addr sh_addr; /* Section virtual addr at execution */ | ||
| 124 | Elf64_Off sh_offset; /* Section file offset */ | ||
| 125 | Elf64_Xword sh_size; /* Section size in bytes */ | ||
| 126 | Elf64_Word sh_link; /* Link to another section */ | ||
| 127 | Elf64_Word sh_info; /* Additional section information */ | ||
| 128 | Elf64_Xword sh_addralign; /* Section alignment */ | ||
| 129 | Elf64_Xword sh_entsize; /* Entry size if section holds table */ | ||
| 130 | }; | ||
| 131 | |||
| 132 | constexpr u32 ElfShnUndef = 0; /* Undefined section */ | ||
| 133 | |||
| 134 | constexpr u32 ElfShtNull = 0; /* Section header table entry unused */ | ||
| 135 | constexpr u32 ElfShtProgBits = 1; /* Program data */ | ||
| 136 | constexpr u32 ElfShtSymtab = 2; /* Symbol table */ | ||
| 137 | constexpr u32 ElfShtStrtab = 3; /* String table */ | ||
| 138 | constexpr u32 ElfShtRela = 4; /* Relocation entries with addends */ | ||
| 139 | constexpr u32 ElfShtDynamic = 6; /* Dynamic linking information */ | ||
| 140 | constexpr u32 ElfShtNobits = 7; /* Program space with no data (bss) */ | ||
| 141 | constexpr u32 ElfShtRel = 9; /* Relocation entries, no addends */ | ||
| 142 | constexpr u32 ElfShtDynsym = 11; /* Dynamic linker symbol table */ | ||
| 143 | |||
| 144 | /* Symbol table entry. */ | ||
| 145 | |||
| 146 | struct Elf32_Sym { | ||
| 147 | Elf32_Word st_name; /* Symbol name (string tbl index) */ | ||
| 148 | Elf32_Addr st_value; /* Symbol value */ | ||
| 149 | Elf32_Word st_size; /* Symbol size */ | ||
| 150 | u8 st_info; /* Symbol type and binding */ | ||
| 151 | u8 st_other; /* Symbol visibility */ | ||
| 152 | Elf32_Section st_shndx; /* Section index */ | ||
| 153 | }; | ||
| 154 | |||
| 155 | struct Elf64_Sym { | ||
| 156 | Elf64_Word st_name; /* Symbol name (string tbl index) */ | ||
| 157 | u8 st_info; /* Symbol type and binding */ | ||
| 158 | u8 st_other; /* Symbol visibility */ | ||
| 159 | Elf64_Section st_shndx; /* Section index */ | ||
| 160 | Elf64_Addr st_value; /* Symbol value */ | ||
| 161 | Elf64_Xword st_size; /* Symbol size */ | ||
| 162 | }; | ||
| 163 | |||
| 164 | /* How to extract and insert information held in the st_info field. */ | ||
| 165 | |||
| 166 | static inline u8 ElfStBind(u8 st_info) { | ||
| 167 | return st_info >> 4; | ||
| 168 | } | ||
| 169 | static inline u8 ElfStType(u8 st_info) { | ||
| 170 | return st_info & 0xf; | ||
| 171 | } | ||
| 172 | static inline u8 ElfStInfo(u8 st_bind, u8 st_type) { | ||
| 173 | return static_cast<u8>((st_bind << 4) + (st_type & 0xf)); | ||
| 174 | } | ||
| 175 | |||
| 176 | constexpr u8 ElfBindLocal = 0; /* Local symbol */ | ||
| 177 | constexpr u8 ElfBindGlobal = 1; /* Global symbol */ | ||
| 178 | constexpr u8 ElfBindWeak = 2; /* Weak symbol */ | ||
| 179 | |||
| 180 | constexpr u8 ElfTypeUnspec = 0; /* Symbol type is unspecified */ | ||
| 181 | constexpr u8 ElfTypeObject = 1; /* Symbol is a data object */ | ||
| 182 | constexpr u8 ElfTypeFunc = 2; /* Symbol is a code object */ | ||
| 183 | |||
| 184 | static inline u8 ElfStVisibility(u8 st_other) { | ||
| 185 | return static_cast<u8>(st_other & 0x3); | ||
| 186 | } | ||
| 187 | |||
| 188 | constexpr u8 ElfVisibilityDefault = 0; /* Default symbol visibility rules */ | ||
| 189 | constexpr u8 ElfVisibilityInternal = 1; /* Processor specific hidden class */ | ||
| 190 | constexpr u8 ElfVisibilityHidden = 2; /* Sym unavailable in other modules */ | ||
| 191 | constexpr u8 ElfVisibilityProtected = 3; /* Not preemptible, not exported */ | ||
| 192 | |||
| 193 | /* Relocation table entry without addend (in section of type ShtRel). */ | ||
| 194 | |||
| 195 | struct Elf32_Rel { | ||
| 196 | Elf32_Addr r_offset; /* Address */ | ||
| 197 | Elf32_Word r_info; /* Relocation type and symbol index */ | ||
| 198 | }; | ||
| 199 | |||
| 200 | /* Relocation table entry with addend (in section of type ShtRela). */ | ||
| 201 | |||
| 202 | struct Elf32_Rela { | ||
| 203 | Elf32_Addr r_offset; /* Address */ | ||
| 204 | Elf32_Word r_info; /* Relocation type and symbol index */ | ||
| 205 | Elf32_Sword r_addend; /* Addend */ | ||
| 206 | }; | ||
| 207 | |||
| 208 | struct Elf64_Rela { | ||
| 209 | Elf64_Addr r_offset; /* Address */ | ||
| 210 | Elf64_Xword r_info; /* Relocation type and symbol index */ | ||
| 211 | Elf64_Sxword r_addend; /* Addend */ | ||
| 212 | }; | ||
| 213 | |||
| 214 | /* How to extract and insert information held in the r_info field. */ | ||
| 215 | |||
| 216 | static inline u32 Elf32RelSymIndex(Elf32_Word r_info) { | ||
| 217 | return r_info >> 8; | ||
| 218 | } | ||
| 219 | static inline u8 Elf32RelType(Elf32_Word r_info) { | ||
| 220 | return static_cast<u8>(r_info & 0xff); | ||
| 221 | } | ||
| 222 | static inline Elf32_Word Elf32RelInfo(u32 sym_index, u8 type) { | ||
| 223 | return (sym_index << 8) + type; | ||
| 224 | } | ||
| 225 | static inline u32 Elf64RelSymIndex(Elf64_Xword r_info) { | ||
| 226 | return static_cast<u32>(r_info >> 32); | ||
| 227 | } | ||
| 228 | static inline u32 Elf64RelType(Elf64_Xword r_info) { | ||
| 229 | return r_info & 0xffffffff; | ||
| 230 | } | ||
| 231 | static inline Elf64_Xword Elf64RelInfo(u32 sym_index, u32 type) { | ||
| 232 | return (static_cast<Elf64_Xword>(sym_index) << 32) + type; | ||
| 233 | } | ||
| 234 | |||
| 235 | constexpr u32 ElfArmCopy = 20; /* Copy symbol at runtime */ | ||
| 236 | constexpr u32 ElfArmGlobDat = 21; /* Create GOT entry */ | ||
| 237 | constexpr u32 ElfArmJumpSlot = 22; /* Create PLT entry */ | ||
| 238 | constexpr u32 ElfArmRelative = 23; /* Adjust by program base */ | ||
| 239 | |||
| 240 | constexpr u32 ElfAArch64Copy = 1024; /* Copy symbol at runtime */ | ||
| 241 | constexpr u32 ElfAArch64GlobDat = 1025; /* Create GOT entry */ | ||
| 242 | constexpr u32 ElfAArch64JumpSlot = 1026; /* Create PLT entry */ | ||
| 243 | constexpr u32 ElfAArch64Relative = 1027; /* Adjust by program base */ | ||
| 244 | |||
| 245 | /* Program segment header. */ | ||
| 246 | |||
| 247 | struct Elf32_Phdr { | ||
| 248 | Elf32_Word p_type; /* Segment type */ | ||
| 249 | Elf32_Off p_offset; /* Segment file offset */ | ||
| 250 | Elf32_Addr p_vaddr; /* Segment virtual address */ | ||
| 251 | Elf32_Addr p_paddr; /* Segment physical address */ | ||
| 252 | Elf32_Word p_filesz; /* Segment size in file */ | ||
| 253 | Elf32_Word p_memsz; /* Segment size in memory */ | ||
| 254 | Elf32_Word p_flags; /* Segment flags */ | ||
| 255 | Elf32_Word p_align; /* Segment alignment */ | ||
| 256 | }; | ||
| 257 | |||
| 258 | struct Elf64_Phdr { | ||
| 259 | Elf64_Word p_type; /* Segment type */ | ||
| 260 | Elf64_Word p_flags; /* Segment flags */ | ||
| 261 | Elf64_Off p_offset; /* Segment file offset */ | ||
| 262 | Elf64_Addr p_vaddr; /* Segment virtual address */ | ||
| 263 | Elf64_Addr p_paddr; /* Segment physical address */ | ||
| 264 | Elf64_Xword p_filesz; /* Segment size in file */ | ||
| 265 | Elf64_Xword p_memsz; /* Segment size in memory */ | ||
| 266 | Elf64_Xword p_align; /* Segment alignment */ | ||
| 267 | }; | ||
| 268 | |||
| 269 | /* Legal values for p_type (segment type). */ | ||
| 270 | |||
| 271 | constexpr u32 ElfPtNull = 0; /* Program header table entry unused */ | ||
| 272 | constexpr u32 ElfPtLoad = 1; /* Loadable program segment */ | ||
| 273 | constexpr u32 ElfPtDynamic = 2; /* Dynamic linking information */ | ||
| 274 | constexpr u32 ElfPtInterp = 3; /* Program interpreter */ | ||
| 275 | constexpr u32 ElfPtNote = 4; /* Auxiliary information */ | ||
| 276 | constexpr u32 ElfPtPhdr = 6; /* Entry for header table itself */ | ||
| 277 | constexpr u32 ElfPtTls = 7; /* Thread-local storage segment */ | ||
| 278 | |||
| 279 | /* Legal values for p_flags (segment flags). */ | ||
| 280 | |||
| 281 | constexpr u32 ElfPfExec = 0; /* Segment is executable */ | ||
| 282 | constexpr u32 ElfPfWrite = 1; /* Segment is writable */ | ||
| 283 | constexpr u32 ElfPfRead = 2; /* Segment is readable */ | ||
| 284 | |||
| 285 | /* Dynamic section entry. */ | ||
| 286 | |||
| 287 | struct Elf32_Dyn { | ||
| 288 | Elf32_Sword d_tag; /* Dynamic entry type */ | ||
| 289 | union { | ||
| 290 | Elf32_Word d_val; /* Integer value */ | ||
| 291 | Elf32_Addr d_ptr; /* Address value */ | ||
| 292 | } d_un; | ||
| 293 | }; | ||
| 294 | |||
| 295 | struct Elf64_Dyn { | ||
| 296 | Elf64_Sxword d_tag; /* Dynamic entry type */ | ||
| 297 | union { | ||
| 298 | Elf64_Xword d_val; /* Integer value */ | ||
| 299 | Elf64_Addr d_ptr; /* Address value */ | ||
| 300 | } d_un; | ||
| 301 | }; | ||
| 302 | |||
| 303 | /* Legal values for d_tag (dynamic entry type). */ | ||
| 304 | |||
| 305 | constexpr u32 ElfDtNull = 0; /* Marks end of dynamic section */ | ||
| 306 | constexpr u32 ElfDtNeeded = 1; /* Name of needed library */ | ||
| 307 | constexpr u32 ElfDtPltRelSz = 2; /* Size in bytes of PLT relocs */ | ||
| 308 | constexpr u32 ElfDtPltGot = 3; /* Processor defined value */ | ||
| 309 | constexpr u32 ElfDtHash = 4; /* Address of symbol hash table */ | ||
| 310 | constexpr u32 ElfDtStrtab = 5; /* Address of string table */ | ||
| 311 | constexpr u32 ElfDtSymtab = 6; /* Address of symbol table */ | ||
| 312 | constexpr u32 ElfDtRela = 7; /* Address of Rela relocs */ | ||
| 313 | constexpr u32 ElfDtRelasz = 8; /* Total size of Rela relocs */ | ||
| 314 | constexpr u32 ElfDtRelaent = 9; /* Size of one Rela reloc */ | ||
| 315 | constexpr u32 ElfDtStrsz = 10; /* Size of string table */ | ||
| 316 | constexpr u32 ElfDtSyment = 11; /* Size of one symbol table entry */ | ||
| 317 | constexpr u32 ElfDtInit = 12; /* Address of init function */ | ||
| 318 | constexpr u32 ElfDtFini = 13; /* Address of termination function */ | ||
| 319 | constexpr u32 ElfDtRel = 17; /* Address of Rel relocs */ | ||
| 320 | constexpr u32 ElfDtRelsz = 18; /* Total size of Rel relocs */ | ||
| 321 | constexpr u32 ElfDtRelent = 19; /* Size of one Rel reloc */ | ||
| 322 | constexpr u32 ElfDtPltRel = 20; /* Type of reloc in PLT */ | ||
| 323 | constexpr u32 ElfDtTextRel = 22; /* Reloc might modify .text */ | ||
| 324 | constexpr u32 ElfDtJmpRel = 23; /* Address of PLT relocs */ | ||
| 325 | constexpr u32 ElfDtBindNow = 24; /* Process relocations of object */ | ||
| 326 | constexpr u32 ElfDtInitArray = 25; /* Array with addresses of init fct */ | ||
| 327 | constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */ | ||
| 328 | constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */ | ||
| 329 | constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */ | ||
| 330 | constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */ | ||
| 331 | |||
| 332 | } // namespace ELF | ||
| 333 | } // namespace Common | ||
diff --git a/src/common/settings.h b/src/common/settings.h index a7bbfb0da..a507744a2 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -496,7 +496,7 @@ struct Values { | |||
| 496 | 496 | ||
| 497 | // Renderer | 497 | // Renderer |
| 498 | RangedSetting<RendererBackend> renderer_backend{ | 498 | RangedSetting<RendererBackend> renderer_backend{ |
| 499 | RendererBackend::OpenGL, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; | 499 | RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; |
| 500 | BasicSetting<bool> renderer_debug{false, "debug"}; | 500 | BasicSetting<bool> renderer_debug{false, "debug"}; |
| 501 | BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"}; | 501 | BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"}; |
| 502 | BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; | 502 | BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; |
diff --git a/src/core/arm/symbols.cpp b/src/core/arm/symbols.cpp index 4aa1a1ee1..0259c7ea2 100644 --- a/src/core/arm/symbols.cpp +++ b/src/core/arm/symbols.cpp | |||
| @@ -3,73 +3,14 @@ | |||
| 3 | 3 | ||
| 4 | #include "common/bit_field.h" | 4 | #include "common/bit_field.h" |
| 5 | #include "common/common_funcs.h" | 5 | #include "common/common_funcs.h" |
| 6 | #include "common/elf.h" | ||
| 6 | #include "core/arm/symbols.h" | 7 | #include "core/arm/symbols.h" |
| 7 | #include "core/core.h" | 8 | #include "core/core.h" |
| 8 | #include "core/memory.h" | 9 | #include "core/memory.h" |
| 9 | 10 | ||
| 10 | namespace Core { | 11 | using namespace Common::ELF; |
| 11 | namespace { | ||
| 12 | |||
| 13 | constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; | ||
| 14 | constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5; | ||
| 15 | constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6; | ||
| 16 | constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11; | ||
| 17 | |||
| 18 | enum class ELFSymbolType : u8 { | ||
| 19 | None = 0, | ||
| 20 | Object = 1, | ||
| 21 | Function = 2, | ||
| 22 | Section = 3, | ||
| 23 | File = 4, | ||
| 24 | Common = 5, | ||
| 25 | TLS = 6, | ||
| 26 | }; | ||
| 27 | |||
| 28 | enum class ELFSymbolBinding : u8 { | ||
| 29 | Local = 0, | ||
| 30 | Global = 1, | ||
| 31 | Weak = 2, | ||
| 32 | }; | ||
| 33 | |||
| 34 | enum class ELFSymbolVisibility : u8 { | ||
| 35 | Default = 0, | ||
| 36 | Internal = 1, | ||
| 37 | Hidden = 2, | ||
| 38 | Protected = 3, | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct ELF64Symbol { | ||
| 42 | u32 name_index; | ||
| 43 | union { | ||
| 44 | u8 info; | ||
| 45 | |||
| 46 | BitField<0, 4, ELFSymbolType> type; | ||
| 47 | BitField<4, 4, ELFSymbolBinding> binding; | ||
| 48 | }; | ||
| 49 | ELFSymbolVisibility visibility; | ||
| 50 | u16 sh_index; | ||
| 51 | u64 value; | ||
| 52 | u64 size; | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size."); | ||
| 55 | |||
| 56 | struct ELF32Symbol { | ||
| 57 | u32 name_index; | ||
| 58 | u32 value; | ||
| 59 | u32 size; | ||
| 60 | union { | ||
| 61 | u8 info; | ||
| 62 | |||
| 63 | BitField<0, 4, ELFSymbolType> type; | ||
| 64 | BitField<4, 4, ELFSymbolBinding> binding; | ||
| 65 | }; | ||
| 66 | ELFSymbolVisibility visibility; | ||
| 67 | u16 sh_index; | ||
| 68 | }; | ||
| 69 | static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size."); | ||
| 70 | |||
| 71 | } // Anonymous namespace | ||
| 72 | 12 | ||
| 13 | namespace Core { | ||
| 73 | namespace Symbols { | 14 | namespace Symbols { |
| 74 | 15 | ||
| 75 | template <typename Word, typename ELFSymbol, typename ByteReader> | 16 | template <typename Word, typename ELFSymbol, typename ByteReader> |
| @@ -110,15 +51,15 @@ static Symbols GetSymbols(ByteReader ReadBytes) { | |||
| 110 | const Word value = ReadWord(dynamic_index + sizeof(Word)); | 51 | const Word value = ReadWord(dynamic_index + sizeof(Word)); |
| 111 | dynamic_index += 2 * sizeof(Word); | 52 | dynamic_index += 2 * sizeof(Word); |
| 112 | 53 | ||
| 113 | if (tag == ELF_DYNAMIC_TAG_NULL) { | 54 | if (tag == ElfDtNull) { |
| 114 | break; | 55 | break; |
| 115 | } | 56 | } |
| 116 | 57 | ||
| 117 | if (tag == ELF_DYNAMIC_TAG_STRTAB) { | 58 | if (tag == ElfDtStrtab) { |
| 118 | string_table_offset = value; | 59 | string_table_offset = value; |
| 119 | } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) { | 60 | } else if (tag == ElfDtSymtab) { |
| 120 | symbol_table_offset = value; | 61 | symbol_table_offset = value; |
| 121 | } else if (tag == ELF_DYNAMIC_TAG_SYMENT) { | 62 | } else if (tag == ElfDtSyment) { |
| 122 | symbol_entry_size = value; | 63 | symbol_entry_size = value; |
| 123 | } | 64 | } |
| 124 | } | 65 | } |
| @@ -134,14 +75,14 @@ static Symbols GetSymbols(ByteReader ReadBytes) { | |||
| 134 | ELFSymbol symbol{}; | 75 | ELFSymbol symbol{}; |
| 135 | ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); | 76 | ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol)); |
| 136 | 77 | ||
| 137 | VAddr string_offset = string_table_offset + symbol.name_index; | 78 | VAddr string_offset = string_table_offset + symbol.st_name; |
| 138 | std::string name; | 79 | std::string name; |
| 139 | for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { | 80 | for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) { |
| 140 | name += static_cast<char>(c); | 81 | name += static_cast<char>(c); |
| 141 | } | 82 | } |
| 142 | 83 | ||
| 143 | symbol_index += symbol_entry_size; | 84 | symbol_index += symbol_entry_size; |
| 144 | out[name] = std::make_pair(symbol.value, symbol.size); | 85 | out[name] = std::make_pair(symbol.st_value, symbol.st_size); |
| 145 | } | 86 | } |
| 146 | 87 | ||
| 147 | return out; | 88 | return out; |
| @@ -152,9 +93,9 @@ Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) { | |||
| 152 | [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; | 93 | [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }}; |
| 153 | 94 | ||
| 154 | if (is_64) { | 95 | if (is_64) { |
| 155 | return GetSymbols<u64, ELF64Symbol>(ReadBytes); | 96 | return GetSymbols<u64, Elf64_Sym>(ReadBytes); |
| 156 | } else { | 97 | } else { |
| 157 | return GetSymbols<u32, ELF32Symbol>(ReadBytes); | 98 | return GetSymbols<u32, Elf32_Sym>(ReadBytes); |
| 158 | } | 99 | } |
| 159 | } | 100 | } |
| 160 | 101 | ||
| @@ -164,9 +105,9 @@ Symbols GetSymbols(std::span<const u8> data, bool is_64) { | |||
| 164 | }}; | 105 | }}; |
| 165 | 106 | ||
| 166 | if (is_64) { | 107 | if (is_64) { |
| 167 | return GetSymbols<u64, ELF64Symbol>(ReadBytes); | 108 | return GetSymbols<u64, Elf64_Sym>(ReadBytes); |
| 168 | } else { | 109 | } else { |
| 169 | return GetSymbols<u32, ELF32Symbol>(ReadBytes); | 110 | return GetSymbols<u32, Elf32_Sym>(ReadBytes); |
| 170 | } | 111 | } |
| 171 | } | 112 | } |
| 172 | 113 | ||
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 68ab33e46..8d64990ed 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -20,15 +20,16 @@ template <typename Readable, typename Buffer, typename Callback> | |||
| 20 | static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { | 20 | static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { |
| 21 | static_assert(std::is_trivial_v<Buffer>); | 21 | static_assert(std::is_trivial_v<Buffer>); |
| 22 | auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))}; | 22 | auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))}; |
| 23 | r.async_read_some(boost_buffer, [&](const boost::system::error_code& error, size_t bytes_read) { | 23 | r.async_read_some( |
| 24 | if (!error.failed()) { | 24 | boost_buffer, [&, c](const boost::system::error_code& error, size_t bytes_read) { |
| 25 | const u8* buffer_start = reinterpret_cast<const u8*>(&buffer); | 25 | if (!error.failed()) { |
| 26 | std::span<const u8> received_data{buffer_start, buffer_start + bytes_read}; | 26 | const u8* buffer_start = reinterpret_cast<const u8*>(&buffer); |
| 27 | c(received_data); | 27 | std::span<const u8> received_data{buffer_start, buffer_start + bytes_read}; |
| 28 | } | 28 | c(received_data); |
| 29 | } | ||
| 29 | 30 | ||
| 30 | AsyncReceiveInto(r, buffer, c); | 31 | AsyncReceiveInto(r, buffer, c); |
| 31 | }); | 32 | }); |
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | template <typename Readable, typename Buffer> | 35 | template <typename Readable, typename Buffer> |
| @@ -65,7 +66,7 @@ public: | |||
| 65 | } | 66 | } |
| 66 | stopped = true; | 67 | stopped = true; |
| 67 | 68 | ||
| 68 | signal_pipe.write_some(boost::asio::buffer(&thread, sizeof(thread))); | 69 | boost::asio::write(signal_pipe, boost::asio::buffer(&thread, sizeof(thread))); |
| 69 | return true; | 70 | return true; |
| 70 | } | 71 | } |
| 71 | 72 | ||
| @@ -74,7 +75,7 @@ public: | |||
| 74 | } | 75 | } |
| 75 | 76 | ||
| 76 | void WriteToClient(std::span<const u8> data) override { | 77 | void WriteToClient(std::span<const u8> data) override { |
| 77 | client_socket.write_some(boost::asio::buffer(data.data(), data.size_bytes())); | 78 | boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes())); |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | void SetActiveThread(Kernel::KThread* thread) override { | 81 | void SetActiveThread(Kernel::KThread* thread) override { |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 0c36069a6..f52d78829 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -34,6 +34,65 @@ constexpr char GDB_STUB_REPLY_ERR[] = "E01"; | |||
| 34 | constexpr char GDB_STUB_REPLY_OK[] = "OK"; | 34 | constexpr char GDB_STUB_REPLY_OK[] = "OK"; |
| 35 | constexpr char GDB_STUB_REPLY_EMPTY[] = ""; | 35 | constexpr char GDB_STUB_REPLY_EMPTY[] = ""; |
| 36 | 36 | ||
| 37 | static u8 CalculateChecksum(std::string_view data) { | ||
| 38 | return std::accumulate(data.begin(), data.end(), u8{0}, | ||
| 39 | [](u8 lhs, u8 rhs) { return static_cast<u8>(lhs + rhs); }); | ||
| 40 | } | ||
| 41 | |||
| 42 | static std::string EscapeGDB(std::string_view data) { | ||
| 43 | std::string escaped; | ||
| 44 | escaped.reserve(data.size()); | ||
| 45 | |||
| 46 | for (char c : data) { | ||
| 47 | switch (c) { | ||
| 48 | case '#': | ||
| 49 | escaped += "}\x03"; | ||
| 50 | break; | ||
| 51 | case '$': | ||
| 52 | escaped += "}\x04"; | ||
| 53 | break; | ||
| 54 | case '*': | ||
| 55 | escaped += "}\x0a"; | ||
| 56 | break; | ||
| 57 | case '}': | ||
| 58 | escaped += "}\x5d"; | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | escaped += c; | ||
| 62 | break; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | return escaped; | ||
| 67 | } | ||
| 68 | |||
| 69 | static std::string EscapeXML(std::string_view data) { | ||
| 70 | std::string escaped; | ||
| 71 | escaped.reserve(data.size()); | ||
| 72 | |||
| 73 | for (char c : data) { | ||
| 74 | switch (c) { | ||
| 75 | case '&': | ||
| 76 | escaped += "&"; | ||
| 77 | break; | ||
| 78 | case '"': | ||
| 79 | escaped += """; | ||
| 80 | break; | ||
| 81 | case '<': | ||
| 82 | escaped += "<"; | ||
| 83 | break; | ||
| 84 | case '>': | ||
| 85 | escaped += ">"; | ||
| 86 | break; | ||
| 87 | default: | ||
| 88 | escaped += c; | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | return escaped; | ||
| 94 | } | ||
| 95 | |||
| 37 | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) | 96 | GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) |
| 38 | : DebuggerFrontend(backend_), system{system_} { | 97 | : DebuggerFrontend(backend_), system{system_} { |
| 39 | if (system.CurrentProcess()->Is64BitProcess()) { | 98 | if (system.CurrentProcess()->Is64BitProcess()) { |
| @@ -255,6 +314,80 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | |||
| 255 | } | 314 | } |
| 256 | } | 315 | } |
| 257 | 316 | ||
| 317 | // Structure offsets are from Atmosphere | ||
| 318 | // See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp | ||
| 319 | |||
| 320 | static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory, | ||
| 321 | const Kernel::KThread* thread) { | ||
| 322 | // Read thread type from TLS | ||
| 323 | const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)}; | ||
| 324 | const VAddr argument_thread_type{thread->GetArgument()}; | ||
| 325 | |||
| 326 | if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||
| 327 | // Probably not created by nnsdk, no name available. | ||
| 328 | return std::nullopt; | ||
| 329 | } | ||
| 330 | |||
| 331 | if (!tls_thread_type) { | ||
| 332 | return std::nullopt; | ||
| 333 | } | ||
| 334 | |||
| 335 | const u16 version{memory.Read16(tls_thread_type + 0x26)}; | ||
| 336 | VAddr name_pointer{}; | ||
| 337 | if (version == 1) { | ||
| 338 | name_pointer = memory.Read32(tls_thread_type + 0xe4); | ||
| 339 | } else { | ||
| 340 | name_pointer = memory.Read32(tls_thread_type + 0xe8); | ||
| 341 | } | ||
| 342 | |||
| 343 | if (!name_pointer) { | ||
| 344 | // No name provided. | ||
| 345 | return std::nullopt; | ||
| 346 | } | ||
| 347 | |||
| 348 | return memory.ReadCString(name_pointer, 256); | ||
| 349 | } | ||
| 350 | |||
| 351 | static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory, | ||
| 352 | const Kernel::KThread* thread) { | ||
| 353 | // Read thread type from TLS | ||
| 354 | const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)}; | ||
| 355 | const VAddr argument_thread_type{thread->GetArgument()}; | ||
| 356 | |||
| 357 | if (argument_thread_type && tls_thread_type != argument_thread_type) { | ||
| 358 | // Probably not created by nnsdk, no name available. | ||
| 359 | return std::nullopt; | ||
| 360 | } | ||
| 361 | |||
| 362 | if (!tls_thread_type) { | ||
| 363 | return std::nullopt; | ||
| 364 | } | ||
| 365 | |||
| 366 | const u16 version{memory.Read16(tls_thread_type + 0x46)}; | ||
| 367 | VAddr name_pointer{}; | ||
| 368 | if (version == 1) { | ||
| 369 | name_pointer = memory.Read64(tls_thread_type + 0x1a0); | ||
| 370 | } else { | ||
| 371 | name_pointer = memory.Read64(tls_thread_type + 0x1a8); | ||
| 372 | } | ||
| 373 | |||
| 374 | if (!name_pointer) { | ||
| 375 | // No name provided. | ||
| 376 | return std::nullopt; | ||
| 377 | } | ||
| 378 | |||
| 379 | return memory.ReadCString(name_pointer, 256); | ||
| 380 | } | ||
| 381 | |||
| 382 | static std::optional<std::string> GetThreadName(Core::System& system, | ||
| 383 | const Kernel::KThread* thread) { | ||
| 384 | if (system.CurrentProcess()->Is64BitProcess()) { | ||
| 385 | return GetNameFromThreadType64(system.Memory(), thread); | ||
| 386 | } else { | ||
| 387 | return GetNameFromThreadType32(system.Memory(), thread); | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 258 | static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) { | 391 | static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) { |
| 259 | switch (thread->GetWaitReasonForDebugging()) { | 392 | switch (thread->GetWaitReasonForDebugging()) { |
| 260 | case Kernel::ThreadWaitReasonForDebugging::Sleep: | 393 | case Kernel::ThreadWaitReasonForDebugging::Sleep: |
| @@ -289,6 +422,18 @@ static std::string GetThreadState(const Kernel::KThread* thread) { | |||
| 289 | } | 422 | } |
| 290 | } | 423 | } |
| 291 | 424 | ||
| 425 | static std::string PaginateBuffer(std::string_view buffer, std::string_view request) { | ||
| 426 | const auto amount{request.substr(request.find(',') + 1)}; | ||
| 427 | const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))}; | ||
| 428 | const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))}; | ||
| 429 | |||
| 430 | if (offset_val + amount_val > buffer.size()) { | ||
| 431 | return fmt::format("l{}", buffer.substr(offset_val)); | ||
| 432 | } else { | ||
| 433 | return fmt::format("m{}", buffer.substr(offset_val, amount_val)); | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 292 | void GDBStub::HandleQuery(std::string_view command) { | 437 | void GDBStub::HandleQuery(std::string_view command) { |
| 293 | if (command.starts_with("TStatus")) { | 438 | if (command.starts_with("TStatus")) { |
| 294 | // no tracepoint support | 439 | // no tracepoint support |
| @@ -297,18 +442,8 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 297 | SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;" | 442 | SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;" |
| 298 | "vContSupported+;QStartNoAckMode+"); | 443 | "vContSupported+;QStartNoAckMode+"); |
| 299 | } else if (command.starts_with("Xfer:features:read:target.xml:")) { | 444 | } else if (command.starts_with("Xfer:features:read:target.xml:")) { |
| 300 | const auto offset{command.substr(30)}; | ||
| 301 | const auto amount{command.substr(command.find(',') + 1)}; | ||
| 302 | |||
| 303 | const auto offset_val{static_cast<u64>(strtoll(offset.data(), nullptr, 16))}; | ||
| 304 | const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))}; | ||
| 305 | const auto target_xml{arch->GetTargetXML()}; | 445 | const auto target_xml{arch->GetTargetXML()}; |
| 306 | 446 | SendReply(PaginateBuffer(target_xml, command.substr(30))); | |
| 307 | if (offset_val + amount_val > target_xml.size()) { | ||
| 308 | SendReply("l" + target_xml.substr(offset_val)); | ||
| 309 | } else { | ||
| 310 | SendReply("m" + target_xml.substr(offset_val, amount_val)); | ||
| 311 | } | ||
| 312 | } else if (command.starts_with("Offsets")) { | 447 | } else if (command.starts_with("Offsets")) { |
| 313 | Loader::AppLoader::Modules modules; | 448 | Loader::AppLoader::Modules modules; |
| 314 | system.GetAppLoader().ReadNSOModules(modules); | 449 | system.GetAppLoader().ReadNSOModules(modules); |
| @@ -321,6 +456,20 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 321 | SendReply(fmt::format("TextSeg={:x}", | 456 | SendReply(fmt::format("TextSeg={:x}", |
| 322 | system.CurrentProcess()->PageTable().GetCodeRegionStart())); | 457 | system.CurrentProcess()->PageTable().GetCodeRegionStart())); |
| 323 | } | 458 | } |
| 459 | } else if (command.starts_with("Xfer:libraries:read::")) { | ||
| 460 | Loader::AppLoader::Modules modules; | ||
| 461 | system.GetAppLoader().ReadNSOModules(modules); | ||
| 462 | |||
| 463 | std::string buffer; | ||
| 464 | buffer += R"(<?xml version="1.0"?>)"; | ||
| 465 | buffer += "<library-list>"; | ||
| 466 | for (const auto& [base, name] : modules) { | ||
| 467 | buffer += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)", | ||
| 468 | EscapeXML(name), base); | ||
| 469 | } | ||
| 470 | buffer += "</library-list>"; | ||
| 471 | |||
| 472 | SendReply(PaginateBuffer(buffer, command.substr(21))); | ||
| 324 | } else if (command.starts_with("fThreadInfo")) { | 473 | } else if (command.starts_with("fThreadInfo")) { |
| 325 | // beginning of list | 474 | // beginning of list |
| 326 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); | 475 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); |
| @@ -332,20 +481,26 @@ void GDBStub::HandleQuery(std::string_view command) { | |||
| 332 | } else if (command.starts_with("sThreadInfo")) { | 481 | } else if (command.starts_with("sThreadInfo")) { |
| 333 | // end of list | 482 | // end of list |
| 334 | SendReply("l"); | 483 | SendReply("l"); |
| 335 | } else if (command.starts_with("Xfer:threads:read")) { | 484 | } else if (command.starts_with("Xfer:threads:read::")) { |
| 336 | std::string buffer; | 485 | std::string buffer; |
| 337 | buffer += R"(l<?xml version="1.0"?>)"; | 486 | buffer += R"(<?xml version="1.0"?>)"; |
| 338 | buffer += "<threads>"; | 487 | buffer += "<threads>"; |
| 339 | 488 | ||
| 340 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); | 489 | const auto& threads = system.GlobalSchedulerContext().GetThreadList(); |
| 341 | for (const auto& thread : threads) { | 490 | for (const auto* thread : threads) { |
| 342 | buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="Thread {:d}">{}</thread>)", | 491 | auto thread_name{GetThreadName(system, thread)}; |
| 492 | if (!thread_name) { | ||
| 493 | thread_name = fmt::format("Thread {:d}", thread->GetThreadID()); | ||
| 494 | } | ||
| 495 | |||
| 496 | buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)", | ||
| 343 | thread->GetThreadID(), thread->GetActiveCore(), | 497 | thread->GetThreadID(), thread->GetActiveCore(), |
| 344 | thread->GetThreadID(), GetThreadState(thread)); | 498 | EscapeXML(*thread_name), GetThreadState(thread)); |
| 345 | } | 499 | } |
| 346 | 500 | ||
| 347 | buffer += "</threads>"; | 501 | buffer += "</threads>"; |
| 348 | SendReply(buffer); | 502 | |
| 503 | SendReply(PaginateBuffer(buffer, command.substr(19))); | ||
| 349 | } else if (command.starts_with("Attached")) { | 504 | } else if (command.starts_with("Attached")) { |
| 350 | SendReply("0"); | 505 | SendReply("0"); |
| 351 | } else if (command.starts_with("StartNoAckMode")) { | 506 | } else if (command.starts_with("StartNoAckMode")) { |
| @@ -438,14 +593,10 @@ std::optional<std::string> GDBStub::DetachCommand() { | |||
| 438 | return data.substr(1, data.size() - 4); | 593 | return data.substr(1, data.size() - 4); |
| 439 | } | 594 | } |
| 440 | 595 | ||
| 441 | u8 GDBStub::CalculateChecksum(std::string_view data) { | ||
| 442 | return std::accumulate(data.begin(), data.end(), u8{0}, | ||
| 443 | [](u8 lhs, u8 rhs) { return static_cast<u8>(lhs + rhs); }); | ||
| 444 | } | ||
| 445 | |||
| 446 | void GDBStub::SendReply(std::string_view data) { | 596 | void GDBStub::SendReply(std::string_view data) { |
| 447 | const auto output{ | 597 | const auto escaped{EscapeGDB(data)}; |
| 448 | fmt::format("{}{}{}{:02x}", GDB_STUB_START, data, GDB_STUB_END, CalculateChecksum(data))}; | 598 | const auto output{fmt::format("{}{}{}{:02x}", GDB_STUB_START, escaped, GDB_STUB_END, |
| 599 | CalculateChecksum(escaped))}; | ||
| 449 | LOG_TRACE(Debug_GDBStub, "Writing reply: {}", output); | 600 | LOG_TRACE(Debug_GDBStub, "Writing reply: {}", output); |
| 450 | 601 | ||
| 451 | // C++ string support is complete rubbish | 602 | // C++ string support is complete rubbish |
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index aa1f7de6c..1bb638187 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h | |||
| @@ -34,7 +34,6 @@ private: | |||
| 34 | std::optional<std::string> DetachCommand(); | 34 | std::optional<std::string> DetachCommand(); |
| 35 | Kernel::KThread* GetThreadByID(u64 thread_id); | 35 | Kernel::KThread* GetThreadByID(u64 thread_id); |
| 36 | 36 | ||
| 37 | static u8 CalculateChecksum(std::string_view data); | ||
| 38 | void SendReply(std::string_view data); | 37 | void SendReply(std::string_view data); |
| 39 | void SendStatus(char status); | 38 | void SendStatus(char status); |
| 40 | 39 | ||
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index ab9ce6a86..940334f59 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -198,6 +198,10 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 198 | resource_limit_release_hint = false; | 198 | resource_limit_release_hint = false; |
| 199 | cpu_time = 0; | 199 | cpu_time = 0; |
| 200 | 200 | ||
| 201 | // Set debug context. | ||
| 202 | stack_top = user_stack_top; | ||
| 203 | argument = arg; | ||
| 204 | |||
| 201 | // Clear our stack parameters. | 205 | // Clear our stack parameters. |
| 202 | std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0, | 206 | std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0, |
| 203 | sizeof(StackParameters)); | 207 | sizeof(StackParameters)); |
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 60ae0da78..f4d83f99a 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -660,6 +660,14 @@ public: | |||
| 660 | void IfDummyThreadTryWait(); | 660 | void IfDummyThreadTryWait(); |
| 661 | void IfDummyThreadEndWait(); | 661 | void IfDummyThreadEndWait(); |
| 662 | 662 | ||
| 663 | [[nodiscard]] uintptr_t GetArgument() const { | ||
| 664 | return argument; | ||
| 665 | } | ||
| 666 | |||
| 667 | [[nodiscard]] VAddr GetUserStackTop() const { | ||
| 668 | return stack_top; | ||
| 669 | } | ||
| 670 | |||
| 663 | private: | 671 | private: |
| 664 | static constexpr size_t PriorityInheritanceCountMax = 10; | 672 | static constexpr size_t PriorityInheritanceCountMax = 10; |
| 665 | union SyncObjectBuffer { | 673 | union SyncObjectBuffer { |
| @@ -791,6 +799,8 @@ private: | |||
| 791 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; | 799 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; |
| 792 | VAddr mutex_wait_address_for_debugging{}; | 800 | VAddr mutex_wait_address_for_debugging{}; |
| 793 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | 801 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; |
| 802 | uintptr_t argument; | ||
| 803 | VAddr stack_top; | ||
| 794 | 804 | ||
| 795 | public: | 805 | public: |
| 796 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; | 806 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; |
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 3eae1ae35..32e0708ba 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -61,6 +61,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | last_update_timestamp = shared_memory->gesture_lifo.timestamp; | 63 | last_update_timestamp = shared_memory->gesture_lifo.timestamp; |
| 64 | UpdateGestureSharedMemory(gesture, time_difference); | ||
| 64 | } | 65 | } |
| 65 | 66 | ||
| 66 | void Controller_Gesture::ReadTouchInput() { | 67 | void Controller_Gesture::ReadTouchInput() { |
| @@ -94,8 +95,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | |||
| 94 | return false; | 95 | return false; |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | 98 | void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, |
| 98 | GestureProperties& gesture, | ||
| 99 | f32 time_difference) { | 99 | f32 time_difference) { |
| 100 | GestureType type = GestureType::Idle; | 100 | GestureType type = GestureType::Idle; |
| 101 | GestureAttribute attributes{}; | 101 | GestureAttribute attributes{}; |
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index c62a341bf..0d6099ea0 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -107,8 +107,7 @@ private: | |||
| 107 | bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); | 107 | bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); |
| 108 | 108 | ||
| 109 | // Updates the shared memory to the next state | 109 | // Updates the shared memory to the next state |
| 110 | void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, | 110 | void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference); |
| 111 | f32 time_difference); | ||
| 112 | 111 | ||
| 113 | // Initializes new gesture | 112 | // Initializes new gesture |
| 114 | void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); | 113 | void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); |
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 9e32f3e60..d2a91d913 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -5,7 +5,9 @@ | |||
| 5 | #include "core/core_timing.h" | 5 | #include "core/core_timing.h" |
| 6 | #include "core/hle/ipc_helpers.h" | 6 | #include "core/hle/ipc_helpers.h" |
| 7 | #include "core/hle/kernel/k_shared_memory.h" | 7 | #include "core/hle/kernel/k_shared_memory.h" |
| 8 | #include "core/hle/kernel/k_transfer_memory.h" | ||
| 8 | #include "core/hle/kernel/kernel.h" | 9 | #include "core/hle/kernel/kernel.h" |
| 10 | #include "core/hle/service/hid/errors.h" | ||
| 9 | #include "core/hle/service/hid/irs.h" | 11 | #include "core/hle/service/hid/irs.h" |
| 10 | 12 | ||
| 11 | namespace Service::HID { | 13 | namespace Service::HID { |
| @@ -38,21 +40,32 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} { | |||
| 38 | } | 40 | } |
| 39 | 41 | ||
| 40 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { | 42 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 41 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 43 | IPC::RequestParser rp{ctx}; |
| 44 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 45 | |||
| 46 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | ||
| 47 | applet_resource_user_id); | ||
| 42 | 48 | ||
| 43 | IPC::ResponseBuilder rb{ctx, 2}; | 49 | IPC::ResponseBuilder rb{ctx, 2}; |
| 44 | rb.Push(ResultSuccess); | 50 | rb.Push(ResultSuccess); |
| 45 | } | 51 | } |
| 46 | 52 | ||
| 47 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { | 53 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 48 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 54 | IPC::RequestParser rp{ctx}; |
| 55 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 56 | |||
| 57 | LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", | ||
| 58 | applet_resource_user_id); | ||
| 49 | 59 | ||
| 50 | IPC::ResponseBuilder rb{ctx, 2}; | 60 | IPC::ResponseBuilder rb{ctx, 2}; |
| 51 | rb.Push(ResultSuccess); | 61 | rb.Push(ResultSuccess); |
| 52 | } | 62 | } |
| 53 | 63 | ||
| 54 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 64 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| 55 | LOG_DEBUG(Service_IRS, "called"); | 65 | IPC::RequestParser rp{ctx}; |
| 66 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 67 | |||
| 68 | LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id); | ||
| 56 | 69 | ||
| 57 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 70 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 58 | rb.Push(ResultSuccess); | 71 | rb.Push(ResultSuccess); |
| @@ -60,35 +73,109 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | |||
| 60 | } | 73 | } |
| 61 | 74 | ||
| 62 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { | 75 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { |
| 63 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 76 | IPC::RequestParser rp{ctx}; |
| 77 | struct Parameters { | ||
| 78 | IrCameraHandle camera_handle; | ||
| 79 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 80 | u64 applet_resource_user_id; | ||
| 81 | }; | ||
| 82 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 83 | |||
| 84 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 85 | |||
| 86 | LOG_WARNING(Service_IRS, | ||
| 87 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 88 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 89 | parameters.applet_resource_user_id); | ||
| 64 | 90 | ||
| 65 | IPC::ResponseBuilder rb{ctx, 2}; | 91 | IPC::ResponseBuilder rb{ctx, 2}; |
| 66 | rb.Push(ResultSuccess); | 92 | rb.Push(ResultSuccess); |
| 67 | } | 93 | } |
| 68 | 94 | ||
| 69 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { | 95 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { |
| 70 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 96 | IPC::RequestParser rp{ctx}; |
| 97 | struct Parameters { | ||
| 98 | IrCameraHandle camera_handle; | ||
| 99 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 100 | u64 applet_resource_user_id; | ||
| 101 | PackedMomentProcessorConfig processor_config; | ||
| 102 | }; | ||
| 103 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); | ||
| 104 | |||
| 105 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 106 | |||
| 107 | LOG_WARNING(Service_IRS, | ||
| 108 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 109 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 110 | parameters.applet_resource_user_id); | ||
| 71 | 111 | ||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | 112 | IPC::ResponseBuilder rb{ctx, 2}; |
| 73 | rb.Push(ResultSuccess); | 113 | rb.Push(ResultSuccess); |
| 74 | } | 114 | } |
| 75 | 115 | ||
| 76 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { | 116 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { |
| 77 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 117 | IPC::RequestParser rp{ctx}; |
| 118 | struct Parameters { | ||
| 119 | IrCameraHandle camera_handle; | ||
| 120 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 121 | u64 applet_resource_user_id; | ||
| 122 | PackedClusteringProcessorConfig processor_config; | ||
| 123 | }; | ||
| 124 | static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size."); | ||
| 125 | |||
| 126 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 127 | |||
| 128 | LOG_WARNING(Service_IRS, | ||
| 129 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 130 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 131 | parameters.applet_resource_user_id); | ||
| 78 | 132 | ||
| 79 | IPC::ResponseBuilder rb{ctx, 2}; | 133 | IPC::ResponseBuilder rb{ctx, 2}; |
| 80 | rb.Push(ResultSuccess); | 134 | rb.Push(ResultSuccess); |
| 81 | } | 135 | } |
| 82 | 136 | ||
| 83 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { | 137 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { |
| 84 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 138 | IPC::RequestParser rp{ctx}; |
| 139 | struct Parameters { | ||
| 140 | IrCameraHandle camera_handle; | ||
| 141 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 142 | u64 applet_resource_user_id; | ||
| 143 | PackedImageTransferProcessorConfig processor_config; | ||
| 144 | u32 transfer_memory_size; | ||
| 145 | }; | ||
| 146 | static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size."); | ||
| 147 | |||
| 148 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 149 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; | ||
| 150 | |||
| 151 | auto t_mem = | ||
| 152 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); | ||
| 153 | |||
| 154 | LOG_WARNING(Service_IRS, | ||
| 155 | "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " | ||
| 156 | "applet_resource_user_id={}", | ||
| 157 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 158 | parameters.transfer_memory_size, parameters.applet_resource_user_id); | ||
| 85 | 159 | ||
| 86 | IPC::ResponseBuilder rb{ctx, 2}; | 160 | IPC::ResponseBuilder rb{ctx, 2}; |
| 87 | rb.Push(ResultSuccess); | 161 | rb.Push(ResultSuccess); |
| 88 | } | 162 | } |
| 89 | 163 | ||
| 90 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | 164 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { |
| 91 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 165 | IPC::RequestParser rp{ctx}; |
| 166 | struct Parameters { | ||
| 167 | IrCameraHandle camera_handle; | ||
| 168 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 169 | u64 applet_resource_user_id; | ||
| 170 | }; | ||
| 171 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 172 | |||
| 173 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 174 | |||
| 175 | LOG_WARNING(Service_IRS, | ||
| 176 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 177 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 178 | parameters.applet_resource_user_id); | ||
| 92 | 179 | ||
| 93 | IPC::ResponseBuilder rb{ctx, 5}; | 180 | IPC::ResponseBuilder rb{ctx, 5}; |
| 94 | rb.Push(ResultSuccess); | 181 | rb.Push(ResultSuccess); |
| @@ -97,71 +184,195 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | |||
| 97 | } | 184 | } |
| 98 | 185 | ||
| 99 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { | 186 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { |
| 100 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 187 | IPC::RequestParser rp{ctx}; |
| 188 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 189 | const auto processor_config{rp.PopRaw<PackedTeraPluginProcessorConfig>()}; | ||
| 190 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 191 | |||
| 192 | LOG_WARNING(Service_IRS, | ||
| 193 | "(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, " | ||
| 194 | "applet_resource_user_id={}", | ||
| 195 | camera_handle.npad_type, camera_handle.npad_id, processor_config.mode, | ||
| 196 | processor_config.required_mcu_version.major, | ||
| 197 | processor_config.required_mcu_version.minor, applet_resource_user_id); | ||
| 101 | 198 | ||
| 102 | IPC::ResponseBuilder rb{ctx, 2}; | 199 | IPC::ResponseBuilder rb{ctx, 2}; |
| 103 | rb.Push(ResultSuccess); | 200 | rb.Push(ResultSuccess); |
| 104 | } | 201 | } |
| 105 | 202 | ||
| 106 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { | 203 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { |
| 107 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 204 | IPC::RequestParser rp{ctx}; |
| 205 | const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()}; | ||
| 206 | |||
| 207 | if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid && | ||
| 208 | npad_id != Core::HID::NpadIdType::Handheld) { | ||
| 209 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 210 | rb.Push(InvalidNpadId); | ||
| 211 | return; | ||
| 212 | } | ||
| 213 | |||
| 214 | IrCameraHandle camera_handle{ | ||
| 215 | .npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)), | ||
| 216 | .npad_type = Core::HID::NpadStyleIndex::None, | ||
| 217 | }; | ||
| 218 | |||
| 219 | LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}", | ||
| 220 | npad_id, camera_handle.npad_id, camera_handle.npad_type); | ||
| 108 | 221 | ||
| 109 | IPC::ResponseBuilder rb{ctx, 3}; | 222 | IPC::ResponseBuilder rb{ctx, 3}; |
| 110 | rb.Push(ResultSuccess); | 223 | rb.Push(ResultSuccess); |
| 111 | rb.PushRaw<u32>(device_handle); | 224 | rb.PushRaw(camera_handle); |
| 112 | } | 225 | } |
| 113 | 226 | ||
| 114 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { | 227 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { |
| 115 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 228 | IPC::RequestParser rp{ctx}; |
| 229 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 230 | const auto processor_config{rp.PopRaw<PackedPointingProcessorConfig>()}; | ||
| 231 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 232 | |||
| 233 | LOG_WARNING( | ||
| 234 | Service_IRS, | ||
| 235 | "(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}", | ||
| 236 | camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major, | ||
| 237 | processor_config.required_mcu_version.minor, applet_resource_user_id); | ||
| 116 | 238 | ||
| 117 | IPC::ResponseBuilder rb{ctx, 2}; | 239 | IPC::ResponseBuilder rb{ctx, 2}; |
| 118 | rb.Push(ResultSuccess); | 240 | rb.Push(ResultSuccess); |
| 119 | } | 241 | } |
| 120 | 242 | ||
| 121 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { | 243 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { |
| 122 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 244 | IPC::RequestParser rp{ctx}; |
| 245 | struct Parameters { | ||
| 246 | IrCameraHandle camera_handle; | ||
| 247 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 248 | u64 applet_resource_user_id; | ||
| 249 | }; | ||
| 250 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 251 | |||
| 252 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 253 | |||
| 254 | LOG_WARNING(Service_IRS, | ||
| 255 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 256 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 257 | parameters.applet_resource_user_id); | ||
| 123 | 258 | ||
| 124 | IPC::ResponseBuilder rb{ctx, 2}; | 259 | IPC::ResponseBuilder rb{ctx, 2}; |
| 125 | rb.Push(ResultSuccess); | 260 | rb.Push(ResultSuccess); |
| 126 | } | 261 | } |
| 127 | 262 | ||
| 128 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { | 263 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { |
| 129 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 264 | IPC::RequestParser rp{ctx}; |
| 265 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 266 | const auto mcu_version{rp.PopRaw<PackedMcuVersion>()}; | ||
| 267 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 268 | |||
| 269 | LOG_WARNING( | ||
| 270 | Service_IRS, | ||
| 271 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}", | ||
| 272 | camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major, | ||
| 273 | mcu_version.minor); | ||
| 130 | 274 | ||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | 275 | IPC::ResponseBuilder rb{ctx, 2}; |
| 132 | rb.Push(ResultSuccess); | 276 | rb.Push(ResultSuccess); |
| 133 | } | 277 | } |
| 134 | 278 | ||
| 135 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { | 279 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 136 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 280 | IPC::RequestParser rp{ctx}; |
| 281 | struct Parameters { | ||
| 282 | IrCameraHandle camera_handle; | ||
| 283 | PackedFunctionLevel function_level; | ||
| 284 | u64 applet_resource_user_id; | ||
| 285 | }; | ||
| 286 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 287 | |||
| 288 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 289 | |||
| 290 | LOG_WARNING(Service_IRS, | ||
| 291 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 292 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 293 | parameters.applet_resource_user_id); | ||
| 137 | 294 | ||
| 138 | IPC::ResponseBuilder rb{ctx, 2}; | 295 | IPC::ResponseBuilder rb{ctx, 2}; |
| 139 | rb.Push(ResultSuccess); | 296 | rb.Push(ResultSuccess); |
| 140 | } | 297 | } |
| 141 | 298 | ||
| 142 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { | 299 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { |
| 143 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 300 | IPC::RequestParser rp{ctx}; |
| 301 | struct Parameters { | ||
| 302 | IrCameraHandle camera_handle; | ||
| 303 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 304 | u64 applet_resource_user_id; | ||
| 305 | PackedImageTransferProcessorExConfig processor_config; | ||
| 306 | u64 transfer_memory_size; | ||
| 307 | }; | ||
| 308 | static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size."); | ||
| 309 | |||
| 310 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 311 | const auto t_mem_handle{ctx.GetCopyHandle(0)}; | ||
| 312 | |||
| 313 | auto t_mem = | ||
| 314 | system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle); | ||
| 315 | |||
| 316 | LOG_WARNING(Service_IRS, | ||
| 317 | "(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, " | ||
| 318 | "applet_resource_user_id={}", | ||
| 319 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 320 | parameters.transfer_memory_size, parameters.applet_resource_user_id); | ||
| 144 | 321 | ||
| 145 | IPC::ResponseBuilder rb{ctx, 2}; | 322 | IPC::ResponseBuilder rb{ctx, 2}; |
| 146 | rb.Push(ResultSuccess); | 323 | rb.Push(ResultSuccess); |
| 147 | } | 324 | } |
| 148 | 325 | ||
| 149 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { | 326 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { |
| 150 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 327 | IPC::RequestParser rp{ctx}; |
| 328 | const auto camera_handle{rp.PopRaw<IrCameraHandle>()}; | ||
| 329 | const auto processor_config{rp.PopRaw<PackedIrLedProcessorConfig>()}; | ||
| 330 | const auto applet_resource_user_id{rp.Pop<u64>()}; | ||
| 331 | |||
| 332 | LOG_WARNING(Service_IRS, | ||
| 333 | "(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} " | ||
| 334 | "applet_resource_user_id={}", | ||
| 335 | camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target, | ||
| 336 | processor_config.required_mcu_version.major, | ||
| 337 | processor_config.required_mcu_version.minor, applet_resource_user_id); | ||
| 151 | 338 | ||
| 152 | IPC::ResponseBuilder rb{ctx, 2}; | 339 | IPC::ResponseBuilder rb{ctx, 2}; |
| 153 | rb.Push(ResultSuccess); | 340 | rb.Push(ResultSuccess); |
| 154 | } | 341 | } |
| 155 | 342 | ||
| 156 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { | 343 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { |
| 157 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 344 | IPC::RequestParser rp{ctx}; |
| 345 | struct Parameters { | ||
| 346 | IrCameraHandle camera_handle; | ||
| 347 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 348 | u64 applet_resource_user_id; | ||
| 349 | }; | ||
| 350 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 351 | |||
| 352 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 353 | |||
| 354 | LOG_WARNING(Service_IRS, | ||
| 355 | "(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}", | ||
| 356 | parameters.camera_handle.npad_type, parameters.camera_handle.npad_id, | ||
| 357 | parameters.applet_resource_user_id); | ||
| 158 | 358 | ||
| 159 | IPC::ResponseBuilder rb{ctx, 2}; | 359 | IPC::ResponseBuilder rb{ctx, 2}; |
| 160 | rb.Push(ResultSuccess); | 360 | rb.Push(ResultSuccess); |
| 161 | } | 361 | } |
| 162 | 362 | ||
| 163 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { | 363 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 164 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | 364 | IPC::RequestParser rp{ctx}; |
| 365 | struct Parameters { | ||
| 366 | PackedFunctionLevel function_level; | ||
| 367 | INSERT_PADDING_WORDS_NOINIT(1); | ||
| 368 | u64 applet_resource_user_id; | ||
| 369 | }; | ||
| 370 | static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); | ||
| 371 | |||
| 372 | const auto parameters{rp.PopRaw<Parameters>()}; | ||
| 373 | |||
| 374 | LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}", | ||
| 375 | parameters.function_level.function_level, parameters.applet_resource_user_id); | ||
| 165 | 376 | ||
| 166 | IPC::ResponseBuilder rb{ctx, 2}; | 377 | IPC::ResponseBuilder rb{ctx, 2}; |
| 167 | rb.Push(ResultSuccess); | 378 | rb.Push(ResultSuccess); |
diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index efb29d3fd..361dc2213 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include "core/hid/hid_types.h" | ||
| 6 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 7 | 8 | ||
| 8 | namespace Core { | 9 | namespace Core { |
| @@ -17,6 +18,235 @@ public: | |||
| 17 | ~IRS() override; | 18 | ~IRS() override; |
| 18 | 19 | ||
| 19 | private: | 20 | private: |
| 21 | // This is nn::irsensor::IrCameraStatus | ||
| 22 | enum IrCameraStatus : u32 { | ||
| 23 | Available, | ||
| 24 | Unsupported, | ||
| 25 | Unconnected, | ||
| 26 | }; | ||
| 27 | |||
| 28 | // This is nn::irsensor::IrCameraInternalStatus | ||
| 29 | enum IrCameraInternalStatus : u32 { | ||
| 30 | Stopped, | ||
| 31 | FirmwareUpdateNeeded, | ||
| 32 | Unkown2, | ||
| 33 | Unkown3, | ||
| 34 | Unkown4, | ||
| 35 | FirmwareVersionRequested, | ||
| 36 | FirmwareVersionIsInvalid, | ||
| 37 | Ready, | ||
| 38 | Setting, | ||
| 39 | }; | ||
| 40 | |||
| 41 | // This is nn::irsensor::detail::StatusManager::IrSensorMode | ||
| 42 | enum IrSensorMode : u64 { | ||
| 43 | None, | ||
| 44 | MomentProcessor, | ||
| 45 | ClusteringProcessor, | ||
| 46 | ImageTransferProcessor, | ||
| 47 | PointingProcessorMarker, | ||
| 48 | TeraPluginProcessor, | ||
| 49 | IrLedProcessor, | ||
| 50 | }; | ||
| 51 | |||
| 52 | // This is nn::irsensor::ImageProcessorStatus | ||
| 53 | enum ImageProcessorStatus : u8 { | ||
| 54 | stopped, | ||
| 55 | running, | ||
| 56 | }; | ||
| 57 | |||
| 58 | // This is nn::irsensor::ImageTransferProcessorFormat | ||
| 59 | enum ImageTransferProcessorFormat : u8 { | ||
| 60 | Size320x240, | ||
| 61 | Size160x120, | ||
| 62 | Size80x60, | ||
| 63 | Size40x30, | ||
| 64 | Size20x15, | ||
| 65 | }; | ||
| 66 | |||
| 67 | // This is nn::irsensor::AdaptiveClusteringMode | ||
| 68 | enum AdaptiveClusteringMode : u8 { | ||
| 69 | StaticFov, | ||
| 70 | DynamicFov, | ||
| 71 | }; | ||
| 72 | |||
| 73 | // This is nn::irsensor::AdaptiveClusteringTargetDistance | ||
| 74 | enum AdaptiveClusteringTargetDistance : u8 { | ||
| 75 | Near, | ||
| 76 | Middle, | ||
| 77 | Far, | ||
| 78 | }; | ||
| 79 | |||
| 80 | // This is nn::irsensor::IrsHandAnalysisMode | ||
| 81 | enum IrsHandAnalysisMode : u8 { | ||
| 82 | Silhouette, | ||
| 83 | Image, | ||
| 84 | SilhoueteAndImage, | ||
| 85 | SilhuetteOnly, | ||
| 86 | }; | ||
| 87 | |||
| 88 | // This is nn::irsensor::IrSensorFunctionLevel | ||
| 89 | enum IrSensorFunctionLevel : u8 { | ||
| 90 | unknown0, | ||
| 91 | unknown1, | ||
| 92 | unknown2, | ||
| 93 | unknown3, | ||
| 94 | unknown4, | ||
| 95 | }; | ||
| 96 | |||
| 97 | // This is nn::irsensor::IrCameraHandle | ||
| 98 | struct IrCameraHandle { | ||
| 99 | u8 npad_id{}; | ||
| 100 | Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; | ||
| 101 | INSERT_PADDING_BYTES(2); | ||
| 102 | }; | ||
| 103 | static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size"); | ||
| 104 | |||
| 105 | struct IrsRect { | ||
| 106 | s16 x; | ||
| 107 | s16 y; | ||
| 108 | s16 width; | ||
| 109 | s16 height; | ||
| 110 | }; | ||
| 111 | |||
| 112 | // This is nn::irsensor::PackedMcuVersion | ||
| 113 | struct PackedMcuVersion { | ||
| 114 | u16 major; | ||
| 115 | u16 minor; | ||
| 116 | }; | ||
| 117 | static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size"); | ||
| 118 | |||
| 119 | // This is nn::irsensor::MomentProcessorConfig | ||
| 120 | struct MomentProcessorConfig { | ||
| 121 | u64 exposire_time; | ||
| 122 | u8 light_target; | ||
| 123 | u8 gain; | ||
| 124 | u8 is_negative_used; | ||
| 125 | INSERT_PADDING_BYTES(7); | ||
| 126 | IrsRect window_of_interest; | ||
| 127 | u8 preprocess; | ||
| 128 | u8 preprocess_intensity_threshold; | ||
| 129 | INSERT_PADDING_BYTES(5); | ||
| 130 | }; | ||
| 131 | static_assert(sizeof(MomentProcessorConfig) == 0x28, | ||
| 132 | "MomentProcessorConfig is an invalid size"); | ||
| 133 | |||
| 134 | // This is nn::irsensor::PackedMomentProcessorConfig | ||
| 135 | struct PackedMomentProcessorConfig { | ||
| 136 | u64 exposire_time; | ||
| 137 | u8 light_target; | ||
| 138 | u8 gain; | ||
| 139 | u8 is_negative_used; | ||
| 140 | INSERT_PADDING_BYTES(5); | ||
| 141 | IrsRect window_of_interest; | ||
| 142 | PackedMcuVersion required_mcu_version; | ||
| 143 | u8 preprocess; | ||
| 144 | u8 preprocess_intensity_threshold; | ||
| 145 | INSERT_PADDING_BYTES(2); | ||
| 146 | }; | ||
| 147 | static_assert(sizeof(PackedMomentProcessorConfig) == 0x20, | ||
| 148 | "PackedMomentProcessorConfig is an invalid size"); | ||
| 149 | |||
| 150 | // This is nn::irsensor::ClusteringProcessorConfig | ||
| 151 | struct ClusteringProcessorConfig { | ||
| 152 | u64 exposire_time; | ||
| 153 | u32 light_target; | ||
| 154 | u32 gain; | ||
| 155 | u8 is_negative_used; | ||
| 156 | INSERT_PADDING_BYTES(7); | ||
| 157 | IrsRect window_of_interest; | ||
| 158 | u32 pixel_count_min; | ||
| 159 | u32 pixel_count_max; | ||
| 160 | u32 object_intensity_min; | ||
| 161 | u8 is_external_light_filter_enabled; | ||
| 162 | INSERT_PADDING_BYTES(3); | ||
| 163 | }; | ||
| 164 | static_assert(sizeof(ClusteringProcessorConfig) == 0x30, | ||
| 165 | "ClusteringProcessorConfig is an invalid size"); | ||
| 166 | |||
| 167 | // This is nn::irsensor::PackedClusteringProcessorConfig | ||
| 168 | struct PackedClusteringProcessorConfig { | ||
| 169 | u64 exposire_time; | ||
| 170 | u8 light_target; | ||
| 171 | u8 gain; | ||
| 172 | u8 is_negative_used; | ||
| 173 | INSERT_PADDING_BYTES(5); | ||
| 174 | IrsRect window_of_interest; | ||
| 175 | PackedMcuVersion required_mcu_version; | ||
| 176 | u32 pixel_count_min; | ||
| 177 | u32 pixel_count_max; | ||
| 178 | u32 object_intensity_min; | ||
| 179 | u8 is_external_light_filter_enabled; | ||
| 180 | INSERT_PADDING_BYTES(2); | ||
| 181 | }; | ||
| 182 | static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30, | ||
| 183 | "PackedClusteringProcessorConfig is an invalid size"); | ||
| 184 | |||
| 185 | // This is nn::irsensor::PackedImageTransferProcessorConfig | ||
| 186 | struct PackedImageTransferProcessorConfig { | ||
| 187 | u64 exposire_time; | ||
| 188 | u8 light_target; | ||
| 189 | u8 gain; | ||
| 190 | u8 is_negative_used; | ||
| 191 | INSERT_PADDING_BYTES(5); | ||
| 192 | PackedMcuVersion required_mcu_version; | ||
| 193 | u8 format; | ||
| 194 | INSERT_PADDING_BYTES(3); | ||
| 195 | }; | ||
| 196 | static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18, | ||
| 197 | "PackedImageTransferProcessorConfig is an invalid size"); | ||
| 198 | |||
| 199 | // This is nn::irsensor::PackedTeraPluginProcessorConfig | ||
| 200 | struct PackedTeraPluginProcessorConfig { | ||
| 201 | PackedMcuVersion required_mcu_version; | ||
| 202 | u8 mode; | ||
| 203 | INSERT_PADDING_BYTES(3); | ||
| 204 | }; | ||
| 205 | static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8, | ||
| 206 | "PackedTeraPluginProcessorConfig is an invalid size"); | ||
| 207 | |||
| 208 | // This is nn::irsensor::PackedPointingProcessorConfig | ||
| 209 | struct PackedPointingProcessorConfig { | ||
| 210 | IrsRect window_of_interest; | ||
| 211 | PackedMcuVersion required_mcu_version; | ||
| 212 | }; | ||
| 213 | static_assert(sizeof(PackedPointingProcessorConfig) == 0xC, | ||
| 214 | "PackedPointingProcessorConfig is an invalid size"); | ||
| 215 | |||
| 216 | // This is nn::irsensor::PackedFunctionLevel | ||
| 217 | struct PackedFunctionLevel { | ||
| 218 | IrSensorFunctionLevel function_level; | ||
| 219 | INSERT_PADDING_BYTES(3); | ||
| 220 | }; | ||
| 221 | static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size"); | ||
| 222 | |||
| 223 | // This is nn::irsensor::PackedImageTransferProcessorExConfig | ||
| 224 | struct PackedImageTransferProcessorExConfig { | ||
| 225 | u64 exposire_time; | ||
| 226 | u8 light_target; | ||
| 227 | u8 gain; | ||
| 228 | u8 is_negative_used; | ||
| 229 | INSERT_PADDING_BYTES(5); | ||
| 230 | PackedMcuVersion required_mcu_version; | ||
| 231 | ImageTransferProcessorFormat origin_format; | ||
| 232 | ImageTransferProcessorFormat trimming_format; | ||
| 233 | u16 trimming_start_x; | ||
| 234 | u16 trimming_start_y; | ||
| 235 | u8 is_external_light_filter_enabled; | ||
| 236 | INSERT_PADDING_BYTES(3); | ||
| 237 | }; | ||
| 238 | static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20, | ||
| 239 | "PackedImageTransferProcessorExConfig is an invalid size"); | ||
| 240 | |||
| 241 | // This is nn::irsensor::PackedIrLedProcessorConfig | ||
| 242 | struct PackedIrLedProcessorConfig { | ||
| 243 | PackedMcuVersion required_mcu_version; | ||
| 244 | u8 light_target; | ||
| 245 | INSERT_PADDING_BYTES(3); | ||
| 246 | }; | ||
| 247 | static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8, | ||
| 248 | "PackedIrLedProcessorConfig is an invalid size"); | ||
| 249 | |||
| 20 | void ActivateIrsensor(Kernel::HLERequestContext& ctx); | 250 | void ActivateIrsensor(Kernel::HLERequestContext& ctx); |
| 21 | void DeactivateIrsensor(Kernel::HLERequestContext& ctx); | 251 | void DeactivateIrsensor(Kernel::HLERequestContext& ctx); |
| 22 | void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx); | 252 | void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx); |
| @@ -35,8 +265,6 @@ private: | |||
| 35 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); | 265 | void RunIrLedProcessor(Kernel::HLERequestContext& ctx); |
| 36 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); | 266 | void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); |
| 37 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); | 267 | void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); |
| 38 | |||
| 39 | const u32 device_handle{0xABCD}; | ||
| 40 | }; | 268 | }; |
| 41 | 269 | ||
| 42 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { | 270 | class IRS_SYS final : public ServiceFramework<IRS_SYS> { |
diff --git a/src/core/hle/service/jit/jit_context.cpp b/src/core/hle/service/jit/jit_context.cpp index 19bd85b6c..4ed3f02e2 100644 --- a/src/core/hle/service/jit/jit_context.cpp +++ b/src/core/hle/service/jit/jit_context.cpp | |||
| @@ -11,10 +11,13 @@ | |||
| 11 | #include "common/alignment.h" | 11 | #include "common/alignment.h" |
| 12 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 13 | #include "common/div_ceil.h" | 13 | #include "common/div_ceil.h" |
| 14 | #include "common/elf.h" | ||
| 14 | #include "common/logging/log.h" | 15 | #include "common/logging/log.h" |
| 15 | #include "core/hle/service/jit/jit_context.h" | 16 | #include "core/hle/service/jit/jit_context.h" |
| 16 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 17 | 18 | ||
| 19 | using namespace Common::ELF; | ||
| 20 | |||
| 18 | namespace Service::JIT { | 21 | namespace Service::JIT { |
| 19 | 22 | ||
| 20 | constexpr std::array<u8, 8> SVC0_ARM64 = { | 23 | constexpr std::array<u8, 8> SVC0_ARM64 = { |
| @@ -26,25 +29,6 @@ constexpr std::array HELPER_FUNCTIONS{ | |||
| 26 | "_stop", "_resolve", "_panic", "memcpy", "memmove", "memset", | 29 | "_stop", "_resolve", "_panic", "memcpy", "memmove", "memset", |
| 27 | }; | 30 | }; |
| 28 | 31 | ||
| 29 | struct Elf64_Dyn { | ||
| 30 | u64 d_tag; | ||
| 31 | u64 d_un; | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct Elf64_Rela { | ||
| 35 | u64 r_offset; | ||
| 36 | u64 r_info; | ||
| 37 | s64 r_addend; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static constexpr u32 Elf64_RelaType(const Elf64_Rela* rela) { | ||
| 41 | return static_cast<u32>(rela->r_info); | ||
| 42 | } | ||
| 43 | |||
| 44 | constexpr int DT_RELA = 7; /* Address of Rela relocs */ | ||
| 45 | constexpr int DT_RELASZ = 8; /* Total size of Rela relocs */ | ||
| 46 | constexpr int R_AARCH64_RELATIVE = 1027; /* Adjust by program base. */ | ||
| 47 | |||
| 48 | constexpr size_t STACK_ALIGN = 16; | 32 | constexpr size_t STACK_ALIGN = 16; |
| 49 | 33 | ||
| 50 | class JITContextImpl; | 34 | class JITContextImpl; |
| @@ -206,17 +190,17 @@ public: | |||
| 206 | if (!dyn.d_tag) { | 190 | if (!dyn.d_tag) { |
| 207 | break; | 191 | break; |
| 208 | } | 192 | } |
| 209 | if (dyn.d_tag == DT_RELA) { | 193 | if (dyn.d_tag == ElfDtRela) { |
| 210 | rela_dyn = dyn.d_un; | 194 | rela_dyn = dyn.d_un.d_ptr; |
| 211 | } | 195 | } |
| 212 | if (dyn.d_tag == DT_RELASZ) { | 196 | if (dyn.d_tag == ElfDtRelasz) { |
| 213 | num_rela = dyn.d_un / sizeof(Elf64_Rela); | 197 | num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela); |
| 214 | } | 198 | } |
| 215 | } | 199 | } |
| 216 | 200 | ||
| 217 | for (size_t i = 0; i < num_rela; i++) { | 201 | for (size_t i = 0; i < num_rela; i++) { |
| 218 | const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))}; | 202 | const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))}; |
| 219 | if (Elf64_RelaType(&rela) != R_AARCH64_RELATIVE) { | 203 | if (Elf64RelType(rela.r_info) != ElfAArch64Relative) { |
| 220 | continue; | 204 | continue; |
| 221 | } | 205 | } |
| 222 | const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; | 206 | const VAddr contents{callbacks->MemoryRead64(rela.r_offset)}; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index d7db77aff..4b3d5efd6 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp | |||
| @@ -89,14 +89,6 @@ Status BufferQueueConsumer::AcquireBuffer(BufferItem* out_buffer, | |||
| 89 | 89 | ||
| 90 | LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot); | 90 | LOG_DEBUG(Service_NVFlinger, "acquiring slot={}", slot); |
| 91 | 91 | ||
| 92 | // If the front buffer is still being tracked, update its slot state | ||
| 93 | if (core->StillTracking(*front)) { | ||
| 94 | slots[slot].acquire_called = true; | ||
| 95 | slots[slot].needs_cleanup_on_release = false; | ||
| 96 | slots[slot].buffer_state = BufferState::Acquired; | ||
| 97 | slots[slot].fence = Fence::NoFence(); | ||
| 98 | } | ||
| 99 | |||
| 100 | // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to | 92 | // If the buffer has previously been acquired by the consumer, set graphic_buffer to nullptr to |
| 101 | // avoid unnecessarily remapping this buffer on the consumer side. | 93 | // avoid unnecessarily remapping this buffer on the consumer side. |
| 102 | if (out_buffer->acquire_called) { | 94 | if (out_buffer->acquire_called) { |
| @@ -139,26 +131,11 @@ Status BufferQueueConsumer::ReleaseBuffer(s32 slot, u64 frame_number, const Fenc | |||
| 139 | ++current; | 131 | ++current; |
| 140 | } | 132 | } |
| 141 | 133 | ||
| 142 | if (slots[slot].buffer_state == BufferState::Acquired) { | 134 | slots[slot].buffer_state = BufferState::Free; |
| 143 | slots[slot].fence = release_fence; | ||
| 144 | slots[slot].buffer_state = BufferState::Free; | ||
| 145 | |||
| 146 | listener = core->connected_producer_listener; | ||
| 147 | |||
| 148 | LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot); | ||
| 149 | } else if (slots[slot].needs_cleanup_on_release) { | ||
| 150 | LOG_DEBUG(Service_NVFlinger, "releasing a stale buffer slot {} (state = {})", slot, | ||
| 151 | slots[slot].buffer_state); | ||
| 152 | 135 | ||
| 153 | slots[slot].needs_cleanup_on_release = false; | 136 | listener = core->connected_producer_listener; |
| 154 | 137 | ||
| 155 | return Status::StaleBufferSlot; | 138 | LOG_DEBUG(Service_NVFlinger, "releasing slot {}", slot); |
| 156 | } else { | ||
| 157 | LOG_ERROR(Service_NVFlinger, "attempted to release buffer slot {} but its state was {}", | ||
| 158 | slot, slots[slot].buffer_state); | ||
| 159 | |||
| 160 | return Status::BadValue; | ||
| 161 | } | ||
| 162 | 139 | ||
| 163 | core->SignalDequeueCondition(); | 140 | core->SignalDequeueCondition(); |
| 164 | } | 141 | } |
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index d4e8b44d0..ea4a14ea4 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp | |||
| @@ -84,10 +84,6 @@ void BufferQueueCore::FreeBufferLocked(s32 slot) { | |||
| 84 | 84 | ||
| 85 | slots[slot].graphic_buffer.reset(); | 85 | slots[slot].graphic_buffer.reset(); |
| 86 | 86 | ||
| 87 | if (slots[slot].buffer_state == BufferState::Acquired) { | ||
| 88 | slots[slot].needs_cleanup_on_release = true; | ||
| 89 | } | ||
| 90 | |||
| 91 | slots[slot].buffer_state = BufferState::Free; | 87 | slots[slot].buffer_state = BufferState::Free; |
| 92 | slots[slot].frame_number = UINT32_MAX; | 88 | slots[slot].frame_number = UINT32_MAX; |
| 93 | slots[slot].acquire_called = false; | 89 | slots[slot].acquire_called = false; |
diff --git a/src/core/hle/service/nvflinger/buffer_slot.h b/src/core/hle/service/nvflinger/buffer_slot.h index 6b3e87446..0cd0e9964 100644 --- a/src/core/hle/service/nvflinger/buffer_slot.h +++ b/src/core/hle/service/nvflinger/buffer_slot.h | |||
| @@ -31,7 +31,6 @@ struct BufferSlot final { | |||
| 31 | u64 frame_number{}; | 31 | u64 frame_number{}; |
| 32 | Fence fence; | 32 | Fence fence; |
| 33 | bool acquire_called{}; | 33 | bool acquire_called{}; |
| 34 | bool needs_cleanup_on_release{}; | ||
| 35 | bool attached_by_consumer{}; | 34 | bool attached_by_consumer{}; |
| 36 | bool is_preallocated{}; | 35 | bool is_preallocated{}; |
| 37 | }; | 36 | }; |
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index cf5933699..dfb10c34f 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include "common/common_funcs.h" | 7 | #include "common/common_funcs.h" |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "common/elf.h" | ||
| 9 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 10 | #include "core/hle/kernel/code_set.h" | 11 | #include "core/hle/kernel/code_set.h" |
| 11 | #include "core/hle/kernel/k_page_table.h" | 12 | #include "core/hle/kernel/k_page_table.h" |
| @@ -13,159 +14,7 @@ | |||
| 13 | #include "core/loader/elf.h" | 14 | #include "core/loader/elf.h" |
| 14 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 15 | 16 | ||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 17 | using namespace Common::ELF; |
| 17 | // ELF Header Constants | ||
| 18 | |||
| 19 | // File type | ||
| 20 | enum ElfType { | ||
| 21 | ET_NONE = 0, | ||
| 22 | ET_REL = 1, | ||
| 23 | ET_EXEC = 2, | ||
| 24 | ET_DYN = 3, | ||
| 25 | ET_CORE = 4, | ||
| 26 | ET_LOPROC = 0xFF00, | ||
| 27 | ET_HIPROC = 0xFFFF, | ||
| 28 | }; | ||
| 29 | |||
| 30 | // Machine/Architecture | ||
| 31 | enum ElfMachine { | ||
| 32 | EM_NONE = 0, | ||
| 33 | EM_M32 = 1, | ||
| 34 | EM_SPARC = 2, | ||
| 35 | EM_386 = 3, | ||
| 36 | EM_68K = 4, | ||
| 37 | EM_88K = 5, | ||
| 38 | EM_860 = 7, | ||
| 39 | EM_MIPS = 8 | ||
| 40 | }; | ||
| 41 | |||
| 42 | // File version | ||
| 43 | #define EV_NONE 0 | ||
| 44 | #define EV_CURRENT 1 | ||
| 45 | |||
| 46 | // Identification index | ||
| 47 | #define EI_MAG0 0 | ||
| 48 | #define EI_MAG1 1 | ||
| 49 | #define EI_MAG2 2 | ||
| 50 | #define EI_MAG3 3 | ||
| 51 | #define EI_CLASS 4 | ||
| 52 | #define EI_DATA 5 | ||
| 53 | #define EI_VERSION 6 | ||
| 54 | #define EI_PAD 7 | ||
| 55 | #define EI_NIDENT 16 | ||
| 56 | |||
| 57 | // Sections constants | ||
| 58 | |||
| 59 | // Section types | ||
| 60 | #define SHT_NULL 0 | ||
| 61 | #define SHT_PROGBITS 1 | ||
| 62 | #define SHT_SYMTAB 2 | ||
| 63 | #define SHT_STRTAB 3 | ||
| 64 | #define SHT_RELA 4 | ||
| 65 | #define SHT_HASH 5 | ||
| 66 | #define SHT_DYNAMIC 6 | ||
| 67 | #define SHT_NOTE 7 | ||
| 68 | #define SHT_NOBITS 8 | ||
| 69 | #define SHT_REL 9 | ||
| 70 | #define SHT_SHLIB 10 | ||
| 71 | #define SHT_DYNSYM 11 | ||
| 72 | #define SHT_LOPROC 0x70000000 | ||
| 73 | #define SHT_HIPROC 0x7FFFFFFF | ||
| 74 | #define SHT_LOUSER 0x80000000 | ||
| 75 | #define SHT_HIUSER 0xFFFFFFFF | ||
| 76 | |||
| 77 | // Section flags | ||
| 78 | enum ElfSectionFlags { | ||
| 79 | SHF_WRITE = 0x1, | ||
| 80 | SHF_ALLOC = 0x2, | ||
| 81 | SHF_EXECINSTR = 0x4, | ||
| 82 | SHF_MASKPROC = 0xF0000000, | ||
| 83 | }; | ||
| 84 | |||
| 85 | // Segment types | ||
| 86 | #define PT_NULL 0 | ||
| 87 | #define PT_LOAD 1 | ||
| 88 | #define PT_DYNAMIC 2 | ||
| 89 | #define PT_INTERP 3 | ||
| 90 | #define PT_NOTE 4 | ||
| 91 | #define PT_SHLIB 5 | ||
| 92 | #define PT_PHDR 6 | ||
| 93 | #define PT_LOPROC 0x70000000 | ||
| 94 | #define PT_HIPROC 0x7FFFFFFF | ||
| 95 | |||
| 96 | // Segment flags | ||
| 97 | #define PF_X 0x1 | ||
| 98 | #define PF_W 0x2 | ||
| 99 | #define PF_R 0x4 | ||
| 100 | #define PF_MASKPROC 0xF0000000 | ||
| 101 | |||
| 102 | typedef unsigned int Elf32_Addr; | ||
| 103 | typedef unsigned short Elf32_Half; | ||
| 104 | typedef unsigned int Elf32_Off; | ||
| 105 | typedef signed int Elf32_Sword; | ||
| 106 | typedef unsigned int Elf32_Word; | ||
| 107 | |||
| 108 | //////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 109 | // ELF file header | ||
| 110 | |||
| 111 | struct Elf32_Ehdr { | ||
| 112 | unsigned char e_ident[EI_NIDENT]; | ||
| 113 | Elf32_Half e_type; | ||
| 114 | Elf32_Half e_machine; | ||
| 115 | Elf32_Word e_version; | ||
| 116 | Elf32_Addr e_entry; | ||
| 117 | Elf32_Off e_phoff; | ||
| 118 | Elf32_Off e_shoff; | ||
| 119 | Elf32_Word e_flags; | ||
| 120 | Elf32_Half e_ehsize; | ||
| 121 | Elf32_Half e_phentsize; | ||
| 122 | Elf32_Half e_phnum; | ||
| 123 | Elf32_Half e_shentsize; | ||
| 124 | Elf32_Half e_shnum; | ||
| 125 | Elf32_Half e_shstrndx; | ||
| 126 | }; | ||
| 127 | |||
| 128 | // Section header | ||
| 129 | struct Elf32_Shdr { | ||
| 130 | Elf32_Word sh_name; | ||
| 131 | Elf32_Word sh_type; | ||
| 132 | Elf32_Word sh_flags; | ||
| 133 | Elf32_Addr sh_addr; | ||
| 134 | Elf32_Off sh_offset; | ||
| 135 | Elf32_Word sh_size; | ||
| 136 | Elf32_Word sh_link; | ||
| 137 | Elf32_Word sh_info; | ||
| 138 | Elf32_Word sh_addralign; | ||
| 139 | Elf32_Word sh_entsize; | ||
| 140 | }; | ||
| 141 | |||
| 142 | // Segment header | ||
| 143 | struct Elf32_Phdr { | ||
| 144 | Elf32_Word p_type; | ||
| 145 | Elf32_Off p_offset; | ||
| 146 | Elf32_Addr p_vaddr; | ||
| 147 | Elf32_Addr p_paddr; | ||
| 148 | Elf32_Word p_filesz; | ||
| 149 | Elf32_Word p_memsz; | ||
| 150 | Elf32_Word p_flags; | ||
| 151 | Elf32_Word p_align; | ||
| 152 | }; | ||
| 153 | |||
| 154 | // Symbol table entry | ||
| 155 | struct Elf32_Sym { | ||
| 156 | Elf32_Word st_name; | ||
| 157 | Elf32_Addr st_value; | ||
| 158 | Elf32_Word st_size; | ||
| 159 | unsigned char st_info; | ||
| 160 | unsigned char st_other; | ||
| 161 | Elf32_Half st_shndx; | ||
| 162 | }; | ||
| 163 | |||
| 164 | // Relocation entries | ||
| 165 | struct Elf32_Rel { | ||
| 166 | Elf32_Addr r_offset; | ||
| 167 | Elf32_Word r_info; | ||
| 168 | }; | ||
| 169 | 18 | ||
| 170 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 19 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 171 | // ElfReader class | 20 | // ElfReader class |
| @@ -193,11 +42,11 @@ public: | |||
| 193 | } | 42 | } |
| 194 | 43 | ||
| 195 | // Quick accessors | 44 | // Quick accessors |
| 196 | ElfType GetType() const { | 45 | u16 GetType() const { |
| 197 | return (ElfType)(header->e_type); | 46 | return header->e_type; |
| 198 | } | 47 | } |
| 199 | ElfMachine GetMachine() const { | 48 | u16 GetMachine() const { |
| 200 | return (ElfMachine)(header->e_machine); | 49 | return header->e_machine; |
| 201 | } | 50 | } |
| 202 | VAddr GetEntryPoint() const { | 51 | VAddr GetEntryPoint() const { |
| 203 | return entryPoint; | 52 | return entryPoint; |
| @@ -220,13 +69,13 @@ public: | |||
| 220 | const u8* GetSectionDataPtr(int section) const { | 69 | const u8* GetSectionDataPtr(int section) const { |
| 221 | if (section < 0 || section >= header->e_shnum) | 70 | if (section < 0 || section >= header->e_shnum) |
| 222 | return nullptr; | 71 | return nullptr; |
| 223 | if (sections[section].sh_type != SHT_NOBITS) | 72 | if (sections[section].sh_type != ElfShtNobits) |
| 224 | return GetPtr(sections[section].sh_offset); | 73 | return GetPtr(sections[section].sh_offset); |
| 225 | else | 74 | else |
| 226 | return nullptr; | 75 | return nullptr; |
| 227 | } | 76 | } |
| 228 | bool IsCodeSection(int section) const { | 77 | bool IsCodeSection(int section) const { |
| 229 | return sections[section].sh_type == SHT_PROGBITS; | 78 | return sections[section].sh_type == ElfShtProgBits; |
| 230 | } | 79 | } |
| 231 | const u8* GetSegmentPtr(int segment) { | 80 | const u8* GetSegmentPtr(int segment) { |
| 232 | return GetPtr(segments[segment].p_offset); | 81 | return GetPtr(segments[segment].p_offset); |
| @@ -256,7 +105,7 @@ ElfReader::ElfReader(void* ptr) { | |||
| 256 | } | 105 | } |
| 257 | 106 | ||
| 258 | const char* ElfReader::GetSectionName(int section) const { | 107 | const char* ElfReader::GetSectionName(int section) const { |
| 259 | if (sections[section].sh_type == SHT_NULL) | 108 | if (sections[section].sh_type == ElfShtNull) |
| 260 | return nullptr; | 109 | return nullptr; |
| 261 | 110 | ||
| 262 | int name_offset = sections[section].sh_name; | 111 | int name_offset = sections[section].sh_name; |
| @@ -272,7 +121,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 272 | LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); | 121 | LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); |
| 273 | 122 | ||
| 274 | // Should we relocate? | 123 | // Should we relocate? |
| 275 | relocate = (header->e_type != ET_EXEC); | 124 | relocate = (header->e_type != ElfTypeExec); |
| 276 | 125 | ||
| 277 | if (relocate) { | 126 | if (relocate) { |
| 278 | LOG_DEBUG(Loader, "Relocatable module"); | 127 | LOG_DEBUG(Loader, "Relocatable module"); |
| @@ -288,7 +137,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 288 | u64 total_image_size = 0; | 137 | u64 total_image_size = 0; |
| 289 | for (unsigned int i = 0; i < header->e_phnum; ++i) { | 138 | for (unsigned int i = 0; i < header->e_phnum; ++i) { |
| 290 | const Elf32_Phdr* p = &segments[i]; | 139 | const Elf32_Phdr* p = &segments[i]; |
| 291 | if (p->p_type == PT_LOAD) { | 140 | if (p->p_type == ElfPtLoad) { |
| 292 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; | 141 | total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; |
| 293 | } | 142 | } |
| 294 | } | 143 | } |
| @@ -303,14 +152,14 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) { | |||
| 303 | LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, | 152 | LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, |
| 304 | p->p_vaddr, p->p_filesz, p->p_memsz); | 153 | p->p_vaddr, p->p_filesz, p->p_memsz); |
| 305 | 154 | ||
| 306 | if (p->p_type == PT_LOAD) { | 155 | if (p->p_type == ElfPtLoad) { |
| 307 | Kernel::CodeSet::Segment* codeset_segment; | 156 | Kernel::CodeSet::Segment* codeset_segment; |
| 308 | u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X); | 157 | u32 permission_flags = p->p_flags & (ElfPfRead | ElfPfWrite | ElfPfExec); |
| 309 | if (permission_flags == (PF_R | PF_X)) { | 158 | if (permission_flags == (ElfPfRead | ElfPfExec)) { |
| 310 | codeset_segment = &codeset.CodeSegment(); | 159 | codeset_segment = &codeset.CodeSegment(); |
| 311 | } else if (permission_flags == (PF_R)) { | 160 | } else if (permission_flags == (ElfPfRead)) { |
| 312 | codeset_segment = &codeset.RODataSegment(); | 161 | codeset_segment = &codeset.RODataSegment(); |
| 313 | } else if (permission_flags == (PF_R | PF_W)) { | 162 | } else if (permission_flags == (ElfPfRead | ElfPfWrite)) { |
| 314 | codeset_segment = &codeset.DataSegment(); | 163 | codeset_segment = &codeset.DataSegment(); |
| 315 | } else { | 164 | } else { |
| 316 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, | 165 | LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 7d0cb8fce..3a4646289 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -595,8 +595,8 @@ void Maxwell3D::DrawArrays() { | |||
| 595 | 595 | ||
| 596 | std::optional<u64> Maxwell3D::GetQueryResult() { | 596 | std::optional<u64> Maxwell3D::GetQueryResult() { |
| 597 | switch (regs.query.query_get.select) { | 597 | switch (regs.query.query_get.select) { |
| 598 | case Regs::QuerySelect::Zero: | 598 | case Regs::QuerySelect::Payload: |
| 599 | return 0; | 599 | return regs.query.query_sequence; |
| 600 | case Regs::QuerySelect::SamplesPassed: | 600 | case Regs::QuerySelect::SamplesPassed: |
| 601 | // Deferred. | 601 | // Deferred. |
| 602 | rasterizer->Query(regs.query.QueryAddress(), QueryType::SamplesPassed, | 602 | rasterizer->Query(regs.query.QueryAddress(), QueryType::SamplesPassed, |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index c0c2c7d96..434ba0877 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -93,7 +93,7 @@ public: | |||
| 93 | }; | 93 | }; |
| 94 | 94 | ||
| 95 | enum class QuerySelect : u32 { | 95 | enum class QuerySelect : u32 { |
| 96 | Zero = 0, | 96 | Payload = 0, |
| 97 | TimeElapsed = 2, | 97 | TimeElapsed = 2, |
| 98 | TransformFeedbackPrimitivesGenerated = 11, | 98 | TransformFeedbackPrimitivesGenerated = 11, |
| 99 | PrimitivesGenerated = 18, | 99 | PrimitivesGenerated = 18, |
diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp index a5dd33fb2..4eb3913ee 100644 --- a/src/video_core/vulkan_common/vulkan_library.cpp +++ b/src/video_core/vulkan_common/vulkan_library.cpp | |||
| @@ -5,11 +5,13 @@ | |||
| 5 | 5 | ||
| 6 | #include "common/dynamic_library.h" | 6 | #include "common/dynamic_library.h" |
| 7 | #include "common/fs/path_util.h" | 7 | #include "common/fs/path_util.h" |
| 8 | #include "common/logging/log.h" | ||
| 8 | #include "video_core/vulkan_common/vulkan_library.h" | 9 | #include "video_core/vulkan_common/vulkan_library.h" |
| 9 | 10 | ||
| 10 | namespace Vulkan { | 11 | namespace Vulkan { |
| 11 | 12 | ||
| 12 | Common::DynamicLibrary OpenLibrary() { | 13 | Common::DynamicLibrary OpenLibrary() { |
| 14 | LOG_DEBUG(Render_Vulkan, "Looking for a Vulkan library"); | ||
| 13 | Common::DynamicLibrary library; | 15 | Common::DynamicLibrary library; |
| 14 | #ifdef __APPLE__ | 16 | #ifdef __APPLE__ |
| 15 | // Check if a path to a specific Vulkan library has been specified. | 17 | // Check if a path to a specific Vulkan library has been specified. |
| @@ -22,9 +24,11 @@ Common::DynamicLibrary OpenLibrary() { | |||
| 22 | } | 24 | } |
| 23 | #else | 25 | #else |
| 24 | std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); | 26 | std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); |
| 27 | LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename); | ||
| 25 | if (!library.Open(filename.c_str())) { | 28 | if (!library.Open(filename.c_str())) { |
| 26 | // Android devices may not have libvulkan.so.1, only libvulkan.so. | 29 | // Android devices may not have libvulkan.so.1, only libvulkan.so. |
| 27 | filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); | 30 | filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); |
| 31 | LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename); | ||
| 28 | void(library.Open(filename.c_str())); | 32 | void(library.Open(filename.c_str())); |
| 29 | } | 33 | } |
| 30 | #endif | 34 | #endif |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 07df9675d..9259ca15e 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -30,6 +30,8 @@ add_executable(yuzu | |||
| 30 | applets/qt_web_browser_scripts.h | 30 | applets/qt_web_browser_scripts.h |
| 31 | bootmanager.cpp | 31 | bootmanager.cpp |
| 32 | bootmanager.h | 32 | bootmanager.h |
| 33 | check_vulkan.cpp | ||
| 34 | check_vulkan.h | ||
| 33 | compatdb.ui | 35 | compatdb.ui |
| 34 | compatibility_list.cpp | 36 | compatibility_list.cpp |
| 35 | compatibility_list.h | 37 | compatibility_list.h |
| @@ -187,7 +189,7 @@ if (ENABLE_QT_TRANSLATION) | |||
| 187 | # Update source TS file if enabled | 189 | # Update source TS file if enabled |
| 188 | if (GENERATE_QT_TRANSLATION) | 190 | if (GENERATE_QT_TRANSLATION) |
| 189 | get_target_property(SRCS yuzu SOURCES) | 191 | get_target_property(SRCS yuzu SOURCES) |
| 190 | qt5_create_translation(QM_FILES | 192 | qt_create_translation(QM_FILES |
| 191 | ${SRCS} | 193 | ${SRCS} |
| 192 | ${UIS} | 194 | ${UIS} |
| 193 | ${YUZU_QT_LANGUAGES}/en.ts | 195 | ${YUZU_QT_LANGUAGES}/en.ts |
| @@ -203,7 +205,7 @@ if (ENABLE_QT_TRANSLATION) | |||
| 203 | list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts) | 205 | list(REMOVE_ITEM LANGUAGES_TS ${YUZU_QT_LANGUAGES}/en.ts) |
| 204 | 206 | ||
| 205 | # Compile TS files to QM files | 207 | # Compile TS files to QM files |
| 206 | qt5_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) | 208 | qt_add_translation(LANGUAGES_QM ${LANGUAGES_TS}) |
| 207 | 209 | ||
| 208 | # Build a QRC file from the QM file list | 210 | # Build a QRC file from the QM file list |
| 209 | set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) | 211 | set(LANGUAGES_QRC ${CMAKE_CURRENT_BINARY_DIR}/languages.qrc) |
| @@ -215,7 +217,7 @@ if (ENABLE_QT_TRANSLATION) | |||
| 215 | file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>") | 217 | file(APPEND ${LANGUAGES_QRC} "</qresource></RCC>") |
| 216 | 218 | ||
| 217 | # Add the QRC file to package in all QM files | 219 | # Add the QRC file to package in all QM files |
| 218 | qt5_add_resources(LANGUAGES ${LANGUAGES_QRC}) | 220 | qt_add_resources(LANGUAGES ${LANGUAGES_QRC}) |
| 219 | else() | 221 | else() |
| 220 | set(LANGUAGES) | 222 | set(LANGUAGES) |
| 221 | endif() | 223 | endif() |
| @@ -236,7 +238,11 @@ if (APPLE) | |||
| 236 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) | 238 | set_target_properties(yuzu PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) |
| 237 | elseif(WIN32) | 239 | elseif(WIN32) |
| 238 | # compile as a win32 gui application instead of a console application | 240 | # compile as a win32 gui application instead of a console application |
| 239 | target_link_libraries(yuzu PRIVATE Qt5::WinMain) | 241 | if (QT_VERSION VERSION_GREATER 6) |
| 242 | target_link_libraries(yuzu PRIVATE Qt6::EntryPointPrivate) | ||
| 243 | else() | ||
| 244 | target_link_libraries(yuzu PRIVATE Qt5::WinMain) | ||
| 245 | endif() | ||
| 240 | if(MSVC) | 246 | if(MSVC) |
| 241 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") | 247 | set_target_properties(yuzu PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") |
| 242 | elseif(MINGW) | 248 | elseif(MINGW) |
| @@ -247,7 +253,7 @@ endif() | |||
| 247 | create_target_directory_groups(yuzu) | 253 | create_target_directory_groups(yuzu) |
| 248 | 254 | ||
| 249 | target_link_libraries(yuzu PRIVATE common core input_common video_core) | 255 | target_link_libraries(yuzu PRIVATE common core input_common video_core) |
| 250 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::Widgets) | 256 | target_link_libraries(yuzu PRIVATE Boost::boost glad Qt::Widgets) |
| 251 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) | 257 | target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) |
| 252 | 258 | ||
| 253 | target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) | 259 | target_include_directories(yuzu PRIVATE ../../externals/Vulkan-Headers/include) |
| @@ -255,7 +261,7 @@ if (NOT WIN32) | |||
| 255 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) | 261 | target_include_directories(yuzu PRIVATE ${Qt5Gui_PRIVATE_INCLUDE_DIRS}) |
| 256 | endif() | 262 | endif() |
| 257 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | 263 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") |
| 258 | target_link_libraries(yuzu PRIVATE Qt5::DBus) | 264 | target_link_libraries(yuzu PRIVATE Qt::DBus) |
| 259 | endif() | 265 | endif() |
| 260 | 266 | ||
| 261 | target_compile_definitions(yuzu PRIVATE | 267 | target_compile_definitions(yuzu PRIVATE |
| @@ -291,7 +297,7 @@ if (USE_DISCORD_PRESENCE) | |||
| 291 | endif() | 297 | endif() |
| 292 | 298 | ||
| 293 | if (YUZU_USE_QT_WEB_ENGINE) | 299 | if (YUZU_USE_QT_WEB_ENGINE) |
| 294 | target_link_libraries(yuzu PRIVATE Qt5::WebEngineCore Qt5::WebEngineWidgets) | 300 | target_link_libraries(yuzu PRIVATE Qt::WebEngineCore Qt::WebEngineWidgets) |
| 295 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) | 301 | target_compile_definitions(yuzu PRIVATE -DYUZU_USE_QT_WEB_ENGINE) |
| 296 | endif () | 302 | endif () |
| 297 | 303 | ||
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index aae2de2f8..bde465485 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -752,7 +752,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { | |||
| 752 | input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); | 752 | input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); |
| 753 | 753 | ||
| 754 | if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { | 754 | if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { |
| 755 | QCursor::setPos(mapToGlobal({center_x, center_y})); | 755 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); |
| 756 | } | 756 | } |
| 757 | 757 | ||
| 758 | emit MouseActivity(); | 758 | emit MouseActivity(); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 87c559e7a..d01538039 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <mutex> | 10 | #include <mutex> |
| 11 | 11 | ||
| 12 | #include <QImage> | 12 | #include <QImage> |
| 13 | #include <QStringList> | ||
| 13 | #include <QThread> | 14 | #include <QThread> |
| 14 | #include <QTouchEvent> | 15 | #include <QTouchEvent> |
| 15 | #include <QWidget> | 16 | #include <QWidget> |
| @@ -20,7 +21,6 @@ | |||
| 20 | class GRenderWindow; | 21 | class GRenderWindow; |
| 21 | class GMainWindow; | 22 | class GMainWindow; |
| 22 | class QKeyEvent; | 23 | class QKeyEvent; |
| 23 | class QStringList; | ||
| 24 | 24 | ||
| 25 | namespace Core { | 25 | namespace Core { |
| 26 | enum class SystemResultStatus : u32; | 26 | enum class SystemResultStatus : u32; |
diff --git a/src/yuzu/check_vulkan.cpp b/src/yuzu/check_vulkan.cpp new file mode 100644 index 000000000..e6d66ab34 --- /dev/null +++ b/src/yuzu/check_vulkan.cpp | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "video_core/vulkan_common/vulkan_wrapper.h" | ||
| 5 | |||
| 6 | #include <filesystem> | ||
| 7 | #include <fstream> | ||
| 8 | #include "common/fs/fs.h" | ||
| 9 | #include "common/fs/path_util.h" | ||
| 10 | #include "common/logging/log.h" | ||
| 11 | #include "video_core/vulkan_common/vulkan_instance.h" | ||
| 12 | #include "video_core/vulkan_common/vulkan_library.h" | ||
| 13 | #include "yuzu/check_vulkan.h" | ||
| 14 | #include "yuzu/uisettings.h" | ||
| 15 | |||
| 16 | constexpr char TEMP_FILE_NAME[] = "vulkan_check"; | ||
| 17 | |||
| 18 | bool CheckVulkan() { | ||
| 19 | if (UISettings::values.has_broken_vulkan) { | ||
| 20 | return true; | ||
| 21 | } | ||
| 22 | |||
| 23 | LOG_DEBUG(Frontend, "Checking presence of Vulkan"); | ||
| 24 | |||
| 25 | const auto fs_config_loc = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir); | ||
| 26 | const auto temp_file_loc = fs_config_loc / TEMP_FILE_NAME; | ||
| 27 | |||
| 28 | if (std::filesystem::exists(temp_file_loc)) { | ||
| 29 | LOG_WARNING(Frontend, "Detected recovery from previous failed Vulkan initialization"); | ||
| 30 | |||
| 31 | UISettings::values.has_broken_vulkan = true; | ||
| 32 | std::filesystem::remove(temp_file_loc); | ||
| 33 | return false; | ||
| 34 | } | ||
| 35 | |||
| 36 | std::ofstream temp_file_handle(temp_file_loc); | ||
| 37 | temp_file_handle.close(); | ||
| 38 | |||
| 39 | try { | ||
| 40 | Vulkan::vk::InstanceDispatch dld; | ||
| 41 | const Common::DynamicLibrary library = Vulkan::OpenLibrary(); | ||
| 42 | const Vulkan::vk::Instance instance = | ||
| 43 | Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); | ||
| 44 | |||
| 45 | } catch (const Vulkan::vk::Exception& exception) { | ||
| 46 | LOG_ERROR(Frontend, "Failed to initialize Vulkan: {}", exception.what()); | ||
| 47 | // Don't set has_broken_vulkan to true here: we care when loading Vulkan crashes the | ||
| 48 | // application, not when we can handle it. | ||
| 49 | } | ||
| 50 | |||
| 51 | std::filesystem::remove(temp_file_loc); | ||
| 52 | return true; | ||
| 53 | } | ||
diff --git a/src/yuzu/check_vulkan.h b/src/yuzu/check_vulkan.h new file mode 100644 index 000000000..e4ea93582 --- /dev/null +++ b/src/yuzu/check_vulkan.h | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | bool CheckVulkan(); | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 583e9df24..9df4752be 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -71,28 +71,28 @@ const std::array<int, 2> Config::default_ringcon_analogs{{ | |||
| 71 | // UISetting::values.shortcuts, which is alphabetically ordered. | 71 | // UISetting::values.shortcuts, which is alphabetically ordered. |
| 72 | // clang-format off | 72 | // clang-format off |
| 73 | const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ | 73 | const std::array<UISettings::Shortcut, 22> Config::default_hotkeys{{ |
| 74 | {QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, | 74 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Mute/Unmute")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, |
| 75 | {QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, | 75 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Down")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, |
| 76 | {QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, | 76 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Audio Volume Up")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, |
| 77 | {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, | 77 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Capture Screenshot")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, |
| 78 | {QStringLiteral("Change Adapting Filter"), QStringLiteral("Main Window"), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, | 78 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Adapting Filter")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F8"), QStringLiteral("Home+L"), Qt::ApplicationShortcut}}, |
| 79 | {QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, | 79 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change Docked Mode")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, |
| 80 | {QStringLiteral("Change GPU Accuracy"), QStringLiteral("Main Window"), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut}}, | 80 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Change GPU Accuracy")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F9"), QStringLiteral("Home+R"), Qt::ApplicationShortcut}}, |
| 81 | {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}}, | 81 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Continue/Pause Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}}, |
| 82 | {QStringLiteral("Exit Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}}, | 82 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 83 | {QStringLiteral("Exit yuzu"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}}, | 83 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Exit yuzu")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}}, |
| 84 | {QStringLiteral("Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}}, | 84 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Fullscreen")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}}, |
| 85 | {QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}}, | 85 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load File")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}}, |
| 86 | {QStringLiteral("Load/Remove Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}}, | 86 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Load/Remove Amiibo")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}}, |
| 87 | {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}}, | 87 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Restart Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 88 | {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}}, | 88 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Stop Emulation")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 89 | {QStringLiteral("TAS Record"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 89 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Record")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F7"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 90 | {QStringLiteral("TAS Reset"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 90 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Reset")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F6"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 91 | {QStringLiteral("TAS Start/Stop"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 91 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "TAS Start/Stop")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 92 | {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}}, | 92 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Filter Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 93 | {QStringLiteral("Toggle Framerate Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}}, | 93 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Framerate Limit")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}}, |
| 94 | {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}}, | 94 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Mouse Panning")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}}, |
| 95 | {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut}}, | 95 | {QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Toggle Status Bar")), QStringLiteral(QT_TRANSLATE_NOOP("Hotkeys", "Main Window")), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut}}, |
| 96 | }}; | 96 | }}; |
| 97 | // clang-format on | 97 | // clang-format on |
| 98 | 98 | ||
| @@ -682,6 +682,12 @@ void Config::ReadRendererValues() { | |||
| 682 | ReadGlobalSetting(Settings::values.bg_green); | 682 | ReadGlobalSetting(Settings::values.bg_green); |
| 683 | ReadGlobalSetting(Settings::values.bg_blue); | 683 | ReadGlobalSetting(Settings::values.bg_blue); |
| 684 | 684 | ||
| 685 | if (!global && UISettings::values.has_broken_vulkan && | ||
| 686 | Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan && | ||
| 687 | !Settings::values.renderer_backend.UsingGlobal()) { | ||
| 688 | Settings::values.renderer_backend.SetGlobal(true); | ||
| 689 | } | ||
| 690 | |||
| 685 | if (global) { | 691 | if (global) { |
| 686 | ReadBasicSetting(Settings::values.renderer_debug); | 692 | ReadBasicSetting(Settings::values.renderer_debug); |
| 687 | ReadBasicSetting(Settings::values.renderer_shader_feedback); | 693 | ReadBasicSetting(Settings::values.renderer_shader_feedback); |
| @@ -801,6 +807,7 @@ void Config::ReadUIValues() { | |||
| 801 | ReadBasicSetting(UISettings::values.pause_when_in_background); | 807 | ReadBasicSetting(UISettings::values.pause_when_in_background); |
| 802 | ReadBasicSetting(UISettings::values.mute_when_in_background); | 808 | ReadBasicSetting(UISettings::values.mute_when_in_background); |
| 803 | ReadBasicSetting(UISettings::values.hide_mouse); | 809 | ReadBasicSetting(UISettings::values.hide_mouse); |
| 810 | ReadBasicSetting(UISettings::values.has_broken_vulkan); | ||
| 804 | ReadBasicSetting(UISettings::values.disable_web_applet); | 811 | ReadBasicSetting(UISettings::values.disable_web_applet); |
| 805 | 812 | ||
| 806 | qt_config->endGroup(); | 813 | qt_config->endGroup(); |
| @@ -1348,6 +1355,7 @@ void Config::SaveUIValues() { | |||
| 1348 | WriteBasicSetting(UISettings::values.pause_when_in_background); | 1355 | WriteBasicSetting(UISettings::values.pause_when_in_background); |
| 1349 | WriteBasicSetting(UISettings::values.mute_when_in_background); | 1356 | WriteBasicSetting(UISettings::values.mute_when_in_background); |
| 1350 | WriteBasicSetting(UISettings::values.hide_mouse); | 1357 | WriteBasicSetting(UISettings::values.hide_mouse); |
| 1358 | WriteBasicSetting(UISettings::values.has_broken_vulkan); | ||
| 1351 | WriteBasicSetting(UISettings::values.disable_web_applet); | 1359 | WriteBasicSetting(UISettings::values.disable_web_applet); |
| 1352 | 1360 | ||
| 1353 | qt_config->endGroup(); | 1361 | qt_config->endGroup(); |
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 2f1435b10..85f34dc35 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include "video_core/vulkan_common/vulkan_library.h" | 17 | #include "video_core/vulkan_common/vulkan_library.h" |
| 18 | #include "yuzu/configuration/configuration_shared.h" | 18 | #include "yuzu/configuration/configuration_shared.h" |
| 19 | #include "yuzu/configuration/configure_graphics.h" | 19 | #include "yuzu/configuration/configure_graphics.h" |
| 20 | #include "yuzu/uisettings.h" | ||
| 20 | 21 | ||
| 21 | ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) | 22 | ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent) |
| 22 | : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { | 23 | : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { |
| @@ -57,6 +58,24 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren | |||
| 57 | UpdateBackgroundColorButton(new_bg_color); | 58 | UpdateBackgroundColorButton(new_bg_color); |
| 58 | }); | 59 | }); |
| 59 | 60 | ||
| 61 | connect(ui->button_check_vulkan, &QAbstractButton::clicked, this, [this] { | ||
| 62 | UISettings::values.has_broken_vulkan = false; | ||
| 63 | |||
| 64 | if (RetrieveVulkanDevices()) { | ||
| 65 | ui->api->setEnabled(true); | ||
| 66 | ui->button_check_vulkan->hide(); | ||
| 67 | |||
| 68 | for (const auto& device : vulkan_devices) { | ||
| 69 | ui->device->addItem(device); | ||
| 70 | } | ||
| 71 | } else { | ||
| 72 | UISettings::values.has_broken_vulkan = true; | ||
| 73 | } | ||
| 74 | }); | ||
| 75 | |||
| 76 | ui->api->setEnabled(!UISettings::values.has_broken_vulkan.GetValue()); | ||
| 77 | ui->button_check_vulkan->setVisible(UISettings::values.has_broken_vulkan.GetValue()); | ||
| 78 | |||
| 60 | ui->bg_label->setVisible(Settings::IsConfiguringGlobal()); | 79 | ui->bg_label->setVisible(Settings::IsConfiguringGlobal()); |
| 61 | ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal()); | 80 | ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal()); |
| 62 | } | 81 | } |
| @@ -296,7 +315,7 @@ void ConfigureGraphics::UpdateAPILayout() { | |||
| 296 | vulkan_device = Settings::values.vulkan_device.GetValue(true); | 315 | vulkan_device = Settings::values.vulkan_device.GetValue(true); |
| 297 | shader_backend = Settings::values.shader_backend.GetValue(true); | 316 | shader_backend = Settings::values.shader_backend.GetValue(true); |
| 298 | ui->device_widget->setEnabled(false); | 317 | ui->device_widget->setEnabled(false); |
| 299 | ui->backend_widget->setEnabled(false); | 318 | ui->backend_widget->setEnabled(UISettings::values.has_broken_vulkan.GetValue()); |
| 300 | } else { | 319 | } else { |
| 301 | vulkan_device = Settings::values.vulkan_device.GetValue(); | 320 | vulkan_device = Settings::values.vulkan_device.GetValue(); |
| 302 | shader_backend = Settings::values.shader_backend.GetValue(); | 321 | shader_backend = Settings::values.shader_backend.GetValue(); |
| @@ -318,7 +337,11 @@ void ConfigureGraphics::UpdateAPILayout() { | |||
| 318 | } | 337 | } |
| 319 | } | 338 | } |
| 320 | 339 | ||
| 321 | void ConfigureGraphics::RetrieveVulkanDevices() try { | 340 | bool ConfigureGraphics::RetrieveVulkanDevices() try { |
| 341 | if (UISettings::values.has_broken_vulkan) { | ||
| 342 | return false; | ||
| 343 | } | ||
| 344 | |||
| 322 | using namespace Vulkan; | 345 | using namespace Vulkan; |
| 323 | 346 | ||
| 324 | vk::InstanceDispatch dld; | 347 | vk::InstanceDispatch dld; |
| @@ -333,8 +356,10 @@ void ConfigureGraphics::RetrieveVulkanDevices() try { | |||
| 333 | vulkan_devices.push_back(QString::fromStdString(name)); | 356 | vulkan_devices.push_back(QString::fromStdString(name)); |
| 334 | } | 357 | } |
| 335 | 358 | ||
| 359 | return true; | ||
| 336 | } catch (const Vulkan::vk::Exception& exception) { | 360 | } catch (const Vulkan::vk::Exception& exception) { |
| 337 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); | 361 | LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); |
| 362 | return false; | ||
| 338 | } | 363 | } |
| 339 | 364 | ||
| 340 | Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { | 365 | Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { |
| @@ -415,4 +440,11 @@ void ConfigureGraphics::SetupPerGameUI() { | |||
| 415 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); | 440 | ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); |
| 416 | ConfigurationShared::InsertGlobalItem( | 441 | ConfigurationShared::InsertGlobalItem( |
| 417 | ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true))); | 442 | ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true))); |
| 443 | |||
| 444 | if (UISettings::values.has_broken_vulkan) { | ||
| 445 | ui->backend_widget->setEnabled(true); | ||
| 446 | ConfigurationShared::SetColoredComboBox( | ||
| 447 | ui->backend, ui->backend_widget, | ||
| 448 | static_cast<int>(Settings::values.shader_backend.GetValue(true))); | ||
| 449 | } | ||
| 418 | } | 450 | } |
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 1b101c940..8438f0187 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h | |||
| @@ -41,7 +41,7 @@ private: | |||
| 41 | void UpdateDeviceSelection(int device); | 41 | void UpdateDeviceSelection(int device); |
| 42 | void UpdateShaderBackendSelection(int backend); | 42 | void UpdateShaderBackendSelection(int backend); |
| 43 | 43 | ||
| 44 | void RetrieveVulkanDevices(); | 44 | bool RetrieveVulkanDevices(); |
| 45 | 45 | ||
| 46 | void SetupPerGameUI(); | 46 | void SetupPerGameUI(); |
| 47 | 47 | ||
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 74f0e0b79..2f94c94bc 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | <rect> | 6 | <rect> |
| 7 | <x>0</x> | 7 | <x>0</x> |
| 8 | <y>0</y> | 8 | <y>0</y> |
| 9 | <width>437</width> | 9 | <width>471</width> |
| 10 | <height>482</height> | 10 | <height>759</height> |
| 11 | </rect> | 11 | </rect> |
| 12 | </property> | 12 | </property> |
| 13 | <property name="windowTitle"> | 13 | <property name="windowTitle"> |
| @@ -171,11 +171,11 @@ | |||
| 171 | </widget> | 171 | </widget> |
| 172 | </item> | 172 | </item> |
| 173 | <item> | 173 | <item> |
| 174 | <widget class="QCheckBox" name="accelerate_astc"> | 174 | <widget class="QCheckBox" name="accelerate_astc"> |
| 175 | <property name="text"> | 175 | <property name="text"> |
| 176 | <string>Accelerate ASTC texture decoding</string> | 176 | <string>Accelerate ASTC texture decoding</string> |
| 177 | </property> | 177 | </property> |
| 178 | </widget> | 178 | </widget> |
| 179 | </item> | 179 | </item> |
| 180 | <item> | 180 | <item> |
| 181 | <widget class="QWidget" name="nvdec_emulation_widget" native="true"> | 181 | <widget class="QWidget" name="nvdec_emulation_widget" native="true"> |
| @@ -438,43 +438,43 @@ | |||
| 438 | </widget> | 438 | </widget> |
| 439 | </item> | 439 | </item> |
| 440 | <item> | 440 | <item> |
| 441 | <widget class="QWidget" name="anti_aliasing_layout" native="true"> | 441 | <widget class="QWidget" name="anti_aliasing_layout" native="true"> |
| 442 | <layout class="QHBoxLayout" name="horizontalLayout_7"> | 442 | <layout class="QHBoxLayout" name="horizontalLayout_7"> |
| 443 | <property name="leftMargin"> | 443 | <property name="leftMargin"> |
| 444 | <number>0</number> | 444 | <number>0</number> |
| 445 | </property> | 445 | </property> |
| 446 | <property name="topMargin"> | 446 | <property name="topMargin"> |
| 447 | <number>0</number> | 447 | <number>0</number> |
| 448 | </property> | 448 | </property> |
| 449 | <property name="rightMargin"> | 449 | <property name="rightMargin"> |
| 450 | <number>0</number> | 450 | <number>0</number> |
| 451 | </property> | ||
| 452 | <property name="bottomMargin"> | ||
| 453 | <number>0</number> | ||
| 454 | </property> | ||
| 455 | <item> | ||
| 456 | <widget class="QLabel" name="anti_aliasing_label"> | ||
| 457 | <property name="text"> | ||
| 458 | <string>Anti-Aliasing Method:</string> | ||
| 459 | </property> | ||
| 460 | </widget> | ||
| 461 | </item> | ||
| 462 | <item> | ||
| 463 | <widget class="QComboBox" name="anti_aliasing_combobox"> | ||
| 464 | <item> | ||
| 465 | <property name="text"> | ||
| 466 | <string>None</string> | ||
| 451 | </property> | 467 | </property> |
| 452 | <property name="bottomMargin"> | 468 | </item> |
| 453 | <number>0</number> | 469 | <item> |
| 470 | <property name="text"> | ||
| 471 | <string>FXAA</string> | ||
| 454 | </property> | 472 | </property> |
| 455 | <item> | 473 | </item> |
| 456 | <widget class="QLabel" name="anti_aliasing_label"> | 474 | </widget> |
| 457 | <property name="text"> | 475 | </item> |
| 458 | <string>Anti-Aliasing Method:</string> | 476 | </layout> |
| 459 | </property> | 477 | </widget> |
| 460 | </widget> | ||
| 461 | </item> | ||
| 462 | <item> | ||
| 463 | <widget class="QComboBox" name="anti_aliasing_combobox"> | ||
| 464 | <item> | ||
| 465 | <property name="text"> | ||
| 466 | <string>None</string> | ||
| 467 | </property> | ||
| 468 | </item> | ||
| 469 | <item> | ||
| 470 | <property name="text"> | ||
| 471 | <string>FXAA</string> | ||
| 472 | </property> | ||
| 473 | </item> | ||
| 474 | </widget> | ||
| 475 | </item> | ||
| 476 | </layout> | ||
| 477 | </widget> | ||
| 478 | </item> | 478 | </item> |
| 479 | <item> | 479 | <item> |
| 480 | <widget class="QWidget" name="bg_layout" native="true"> | 480 | <widget class="QWidget" name="bg_layout" native="true"> |
| @@ -574,6 +574,13 @@ | |||
| 574 | </property> | 574 | </property> |
| 575 | </spacer> | 575 | </spacer> |
| 576 | </item> | 576 | </item> |
| 577 | <item> | ||
| 578 | <widget class="QPushButton" name="button_check_vulkan"> | ||
| 579 | <property name="text"> | ||
| 580 | <string>Check for Working Vulkan</string> | ||
| 581 | </property> | ||
| 582 | </widget> | ||
| 583 | </item> | ||
| 577 | </layout> | 584 | </layout> |
| 578 | </widget> | 585 | </widget> |
| 579 | <resources/> | 586 | <resources/> |
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp index 6679e9c53..edf0893c4 100644 --- a/src/yuzu/configuration/configure_hotkeys.cpp +++ b/src/yuzu/configuration/configure_hotkeys.cpp | |||
| @@ -61,14 +61,18 @@ ConfigureHotkeys::~ConfigureHotkeys() = default; | |||
| 61 | 61 | ||
| 62 | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { | 62 | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { |
| 63 | for (const auto& group : registry.hotkey_groups) { | 63 | for (const auto& group : registry.hotkey_groups) { |
| 64 | auto* parent_item = new QStandardItem(group.first); | 64 | auto* parent_item = |
| 65 | new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(group.first))); | ||
| 65 | parent_item->setEditable(false); | 66 | parent_item->setEditable(false); |
| 67 | parent_item->setData(group.first); | ||
| 66 | for (const auto& hotkey : group.second) { | 68 | for (const auto& hotkey : group.second) { |
| 67 | auto* action = new QStandardItem(hotkey.first); | 69 | auto* action = |
| 70 | new QStandardItem(QCoreApplication::translate("Hotkeys", qPrintable(hotkey.first))); | ||
| 68 | auto* keyseq = | 71 | auto* keyseq = |
| 69 | new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); | 72 | new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); |
| 70 | auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); | 73 | auto* controller_keyseq = new QStandardItem(hotkey.second.controller_keyseq); |
| 71 | action->setEditable(false); | 74 | action->setEditable(false); |
| 75 | action->setData(hotkey.first); | ||
| 72 | keyseq->setEditable(false); | 76 | keyseq->setEditable(false); |
| 73 | controller_keyseq->setEditable(false); | 77 | controller_keyseq->setEditable(false); |
| 74 | parent_item->appendRow({action, keyseq, controller_keyseq}); | 78 | parent_item->appendRow({action, keyseq, controller_keyseq}); |
| @@ -93,6 +97,16 @@ void ConfigureHotkeys::RetranslateUI() { | |||
| 93 | ui->retranslateUi(this); | 97 | ui->retranslateUi(this); |
| 94 | 98 | ||
| 95 | model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Controller Hotkey")}); | 99 | model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Controller Hotkey")}); |
| 100 | for (int key_id = 0; key_id < model->rowCount(); key_id++) { | ||
| 101 | QStandardItem* parent = model->item(key_id, 0); | ||
| 102 | parent->setText( | ||
| 103 | QCoreApplication::translate("Hotkeys", qPrintable(parent->data().toString()))); | ||
| 104 | for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) { | ||
| 105 | QStandardItem* action = parent->child(key_column_id, name_column); | ||
| 106 | action->setText( | ||
| 107 | QCoreApplication::translate("Hotkeys", qPrintable(action->data().toString()))); | ||
| 108 | } | ||
| 109 | } | ||
| 96 | } | 110 | } |
| 97 | 111 | ||
| 98 | void ConfigureHotkeys::Configure(QModelIndex index) { | 112 | void ConfigureHotkeys::Configure(QModelIndex index) { |
| @@ -273,10 +287,10 @@ void ConfigureHotkeys::ApplyConfiguration(HotkeyRegistry& registry) { | |||
| 273 | const QStandardItem* controller_keyseq = | 287 | const QStandardItem* controller_keyseq = |
| 274 | parent->child(key_column_id, controller_column); | 288 | parent->child(key_column_id, controller_column); |
| 275 | for (auto& [group, sub_actions] : registry.hotkey_groups) { | 289 | for (auto& [group, sub_actions] : registry.hotkey_groups) { |
| 276 | if (group != parent->text()) | 290 | if (group != parent->data()) |
| 277 | continue; | 291 | continue; |
| 278 | for (auto& [action_name, hotkey] : sub_actions) { | 292 | for (auto& [action_name, hotkey] : sub_actions) { |
| 279 | if (action_name != action->text()) | 293 | if (action_name != action->data()) |
| 280 | continue; | 294 | continue; |
| 281 | hotkey.keyseq = QKeySequence(keyseq->text()); | 295 | hotkey.keyseq = QKeySequence(keyseq->text()); |
| 282 | hotkey.controller_keyseq = controller_keyseq->text(); | 296 | hotkey.controller_keyseq = controller_keyseq->text(); |
diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index 27559c37b..c313b0919 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp | |||
| @@ -151,6 +151,8 @@ void ConfigureMotionTouch::ConnectEvents() { | |||
| 151 | &ConfigureMotionTouch::OnConfigureTouchCalibration); | 151 | &ConfigureMotionTouch::OnConfigureTouchCalibration); |
| 152 | connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, | 152 | connect(ui->touch_from_button_config_btn, &QPushButton::clicked, this, |
| 153 | &ConfigureMotionTouch::OnConfigureTouchFromButton); | 153 | &ConfigureMotionTouch::OnConfigureTouchFromButton); |
| 154 | connect(ui->buttonBox, &QDialogButtonBox::accepted, this, | ||
| 155 | &ConfigureMotionTouch::ApplyConfiguration); | ||
| 154 | connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] { | 156 | connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] { |
| 155 | if (CanCloseDialog()) { | 157 | if (CanCloseDialog()) { |
| 156 | reject(); | 158 | reject(); |
diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui index c75a84ae4..0237fae54 100644 --- a/src/yuzu/configuration/configure_motion_touch.ui +++ b/src/yuzu/configuration/configure_motion_touch.ui | |||
| @@ -293,22 +293,5 @@ | |||
| 293 | </layout> | 293 | </layout> |
| 294 | </widget> | 294 | </widget> |
| 295 | <resources/> | 295 | <resources/> |
| 296 | <connections> | 296 | <connections/> |
| 297 | <connection> | ||
| 298 | <sender>buttonBox</sender> | ||
| 299 | <signal>accepted()</signal> | ||
| 300 | <receiver>ConfigureMotionTouch</receiver> | ||
| 301 | <slot>ApplyConfiguration()</slot> | ||
| 302 | <hints> | ||
| 303 | <hint type="sourcelabel"> | ||
| 304 | <x>20</x> | ||
| 305 | <y>20</y> | ||
| 306 | </hint> | ||
| 307 | <hint type="destinationlabel"> | ||
| 308 | <x>20</x> | ||
| 309 | <y>20</y> | ||
| 310 | </hint> | ||
| 311 | </hints> | ||
| 312 | </connection> | ||
| 313 | </connections> | ||
| 314 | </ui> | 297 | </ui> |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index 19aa589f9..ecebb0fb7 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -130,8 +130,7 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 130 | // Guard if during game and set to game-specific value | 130 | // Guard if during game and set to game-specific value |
| 131 | if (Settings::values.rng_seed.UsingGlobal()) { | 131 | if (Settings::values.rng_seed.UsingGlobal()) { |
| 132 | if (ui->rng_seed_checkbox->isChecked()) { | 132 | if (ui->rng_seed_checkbox->isChecked()) { |
| 133 | Settings::values.rng_seed.SetValue( | 133 | Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16)); |
| 134 | ui->rng_seed_edit->text().toULongLong(nullptr, 16)); | ||
| 135 | } else { | 134 | } else { |
| 136 | Settings::values.rng_seed.SetValue(std::nullopt); | 135 | Settings::values.rng_seed.SetValue(std::nullopt); |
| 137 | } | 136 | } |
| @@ -142,8 +141,7 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 142 | case ConfigurationShared::CheckState::Off: | 141 | case ConfigurationShared::CheckState::Off: |
| 143 | Settings::values.rng_seed.SetGlobal(false); | 142 | Settings::values.rng_seed.SetGlobal(false); |
| 144 | if (ui->rng_seed_checkbox->isChecked()) { | 143 | if (ui->rng_seed_checkbox->isChecked()) { |
| 145 | Settings::values.rng_seed.SetValue( | 144 | Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toUInt(nullptr, 16)); |
| 146 | ui->rng_seed_edit->text().toULongLong(nullptr, 16)); | ||
| 147 | } else { | 145 | } else { |
| 148 | Settings::values.rng_seed.SetValue(std::nullopt); | 146 | Settings::values.rng_seed.SetValue(std::nullopt); |
| 149 | } | 147 | } |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 4a6d74a7e..d13530a5b 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -483,7 +483,7 @@ void GameList::DonePopulating(const QStringList& watch_list) { | |||
| 483 | // Also artificially caps the watcher to a certain number of directories | 483 | // Also artificially caps the watcher to a certain number of directories |
| 484 | constexpr int LIMIT_WATCH_DIRECTORIES = 5000; | 484 | constexpr int LIMIT_WATCH_DIRECTORIES = 5000; |
| 485 | constexpr int SLICE_SIZE = 25; | 485 | constexpr int SLICE_SIZE = 25; |
| 486 | int len = std::min(watch_list.length(), LIMIT_WATCH_DIRECTORIES); | 486 | int len = std::min(static_cast<int>(watch_list.size()), LIMIT_WATCH_DIRECTORIES); |
| 487 | for (int i = 0; i < len; i += SLICE_SIZE) { | 487 | for (int i = 0; i < len; i += SLICE_SIZE) { |
| 488 | watcher->addPaths(watch_list.mid(i, i + SLICE_SIZE)); | 488 | watcher->addPaths(watch_list.mid(i, i + SLICE_SIZE)); |
| 489 | QCoreApplication::processEvents(); | 489 | QCoreApplication::processEvents(); |
diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp index edfb946a8..e273744fd 100644 --- a/src/yuzu/loading_screen.cpp +++ b/src/yuzu/loading_screen.cpp | |||
| @@ -183,7 +183,7 @@ void LoadingScreen::OnLoadProgress(VideoCore::LoadCallbackStage stage, std::size | |||
| 183 | 183 | ||
| 184 | void LoadingScreen::paintEvent(QPaintEvent* event) { | 184 | void LoadingScreen::paintEvent(QPaintEvent* event) { |
| 185 | QStyleOption opt; | 185 | QStyleOption opt; |
| 186 | opt.init(this); | 186 | opt.initFrom(this); |
| 187 | QPainter p(this); | 187 | QPainter p(this); |
| 188 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); | 188 | style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); |
| 189 | QWidget::paintEvent(event); | 189 | QWidget::paintEvent(event); |
diff --git a/src/yuzu/loading_screen.h b/src/yuzu/loading_screen.h index 7c960ee72..17045595d 100644 --- a/src/yuzu/loading_screen.h +++ b/src/yuzu/loading_screen.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <QString> | 8 | #include <QString> |
| 9 | #include <QWidget> | 9 | #include <QWidget> |
| 10 | #include <QtGlobal> | ||
| 10 | 11 | ||
| 11 | #if !QT_CONFIG(movie) | 12 | #if !QT_CONFIG(movie) |
| 12 | #define YUZU_QT_MOVIE_MISSING 1 | 13 | #define YUZU_QT_MOVIE_MISSING 1 |
| @@ -88,4 +89,6 @@ private: | |||
| 88 | std::size_t slow_shader_first_value = 0; | 89 | std::size_t slow_shader_first_value = 0; |
| 89 | }; | 90 | }; |
| 90 | 91 | ||
| 92 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) | ||
| 91 | Q_DECLARE_METATYPE(VideoCore::LoadCallbackStage); | 93 | Q_DECLARE_METATYPE(VideoCore::LoadCallbackStage); |
| 94 | #endif | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 8e7f91a0f..4d7634184 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -115,6 +115,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual | |||
| 115 | #include "video_core/shader_notify.h" | 115 | #include "video_core/shader_notify.h" |
| 116 | #include "yuzu/about_dialog.h" | 116 | #include "yuzu/about_dialog.h" |
| 117 | #include "yuzu/bootmanager.h" | 117 | #include "yuzu/bootmanager.h" |
| 118 | #include "yuzu/check_vulkan.h" | ||
| 118 | #include "yuzu/compatdb.h" | 119 | #include "yuzu/compatdb.h" |
| 119 | #include "yuzu/compatibility_list.h" | 120 | #include "yuzu/compatibility_list.h" |
| 120 | #include "yuzu/configuration/config.h" | 121 | #include "yuzu/configuration/config.h" |
| @@ -198,6 +199,31 @@ static void RemoveCachedContents() { | |||
| 198 | Common::FS::RemoveDirRecursively(offline_system_data); | 199 | Common::FS::RemoveDirRecursively(offline_system_data); |
| 199 | } | 200 | } |
| 200 | 201 | ||
| 202 | static QString PrettyProductName() { | ||
| 203 | #ifdef _WIN32 | ||
| 204 | // After Windows 10 Version 2004, Microsoft decided to switch to a different notation: 20H2 | ||
| 205 | // With that notation change they changed the registry key used to denote the current version | ||
| 206 | QSettings windows_registry( | ||
| 207 | QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), | ||
| 208 | QSettings::NativeFormat); | ||
| 209 | const QString release_id = windows_registry.value(QStringLiteral("ReleaseId")).toString(); | ||
| 210 | if (release_id == QStringLiteral("2009")) { | ||
| 211 | const u32 current_build = windows_registry.value(QStringLiteral("CurrentBuild")).toUInt(); | ||
| 212 | const QString display_version = | ||
| 213 | windows_registry.value(QStringLiteral("DisplayVersion")).toString(); | ||
| 214 | const u32 ubr = windows_registry.value(QStringLiteral("UBR")).toUInt(); | ||
| 215 | u32 version = 10; | ||
| 216 | if (current_build >= 22000) { | ||
| 217 | version = 11; | ||
| 218 | } | ||
| 219 | return QStringLiteral("Windows %1 Version %2 (Build %3.%4)") | ||
| 220 | .arg(QString::number(version), display_version, QString::number(current_build), | ||
| 221 | QString::number(ubr)); | ||
| 222 | } | ||
| 223 | #endif | ||
| 224 | return QSysInfo::prettyProductName(); | ||
| 225 | } | ||
| 226 | |||
| 201 | GMainWindow::GMainWindow() | 227 | GMainWindow::GMainWindow() |
| 202 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, | 228 | : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, |
| 203 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, | 229 | input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, |
| @@ -259,7 +285,7 @@ GMainWindow::GMainWindow() | |||
| 259 | } | 285 | } |
| 260 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); | 286 | LOG_INFO(Frontend, "Host CPU: {}", cpu_string); |
| 261 | #endif | 287 | #endif |
| 262 | LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString()); | 288 | LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); |
| 263 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", | 289 | LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", |
| 264 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); | 290 | Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB}); |
| 265 | LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); | 291 | LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB}); |
| @@ -297,6 +323,23 @@ GMainWindow::GMainWindow() | |||
| 297 | 323 | ||
| 298 | MigrateConfigFiles(); | 324 | MigrateConfigFiles(); |
| 299 | 325 | ||
| 326 | if (!CheckVulkan()) { | ||
| 327 | config->Save(); | ||
| 328 | |||
| 329 | QMessageBox::warning( | ||
| 330 | this, tr("Broken Vulkan Installation Detected"), | ||
| 331 | tr("Vulkan initialization failed on the previous boot.<br><br>Click <a " | ||
| 332 | "href='https://yuzu-emu.org/wiki/faq/" | ||
| 333 | "#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>here for " | ||
| 334 | "instructions to fix the issue</a>.")); | ||
| 335 | } | ||
| 336 | if (UISettings::values.has_broken_vulkan) { | ||
| 337 | Settings::values.renderer_backend = Settings::RendererBackend::OpenGL; | ||
| 338 | |||
| 339 | renderer_status_button->setDisabled(true); | ||
| 340 | renderer_status_button->setChecked(false); | ||
| 341 | } | ||
| 342 | |||
| 300 | #if defined(HAVE_SDL2) && !defined(_WIN32) | 343 | #if defined(HAVE_SDL2) && !defined(_WIN32) |
| 301 | SDL_InitSubSystem(SDL_INIT_VIDEO); | 344 | SDL_InitSubSystem(SDL_INIT_VIDEO); |
| 302 | // SDL disables the screen saver by default, and setting the hint | 345 | // SDL disables the screen saver by default, and setting the hint |
| @@ -827,12 +870,11 @@ void GMainWindow::InitializeWidgets() { | |||
| 827 | 870 | ||
| 828 | // Setup Dock button | 871 | // Setup Dock button |
| 829 | dock_status_button = new QPushButton(); | 872 | dock_status_button = new QPushButton(); |
| 830 | dock_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); | 873 | dock_status_button->setObjectName(QStringLiteral("DockingStatusBarButton")); |
| 831 | dock_status_button->setFocusPolicy(Qt::NoFocus); | 874 | dock_status_button->setFocusPolicy(Qt::NoFocus); |
| 832 | connect(dock_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleDockedMode); | 875 | connect(dock_status_button, &QPushButton::clicked, this, &GMainWindow::OnToggleDockedMode); |
| 833 | dock_status_button->setText(tr("DOCK")); | ||
| 834 | dock_status_button->setCheckable(true); | 876 | dock_status_button->setCheckable(true); |
| 835 | dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); | 877 | UpdateDockedButton(); |
| 836 | statusBar()->insertPermanentWidget(0, dock_status_button); | 878 | statusBar()->insertPermanentWidget(0, dock_status_button); |
| 837 | 879 | ||
| 838 | gpu_accuracy_button = new QPushButton(); | 880 | gpu_accuracy_button = new QPushButton(); |
| @@ -1567,7 +1609,7 @@ void GMainWindow::ShutdownGame() { | |||
| 1567 | emu_speed_label->setVisible(false); | 1609 | emu_speed_label->setVisible(false); |
| 1568 | game_fps_label->setVisible(false); | 1610 | game_fps_label->setVisible(false); |
| 1569 | emu_frametime_label->setVisible(false); | 1611 | emu_frametime_label->setVisible(false); |
| 1570 | renderer_status_button->setEnabled(true); | 1612 | renderer_status_button->setEnabled(!UISettings::values.has_broken_vulkan); |
| 1571 | 1613 | ||
| 1572 | game_path.clear(); | 1614 | game_path.clear(); |
| 1573 | 1615 | ||
| @@ -1587,7 +1629,7 @@ void GMainWindow::StoreRecentFile(const QString& filename) { | |||
| 1587 | 1629 | ||
| 1588 | void GMainWindow::UpdateRecentFiles() { | 1630 | void GMainWindow::UpdateRecentFiles() { |
| 1589 | const int num_recent_files = | 1631 | const int num_recent_files = |
| 1590 | std::min(UISettings::values.recent_files.size(), max_recent_files_item); | 1632 | std::min(static_cast<int>(UISettings::values.recent_files.size()), max_recent_files_item); |
| 1591 | 1633 | ||
| 1592 | for (int i = 0; i < num_recent_files; i++) { | 1634 | for (int i = 0; i < num_recent_files; i++) { |
| 1593 | const QString text = QStringLiteral("&%1. %2").arg(i + 1).arg( | 1635 | const QString text = QStringLiteral("&%1. %2").arg(i + 1).arg( |
| @@ -2777,6 +2819,10 @@ void GMainWindow::OnConfigure() { | |||
| 2777 | mouse_hide_timer.start(); | 2819 | mouse_hide_timer.start(); |
| 2778 | } | 2820 | } |
| 2779 | 2821 | ||
| 2822 | if (!UISettings::values.has_broken_vulkan) { | ||
| 2823 | renderer_status_button->setEnabled(!emulation_running); | ||
| 2824 | } | ||
| 2825 | |||
| 2780 | UpdateStatusButtons(); | 2826 | UpdateStatusButtons(); |
| 2781 | controller_dialog->refreshConfiguration(); | 2827 | controller_dialog->refreshConfiguration(); |
| 2782 | } | 2828 | } |
| @@ -2862,7 +2908,7 @@ void GMainWindow::OnToggleDockedMode() { | |||
| 2862 | } | 2908 | } |
| 2863 | 2909 | ||
| 2864 | Settings::values.use_docked_mode.SetValue(!is_docked); | 2910 | Settings::values.use_docked_mode.SetValue(!is_docked); |
| 2865 | dock_status_button->setChecked(!is_docked); | 2911 | UpdateDockedButton(); |
| 2866 | OnDockedModeChanged(is_docked, !is_docked, *system); | 2912 | OnDockedModeChanged(is_docked, !is_docked, *system); |
| 2867 | } | 2913 | } |
| 2868 | 2914 | ||
| @@ -3228,6 +3274,12 @@ void GMainWindow::UpdateGPUAccuracyButton() { | |||
| 3228 | } | 3274 | } |
| 3229 | } | 3275 | } |
| 3230 | 3276 | ||
| 3277 | void GMainWindow::UpdateDockedButton() { | ||
| 3278 | const bool is_docked = Settings::values.use_docked_mode.GetValue(); | ||
| 3279 | dock_status_button->setChecked(is_docked); | ||
| 3280 | dock_status_button->setText(is_docked ? tr("DOCKED") : tr("HANDHELD")); | ||
| 3281 | } | ||
| 3282 | |||
| 3231 | void GMainWindow::UpdateFilterText() { | 3283 | void GMainWindow::UpdateFilterText() { |
| 3232 | const auto filter = Settings::values.scaling_filter.GetValue(); | 3284 | const auto filter = Settings::values.scaling_filter.GetValue(); |
| 3233 | switch (filter) { | 3285 | switch (filter) { |
| @@ -3271,10 +3323,10 @@ void GMainWindow::UpdateAAText() { | |||
| 3271 | } | 3323 | } |
| 3272 | 3324 | ||
| 3273 | void GMainWindow::UpdateStatusButtons() { | 3325 | void GMainWindow::UpdateStatusButtons() { |
| 3274 | dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); | ||
| 3275 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == | 3326 | renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == |
| 3276 | Settings::RendererBackend::Vulkan); | 3327 | Settings::RendererBackend::Vulkan); |
| 3277 | UpdateGPUAccuracyButton(); | 3328 | UpdateGPUAccuracyButton(); |
| 3329 | UpdateDockedButton(); | ||
| 3278 | UpdateFilterText(); | 3330 | UpdateFilterText(); |
| 3279 | UpdateAAText(); | 3331 | UpdateAAText(); |
| 3280 | } | 3332 | } |
| @@ -3325,7 +3377,7 @@ void GMainWindow::CenterMouseCursor() { | |||
| 3325 | const int center_x = render_window->width() / 2; | 3377 | const int center_x = render_window->width() / 2; |
| 3326 | const int center_y = render_window->height() / 2; | 3378 | const int center_y = render_window->height() / 2; |
| 3327 | 3379 | ||
| 3328 | QCursor::setPos(mapToGlobal({center_x, center_y})); | 3380 | QCursor::setPos(mapToGlobal(QPoint{center_x, center_y})); |
| 3329 | } | 3381 | } |
| 3330 | 3382 | ||
| 3331 | void GMainWindow::OnMouseActivity() { | 3383 | void GMainWindow::OnMouseActivity() { |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b399e9b01..600647015 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -320,6 +320,7 @@ private: | |||
| 320 | void MigrateConfigFiles(); | 320 | void MigrateConfigFiles(); |
| 321 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, | 321 | void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, |
| 322 | std::string_view gpu_vendor = {}); | 322 | std::string_view gpu_vendor = {}); |
| 323 | void UpdateDockedButton(); | ||
| 323 | void UpdateFilterText(); | 324 | void UpdateFilterText(); |
| 324 | void UpdateAAText(); | 325 | void UpdateAAText(); |
| 325 | void UpdateStatusBar(); | 326 | void UpdateStatusBar(); |
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 15ba9ea17..c64d87ace 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h | |||
| @@ -77,6 +77,8 @@ struct Values { | |||
| 77 | Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; | 77 | Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"}; |
| 78 | Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"}; | 78 | Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"}; |
| 79 | Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"}; | 79 | Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"}; |
| 80 | // Set when Vulkan is known to crash the application | ||
| 81 | Settings::BasicSetting<bool> has_broken_vulkan{false, "has_broken_vulkan"}; | ||
| 80 | 82 | ||
| 81 | Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; | 83 | Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; |
| 82 | 84 | ||
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index f34d6b728..39063e32b 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -218,7 +218,7 @@ cpuopt_unsafe_ignore_global_monitor = | |||
| 218 | 218 | ||
| 219 | [Renderer] | 219 | [Renderer] |
| 220 | # Which backend API to use. | 220 | # Which backend API to use. |
| 221 | # 0 (default): OpenGL, 1: Vulkan | 221 | # 0: OpenGL, 1 (default): Vulkan |
| 222 | backend = | 222 | backend = |
| 223 | 223 | ||
| 224 | # Enable graphics API debugging mode. | 224 | # Enable graphics API debugging mode. |