Compare commits
8 Commits
d391171809
...
b3d46ab6e8
Author | SHA1 | Date |
---|---|---|
Radosław Gliński | b3d46ab6e8 | |
Gliniak | 0474053931 | |
Gliniak | 85695692a7 | |
Marco Rodolfi | 55bbb28a80 | |
The-Little-Wolf | 4d7b30e844 | |
Adrian | ae23222ba8 | |
Adrian | d99d053408 | |
Gliniak | 22e5216d48 |
|
@ -31,7 +31,6 @@
|
|||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/emulator.h"
|
||||
#include "xenia/gpu/command_processor.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_command_processor.h"
|
||||
#include "xenia/gpu/graphics_system.h"
|
||||
#include "xenia/hid/input_system.h"
|
||||
#include "xenia/kernel/xam/profile_manager.h"
|
||||
|
@ -58,7 +57,9 @@ DECLARE_bool(guide_button);
|
|||
|
||||
DECLARE_bool(clear_memory_page_state);
|
||||
|
||||
DECLARE_bool(d3d12_readback_resolve);
|
||||
DECLARE_bool(readback_resolve);
|
||||
|
||||
DECLARE_bool(readback_memexport);
|
||||
|
||||
DEFINE_bool(fullscreen, false, "Whether to launch the emulator in fullscreen.",
|
||||
"Display");
|
||||
|
@ -1674,7 +1675,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
|||
}
|
||||
} break;
|
||||
case ButtonFunctions::ClearMemoryPageState:
|
||||
ToggleGPUSetting(gpu_cvar::ClearMemoryPageState);
|
||||
ToggleGPUSetting(GPUSetting::ClearMemoryPageState);
|
||||
|
||||
// Assume the user wants ClearCaches as well
|
||||
if (cvars::clear_memory_page_state) {
|
||||
|
@ -1689,10 +1690,10 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
|||
xe::threading::Sleep(delay);
|
||||
break;
|
||||
case ButtonFunctions::ReadbackResolve:
|
||||
ToggleGPUSetting(gpu_cvar::ReadbackResolve);
|
||||
ToggleGPUSetting(GPUSetting::ReadbackResolve);
|
||||
|
||||
notificationTitle = "Toggle Readback Resolve";
|
||||
notificationDesc = cvars::d3d12_readback_resolve ? "Enabled" : "Disabled";
|
||||
notificationDesc = cvars::readback_resolve ? "Enabled" : "Disabled";
|
||||
|
||||
// Extra Sleep
|
||||
xe::threading::Sleep(delay);
|
||||
|
@ -1862,15 +1863,17 @@ void EmulatorWindow::GamepadHotKeys() {
|
|||
}
|
||||
}
|
||||
|
||||
void EmulatorWindow::ToggleGPUSetting(gpu_cvar value) {
|
||||
switch (value) {
|
||||
case gpu_cvar::ClearMemoryPageState:
|
||||
CommonSaveGPUSetting(CommonGPUSetting::ClearMemoryPageState,
|
||||
!cvars::clear_memory_page_state);
|
||||
void EmulatorWindow::ToggleGPUSetting(gpu::GPUSetting setting) {
|
||||
switch (setting) {
|
||||
case GPUSetting::ClearMemoryPageState:
|
||||
SaveGPUSetting(GPUSetting::ClearMemoryPageState,
|
||||
!cvars::clear_memory_page_state);
|
||||
break;
|
||||
case gpu_cvar::ReadbackResolve:
|
||||
D3D12SaveGPUSetting(D3D12GPUSetting::ReadbackResolve,
|
||||
!cvars::d3d12_readback_resolve);
|
||||
case GPUSetting::ReadbackResolve:
|
||||
SaveGPUSetting(GPUSetting::ReadbackResolve, !cvars::readback_resolve);
|
||||
break;
|
||||
case GPUSetting::ReadbackMemexport:
|
||||
SaveGPUSetting(GPUSetting::ReadbackMemexport, !cvars::readback_memexport);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1915,7 +1918,7 @@ void EmulatorWindow::DisplayHotKeysConfig() {
|
|||
msg += "\n";
|
||||
|
||||
msg += "Readback Resolve: " +
|
||||
xe::string_util::BoolToString(cvars::d3d12_readback_resolve);
|
||||
xe::string_util::BoolToString(cvars::readback_resolve);
|
||||
msg += "\n";
|
||||
|
||||
msg += "Clear Memory Page State: " +
|
||||
|
|
|
@ -112,11 +112,6 @@ class EmulatorWindow {
|
|||
Unknown
|
||||
};
|
||||
|
||||
enum class gpu_cvar {
|
||||
ClearMemoryPageState,
|
||||
ReadbackResolve,
|
||||
};
|
||||
|
||||
class ControllerHotKey {
|
||||
public:
|
||||
// If true the hotkey can be activated while a title is running, otherwise
|
||||
|
@ -235,7 +230,7 @@ class EmulatorWindow {
|
|||
void VibrateController(xe::hid::InputSystem* input_sys, uint32_t user_index,
|
||||
bool vibrate = true);
|
||||
void GamepadHotKeys();
|
||||
void ToggleGPUSetting(gpu_cvar index);
|
||||
void ToggleGPUSetting(gpu::GPUSetting setting);
|
||||
void DisplayHotKeysConfig();
|
||||
|
||||
static std::string CanonicalizeFileExtension(
|
||||
|
|
|
@ -402,6 +402,7 @@ class Timer : public WaitHandle {
|
|||
virtual bool Cancel() = 0;
|
||||
};
|
||||
|
||||
#if XE_PLATFORM_WIN32
|
||||
struct ThreadPriority {
|
||||
static const int32_t kLowest = -2;
|
||||
static const int32_t kBelowNormal = -1;
|
||||
|
@ -409,6 +410,15 @@ struct ThreadPriority {
|
|||
static const int32_t kAboveNormal = 1;
|
||||
static const int32_t kHighest = 2;
|
||||
};
|
||||
#else
|
||||
struct ThreadPriority {
|
||||
static const int32_t kLowest = 1;
|
||||
static const int32_t kBelowNormal = 8;
|
||||
static const int32_t kNormal = 16;
|
||||
static const int32_t kAboveNormal = 24;
|
||||
static const int32_t kHighest = 32;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Models a Win32-like thread object.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms682453(v=vs.85).aspx
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#if XE_PLATFORM_ANDROID
|
||||
#include <dlfcn.h>
|
||||
|
||||
|
@ -660,8 +662,18 @@ class PosixCondition<Thread> : public PosixConditionBase {
|
|||
WaitStarted();
|
||||
sched_param param{};
|
||||
param.sched_priority = new_priority;
|
||||
if (pthread_setschedparam(thread_, SCHED_FIFO, ¶m) != 0)
|
||||
assert_always();
|
||||
int res = pthread_setschedparam(thread_, SCHED_FIFO, ¶m);
|
||||
if (res != 0) {
|
||||
switch (res) {
|
||||
case EPERM:
|
||||
XELOGW("Permission denied while setting priority");
|
||||
break;
|
||||
case EINVAL:
|
||||
assert_always();
|
||||
default:
|
||||
XELOGW("Unknown error while setting priority");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QueueUserCallback(std::function<void()> callback) {
|
||||
|
|
|
@ -1372,6 +1372,12 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
|||
return X_STATUS_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!module->is_executable()) {
|
||||
kernel_state_->UnloadUserModule(module, false);
|
||||
XELOGE("Failed to load user module {}", path);
|
||||
return X_STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
X_RESULT result = kernel_state_->ApplyTitleUpdate(module);
|
||||
if (XFAILED(result)) {
|
||||
XELOGE("Failed to apply title update! Cannot run module {}", path);
|
||||
|
|
|
@ -50,17 +50,52 @@ DEFINE_bool(clear_memory_page_state, false,
|
|||
"for 'Team Ninja' Games to fix missing character models)",
|
||||
"GPU");
|
||||
|
||||
DEFINE_bool(
|
||||
readback_resolve, false,
|
||||
"[D3D12 Only] Read render-to-texture results on the CPU. This may be "
|
||||
"needed in some games, for instance, for screenshots in saved games, but "
|
||||
"causes mid-frame synchronization, so it has a huge performance impact.",
|
||||
"GPU");
|
||||
|
||||
DEFINE_bool(
|
||||
readback_memexport, false,
|
||||
"[D3D12 Only] Read data written by memory export in shaders on the CPU. "
|
||||
"This may be needed in some games (but many only access exported data on "
|
||||
"the GPU, and this flag isn't needed to handle such behavior), but causes "
|
||||
"mid-frame synchronization, so it has a huge performance impact.",
|
||||
"GPU");
|
||||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
void CommonSaveGPUSetting(CommonGPUSetting setting, uint64_t value) {
|
||||
// This should be written completely differently with support for different
|
||||
// types.
|
||||
void SaveGPUSetting(GPUSetting setting, uint64_t value) {
|
||||
switch (setting) {
|
||||
case CommonGPUSetting::ClearMemoryPageState:
|
||||
OVERRIDE_bool(clear_memory_page_state, (bool)value);
|
||||
case GPUSetting::ClearMemoryPageState:
|
||||
OVERRIDE_bool(clear_memory_page_state, static_cast<bool>(value));
|
||||
break;
|
||||
case GPUSetting::ReadbackResolve:
|
||||
OVERRIDE_bool(readback_resolve, static_cast<bool>(value));
|
||||
break;
|
||||
case GPUSetting::ReadbackMemexport:
|
||||
OVERRIDE_bool(readback_memexport, static_cast<bool>(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool GetGPUSetting(GPUSetting setting) {
|
||||
switch (setting) {
|
||||
case GPUSetting::ClearMemoryPageState:
|
||||
return cvars::clear_memory_page_state;
|
||||
case GPUSetting::ReadbackResolve:
|
||||
return cvars::readback_resolve;
|
||||
case GPUSetting::ReadbackMemexport:
|
||||
return cvars::readback_memexport;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
using namespace xe::gpu::xenos;
|
||||
|
||||
CommandProcessor::CommandProcessor(GraphicsSystem* graphics_system,
|
||||
|
|
|
@ -33,11 +33,14 @@ class ByteStream;
|
|||
|
||||
namespace gpu {
|
||||
|
||||
enum class CommonGPUSetting {
|
||||
enum class GPUSetting {
|
||||
ClearMemoryPageState,
|
||||
ReadbackResolve,
|
||||
ReadbackMemexport
|
||||
};
|
||||
|
||||
void CommonSaveGPUSetting(CommonGPUSetting setting, uint64_t value);
|
||||
void SaveGPUSetting(GPUSetting setting, uint64_t value);
|
||||
bool GetGPUSetting(GPUSetting setting);
|
||||
|
||||
class GraphicsSystem;
|
||||
class Shader;
|
||||
|
|
|
@ -32,19 +32,7 @@ DEFINE_bool(d3d12_bindless, true,
|
|||
"Use bindless resources where available - may improve performance, "
|
||||
"but may make debugging more complicated.",
|
||||
"D3D12");
|
||||
DEFINE_bool(d3d12_readback_memexport, false,
|
||||
"Read data written by memory export in shaders on the CPU. This "
|
||||
"may be needed in some games (but many only access exported data "
|
||||
"on the GPU, and this flag isn't needed to handle such behavior), "
|
||||
"but causes mid-frame synchronization, so it has a huge "
|
||||
"performance impact.",
|
||||
"D3D12");
|
||||
DEFINE_bool(d3d12_readback_resolve, false,
|
||||
"Read render-to-texture results on the CPU. This may be needed in "
|
||||
"some games, for instance, for screenshots in saved games, but "
|
||||
"causes mid-frame synchronization, so it has a huge performance "
|
||||
"impact.",
|
||||
"D3D12");
|
||||
|
||||
DEFINE_bool(d3d12_submit_on_primary_buffer_end, true,
|
||||
"Submit the command list when a PM4 primary buffer ends if it's "
|
||||
"possible to submit immediately to try to reduce frame latency.",
|
||||
|
@ -54,15 +42,6 @@ DECLARE_bool(clear_memory_page_state);
|
|||
|
||||
namespace xe {
|
||||
namespace gpu {
|
||||
|
||||
void D3D12SaveGPUSetting(D3D12GPUSetting setting, uint64_t value) {
|
||||
switch (setting) {
|
||||
case D3D12GPUSetting::ReadbackResolve:
|
||||
OVERRIDE_bool(d3d12_readback_resolve, (bool)value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
namespace d3d12 {
|
||||
|
||||
// Generated with `xb buildshaders`.
|
||||
|
@ -3011,7 +2990,7 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
|||
memexport_range.base_address_dwords << 2, memexport_range.size_bytes,
|
||||
false);
|
||||
}
|
||||
if (cvars::d3d12_readback_memexport) {
|
||||
if (GetGPUSetting(GPUSetting::ReadbackResolve)) {
|
||||
// Read the exported data on the CPU.
|
||||
uint32_t memexport_total_size = 0;
|
||||
for (const draw_util::MemExportRange& memexport_range :
|
||||
|
@ -3091,7 +3070,7 @@ bool D3D12CommandProcessor::IssueCopy() {
|
|||
if (!BeginSubmission(true)) {
|
||||
return false;
|
||||
}
|
||||
if (!cvars::d3d12_readback_resolve) {
|
||||
if (!GetGPUSetting(GPUSetting::ReadbackResolve)) {
|
||||
uint32_t written_address, written_length;
|
||||
return render_target_cache_->Resolve(*memory_, *shared_memory_,
|
||||
*texture_cache_, written_address,
|
||||
|
|
|
@ -799,6 +799,18 @@ dword_result_t XamUserGetUserFlagsFromXUID_entry(qword_t xuid) {
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamUserGetUserFlagsFromXUID, kUserProfiles, kImplemented);
|
||||
|
||||
dword_result_t XamUserGetOnlineLanguageFromXUID_entry(qword_t xuid) {
|
||||
/* Notes:
|
||||
- Calls XamUserGetUserFlagsFromXUID and returns (ulonglong)(cached_flag <<
|
||||
0x20) >> 0x39 & 0x1f;
|
||||
- XamUserGetMembershipTierFromXUID and XamUserGetOnlineCountryFromXUID also
|
||||
call it
|
||||
- Removed in metro
|
||||
*/
|
||||
return cvars::user_language;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamUserGetOnlineLanguageFromXUID, kUserProfiles, kStub);
|
||||
|
||||
constexpr uint8_t kStatsMaxAmount = 64;
|
||||
|
||||
struct X_STATS_DETAILS {
|
||||
|
|
|
@ -763,6 +763,12 @@ X_STATUS XThread::Delay(uint32_t processor_mode, uint32_t alertable,
|
|||
timeout_ms = uint32_t(-timeout_ticks / 10000); // Ticks -> MS
|
||||
} else {
|
||||
timeout_ms = 0;
|
||||
// TODO(Gliniak): Check how it works, but it seems outright wrong.
|
||||
// However some titles like to change priority then go to sleep with timeout
|
||||
// 0.
|
||||
if (priority_ <= xe::threading::ThreadPriority::kNormal) {
|
||||
timeout_ms = 1;
|
||||
}
|
||||
}
|
||||
timeout_ms = Clock::ScaleGuestDurationMillis(timeout_ms);
|
||||
if (alertable) {
|
||||
|
|
|
@ -48,8 +48,8 @@ void PluginLoader::LoadConfigs() {
|
|||
xe::filesystem::FilterByName(dir_files, std::regex("[A-Fa-f0-9]{8}"));
|
||||
|
||||
for (const auto& entry : dir_files) {
|
||||
const uint32_t title_id =
|
||||
std::stoi(entry.name.filename().string(), nullptr, 16);
|
||||
const uint32_t title_id = string_util::from_string<uint32_t>(
|
||||
entry.name.filename().string(), true);
|
||||
|
||||
LoadTitleConfig(title_id);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue