Compare commits
89 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2318c394a8 | ||
|
|
d9c4d64ed5 | ||
|
|
428d8098a7 | ||
|
|
17255cd835 | ||
|
|
3039211c20 | ||
|
|
c9c4208c4a | ||
|
|
aa83639b78 | ||
|
|
4d2da5a40a | ||
|
|
d81d4a0f68 | ||
|
|
7e650088dd | ||
|
|
05235ccaa9 | ||
|
|
5f01ec338e | ||
|
|
d00ca5c6c8 | ||
|
|
d184224e8f | ||
|
|
594328f494 | ||
|
|
9175bffbdb | ||
|
|
ac3775e6ae | ||
|
|
b54bd3f018 | ||
|
|
3bd5f01240 | ||
|
|
a6ed792ac4 | ||
|
|
3ff0c70c72 | ||
|
|
4452195d41 | ||
|
|
8e9a1e4249 | ||
|
|
dfddb12255 | ||
|
|
f9ad88f9d7 | ||
|
|
edf8c0a545 | ||
|
|
209a0dfa35 | ||
|
|
27033de2e5 | ||
|
|
30c984dc97 | ||
|
|
256e5c9583 | ||
|
|
b42ca9888d | ||
|
|
ffd9a1f3ef | ||
|
|
2437ca04d7 | ||
|
|
aa61478d8c | ||
|
|
bc6972caf9 | ||
|
|
3356ea5bc2 | ||
|
|
22324e3ef1 | ||
|
|
d77d1a0207 | ||
|
|
cad4f2ed29 | ||
|
|
a059b9eed4 | ||
|
|
242273788a | ||
|
|
d5cce86431 | ||
|
|
88c263ee8e | ||
|
|
a47aaa7f1b | ||
|
|
21ea8b2fcb | ||
|
|
52340c3294 | ||
|
|
a652e58c54 | ||
|
|
fb85d5670d | ||
|
|
6f1720a5b7 | ||
|
|
865025f612 | ||
|
|
1975d32f2d | ||
|
|
4cf64f8e09 | ||
|
|
69265e4504 | ||
|
|
5f877d9458 | ||
|
|
e6c60b419c | ||
|
|
a6fb6ccc83 | ||
|
|
fc975e9021 | ||
|
|
b01cce716e | ||
|
|
9b6d993e52 | ||
|
|
ec1c69258a | ||
|
|
0f83c8dffa | ||
|
|
5db1b54b58 | ||
|
|
48ce5880a0 | ||
|
|
c212fc9b2c | ||
|
|
d6d809db87 | ||
|
|
c4d549919f | ||
|
|
dadcf317dc | ||
|
|
8b933e77cd | ||
|
|
3e8e335a5c | ||
|
|
940a71089d | ||
|
|
9ef45f00bf | ||
|
|
c823cf6594 | ||
|
|
716fbaef74 | ||
|
|
d4bcd006b2 | ||
|
|
fd12788967 | ||
|
|
53afe47cec | ||
|
|
5235b053b4 | ||
|
|
b6408e9671 | ||
|
|
e43ba3acd4 | ||
|
|
e3c45b4338 | ||
|
|
175fe8aaeb | ||
|
|
6d28d288a3 | ||
|
|
ba165b1092 | ||
|
|
c56d893e77 | ||
|
|
d955944869 | ||
|
|
bf1829a717 | ||
|
|
5d0dca73c6 | ||
|
|
4c36b78567 | ||
|
|
a3eb91ed8c |
@@ -132,7 +132,7 @@ find_package(Threads REQUIRED)
|
||||
if (ENABLE_SDL2)
|
||||
if (YUZU_USE_BUNDLED_SDL2)
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(SDL2_VER "SDL2-2.0.8")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
|
||||
@@ -165,7 +165,7 @@ if (YUZU_USE_BUNDLED_UNICORN)
|
||||
if (MSVC)
|
||||
message(STATUS "unicorn not found, falling back to bundled")
|
||||
# Detect toolchain and platform
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(UNICORN_VER "unicorn-yuzu")
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
|
||||
@@ -233,7 +233,7 @@ endif()
|
||||
|
||||
if (ENABLE_QT)
|
||||
if (YUZU_USE_BUNDLED_QT)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) AND ARCHITECTURE_x86_64)
|
||||
if ((MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1930) AND ARCHITECTURE_x86_64)
|
||||
set(QT_VER qt-5.12.0-msvc2017_64)
|
||||
else()
|
||||
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
|
||||
|
||||
@@ -51,7 +51,10 @@ if (MSVC)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG /MANIFEST:NO" CACHE STRING "" FORCE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG /MANIFEST:NO /INCREMENTAL:NO /OPT:REF,ICF" CACHE STRING "" FORCE)
|
||||
else()
|
||||
add_compile_options("-Wno-attributes")
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wno-attributes
|
||||
)
|
||||
|
||||
if (APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||
add_compile_options("-stdlib=libc++")
|
||||
|
||||
@@ -438,7 +438,7 @@ inline float RequestParser::Pop() {
|
||||
template <>
|
||||
inline double RequestParser::Pop() {
|
||||
const u64 value = Pop<u64>();
|
||||
float real;
|
||||
double real;
|
||||
std::memcpy(&real, &value, sizeof(real));
|
||||
return real;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
if (!writable_event) {
|
||||
// Create event if not provided
|
||||
const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
const auto pair = WritableEvent::CreateEventPair(kernel, ResetType::Automatic,
|
||||
"HLE Pause Event: " + reason);
|
||||
writable_event = pair.writable;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ enum class HandleType : u32 {
|
||||
};
|
||||
|
||||
enum class ResetType {
|
||||
OneShot, ///< Reset automatically on object acquisition
|
||||
Sticky, ///< Never reset automatically
|
||||
Automatic, ///< Reset automatically on object acquisition
|
||||
Manual, ///< Never reset automatically
|
||||
};
|
||||
|
||||
class Object : NonCopyable {
|
||||
|
||||
@@ -21,8 +21,9 @@ bool ReadableEvent::ShouldWait(const Thread* thread) const {
|
||||
void ReadableEvent::Acquire(Thread* thread) {
|
||||
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
|
||||
|
||||
if (reset_type == ResetType::OneShot)
|
||||
if (reset_type == ResetType::Automatic) {
|
||||
signaled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReadableEvent::Signal() {
|
||||
|
||||
@@ -1255,8 +1255,8 @@ static ResultCode MapProcessCodeMemory(Core::System& system, Handle process_hand
|
||||
return vm_manager.MapCodeMemory(dst_address, src_address, size);
|
||||
}
|
||||
|
||||
ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle, u64 dst_address,
|
||||
u64 src_address, u64 size) {
|
||||
static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_handle,
|
||||
u64 dst_address, u64 src_address, u64 size) {
|
||||
LOG_DEBUG(Kernel_SVC,
|
||||
"called. process_handle=0x{:08X}, dst_address=0x{:016X}, src_address=0x{:016X}, "
|
||||
"size=0x{:016X}",
|
||||
@@ -1980,7 +1980,7 @@ static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle
|
||||
|
||||
auto& kernel = system.Kernel();
|
||||
const auto [readable_event, writable_event] =
|
||||
WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent");
|
||||
WritableEvent::CreateEventPair(kernel, ResetType::Manual, "CreateEvent");
|
||||
|
||||
HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
|
||||
|
||||
@@ -2183,8 +2183,8 @@ static ResultCode GetProcessList(Core::System& system, u32* out_num_processes,
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids,
|
||||
u32 out_thread_ids_size, Handle debug_handle) {
|
||||
static ResultCode GetThreadList(Core::System& system, u32* out_num_threads, VAddr out_thread_ids,
|
||||
u32 out_thread_ids_size, Handle debug_handle) {
|
||||
// TODO: Handle this case when debug events are supported.
|
||||
UNIMPLEMENTED_IF(debug_handle != InvalidHandle);
|
||||
|
||||
|
||||
@@ -276,7 +276,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"ISelfController:LaunchableEvent");
|
||||
}
|
||||
|
||||
@@ -442,10 +442,10 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"AMMessageQueue:OnMessageRecieved");
|
||||
on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
|
||||
kernel, Kernel::ResetType::Automatic, "AMMessageQueue:OperationModeChanged");
|
||||
}
|
||||
|
||||
AppletMessageQueue::~AppletMessageQueue() = default;
|
||||
@@ -835,6 +835,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
return;
|
||||
}
|
||||
|
||||
std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
|
||||
@@ -857,6 +858,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(backing.buffer.data() + offset, size);
|
||||
|
||||
@@ -26,11 +26,11 @@ namespace Service::AM::Applets {
|
||||
AppletDataBroker::AppletDataBroker() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
state_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:StateChangedEvent");
|
||||
pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopDataOutEvent");
|
||||
pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Sticky, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
kernel, Kernel::ResetType::Manual, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
|
||||
}
|
||||
|
||||
AppletDataBroker::~AppletDataBroker() = default;
|
||||
|
||||
@@ -68,7 +68,7 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"GetAddOnContentListChanged:Event");
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
// This is the event handle used to check if the audio buffer was released
|
||||
auto& system = Core::System::GetInstance();
|
||||
buffer_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
|
||||
system.Kernel(), Kernel::ResetType::Manual, "IAudioOutBufferReleased");
|
||||
|
||||
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
||||
audio_params.channel_count, std::move(unique_name),
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
system_event = Kernel::WritableEvent::CreateEventPair(
|
||||
system.Kernel(), Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
|
||||
system.Kernel(), Kernel::ResetType::Manual, "IAudioRenderer:SystemEvent");
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), audren_params,
|
||||
system_event.writable);
|
||||
}
|
||||
@@ -178,7 +178,7 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IAudioOutBufferReleasedEvent");
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
"BT:RegisterEvent");
|
||||
register_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::Automatic, "BT:RegisterEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -57,13 +57,13 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IBtmUserCore:ScanEvent");
|
||||
connection_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent");
|
||||
kernel, Kernel::ResetType::Automatic, "IBtmUserCore:ConnectionEvent");
|
||||
service_discovery = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
|
||||
config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
kernel, Kernel::ResetType::Automatic, "IBtmUserCore:Discovery");
|
||||
config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IBtmUserCore:ConfigEvent");
|
||||
}
|
||||
|
||||
|
||||
@@ -170,7 +170,7 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
|
||||
void Controller_NPad::OnInit() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
|
||||
kernel, Kernel::ResetType::Automatic, "npad:NpadStyleSetChanged");
|
||||
|
||||
if (!IsControllerActivated()) {
|
||||
return;
|
||||
|
||||
@@ -26,7 +26,7 @@ constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
: ServiceFramework(name), module(std::move(module)) {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IUser:NFCTagDetected");
|
||||
}
|
||||
|
||||
@@ -67,9 +67,9 @@ public:
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
deactivate_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
|
||||
kernel, Kernel::ResetType::Automatic, "IUser:DeactivateEvent");
|
||||
availability_change_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
|
||||
kernel, Kernel::ResetType::Automatic, "IUser:AvailabilityChangeEvent");
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -62,9 +62,9 @@ public:
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IRequest:Event1");
|
||||
event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"IRequest:Event2");
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
finished_event = Kernel::WritableEvent::CreateEventPair(
|
||||
kernel, Kernel::ResetType::OneShot,
|
||||
kernel, Kernel::ResetType::Automatic,
|
||||
"IEnsureNetworkClockAvailabilityService:FinishEvent");
|
||||
}
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
|
||||
RegisterHandlers(functions);
|
||||
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
|
||||
query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Automatic,
|
||||
"NVDRV::query_event");
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Service::NVFlinger {
|
||||
|
||||
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
"BufferQueue NativeHandle");
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service::Set {
|
||||
|
||||
namespace {
|
||||
constexpr std::array<LanguageCode, 17> available_language_codes = {{
|
||||
LanguageCode::JA,
|
||||
LanguageCode::EN_US,
|
||||
@@ -32,41 +31,35 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
|
||||
LanguageCode::ZH_HANT,
|
||||
}};
|
||||
|
||||
constexpr std::size_t pre4_0_0_max_entries = 0xF;
|
||||
constexpr std::size_t post4_0_0_max_entries = 0x40;
|
||||
constexpr std::size_t pre4_0_0_max_entries = 15;
|
||||
constexpr std::size_t post4_0_0_max_entries = 17;
|
||||
|
||||
constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
|
||||
|
||||
void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_language_codes) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u32>(num_language_codes));
|
||||
}
|
||||
|
||||
void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_size) {
|
||||
const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode);
|
||||
const std::size_t copy_amount = std::min(requested_amount, max_size);
|
||||
const std::size_t copy_size = copy_amount * sizeof(LanguageCode);
|
||||
|
||||
ctx.WriteBuffer(available_language_codes.data(), copy_size);
|
||||
PushResponseLanguageCode(ctx, copy_amount);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
|
||||
return available_language_codes.at(index);
|
||||
}
|
||||
|
||||
template <std::size_t size>
|
||||
static std::array<LanguageCode, size> MakeLanguageCodeSubset() {
|
||||
std::array<LanguageCode, size> arr;
|
||||
std::copy_n(available_language_codes.begin(), size, arr.begin());
|
||||
return arr;
|
||||
}
|
||||
|
||||
static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
if (available_language_codes.size() > max_size) {
|
||||
rb.Push(static_cast<u32>(max_size));
|
||||
} else {
|
||||
rb.Push(static_cast<u32>(available_language_codes.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
if (available_language_codes.size() > pre4_0_0_max_entries) {
|
||||
ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>());
|
||||
} else {
|
||||
ctx.WriteBuffer(available_language_codes);
|
||||
}
|
||||
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
|
||||
GetAvailableLanguageCodesImpl(ctx, pre4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
@@ -87,12 +80,7 @@ void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
if (available_language_codes.size() > post4_0_0_max_entries) {
|
||||
ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>());
|
||||
} else {
|
||||
ctx.WriteBuffer(available_language_codes);
|
||||
}
|
||||
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
|
||||
GetAvailableLanguageCodesImpl(ctx, post4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
|
||||
@@ -102,9 +90,9 @@ void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
|
||||
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
|
||||
|
||||
LOG_DEBUG(Service_SET, "called");
|
||||
|
||||
PushResponseLanguageCode(ctx, post4_0_0_max_entries);
|
||||
}
|
||||
|
||||
void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Service::VI {
|
||||
|
||||
Display::Display(u64 id, std::string name) : id{id}, name{std::move(name)} {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
|
||||
vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Manual,
|
||||
fmt::format("Display VSync Event {}", id));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "video_core/engines/engine_upload.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
@@ -10,7 +12,9 @@
|
||||
namespace Tegra::Engines::Upload {
|
||||
|
||||
State::State(MemoryManager& memory_manager, Registers& regs)
|
||||
: memory_manager(memory_manager), regs(regs) {}
|
||||
: regs{regs}, memory_manager{memory_manager} {}
|
||||
|
||||
State::~State() = default;
|
||||
|
||||
void State::ProcessExec(const bool is_linear) {
|
||||
write_offset = 0;
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Tegra {
|
||||
@@ -57,10 +55,10 @@ struct Registers {
|
||||
class State {
|
||||
public:
|
||||
State(MemoryManager& memory_manager, Registers& regs);
|
||||
~State() = default;
|
||||
~State();
|
||||
|
||||
void ProcessExec(const bool is_linear);
|
||||
void ProcessData(const u32 data, const bool is_last_call);
|
||||
void ProcessExec(bool is_linear);
|
||||
void ProcessData(u32 data, bool is_last_call);
|
||||
|
||||
private:
|
||||
u32 write_offset = 0;
|
||||
|
||||
@@ -34,9 +34,9 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
|
||||
// Depth range near/far is not always set, but is expected to be the default 0.0f, 1.0f. This is
|
||||
// needed for ARMS.
|
||||
for (std::size_t viewport{}; viewport < Regs::NumViewports; ++viewport) {
|
||||
regs.viewports[viewport].depth_range_near = 0.0f;
|
||||
regs.viewports[viewport].depth_range_far = 1.0f;
|
||||
for (auto& viewport : regs.viewports) {
|
||||
viewport.depth_range_near = 0.0f;
|
||||
viewport.depth_range_far = 1.0f;
|
||||
}
|
||||
|
||||
// Doom and Bomberman seems to use the uninitialized registers and just enable blend
|
||||
@@ -47,13 +47,13 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
regs.blend.equation_a = Regs::Blend::Equation::Add;
|
||||
regs.blend.factor_source_a = Regs::Blend::Factor::One;
|
||||
regs.blend.factor_dest_a = Regs::Blend::Factor::Zero;
|
||||
for (std::size_t blend_index = 0; blend_index < Regs::NumRenderTargets; blend_index++) {
|
||||
regs.independent_blend[blend_index].equation_rgb = Regs::Blend::Equation::Add;
|
||||
regs.independent_blend[blend_index].factor_source_rgb = Regs::Blend::Factor::One;
|
||||
regs.independent_blend[blend_index].factor_dest_rgb = Regs::Blend::Factor::Zero;
|
||||
regs.independent_blend[blend_index].equation_a = Regs::Blend::Equation::Add;
|
||||
regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One;
|
||||
regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero;
|
||||
for (auto& blend : regs.independent_blend) {
|
||||
blend.equation_rgb = Regs::Blend::Equation::Add;
|
||||
blend.factor_source_rgb = Regs::Blend::Factor::One;
|
||||
blend.factor_dest_rgb = Regs::Blend::Factor::Zero;
|
||||
blend.equation_a = Regs::Blend::Equation::Add;
|
||||
blend.factor_source_a = Regs::Blend::Factor::One;
|
||||
blend.factor_dest_a = Regs::Blend::Factor::Zero;
|
||||
}
|
||||
regs.stencil_front_op_fail = Regs::StencilOp::Keep;
|
||||
regs.stencil_front_op_zfail = Regs::StencilOp::Keep;
|
||||
@@ -75,11 +75,11 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
|
||||
// TODO(bunnei): Some games do not initialize the color masks (e.g. Sonic Mania). Assuming a
|
||||
// default of enabled fixes rendering here.
|
||||
for (std::size_t color_mask = 0; color_mask < Regs::NumRenderTargets; color_mask++) {
|
||||
regs.color_mask[color_mask].R.Assign(1);
|
||||
regs.color_mask[color_mask].G.Assign(1);
|
||||
regs.color_mask[color_mask].B.Assign(1);
|
||||
regs.color_mask[color_mask].A.Assign(1);
|
||||
for (auto& color_mask : regs.color_mask) {
|
||||
color_mask.R.Assign(1);
|
||||
color_mask.G.Assign(1);
|
||||
color_mask.B.Assign(1);
|
||||
color_mask.A.Assign(1);
|
||||
}
|
||||
|
||||
// Commercial games seem to assume this value is enabled and nouveau sets this value manually.
|
||||
@@ -178,13 +178,13 @@ void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) {
|
||||
|
||||
// Vertex buffer
|
||||
if (method >= MAXWELL3D_REG_INDEX(vertex_array) &&
|
||||
method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) {
|
||||
method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * Regs::NumVertexArrays) {
|
||||
dirty_flags.vertex_array.set((method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2);
|
||||
} else if (method >= MAXWELL3D_REG_INDEX(vertex_array_limit) &&
|
||||
method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) {
|
||||
method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * Regs::NumVertexArrays) {
|
||||
dirty_flags.vertex_array.set((method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1);
|
||||
} else if (method >= MAXWELL3D_REG_INDEX(instanced_arrays) &&
|
||||
method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) {
|
||||
method < MAXWELL3D_REG_INDEX(instanced_arrays) + Regs::NumVertexArrays) {
|
||||
dirty_flags.vertex_array.set(method - MAXWELL3D_REG_INDEX(instanced_arrays));
|
||||
}
|
||||
}
|
||||
@@ -442,7 +442,7 @@ Texture::TICEntry Maxwell3D::GetTICEntry(u32 tic_index) const {
|
||||
const auto a_type = tic_entry.a_type.Value();
|
||||
|
||||
// TODO(Subv): Different data types for separate components are not supported
|
||||
ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
|
||||
DEBUG_ASSERT(r_type == g_type && r_type == b_type && r_type == a_type);
|
||||
|
||||
return tic_entry;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -1107,6 +1108,7 @@ public:
|
||||
} regs{};
|
||||
|
||||
static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32), "Maxwell3D Regs has wrong size");
|
||||
static_assert(std::is_trivially_copyable_v<Regs>, "Maxwell3D Regs must be trivially copyable");
|
||||
|
||||
struct State {
|
||||
struct ConstBufferInfo {
|
||||
|
||||
@@ -44,7 +44,7 @@ static void RunThread(VideoCore::RendererBase& renderer, Tegra::DmaPusher& dma_p
|
||||
renderer.Rasterizer().FlushRegion(data->addr, data->size);
|
||||
} else if (const auto data = std::get_if<InvalidateRegionCommand>(&next.data)) {
|
||||
renderer.Rasterizer().InvalidateRegion(data->addr, data->size);
|
||||
} else if (const auto data = std::get_if<EndProcessingCommand>(&next.data)) {
|
||||
} else if (std::holds_alternative<EndProcessingCommand>(next.data)) {
|
||||
return;
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
@@ -118,7 +118,7 @@ void SynchState::WaitForSynchronization(u64 fence) {
|
||||
// Wait for the GPU to be idle (all commands to be executed)
|
||||
{
|
||||
MICROPROFILE_SCOPE(GPU_wait);
|
||||
std::unique_lock<std::mutex> lock{synchronization_mutex};
|
||||
std::unique_lock lock{synchronization_mutex};
|
||||
synchronization_condition.wait(lock, [this, fence] { return signaled_fence >= fence; });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ struct SynchState final {
|
||||
|
||||
void TrySynchronize() {
|
||||
if (IsSynchronized()) {
|
||||
std::lock_guard<std::mutex> lock{synchronization_mutex};
|
||||
std::lock_guard lock{synchronization_mutex};
|
||||
synchronization_condition.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,10 +118,10 @@ bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
|
||||
static_cast<u32>(opcode.operation.Value()));
|
||||
}
|
||||
|
||||
if (opcode.is_exit) {
|
||||
// An instruction with the Exit flag will not actually
|
||||
// cause an exit if it's executed inside a delay slot.
|
||||
if (opcode.is_exit && !is_delay_slot) {
|
||||
// Exit has a delay slot, execute the next instruction
|
||||
// Note: Executing an exit during a branch delay slot will cause the instruction at the
|
||||
// branch target to be executed before exiting.
|
||||
Step(offset, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ MemoryManager::MemoryManager(VideoCore::RasterizerInterface& rasterizer) : raste
|
||||
UpdatePageTableForVMA(initial_vma);
|
||||
}
|
||||
|
||||
MemoryManager::~MemoryManager() = default;
|
||||
|
||||
GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
|
||||
const u64 aligned_size{Common::AlignUp(size, page_size)};
|
||||
const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)};
|
||||
@@ -199,11 +201,11 @@ const u8* MemoryManager::GetPointer(GPUVAddr addr) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool MemoryManager::IsBlockContinous(const GPUVAddr start, const std::size_t size) {
|
||||
bool MemoryManager::IsBlockContinuous(const GPUVAddr start, const std::size_t size) const {
|
||||
const GPUVAddr end = start + size;
|
||||
const auto host_ptr_start = reinterpret_cast<std::uintptr_t>(GetPointer(start));
|
||||
const auto host_ptr_end = reinterpret_cast<std::uintptr_t>(GetPointer(end));
|
||||
const std::size_t range = static_cast<std::size_t>(host_ptr_end - host_ptr_start);
|
||||
const auto range = static_cast<std::size_t>(host_ptr_end - host_ptr_start);
|
||||
return range == size;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ struct VirtualMemoryArea {
|
||||
|
||||
class MemoryManager final {
|
||||
public:
|
||||
MemoryManager(VideoCore::RasterizerInterface& rasterizer);
|
||||
explicit MemoryManager(VideoCore::RasterizerInterface& rasterizer);
|
||||
~MemoryManager();
|
||||
|
||||
GPUVAddr AllocateSpace(u64 size, u64 align);
|
||||
GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
|
||||
@@ -65,18 +66,18 @@ public:
|
||||
u8* GetPointer(GPUVAddr addr);
|
||||
const u8* GetPointer(GPUVAddr addr) const;
|
||||
|
||||
// Returns true if the block is continous in host memory, false otherwise
|
||||
bool IsBlockContinous(const GPUVAddr start, const std::size_t size);
|
||||
/// Returns true if the block is continuous in host memory, false otherwise
|
||||
bool IsBlockContinuous(GPUVAddr start, std::size_t size) const;
|
||||
|
||||
/**
|
||||
* ReadBlock and WriteBlock are full read and write operations over virtual
|
||||
* GPU Memory. It's important to use these when GPU memory may not be continous
|
||||
* GPU Memory. It's important to use these when GPU memory may not be continuous
|
||||
* in the Host Memory counterpart. Note: This functions cause Host GPU Memory
|
||||
* Flushes and Invalidations, respectively to each operation.
|
||||
*/
|
||||
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const;
|
||||
void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size);
|
||||
void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size);
|
||||
void ReadBlock(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
|
||||
void WriteBlock(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
|
||||
void CopyBlock(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
|
||||
|
||||
/**
|
||||
* ReadBlockUnsafe and WriteBlockUnsafe are special versions of ReadBlock and
|
||||
@@ -88,9 +89,9 @@ public:
|
||||
* WriteBlockUnsafe instead of WriteBlock since it shouldn't invalidate the texture
|
||||
* being flushed.
|
||||
*/
|
||||
void ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, const std::size_t size) const;
|
||||
void WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, const std::size_t size);
|
||||
void CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, const std::size_t size);
|
||||
void ReadBlockUnsafe(GPUVAddr src_addr, void* dest_buffer, std::size_t size) const;
|
||||
void WriteBlockUnsafe(GPUVAddr dest_addr, const void* src_buffer, std::size_t size);
|
||||
void CopyBlockUnsafe(GPUVAddr dest_addr, GPUVAddr src_addr, std::size_t size);
|
||||
|
||||
private:
|
||||
using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>;
|
||||
@@ -111,10 +112,10 @@ private:
|
||||
/**
|
||||
* Maps an unmanaged host memory pointer at a given address.
|
||||
*
|
||||
* @param target The guest address to start the mapping at.
|
||||
* @param memory The memory to be mapped.
|
||||
* @param size Size of the mapping.
|
||||
* @param state MemoryState tag to attach to the VMA.
|
||||
* @param target The guest address to start the mapping at.
|
||||
* @param memory The memory to be mapped.
|
||||
* @param size Size of the mapping in bytes.
|
||||
* @param backing_addr The base address of the range to back this mapping.
|
||||
*/
|
||||
VMAHandle MapBackingMemory(GPUVAddr target, u8* memory, u64 size, VAddr backing_addr);
|
||||
|
||||
@@ -124,7 +125,7 @@ private:
|
||||
/// Converts a VMAHandle to a mutable VMAIter.
|
||||
VMAIter StripIterConstness(const VMAHandle& iter);
|
||||
|
||||
/// Marks as the specfied VMA as allocated.
|
||||
/// Marks as the specified VMA as allocated.
|
||||
VMAIter Allocate(VMAIter vma);
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,9 +37,6 @@ public:
|
||||
/// Gets the size of the shader in guest memory, required for cache management
|
||||
virtual std::size_t GetSizeInBytes() const = 0;
|
||||
|
||||
/// Wriets any cached resources back to memory
|
||||
virtual void Flush() = 0;
|
||||
|
||||
/// Sets whether the cached object should be considered registered
|
||||
void SetIsRegistered(bool registered) {
|
||||
is_registered = registered;
|
||||
@@ -158,6 +155,8 @@ protected:
|
||||
return ++modified_ticks;
|
||||
}
|
||||
|
||||
virtual void FlushObjectInner(const T& object) = 0;
|
||||
|
||||
/// Flushes the specified object, updating appropriate cache state as needed
|
||||
void FlushObject(const T& object) {
|
||||
std::lock_guard lock{mutex};
|
||||
@@ -165,7 +164,7 @@ protected:
|
||||
if (!object->IsDirty()) {
|
||||
return;
|
||||
}
|
||||
object->Flush();
|
||||
FlushObjectInner(object);
|
||||
object->MarkAsModified(false, *this);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,6 @@ public:
|
||||
return alignment;
|
||||
}
|
||||
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
void Flush() override {}
|
||||
|
||||
private:
|
||||
VAddr cpu_addr{};
|
||||
std::size_t size{};
|
||||
@@ -75,6 +72,9 @@ public:
|
||||
protected:
|
||||
void AlignBuffer(std::size_t alignment);
|
||||
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
void FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& object) override {}
|
||||
|
||||
private:
|
||||
OGLStreamBuffer stream_buffer;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
/// Reloads the global region from guest memory
|
||||
void Reload(u32 size_);
|
||||
|
||||
void Flush() override;
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
VAddr cpu_addr{};
|
||||
@@ -65,6 +65,11 @@ public:
|
||||
GlobalRegion GetGlobalRegion(const GLShader::GlobalMemoryEntry& descriptor,
|
||||
Tegra::Engines::Maxwell3D::Regs::ShaderStage stage);
|
||||
|
||||
protected:
|
||||
void FlushObjectInner(const GlobalRegion& object) override {
|
||||
object->Flush();
|
||||
}
|
||||
|
||||
private:
|
||||
GlobalRegion TryGetReservedGlobalRegion(CacheAddr addr, u32 size) const;
|
||||
GlobalRegion GetUncachedGlobalRegion(GPUVAddr addr, u8* host_ptr, u32 size);
|
||||
|
||||
@@ -261,8 +261,8 @@ DrawParameters RasterizerOpenGL::SetupDraw() {
|
||||
// MakeQuadArray always generates u32 indexes
|
||||
params.index_format = GL_UNSIGNED_INT;
|
||||
params.count = (regs.vertex_buffer.count / 4) * 6;
|
||||
params.index_buffer_offset =
|
||||
primitive_assembler.MakeQuadArray(regs.vertex_buffer.first, params.count);
|
||||
params.index_buffer_offset = primitive_assembler.MakeQuadArray(
|
||||
regs.vertex_buffer.first, regs.vertex_buffer.count);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
@@ -1135,7 +1135,9 @@ void RasterizerOpenGL::SyncTransformFeedback() {
|
||||
|
||||
void RasterizerOpenGL::SyncPointState() {
|
||||
const auto& regs = system.GPU().Maxwell3D().regs;
|
||||
state.point.size = regs.point_size;
|
||||
// Limit the point size to 1 since nouveau sometimes sets a point size of 0 (and that's invalid
|
||||
// in OpenGL).
|
||||
state.point.size = std::max(1.0f, regs.point_size);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncPolygonOffset() {
|
||||
|
||||
@@ -628,9 +628,11 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
|
||||
void CachedSurface::LoadGLBuffer() {
|
||||
void CachedSurface::LoadGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem) {
|
||||
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
||||
gl_buffer.resize(params.max_mip_level);
|
||||
auto& gl_buffer = res_cache_tmp_mem.gl_buffer;
|
||||
if (gl_buffer.size() < params.max_mip_level)
|
||||
gl_buffer.resize(params.max_mip_level);
|
||||
for (u32 i = 0; i < params.max_mip_level; i++)
|
||||
gl_buffer[i].resize(params.GetMipmapSizeGL(i));
|
||||
if (params.is_tiled) {
|
||||
@@ -671,13 +673,13 @@ void CachedSurface::LoadGLBuffer() {
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
||||
void CachedSurface::FlushGLBuffer() {
|
||||
void CachedSurface::FlushGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem) {
|
||||
MICROPROFILE_SCOPE(OpenGL_SurfaceFlush);
|
||||
|
||||
ASSERT_MSG(!IsPixelFormatASTC(params.pixel_format), "Unimplemented");
|
||||
|
||||
auto& gl_buffer = res_cache_tmp_mem.gl_buffer;
|
||||
// OpenGL temporary buffer needs to be big enough to store raw texture size
|
||||
gl_buffer.resize(1);
|
||||
gl_buffer[0].resize(GetSizeInBytes());
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||
@@ -713,10 +715,12 @@ void CachedSurface::FlushGLBuffer() {
|
||||
}
|
||||
}
|
||||
|
||||
void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||
GLuint draw_fb_handle) {
|
||||
void CachedSurface::UploadGLMipmapTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, u32 mip_map,
|
||||
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||
const auto& rect{params.GetRect(mip_map)};
|
||||
|
||||
auto& gl_buffer = res_cache_tmp_mem.gl_buffer;
|
||||
|
||||
// Load data from memory to the surface
|
||||
const auto x0 = static_cast<GLint>(rect.left);
|
||||
const auto y0 = static_cast<GLint>(rect.bottom);
|
||||
@@ -801,7 +805,6 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||
tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap: {
|
||||
std::size_t start = buffer_offset;
|
||||
for (std::size_t face = 0; face < params.depth; ++face) {
|
||||
glTextureSubImage3D(texture.handle, mip_map, x0, y0, static_cast<GLint>(face),
|
||||
static_cast<GLsizei>(rect.GetWidth()),
|
||||
@@ -845,11 +848,12 @@ void CachedSurface::EnsureTextureDiscrepantView() {
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
|
||||
void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||
void CachedSurface::UploadGLTexture(RasterizerTemporaryMemory& res_cache_tmp_mem,
|
||||
GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||
MICROPROFILE_SCOPE(OpenGL_TextureUL);
|
||||
|
||||
for (u32 i = 0; i < params.max_mip_level; i++)
|
||||
UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
|
||||
UploadGLMipmapTexture(res_cache_tmp_mem, i, read_fb_handle, draw_fb_handle);
|
||||
}
|
||||
|
||||
void CachedSurface::UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
|
||||
@@ -929,8 +933,8 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre
|
||||
}
|
||||
|
||||
void RasterizerCacheOpenGL::LoadSurface(const Surface& surface) {
|
||||
surface->LoadGLBuffer();
|
||||
surface->UploadGLTexture(read_framebuffer.handle, draw_framebuffer.handle);
|
||||
surface->LoadGLBuffer(temporal_memory);
|
||||
surface->UploadGLTexture(temporal_memory, read_framebuffer.handle, draw_framebuffer.handle);
|
||||
surface->MarkAsModified(false, *this);
|
||||
surface->MarkForReload(false);
|
||||
}
|
||||
|
||||
@@ -355,6 +355,12 @@ namespace OpenGL {
|
||||
|
||||
class RasterizerOpenGL;
|
||||
|
||||
// This is used to store temporary big buffers,
|
||||
// instead of creating/destroying all the time
|
||||
struct RasterizerTemporaryMemory {
|
||||
std::vector<std::vector<u8>> gl_buffer;
|
||||
};
|
||||
|
||||
class CachedSurface final : public RasterizerCacheObject {
|
||||
public:
|
||||
explicit CachedSurface(const SurfaceParams& params);
|
||||
@@ -371,10 +377,6 @@ public:
|
||||
return memory_size;
|
||||
}
|
||||
|
||||
void Flush() override {
|
||||
FlushGLBuffer();
|
||||
}
|
||||
|
||||
const OGLTexture& Texture() const {
|
||||
return texture;
|
||||
}
|
||||
@@ -397,11 +399,12 @@ public:
|
||||
}
|
||||
|
||||
// Read/Write data in Switch memory to/from gl_buffer
|
||||
void LoadGLBuffer();
|
||||
void FlushGLBuffer();
|
||||
void LoadGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem);
|
||||
void FlushGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem);
|
||||
|
||||
// Upload data in gl_buffer to this surface's texture
|
||||
void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||
void UploadGLTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, GLuint read_fb_handle,
|
||||
GLuint draw_fb_handle);
|
||||
|
||||
void UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
|
||||
Tegra::Texture::SwizzleSource swizzle_y,
|
||||
@@ -429,13 +432,13 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||
void UploadGLMipmapTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, u32 mip_map,
|
||||
GLuint read_fb_handle, GLuint draw_fb_handle);
|
||||
|
||||
void EnsureTextureDiscrepantView();
|
||||
|
||||
OGLTexture texture;
|
||||
OGLTexture discrepant_view;
|
||||
std::vector<std::vector<u8>> gl_buffer;
|
||||
SurfaceParams params{};
|
||||
GLenum gl_target{};
|
||||
GLenum gl_internal_format{};
|
||||
@@ -473,6 +476,11 @@ public:
|
||||
void SignalPreDrawCall();
|
||||
void SignalPostDrawCall();
|
||||
|
||||
protected:
|
||||
void FlushObjectInner(const Surface& object) override {
|
||||
object->FlushGLBuffer(temporal_memory);
|
||||
}
|
||||
|
||||
private:
|
||||
void LoadSurface(const Surface& surface);
|
||||
Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true);
|
||||
@@ -519,6 +527,8 @@ private:
|
||||
std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers;
|
||||
Surface last_depth_buffer;
|
||||
|
||||
RasterizerTemporaryMemory temporal_memory;
|
||||
|
||||
using SurfaceIntervalCache = boost::icl::interval_map<CacheAddr, Surface>;
|
||||
using SurfaceInterval = typename SurfaceIntervalCache::interval_type;
|
||||
|
||||
|
||||
@@ -345,7 +345,7 @@ ShaderDiskCacheUsage CachedShader::GetUsage(GLenum primitive_mode,
|
||||
|
||||
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer, Core::System& system,
|
||||
const Device& device)
|
||||
: RasterizerCache{rasterizer}, disk_cache{system}, device{device} {}
|
||||
: RasterizerCache{rasterizer}, device{device}, disk_cache{system} {}
|
||||
|
||||
void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
|
||||
const VideoCore::DiskResourceLoadCallback& callback) {
|
||||
|
||||
@@ -57,9 +57,6 @@ public:
|
||||
return shader_length;
|
||||
}
|
||||
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
void Flush() override {}
|
||||
|
||||
/// Gets the shader entries for the shader
|
||||
const GLShader::ShaderEntries& GetShaderEntries() const {
|
||||
return entries;
|
||||
@@ -123,6 +120,10 @@ public:
|
||||
/// Gets the current specified shader stage program
|
||||
Shader GetStageProgram(Maxwell::ShaderProgram program);
|
||||
|
||||
protected:
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
void FlushObjectInner(const Shader& object) override {}
|
||||
|
||||
private:
|
||||
std::unordered_map<u64, UnspecializedShader> GenerateUnspecializedShaders(
|
||||
const std::atomic_bool& stop_loading, const VideoCore::DiskResourceLoadCallback& callback,
|
||||
|
||||
@@ -871,17 +871,6 @@ private:
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string Composite(Operation operation) {
|
||||
std::string value = "vec4(";
|
||||
for (std::size_t i = 0; i < 4; ++i) {
|
||||
value += Visit(operation[i]);
|
||||
if (i < 3)
|
||||
value += ", ";
|
||||
}
|
||||
value += ')';
|
||||
return value;
|
||||
}
|
||||
|
||||
template <Type type>
|
||||
std::string Add(Operation operation) {
|
||||
return GenerateBinaryInfix(operation, "+", type, type, type);
|
||||
|
||||
@@ -33,14 +33,14 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config {
|
||||
};
|
||||
|
||||
)";
|
||||
ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||
const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||
ProgramResult program =
|
||||
Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Vertex, "vertex");
|
||||
|
||||
out += program.first;
|
||||
|
||||
if (setup.IsDualProgram()) {
|
||||
ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET);
|
||||
const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET);
|
||||
ProgramResult program_b =
|
||||
Decompile(device, program_ir_b, Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b");
|
||||
|
||||
@@ -76,7 +76,7 @@ void main() {
|
||||
}
|
||||
})";
|
||||
|
||||
return {out, program.second};
|
||||
return {std::move(out), std::move(program.second)};
|
||||
}
|
||||
|
||||
ProgramResult GenerateGeometryShader(const Device& device, const ShaderSetup& setup) {
|
||||
@@ -97,7 +97,7 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config {
|
||||
};
|
||||
|
||||
)";
|
||||
ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||
const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||
ProgramResult program =
|
||||
Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Geometry, "geometry");
|
||||
out += program.first;
|
||||
@@ -107,7 +107,7 @@ void main() {
|
||||
execute_geometry();
|
||||
};)";
|
||||
|
||||
return {out, program.second};
|
||||
return {std::move(out), std::move(program.second)};
|
||||
}
|
||||
|
||||
ProgramResult GenerateFragmentShader(const Device& device, const ShaderSetup& setup) {
|
||||
@@ -160,7 +160,7 @@ bool AlphaFunc(in float value) {
|
||||
}
|
||||
|
||||
)";
|
||||
ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||
const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET);
|
||||
ProgramResult program =
|
||||
Decompile(device, program_ir, Maxwell3D::Regs::ShaderStage::Fragment, "fragment");
|
||||
|
||||
@@ -172,7 +172,7 @@ void main() {
|
||||
}
|
||||
|
||||
)";
|
||||
return {out, program.second};
|
||||
return {std::move(out), std::move(program.second)};
|
||||
}
|
||||
|
||||
} // namespace OpenGL::GLShader
|
||||
|
||||
@@ -126,6 +126,8 @@ inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) {
|
||||
return GL_TRIANGLES;
|
||||
case Maxwell::PrimitiveTopology::TriangleStrip:
|
||||
return GL_TRIANGLE_STRIP;
|
||||
case Maxwell::PrimitiveTopology::TriangleFan:
|
||||
return GL_TRIANGLE_FAN;
|
||||
default:
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented topology={}", static_cast<u32>(topology));
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -49,9 +49,6 @@ public:
|
||||
return alignment;
|
||||
}
|
||||
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
void Flush() override {}
|
||||
|
||||
private:
|
||||
VAddr cpu_addr{};
|
||||
std::size_t size{};
|
||||
@@ -87,6 +84,10 @@ public:
|
||||
return buffer_handle;
|
||||
}
|
||||
|
||||
protected:
|
||||
// We do not have to flush this cache as things in it are never modified by us.
|
||||
void FlushObjectInner(const std::shared_ptr<CachedBufferEntry>& object) override {}
|
||||
|
||||
private:
|
||||
void AlignBuffer(std::size_t alignment);
|
||||
|
||||
|
||||
@@ -315,7 +315,6 @@ private:
|
||||
constexpr std::array<const char*, INTERNAL_FLAGS_COUNT> names = {"zero", "sign", "carry",
|
||||
"overflow"};
|
||||
for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) {
|
||||
const auto flag_code = static_cast<InternalFlag>(flag);
|
||||
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
|
||||
internal_flags[flag] = AddGlobalVariable(Name(id, names[flag]));
|
||||
}
|
||||
|
||||
@@ -540,7 +540,6 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type,
|
||||
Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool depth_compare,
|
||||
bool is_array, bool is_aoffi) {
|
||||
const std::size_t coord_count = GetCoordCount(texture_type);
|
||||
const std::size_t total_coord_count = coord_count + (is_array ? 1 : 0);
|
||||
|
||||
// If enabled arrays index is always stored in the gpr8 field
|
||||
const u64 array_register = instr.gpr8.Value();
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
class InputBitStream {
|
||||
public:
|
||||
explicit InputBitStream(const unsigned char* ptr, int nBits = 0, int start_offset = 0)
|
||||
: m_NumBits(nBits), m_CurByte(ptr), m_NextBit(start_offset % 8) {}
|
||||
explicit InputBitStream(const unsigned char* ptr, int start_offset = 0)
|
||||
: m_CurByte(ptr), m_NextBit(start_offset % 8) {}
|
||||
|
||||
~InputBitStream() = default;
|
||||
|
||||
@@ -55,12 +55,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
const int m_NumBits;
|
||||
const unsigned char* m_CurByte;
|
||||
int m_NextBit = 0;
|
||||
int m_BitsRead = 0;
|
||||
|
||||
bool done = false;
|
||||
};
|
||||
|
||||
class OutputBitStream {
|
||||
@@ -114,7 +111,6 @@ private:
|
||||
const int m_NumBits;
|
||||
unsigned char* m_CurByte;
|
||||
int m_NextBit = 0;
|
||||
int m_BitsRead = 0;
|
||||
|
||||
bool done = false;
|
||||
};
|
||||
|
||||
@@ -82,8 +82,6 @@ add_executable(yuzu
|
||||
util/limitable_input_dialog.h
|
||||
util/sequence_dialog/sequence_dialog.cpp
|
||||
util/sequence_dialog/sequence_dialog.h
|
||||
util/spinbox.cpp
|
||||
util/spinbox.h
|
||||
util/util.cpp
|
||||
util/util.h
|
||||
compatdb.cpp
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) {
|
||||
ui->setupUi(this);
|
||||
ui->labelLogo->setPixmap(QIcon::fromTheme("yuzu").pixmap(200));
|
||||
ui->labelBuildInfo->setText(
|
||||
ui->labelBuildInfo->text().arg(Common::g_build_fullname, Common::g_scm_branch,
|
||||
Common::g_scm_desc, QString(Common::g_build_date).left(10)));
|
||||
ui->labelLogo->setPixmap(QIcon::fromTheme(QStringLiteral("yuzu")).pixmap(200));
|
||||
ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg(
|
||||
QString::fromUtf8(Common::g_build_fullname), QString::fromUtf8(Common::g_scm_branch),
|
||||
QString::fromUtf8(Common::g_scm_desc), QString::fromUtf8(Common::g_build_date).left(10)));
|
||||
}
|
||||
|
||||
AboutDialog::~AboutDialog() = default;
|
||||
|
||||
@@ -54,6 +54,6 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te
|
||||
|
||||
void QtErrorDisplay::MainWindowFinishedError() {
|
||||
// Acquire the HLE mutex
|
||||
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
||||
std::lock_guard lock{HLE::g_hle_lock};
|
||||
callback();
|
||||
}
|
||||
|
||||
@@ -84,10 +84,10 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
|
||||
tree_view->setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
item_model->insertColumns(0, 1);
|
||||
item_model->setHeaderData(0, Qt::Horizontal, "Users");
|
||||
item_model->setHeaderData(0, Qt::Horizontal, tr("Users"));
|
||||
|
||||
// We must register all custom types with the Qt Automoc system so that we are able to use it
|
||||
// with signals/slots. In this case, QList falls under the umbrells of custom types.
|
||||
// with signals/slots. In this case, QList falls under the umbrella of custom types.
|
||||
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
|
||||
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@@ -379,6 +379,7 @@ void GRenderWindow::InitRenderTarget() {
|
||||
fmt.setVersion(4, 3);
|
||||
if (Settings::values.use_compatibility_profile) {
|
||||
fmt.setProfile(QSurfaceFormat::CompatibilityProfile);
|
||||
fmt.setOption(QSurfaceFormat::FormatOption::DeprecatedFunctions);
|
||||
} else {
|
||||
fmt.setProfile(QSurfaceFormat::CoreProfile);
|
||||
}
|
||||
|
||||
@@ -16,21 +16,21 @@ ConfigureAudio::ConfigureAudio(QWidget* parent)
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->output_sink_combo_box->clear();
|
||||
ui->output_sink_combo_box->addItem("auto");
|
||||
ui->output_sink_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name));
|
||||
for (const char* id : AudioCore::GetSinkIDs()) {
|
||||
ui->output_sink_combo_box->addItem(id);
|
||||
ui->output_sink_combo_box->addItem(QString::fromUtf8(id));
|
||||
}
|
||||
|
||||
connect(ui->volume_slider, &QSlider::valueChanged, this,
|
||||
&ConfigureAudio::setVolumeIndicatorText);
|
||||
|
||||
this->setConfiguration();
|
||||
connect(ui->output_sink_combo_box,
|
||||
static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this,
|
||||
connect(ui->output_sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
|
||||
&ConfigureAudio::updateAudioDevices);
|
||||
|
||||
ui->output_sink_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
ui->audio_device_combo_box->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
const bool is_powered_on = Core::System::GetInstance().IsPoweredOn();
|
||||
ui->output_sink_combo_box->setEnabled(!is_powered_on);
|
||||
ui->audio_device_combo_box->setEnabled(!is_powered_on);
|
||||
}
|
||||
|
||||
ConfigureAudio::~ConfigureAudio() = default;
|
||||
@@ -94,7 +94,7 @@ void ConfigureAudio::applyConfiguration() {
|
||||
|
||||
void ConfigureAudio::updateAudioDevices(int sink_index) {
|
||||
ui->audio_device_combo_box->clear();
|
||||
ui->audio_device_combo_box->addItem(AudioCore::auto_device_name);
|
||||
ui->audio_device_combo_box->addItem(QString::fromUtf8(AudioCore::auto_device_name));
|
||||
|
||||
const std::string sink_id = ui->output_sink_combo_box->itemText(sink_index).toStdString();
|
||||
for (const auto& device : AudioCore::GetDeviceListForSink(sink_id)) {
|
||||
|
||||
@@ -100,13 +100,15 @@ void ConfigureGameList::RetranslateUI() {
|
||||
|
||||
void ConfigureGameList::InitializeIconSizeComboBox() {
|
||||
for (const auto& size : default_icon_sizes) {
|
||||
ui->icon_size_combobox->addItem(size.second, size.first);
|
||||
ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureGameList::InitializeRowComboBoxes() {
|
||||
for (std::size_t i = 0; i < row_text_names.size(); ++i) {
|
||||
ui->row_1_text_combobox->addItem(row_text_names[i], QVariant::fromValue(i));
|
||||
ui->row_2_text_combobox->addItem(row_text_names[i], QVariant::fromValue(i));
|
||||
const QString row_text_name = QString::fromUtf8(row_text_names[i]);
|
||||
|
||||
ui->row_1_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
|
||||
ui->row_2_text_combobox->addItem(row_text_name, QVariant::fromValue(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
|
||||
ui->setupUi(this);
|
||||
|
||||
for (const auto& theme : UISettings::themes) {
|
||||
ui->theme_combobox->addItem(theme.first, theme.second);
|
||||
ui->theme_combobox->addItem(QString::fromUtf8(theme.first),
|
||||
QString::fromUtf8(theme.second));
|
||||
}
|
||||
|
||||
this->setConfiguration();
|
||||
|
||||
@@ -69,16 +69,20 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
|
||||
ConfigureGraphics::~ConfigureGraphics() = default;
|
||||
|
||||
void ConfigureGraphics::setConfiguration() {
|
||||
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
||||
|
||||
ui->resolution_factor_combobox->setCurrentIndex(
|
||||
static_cast<int>(FromResolutionFactor(Settings::values.resolution_factor)));
|
||||
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
|
||||
ui->frame_limit->setValue(Settings::values.frame_limit);
|
||||
ui->use_compatibility_profile->setEnabled(runtime_lock);
|
||||
ui->use_compatibility_profile->setChecked(Settings::values.use_compatibility_profile);
|
||||
ui->use_disk_shader_cache->setEnabled(runtime_lock);
|
||||
ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache);
|
||||
ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation);
|
||||
ui->use_asynchronous_gpu_emulation->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
|
||||
ui->use_asynchronous_gpu_emulation->setChecked(Settings::values.use_asynchronous_gpu_emulation);
|
||||
ui->force_30fps_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
ui->force_30fps_mode->setEnabled(runtime_lock);
|
||||
ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode);
|
||||
UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
|
||||
Settings::values.bg_blue));
|
||||
|
||||
@@ -75,8 +75,8 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
};
|
||||
|
||||
for (auto* controller_box : players_controller) {
|
||||
controller_box->addItems({"None", "Pro Controller", "Dual Joycons", "Single Right Joycon",
|
||||
"Single Left Joycon"});
|
||||
controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"),
|
||||
tr("Single Right Joycon"), tr("Single Left Joycon")});
|
||||
}
|
||||
|
||||
this->loadConfiguration();
|
||||
@@ -85,9 +85,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
|
||||
connect(ui->restore_defaults_button, &QPushButton::pressed, this,
|
||||
&ConfigureInput::restoreDefaults);
|
||||
|
||||
for (auto* enabled : players_controller)
|
||||
for (auto* enabled : players_controller) {
|
||||
connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&ConfigureInput::updateUIEnabled);
|
||||
}
|
||||
connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::updateUIEnabled);
|
||||
connect(ui->handheld_connected, &QCheckBox::stateChanged, this,
|
||||
&ConfigureInput::updateUIEnabled);
|
||||
@@ -147,10 +148,12 @@ void ConfigureInput::updateUIEnabled() {
|
||||
bool hit_disabled = false;
|
||||
for (auto* player : players_controller) {
|
||||
player->setDisabled(hit_disabled);
|
||||
if (hit_disabled)
|
||||
if (hit_disabled) {
|
||||
player->setCurrentIndex(0);
|
||||
if (!hit_disabled && player->currentIndex() == 0)
|
||||
}
|
||||
if (!hit_disabled && player->currentIndex() == 0) {
|
||||
hit_disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < players_controller.size(); ++i) {
|
||||
|
||||
@@ -45,7 +45,7 @@ static QString GetKeyName(int key_code) {
|
||||
case Qt::Key_Alt:
|
||||
return QObject::tr("Alt");
|
||||
case Qt::Key_Meta:
|
||||
return "";
|
||||
return {};
|
||||
default:
|
||||
return QKeySequence(key_code).toString();
|
||||
}
|
||||
@@ -65,46 +65,70 @@ static void SetAnalogButton(const Common::ParamPackage& input_param,
|
||||
static QString ButtonToText(const Common::ParamPackage& param) {
|
||||
if (!param.Has("engine")) {
|
||||
return QObject::tr("[not set]");
|
||||
} else if (param.Get("engine", "") == "keyboard") {
|
||||
return GetKeyName(param.Get("code", 0));
|
||||
} else if (param.Get("engine", "") == "sdl") {
|
||||
if (param.Has("hat")) {
|
||||
return QString(QObject::tr("Hat %1 %2"))
|
||||
.arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
|
||||
}
|
||||
if (param.Has("axis")) {
|
||||
return QString(QObject::tr("Axis %1%2"))
|
||||
.arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
|
||||
}
|
||||
if (param.Has("button")) {
|
||||
return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
|
||||
}
|
||||
return QString();
|
||||
} else {
|
||||
return QObject::tr("[unknown]");
|
||||
}
|
||||
};
|
||||
|
||||
if (param.Get("engine", "") == "keyboard") {
|
||||
return GetKeyName(param.Get("code", 0));
|
||||
}
|
||||
|
||||
if (param.Get("engine", "") == "sdl") {
|
||||
if (param.Has("hat")) {
|
||||
const QString hat_str = QString::fromStdString(param.Get("hat", ""));
|
||||
const QString direction_str = QString::fromStdString(param.Get("direction", ""));
|
||||
|
||||
return QObject::tr("Hat %1 %2").arg(hat_str, direction_str);
|
||||
}
|
||||
|
||||
if (param.Has("axis")) {
|
||||
const QString axis_str = QString::fromStdString(param.Get("axis", ""));
|
||||
const QString direction_str = QString::fromStdString(param.Get("direction", ""));
|
||||
|
||||
return QObject::tr("Axis %1%2").arg(axis_str, direction_str);
|
||||
}
|
||||
|
||||
if (param.Has("button")) {
|
||||
const QString button_str = QString::fromStdString(param.Get("button", ""));
|
||||
|
||||
return QObject::tr("Button %1").arg(button_str);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
return QObject::tr("[unknown]");
|
||||
}
|
||||
|
||||
static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
|
||||
if (!param.Has("engine")) {
|
||||
return QObject::tr("[not set]");
|
||||
} else if (param.Get("engine", "") == "analog_from_button") {
|
||||
}
|
||||
|
||||
if (param.Get("engine", "") == "analog_from_button") {
|
||||
return ButtonToText(Common::ParamPackage{param.Get(dir, "")});
|
||||
} else if (param.Get("engine", "") == "sdl") {
|
||||
}
|
||||
|
||||
if (param.Get("engine", "") == "sdl") {
|
||||
if (dir == "modifier") {
|
||||
return QString(QObject::tr("[unused]"));
|
||||
return QObject::tr("[unused]");
|
||||
}
|
||||
|
||||
if (dir == "left" || dir == "right") {
|
||||
return QString(QObject::tr("Axis %1")).arg(param.Get("axis_x", "").c_str());
|
||||
} else if (dir == "up" || dir == "down") {
|
||||
return QString(QObject::tr("Axis %1")).arg(param.Get("axis_y", "").c_str());
|
||||
const QString axis_x_str = QString::fromStdString(param.Get("axis_x", ""));
|
||||
|
||||
return QObject::tr("Axis %1").arg(axis_x_str);
|
||||
}
|
||||
return QString();
|
||||
} else {
|
||||
return QObject::tr("[unknown]");
|
||||
|
||||
if (dir == "up" || dir == "down") {
|
||||
const QString axis_y_str = QString::fromStdString(param.Get("axis_y", ""));
|
||||
|
||||
return QObject::tr("Axis %1").arg(axis_y_str);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
return QObject::tr("[unknown]");
|
||||
}
|
||||
|
||||
ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug)
|
||||
: QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index),
|
||||
@@ -214,38 +238,42 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
|
||||
|
||||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
|
||||
if (!button_map[button_id])
|
||||
auto* const button = button_map[button_id];
|
||||
if (button == nullptr) {
|
||||
continue;
|
||||
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(button_map[button_id], &QPushButton::released, [=]() {
|
||||
}
|
||||
|
||||
button->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(button, &QPushButton::released, [=] {
|
||||
handleClick(
|
||||
button_map[button_id],
|
||||
[=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
|
||||
InputCommon::Polling::DeviceType::Button);
|
||||
});
|
||||
connect(button_map[button_id], &QPushButton::customContextMenuRequested,
|
||||
[=](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
buttons_param[button_id].Clear();
|
||||
button_map[button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Restore Default"), [&] {
|
||||
buttons_param[button_id] = Common::ParamPackage{
|
||||
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
|
||||
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
|
||||
});
|
||||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
||||
});
|
||||
connect(button, &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
buttons_param[button_id].Clear();
|
||||
button_map[button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Restore Default"), [&] {
|
||||
buttons_param[button_id] = Common::ParamPackage{
|
||||
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
|
||||
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
|
||||
});
|
||||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
||||
});
|
||||
}
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
|
||||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
|
||||
if (!analog_map_buttons[analog_id][sub_button_id])
|
||||
auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
|
||||
if (analog_button == nullptr) {
|
||||
continue;
|
||||
analog_map_buttons[analog_id][sub_button_id]->setContextMenuPolicy(
|
||||
Qt::CustomContextMenu);
|
||||
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released, [=]() {
|
||||
}
|
||||
|
||||
analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(analog_button, &QPushButton::released, [=]() {
|
||||
handleClick(analog_map_buttons[analog_id][sub_button_id],
|
||||
[=](const Common::ParamPackage& params) {
|
||||
SetAnalogButton(params, analogs_param[analog_id],
|
||||
@@ -253,8 +281,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
},
|
||||
InputCommon::Polling::DeviceType::Button);
|
||||
});
|
||||
connect(analog_map_buttons[analog_id][sub_button_id],
|
||||
&QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
|
||||
connect(analog_button, &QPushButton::customContextMenuRequested,
|
||||
[=](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
|
||||
@@ -272,7 +300,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
|
||||
menu_location));
|
||||
});
|
||||
}
|
||||
connect(analog_map_stick[analog_id], &QPushButton::released, [=]() {
|
||||
connect(analog_map_stick[analog_id], &QPushButton::released, [=] {
|
||||
QMessageBox::information(this, tr("Information"),
|
||||
tr("After pressing OK, first move your joystick horizontally, "
|
||||
"and then vertically."));
|
||||
@@ -351,7 +379,7 @@ void ConfigureInputPlayer::OnControllerButtonClick(int i) {
|
||||
return;
|
||||
controller_colors[i] = new_bg_color;
|
||||
controller_color_buttons[i]->setStyleSheet(
|
||||
QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
|
||||
QStringLiteral("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
|
||||
}
|
||||
|
||||
void ConfigureInputPlayer::loadConfiguration() {
|
||||
@@ -388,7 +416,8 @@ void ConfigureInputPlayer::loadConfiguration() {
|
||||
|
||||
for (std::size_t i = 0; i < colors.size(); ++i) {
|
||||
controller_color_buttons[i]->setStyleSheet(
|
||||
QString("QPushButton { background-color: %1 }").arg(controller_colors[i].name()));
|
||||
QStringLiteral("QPushButton { background-color: %1 }")
|
||||
.arg(controller_colors[i].name()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,14 +439,22 @@ void ConfigureInputPlayer::restoreDefaults() {
|
||||
|
||||
void ConfigureInputPlayer::ClearAll() {
|
||||
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
|
||||
if (button_map[button_id] && button_map[button_id]->isEnabled())
|
||||
buttons_param[button_id].Clear();
|
||||
const auto* const button = button_map[button_id];
|
||||
if (button == nullptr || !button->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
buttons_param[button_id].Clear();
|
||||
}
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
|
||||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
|
||||
if (analog_map_buttons[analog_id][sub_button_id] &&
|
||||
analog_map_buttons[analog_id][sub_button_id]->isEnabled())
|
||||
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
|
||||
const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
|
||||
if (analog_button == nullptr || !analog_button->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,10 +468,14 @@ void ConfigureInputPlayer::updateButtonLabels() {
|
||||
|
||||
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
|
||||
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
|
||||
if (analog_map_buttons[analog_id][sub_button_id]) {
|
||||
analog_map_buttons[analog_id][sub_button_id]->setText(
|
||||
AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
|
||||
auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
|
||||
|
||||
if (analog_button == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
analog_button->setText(
|
||||
AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
|
||||
}
|
||||
analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ static QString GetKeyName(int key_code) {
|
||||
case Qt::Key_Alt:
|
||||
return QObject::tr("Alt");
|
||||
case Qt::Key_Meta:
|
||||
return "";
|
||||
return {};
|
||||
default:
|
||||
return QKeySequence(key_code).toString();
|
||||
}
|
||||
@@ -34,24 +34,36 @@ static QString GetKeyName(int key_code) {
|
||||
static QString ButtonToText(const Common::ParamPackage& param) {
|
||||
if (!param.Has("engine")) {
|
||||
return QObject::tr("[not set]");
|
||||
} else if (param.Get("engine", "") == "keyboard") {
|
||||
return GetKeyName(param.Get("code", 0));
|
||||
} else if (param.Get("engine", "") == "sdl") {
|
||||
if (param.Has("hat")) {
|
||||
return QString(QObject::tr("Hat %1 %2"))
|
||||
.arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
|
||||
}
|
||||
if (param.Has("axis")) {
|
||||
return QString(QObject::tr("Axis %1%2"))
|
||||
.arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
|
||||
}
|
||||
if (param.Has("button")) {
|
||||
return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
|
||||
}
|
||||
return QString();
|
||||
} else {
|
||||
return QObject::tr("[unknown]");
|
||||
}
|
||||
|
||||
if (param.Get("engine", "") == "keyboard") {
|
||||
return GetKeyName(param.Get("code", 0));
|
||||
}
|
||||
|
||||
if (param.Get("engine", "") == "sdl") {
|
||||
if (param.Has("hat")) {
|
||||
const QString hat_str = QString::fromStdString(param.Get("hat", ""));
|
||||
const QString direction_str = QString::fromStdString(param.Get("direction", ""));
|
||||
|
||||
return QObject::tr("Hat %1 %2").arg(hat_str, direction_str);
|
||||
}
|
||||
|
||||
if (param.Has("axis")) {
|
||||
const QString axis_str = QString::fromStdString(param.Get("axis", ""));
|
||||
const QString direction_str = QString::fromStdString(param.Get("direction", ""));
|
||||
|
||||
return QObject::tr("Axis %1%2").arg(axis_str, direction_str);
|
||||
}
|
||||
|
||||
if (param.Has("button")) {
|
||||
const QString button_str = QString::fromStdString(param.Get("button", ""));
|
||||
|
||||
return QObject::tr("Button %1").arg(button_str);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
return QObject::tr("[unknown]");
|
||||
}
|
||||
|
||||
ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
|
||||
@@ -65,30 +77,31 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
|
||||
};
|
||||
|
||||
for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
|
||||
if (!button_map[button_id])
|
||||
auto* const button = button_map[button_id];
|
||||
if (button == nullptr) {
|
||||
continue;
|
||||
button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(button_map[button_id], &QPushButton::released, [=]() {
|
||||
}
|
||||
|
||||
button->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(button, &QPushButton::released, [=] {
|
||||
handleClick(
|
||||
button_map[button_id],
|
||||
[=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
|
||||
InputCommon::Polling::DeviceType::Button);
|
||||
});
|
||||
connect(button_map[button_id], &QPushButton::customContextMenuRequested,
|
||||
[=](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
buttons_param[button_id].Clear();
|
||||
button_map[button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Restore Default"), [&] {
|
||||
buttons_param[button_id] =
|
||||
Common::ParamPackage{InputCommon::GenerateKeyboardParam(
|
||||
Config::default_mouse_buttons[button_id])};
|
||||
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
|
||||
});
|
||||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
||||
});
|
||||
connect(button, &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
|
||||
QMenu context_menu;
|
||||
context_menu.addAction(tr("Clear"), [&] {
|
||||
buttons_param[button_id].Clear();
|
||||
button_map[button_id]->setText(tr("[not set]"));
|
||||
});
|
||||
context_menu.addAction(tr("Restore Default"), [&] {
|
||||
buttons_param[button_id] = Common::ParamPackage{
|
||||
InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
|
||||
button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
|
||||
});
|
||||
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
|
||||
});
|
||||
}
|
||||
|
||||
connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
|
||||
@@ -138,8 +151,10 @@ void ConfigureMouseAdvanced::restoreDefaults() {
|
||||
|
||||
void ConfigureMouseAdvanced::ClearAll() {
|
||||
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
|
||||
if (button_map[i] && button_map[i]->isEnabled())
|
||||
const auto* const button = button_map[i];
|
||||
if (button != nullptr && button->isEnabled()) {
|
||||
buttons_param[i].Clear();
|
||||
}
|
||||
}
|
||||
|
||||
updateButtonLabels();
|
||||
|
||||
@@ -88,15 +88,15 @@ void ConfigurePerGameGeneral::loadFromFile(FileSys::VirtualFile file) {
|
||||
}
|
||||
|
||||
void ConfigurePerGameGeneral::loadConfiguration() {
|
||||
if (file == nullptr)
|
||||
if (file == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto loader = Loader::GetLoader(file);
|
||||
|
||||
ui->display_title_id->setText(fmt::format("{:016X}", title_id).c_str());
|
||||
ui->display_title_id->setText(QString::fromStdString(fmt::format("{:016X}", title_id)));
|
||||
|
||||
FileSys::PatchManager pm{title_id};
|
||||
const auto control = pm.GetControlMetadata();
|
||||
const auto loader = Loader::GetLoader(file);
|
||||
|
||||
if (control.first != nullptr) {
|
||||
ui->display_version->setText(QString::fromStdString(control.first->GetVersionString()));
|
||||
@@ -142,8 +142,10 @@ void ConfigurePerGameGeneral::loadConfiguration() {
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
|
||||
for (const auto& patch : pm.GetPatchVersionNames(update_raw)) {
|
||||
QStandardItem* first_item = new QStandardItem;
|
||||
const auto name = QString::fromStdString(patch.first).replace("[D] ", "");
|
||||
const auto name =
|
||||
QString::fromStdString(patch.first).replace(QStringLiteral("[D] "), QString{});
|
||||
|
||||
auto* const first_item = new QStandardItem;
|
||||
first_item->setText(name);
|
||||
first_item->setCheckable(true);
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ ConfigureProfileManager ::ConfigureProfileManager(QWidget* parent)
|
||||
tree_view->setContextMenuPolicy(Qt::NoContextMenu);
|
||||
|
||||
item_model->insertColumns(0, 1);
|
||||
item_model->setHeaderData(0, Qt::Horizontal, "Users");
|
||||
item_model->setHeaderData(0, Qt::Horizontal, tr("Users"));
|
||||
|
||||
// We must register all custom types with the Qt Automoc system so that we are able to use it
|
||||
// with signals/slots. In this case, QList falls under the umbrells of custom types.
|
||||
|
||||
@@ -66,8 +66,9 @@ void ConfigureSystem::setConfiguration() {
|
||||
ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.has_value());
|
||||
ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.has_value());
|
||||
|
||||
const auto rng_seed =
|
||||
QString("%1").arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'}).toUpper();
|
||||
const auto rng_seed = QStringLiteral("%1")
|
||||
.arg(Settings::values.rng_seed.value_or(0), 8, 16, QLatin1Char{'0'})
|
||||
.toUpper();
|
||||
ui->rng_seed_edit->setText(rng_seed);
|
||||
|
||||
ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value());
|
||||
|
||||
@@ -78,12 +78,16 @@ void ConfigureWeb::RefreshTelemetryID() {
|
||||
void ConfigureWeb::OnLoginChanged() {
|
||||
if (ui->edit_username->text().isEmpty() && ui->edit_token->text().isEmpty()) {
|
||||
user_verified = true;
|
||||
ui->label_username_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
|
||||
ui->label_token_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
|
||||
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
} else {
|
||||
user_verified = false;
|
||||
ui->label_username_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
|
||||
ui->label_token_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
|
||||
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +105,15 @@ void ConfigureWeb::OnLoginVerified() {
|
||||
ui->button_verify_login->setText(tr("Verify"));
|
||||
if (verify_watcher.result()) {
|
||||
user_verified = true;
|
||||
ui->label_username_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
|
||||
ui->label_token_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16));
|
||||
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
} else {
|
||||
ui->label_username_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
|
||||
ui->label_token_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16));
|
||||
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
|
||||
ui->label_username_verified->setPixmap(pixmap);
|
||||
ui->label_token_verified->setPixmap(pixmap);
|
||||
|
||||
QMessageBox::critical(
|
||||
this, tr("Verification failed"),
|
||||
tr("Verification failed. Check that you have entered your username and token "
|
||||
|
||||
@@ -135,7 +135,7 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(
|
||||
std::shared_ptr<Tegra::DebugContext> debug_context, QWidget* parent)
|
||||
: QDockWidget(tr("Maxwell Breakpoints"), parent), Tegra::DebugContext::BreakPointObserver(
|
||||
debug_context) {
|
||||
setObjectName("TegraBreakPointsWidget");
|
||||
setObjectName(QStringLiteral("TegraBreakPointsWidget"));
|
||||
|
||||
status_text = new QLabel(tr("Emulation running"));
|
||||
resume_button = new QPushButton(tr("Resume"));
|
||||
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
#endif
|
||||
|
||||
MicroProfileDialog::MicroProfileDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) {
|
||||
setObjectName("MicroProfile");
|
||||
setObjectName(QStringLiteral("MicroProfile"));
|
||||
setWindowTitle(tr("MicroProfile"));
|
||||
resize(1000, 600);
|
||||
// Remove the "?" button from the titlebar and enable the maximize button
|
||||
@@ -191,7 +191,7 @@ void MicroProfileDrawText(int x, int y, u32 hex_color, const char* text, u32 tex
|
||||
for (u32 i = 0; i < text_length; ++i) {
|
||||
// Position the text baseline 1 pixel above the bottom of the text cell, this gives nice
|
||||
// vertical alignment of text for a wide range of tested fonts.
|
||||
mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QChar(text[i]));
|
||||
mp_painter->drawText(x, y + MICROPROFILE_TEXT_HEIGHT - 2, QString{QLatin1Char{text[i]}});
|
||||
x += MICROPROFILE_TEXT_WIDTH + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,19 +91,19 @@ WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address, const Kernel::HandleTa
|
||||
WaitTreeMutexInfo::~WaitTreeMutexInfo() = default;
|
||||
|
||||
QString WaitTreeMutexInfo::GetText() const {
|
||||
return tr("waiting for mutex 0x%1").arg(mutex_address, 16, 16, QLatin1Char('0'));
|
||||
return tr("waiting for mutex 0x%1").arg(mutex_address, 16, 16, QLatin1Char{'0'});
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() const {
|
||||
const bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0;
|
||||
|
||||
std::vector<std::unique_ptr<WaitTreeItem>> list;
|
||||
|
||||
bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0;
|
||||
|
||||
list.push_back(std::make_unique<WaitTreeText>(tr("has waiters: %1").arg(has_waiters)));
|
||||
list.push_back(std::make_unique<WaitTreeText>(
|
||||
tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char('0'))));
|
||||
if (owner != nullptr)
|
||||
tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char{'0'})));
|
||||
if (owner != nullptr) {
|
||||
list.push_back(std::make_unique<WaitTreeThread>(*owner));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -121,11 +121,14 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
|
||||
u64 base_pointer = thread.GetContext().cpu_registers[BaseRegister];
|
||||
|
||||
while (base_pointer != 0) {
|
||||
u64 lr = Memory::Read64(base_pointer + sizeof(u64));
|
||||
if (lr == 0)
|
||||
const u64 lr = Memory::Read64(base_pointer + sizeof(u64));
|
||||
if (lr == 0) {
|
||||
break;
|
||||
list.push_back(
|
||||
std::make_unique<WaitTreeText>(tr("0x%1").arg(lr - sizeof(u32), 16, 16, QChar('0'))));
|
||||
}
|
||||
|
||||
list.push_back(std::make_unique<WaitTreeText>(
|
||||
tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'})));
|
||||
|
||||
base_pointer = Memory::Read64(base_pointer);
|
||||
}
|
||||
|
||||
@@ -174,10 +177,10 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() con
|
||||
|
||||
QString WaitTreeWaitObject::GetResetTypeQString(Kernel::ResetType reset_type) {
|
||||
switch (reset_type) {
|
||||
case Kernel::ResetType::OneShot:
|
||||
return tr("one shot");
|
||||
case Kernel::ResetType::Sticky:
|
||||
return tr("sticky");
|
||||
case Kernel::ResetType::Automatic:
|
||||
return tr("automatic reset");
|
||||
case Kernel::ResetType::Manual:
|
||||
return tr("manual reset");
|
||||
}
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
@@ -249,9 +252,9 @@ QString WaitTreeThread::GetText() const {
|
||||
|
||||
const auto& context = thread.GetContext();
|
||||
const QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
|
||||
.arg(context.pc, 8, 16, QLatin1Char('0'))
|
||||
.arg(context.cpu_registers[30], 8, 16, QLatin1Char('0'));
|
||||
return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") ";
|
||||
.arg(context.pc, 8, 16, QLatin1Char{'0'})
|
||||
.arg(context.cpu_registers[30], 8, 16, QLatin1Char{'0'});
|
||||
return QStringLiteral("%1%2 (%3) ").arg(WaitTreeWaitObject::GetText(), pc_info, status);
|
||||
}
|
||||
|
||||
QColor WaitTreeThread::GetColor() const {
|
||||
@@ -424,7 +427,7 @@ void WaitTreeModel::InitItems() {
|
||||
}
|
||||
|
||||
WaitTreeWidget::WaitTreeWidget(QWidget* parent) : QDockWidget(tr("Wait Tree"), parent) {
|
||||
setObjectName("WaitTreeWidget");
|
||||
setObjectName(QStringLiteral("WaitTreeWidget"));
|
||||
view = new QTreeView(this);
|
||||
view->setHeaderHidden(true);
|
||||
setWidget(view);
|
||||
|
||||
@@ -198,11 +198,11 @@ GMainWindow::GMainWindow()
|
||||
|
||||
ConnectMenuEvents();
|
||||
ConnectWidgetEvents();
|
||||
|
||||
LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch,
|
||||
Common::g_scm_desc);
|
||||
UpdateWindowTitle();
|
||||
|
||||
setWindowTitle(QString("yuzu %1| %2-%3")
|
||||
.arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc));
|
||||
show();
|
||||
|
||||
Core::System::GetInstance().SetContentProvider(
|
||||
@@ -936,9 +936,7 @@ void GMainWindow::BootGame(const QString& filename) {
|
||||
title_name = FileUtil::GetFilename(filename.toStdString());
|
||||
}
|
||||
|
||||
setWindowTitle(QString("yuzu %1| %4 | %2-%3")
|
||||
.arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc,
|
||||
QString::fromStdString(title_name)));
|
||||
UpdateWindowTitle(QString::fromStdString(title_name));
|
||||
|
||||
loading_screen->Prepare(Core::System::GetInstance().GetAppLoader());
|
||||
loading_screen->show();
|
||||
@@ -979,8 +977,8 @@ void GMainWindow::ShutdownGame() {
|
||||
loading_screen->Clear();
|
||||
game_list->show();
|
||||
game_list->setFilterFocus();
|
||||
setWindowTitle(QString("yuzu %1| %2-%3")
|
||||
.arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc));
|
||||
|
||||
UpdateWindowTitle();
|
||||
|
||||
// Disable status bar updates
|
||||
status_bar_update_timer.stop();
|
||||
@@ -1767,6 +1765,19 @@ void GMainWindow::OnCaptureScreenshot() {
|
||||
OnStartGame();
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateWindowTitle(const QString& title_name) {
|
||||
const QString full_name = QString::fromUtf8(Common::g_build_fullname);
|
||||
const QString branch_name = QString::fromUtf8(Common::g_scm_branch);
|
||||
const QString description = QString::fromUtf8(Common::g_scm_desc);
|
||||
|
||||
if (title_name.isEmpty()) {
|
||||
setWindowTitle(QStringLiteral("yuzu %1| %2-%3").arg(full_name, branch_name, description));
|
||||
} else {
|
||||
setWindowTitle(QStringLiteral("yuzu %1| %4 | %2-%3")
|
||||
.arg(full_name, branch_name, description, title_name));
|
||||
}
|
||||
}
|
||||
|
||||
void GMainWindow::UpdateStatusBar() {
|
||||
if (emu_thread == nullptr) {
|
||||
status_bar_update_timer.stop();
|
||||
|
||||
@@ -209,6 +209,7 @@ private slots:
|
||||
|
||||
private:
|
||||
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
|
||||
void UpdateWindowTitle(const QString& title_name = {});
|
||||
void UpdateStatusBar();
|
||||
|
||||
Ui::MainWindow ui;
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Copyright 2014 Tony Wasserka
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the owner nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <cstdlib>
|
||||
#include <QLineEdit>
|
||||
#include <QRegExpValidator>
|
||||
#include "common/assert.h"
|
||||
#include "yuzu/util/spinbox.h"
|
||||
|
||||
CSpinBox::CSpinBox(QWidget* parent)
|
||||
: QAbstractSpinBox(parent), min_value(-100), max_value(100), value(0), base(10), num_digits(0) {
|
||||
// TODO: Might be nice to not immediately call the slot.
|
||||
// Think of an address that is being replaced by a different one, in which case a lot
|
||||
// invalid intermediate addresses would be read from during editing.
|
||||
connect(lineEdit(), &QLineEdit::textEdited, this, &CSpinBox::OnEditingFinished);
|
||||
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
void CSpinBox::SetValue(qint64 val) {
|
||||
auto old_value = value;
|
||||
value = std::max(std::min(val, max_value), min_value);
|
||||
|
||||
if (old_value != value) {
|
||||
UpdateText();
|
||||
emit ValueChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
void CSpinBox::SetRange(qint64 min, qint64 max) {
|
||||
min_value = min;
|
||||
max_value = max;
|
||||
|
||||
SetValue(value);
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
void CSpinBox::stepBy(int steps) {
|
||||
auto new_value = value;
|
||||
// Scale number of steps by the currently selected digit
|
||||
// TODO: Move this code elsewhere and enable it.
|
||||
// TODO: Support for num_digits==0, too
|
||||
// TODO: Support base!=16, too
|
||||
// TODO: Make the cursor not jump back to the end of the line...
|
||||
/*if (base == 16 && num_digits > 0) {
|
||||
int digit = num_digits - (lineEdit()->cursorPosition() - prefix.length()) - 1;
|
||||
digit = std::max(0, std::min(digit, num_digits - 1));
|
||||
steps <<= digit * 4;
|
||||
}*/
|
||||
|
||||
// Increment "new_value" by "steps", and perform annoying overflow checks, too.
|
||||
if (steps < 0 && new_value + steps > new_value) {
|
||||
new_value = std::numeric_limits<qint64>::min();
|
||||
} else if (steps > 0 && new_value + steps < new_value) {
|
||||
new_value = std::numeric_limits<qint64>::max();
|
||||
} else {
|
||||
new_value += steps;
|
||||
}
|
||||
|
||||
SetValue(new_value);
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
QAbstractSpinBox::StepEnabled CSpinBox::stepEnabled() const {
|
||||
StepEnabled ret = StepNone;
|
||||
|
||||
if (value > min_value)
|
||||
ret |= StepDownEnabled;
|
||||
|
||||
if (value < max_value)
|
||||
ret |= StepUpEnabled;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CSpinBox::SetBase(int base) {
|
||||
this->base = base;
|
||||
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
void CSpinBox::SetNumDigits(int num_digits) {
|
||||
this->num_digits = num_digits;
|
||||
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
void CSpinBox::SetPrefix(const QString& prefix) {
|
||||
this->prefix = prefix;
|
||||
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
void CSpinBox::SetSuffix(const QString& suffix) {
|
||||
this->suffix = suffix;
|
||||
|
||||
UpdateText();
|
||||
}
|
||||
|
||||
static QString StringToInputMask(const QString& input) {
|
||||
QString mask = input;
|
||||
|
||||
// ... replace any special characters by their escaped counterparts ...
|
||||
mask.replace("\\", "\\\\");
|
||||
mask.replace("A", "\\A");
|
||||
mask.replace("a", "\\a");
|
||||
mask.replace("N", "\\N");
|
||||
mask.replace("n", "\\n");
|
||||
mask.replace("X", "\\X");
|
||||
mask.replace("x", "\\x");
|
||||
mask.replace("9", "\\9");
|
||||
mask.replace("0", "\\0");
|
||||
mask.replace("D", "\\D");
|
||||
mask.replace("d", "\\d");
|
||||
mask.replace("#", "\\#");
|
||||
mask.replace("H", "\\H");
|
||||
mask.replace("h", "\\h");
|
||||
mask.replace("B", "\\B");
|
||||
mask.replace("b", "\\b");
|
||||
mask.replace(">", "\\>");
|
||||
mask.replace("<", "\\<");
|
||||
mask.replace("!", "\\!");
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
void CSpinBox::UpdateText() {
|
||||
// If a fixed number of digits is used, we put the line edit in insertion mode by setting an
|
||||
// input mask.
|
||||
QString mask;
|
||||
if (num_digits != 0) {
|
||||
mask += StringToInputMask(prefix);
|
||||
|
||||
// For base 10 and negative range, demand a single sign character
|
||||
if (HasSign())
|
||||
mask += "X"; // identified as "-" or "+" in the validator
|
||||
|
||||
// Uppercase digits greater than 9.
|
||||
mask += ">";
|
||||
|
||||
// Match num_digits digits
|
||||
// Digits irrelevant to the chosen number base are filtered in the validator
|
||||
mask += QString("H").repeated(std::max(num_digits, 1));
|
||||
|
||||
// Switch off case conversion
|
||||
mask += "!";
|
||||
|
||||
mask += StringToInputMask(suffix);
|
||||
}
|
||||
lineEdit()->setInputMask(mask);
|
||||
|
||||
// Set new text without changing the cursor position. This will cause the cursor to briefly
|
||||
// appear at the end of the line and then to jump back to its original position. That's
|
||||
// a bit ugly, but better than having setText() move the cursor permanently all the time.
|
||||
int cursor_position = lineEdit()->cursorPosition();
|
||||
lineEdit()->setText(TextFromValue());
|
||||
lineEdit()->setCursorPosition(cursor_position);
|
||||
}
|
||||
|
||||
QString CSpinBox::TextFromValue() {
|
||||
return prefix + QString(HasSign() ? ((value < 0) ? "-" : "+") : "") +
|
||||
QString("%1").arg(std::abs(value), num_digits, base, QLatin1Char('0')).toUpper() +
|
||||
suffix;
|
||||
}
|
||||
|
||||
qint64 CSpinBox::ValueFromText() {
|
||||
unsigned strpos = prefix.length();
|
||||
|
||||
QString num_string = text().mid(strpos, text().length() - strpos - suffix.length());
|
||||
return num_string.toLongLong(nullptr, base);
|
||||
}
|
||||
|
||||
bool CSpinBox::HasSign() const {
|
||||
return base == 10 && min_value < 0;
|
||||
}
|
||||
|
||||
void CSpinBox::OnEditingFinished() {
|
||||
// Only update for valid input
|
||||
QString input = lineEdit()->text();
|
||||
int pos = 0;
|
||||
if (QValidator::Acceptable == validate(input, pos))
|
||||
SetValue(ValueFromText());
|
||||
}
|
||||
|
||||
QValidator::State CSpinBox::validate(QString& input, int& pos) const {
|
||||
if (!prefix.isEmpty() && input.left(prefix.length()) != prefix)
|
||||
return QValidator::Invalid;
|
||||
|
||||
int strpos = prefix.length();
|
||||
|
||||
// Empty "numbers" allowed as intermediate values
|
||||
if (strpos >= input.length() - HasSign() - suffix.length())
|
||||
return QValidator::Intermediate;
|
||||
|
||||
DEBUG_ASSERT(base <= 10 || base == 16);
|
||||
QString regexp;
|
||||
|
||||
// Demand sign character for negative ranges
|
||||
if (HasSign())
|
||||
regexp += "[+\\-]";
|
||||
|
||||
// Match digits corresponding to the chosen number base.
|
||||
regexp += QString("[0-%1").arg(std::min(base, 9));
|
||||
if (base == 16) {
|
||||
regexp += "a-fA-F";
|
||||
}
|
||||
regexp += "]";
|
||||
|
||||
// Specify number of digits
|
||||
if (num_digits > 0) {
|
||||
regexp += QString("{%1}").arg(num_digits);
|
||||
} else {
|
||||
regexp += "+";
|
||||
}
|
||||
|
||||
// Match string
|
||||
QRegExp num_regexp(regexp);
|
||||
int num_pos = strpos;
|
||||
QString sub_input = input.mid(strpos, input.length() - strpos - suffix.length());
|
||||
|
||||
if (!num_regexp.exactMatch(sub_input) && num_regexp.matchedLength() == 0)
|
||||
return QValidator::Invalid;
|
||||
|
||||
sub_input = sub_input.left(num_regexp.matchedLength());
|
||||
bool ok;
|
||||
qint64 val = sub_input.toLongLong(&ok, base);
|
||||
|
||||
if (!ok)
|
||||
return QValidator::Invalid;
|
||||
|
||||
// Outside boundaries => don't accept
|
||||
if (val < min_value || val > max_value)
|
||||
return QValidator::Invalid;
|
||||
|
||||
// Make sure we are actually at the end of this string...
|
||||
strpos += num_regexp.matchedLength();
|
||||
|
||||
if (!suffix.isEmpty() && input.mid(strpos) != suffix) {
|
||||
return QValidator::Invalid;
|
||||
} else {
|
||||
strpos += suffix.length();
|
||||
}
|
||||
|
||||
if (strpos != input.length())
|
||||
return QValidator::Invalid;
|
||||
|
||||
// At this point we can say for sure that the input is fine. Let's fix it up a bit though
|
||||
input.replace(num_pos, sub_input.length(), sub_input.toUpper());
|
||||
|
||||
return QValidator::Acceptable;
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Copyright 2014 Tony Wasserka
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the owner nor the names of its contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractSpinBox>
|
||||
#include <QtGlobal>
|
||||
|
||||
class QVariant;
|
||||
|
||||
/**
|
||||
* A custom spin box widget with enhanced functionality over Qt's QSpinBox
|
||||
*/
|
||||
class CSpinBox : public QAbstractSpinBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CSpinBox(QWidget* parent = nullptr);
|
||||
|
||||
void stepBy(int steps) override;
|
||||
StepEnabled stepEnabled() const override;
|
||||
|
||||
void SetValue(qint64 val);
|
||||
|
||||
void SetRange(qint64 min, qint64 max);
|
||||
|
||||
void SetBase(int base);
|
||||
|
||||
void SetPrefix(const QString& prefix);
|
||||
void SetSuffix(const QString& suffix);
|
||||
|
||||
void SetNumDigits(int num_digits);
|
||||
|
||||
QValidator::State validate(QString& input, int& pos) const override;
|
||||
|
||||
signals:
|
||||
void ValueChanged(qint64 val);
|
||||
|
||||
private slots:
|
||||
void OnEditingFinished();
|
||||
|
||||
private:
|
||||
void UpdateText();
|
||||
|
||||
bool HasSign() const;
|
||||
|
||||
QString TextFromValue();
|
||||
qint64 ValueFromText();
|
||||
|
||||
qint64 min_value, max_value;
|
||||
|
||||
qint64 value;
|
||||
|
||||
QString prefix, suffix;
|
||||
|
||||
int base;
|
||||
|
||||
int num_digits;
|
||||
};
|
||||
@@ -176,9 +176,13 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
||||
|
||||
SDL_SetMainReady();
|
||||
|
||||
const SDL_GLprofile profile = Settings::values.use_compatibility_profile
|
||||
? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY
|
||||
: SDL_GL_CONTEXT_PROFILE_CORE;
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
|
||||
@@ -222,6 +222,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL");
|
||||
|
||||
emu_window->MakeCurrent();
|
||||
system.Renderer().Rasterizer().LoadDiskResources();
|
||||
|
||||
while (emu_window->IsOpen()) {
|
||||
|
||||
Reference in New Issue
Block a user