[GPU] Add FXAA post-processing [UI] Add FidelityFX FSR and CAS post-processing [UI] Add blue noise dithering from 10bpc to 8bpc [GPU] Apply the DC PWL gamma ramp closer to the spec, supporting fully white color [UI] Allow the GPU CP thread to present on the host directly, bypassing the UI thread OS paint event [UI] Allow variable refresh rate (or tearing) [UI] Present the newest frame (restart) on DXGI [UI] Replace GraphicsContext with a far more advanced Presenter with more coherent surface connection and UI overlay state management [UI] Connect presentation to windows via the Surface class, not native window handles [Vulkan] Switch to simpler Vulkan setup with no instance/device separation due to interdependencies and to pass fewer objects around [Vulkan] Lower the minimum required Vulkan version to 1.0 [UI/GPU] Various cleanup, mainly ComPtr usage [UI] Support per-monitor DPI awareness v2 on Windows [UI] DPI-scale Dear ImGui [UI] Replace the remaining non-detachable window delegates with unified window event and input listeners [UI] Allow listeners to safely destroy or close the window, and to register/unregister listeners without use-after-free and the ABA problem [UI] Explicit Z ordering of input listeners and UI overlays, top-down for input, bottom-up for drawing [UI] Add explicit window lifecycle phases [UI] Replace Window virtual functions with explicit desired state, its application, actual state, its feedback [UI] GTK: Apply the initial size to the drawing area [UI] Limit internal UI frame rate to that of the monitor [UI] Hide the cursor using a timer instead of polling due to no repeated UI thread paints with GPU CP thread presentation, and only within the window
162 lines
5.1 KiB
C++
162 lines
5.1 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2022 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include "xenia/base/debugging.h"
|
|
#include "xenia/base/logging.h"
|
|
#include "xenia/kernel/kernel_state.h"
|
|
#include "xenia/kernel/util/shim_utils.h"
|
|
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
|
|
#include "xenia/kernel/xthread.h"
|
|
#include "xenia/xbox.h"
|
|
|
|
namespace xe {
|
|
namespace kernel {
|
|
namespace xboxkrnl {
|
|
|
|
void DbgBreakPoint_entry() { xe::debugging::Break(); }
|
|
DECLARE_XBOXKRNL_EXPORT2(DbgBreakPoint, kDebug, kStub, kImportant);
|
|
|
|
// https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
|
typedef struct {
|
|
xe::be<uint32_t> type;
|
|
xe::be<uint32_t> name_ptr;
|
|
xe::be<uint32_t> thread_id;
|
|
xe::be<uint32_t> flags;
|
|
} X_THREADNAME_INFO;
|
|
static_assert_size(X_THREADNAME_INFO, 0x10);
|
|
|
|
void HandleSetThreadName(pointer_t<X_EXCEPTION_RECORD> record) {
|
|
// SetThreadName. FFS.
|
|
// https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
|
|
|
// TODO(benvanik): check record->number_parameters to make sure it's a
|
|
// correct size.
|
|
auto thread_info =
|
|
reinterpret_cast<X_THREADNAME_INFO*>(&record->exception_information[0]);
|
|
|
|
assert_true(thread_info->type == 0x1000);
|
|
|
|
if (!thread_info->name_ptr) {
|
|
XELOGD("SetThreadName called with null name_ptr");
|
|
return;
|
|
}
|
|
|
|
// 4D5307D6 (and its demo) has a bug where it ends up passing freed memory for
|
|
// the name, so at the point of SetThreadName it's filled with junk.
|
|
|
|
// TODO(gibbed): cvar for thread name encoding for conversion, some games use
|
|
// SJIS and there's no way to automatically know this.
|
|
auto name = std::string(
|
|
kernel_memory()->TranslateVirtual<const char*>(thread_info->name_ptr));
|
|
std::replace_if(
|
|
name.begin(), name.end(), [](auto c) { return c < 32 || c > 127; }, '?');
|
|
|
|
object_ref<XThread> thread;
|
|
if (thread_info->thread_id == -1) {
|
|
// Current thread.
|
|
thread = retain_object(XThread::GetCurrentThread());
|
|
} else {
|
|
// Lookup thread by ID.
|
|
thread = kernel_state()->GetThreadByID(thread_info->thread_id);
|
|
}
|
|
|
|
if (thread) {
|
|
XELOGD("SetThreadName({}, {})", thread->thread_id(), name);
|
|
thread->set_name(name);
|
|
}
|
|
|
|
// TODO(benvanik): unwinding required here?
|
|
}
|
|
|
|
typedef struct {
|
|
xe::be<int32_t> mdisp;
|
|
xe::be<int32_t> pdisp;
|
|
xe::be<int32_t> vdisp;
|
|
} x_PMD;
|
|
|
|
typedef struct {
|
|
xe::be<uint32_t> properties;
|
|
xe::be<uint32_t> type_ptr;
|
|
x_PMD this_displacement;
|
|
xe::be<int32_t> size_or_offset;
|
|
xe::be<uint32_t> copy_function_ptr;
|
|
} x_s__CatchableType;
|
|
|
|
typedef struct {
|
|
xe::be<int32_t> number_catchable_types;
|
|
xe::be<uint32_t> catchable_type_ptrs[1];
|
|
} x_s__CatchableTypeArray;
|
|
|
|
typedef struct {
|
|
xe::be<uint32_t> attributes;
|
|
xe::be<uint32_t> unwind_ptr;
|
|
xe::be<uint32_t> forward_compat_ptr;
|
|
xe::be<uint32_t> catchable_type_array_ptr;
|
|
} x_s__ThrowInfo;
|
|
|
|
void HandleCppException(pointer_t<X_EXCEPTION_RECORD> record) {
|
|
// C++ exception.
|
|
// https://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx
|
|
// http://www.drdobbs.com/visual-c-exception-handling-instrumentat/184416600
|
|
// http://www.openrce.org/articles/full_view/21
|
|
|
|
assert_true(record->number_parameters == 3);
|
|
assert_true(record->exception_information[0] == 0x19930520);
|
|
|
|
auto thrown_ptr = record->exception_information[1];
|
|
auto thrown = kernel_memory()->TranslateVirtual(thrown_ptr);
|
|
auto vftable_ptr = *reinterpret_cast<xe::be<uint32_t>*>(thrown);
|
|
|
|
auto throw_info_ptr = record->exception_information[2];
|
|
auto throw_info =
|
|
kernel_memory()->TranslateVirtual<x_s__ThrowInfo*>(throw_info_ptr);
|
|
auto catchable_types =
|
|
kernel_memory()->TranslateVirtual<x_s__CatchableTypeArray*>(
|
|
throw_info->catchable_type_array_ptr);
|
|
|
|
xe::debugging::Break();
|
|
}
|
|
|
|
void RtlRaiseException_entry(pointer_t<X_EXCEPTION_RECORD> record) {
|
|
switch (record->code) {
|
|
case 0x406D1388: {
|
|
HandleSetThreadName(record);
|
|
return;
|
|
}
|
|
case 0xE06D7363: {
|
|
HandleCppException(record);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// TODO(benvanik): unwinding.
|
|
// This is going to suck.
|
|
xe::debugging::Break();
|
|
}
|
|
DECLARE_XBOXKRNL_EXPORT2(RtlRaiseException, kDebug, kStub, kImportant);
|
|
|
|
void KeBugCheckEx_entry(dword_t code, dword_t param1, dword_t param2,
|
|
dword_t param3, dword_t param4) {
|
|
XELOGD("*** STOP: 0x{:08X} (0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X})", code,
|
|
param1, param2, param3, param4);
|
|
fflush(stdout);
|
|
xe::debugging::Break();
|
|
assert_always();
|
|
}
|
|
DECLARE_XBOXKRNL_EXPORT2(KeBugCheckEx, kDebug, kStub, kImportant);
|
|
|
|
void KeBugCheck_entry(dword_t code) { KeBugCheckEx_entry(code, 0, 0, 0, 0); }
|
|
DECLARE_XBOXKRNL_EXPORT2(KeBugCheck, kDebug, kImplemented, kImportant);
|
|
|
|
} // namespace xboxkrnl
|
|
} // namespace kernel
|
|
} // namespace xe
|
|
|
|
DECLARE_XBOXKRNL_EMPTY_REGISTER_EXPORTS(Debug);
|