diff options
Diffstat (limited to 'src')
47 files changed, 825 insertions, 223 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index d18ef6940..50846a854 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp | |||
| @@ -17,7 +17,7 @@ namespace AudioCore { | |||
| 17 | 17 | ||
| 18 | constexpr u32 STREAM_SAMPLE_RATE{48000}; | 18 | constexpr u32 STREAM_SAMPLE_RATE{48000}; |
| 19 | constexpr u32 STREAM_NUM_CHANNELS{2}; | 19 | constexpr u32 STREAM_NUM_CHANNELS{2}; |
| 20 | 20 | using VoiceChannelHolder = std::array<VoiceResourceInformation*, 6>; | |
| 21 | class AudioRenderer::VoiceState { | 21 | class AudioRenderer::VoiceState { |
| 22 | public: | 22 | public: |
| 23 | bool IsPlaying() const { | 23 | bool IsPlaying() const { |
| @@ -37,9 +37,10 @@ public: | |||
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | void SetWaveIndex(std::size_t index); | 39 | void SetWaveIndex(std::size_t index); |
| 40 | std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory); | 40 | std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory, |
| 41 | const VoiceChannelHolder& voice_resources); | ||
| 41 | void UpdateState(); | 42 | void UpdateState(); |
| 42 | void RefreshBuffer(Core::Memory::Memory& memory); | 43 | void RefreshBuffer(Core::Memory::Memory& memory, const VoiceChannelHolder& voice_resources); |
| 43 | 44 | ||
| 44 | private: | 45 | private: |
| 45 | bool is_in_use{}; | 46 | bool is_in_use{}; |
| @@ -79,7 +80,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory | |||
| 79 | std::shared_ptr<Kernel::WritableEvent> buffer_event, | 80 | std::shared_ptr<Kernel::WritableEvent> buffer_event, |
| 80 | std::size_t instance_number) | 81 | std::size_t instance_number) |
| 81 | : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), | 82 | : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), |
| 82 | effects(params.effect_count), memory{memory_} { | 83 | voice_resources(params.voice_count), effects(params.effect_count), memory{memory_} { |
| 83 | behavior_info.SetUserRevision(params.revision); | 84 | behavior_info.SetUserRevision(params.revision); |
| 84 | audio_out = std::make_unique<AudioCore::AudioOut>(); | 85 | audio_out = std::make_unique<AudioCore::AudioOut>(); |
| 85 | stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, | 86 | stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, |
| @@ -127,6 +128,12 @@ ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector< | |||
| 127 | input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size, | 128 | input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size, |
| 128 | memory_pool_count * sizeof(MemoryPoolInfo)); | 129 | memory_pool_count * sizeof(MemoryPoolInfo)); |
| 129 | 130 | ||
| 131 | // Copy voice resources | ||
| 132 | const std::size_t voice_resource_offset{sizeof(UpdateDataHeader) + config.behavior_size + | ||
| 133 | config.memory_pools_size}; | ||
| 134 | std::memcpy(voice_resources.data(), input_params.data() + voice_resource_offset, | ||
| 135 | sizeof(VoiceResourceInformation) * voice_resources.size()); | ||
| 136 | |||
| 130 | // Copy VoiceInfo structs | 137 | // Copy VoiceInfo structs |
| 131 | std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size + | 138 | std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size + |
| 132 | config.memory_pools_size + config.voice_resource_size}; | 139 | config.memory_pools_size + config.voice_resource_size}; |
| @@ -220,14 +227,15 @@ void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) { | |||
| 220 | is_refresh_pending = true; | 227 | is_refresh_pending = true; |
| 221 | } | 228 | } |
| 222 | 229 | ||
| 223 | std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count, | 230 | std::vector<s16> AudioRenderer::VoiceState::DequeueSamples( |
| 224 | Core::Memory::Memory& memory) { | 231 | std::size_t sample_count, Core::Memory::Memory& memory, |
| 232 | const VoiceChannelHolder& voice_resources) { | ||
| 225 | if (!IsPlaying()) { | 233 | if (!IsPlaying()) { |
| 226 | return {}; | 234 | return {}; |
| 227 | } | 235 | } |
| 228 | 236 | ||
| 229 | if (is_refresh_pending) { | 237 | if (is_refresh_pending) { |
| 230 | RefreshBuffer(memory); | 238 | RefreshBuffer(memory, voice_resources); |
| 231 | } | 239 | } |
| 232 | 240 | ||
| 233 | const std::size_t max_size{samples.size() - offset}; | 241 | const std::size_t max_size{samples.size() - offset}; |
| @@ -271,7 +279,8 @@ void AudioRenderer::VoiceState::UpdateState() { | |||
| 271 | is_in_use = info.is_in_use; | 279 | is_in_use = info.is_in_use; |
| 272 | } | 280 | } |
| 273 | 281 | ||
| 274 | void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) { | 282 | void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory, |
| 283 | const VoiceChannelHolder& voice_resources) { | ||
| 275 | const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr; | 284 | const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr; |
| 276 | const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz; | 285 | const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz; |
| 277 | std::vector<s16> new_samples(wave_buffer_size / sizeof(s16)); | 286 | std::vector<s16> new_samples(wave_buffer_size / sizeof(s16)); |
| @@ -296,17 +305,77 @@ void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) { | |||
| 296 | } | 305 | } |
| 297 | 306 | ||
| 298 | switch (info.channel_count) { | 307 | switch (info.channel_count) { |
| 299 | case 1: | 308 | case 1: { |
| 300 | // 1 channel is upsampled to 2 channel | 309 | // 1 channel is upsampled to 2 channel |
| 301 | samples.resize(new_samples.size() * 2); | 310 | samples.resize(new_samples.size() * 2); |
| 311 | |||
| 302 | for (std::size_t index = 0; index < new_samples.size(); ++index) { | 312 | for (std::size_t index = 0; index < new_samples.size(); ++index) { |
| 303 | samples[index * 2] = new_samples[index]; | 313 | auto sample = static_cast<float>(new_samples[index]); |
| 304 | samples[index * 2 + 1] = new_samples[index]; | 314 | if (voice_resources[0]->in_use) { |
| 315 | sample *= voice_resources[0]->mix_volumes[0]; | ||
| 316 | } | ||
| 317 | |||
| 318 | samples[index * 2] = static_cast<s16>(sample * info.volume); | ||
| 319 | samples[index * 2 + 1] = static_cast<s16>(sample * info.volume); | ||
| 305 | } | 320 | } |
| 306 | break; | 321 | break; |
| 322 | } | ||
| 307 | case 2: { | 323 | case 2: { |
| 308 | // 2 channel is played as is | 324 | // 2 channel is played as is |
| 309 | samples = std::move(new_samples); | 325 | samples = std::move(new_samples); |
| 326 | const std::size_t sample_count = (samples.size() / 2); | ||
| 327 | for (std::size_t index = 0; index < sample_count; ++index) { | ||
| 328 | const std::size_t index_l = index * 2; | ||
| 329 | const std::size_t index_r = index * 2 + 1; | ||
| 330 | |||
| 331 | auto sample_l = static_cast<float>(samples[index_l]); | ||
| 332 | auto sample_r = static_cast<float>(samples[index_r]); | ||
| 333 | |||
| 334 | if (voice_resources[0]->in_use) { | ||
| 335 | sample_l *= voice_resources[0]->mix_volumes[0]; | ||
| 336 | } | ||
| 337 | |||
| 338 | if (voice_resources[1]->in_use) { | ||
| 339 | sample_r *= voice_resources[1]->mix_volumes[1]; | ||
| 340 | } | ||
| 341 | |||
| 342 | samples[index_l] = static_cast<s16>(sample_l * info.volume); | ||
| 343 | samples[index_r] = static_cast<s16>(sample_r * info.volume); | ||
| 344 | } | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | case 6: { | ||
| 348 | samples.resize((new_samples.size() / 6) * 2); | ||
| 349 | const std::size_t sample_count = samples.size() / 2; | ||
| 350 | |||
| 351 | for (std::size_t index = 0; index < sample_count; ++index) { | ||
| 352 | auto FL = static_cast<float>(new_samples[index * 6]); | ||
| 353 | auto FR = static_cast<float>(new_samples[index * 6 + 1]); | ||
| 354 | auto FC = static_cast<float>(new_samples[index * 6 + 2]); | ||
| 355 | auto BL = static_cast<float>(new_samples[index * 6 + 4]); | ||
| 356 | auto BR = static_cast<float>(new_samples[index * 6 + 5]); | ||
| 357 | |||
| 358 | if (voice_resources[0]->in_use) { | ||
| 359 | FL *= voice_resources[0]->mix_volumes[0]; | ||
| 360 | } | ||
| 361 | if (voice_resources[1]->in_use) { | ||
| 362 | FR *= voice_resources[1]->mix_volumes[1]; | ||
| 363 | } | ||
| 364 | if (voice_resources[2]->in_use) { | ||
| 365 | FC *= voice_resources[2]->mix_volumes[2]; | ||
| 366 | } | ||
| 367 | if (voice_resources[4]->in_use) { | ||
| 368 | BL *= voice_resources[4]->mix_volumes[4]; | ||
| 369 | } | ||
| 370 | if (voice_resources[5]->in_use) { | ||
| 371 | BR *= voice_resources[5]->mix_volumes[5]; | ||
| 372 | } | ||
| 373 | |||
| 374 | samples[index * 2] = | ||
| 375 | static_cast<s16>((0.3694f * FL + 0.2612f * FC + 0.3694f * BL) * info.volume); | ||
| 376 | samples[index * 2 + 1] = | ||
| 377 | static_cast<s16>((0.3694f * FR + 0.2612f * FC + 0.3694f * BR) * info.volume); | ||
| 378 | } | ||
| 310 | break; | 379 | break; |
| 311 | } | 380 | } |
| 312 | default: | 381 | default: |
| @@ -352,11 +421,17 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||
| 352 | if (!voice.IsPlaying()) { | 421 | if (!voice.IsPlaying()) { |
| 353 | continue; | 422 | continue; |
| 354 | } | 423 | } |
| 424 | VoiceChannelHolder resources{}; | ||
| 425 | for (u32 channel = 0; channel < voice.GetInfo().channel_count; channel++) { | ||
| 426 | const auto channel_resource_id = voice.GetInfo().voice_channel_resource_ids[channel]; | ||
| 427 | resources[channel] = &voice_resources[channel_resource_id]; | ||
| 428 | } | ||
| 355 | 429 | ||
| 356 | std::size_t offset{}; | 430 | std::size_t offset{}; |
| 357 | s64 samples_remaining{BUFFER_SIZE}; | 431 | s64 samples_remaining{BUFFER_SIZE}; |
| 358 | while (samples_remaining > 0) { | 432 | while (samples_remaining > 0) { |
| 359 | const std::vector<s16> samples{voice.DequeueSamples(samples_remaining, memory)}; | 433 | const std::vector<s16> samples{ |
| 434 | voice.DequeueSamples(samples_remaining, memory, resources)}; | ||
| 360 | 435 | ||
| 361 | if (samples.empty()) { | 436 | if (samples.empty()) { |
| 362 | break; | 437 | break; |
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index b42770fae..1f9114c07 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | 10 | ||
| 11 | #include "audio_core/behavior_info.h" | 11 | #include "audio_core/behavior_info.h" |
| 12 | #include "audio_core/common.h" | ||
| 12 | #include "audio_core/stream.h" | 13 | #include "audio_core/stream.h" |
| 13 | #include "common/common_funcs.h" | 14 | #include "common/common_funcs.h" |
| 14 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| @@ -116,6 +117,14 @@ struct WaveBuffer { | |||
| 116 | }; | 117 | }; |
| 117 | static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size"); | 118 | static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size"); |
| 118 | 119 | ||
| 120 | struct VoiceResourceInformation { | ||
| 121 | s32_le id{}; | ||
| 122 | std::array<float_le, MAX_MIX_BUFFERS> mix_volumes{}; | ||
| 123 | bool in_use{}; | ||
| 124 | INSERT_PADDING_BYTES(11); | ||
| 125 | }; | ||
| 126 | static_assert(sizeof(VoiceResourceInformation) == 0x70, "VoiceResourceInformation has wrong size"); | ||
| 127 | |||
| 119 | struct VoiceInfo { | 128 | struct VoiceInfo { |
| 120 | u32_le id; | 129 | u32_le id; |
| 121 | u32_le node_id; | 130 | u32_le node_id; |
| @@ -244,6 +253,7 @@ private: | |||
| 244 | AudioRendererParameter worker_params; | 253 | AudioRendererParameter worker_params; |
| 245 | std::shared_ptr<Kernel::WritableEvent> buffer_event; | 254 | std::shared_ptr<Kernel::WritableEvent> buffer_event; |
| 246 | std::vector<VoiceState> voices; | 255 | std::vector<VoiceState> voices; |
| 256 | std::vector<VoiceResourceInformation> voice_resources; | ||
| 247 | std::vector<EffectState> effects; | 257 | std::vector<EffectState> effects; |
| 248 | std::unique_ptr<AudioOut> audio_out; | 258 | std::unique_ptr<AudioOut> audio_out; |
| 249 | StreamPtr stream; | 259 | StreamPtr stream; |
diff --git a/src/audio_core/common.h b/src/audio_core/common.h index 98478b66b..7bb145c53 100644 --- a/src/audio_core/common.h +++ b/src/audio_core/common.h | |||
| @@ -14,6 +14,7 @@ constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41}; | |||
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8'); | 16 | constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8'); |
| 17 | constexpr std::size_t MAX_MIX_BUFFERS = 24; | ||
| 17 | 18 | ||
| 18 | static constexpr u32 VersionFromRevision(u32_le rev) { | 19 | static constexpr u32 VersionFromRevision(u32_le rev) { |
| 19 | // "REV7" -> 7 | 20 | // "REV7" -> 7 |
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index d1ec8ff08..e6769a5f3 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -148,6 +148,8 @@ add_library(common STATIC | |||
| 148 | thread.h | 148 | thread.h |
| 149 | thread_queue_list.h | 149 | thread_queue_list.h |
| 150 | threadsafe_queue.h | 150 | threadsafe_queue.h |
| 151 | time_zone.cpp | ||
| 152 | time_zone.h | ||
| 151 | timer.cpp | 153 | timer.cpp |
| 152 | timer.h | 154 | timer.h |
| 153 | uint128.cpp | 155 | uint128.cpp |
diff --git a/src/common/time_zone.cpp b/src/common/time_zone.cpp new file mode 100644 index 000000000..ce239eb63 --- /dev/null +++ b/src/common/time_zone.cpp | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <chrono> | ||
| 6 | #include <iomanip> | ||
| 7 | #include <sstream> | ||
| 8 | |||
| 9 | #include "common/logging/log.h" | ||
| 10 | #include "common/time_zone.h" | ||
| 11 | |||
| 12 | namespace Common::TimeZone { | ||
| 13 | |||
| 14 | std::string GetDefaultTimeZone() { | ||
| 15 | return "GMT"; | ||
| 16 | } | ||
| 17 | |||
| 18 | static std::string GetOsTimeZoneOffset() { | ||
| 19 | const std::time_t t{std::time(nullptr)}; | ||
| 20 | const std::tm tm{*std::localtime(&t)}; | ||
| 21 | |||
| 22 | std::stringstream ss; | ||
| 23 | ss << std::put_time(&tm, "%z"); // Get the current timezone offset, e.g. "-400", as a string | ||
| 24 | |||
| 25 | return ss.str(); | ||
| 26 | } | ||
| 27 | |||
| 28 | static int ConvertOsTimeZoneOffsetToInt(const std::string& timezone) { | ||
| 29 | try { | ||
| 30 | return std::stoi(timezone); | ||
| 31 | } catch (const std::invalid_argument&) { | ||
| 32 | LOG_CRITICAL(Common, "invalid_argument with {}!", timezone); | ||
| 33 | return 0; | ||
| 34 | } catch (const std::out_of_range&) { | ||
| 35 | LOG_CRITICAL(Common, "out_of_range with {}!", timezone); | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 40 | std::chrono::seconds GetCurrentOffsetSeconds() { | ||
| 41 | const int offset{ConvertOsTimeZoneOffsetToInt(GetOsTimeZoneOffset())}; | ||
| 42 | |||
| 43 | int seconds{(offset / 100) * 60 * 60}; // Convert hour component to seconds | ||
| 44 | seconds += (offset % 100) * 60; // Convert minute component to seconds | ||
| 45 | |||
| 46 | return std::chrono::seconds{seconds}; | ||
| 47 | } | ||
| 48 | |||
| 49 | } // namespace Common::TimeZone | ||
diff --git a/src/common/time_zone.h b/src/common/time_zone.h new file mode 100644 index 000000000..945daa09c --- /dev/null +++ b/src/common/time_zone.h | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <chrono> | ||
| 8 | #include <string> | ||
| 9 | |||
| 10 | namespace Common::TimeZone { | ||
| 11 | |||
| 12 | /// Gets the default timezone, i.e. "GMT" | ||
| 13 | std::string GetDefaultTimeZone(); | ||
| 14 | |||
| 15 | /// Gets the offset of the current timezone (from the default), in seconds | ||
| 16 | std::chrono::seconds GetCurrentOffsetSeconds(); | ||
| 17 | |||
| 18 | } // namespace Common::TimeZone | ||
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index f155a1341..63cd2eead 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp | |||
| @@ -95,6 +95,10 @@ u32 NACP::GetSupportedLanguages() const { | |||
| 95 | return raw.supported_languages; | 95 | return raw.supported_languages; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | u64 NACP::GetDeviceSaveDataSize() const { | ||
| 99 | return raw.device_save_data_size; | ||
| 100 | } | ||
| 101 | |||
| 98 | std::vector<u8> NACP::GetRawBytes() const { | 102 | std::vector<u8> NACP::GetRawBytes() const { |
| 99 | std::vector<u8> out(sizeof(RawNACP)); | 103 | std::vector<u8> out(sizeof(RawNACP)); |
| 100 | std::memcpy(out.data(), &raw, sizeof(RawNACP)); | 104 | std::memcpy(out.data(), &raw, sizeof(RawNACP)); |
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 2d8c251ac..e37b2fadf 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h | |||
| @@ -113,6 +113,7 @@ public: | |||
| 113 | u32 GetSupportedLanguages() const; | 113 | u32 GetSupportedLanguages() const; |
| 114 | std::vector<u8> GetRawBytes() const; | 114 | std::vector<u8> GetRawBytes() const; |
| 115 | bool GetUserAccountSwitchLock() const; | 115 | bool GetUserAccountSwitchLock() const; |
| 116 | u64 GetDeviceSaveDataSize() const; | ||
| 116 | 117 | ||
| 117 | private: | 118 | private: |
| 118 | RawNACP raw{}; | 119 | RawNACP raw{}; |
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp index f3def93ab..adfd2c1a4 100644 --- a/src/core/file_sys/savedata_factory.cpp +++ b/src/core/file_sys/savedata_factory.cpp | |||
| @@ -57,7 +57,8 @@ void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) { | |||
| 57 | bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { | 57 | bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { |
| 58 | return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || | 58 | return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || |
| 59 | (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User | 59 | (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User |
| 60 | desc.type == SaveDataType::SaveData && desc.title_id == 0 && desc.save_id == 0); | 60 | (desc.type == SaveDataType::SaveData || desc.type == SaveDataType::DeviceSaveData) && |
| 61 | desc.title_id == 0 && desc.save_id == 0); | ||
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | } // Anonymous namespace | 64 | } // Anonymous namespace |
| @@ -139,8 +140,10 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ | |||
| 139 | u128 user_id, u64 save_id) { | 140 | u128 user_id, u64 save_id) { |
| 140 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should | 141 | // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should |
| 141 | // be interpreted as the title id of the current process. | 142 | // be interpreted as the title id of the current process. |
| 142 | if (type == SaveDataType::SaveData && title_id == 0) { | 143 | if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) { |
| 143 | title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 144 | if (title_id == 0) { |
| 145 | title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | ||
| 146 | } | ||
| 144 | } | 147 | } |
| 145 | 148 | ||
| 146 | std::string out = GetSaveDataSpaceIdPath(space); | 149 | std::string out = GetSaveDataSpaceIdPath(space); |
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index eda466a5d..9a081fbd4 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -46,7 +46,7 @@ private: | |||
| 46 | EmuWindow::EmuWindow() { | 46 | EmuWindow::EmuWindow() { |
| 47 | // TODO: Find a better place to set this. | 47 | // TODO: Find a better place to set this. |
| 48 | config.min_client_area_size = | 48 | config.min_client_area_size = |
| 49 | std::make_pair(Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height); | 49 | std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height); |
| 50 | active_config = config; | 50 | active_config = config; |
| 51 | touch_state = std::make_shared<TouchState>(); | 51 | touch_state = std::make_shared<TouchState>(); |
| 52 | Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state); | 52 | Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state); |
diff --git a/src/core/frontend/framebuffer_layout.h b/src/core/frontend/framebuffer_layout.h index 15ecfb13d..91ecc30ab 100644 --- a/src/core/frontend/framebuffer_layout.h +++ b/src/core/frontend/framebuffer_layout.h | |||
| @@ -8,6 +8,11 @@ | |||
| 8 | 8 | ||
| 9 | namespace Layout { | 9 | namespace Layout { |
| 10 | 10 | ||
| 11 | namespace MinimumSize { | ||
| 12 | constexpr u32 Width = 640; | ||
| 13 | constexpr u32 Height = 360; | ||
| 14 | } // namespace MinimumSize | ||
| 15 | |||
| 11 | namespace ScreenUndocked { | 16 | namespace ScreenUndocked { |
| 12 | constexpr u32 Width = 1280; | 17 | constexpr u32 Width = 1280; |
| 13 | constexpr u32 Height = 720; | 18 | constexpr u32 Height = 720; |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index f6503fe2f..20c331b77 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -767,7 +767,7 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter) | |||
| 767 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, | 767 | {1014, nullptr, "OutputMultiProgramTagAccessLog"}, |
| 768 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, | 768 | {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, |
| 769 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, | 769 | {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"}, |
| 770 | {1200, nullptr, "OpenMultiCommitManager"}, | 770 | {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"}, |
| 771 | {1300, nullptr, "OpenBisWiper"}, | 771 | {1300, nullptr, "OpenBisWiper"}, |
| 772 | }; | 772 | }; |
| 773 | // clang-format on | 773 | // clang-format on |
| @@ -988,4 +988,40 @@ void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) { | |||
| 988 | rb.Push(access_log_program_index); | 988 | rb.Push(access_log_program_index); |
| 989 | } | 989 | } |
| 990 | 990 | ||
| 991 | class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> { | ||
| 992 | public: | ||
| 993 | explicit IMultiCommitManager() : ServiceFramework("IMultiCommitManager") { | ||
| 994 | static const FunctionInfo functions[] = { | ||
| 995 | {1, &IMultiCommitManager::Add, "Add"}, | ||
| 996 | {2, &IMultiCommitManager::Commit, "Commit"}, | ||
| 997 | }; | ||
| 998 | RegisterHandlers(functions); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | private: | ||
| 1002 | FileSys::VirtualFile backend; | ||
| 1003 | |||
| 1004 | void Add(Kernel::HLERequestContext& ctx) { | ||
| 1005 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 1006 | |||
| 1007 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1008 | rb.Push(RESULT_SUCCESS); | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | void Commit(Kernel::HLERequestContext& ctx) { | ||
| 1012 | LOG_WARNING(Service_FS, "(STUBBED) called"); | ||
| 1013 | |||
| 1014 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1015 | rb.Push(RESULT_SUCCESS); | ||
| 1016 | } | ||
| 1017 | }; | ||
| 1018 | |||
| 1019 | void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) { | ||
| 1020 | LOG_DEBUG(Service_FS, "called"); | ||
| 1021 | |||
| 1022 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 1023 | rb.Push(RESULT_SUCCESS); | ||
| 1024 | rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>()); | ||
| 1025 | } | ||
| 1026 | |||
| 991 | } // namespace Service::FileSystem | 1027 | } // namespace Service::FileSystem |
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index d52b55999..dfb3e395b 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h | |||
| @@ -50,6 +50,7 @@ private: | |||
| 50 | void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); | 50 | void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); |
| 51 | void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); | 51 | void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); |
| 52 | void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); | 52 | void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); |
| 53 | void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); | ||
| 53 | 54 | ||
| 54 | FileSystemController& fsc; | 55 | FileSystemController& fsc; |
| 55 | 56 | ||
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 5559587e3..c84cb1483 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -157,7 +157,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) { | |||
| 157 | {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, | 157 | {11, &Hid::ActivateTouchScreen, "ActivateTouchScreen"}, |
| 158 | {21, &Hid::ActivateMouse, "ActivateMouse"}, | 158 | {21, &Hid::ActivateMouse, "ActivateMouse"}, |
| 159 | {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, | 159 | {31, &Hid::ActivateKeyboard, "ActivateKeyboard"}, |
| 160 | {32, nullptr, "SendKeyboardLockKeyEvent"}, | 160 | {32, &Hid::SendKeyboardLockKeyEvent, "SendKeyboardLockKeyEvent"}, |
| 161 | {40, nullptr, "AcquireXpadIdEventHandle"}, | 161 | {40, nullptr, "AcquireXpadIdEventHandle"}, |
| 162 | {41, nullptr, "ReleaseXpadIdEventHandle"}, | 162 | {41, nullptr, "ReleaseXpadIdEventHandle"}, |
| 163 | {51, &Hid::ActivateXpad, "ActivateXpad"}, | 163 | {51, &Hid::ActivateXpad, "ActivateXpad"}, |
| @@ -871,6 +871,15 @@ void Hid::InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx) { | |||
| 871 | rb.Push(RESULT_SUCCESS); | 871 | rb.Push(RESULT_SUCCESS); |
| 872 | } | 872 | } |
| 873 | 873 | ||
| 874 | void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { | ||
| 875 | IPC::RequestParser rp{ctx}; | ||
| 876 | const auto flags{rp.Pop<u32>()}; | ||
| 877 | LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); | ||
| 878 | |||
| 879 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 880 | rb.Push(RESULT_SUCCESS); | ||
| 881 | } | ||
| 882 | |||
| 874 | class HidDbg final : public ServiceFramework<HidDbg> { | 883 | class HidDbg final : public ServiceFramework<HidDbg> { |
| 875 | public: | 884 | public: |
| 876 | explicit HidDbg() : ServiceFramework{"hid:dbg"} { | 885 | explicit HidDbg() : ServiceFramework{"hid:dbg"} { |
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 23552efb1..c8ed4ad8b 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h | |||
| @@ -130,6 +130,7 @@ private: | |||
| 130 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); | 130 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); |
| 131 | void StopSevenSixAxisSensor(Kernel::HLERequestContext& ctx); | 131 | void StopSevenSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 132 | void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx); | 132 | void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx); |
| 133 | void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); | ||
| 133 | 134 | ||
| 134 | std::shared_ptr<IAppletResource> applet_resource; | 135 | std::shared_ptr<IAppletResource> applet_resource; |
| 135 | Core::System& system; | 136 | Core::System& system; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index f1e3d832a..caca80dde 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -138,9 +138,7 @@ u32 BufferQueue::Query(QueryType type) { | |||
| 138 | 138 | ||
| 139 | switch (type) { | 139 | switch (type) { |
| 140 | case QueryType::NativeWindowFormat: | 140 | case QueryType::NativeWindowFormat: |
| 141 | // TODO(Subv): Use an enum for this | 141 | return static_cast<u32>(PixelFormat::RGBA8888); |
| 142 | static constexpr u32 FormatABGR8 = 1; | ||
| 143 | return FormatABGR8; | ||
| 144 | } | 142 | } |
| 145 | 143 | ||
| 146 | UNIMPLEMENTED(); | 144 | UNIMPLEMENTED(); |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index d5f31e567..8a837e5aa 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -66,6 +66,16 @@ public: | |||
| 66 | Rotate270 = 0x07, | 66 | Rotate270 = 0x07, |
| 67 | }; | 67 | }; |
| 68 | 68 | ||
| 69 | enum class PixelFormat : u32 { | ||
| 70 | RGBA8888 = 1, | ||
| 71 | RGBX8888 = 2, | ||
| 72 | RGB888 = 3, | ||
| 73 | RGB565 = 4, | ||
| 74 | BGRA8888 = 5, | ||
| 75 | RGBA5551 = 6, | ||
| 76 | RRGBA4444 = 7, | ||
| 77 | }; | ||
| 78 | |||
| 69 | struct Buffer { | 79 | struct Buffer { |
| 70 | enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; | 80 | enum class Status { Free = 0, Queued = 1, Dequeued = 2, Acquired = 3 }; |
| 71 | 81 | ||
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index 9d6c55865..b4dfe45e5 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <chrono> | 5 | #include <chrono> |
| 6 | #include <ctime> | 6 | #include <ctime> |
| 7 | 7 | ||
| 8 | #include "common/time_zone.h" | ||
| 8 | #include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h" | 9 | #include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h" |
| 9 | #include "core/hle/service/time/local_system_clock_context_writer.h" | 10 | #include "core/hle/service/time/local_system_clock_context_writer.h" |
| 10 | #include "core/hle/service/time/network_system_clock_context_writer.h" | 11 | #include "core/hle/service/time/network_system_clock_context_writer.h" |
| @@ -21,8 +22,16 @@ static std::chrono::seconds GetSecondsSinceEpoch() { | |||
| 21 | Settings::values.custom_rtc_differential; | 22 | Settings::values.custom_rtc_differential; |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 25 | static s64 GetExternalTimeZoneOffset() { | ||
| 26 | // With "auto" timezone setting, we use the external system's timezone offset | ||
| 27 | if (Settings::GetTimeZoneString() == "auto") { | ||
| 28 | return Common::TimeZone::GetCurrentOffsetSeconds().count(); | ||
| 29 | } | ||
| 30 | return 0; | ||
| 31 | } | ||
| 32 | |||
| 24 | static s64 GetExternalRtcValue() { | 33 | static s64 GetExternalRtcValue() { |
| 25 | return GetSecondsSinceEpoch().count(); | 34 | return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset(); |
| 26 | } | 35 | } |
| 27 | 36 | ||
| 28 | TimeManager::TimeManager(Core::System& system) | 37 | TimeManager::TimeManager(Core::System& system) |
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp index 78d4acd95..c070d6e97 100644 --- a/src/core/hle/service/time/time_zone_content_manager.cpp +++ b/src/core/hle/service/time/time_zone_content_manager.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <sstream> | 5 | #include <sstream> |
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "common/time_zone.h" | ||
| 8 | #include "core/core.h" | 9 | #include "core/core.h" |
| 9 | #include "core/file_sys/content_archive.h" | 10 | #include "core/file_sys/content_archive.h" |
| 10 | #include "core/file_sys/nca_metadata.h" | 11 | #include "core/file_sys/nca_metadata.h" |
| @@ -14,6 +15,7 @@ | |||
| 14 | #include "core/hle/service/filesystem/filesystem.h" | 15 | #include "core/hle/service/filesystem/filesystem.h" |
| 15 | #include "core/hle/service/time/time_manager.h" | 16 | #include "core/hle/service/time/time_manager.h" |
| 16 | #include "core/hle/service/time/time_zone_content_manager.h" | 17 | #include "core/hle/service/time/time_zone_content_manager.h" |
| 18 | #include "core/settings.h" | ||
| 17 | 19 | ||
| 18 | namespace Service::Time::TimeZone { | 20 | namespace Service::Time::TimeZone { |
| 19 | 21 | ||
| @@ -68,10 +70,22 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) { | |||
| 68 | 70 | ||
| 69 | TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) | 71 | TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) |
| 70 | : system{system}, location_name_cache{BuildLocationNameCache(system)} { | 72 | : system{system}, location_name_cache{BuildLocationNameCache(system)} { |
| 71 | if (FileSys::VirtualFile vfs_file; GetTimeZoneInfoFile("GMT", vfs_file) == RESULT_SUCCESS) { | 73 | |
| 74 | std::string location_name; | ||
| 75 | const auto timezone_setting = Settings::GetTimeZoneString(); | ||
| 76 | if (timezone_setting == "auto") { | ||
| 77 | location_name = Common::TimeZone::GetDefaultTimeZone(); | ||
| 78 | } else if (timezone_setting == "default") { | ||
| 79 | location_name = location_name; | ||
| 80 | } else { | ||
| 81 | location_name = timezone_setting; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (FileSys::VirtualFile vfs_file; | ||
| 85 | GetTimeZoneInfoFile(location_name, vfs_file) == RESULT_SUCCESS) { | ||
| 72 | const auto time_point{ | 86 | const auto time_point{ |
| 73 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; | 87 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; |
| 74 | time_manager.SetupTimeZoneManager("GMT", time_point, location_name_cache.size(), {}, | 88 | time_manager.SetupTimeZoneManager(location_name, time_point, location_name_cache.size(), {}, |
| 75 | vfs_file); | 89 | vfs_file); |
| 76 | } else { | 90 | } else { |
| 77 | time_zone_manager.MarkAsInitialized(); | 91 | time_zone_manager.MarkAsInitialized(); |
| @@ -114,6 +128,12 @@ ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& locati | |||
| 114 | 128 | ||
| 115 | vfs_file = zoneinfo_dir->GetFile(location_name); | 129 | vfs_file = zoneinfo_dir->GetFile(location_name); |
| 116 | if (!vfs_file) { | 130 | if (!vfs_file) { |
| 131 | LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"! Using default timezone.", | ||
| 132 | time_zone_binary_titleid, location_name); | ||
| 133 | vfs_file = zoneinfo_dir->GetFile(Common::TimeZone::GetDefaultTimeZone()); | ||
| 134 | } | ||
| 135 | |||
| 136 | if (!vfs_file) { | ||
| 117 | LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid, | 137 | LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid, |
| 118 | location_name); | 138 | location_name); |
| 119 | return ERROR_TIME_NOT_FOUND; | 139 | return ERROR_TIME_NOT_FOUND; |
diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 2b0bdc4d3..da53cde05 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp | |||
| @@ -63,6 +63,21 @@ const std::array<const char*, NumMouseButtons> mapping = {{ | |||
| 63 | 63 | ||
| 64 | Values values = {}; | 64 | Values values = {}; |
| 65 | 65 | ||
| 66 | std::string GetTimeZoneString() { | ||
| 67 | static constexpr std::array<const char*, 46> timezones{{ | ||
| 68 | "auto", "default", "CET", "CST6CDT", "Cuba", "EET", "Egypt", "Eire", | ||
| 69 | "EST", "EST5EDT", "GB", "GB-Eire", "GMT", "GMT+0", "GMT-0", "GMT0", | ||
| 70 | "Greenwich", "Hongkong", "HST", "Iceland", "Iran", "Israel", "Jamaica", "Japan", | ||
| 71 | "Kwajalein", "Libya", "MET", "MST", "MST7MDT", "Navajo", "NZ", "NZ-CHAT", | ||
| 72 | "Poland", "Portugal", "PRC", "PST8PDT", "ROC", "ROK", "Singapore", "Turkey", | ||
| 73 | "UCT", "Universal", "UTC", "W-SU", "WET", "Zulu", | ||
| 74 | }}; | ||
| 75 | |||
| 76 | ASSERT(Settings::values.time_zone_index < timezones.size()); | ||
| 77 | |||
| 78 | return timezones[Settings::values.time_zone_index]; | ||
| 79 | } | ||
| 80 | |||
| 66 | void Apply() { | 81 | void Apply() { |
| 67 | GDBStub::SetServerPort(values.gdbstub_port); | 82 | GDBStub::SetServerPort(values.gdbstub_port); |
| 68 | GDBStub::ToggleServer(values.use_gdbstub); | 83 | GDBStub::ToggleServer(values.use_gdbstub); |
| @@ -87,6 +102,7 @@ void LogSettings() { | |||
| 87 | LogSetting("System_CurrentUser", Settings::values.current_user); | 102 | LogSetting("System_CurrentUser", Settings::values.current_user); |
| 88 | LogSetting("System_LanguageIndex", Settings::values.language_index); | 103 | LogSetting("System_LanguageIndex", Settings::values.language_index); |
| 89 | LogSetting("System_RegionIndex", Settings::values.region_index); | 104 | LogSetting("System_RegionIndex", Settings::values.region_index); |
| 105 | LogSetting("System_TimeZoneIndex", Settings::values.time_zone_index); | ||
| 90 | LogSetting("Core_UseMultiCore", Settings::values.use_multi_core); | 106 | LogSetting("Core_UseMultiCore", Settings::values.use_multi_core); |
| 91 | LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); | 107 | LogSetting("Renderer_UseResolutionFactor", Settings::values.resolution_factor); |
| 92 | LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); | 108 | LogSetting("Renderer_UseFrameLimit", Settings::values.use_frame_limit); |
diff --git a/src/core/settings.h b/src/core/settings.h index 163900f0b..c1266b341 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -394,6 +394,7 @@ struct Values { | |||
| 394 | s32 current_user; | 394 | s32 current_user; |
| 395 | s32 language_index; | 395 | s32 language_index; |
| 396 | s32 region_index; | 396 | s32 region_index; |
| 397 | s32 time_zone_index; | ||
| 397 | s32 sound_index; | 398 | s32 sound_index; |
| 398 | 399 | ||
| 399 | // Controls | 400 | // Controls |
| @@ -490,6 +491,9 @@ struct Values { | |||
| 490 | bool IsGPULevelExtreme(); | 491 | bool IsGPULevelExtreme(); |
| 491 | bool IsGPULevelHigh(); | 492 | bool IsGPULevelHigh(); |
| 492 | 493 | ||
| 494 | std::string GetTimeZoneString(); | ||
| 495 | |||
| 493 | void Apply(); | 496 | void Apply(); |
| 494 | void LogSettings(); | 497 | void LogSettings(); |
| 498 | |||
| 495 | } // namespace Settings | 499 | } // namespace Settings |
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp index bdc023d54..f2f96ac33 100644 --- a/src/video_core/dma_pusher.cpp +++ b/src/video_core/dma_pusher.cpp | |||
| @@ -54,9 +54,7 @@ bool DmaPusher::Step() { | |||
| 54 | return true; | 54 | return true; |
| 55 | }); | 55 | }); |
| 56 | const CommandListHeader command_list_header{command_list[dma_pushbuffer_subindex++]}; | 56 | const CommandListHeader command_list_header{command_list[dma_pushbuffer_subindex++]}; |
| 57 | GPUVAddr dma_get = command_list_header.addr; | 57 | const GPUVAddr dma_get = command_list_header.addr; |
| 58 | GPUVAddr dma_put = dma_get + command_list_header.size * sizeof(u32); | ||
| 59 | bool non_main = command_list_header.is_non_main; | ||
| 60 | 58 | ||
| 61 | if (dma_pushbuffer_subindex >= command_list.size()) { | 59 | if (dma_pushbuffer_subindex >= command_list.size()) { |
| 62 | // We've gone through the current list, remove it from the queue | 60 | // We've gone through the current list, remove it from the queue |
| @@ -133,11 +131,6 @@ bool DmaPusher::Step() { | |||
| 133 | index++; | 131 | index++; |
| 134 | } | 132 | } |
| 135 | 133 | ||
| 136 | if (!non_main) { | ||
| 137 | // TODO (degasus): This is dead code, as dma_mget is never read. | ||
| 138 | dma_mget = dma_put; | ||
| 139 | } | ||
| 140 | |||
| 141 | return true; | 134 | return true; |
| 142 | } | 135 | } |
| 143 | 136 | ||
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h index e8b714e94..efa90d170 100644 --- a/src/video_core/dma_pusher.h +++ b/src/video_core/dma_pusher.h | |||
| @@ -102,7 +102,6 @@ private: | |||
| 102 | DmaState dma_state{}; | 102 | DmaState dma_state{}; |
| 103 | bool dma_increment_once{}; | 103 | bool dma_increment_once{}; |
| 104 | 104 | ||
| 105 | GPUVAddr dma_mget{}; ///< main pushbuffer last read address | ||
| 106 | bool ib_enable{true}; ///< IB mode enabled | 105 | bool ib_enable{true}; ///< IB mode enabled |
| 107 | 106 | ||
| 108 | std::array<Tegra::Engines::EngineInterface*, max_subchannels> subchannels{}; | 107 | std::array<Tegra::Engines::EngineInterface*, max_subchannels> subchannels{}; |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 8dae754d4..e7cb87589 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -168,18 +168,22 @@ enum class Pred : u64 { | |||
| 168 | }; | 168 | }; |
| 169 | 169 | ||
| 170 | enum class PredCondition : u64 { | 170 | enum class PredCondition : u64 { |
| 171 | LessThan = 1, | 171 | F = 0, // Always false |
| 172 | Equal = 2, | 172 | LT = 1, // Ordered less than |
| 173 | LessEqual = 3, | 173 | EQ = 2, // Ordered equal |
| 174 | GreaterThan = 4, | 174 | LE = 3, // Ordered less than or equal |
| 175 | NotEqual = 5, | 175 | GT = 4, // Ordered greater than |
| 176 | GreaterEqual = 6, | 176 | NE = 5, // Ordered not equal |
| 177 | LessThanWithNan = 9, | 177 | GE = 6, // Ordered greater than or equal |
| 178 | LessEqualWithNan = 11, | 178 | NUM = 7, // Ordered |
| 179 | GreaterThanWithNan = 12, | 179 | NAN_ = 8, // Unordered |
| 180 | NotEqualWithNan = 13, | 180 | LTU = 9, // Unordered less than |
| 181 | GreaterEqualWithNan = 14, | 181 | EQU = 10, // Unordered equal |
| 182 | // TODO(Subv): Other condition types | 182 | LEU = 11, // Unordered less than or equal |
| 183 | GTU = 12, // Unordered greater than | ||
| 184 | NEU = 13, // Unordered not equal | ||
| 185 | GEU = 14, // Unordered greater than or equal | ||
| 186 | T = 15, // Always true | ||
| 183 | }; | 187 | }; |
| 184 | 188 | ||
| 185 | enum class PredOperation : u64 { | 189 | enum class PredOperation : u64 { |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 99fd4ae2c..960ebf1a1 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -1840,34 +1840,40 @@ private: | |||
| 1840 | Type::HalfFloat}; | 1840 | Type::HalfFloat}; |
| 1841 | } | 1841 | } |
| 1842 | 1842 | ||
| 1843 | template <Type type> | 1843 | template <const std::string_view& op, Type type, bool unordered = false> |
| 1844 | Expression LogicalLessThan(Operation operation) { | 1844 | Expression Comparison(Operation operation) { |
| 1845 | return GenerateBinaryInfix(operation, "<", Type::Bool, type, type); | 1845 | static_assert(!unordered || type == Type::Float); |
| 1846 | } | 1846 | |
| 1847 | 1847 | const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type); | |
| 1848 | template <Type type> | 1848 | |
| 1849 | Expression LogicalEqual(Operation operation) { | 1849 | if constexpr (op.compare("!=") == 0 && type == Type::Float && !unordered) { |
| 1850 | return GenerateBinaryInfix(operation, "==", Type::Bool, type, type); | 1850 | // GLSL's operator!=(float, float) doesn't seem be ordered. This happens on both AMD's |
| 1851 | } | 1851 | // and Nvidia's proprietary stacks. Manually force an ordered comparison. |
| 1852 | 1852 | return {fmt::format("({} && !isnan({}) && !isnan({}))", expr.AsBool(), | |
| 1853 | template <Type type> | 1853 | VisitOperand(operation, 0).AsFloat(), |
| 1854 | Expression LogicalLessEqual(Operation operation) { | 1854 | VisitOperand(operation, 1).AsFloat()), |
| 1855 | return GenerateBinaryInfix(operation, "<=", Type::Bool, type, type); | 1855 | Type::Bool}; |
| 1856 | } | 1856 | } |
| 1857 | 1857 | if constexpr (!unordered) { | |
| 1858 | template <Type type> | 1858 | return expr; |
| 1859 | Expression LogicalGreaterThan(Operation operation) { | 1859 | } |
| 1860 | return GenerateBinaryInfix(operation, ">", Type::Bool, type, type); | 1860 | // Unordered comparisons are always true for NaN operands. |
| 1861 | return {fmt::format("({} || isnan({}) || isnan({}))", expr.AsBool(), | ||
| 1862 | VisitOperand(operation, 0).AsFloat(), | ||
| 1863 | VisitOperand(operation, 1).AsFloat()), | ||
| 1864 | Type::Bool}; | ||
| 1861 | } | 1865 | } |
| 1862 | 1866 | ||
| 1863 | template <Type type> | 1867 | Expression FOrdered(Operation operation) { |
| 1864 | Expression LogicalNotEqual(Operation operation) { | 1868 | return {fmt::format("(!isnan({}) && !isnan({}))", VisitOperand(operation, 0).AsFloat(), |
| 1865 | return GenerateBinaryInfix(operation, "!=", Type::Bool, type, type); | 1869 | VisitOperand(operation, 1).AsFloat()), |
| 1870 | Type::Bool}; | ||
| 1866 | } | 1871 | } |
| 1867 | 1872 | ||
| 1868 | template <Type type> | 1873 | Expression FUnordered(Operation operation) { |
| 1869 | Expression LogicalGreaterEqual(Operation operation) { | 1874 | return {fmt::format("(isnan({}) || isnan({}))", VisitOperand(operation, 0).AsFloat(), |
| 1870 | return GenerateBinaryInfix(operation, ">=", Type::Bool, type, type); | 1875 | VisitOperand(operation, 1).AsFloat()), |
| 1876 | Type::Bool}; | ||
| 1871 | } | 1877 | } |
| 1872 | 1878 | ||
| 1873 | Expression LogicalAddCarry(Operation operation) { | 1879 | Expression LogicalAddCarry(Operation operation) { |
| @@ -2324,6 +2330,13 @@ private: | |||
| 2324 | Func() = delete; | 2330 | Func() = delete; |
| 2325 | ~Func() = delete; | 2331 | ~Func() = delete; |
| 2326 | 2332 | ||
| 2333 | static constexpr std::string_view LessThan = "<"; | ||
| 2334 | static constexpr std::string_view Equal = "=="; | ||
| 2335 | static constexpr std::string_view LessEqual = "<="; | ||
| 2336 | static constexpr std::string_view GreaterThan = ">"; | ||
| 2337 | static constexpr std::string_view NotEqual = "!="; | ||
| 2338 | static constexpr std::string_view GreaterEqual = ">="; | ||
| 2339 | |||
| 2327 | static constexpr std::string_view Add = "Add"; | 2340 | static constexpr std::string_view Add = "Add"; |
| 2328 | static constexpr std::string_view Min = "Min"; | 2341 | static constexpr std::string_view Min = "Min"; |
| 2329 | static constexpr std::string_view Max = "Max"; | 2342 | static constexpr std::string_view Max = "Max"; |
| @@ -2425,27 +2438,34 @@ private: | |||
| 2425 | &GLSLDecompiler::LogicalPick2, | 2438 | &GLSLDecompiler::LogicalPick2, |
| 2426 | &GLSLDecompiler::LogicalAnd2, | 2439 | &GLSLDecompiler::LogicalAnd2, |
| 2427 | 2440 | ||
| 2428 | &GLSLDecompiler::LogicalLessThan<Type::Float>, | 2441 | &GLSLDecompiler::Comparison<Func::LessThan, Type::Float, false>, |
| 2429 | &GLSLDecompiler::LogicalEqual<Type::Float>, | 2442 | &GLSLDecompiler::Comparison<Func::Equal, Type::Float, false>, |
| 2430 | &GLSLDecompiler::LogicalLessEqual<Type::Float>, | 2443 | &GLSLDecompiler::Comparison<Func::LessEqual, Type::Float, false>, |
| 2431 | &GLSLDecompiler::LogicalGreaterThan<Type::Float>, | 2444 | &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Float, false>, |
| 2432 | &GLSLDecompiler::LogicalNotEqual<Type::Float>, | 2445 | &GLSLDecompiler::Comparison<Func::NotEqual, Type::Float, false>, |
| 2433 | &GLSLDecompiler::LogicalGreaterEqual<Type::Float>, | 2446 | &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Float, false>, |
| 2434 | &GLSLDecompiler::LogicalFIsNan, | 2447 | &GLSLDecompiler::FOrdered, |
| 2435 | 2448 | &GLSLDecompiler::FUnordered, | |
| 2436 | &GLSLDecompiler::LogicalLessThan<Type::Int>, | 2449 | &GLSLDecompiler::Comparison<Func::LessThan, Type::Float, true>, |
| 2437 | &GLSLDecompiler::LogicalEqual<Type::Int>, | 2450 | &GLSLDecompiler::Comparison<Func::Equal, Type::Float, true>, |
| 2438 | &GLSLDecompiler::LogicalLessEqual<Type::Int>, | 2451 | &GLSLDecompiler::Comparison<Func::LessEqual, Type::Float, true>, |
| 2439 | &GLSLDecompiler::LogicalGreaterThan<Type::Int>, | 2452 | &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Float, true>, |
| 2440 | &GLSLDecompiler::LogicalNotEqual<Type::Int>, | 2453 | &GLSLDecompiler::Comparison<Func::NotEqual, Type::Float, true>, |
| 2441 | &GLSLDecompiler::LogicalGreaterEqual<Type::Int>, | 2454 | &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Float, true>, |
| 2442 | 2455 | ||
| 2443 | &GLSLDecompiler::LogicalLessThan<Type::Uint>, | 2456 | &GLSLDecompiler::Comparison<Func::LessThan, Type::Int>, |
| 2444 | &GLSLDecompiler::LogicalEqual<Type::Uint>, | 2457 | &GLSLDecompiler::Comparison<Func::Equal, Type::Int>, |
| 2445 | &GLSLDecompiler::LogicalLessEqual<Type::Uint>, | 2458 | &GLSLDecompiler::Comparison<Func::LessEqual, Type::Int>, |
| 2446 | &GLSLDecompiler::LogicalGreaterThan<Type::Uint>, | 2459 | &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Int>, |
| 2447 | &GLSLDecompiler::LogicalNotEqual<Type::Uint>, | 2460 | &GLSLDecompiler::Comparison<Func::NotEqual, Type::Int>, |
| 2448 | &GLSLDecompiler::LogicalGreaterEqual<Type::Uint>, | 2461 | &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Int>, |
| 2462 | |||
| 2463 | &GLSLDecompiler::Comparison<Func::LessThan, Type::Uint>, | ||
| 2464 | &GLSLDecompiler::Comparison<Func::Equal, Type::Uint>, | ||
| 2465 | &GLSLDecompiler::Comparison<Func::LessEqual, Type::Uint>, | ||
| 2466 | &GLSLDecompiler::Comparison<Func::GreaterThan, Type::Uint>, | ||
| 2467 | &GLSLDecompiler::Comparison<Func::NotEqual, Type::Uint>, | ||
| 2468 | &GLSLDecompiler::Comparison<Func::GreaterEqual, Type::Uint>, | ||
| 2449 | 2469 | ||
| 2450 | &GLSLDecompiler::LogicalAddCarry, | 2470 | &GLSLDecompiler::LogicalAddCarry, |
| 2451 | 2471 | ||
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 6cead3a28..568744e3c 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp | |||
| @@ -93,6 +93,7 @@ void FixedPipelineState::Rasterizer::Fill(const Maxwell& regs) noexcept { | |||
| 93 | tessellation_clockwise.Assign(regs.tess_mode.cw.Value()); | 93 | tessellation_clockwise.Assign(regs.tess_mode.cw.Value()); |
| 94 | logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); | 94 | logic_op_enable.Assign(regs.logic_op.enable != 0 ? 1 : 0); |
| 95 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); | 95 | logic_op.Assign(PackLogicOp(regs.logic_op.operation)); |
| 96 | rasterize_enable.Assign(regs.rasterize_enable != 0 ? 1 : 0); | ||
| 96 | std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast | 97 | std::memcpy(&point_size, ®s.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast |
| 97 | } | 98 | } |
| 98 | 99 | ||
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index cecaee48d..31a6398f2 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h | |||
| @@ -164,6 +164,7 @@ struct FixedPipelineState { | |||
| 164 | BitField<23, 1, u32> tessellation_clockwise; | 164 | BitField<23, 1, u32> tessellation_clockwise; |
| 165 | BitField<24, 1, u32> logic_op_enable; | 165 | BitField<24, 1, u32> logic_op_enable; |
| 166 | BitField<25, 4, u32> logic_op; | 166 | BitField<25, 4, u32> logic_op; |
| 167 | BitField<29, 1, u32> rasterize_enable; | ||
| 167 | }; | 168 | }; |
| 168 | 169 | ||
| 169 | // TODO(Rodrigo): Move this to push constants | 170 | // TODO(Rodrigo): Move this to push constants |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 5beea6a03..69b6bba00 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -281,7 +281,7 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa | |||
| 281 | rasterization_ci.pNext = nullptr; | 281 | rasterization_ci.pNext = nullptr; |
| 282 | rasterization_ci.flags = 0; | 282 | rasterization_ci.flags = 0; |
| 283 | rasterization_ci.depthClampEnable = rs.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE; | 283 | rasterization_ci.depthClampEnable = rs.depth_clamp_disabled == 0 ? VK_TRUE : VK_FALSE; |
| 284 | rasterization_ci.rasterizerDiscardEnable = VK_FALSE; | 284 | rasterization_ci.rasterizerDiscardEnable = rs.rasterize_enable == 0 ? VK_TRUE : VK_FALSE; |
| 285 | rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; | 285 | rasterization_ci.polygonMode = VK_POLYGON_MODE_FILL; |
| 286 | rasterization_ci.cullMode = | 286 | rasterization_ci.cullMode = |
| 287 | rs.cull_enable ? MaxwellToVK::CullFace(rs.CullFace()) : VK_CULL_MODE_NONE; | 287 | rs.cull_enable ? MaxwellToVK::CullFace(rs.CullFace()) : VK_CULL_MODE_NONE; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 8b009fc22..17a2efe8e 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -569,7 +569,9 @@ void RasterizerVulkan::ReleaseFences() { | |||
| 569 | } | 569 | } |
| 570 | 570 | ||
| 571 | void RasterizerVulkan::FlushAndInvalidateRegion(VAddr addr, u64 size) { | 571 | void RasterizerVulkan::FlushAndInvalidateRegion(VAddr addr, u64 size) { |
| 572 | FlushRegion(addr, size); | 572 | if (Settings::IsGPULevelExtreme()) { |
| 573 | FlushRegion(addr, size); | ||
| 574 | } | ||
| 573 | InvalidateRegion(addr, size); | 575 | InvalidateRegion(addr, size); |
| 574 | } | 576 | } |
| 575 | 577 | ||
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 18678968c..167e20e91 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -1618,6 +1618,24 @@ private: | |||
| 1618 | return {}; | 1618 | return {}; |
| 1619 | } | 1619 | } |
| 1620 | 1620 | ||
| 1621 | Expression LogicalFOrdered(Operation operation) { | ||
| 1622 | // Emulate SPIR-V's OpOrdered | ||
| 1623 | const Id op_a = AsFloat(Visit(operation[0])); | ||
| 1624 | const Id op_b = AsFloat(Visit(operation[1])); | ||
| 1625 | const Id is_num_a = OpFOrdEqual(t_bool, op_a, op_a); | ||
| 1626 | const Id is_num_b = OpFOrdEqual(t_bool, op_b, op_b); | ||
| 1627 | return {OpLogicalAnd(t_bool, is_num_a, is_num_b), Type::Bool}; | ||
| 1628 | } | ||
| 1629 | |||
| 1630 | Expression LogicalFUnordered(Operation operation) { | ||
| 1631 | // Emulate SPIR-V's OpUnordered | ||
| 1632 | const Id op_a = AsFloat(Visit(operation[0])); | ||
| 1633 | const Id op_b = AsFloat(Visit(operation[1])); | ||
| 1634 | const Id is_nan_a = OpIsNan(t_bool, op_a); | ||
| 1635 | const Id is_nan_b = OpIsNan(t_bool, op_b); | ||
| 1636 | return {OpLogicalOr(t_bool, is_nan_a, is_nan_b), Type::Bool}; | ||
| 1637 | } | ||
| 1638 | |||
| 1621 | Id GetTextureSampler(Operation operation) { | 1639 | Id GetTextureSampler(Operation operation) { |
| 1622 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); | 1640 | const auto& meta = std::get<MetaTexture>(operation.GetMeta()); |
| 1623 | ASSERT(!meta.sampler.is_buffer); | 1641 | ASSERT(!meta.sampler.is_buffer); |
| @@ -2511,7 +2529,14 @@ private: | |||
| 2511 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::Float>, | 2529 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThan, Type::Bool, Type::Float>, |
| 2512 | &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::Float>, | 2530 | &SPIRVDecompiler::Binary<&Module::OpFOrdNotEqual, Type::Bool, Type::Float>, |
| 2513 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::Float>, | 2531 | &SPIRVDecompiler::Binary<&Module::OpFOrdGreaterThanEqual, Type::Bool, Type::Float>, |
| 2514 | &SPIRVDecompiler::Unary<&Module::OpIsNan, Type::Bool, Type::Float>, | 2532 | &SPIRVDecompiler::LogicalFOrdered, |
| 2533 | &SPIRVDecompiler::LogicalFUnordered, | ||
| 2534 | &SPIRVDecompiler::Binary<&Module::OpFUnordLessThan, Type::Bool, Type::Float>, | ||
| 2535 | &SPIRVDecompiler::Binary<&Module::OpFUnordEqual, Type::Bool, Type::Float>, | ||
| 2536 | &SPIRVDecompiler::Binary<&Module::OpFUnordLessThanEqual, Type::Bool, Type::Float>, | ||
| 2537 | &SPIRVDecompiler::Binary<&Module::OpFUnordGreaterThan, Type::Bool, Type::Float>, | ||
| 2538 | &SPIRVDecompiler::Binary<&Module::OpFUnordNotEqual, Type::Bool, Type::Float>, | ||
| 2539 | &SPIRVDecompiler::Binary<&Module::OpFUnordGreaterThanEqual, Type::Bool, Type::Float>, | ||
| 2515 | 2540 | ||
| 2516 | &SPIRVDecompiler::Binary<&Module::OpSLessThan, Type::Bool, Type::Int>, | 2541 | &SPIRVDecompiler::Binary<&Module::OpSLessThan, Type::Bool, Type::Int>, |
| 2517 | &SPIRVDecompiler::Binary<&Module::OpIEqual, Type::Bool, Type::Int>, | 2542 | &SPIRVDecompiler::Binary<&Module::OpIEqual, Type::Bool, Type::Int>, |
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index a75a5cc63..eeac328a6 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp | |||
| @@ -255,7 +255,7 @@ void ShaderIR::InsertControlFlow(NodeBlock& bb, const ShaderBlock& block) { | |||
| 255 | Node n = Operation(OperationCode::Branch, Immediate(branch_case.address)); | 255 | Node n = Operation(OperationCode::Branch, Immediate(branch_case.address)); |
| 256 | Node op_b = Immediate(branch_case.cmp_value); | 256 | Node op_b = Immediate(branch_case.cmp_value); |
| 257 | Node condition = | 257 | Node condition = |
| 258 | GetPredicateComparisonInteger(Tegra::Shader::PredCondition::Equal, false, op_a, op_b); | 258 | GetPredicateComparisonInteger(Tegra::Shader::PredCondition::EQ, false, op_a, op_b); |
| 259 | auto result = Conditional(condition, {n}); | 259 | auto result = Conditional(condition, {n}); |
| 260 | bb.push_back(result); | 260 | bb.push_back(result); |
| 261 | global_code.push_back(result); | 261 | global_code.push_back(result); |
diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp index 6191ffba1..c83dc6615 100644 --- a/src/video_core/shader/decode/xmad.cpp +++ b/src/video_core/shader/decode/xmad.cpp | |||
| @@ -97,19 +97,19 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) { | |||
| 97 | return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b); | 97 | return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b); |
| 98 | } | 98 | } |
| 99 | case Tegra::Shader::XmadMode::CSfu: { | 99 | case Tegra::Shader::XmadMode::CSfu: { |
| 100 | const Node comp_a = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_a, | 100 | const Node comp_a = |
| 101 | op_a, Immediate(0)); | 101 | GetPredicateComparisonInteger(PredCondition::EQ, is_signed_a, op_a, Immediate(0)); |
| 102 | const Node comp_b = GetPredicateComparisonInteger(PredCondition::Equal, is_signed_b, | 102 | const Node comp_b = |
| 103 | op_b, Immediate(0)); | 103 | GetPredicateComparisonInteger(PredCondition::EQ, is_signed_b, op_b, Immediate(0)); |
| 104 | const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b); | 104 | const Node comp = Operation(OperationCode::LogicalOr, comp_a, comp_b); |
| 105 | 105 | ||
| 106 | const Node comp_minus_a = GetPredicateComparisonInteger( | 106 | const Node comp_minus_a = GetPredicateComparisonInteger( |
| 107 | PredCondition::NotEqual, is_signed_a, | 107 | PredCondition::NE, is_signed_a, |
| 108 | SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a, | 108 | SignedOperation(OperationCode::IBitwiseAnd, is_signed_a, op_a, |
| 109 | Immediate(0x80000000)), | 109 | Immediate(0x80000000)), |
| 110 | Immediate(0)); | 110 | Immediate(0)); |
| 111 | const Node comp_minus_b = GetPredicateComparisonInteger( | 111 | const Node comp_minus_b = GetPredicateComparisonInteger( |
| 112 | PredCondition::NotEqual, is_signed_b, | 112 | PredCondition::NE, is_signed_b, |
| 113 | SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b, | 113 | SignedOperation(OperationCode::IBitwiseAnd, is_signed_b, op_b, |
| 114 | Immediate(0x80000000)), | 114 | Immediate(0x80000000)), |
| 115 | Immediate(0)); | 115 | Immediate(0)); |
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index 601c822d2..f75b62240 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h | |||
| @@ -110,13 +110,20 @@ enum class OperationCode { | |||
| 110 | LogicalPick2, /// (bool2 pair, uint index) -> bool | 110 | LogicalPick2, /// (bool2 pair, uint index) -> bool |
| 111 | LogicalAnd2, /// (bool2 a) -> bool | 111 | LogicalAnd2, /// (bool2 a) -> bool |
| 112 | 112 | ||
| 113 | LogicalFLessThan, /// (float a, float b) -> bool | 113 | LogicalFOrdLessThan, /// (float a, float b) -> bool |
| 114 | LogicalFEqual, /// (float a, float b) -> bool | 114 | LogicalFOrdEqual, /// (float a, float b) -> bool |
| 115 | LogicalFLessEqual, /// (float a, float b) -> bool | 115 | LogicalFOrdLessEqual, /// (float a, float b) -> bool |
| 116 | LogicalFGreaterThan, /// (float a, float b) -> bool | 116 | LogicalFOrdGreaterThan, /// (float a, float b) -> bool |
| 117 | LogicalFNotEqual, /// (float a, float b) -> bool | 117 | LogicalFOrdNotEqual, /// (float a, float b) -> bool |
| 118 | LogicalFGreaterEqual, /// (float a, float b) -> bool | 118 | LogicalFOrdGreaterEqual, /// (float a, float b) -> bool |
| 119 | LogicalFIsNan, /// (float a) -> bool | 119 | LogicalFOrdered, /// (float a, float b) -> bool |
| 120 | LogicalFUnordered, /// (float a, float b) -> bool | ||
| 121 | LogicalFUnordLessThan, /// (float a, float b) -> bool | ||
| 122 | LogicalFUnordEqual, /// (float a, float b) -> bool | ||
| 123 | LogicalFUnordLessEqual, /// (float a, float b) -> bool | ||
| 124 | LogicalFUnordGreaterThan, /// (float a, float b) -> bool | ||
| 125 | LogicalFUnordNotEqual, /// (float a, float b) -> bool | ||
| 126 | LogicalFUnordGreaterEqual, /// (float a, float b) -> bool | ||
| 120 | 127 | ||
| 121 | LogicalILessThan, /// (int a, int b) -> bool | 128 | LogicalILessThan, /// (int a, int b) -> bool |
| 122 | LogicalIEqual, /// (int a, int b) -> bool | 129 | LogicalIEqual, /// (int a, int b) -> bool |
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 822674926..e322c3402 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "video_core/engines/shader_bytecode.h" | 12 | #include "video_core/engines/shader_bytecode.h" |
| 13 | #include "video_core/shader/node.h" | ||
| 13 | #include "video_core/shader/node_helper.h" | 14 | #include "video_core/shader/node_helper.h" |
| 14 | #include "video_core/shader/registry.h" | 15 | #include "video_core/shader/registry.h" |
| 15 | #include "video_core/shader/shader_ir.h" | 16 | #include "video_core/shader/shader_ir.h" |
| @@ -243,56 +244,44 @@ Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) { | |||
| 243 | } | 244 | } |
| 244 | 245 | ||
| 245 | Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { | 246 | Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) { |
| 247 | if (condition == PredCondition::T) { | ||
| 248 | return GetPredicate(true); | ||
| 249 | } else if (condition == PredCondition::F) { | ||
| 250 | return GetPredicate(false); | ||
| 251 | } | ||
| 252 | |||
| 246 | static constexpr std::array comparison_table{ | 253 | static constexpr std::array comparison_table{ |
| 247 | std::pair{PredCondition::LessThan, OperationCode::LogicalFLessThan}, | 254 | OperationCode(0), |
| 248 | std::pair{PredCondition::Equal, OperationCode::LogicalFEqual}, | 255 | OperationCode::LogicalFOrdLessThan, // LT |
| 249 | std::pair{PredCondition::LessEqual, OperationCode::LogicalFLessEqual}, | 256 | OperationCode::LogicalFOrdEqual, // EQ |
| 250 | std::pair{PredCondition::GreaterThan, OperationCode::LogicalFGreaterThan}, | 257 | OperationCode::LogicalFOrdLessEqual, // LE |
| 251 | std::pair{PredCondition::NotEqual, OperationCode::LogicalFNotEqual}, | 258 | OperationCode::LogicalFOrdGreaterThan, // GT |
| 252 | std::pair{PredCondition::GreaterEqual, OperationCode::LogicalFGreaterEqual}, | 259 | OperationCode::LogicalFOrdNotEqual, // NE |
| 253 | std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalFLessThan}, | 260 | OperationCode::LogicalFOrdGreaterEqual, // GE |
| 254 | std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalFNotEqual}, | 261 | OperationCode::LogicalFOrdered, // NUM |
| 255 | std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalFLessEqual}, | 262 | OperationCode::LogicalFUnordered, // NAN |
| 256 | std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalFGreaterThan}, | 263 | OperationCode::LogicalFUnordLessThan, // LTU |
| 257 | std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalFGreaterEqual}, | 264 | OperationCode::LogicalFUnordEqual, // EQU |
| 265 | OperationCode::LogicalFUnordLessEqual, // LEU | ||
| 266 | OperationCode::LogicalFUnordGreaterThan, // GTU | ||
| 267 | OperationCode::LogicalFUnordNotEqual, // NEU | ||
| 268 | OperationCode::LogicalFUnordGreaterEqual, // GEU | ||
| 258 | }; | 269 | }; |
| 270 | const std::size_t index = static_cast<std::size_t>(condition); | ||
| 271 | ASSERT_MSG(index < std::size(comparison_table), "Invalid condition={}", index); | ||
| 259 | 272 | ||
| 260 | const auto comparison = | 273 | return Operation(comparison_table[index], op_a, op_b); |
| 261 | std::find_if(comparison_table.cbegin(), comparison_table.cend(), | ||
| 262 | [condition](const auto entry) { return condition == entry.first; }); | ||
| 263 | UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(), | ||
| 264 | "Unknown predicate comparison operation"); | ||
| 265 | |||
| 266 | Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b); | ||
| 267 | |||
| 268 | if (condition == PredCondition::LessThanWithNan || | ||
| 269 | condition == PredCondition::NotEqualWithNan || | ||
| 270 | condition == PredCondition::LessEqualWithNan || | ||
| 271 | condition == PredCondition::GreaterThanWithNan || | ||
| 272 | condition == PredCondition::GreaterEqualWithNan) { | ||
| 273 | predicate = Operation(OperationCode::LogicalOr, predicate, | ||
| 274 | Operation(OperationCode::LogicalFIsNan, op_a)); | ||
| 275 | predicate = Operation(OperationCode::LogicalOr, predicate, | ||
| 276 | Operation(OperationCode::LogicalFIsNan, op_b)); | ||
| 277 | } | ||
| 278 | |||
| 279 | return predicate; | ||
| 280 | } | 274 | } |
| 281 | 275 | ||
| 282 | Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a, | 276 | Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a, |
| 283 | Node op_b) { | 277 | Node op_b) { |
| 284 | static constexpr std::array comparison_table{ | 278 | static constexpr std::array comparison_table{ |
| 285 | std::pair{PredCondition::LessThan, OperationCode::LogicalILessThan}, | 279 | std::pair{PredCondition::LT, OperationCode::LogicalILessThan}, |
| 286 | std::pair{PredCondition::Equal, OperationCode::LogicalIEqual}, | 280 | std::pair{PredCondition::EQ, OperationCode::LogicalIEqual}, |
| 287 | std::pair{PredCondition::LessEqual, OperationCode::LogicalILessEqual}, | 281 | std::pair{PredCondition::LE, OperationCode::LogicalILessEqual}, |
| 288 | std::pair{PredCondition::GreaterThan, OperationCode::LogicalIGreaterThan}, | 282 | std::pair{PredCondition::GT, OperationCode::LogicalIGreaterThan}, |
| 289 | std::pair{PredCondition::NotEqual, OperationCode::LogicalINotEqual}, | 283 | std::pair{PredCondition::NE, OperationCode::LogicalINotEqual}, |
| 290 | std::pair{PredCondition::GreaterEqual, OperationCode::LogicalIGreaterEqual}, | 284 | std::pair{PredCondition::GE, OperationCode::LogicalIGreaterEqual}, |
| 291 | std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalILessThan}, | ||
| 292 | std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalINotEqual}, | ||
| 293 | std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalILessEqual}, | ||
| 294 | std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalIGreaterThan}, | ||
| 295 | std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalIGreaterEqual}, | ||
| 296 | }; | 285 | }; |
| 297 | 286 | ||
| 298 | const auto comparison = | 287 | const auto comparison = |
| @@ -301,32 +290,24 @@ Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_si | |||
| 301 | UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(), | 290 | UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(), |
| 302 | "Unknown predicate comparison operation"); | 291 | "Unknown predicate comparison operation"); |
| 303 | 292 | ||
| 304 | Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a), | 293 | return SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a), |
| 305 | std::move(op_b)); | 294 | std::move(op_b)); |
| 306 | |||
| 307 | UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan || | ||
| 308 | condition == PredCondition::NotEqualWithNan || | ||
| 309 | condition == PredCondition::LessEqualWithNan || | ||
| 310 | condition == PredCondition::GreaterThanWithNan || | ||
| 311 | condition == PredCondition::GreaterEqualWithNan, | ||
| 312 | "NaN comparisons for integers are not implemented"); | ||
| 313 | return predicate; | ||
| 314 | } | 295 | } |
| 315 | 296 | ||
| 316 | Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a, | 297 | Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a, |
| 317 | Node op_b) { | 298 | Node op_b) { |
| 318 | static constexpr std::array comparison_table{ | 299 | static constexpr std::array comparison_table{ |
| 319 | std::pair{PredCondition::LessThan, OperationCode::Logical2HLessThan}, | 300 | std::pair{PredCondition::LT, OperationCode::Logical2HLessThan}, |
| 320 | std::pair{PredCondition::Equal, OperationCode::Logical2HEqual}, | 301 | std::pair{PredCondition::EQ, OperationCode::Logical2HEqual}, |
| 321 | std::pair{PredCondition::LessEqual, OperationCode::Logical2HLessEqual}, | 302 | std::pair{PredCondition::LE, OperationCode::Logical2HLessEqual}, |
| 322 | std::pair{PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan}, | 303 | std::pair{PredCondition::GT, OperationCode::Logical2HGreaterThan}, |
| 323 | std::pair{PredCondition::NotEqual, OperationCode::Logical2HNotEqual}, | 304 | std::pair{PredCondition::NE, OperationCode::Logical2HNotEqual}, |
| 324 | std::pair{PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual}, | 305 | std::pair{PredCondition::GE, OperationCode::Logical2HGreaterEqual}, |
| 325 | std::pair{PredCondition::LessThanWithNan, OperationCode::Logical2HLessThanWithNan}, | 306 | std::pair{PredCondition::LTU, OperationCode::Logical2HLessThanWithNan}, |
| 326 | std::pair{PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqualWithNan}, | 307 | std::pair{PredCondition::LEU, OperationCode::Logical2HLessEqualWithNan}, |
| 327 | std::pair{PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqualWithNan}, | 308 | std::pair{PredCondition::GTU, OperationCode::Logical2HGreaterThanWithNan}, |
| 328 | std::pair{PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThanWithNan}, | 309 | std::pair{PredCondition::NEU, OperationCode::Logical2HNotEqualWithNan}, |
| 329 | std::pair{PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqualWithNan}, | 310 | std::pair{PredCondition::GEU, OperationCode::Logical2HGreaterEqualWithNan}, |
| 330 | }; | 311 | }; |
| 331 | 312 | ||
| 332 | const auto comparison = | 313 | const auto comparison = |
| @@ -397,7 +378,7 @@ void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc | |||
| 397 | if (!sets_cc) { | 378 | if (!sets_cc) { |
| 398 | return; | 379 | return; |
| 399 | } | 380 | } |
| 400 | Node zerop = Operation(OperationCode::LogicalFEqual, std::move(value), Immediate(0.0f)); | 381 | Node zerop = Operation(OperationCode::LogicalFOrdEqual, std::move(value), Immediate(0.0f)); |
| 401 | SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop)); | 382 | SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop)); |
| 402 | LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete"); | 383 | LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete"); |
| 403 | } | 384 | } |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 3d759f77b..1adf8932b 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -150,18 +150,19 @@ public: | |||
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | void MakeCurrent() override { | 152 | void MakeCurrent() override { |
| 153 | if (is_current) { | 153 | // We can't track the current state of the underlying context in this wrapper class because |
| 154 | return; | 154 | // Qt may make the underlying context not current for one reason or another. In particular, |
| 155 | // the WebBrowser uses GL, so it seems to conflict if we aren't careful. | ||
| 156 | // Instead of always just making the context current (which does not have any caching to | ||
| 157 | // check if the underlying context is already current) we can check for the current context | ||
| 158 | // in the thread local data by calling `currentContext()` and checking if its ours. | ||
| 159 | if (QOpenGLContext::currentContext() != context.get()) { | ||
| 160 | context->makeCurrent(surface); | ||
| 155 | } | 161 | } |
| 156 | is_current = context->makeCurrent(surface); | ||
| 157 | } | 162 | } |
| 158 | 163 | ||
| 159 | void DoneCurrent() override { | 164 | void DoneCurrent() override { |
| 160 | if (!is_current) { | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | context->doneCurrent(); | 165 | context->doneCurrent(); |
| 164 | is_current = false; | ||
| 165 | } | 166 | } |
| 166 | 167 | ||
| 167 | QOpenGLContext* GetShareContext() { | 168 | QOpenGLContext* GetShareContext() { |
| @@ -178,7 +179,6 @@ private: | |||
| 178 | std::unique_ptr<QOpenGLContext> context; | 179 | std::unique_ptr<QOpenGLContext> context; |
| 179 | std::unique_ptr<QOffscreenSurface> offscreen_surface{}; | 180 | std::unique_ptr<QOffscreenSurface> offscreen_surface{}; |
| 180 | QSurface* surface; | 181 | QSurface* surface; |
| 181 | bool is_current = false; | ||
| 182 | }; | 182 | }; |
| 183 | 183 | ||
| 184 | class DummyContext : public Core::Frontend::GraphicsContext {}; | 184 | class DummyContext : public Core::Frontend::GraphicsContext {}; |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 75c6cf20b..27775701d 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -687,6 +687,8 @@ void Config::ReadSystemValues() { | |||
| 687 | 687 | ||
| 688 | Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt(); | 688 | Settings::values.region_index = ReadSetting(QStringLiteral("region_index"), 1).toInt(); |
| 689 | 689 | ||
| 690 | Settings::values.time_zone_index = ReadSetting(QStringLiteral("time_zone_index"), 0).toInt(); | ||
| 691 | |||
| 690 | const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool(); | 692 | const auto rng_seed_enabled = ReadSetting(QStringLiteral("rng_seed_enabled"), false).toBool(); |
| 691 | if (rng_seed_enabled) { | 693 | if (rng_seed_enabled) { |
| 692 | Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong(); | 694 | Settings::values.rng_seed = ReadSetting(QStringLiteral("rng_seed"), 0).toULongLong(); |
| @@ -1126,6 +1128,7 @@ void Config::SaveSystemValues() { | |||
| 1126 | WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0); | 1128 | WriteSetting(QStringLiteral("current_user"), Settings::values.current_user, 0); |
| 1127 | WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1); | 1129 | WriteSetting(QStringLiteral("language_index"), Settings::values.language_index, 1); |
| 1128 | WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1); | 1130 | WriteSetting(QStringLiteral("region_index"), Settings::values.region_index, 1); |
| 1131 | WriteSetting(QStringLiteral("time_zone_index"), Settings::values.time_zone_index, 0); | ||
| 1129 | 1132 | ||
| 1130 | WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false); | 1133 | WriteSetting(QStringLiteral("rng_seed_enabled"), Settings::values.rng_seed.has_value(), false); |
| 1131 | WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0); | 1134 | WriteSetting(QStringLiteral("rng_seed"), Settings::values.rng_seed.value_or(0), 0); |
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index f49cd4c8f..10315e7a6 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp | |||
| @@ -57,6 +57,7 @@ void ConfigureSystem::SetConfiguration() { | |||
| 57 | 57 | ||
| 58 | ui->combo_language->setCurrentIndex(Settings::values.language_index); | 58 | ui->combo_language->setCurrentIndex(Settings::values.language_index); |
| 59 | ui->combo_region->setCurrentIndex(Settings::values.region_index); | 59 | ui->combo_region->setCurrentIndex(Settings::values.region_index); |
| 60 | ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index); | ||
| 60 | ui->combo_sound->setCurrentIndex(Settings::values.sound_index); | 61 | ui->combo_sound->setCurrentIndex(Settings::values.sound_index); |
| 61 | 62 | ||
| 62 | ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value()); | 63 | ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value()); |
| @@ -84,6 +85,7 @@ void ConfigureSystem::ApplyConfiguration() { | |||
| 84 | 85 | ||
| 85 | Settings::values.language_index = ui->combo_language->currentIndex(); | 86 | Settings::values.language_index = ui->combo_language->currentIndex(); |
| 86 | Settings::values.region_index = ui->combo_region->currentIndex(); | 87 | Settings::values.region_index = ui->combo_region->currentIndex(); |
| 88 | Settings::values.time_zone_index = ui->combo_time_zone->currentIndex(); | ||
| 87 | Settings::values.sound_index = ui->combo_sound->currentIndex(); | 89 | Settings::values.sound_index = ui->combo_sound->currentIndex(); |
| 88 | 90 | ||
| 89 | if (ui->rng_seed_checkbox->isChecked()) { | 91 | if (ui->rng_seed_checkbox->isChecked()) { |
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h index d8fa2d2cc..26d42d5c5 100644 --- a/src/yuzu/configuration/configure_system.h +++ b/src/yuzu/configuration/configure_system.h | |||
| @@ -37,5 +37,6 @@ private: | |||
| 37 | 37 | ||
| 38 | int language_index = 0; | 38 | int language_index = 0; |
| 39 | int region_index = 0; | 39 | int region_index = 0; |
| 40 | int time_zone_index = 0; | ||
| 40 | int sound_index = 0; | 41 | int sound_index = 0; |
| 41 | }; | 42 | }; |
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui index 4e2c7e76e..9c8cca6dc 100644 --- a/src/yuzu/configuration/configure_system.ui +++ b/src/yuzu/configuration/configure_system.ui | |||
| @@ -22,14 +22,14 @@ | |||
| 22 | <string>System Settings</string> | 22 | <string>System Settings</string> |
| 23 | </property> | 23 | </property> |
| 24 | <layout class="QGridLayout" name="gridLayout"> | 24 | <layout class="QGridLayout" name="gridLayout"> |
| 25 | <item row="2" column="0"> | 25 | <item row="3" column="0"> |
| 26 | <widget class="QLabel" name="label_sound"> | 26 | <widget class="QLabel" name="label_sound"> |
| 27 | <property name="text"> | 27 | <property name="text"> |
| 28 | <string>Sound output mode</string> | 28 | <string>Sound output mode</string> |
| 29 | </property> | 29 | </property> |
| 30 | </widget> | 30 | </widget> |
| 31 | </item> | 31 | </item> |
| 32 | <item row="3" column="0"> | 32 | <item row="4" column="0"> |
| 33 | <widget class="QLabel" name="label_console_id"> | 33 | <widget class="QLabel" name="label_console_id"> |
| 34 | <property name="text"> | 34 | <property name="text"> |
| 35 | <string>Console ID:</string> | 35 | <string>Console ID:</string> |
| @@ -174,14 +174,255 @@ | |||
| 174 | </item> | 174 | </item> |
| 175 | </widget> | 175 | </widget> |
| 176 | </item> | 176 | </item> |
| 177 | <item row="5" column="0"> | 177 | <item row="2" column="0"> |
| 178 | <widget class="QLabel" name="label_timezone"> | ||
| 179 | <property name="text"> | ||
| 180 | <string>Time Zone:</string> | ||
| 181 | </property> | ||
| 182 | </widget> | ||
| 183 | </item> | ||
| 184 | <item row="2" column="1"> | ||
| 185 | <widget class="QComboBox" name="combo_time_zone"> | ||
| 186 | <item> | ||
| 187 | <property name="text"> | ||
| 188 | <string>Auto</string> | ||
| 189 | </property> | ||
| 190 | </item> | ||
| 191 | <item> | ||
| 192 | <property name="text"> | ||
| 193 | <string>Default</string> | ||
| 194 | </property> | ||
| 195 | </item> | ||
| 196 | <item> | ||
| 197 | <property name="text"> | ||
| 198 | <string>CET</string> | ||
| 199 | </property> | ||
| 200 | </item> | ||
| 201 | <item> | ||
| 202 | <property name="text"> | ||
| 203 | <string>CST6CDT</string> | ||
| 204 | </property> | ||
| 205 | </item> | ||
| 206 | <item> | ||
| 207 | <property name="text"> | ||
| 208 | <string>Cuba</string> | ||
| 209 | </property> | ||
| 210 | </item> | ||
| 211 | <item> | ||
| 212 | <property name="text"> | ||
| 213 | <string>EET</string> | ||
| 214 | </property> | ||
| 215 | </item> | ||
| 216 | <item> | ||
| 217 | <property name="text"> | ||
| 218 | <string>Egypt</string> | ||
| 219 | </property> | ||
| 220 | </item> | ||
| 221 | <item> | ||
| 222 | <property name="text"> | ||
| 223 | <string>Eire</string> | ||
| 224 | </property> | ||
| 225 | </item> | ||
| 226 | <item> | ||
| 227 | <property name="text"> | ||
| 228 | <string>EST</string> | ||
| 229 | </property> | ||
| 230 | </item> | ||
| 231 | <item> | ||
| 232 | <property name="text"> | ||
| 233 | <string>EST5EDT</string> | ||
| 234 | </property> | ||
| 235 | </item> | ||
| 236 | <item> | ||
| 237 | <property name="text"> | ||
| 238 | <string>GB</string> | ||
| 239 | </property> | ||
| 240 | </item> | ||
| 241 | <item> | ||
| 242 | <property name="text"> | ||
| 243 | <string>GB-Eire</string> | ||
| 244 | </property> | ||
| 245 | </item> | ||
| 246 | <item> | ||
| 247 | <property name="text"> | ||
| 248 | <string>GMT</string> | ||
| 249 | </property> | ||
| 250 | </item> | ||
| 251 | <item> | ||
| 252 | <property name="text"> | ||
| 253 | <string>GMT+0</string> | ||
| 254 | </property> | ||
| 255 | </item> | ||
| 256 | <item> | ||
| 257 | <property name="text"> | ||
| 258 | <string>GMT-0</string> | ||
| 259 | </property> | ||
| 260 | </item> | ||
| 261 | <item> | ||
| 262 | <property name="text"> | ||
| 263 | <string>GMT0</string> | ||
| 264 | </property> | ||
| 265 | </item> | ||
| 266 | <item> | ||
| 267 | <property name="text"> | ||
| 268 | <string>Greenwich</string> | ||
| 269 | </property> | ||
| 270 | </item> | ||
| 271 | <item> | ||
| 272 | <property name="text"> | ||
| 273 | <string>Hongkong</string> | ||
| 274 | </property> | ||
| 275 | </item> | ||
| 276 | <item> | ||
| 277 | <property name="text"> | ||
| 278 | <string>HST</string> | ||
| 279 | </property> | ||
| 280 | </item> | ||
| 281 | <item> | ||
| 282 | <property name="text"> | ||
| 283 | <string>Iceland</string> | ||
| 284 | </property> | ||
| 285 | </item> | ||
| 286 | <item> | ||
| 287 | <property name="text"> | ||
| 288 | <string>Iran</string> | ||
| 289 | </property> | ||
| 290 | </item> | ||
| 291 | <item> | ||
| 292 | <property name="text"> | ||
| 293 | <string>Israel</string> | ||
| 294 | </property> | ||
| 295 | </item> | ||
| 296 | <item> | ||
| 297 | <property name="text"> | ||
| 298 | <string>Jamaica</string> | ||
| 299 | </property> | ||
| 300 | </item> | ||
| 301 | <item> | ||
| 302 | <property name="text"> | ||
| 303 | <string>Japan</string> | ||
| 304 | </property> | ||
| 305 | </item> | ||
| 306 | <item> | ||
| 307 | <property name="text"> | ||
| 308 | <string>Kwajalein</string> | ||
| 309 | </property> | ||
| 310 | </item> | ||
| 311 | <item> | ||
| 312 | <property name="text"> | ||
| 313 | <string>Libya</string> | ||
| 314 | </property> | ||
| 315 | </item> | ||
| 316 | <item> | ||
| 317 | <property name="text"> | ||
| 318 | <string>MET</string> | ||
| 319 | </property> | ||
| 320 | </item> | ||
| 321 | <item> | ||
| 322 | <property name="text"> | ||
| 323 | <string>MST</string> | ||
| 324 | </property> | ||
| 325 | </item> | ||
| 326 | <item> | ||
| 327 | <property name="text"> | ||
| 328 | <string>MST7MDT</string> | ||
| 329 | </property> | ||
| 330 | </item> | ||
| 331 | <item> | ||
| 332 | <property name="text"> | ||
| 333 | <string>Navajo</string> | ||
| 334 | </property> | ||
| 335 | </item> | ||
| 336 | <item> | ||
| 337 | <property name="text"> | ||
| 338 | <string>NZ</string> | ||
| 339 | </property> | ||
| 340 | </item> | ||
| 341 | <item> | ||
| 342 | <property name="text"> | ||
| 343 | <string>NZ-CHAT</string> | ||
| 344 | </property> | ||
| 345 | </item> | ||
| 346 | <item> | ||
| 347 | <property name="text"> | ||
| 348 | <string>Poland</string> | ||
| 349 | </property> | ||
| 350 | </item> | ||
| 351 | <item> | ||
| 352 | <property name="text"> | ||
| 353 | <string>Portugal</string> | ||
| 354 | </property> | ||
| 355 | </item> | ||
| 356 | <item> | ||
| 357 | <property name="text"> | ||
| 358 | <string>PRC</string> | ||
| 359 | </property> | ||
| 360 | </item> | ||
| 361 | <item> | ||
| 362 | <property name="text"> | ||
| 363 | <string>PST8PDT</string> | ||
| 364 | </property> | ||
| 365 | </item> | ||
| 366 | <item> | ||
| 367 | <property name="text"> | ||
| 368 | <string>ROC</string> | ||
| 369 | </property> | ||
| 370 | </item> | ||
| 371 | <item> | ||
| 372 | <property name="text"> | ||
| 373 | <string>ROK</string> | ||
| 374 | </property> | ||
| 375 | </item> | ||
| 376 | <item> | ||
| 377 | <property name="text"> | ||
| 378 | <string>Singapore</string> | ||
| 379 | </property> | ||
| 380 | </item> | ||
| 381 | <item> | ||
| 382 | <property name="text"> | ||
| 383 | <string>Turkey</string> | ||
| 384 | </property> | ||
| 385 | </item> | ||
| 386 | <item> | ||
| 387 | <property name="text"> | ||
| 388 | <string>UCT</string> | ||
| 389 | </property> | ||
| 390 | </item> | ||
| 391 | <item> | ||
| 392 | <property name="text"> | ||
| 393 | <string>Universal</string> | ||
| 394 | </property> | ||
| 395 | </item> | ||
| 396 | <item> | ||
| 397 | <property name="text"> | ||
| 398 | <string>UTC</string> | ||
| 399 | </property> | ||
| 400 | </item> | ||
| 401 | <item> | ||
| 402 | <property name="text"> | ||
| 403 | <string>W-SU</string> | ||
| 404 | </property> | ||
| 405 | </item> | ||
| 406 | <item> | ||
| 407 | <property name="text"> | ||
| 408 | <string>WET</string> | ||
| 409 | </property> | ||
| 410 | </item> | ||
| 411 | <item> | ||
| 412 | <property name="text"> | ||
| 413 | <string>Zulu</string> | ||
| 414 | </property> | ||
| 415 | </item> | ||
| 416 | </widget> | ||
| 417 | </item> | ||
| 418 | <item row="6" column="0"> | ||
| 178 | <widget class="QCheckBox" name="rng_seed_checkbox"> | 419 | <widget class="QCheckBox" name="rng_seed_checkbox"> |
| 179 | <property name="text"> | 420 | <property name="text"> |
| 180 | <string>RNG Seed</string> | 421 | <string>RNG Seed</string> |
| 181 | </property> | 422 | </property> |
| 182 | </widget> | 423 | </widget> |
| 183 | </item> | 424 | </item> |
| 184 | <item row="2" column="1"> | 425 | <item row="3" column="1"> |
| 185 | <widget class="QComboBox" name="combo_sound"> | 426 | <widget class="QComboBox" name="combo_sound"> |
| 186 | <item> | 427 | <item> |
| 187 | <property name="text"> | 428 | <property name="text"> |
| @@ -207,7 +448,7 @@ | |||
| 207 | </property> | 448 | </property> |
| 208 | </widget> | 449 | </widget> |
| 209 | </item> | 450 | </item> |
| 210 | <item row="3" column="1"> | 451 | <item row="4" column="1"> |
| 211 | <widget class="QPushButton" name="button_regenerate_console_id"> | 452 | <widget class="QPushButton" name="button_regenerate_console_id"> |
| 212 | <property name="sizePolicy"> | 453 | <property name="sizePolicy"> |
| 213 | <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> | 454 | <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> |
| @@ -223,14 +464,14 @@ | |||
| 223 | </property> | 464 | </property> |
| 224 | </widget> | 465 | </widget> |
| 225 | </item> | 466 | </item> |
| 226 | <item row="4" column="0"> | 467 | <item row="5" column="0"> |
| 227 | <widget class="QCheckBox" name="custom_rtc_checkbox"> | 468 | <widget class="QCheckBox" name="custom_rtc_checkbox"> |
| 228 | <property name="text"> | 469 | <property name="text"> |
| 229 | <string>Custom RTC</string> | 470 | <string>Custom RTC</string> |
| 230 | </property> | 471 | </property> |
| 231 | </widget> | 472 | </widget> |
| 232 | </item> | 473 | </item> |
| 233 | <item row="4" column="1"> | 474 | <item row="5" column="1"> |
| 234 | <widget class="QDateTimeEdit" name="custom_rtc_edit"> | 475 | <widget class="QDateTimeEdit" name="custom_rtc_edit"> |
| 235 | <property name="minimumDate"> | 476 | <property name="minimumDate"> |
| 236 | <date> | 477 | <date> |
| @@ -244,7 +485,7 @@ | |||
| 244 | </property> | 485 | </property> |
| 245 | </widget> | 486 | </widget> |
| 246 | </item> | 487 | </item> |
| 247 | <item row="5" column="1"> | 488 | <item row="6" column="1"> |
| 248 | <widget class="QLineEdit" name="rng_seed_edit"> | 489 | <widget class="QLineEdit" name="rng_seed_edit"> |
| 249 | <property name="sizePolicy"> | 490 | <property name="sizePolicy"> |
| 250 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | 491 | <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index dccbabcbf..bfb600df0 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -488,11 +488,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string pat | |||
| 488 | auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); | 488 | auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); |
| 489 | navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); | 489 | navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); |
| 490 | 490 | ||
| 491 | connect(open_save_location, &QAction::triggered, [this, program_id]() { | 491 | connect(open_save_location, &QAction::triggered, [this, program_id, path]() { |
| 492 | emit OpenFolderRequested(program_id, GameListOpenTarget::SaveData); | 492 | emit OpenFolderRequested(GameListOpenTarget::SaveData, path); |
| 493 | }); | 493 | }); |
| 494 | connect(open_lfs_location, &QAction::triggered, [this, program_id]() { | 494 | connect(open_lfs_location, &QAction::triggered, [this, program_id, path]() { |
| 495 | emit OpenFolderRequested(program_id, GameListOpenTarget::ModData); | 495 | emit OpenFolderRequested(GameListOpenTarget::ModData, path); |
| 496 | }); | 496 | }); |
| 497 | connect(open_transferable_shader_cache, &QAction::triggered, | 497 | connect(open_transferable_shader_cache, &QAction::triggered, |
| 498 | [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); | 498 | [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 878d94413..a38cb2fc3 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -73,7 +73,7 @@ public: | |||
| 73 | signals: | 73 | signals: |
| 74 | void GameChosen(QString game_path); | 74 | void GameChosen(QString game_path); |
| 75 | void ShouldCancelWorker(); | 75 | void ShouldCancelWorker(); |
| 76 | void OpenFolderRequested(u64 program_id, GameListOpenTarget target); | 76 | void OpenFolderRequested(GameListOpenTarget target, const std::string& game_path); |
| 77 | void OpenTransferableShaderCacheRequested(u64 program_id); | 77 | void OpenTransferableShaderCacheRequested(u64 program_id); |
| 78 | void DumpRomFSRequested(u64 program_id, const std::string& game_path); | 78 | void DumpRomFSRequested(u64 program_id, const std::string& game_path); |
| 79 | void CopyTIDRequested(u64 program_id); | 79 | void CopyTIDRequested(u64 program_id); |
diff --git a/src/yuzu/loading_screen.cpp b/src/yuzu/loading_screen.cpp index 2a6483370..ae842306c 100644 --- a/src/yuzu/loading_screen.cpp +++ b/src/yuzu/loading_screen.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <QTime> | 19 | #include <QTime> |
| 20 | #include <QtConcurrent/QtConcurrentRun> | 20 | #include <QtConcurrent/QtConcurrentRun> |
| 21 | #include "common/logging/log.h" | 21 | #include "common/logging/log.h" |
| 22 | #include "core/frontend/framebuffer_layout.h" | ||
| 22 | #include "core/loader/loader.h" | 23 | #include "core/loader/loader.h" |
| 23 | #include "ui_loading_screen.h" | 24 | #include "ui_loading_screen.h" |
| 24 | #include "video_core/rasterizer_interface.h" | 25 | #include "video_core/rasterizer_interface.h" |
| @@ -61,7 +62,7 @@ LoadingScreen::LoadingScreen(QWidget* parent) | |||
| 61 | : QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()), | 62 | : QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()), |
| 62 | previous_stage(VideoCore::LoadCallbackStage::Complete) { | 63 | previous_stage(VideoCore::LoadCallbackStage::Complete) { |
| 63 | ui->setupUi(this); | 64 | ui->setupUi(this); |
| 64 | setMinimumSize(1280, 720); | 65 | setMinimumSize(Layout::MinimumSize::Width, Layout::MinimumSize::Height); |
| 65 | 66 | ||
| 66 | // Create a fade out effect to hide this loading screen widget. | 67 | // Create a fade out effect to hide this loading screen widget. |
| 67 | // When fading opacity, it will fade to the parent widgets background color, which is why we | 68 | // When fading opacity, it will fade to the parent widgets background color, which is why we |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 86e8a1d49..0b291c7d0 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -724,13 +724,13 @@ void GMainWindow::InitializeHotkeys() { | |||
| 724 | } | 724 | } |
| 725 | 725 | ||
| 726 | void GMainWindow::SetDefaultUIGeometry() { | 726 | void GMainWindow::SetDefaultUIGeometry() { |
| 727 | // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half | 727 | // geometry: 53% of the window contents are in the upper screen half, 47% in the lower half |
| 728 | const QRect screenRect = QApplication::desktop()->screenGeometry(this); | 728 | const QRect screenRect = QApplication::desktop()->screenGeometry(this); |
| 729 | 729 | ||
| 730 | const int w = screenRect.width() * 2 / 3; | 730 | const int w = screenRect.width() * 2 / 3; |
| 731 | const int h = screenRect.height() / 2; | 731 | const int h = screenRect.height() * 2 / 3; |
| 732 | const int x = (screenRect.x() + screenRect.width()) / 2 - w / 2; | 732 | const int x = (screenRect.x() + screenRect.width()) / 2 - w / 2; |
| 733 | const int y = (screenRect.y() + screenRect.height()) / 2 - h * 55 / 100; | 733 | const int y = (screenRect.y() + screenRect.height()) / 2 - h * 53 / 100; |
| 734 | 734 | ||
| 735 | setGeometry(x, y, w, h); | 735 | setGeometry(x, y, w, h); |
| 736 | } | 736 | } |
| @@ -831,6 +831,7 @@ void GMainWindow::ConnectMenuEvents() { | |||
| 831 | &GMainWindow::OnDisplayTitleBars); | 831 | &GMainWindow::OnDisplayTitleBars); |
| 832 | connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); | 832 | connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); |
| 833 | connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); | 833 | connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); |
| 834 | connect(ui.action_Reset_Window_Size, &QAction::triggered, this, &GMainWindow::ResetWindowSize); | ||
| 834 | 835 | ||
| 835 | // Fullscreen | 836 | // Fullscreen |
| 836 | ui.action_Fullscreen->setShortcut( | 837 | ui.action_Fullscreen->setShortcut( |
| @@ -1154,39 +1155,61 @@ void GMainWindow::OnGameListLoadFile(QString game_path) { | |||
| 1154 | BootGame(game_path); | 1155 | BootGame(game_path); |
| 1155 | } | 1156 | } |
| 1156 | 1157 | ||
| 1157 | void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target) { | 1158 | void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path) { |
| 1158 | std::string path; | 1159 | std::string path; |
| 1159 | QString open_target; | 1160 | QString open_target; |
| 1161 | |||
| 1162 | const auto v_file = Core::GetGameFileFromPath(vfs, game_path); | ||
| 1163 | const auto loader = Loader::GetLoader(v_file); | ||
| 1164 | FileSys::NACP control{}; | ||
| 1165 | u64 program_id{}; | ||
| 1166 | |||
| 1167 | loader->ReadControlData(control); | ||
| 1168 | loader->ReadProgramId(program_id); | ||
| 1169 | |||
| 1170 | const bool has_user_save{control.GetDefaultNormalSaveSize() > 0}; | ||
| 1171 | const bool has_device_save{control.GetDeviceSaveDataSize() > 0}; | ||
| 1172 | |||
| 1173 | ASSERT_MSG(has_user_save != has_device_save, "Game uses both user and device savedata?"); | ||
| 1174 | |||
| 1160 | switch (target) { | 1175 | switch (target) { |
| 1161 | case GameListOpenTarget::SaveData: { | 1176 | case GameListOpenTarget::SaveData: { |
| 1162 | open_target = tr("Save Data"); | 1177 | open_target = tr("Save Data"); |
| 1163 | const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); | 1178 | const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); |
| 1164 | ASSERT(program_id != 0); | 1179 | ASSERT(program_id != 0); |
| 1165 | 1180 | ||
| 1166 | const auto select_profile = [this] { | 1181 | if (has_user_save) { |
| 1167 | QtProfileSelectionDialog dialog(this); | 1182 | // User save data |
| 1168 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | | 1183 | const auto select_profile = [this] { |
| 1169 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | 1184 | QtProfileSelectionDialog dialog(this); |
| 1170 | dialog.setWindowModality(Qt::WindowModal); | 1185 | dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | |
| 1186 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint); | ||
| 1187 | dialog.setWindowModality(Qt::WindowModal); | ||
| 1171 | 1188 | ||
| 1172 | if (dialog.exec() == QDialog::Rejected) { | 1189 | if (dialog.exec() == QDialog::Rejected) { |
| 1173 | return -1; | 1190 | return -1; |
| 1174 | } | 1191 | } |
| 1175 | 1192 | ||
| 1176 | return dialog.GetIndex(); | 1193 | return dialog.GetIndex(); |
| 1177 | }; | 1194 | }; |
| 1178 | 1195 | ||
| 1179 | const auto index = select_profile(); | 1196 | const auto index = select_profile(); |
| 1180 | if (index == -1) { | 1197 | if (index == -1) { |
| 1181 | return; | 1198 | return; |
| 1182 | } | 1199 | } |
| 1183 | 1200 | ||
| 1184 | Service::Account::ProfileManager manager; | 1201 | Service::Account::ProfileManager manager; |
| 1185 | const auto user_id = manager.GetUser(static_cast<std::size_t>(index)); | 1202 | const auto user_id = manager.GetUser(static_cast<std::size_t>(index)); |
| 1186 | ASSERT(user_id); | 1203 | ASSERT(user_id); |
| 1187 | path = nand_dir + FileSys::SaveDataFactory::GetFullPath(FileSys::SaveDataSpaceId::NandUser, | 1204 | path = nand_dir + FileSys::SaveDataFactory::GetFullPath( |
| 1188 | FileSys::SaveDataType::SaveData, | 1205 | FileSys::SaveDataSpaceId::NandUser, |
| 1189 | program_id, user_id->uuid, 0); | 1206 | FileSys::SaveDataType::SaveData, program_id, user_id->uuid, 0); |
| 1207 | } else { | ||
| 1208 | // Device save data | ||
| 1209 | path = nand_dir + FileSys::SaveDataFactory::GetFullPath( | ||
| 1210 | FileSys::SaveDataSpaceId::NandUser, | ||
| 1211 | FileSys::SaveDataType::SaveData, program_id, {}, 0); | ||
| 1212 | } | ||
| 1190 | 1213 | ||
| 1191 | if (!FileUtil::Exists(path)) { | 1214 | if (!FileUtil::Exists(path)) { |
| 1192 | FileUtil::CreateFullPath(path); | 1215 | FileUtil::CreateFullPath(path); |
| @@ -1829,6 +1852,20 @@ void GMainWindow::ToggleWindowMode() { | |||
| 1829 | } | 1852 | } |
| 1830 | } | 1853 | } |
| 1831 | 1854 | ||
| 1855 | void GMainWindow::ResetWindowSize() { | ||
| 1856 | const auto aspect_ratio = Layout::EmulationAspectRatio( | ||
| 1857 | static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio), | ||
| 1858 | static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width); | ||
| 1859 | if (!ui.action_Single_Window_Mode->isChecked()) { | ||
| 1860 | render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio, | ||
| 1861 | Layout::ScreenUndocked::Height); | ||
| 1862 | } else { | ||
| 1863 | resize(Layout::ScreenUndocked::Height / aspect_ratio, | ||
| 1864 | Layout::ScreenUndocked::Height + menuBar()->height() + | ||
| 1865 | (ui.action_Show_Status_Bar->isChecked() ? statusBar()->height() : 0)); | ||
| 1866 | } | ||
| 1867 | } | ||
| 1868 | |||
| 1832 | void GMainWindow::OnConfigure() { | 1869 | void GMainWindow::OnConfigure() { |
| 1833 | const auto old_theme = UISettings::values.theme; | 1870 | const auto old_theme = UISettings::values.theme; |
| 1834 | const bool old_discord_presence = UISettings::values.enable_discord_presence; | 1871 | const bool old_discord_presence = UISettings::values.enable_discord_presence; |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 60b17c54a..4f4c8ddbe 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -183,7 +183,7 @@ private slots: | |||
| 183 | void OnMenuReportCompatibility(); | 183 | void OnMenuReportCompatibility(); |
| 184 | /// Called whenever a user selects a game in the game list widget. | 184 | /// Called whenever a user selects a game in the game list widget. |
| 185 | void OnGameListLoadFile(QString game_path); | 185 | void OnGameListLoadFile(QString game_path); |
| 186 | void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); | 186 | void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path); |
| 187 | void OnTransferableShaderCacheOpenFile(u64 program_id); | 187 | void OnTransferableShaderCacheOpenFile(u64 program_id); |
| 188 | void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); | 188 | void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); |
| 189 | void OnGameListCopyTID(u64 program_id); | 189 | void OnGameListCopyTID(u64 program_id); |
| @@ -208,6 +208,7 @@ private slots: | |||
| 208 | void ShowFullscreen(); | 208 | void ShowFullscreen(); |
| 209 | void HideFullscreen(); | 209 | void HideFullscreen(); |
| 210 | void ToggleWindowMode(); | 210 | void ToggleWindowMode(); |
| 211 | void ResetWindowSize(); | ||
| 211 | void OnCaptureScreenshot(); | 212 | void OnCaptureScreenshot(); |
| 212 | void OnCoreError(Core::System::ResultStatus, std::string); | 213 | void OnCoreError(Core::System::ResultStatus, std::string); |
| 213 | void OnReinitializeKeys(ReinitializeKeyBehavior behavior); | 214 | void OnReinitializeKeys(ReinitializeKeyBehavior behavior); |
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index ae414241e..97c90f50b 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.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>1081</width> | 9 | <width>1280</width> |
| 10 | <height>730</height> | 10 | <height>720</height> |
| 11 | </rect> | 11 | </rect> |
| 12 | </property> | 12 | </property> |
| 13 | <property name="windowTitle"> | 13 | <property name="windowTitle"> |
| @@ -44,7 +44,7 @@ | |||
| 44 | <rect> | 44 | <rect> |
| 45 | <x>0</x> | 45 | <x>0</x> |
| 46 | <y>0</y> | 46 | <y>0</y> |
| 47 | <width>1081</width> | 47 | <width>1280</width> |
| 48 | <height>21</height> | 48 | <height>21</height> |
| 49 | </rect> | 49 | </rect> |
| 50 | </property> | 50 | </property> |
| @@ -96,6 +96,7 @@ | |||
| 96 | <addaction name="action_Display_Dock_Widget_Headers"/> | 96 | <addaction name="action_Display_Dock_Widget_Headers"/> |
| 97 | <addaction name="action_Show_Filter_Bar"/> | 97 | <addaction name="action_Show_Filter_Bar"/> |
| 98 | <addaction name="action_Show_Status_Bar"/> | 98 | <addaction name="action_Show_Status_Bar"/> |
| 99 | <addaction name="action_Reset_Window_Size"/> | ||
| 99 | <addaction name="separator"/> | 100 | <addaction name="separator"/> |
| 100 | <addaction name="menu_View_Debugging"/> | 101 | <addaction name="menu_View_Debugging"/> |
| 101 | </widget> | 102 | </widget> |
| @@ -215,6 +216,11 @@ | |||
| 215 | <string>Show Status Bar</string> | 216 | <string>Show Status Bar</string> |
| 216 | </property> | 217 | </property> |
| 217 | </action> | 218 | </action> |
| 219 | <action name="action_Reset_Window_Size"> | ||
| 220 | <property name="text"> | ||
| 221 | <string>Reset Window Size</string> | ||
| 222 | </property> | ||
| 223 | </action> | ||
| 218 | <action name="action_Fullscreen"> | 224 | <action name="action_Fullscreen"> |
| 219 | <property name="checkable"> | 225 | <property name="checkable"> |
| 220 | <bool>true</bool> | 226 | <bool>true</bool> |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 8476a5a16..2348e6e0d 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -367,6 +367,9 @@ void Config::ReadValues() { | |||
| 367 | Settings::values.custom_rtc = std::nullopt; | 367 | Settings::values.custom_rtc = std::nullopt; |
| 368 | } | 368 | } |
| 369 | 369 | ||
| 370 | Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1); | ||
| 371 | Settings::values.time_zone_index = sdl2_config->GetInteger("System", "time_zone_index", 0); | ||
| 372 | |||
| 370 | // Core | 373 | // Core |
| 371 | Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); | 374 | Settings::values.use_multi_core = sdl2_config->GetBoolean("Core", "use_multi_core", false); |
| 372 | 375 | ||
| @@ -409,8 +412,6 @@ void Config::ReadValues() { | |||
| 409 | Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); | 412 | Settings::values.audio_device_id = sdl2_config->Get("Audio", "output_device", "auto"); |
| 410 | Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)); | 413 | Settings::values.volume = static_cast<float>(sdl2_config->GetReal("Audio", "volume", 1)); |
| 411 | 414 | ||
| 412 | Settings::values.language_index = sdl2_config->GetInteger("System", "language_index", 1); | ||
| 413 | |||
| 414 | // Miscellaneous | 415 | // Miscellaneous |
| 415 | Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); | 416 | Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); |
| 416 | Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false); | 417 | Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 60b1a62fa..ae94b51c4 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -262,6 +262,10 @@ language_index = | |||
| 262 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | 262 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan |
| 263 | region_value = | 263 | region_value = |
| 264 | 264 | ||
| 265 | # The system time zone that yuzu will use during emulation | ||
| 266 | # 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone | ||
| 267 | time_zone_index = | ||
| 268 | |||
| 265 | [Miscellaneous] | 269 | [Miscellaneous] |
| 266 | # A filter which removes logs below a certain logging level. | 270 | # A filter which removes logs below a certain logging level. |
| 267 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | 271 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical |