From 23826fa9573f1d9226dee2abfb348c0ac27c9240 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 1 Jun 2015 18:19:32 -0700 Subject: [PATCH] Initial experiment with new kernel export format. --- libxenia.vcxproj | 1 + libxenia.vcxproj.filters | 3 + src/xenia/cpu/export_resolver.h | 22 +- src/xenia/kernel/util/shim_utils.cc | 22 ++ src/xenia/kernel/util/shim_utils.h | 397 +++++++++++++++++++-- src/xenia/kernel/xam_video.cc | 5 +- src/xenia/kernel/xboxkrnl_video.cc | 533 +++++++++++----------------- 7 files changed, 633 insertions(+), 350 deletions(-) create mode 100644 src/xenia/kernel/util/shim_utils.cc diff --git a/libxenia.vcxproj b/libxenia.vcxproj index 0fa0d6a3c..2a6e568bb 100644 --- a/libxenia.vcxproj +++ b/libxenia.vcxproj @@ -159,6 +159,7 @@ + diff --git a/libxenia.vcxproj.filters b/libxenia.vcxproj.filters index a64a8f85f..42cf5c742 100644 --- a/libxenia.vcxproj.filters +++ b/libxenia.vcxproj.filters @@ -709,6 +709,9 @@ src\xenia\base + + src\xenia\kernel\util + diff --git a/src/xenia/cpu/export_resolver.h b/src/xenia/cpu/export_resolver.h index 153230036..2c0b64d2a 100644 --- a/src/xenia/cpu/export_resolver.h +++ b/src/xenia/cpu/export_resolver.h @@ -21,10 +21,16 @@ namespace cpu { struct ExportTag { typedef uint32_t type; + // Export is implemented in some form and can be used. static const type kImplemented = 1 << 0; - static const type kSketchy = 1 << 1; - static const type kHighFrequency = 1 << 2; - static const type kImportant = 1 << 3; + // Export is a stub and is probably bad. + static const type kStub = 1 << 1; + // Export is known to cause problems, or may not be complete. + static const type kSketchy = 1 << 2; + // Export is called *a lot*. + static const type kHighFrequency = 1 << 3; + // Export is important and should always be logged. + static const type kImportant = 1 << 4; static const type kThreading = 1 << 10; static const type kInput = 1 << 11; @@ -34,7 +40,10 @@ struct ExportTag { static const type kModules = 1 << 15; static const type kUserProfiles = 1 << 16; - static const type kLog = 1 << 31; + // Export will be logged on each call. + static const type kLog = 1 << 30; + // Export's result will be logged on each call. + static const type kLogResult = 1 << 31; }; // DEPRECATED @@ -49,11 +58,12 @@ class Export { kVariable = 1, }; - Export(uint16_t ordinal, Type type, std::string name) + Export(uint16_t ordinal, Type type, std::string name, + ExportTag::type tags = 0) : ordinal(ordinal), type(type), name(name), - tags(0), + tags(tags), variable_ptr(0), function_data({nullptr, nullptr, 0}) {} diff --git a/src/xenia/kernel/util/shim_utils.cc b/src/xenia/kernel/util/shim_utils.cc new file mode 100644 index 000000000..4da37acc0 --- /dev/null +++ b/src/xenia/kernel/util/shim_utils.cc @@ -0,0 +1,22 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/kernel/util/shim_utils.h" + +namespace xe { +namespace kernel { +namespace shim { + +thread_local StringBuffer string_buffer_; + +StringBuffer* thread_local_string_buffer() { return &string_buffer_; } + +} // namespace shim +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 891a16a53..7f7ee0457 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -10,6 +10,9 @@ #ifndef XENIA_KERNEL_UTIL_SHIM_UTILS_H_ #define XENIA_KERNEL_UTIL_SHIM_UTILS_H_ +#include "xenia/base/byte_order.h" +#include "xenia/base/memory.h" +#include "xenia/base/string_buffer.h" #include "xenia/cpu/export_resolver.h" #include "xenia/cpu/frontend/ppc_context.h" @@ -37,37 +40,37 @@ using PPCContext = xe::cpu::frontend::PPCContext; #define SHIM_SET_MEM_64(a, v) xe::store_and_swap(SHIM_MEM_ADDR(a), v) namespace util { - inline uint32_t get_arg_stack_ptr(PPCContext* ppc_context, uint8_t index) { - return ((uint32_t)ppc_context->r[1]) + 0x54 + index * 8; - } +inline uint32_t get_arg_stack_ptr(PPCContext* ppc_context, uint8_t index) { + return ((uint32_t)ppc_context->r[1]) + 0x54 + index * 8; +} - inline uint8_t get_arg_8(PPCContext* ppc_context, uint8_t index) { - if (index <= 7) { - return (uint8_t)ppc_context->r[3 + index]; - } - return SHIM_MEM_8(get_arg_stack_ptr(ppc_context, index - 7)); +inline uint8_t get_arg_8(PPCContext* ppc_context, uint8_t index) { + if (index <= 7) { + return (uint8_t)ppc_context->r[3 + index]; } + return SHIM_MEM_8(get_arg_stack_ptr(ppc_context, index - 7)); +} - inline uint16_t get_arg_16(PPCContext* ppc_context, uint8_t index) { - if (index <= 7) { - return (uint16_t)ppc_context->r[3 + index]; - } - return SHIM_MEM_16(get_arg_stack_ptr(ppc_context, index - 7)); +inline uint16_t get_arg_16(PPCContext* ppc_context, uint8_t index) { + if (index <= 7) { + return (uint16_t)ppc_context->r[3 + index]; } + return SHIM_MEM_16(get_arg_stack_ptr(ppc_context, index - 7)); +} - inline uint32_t get_arg_32(PPCContext* ppc_context, uint8_t index) { - if (index <= 7) { - return (uint32_t)ppc_context->r[3 + index]; - } - return SHIM_MEM_32(get_arg_stack_ptr(ppc_context, index - 7)); +inline uint32_t get_arg_32(PPCContext* ppc_context, uint8_t index) { + if (index <= 7) { + return (uint32_t)ppc_context->r[3 + index]; } + return SHIM_MEM_32(get_arg_stack_ptr(ppc_context, index - 7)); +} - inline uint64_t get_arg_64(PPCContext* ppc_context, uint8_t index) { - if (index <= 7) { - return ppc_context->r[3 + index]; - } - return SHIM_MEM_64(get_arg_stack_ptr(ppc_context, index - 7)); +inline uint64_t get_arg_64(PPCContext* ppc_context, uint8_t index) { + if (index <= 7) { + return ppc_context->r[3 + index]; } + return SHIM_MEM_64(get_arg_stack_ptr(ppc_context, index - 7)); +} } #define SHIM_GET_ARG_8(n) util::get_arg_8(ppc_context, n) @@ -79,6 +82,354 @@ namespace util { #define SHIM_STRUCT(type, address) \ reinterpret_cast(SHIM_MEM_ADDR(address)) +namespace shim { + +class Param { + public: + struct Init { + PPCContext* ppc_context; + int ordinal; + int float_ordinal; + }; + + Param& operator=(const Param&) = delete; + + int ordinal() const { return ordinal_; } + + protected: + Param() : ordinal_(-1) {} + explicit Param(Init& init) : ordinal_(--init.ordinal) {} + + int ordinal_; +}; +template +class ParamBase : public Param { + public: + ParamBase() : Param(), value_(0) {} + ParamBase(Init& init) : Param(init) { LoadValue(init); } + ParamBase& operator=(const T& other) { + value_ = other; + return *this; + } + operator T() const { return value_; } + + private: + template + void LoadValue(Init& init) { + if (ordinal_ <= 7) { + value_ = V(init.ppc_context->r[3 + ordinal_]); + } else { + uint32_t stack_ptr = + uint32_t(init.ppc_context->r[1]) + 0x54 + (ordinal_ - 7) * 8; + value_ = + xe::load_and_swap(init.ppc_context->virtual_membase + stack_ptr); + } + } + template <> + void LoadValue(Init& init) { + value_ = init.ppc_context->f[1 + ++init.float_ordinal]; + } + template <> + void LoadValue(Init& init) { + value_ = init.ppc_context->f[1 + ++init.float_ordinal]; + } + + protected: + T value_; +}; + +class PointerParam : public ParamBase { + public: + PointerParam(Init& init) : ParamBase(init) { + host_ptr_ = value_ ? init.ppc_context->virtual_membase + value_ : nullptr; + } + PointerParam(void* host_ptr) : ParamBase(), host_ptr_(host_ptr) {} + PointerParam& operator=(void*& other) { + host_ptr_ = other; + return *this; + } + uint32_t guest_address() const { return value_; } + uintptr_t host_address() const { + return reinterpret_cast(host_ptr_); + } + template + T as() const { + return reinterpret_cast(host_ptr_); + } + template + xe::be* as_array() const { + return reinterpret_cast*>(host_ptr_); + } + operator void*() const { return host_ptr_; } + operator uint8_t*() const { return reinterpret_cast(host_ptr_); } + operator bool() const { return host_ptr_ != nullptr; } + void* operator+(int offset) const { + return reinterpret_cast(host_ptr_) + offset; + } + void Zero(size_t size) const { + assert_not_null(host_ptr_); + std::memset(host_ptr_, 0, size); + } + + protected: + void* host_ptr_; +}; + +template +class PrimitivePointerParam : public ParamBase { + public: + PrimitivePointerParam(Init& init) : ParamBase(init) { + host_ptr_ = value_ ? reinterpret_cast*>( + init.ppc_context->virtual_membase + value_) + : nullptr; + } + PrimitivePointerParam(T* host_ptr) : ParamBase(), host_ptr_(host_ptr) {} + PrimitivePointerParam& operator=(const T*& other) { + host_ptr_ = other; + return *this; + } + uint32_t guest_address() const { return value_; } + uintptr_t host_address() const { + return reinterpret_cast(host_ptr_); + } + T value() const { return *host_ptr_; } + operator T() const { return *host_ptr_; } + operator xe::be*() const { return host_ptr_; } + operator bool() const { return host_ptr_ != nullptr; } + void Zero() const { + assert_not_null(host_ptr_); + *host_ptr_ = 0; + } + + protected: + xe::be* host_ptr_; +}; + +template +class TypedPointerParam : public ParamBase { + public: + TypedPointerParam(Init& init) : ParamBase(init) { + host_ptr_ = + value_ + ? reinterpret_cast(init.ppc_context->virtual_membase + value_) + : nullptr; + } + TypedPointerParam(T* host_ptr) : ParamBase(), host_ptr_(host_ptr) {} + TypedPointerParam& operator=(const T*& other) { + host_ptr_ = other; + return *this; + } + uint32_t guest_address() const { return value_; } + uintptr_t host_address() const { + return reinterpret_cast(host_ptr_); + } + operator T*() const { return host_ptr_; } + operator bool() const { return host_ptr_ != nullptr; } + T* operator->() const { + assert_not_null(host_ptr_); + return host_ptr_; + } + void Zero() const { + assert_not_null(host_ptr_); + std::memset(host_ptr_, 0, sizeof(T)); + } + + protected: + T* host_ptr_; +}; + +template +class Result { + public: + Result(T value) : value_(value) {} + void Store(PPCContext* ppc_context) { + ppc_context->r[3] = uint64_t(int32_t(value_)); + } + Result() = delete; + Result& operator=(const Result&) = delete; + + private: + T value_; +}; + +} // namespace shim + +using int_param_t = const shim::ParamBase&; +using dword_param_t = const shim::ParamBase&; +using qword_param_t = const shim::ParamBase&; +using float_param_t = const shim::ParamBase&; +using double_param_t = const shim::ParamBase&; +using lpvoid_param_t = const shim::PointerParam&; +using lpdword_param_t = const shim::PrimitivePointerParam&; +using lpqword_param_t = const shim::PrimitivePointerParam&; +using lpfloat_param_t = const shim::PrimitivePointerParam&; +using lpdouble_param_t = const shim::PrimitivePointerParam&; +using fn_param_t = const shim::ParamBase&; +using unknown_param_t = const shim::ParamBase&; +using unknown_pointer_param_t = const shim::PointerParam&; +template +using typed_param_t = const shim::TypedPointerParam&; + +using dword_result_t = shim::Result; +using pointer_result_t = shim::Result; + +namespace shim { + + inline void AppendParam(StringBuffer& string_buffer, int_param_t param) { + string_buffer.AppendFormat("%d", int32_t(param)); +} +inline void AppendParam(StringBuffer& string_buffer, dword_param_t param) { + string_buffer.AppendFormat("%.8X", uint32_t(param)); +} +inline void AppendParam(StringBuffer& string_buffer, qword_param_t param) { + string_buffer.AppendFormat("%.16llX", uint64_t(param)); +} +inline void AppendParam(StringBuffer& string_buffer, float_param_t param) { + string_buffer.AppendFormat("%G", float(param)); +} +inline void AppendParam(StringBuffer& string_buffer, double_param_t param) { + string_buffer.AppendFormat("%G", double(param)); +} +inline void AppendParam(StringBuffer& string_buffer, lpvoid_param_t param) { + string_buffer.AppendFormat("%.8X", uint32_t(param)); +} +inline void AppendParam(StringBuffer& string_buffer, lpdword_param_t param) { + string_buffer.AppendFormat("%.8X(%.8X)", param.guest_address(), + param.value()); +} +inline void AppendParam(StringBuffer& string_buffer, lpqword_param_t param) { + string_buffer.AppendFormat("%.8X(%.16llX)", param.guest_address(), + param.value()); +} +inline void AppendParam(StringBuffer& string_buffer, lpfloat_param_t param) { + string_buffer.AppendFormat("%.8X(%G)", param.guest_address(), param.value()); +} +inline void AppendParam(StringBuffer& string_buffer, lpdouble_param_t param) { + string_buffer.AppendFormat("%.8X(%G)", param.guest_address(), param.value()); +} +template +void AppendParam(StringBuffer& string_buffer, typed_param_t param) { + string_buffer.AppendFormat("%.8X", param.guest_address()); +} + +enum class KernelModuleId { + xboxkrnl, + xam, +}; + +template +auto KernelTrampoline(F&& f, PPCContext* ppc_context, KernelState* kernel_state, + Tuple&& t, std::index_sequence) { + return std::forward(f)(ppc_context, kernel_state, + std::get(std::forward(t))...); +} + +template +typename std::enable_if::type AppendKernelCallParams( + StringBuffer& string_buffer, xe::cpu::Export* export, const std::tuple&) {} + +template + typename std::enable_if < + I::type AppendKernelCallParams( + StringBuffer& string_buffer, xe::cpu::Export* export, const std::tuple& params) { + if (I) { + string_buffer.Append(", "); + } + auto param = std::get(params); + AppendParam(string_buffer, param); + AppendKernelCallParams(string_buffer, export, params); +} + +StringBuffer* thread_local_string_buffer(); + +template +void PrintKernelCall(cpu::Export* export, const Tuple& params) { + auto& string_buffer = *thread_local_string_buffer(); + string_buffer.Reset(); + string_buffer.Append(export->name); + string_buffer.Append('('); + AppendKernelCallParams(string_buffer, export, params); + string_buffer.Append(')'); + auto str = string_buffer.GetString(); + if (export->tags & ExportTag::kImportant) { + XELOGI(str); + } else { + XELOGD(str); + } +} + +template +xe::cpu::Export* RegisterExport(R (*fn)(PPCContext* ppc_context, + xe::kernel::KernelState* kernel_state, + Ps&...), + std::string name, + xe::cpu::ExportTag::type tags) { + static const auto export = + new cpu::Export(ORDINAL, xe::cpu::Export::Type::kFunction, name, + tags | ExportTag::kImplemented | ExportTag::kLog); + static R (*FN)(PPCContext* ppc_context, xe::kernel::KernelState* kernel_state, + Ps&...) = fn; + struct X { + static void Trampoline(PPCContext* ppc_context) { + ++export->function_data.call_count; + Param::Init init = { + ppc_context, sizeof...(Ps), 0, + }; + auto params = std::make_tuple(Ps(init)...); + if (export->tags & ExportTag::kLog) { + PrintKernelCall(export, params); + } + auto result = KernelTrampoline(FN, ppc_context, ppc_context->kernel_state, + std::forward>(params), + std::make_index_sequence()); + result.Store(ppc_context); + if (export->tags & (ExportTag::kLog | ExportTag::kLogResult)) { + // TODO(benvanik): log result. + } + } + }; + export->function_data.trampoline = &X::Trampoline; + return export; +} + +template +xe::cpu::Export* RegisterExport( + void (*fn)(PPCContext* ppc_context, xe::kernel::KernelState* kernel_state, + Ps&...), + std::string name, xe::cpu::ExportTag::type tags) { + static const auto export = + new cpu::Export(ORDINAL, xe::cpu::Export::Type::kFunction, name, + tags | ExportTag::kImplemented | ExportTag::kLog); + static void (*FN)(PPCContext* ppc_context, + xe::kernel::KernelState* kernel_state, Ps&...) = fn; + struct X { + static void Trampoline(PPCContext* ppc_context) { + ++export->function_data.call_count; + Param::Init init = { + ppc_context, sizeof...(Ps), + }; + auto params = std::make_tuple(Ps(init)...); + if (export->tags & ExportTag::kLog) { + PrintKernelCall(export, params); + } + KernelTrampoline(FN, ppc_context, ppc_context->kernel_state, + std::forward>(params), + std::make_index_sequence()); + } + }; + export->function_data.trampoline = &X::Trampoline; + return export; +} + +} // namespace shim + +using xe::cpu::ExportTag; +#define DECLARE_EXPORT(module_name, name, tags) \ + auto EXPORT_##module_name##_##name = \ + RegisterExport_##module_name(xe::kernel::shim::RegisterExport< \ + xe::kernel::shim::KernelModuleId::module_name, ordinals::##name>( \ + &name, std::string(#name), tags)); + } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/xam_video.cc b/src/xenia/kernel/xam_video.cc index 8369d25c4..6e85df773 100644 --- a/src/xenia/kernel/xam_video.cc +++ b/src/xenia/kernel/xam_video.cc @@ -17,7 +17,8 @@ namespace xe { namespace kernel { // TODO(benvanik): actually check to see if these are the same. -void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode); +void VdQueryVideoMode(PPCContext* ppc_context, KernelState* kernel_state, + typed_param_t video_mode); SHIM_CALL XGetVideoMode_shim(PPCContext* ppc_context, KernelState* kernel_state) { uint32_t video_mode_ptr = SHIM_GET_ARG_32(0); @@ -25,7 +26,7 @@ SHIM_CALL XGetVideoMode_shim(PPCContext* ppc_context, XELOGD("XGetVideoMode(%.8X)", video_mode_ptr); - xeVdQueryVideoMode(video_mode); + VdQueryVideoMode(ppc_context, kernel_state, video_mode); } SHIM_CALL XGetVideoCapabilities_shim(PPCContext* ppc_context, diff --git a/src/xenia/kernel/xboxkrnl_video.cc b/src/xenia/kernel/xboxkrnl_video.cc index 403867d0a..326ed6f28 100644 --- a/src/xenia/kernel/xboxkrnl_video.cc +++ b/src/xenia/kernel/xboxkrnl_video.cc @@ -36,71 +36,49 @@ using xe::gpu::GraphicsSystem; // http://www.microsoft.com/en-za/download/details.aspx?id=5313 -- "Stripped // Down Direct3D: Xbox 360 Command Buffer and Resource Management" -SHIM_CALL VdGetCurrentDisplayGamma_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t arg0_ptr = SHIM_GET_ARG_32(0); - uint32_t arg1_ptr = SHIM_GET_ARG_32(1); - - XELOGD("VdGetCurrentDisplayGamma(%.8X, %.8X)", arg0_ptr, arg1_ptr); - - SHIM_SET_MEM_32(arg0_ptr, 2); - xe::store_and_swap(SHIM_MEM_ADDR(arg1_ptr), 2.22222233f); +void VdGetCurrentDisplayGamma(PPCContext* ppc_context, + KernelState* kernel_state, + lpdword_param_t arg0_ptr, + lpfloat_param_t arg1_ptr) { + *arg0_ptr = 2; + *arg1_ptr = 2.22222233f; } +DECLARE_EXPORT(xboxkrnl, VdGetCurrentDisplayGamma, ExportTag::kVideo); -SHIM_CALL VdGetCurrentDisplayInformation_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t ptr = SHIM_GET_ARG_32(0); - - XELOGD("VdGetCurrentDisplayInformation(%.8X)", ptr); - +void VdGetCurrentDisplayInformation(PPCContext* ppc_context, + KernelState* kernel_state, + lpvoid_param_t info_ptr) { + auto info = info_ptr.as_array(); // Expecting a length 0x58 struct of stuff. - SHIM_SET_MEM_32(ptr + 0, (1280 << 16) | 720); - SHIM_SET_MEM_32(ptr + 4, 0); - SHIM_SET_MEM_32(ptr + 8, 0); - SHIM_SET_MEM_32(ptr + 12, 0); - SHIM_SET_MEM_32(ptr + 16, 1280); // backbuffer width? - SHIM_SET_MEM_32(ptr + 20, 720); // backbuffer height? - SHIM_SET_MEM_32(ptr + 24, 1280); - SHIM_SET_MEM_32(ptr + 28, 720); - SHIM_SET_MEM_32(ptr + 32, 1); - SHIM_SET_MEM_32(ptr + 36, 0); - SHIM_SET_MEM_32(ptr + 40, 0); - SHIM_SET_MEM_32(ptr + 44, 0); - SHIM_SET_MEM_32(ptr + 48, 1); - SHIM_SET_MEM_32(ptr + 52, 0); - SHIM_SET_MEM_32(ptr + 56, 0); - SHIM_SET_MEM_32(ptr + 60, 0); - SHIM_SET_MEM_32(ptr + 64, 0x014000B4); // ? - SHIM_SET_MEM_32(ptr + 68, 0x014000B4); // ? - SHIM_SET_MEM_32(ptr + 72, (1280 << 16) | 720); // actual display size? - SHIM_SET_MEM_32(ptr + 76, 0x42700000); - SHIM_SET_MEM_32(ptr + 80, 0); - SHIM_SET_MEM_32(ptr + 84, 1280); // display width + info[0 / 4] = (1280 << 16) | 720; + info[4 / 4] = 0; + info[8 / 4] = 0; + info[12 / 4] = 0; + info[16 / 4] = 1280; // backbuffer width? + info[20 / 4] = 720; // backbuffer height? + info[24 / 4] = 1280; + info[28 / 4] = 720; + info[32 / 4] = 1; + info[36 / 4] = 0; + info[40 / 4] = 0; + info[44 / 4] = 0; + info[48 / 4] = 1; + info[52 / 4] = 0; + info[56 / 4] = 0; + info[60 / 4] = 0; + info[64 / 4] = 0x014000B4; // ? + info[68 / 4] = 0x014000B4; // ? + info[72 / 4] = (1280 << 16) | 720; // actual display size? + info[76 / 4] = 0x42700000; + info[80 / 4] = 0; + info[84 / 4] = 1280; // display width } +DECLARE_EXPORT(xboxkrnl, VdGetCurrentDisplayInformation, ExportTag::kVideo); -void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode); - -SHIM_CALL VdQueryVideoFlags_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - XELOGD("VdQueryVideoFlags()"); - - X_VIDEO_MODE mode; - xeVdQueryVideoMode(&mode); - - uint32_t flags = 0; - flags |= mode.is_widescreen ? 1 : 0; - flags |= mode.display_width >= 1024 ? 2 : 0; - flags |= mode.display_width >= 1920 ? 4 : 0; - - SHIM_SET_RETURN_32(flags); -} - -void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode) { - if (video_mode == NULL) { - return; - } - +void VdQueryVideoMode(PPCContext* ppc_context, KernelState* kernel_state, + typed_param_t video_mode) { // TODO: get info from actual display + video_mode.Zero(); video_mode->display_width = 1280; video_mode->display_height = 720; video_mode->is_interlaced = 0; @@ -110,274 +88,226 @@ void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode) { video_mode->video_standard = 1; // NTSC video_mode->unknown_0x8a = 0x4A; video_mode->unknown_0x01 = 0x01; - video_mode->reserved[0] = video_mode->reserved[1] = video_mode->reserved[2] = - 0; + video_mode->reserved[0] = 0; + video_mode->reserved[1] = 0; + video_mode->reserved[2] = 0; } +DECLARE_EXPORT(xboxkrnl, VdQueryVideoMode, ExportTag::kVideo); -SHIM_CALL VdQueryVideoMode_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t video_mode_ptr = SHIM_GET_ARG_32(0); - X_VIDEO_MODE* video_mode = (X_VIDEO_MODE*)SHIM_MEM_ADDR(video_mode_ptr); +dword_result_t VdQueryVideoFlags(PPCContext* ppc_context, + KernelState* kernel_state) { + X_VIDEO_MODE mode; + VdQueryVideoMode(ppc_context, kernel_state, &mode); - XELOGD("VdQueryVideoMode(%.8X)", video_mode_ptr); + uint32_t flags = 0; + flags |= mode.is_widescreen ? 1 : 0; + flags |= mode.display_width >= 1024 ? 2 : 0; + flags |= mode.display_width >= 1920 ? 4 : 0; - xeVdQueryVideoMode(video_mode); + return flags; } +DECLARE_EXPORT(xboxkrnl, VdQueryVideoFlags, ExportTag::kVideo); -SHIM_CALL VdSetDisplayMode_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t mode = SHIM_GET_ARG_32(0); - - // 40000000 - XELOGD("VdSetDisplayMode(%.8X)", mode); - - SHIM_SET_RETURN_32(0); +dword_result_t VdSetDisplayMode(PPCContext* ppc_context, + KernelState* kernel_state, dword_param_t mode) { + // Often 0x40000000. + return 0; } +DECLARE_EXPORT(xboxkrnl, VdSetDisplayMode, + ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdSetDisplayModeOverride_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t unk0 = SHIM_GET_ARG_32(0); - uint32_t unk1 = SHIM_GET_ARG_32(1); - double refresh_rate = ppc_context->f[1]; // 0, 50, 59.9, etc. - uint32_t unk3 = SHIM_GET_ARG_32(3); - uint32_t unk4 = SHIM_GET_ARG_32(4); - - // TODO(benvanik): something with refresh rate? - XELOGD("VdSetDisplayModeOverride(%.8X, %.8X, %g, %.8X, %.8X)", unk0, unk1, - refresh_rate, unk3, unk4); - - SHIM_SET_RETURN_32(0); +dword_result_t VdSetDisplayModeOverride( + PPCContext* ppc_context, KernelState* kernel_state, unknown_param_t unk0, + unknown_param_t unk1, double_param_t refresh_rate, unknown_param_t unk3, + unknown_param_t unk4) { + // refresh_rate = 0, 50, 59.9, etc. + return 0; } +DECLARE_EXPORT(xboxkrnl, VdSetDisplayModeOverride, + ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdInitializeEngines_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t unk0 = SHIM_GET_ARG_32(0); - uint32_t callback = SHIM_GET_ARG_32(1); - uint32_t unk1 = SHIM_GET_ARG_32(2); - uint32_t unk2_ptr = SHIM_GET_ARG_32(3); - uint32_t unk3_ptr = SHIM_GET_ARG_32(4); - - XELOGD("VdInitializeEngines(%.8X, %.8X, %.8X, %.8X, %.8X)", unk0, callback, - unk1, unk2_ptr, unk3_ptr); - +dword_result_t VdInitializeEngines(PPCContext* ppc_context, + KernelState* kernel_state, + unknown_param_t unk0, fn_param_t callback, + unknown_param_t unk1, + unknown_pointer_param_t unk2_ptr, + unknown_pointer_param_t unk3_ptr) { // r3 = 0x4F810000 // r4 = function ptr (cleanup callback?) // r5 = 0 // r6/r7 = some binary data in .data - - SHIM_SET_RETURN_32(1); + return 1; } +DECLARE_EXPORT(xboxkrnl, VdInitializeEngines, + ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdShutdownEngines_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - XELOGD("VdShutdownEngines()"); - +void VdShutdownEngines(PPCContext* ppc_context, KernelState* kernel_state) { // Ignored for now. // Games seem to call an Initialize/Shutdown pair to query info, then // re-initialize. } +DECLARE_EXPORT(xboxkrnl, VdShutdownEngines, + ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdGetGraphicsAsicID_shim(PPCContext* ppc_context, +dword_result_t VdGetGraphicsAsicID(PPCContext* ppc_context, KernelState* kernel_state) { - XELOGD("VdGetGraphicsAsicID()"); - // Games compare for < 0x10 and do VdInitializeEDRAM, else other // (retrain/etc). - SHIM_SET_RETURN_32(0x11); + return 0x11; } +DECLARE_EXPORT(xboxkrnl, VdGetGraphicsAsicID, ExportTag::kVideo); -SHIM_CALL VdEnableDisableClockGating_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t enabled = SHIM_GET_ARG_32(0); - - XELOGD("VdEnableDisableClockGating(%d)", enabled); - +dword_result_t VdEnableDisableClockGating(PPCContext* ppc_context, + KernelState* kernel_state, + dword_param_t enabled) { // Ignored, as it really doesn't matter. - - SHIM_SET_RETURN_32(0); + return 0; } +DECLARE_EXPORT(xboxkrnl, VdEnableDisableClockGating, ExportTag::kVideo); -SHIM_CALL VdSetGraphicsInterruptCallback_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t callback = SHIM_GET_ARG_32(0); - uint32_t user_data = SHIM_GET_ARG_32(1); - - XELOGD("VdSetGraphicsInterruptCallback(%.8X, %.8X)", callback, user_data); - - GraphicsSystem* gs = kernel_state->emulator()->graphics_system(); - if (!gs) { - return; - } - +void VdSetGraphicsInterruptCallback(PPCContext* ppc_context, + KernelState* kernel_state, + fn_param_t callback, + lpvoid_param_t user_data) { // callback takes 2 params // r3 = bool 0/1 - 0 is normal interrupt, 1 is some acquire/lock mumble // r4 = user_data (r4 of VdSetGraphicsInterruptCallback) - - gs->SetInterruptCallback(callback, user_data); -} - -SHIM_CALL VdInitializeRingBuffer_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t ptr = SHIM_GET_ARG_32(0); - uint32_t page_count = SHIM_GET_ARG_32(1); - - XELOGD("VdInitializeRingBuffer(%.8X, %.8X)", ptr, page_count); - - GraphicsSystem* gs = kernel_state->emulator()->graphics_system(); - if (!gs) { - return; + auto gs = kernel_state->emulator()->graphics_system(); + if (gs) { + gs->SetInterruptCallback(callback, user_data); } +} +DECLARE_EXPORT(xboxkrnl, VdSetGraphicsInterruptCallback, ExportTag::kVideo); +void VdInitializeRingBuffer(PPCContext* ppc_context, KernelState* kernel_state, + lpvoid_param_t ptr, int_param_t page_count) { // r3 = result of MmGetPhysicalAddress // r4 = number of pages? page size? // 0x8000 -> cntlzw=16 -> 0x1C - 16 = 12 // Buffer pointers are from MmAllocatePhysicalMemory with WRITE_COMBINE. // Sizes could be zero? XBLA games seem to do this. Default sizes? // D3D does size / region_count - must be > 1024 - - gs->InitializeRingBuffer(ptr, page_count); + auto gs = kernel_state->emulator()->graphics_system(); + if (gs) { + gs->InitializeRingBuffer(ptr, page_count); + } } +DECLARE_EXPORT(xboxkrnl, VdInitializeRingBuffer, ExportTag::kVideo); -SHIM_CALL VdEnableRingBufferRPtrWriteBack_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t ptr = SHIM_GET_ARG_32(0); - uint32_t block_size = SHIM_GET_ARG_32(1); - - XELOGD("VdEnableRingBufferRPtrWriteBack(%.8X, %.8X)", ptr, block_size); - - GraphicsSystem* gs = kernel_state->emulator()->graphics_system(); +void VdEnableRingBufferRPtrWriteBack(PPCContext* ppc_context, + KernelState* kernel_state, + lpvoid_param_t ptr, + int_param_t block_size) { + auto gs = kernel_state->emulator()->graphics_system(); if (!gs) { return; } // r4 = 6, usually --- <=19 gs->EnableReadPointerWriteBack(ptr, block_size); - - ptr += 0x20000000; - // printf("%.8X", ptr); - // 0x0110343c - - // r3 = 0x2B10(d3d?) + 0x3C - - //((p + 0x3C) & 0x1FFFFFFF) + ((((p + 0x3C) >> 20) + 0x200) & 0x1000) - // also 0x3C offset into WriteBacks is PrimaryRingBufferReadIndex - //(1:17:38 AM) Rick: .text:8201B348 lwz r11, 0x2B10(r31) - //(1:17:38 AM) Rick: .text:8201B34C addi r11, r11, 0x3C - //(1:17:38 AM) Rick: .text:8201B350 srwi r10, r11, 20 # - // r10 = r11 >> 20 - //(1:17:38 AM) Rick: .text:8201B354 clrlwi r11, r11, 3 # - // r11 = r11 & 0x1FFFFFFF - //(1:17:38 AM) Rick: .text:8201B358 addi r10, r10, 0x200 - //(1:17:39 AM) Rick: .text:8201B35C rlwinm r10, r10, - // 0,19,19 # r10 = r10 & 0x1000 - //(1:17:39 AM) Rick: .text:8201B360 add r3, r10, r11 - //(1:17:39 AM) Rick: .text:8201B364 bl - // VdEnableRingBufferRPtrWriteBack - // TODO(benvanik): something? } +DECLARE_EXPORT(xboxkrnl, VdEnableRingBufferRPtrWriteBack, ExportTag::kVideo); -SHIM_CALL VdGetSystemCommandBuffer_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t p0_ptr = SHIM_GET_ARG_32(0); - uint32_t p1_ptr = SHIM_GET_ARG_32(1); - - XELOGD("VdGetSystemCommandBuffer(%.8X, %.8X)", p0_ptr, p1_ptr); - - std::memset(SHIM_MEM_ADDR(p0_ptr), 0, 0x94); - SHIM_SET_MEM_32(p0_ptr, 0xBEEF0000); - SHIM_SET_MEM_32(p1_ptr, 0xBEEF0001); +void VdGetSystemCommandBuffer(PPCContext* ppc_context, + KernelState* kernel_state, + unknown_pointer_param_t p0_ptr, + unknown_pointer_param_t p1_ptr) { + p0_ptr.Zero(0x94); + xe::store_and_swap(p0_ptr, 0xBEEF0000); + xe::store_and_swap(p1_ptr, 0xBEEF0001); } +DECLARE_EXPORT(xboxkrnl, VdGetSystemCommandBuffer, + ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdSetSystemCommandBufferGpuIdentifierAddress_shim( - PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t unk = SHIM_GET_ARG_32(0); - - XELOGD("VdSetSystemCommandBufferGpuIdentifierAddress(%.8X)", unk); - +void VdSetSystemCommandBufferGpuIdentifierAddress(PPCContext* ppc_context, + KernelState* kernel_state, + unknown_pointer_param_t unk) { // r3 = 0x2B10(d3d?) + 8 } +DECLARE_EXPORT(xboxkrnl, VdSetSystemCommandBufferGpuIdentifierAddress, + ExportTag::kVideo | ExportTag::kStub); // VdVerifyMEInitCommand // r3 // r4 = 19 // no op? -SHIM_CALL VdInitializeScalerCommandBuffer_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t unk0 = SHIM_GET_ARG_32(0); // 0? - uint32_t unk1 = SHIM_GET_ARG_32(1); // 0x050002d0 size of ? - uint32_t unk2 = SHIM_GET_ARG_32(2); // 0? - uint32_t unk3 = SHIM_GET_ARG_32(3); // 0x050002d0 size of ? - uint32_t unk4 = SHIM_GET_ARG_32(4); // 0x050002d0 size of ? - uint32_t unk5 = SHIM_GET_ARG_32(5); // 7? - uint32_t unk6 = SHIM_GET_ARG_32(6); // 0x2004909c <-- points to zeros? - uint32_t unk7 = SHIM_GET_ARG_32(7); // 7? - uint32_t dest_ptr = SHIM_GET_ARG_32(8); // Points to the first 80000000h where the memcpy sources from. - - XELOGD( - "VdInitializeScalerCommandBuffer(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X, " - "%.8X, %.8X, %.8X)", - unk0, unk1, unk2, unk3, unk4, unk5, unk6, unk7, dest_ptr); - +dword_result_t VdInitializeScalerCommandBuffer( + PPCContext* ppc_context, KernelState* kernel_state, + unknown_param_t unk0, // 0? + unknown_param_t unk1, // 0x050002d0 size of ? + unknown_param_t unk2, // 0? + unknown_param_t unk3, // 0x050002d0 size of ? + unknown_param_t unk4, // 0x050002d0 size of ? + unknown_param_t unk5, // 7? + unknown_pointer_param_t unk6, // 0x2004909c <-- points to zeros? + unknown_param_t unk7, // 7? + lpvoid_param_t dest_ptr // Points to the first 80000000h where the memcpy + // sources from. + ) { // We could fake the commands here, but I'm not sure the game checks for // anything but success (non-zero ret). // For now, we just fill it with NOPs. - size_t total_words = 0x1CC / 4; - uint8_t* p = SHIM_MEM_ADDR(dest_ptr); - for (size_t i = 0; i < total_words; ++i, p += 4) { - xe::store_and_swap(p, 0x80000000); + uint32_t total_words = 0x1CC / 4; + auto dest = dest_ptr.as_array(); + for (size_t i = 0; i < total_words; ++i) { + dest[i] = 0x80000000; } // returns memcpy size >> 2 for memcpy(...,...,ret << 2) - SHIM_SET_RETURN_32(total_words >> 2); + return total_words >> 2; } +DECLARE_EXPORT(xboxkrnl, VdInitializeScalerCommandBuffer, + ExportTag::kVideo | ExportTag::kSketchy); // We use these to shuffle data to VdSwap. // This way it gets properly stored in the command buffer (for replay/etc). -static uint32_t last_frontbuffer_width_ = 1280; -static uint32_t last_frontbuffer_height_ = 720; +uint32_t last_frontbuffer_width_ = 1280; +uint32_t last_frontbuffer_height_ = 720; -SHIM_CALL VdCallGraphicsNotificationRoutines_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t unk_1 = SHIM_GET_ARG_32(0); - uint32_t args_ptr = SHIM_GET_ARG_32(1); +struct BufferScaling { + xe::be fb_width; + xe::be fb_height; + xe::be bb_width; + xe::be bb_height; +}; +void AppendParam(StringBuffer& string_buffer, + typed_param_t param) { + string_buffer.AppendFormat( + "%.8X(scale %dx%d -> %dx%d))", param.guest_address(), + uint16_t(param->bb_width), uint16_t(param->bb_height), + uint16_t(param->fb_width), uint16_t(param->fb_height)); +} - assert_true(unk_1 == 1); - - uint16_t fb_width = SHIM_MEM_16(args_ptr + 0); - uint16_t fb_height = SHIM_MEM_16(args_ptr + 2); - uint16_t bb_width = SHIM_MEM_16(args_ptr + 4); - uint16_t bb_height = SHIM_MEM_16(args_ptr + 6); - - XELOGD("VdCallGraphicsNotificationRoutines(%d, %.8X(scale %dx%d -> %dx%d))", - unk_1, args_ptr, bb_width, bb_height, fb_width, fb_height); +dword_result_t VdCallGraphicsNotificationRoutines( + PPCContext* ppc_context, KernelState* kernel_state, unknown_param_t unk0, + typed_param_t args_ptr) { + assert_true(unk0 == 1); // TODO(benvanik): what does this mean, I forget: // callbacks get 0, r3, r4 // For use by VdSwap. - last_frontbuffer_width_ = fb_width; - last_frontbuffer_height_ = fb_height; + last_frontbuffer_width_ = args_ptr->fb_width; + last_frontbuffer_height_ = args_ptr->fb_height; - SHIM_SET_RETURN_32(0); + return 0; } +DECLARE_EXPORT(xboxkrnl, VdCallGraphicsNotificationRoutines, + ExportTag::kVideo | ExportTag::kSketchy); -SHIM_CALL VdIsHSIOTrainingSucceeded_shim(PPCContext* ppc_context, +dword_result_t VdIsHSIOTrainingSucceeded(PPCContext* ppc_context, KernelState* kernel_state) { - XELOGD("VdIsHSIOTrainingSucceeded()"); - // Not really sure what this should be - code does weird stuff here: // (cntlzw r11, r3 / extrwi r11, r11, 1, 26) - SHIM_SET_RETURN_32(1); + return 1; } +DECLARE_EXPORT(xboxkrnl, VdIsHSIOTrainingSucceeded, + ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdPersistDisplay_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t unk0 = SHIM_GET_ARG_32(0); - uint32_t unk1_ptr = SHIM_GET_ARG_32(1); - - XELOGD("VdPersistDisplay(%.8X, %.8X)", unk0, unk1_ptr); - +dword_result_t VdPersistDisplay(PPCContext* ppc_context, + KernelState* kernel_state, unknown_param_t unk0, + lpdword_param_t unk1_ptr) { // unk1_ptr needs to be populated with a pointer passed to // MmFreePhysicalMemory(1, *unk1_ptr). if (unk1_ptr) { @@ -385,112 +315,77 @@ SHIM_CALL VdPersistDisplay_shim(PPCContext* ppc_context, uint32_t unk1_value; heap->Alloc(64, 32, kMemoryAllocationReserve | kMemoryAllocationCommit, kMemoryProtectNoAccess, false, &unk1_value); - SHIM_SET_MEM_32(unk1_ptr, unk1_value); + *unk1_ptr = unk1_value; } - // ? - SHIM_SET_RETURN_32(1); + return 1; } +DECLARE_EXPORT(xboxkrnl, VdPersistDisplay, + ExportTag::kVideo | ExportTag::kSketchy); -SHIM_CALL VdRetrainEDRAMWorker_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t unk0 = SHIM_GET_ARG_32(0); - - XELOGD("VdRetrainEDRAMWorker(%.8X)", unk0); - - SHIM_SET_RETURN_32(0); +dword_result_t VdRetrainEDRAMWorker(PPCContext* ppc_context, + KernelState* kernel_state, + unknown_param_t unk0) { + return 0; } +DECLARE_EXPORT(xboxkrnl, VdRetrainEDRAMWorker, + ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdRetrainEDRAM_shim(PPCContext* ppc_context, - KernelState* kernel_state) { - uint32_t unk0 = SHIM_GET_ARG_32(0); - uint32_t unk1 = SHIM_GET_ARG_32(1); - uint32_t unk2 = SHIM_GET_ARG_32(2); - uint32_t unk3 = SHIM_GET_ARG_32(3); - uint32_t unk4 = SHIM_GET_ARG_32(4); - uint32_t unk5 = SHIM_GET_ARG_32(5); - - XELOGD("VdRetrainEDRAM(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X)", unk0, unk1, unk2, - unk3, unk4, unk5); - - SHIM_SET_RETURN_32(0); +dword_result_t VdRetrainEDRAM(PPCContext* ppc_context, + KernelState* kernel_state, unknown_param_t unk0, + unknown_param_t unk1, unknown_param_t unk2, + unknown_param_t unk3, unknown_param_t unk4, + unknown_param_t unk5) { + return 0; } +DECLARE_EXPORT(xboxkrnl, VdRetrainEDRAM, ExportTag::kVideo | ExportTag::kStub); -SHIM_CALL VdSwap_shim(PPCContext* ppc_context, KernelState* kernel_state) { - uint32_t buffer_ptr = SHIM_GET_ARG_32(0); // ptr into primary ringbuffer - uint32_t fetch_ptr = SHIM_GET_ARG_32(1); // frontbuffer texture fetch - uint32_t unk2 = SHIM_GET_ARG_32(2); - uint32_t unk3 = SHIM_GET_ARG_32(3); // buffer from VdGetSystemCommandBuffer - uint32_t unk4 = - SHIM_GET_ARG_32(4); // pointer from VdGetSystemCommandBuffer (0xBEEF0001) - uint32_t frontbuffer_ptr = SHIM_GET_ARG_32(5); // ptr to frontbuffer address - uint32_t color_format_ptr = SHIM_GET_ARG_32(6); - uint32_t color_space_ptr = SHIM_GET_ARG_32(7); - - uint32_t frontbuffer = SHIM_MEM_32(frontbuffer_ptr); - +void VdSwap( + PPCContext* ppc_context, KernelState* kernel_state, + lpvoid_param_t buffer_ptr, // ptr into primary ringbuffer + lpvoid_param_t fetch_ptr, // frontbuffer texture fetch + unknown_param_t unk2, // + unknown_pointer_param_t unk3, // buffer from VdGetSystemCommandBuffer + unknown_pointer_param_t unk4, // from VdGetSystemCommandBuffer (0xBEEF0001) + lpdword_param_t frontbuffer_ptr, // ptr to frontbuffer address + lpdword_param_t color_format_ptr, lpdword_param_t color_space_ptr) { gpu::xenos::xe_gpu_texture_fetch_t fetch; - xe::copy_and_swap_32_unaligned((uint32_t*)&fetch, - (uint32_t*)SHIM_MEM_ADDR(fetch_ptr), 6); + xe::copy_and_swap_32_unaligned( + reinterpret_cast(&fetch), + reinterpret_cast(fetch_ptr.host_address()), 6); - auto color_format = (gpu::xenos::ColorFormat)SHIM_MEM_32(color_format_ptr); - auto color_space = SHIM_MEM_32(color_space_ptr); + auto color_format = gpu::xenos::ColorFormat(color_format_ptr.value()); + auto color_space = *color_space_ptr; assert_true(color_format == gpu::xenos::ColorFormat::k_8_8_8_8); assert_true(color_space == 0); - assert_true(frontbuffer == fetch.address << 12); + assert_true(*frontbuffer_ptr == fetch.address << 12); assert_true(last_frontbuffer_width_ == 1 + fetch.size_2d.width); assert_true(last_frontbuffer_height_ == 1 + fetch.size_2d.height); - XELOGD("VdSwap(%.8X, %.8X, %.8X, %.8X, %.8X, %.8X(%.8X), %.8X(%u), %.8X(%u))", - buffer_ptr, fetch_ptr, unk2, unk3, unk4, frontbuffer_ptr, frontbuffer, - color_format_ptr, color_format, color_space_ptr, color_space); - // The caller seems to reserve 64 words (256b) in the primary ringbuffer // for this method to do what it needs. We just zero them out and send a // token value. It'd be nice to figure out what this is really doing so // that we could simulate it, though due to TCR I bet all games need to // use this method. - std::memset(SHIM_MEM_ADDR(buffer_ptr), 0, 64 * 4); - auto dwords = reinterpret_cast(SHIM_MEM_ADDR(buffer_ptr)); - dwords[0] = xe::byte_swap((0x3 << 30) | ((63 - 1) << 16) | - (xe::gpu::xenos::PM4_XE_SWAP << 8)); - dwords[1] = xe::byte_swap('SWAP'); - dwords[2] = xe::byte_swap(frontbuffer); + buffer_ptr.Zero(64 * 4); + + auto dwords = buffer_ptr.as_array(); + dwords[0] = + (0x3 << 30) | ((63 - 1) << 16) | (xe::gpu::xenos::PM4_XE_SWAP << 8); + dwords[1] = 'SWAP'; + dwords[2] = *frontbuffer_ptr; // Set by VdCallGraphicsNotificationRoutines. - dwords[3] = xe::byte_swap(last_frontbuffer_width_); - dwords[4] = xe::byte_swap(last_frontbuffer_height_); + dwords[3] = last_frontbuffer_width_; + dwords[4] = last_frontbuffer_height_; } +DECLARE_EXPORT(xboxkrnl, VdSwap, ExportTag::kVideo | ExportTag::kImportant); } // namespace kernel } // namespace xe void xe::kernel::xboxkrnl::RegisterVideoExports( xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) { - SHIM_SET_MAPPING("xboxkrnl.exe", VdGetCurrentDisplayGamma, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdGetCurrentDisplayInformation, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdQueryVideoFlags, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdQueryVideoMode, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdSetDisplayMode, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdSetDisplayModeOverride, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdInitializeEngines, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdShutdownEngines, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdGetGraphicsAsicID, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdEnableDisableClockGating, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdSetGraphicsInterruptCallback, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdInitializeRingBuffer, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdEnableRingBufferRPtrWriteBack, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdGetSystemCommandBuffer, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdSetSystemCommandBufferGpuIdentifierAddress, - state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdInitializeScalerCommandBuffer, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdCallGraphicsNotificationRoutines, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdIsHSIOTrainingSucceeded, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdPersistDisplay, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdRetrainEDRAMWorker, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdRetrainEDRAM, state); - SHIM_SET_MAPPING("xboxkrnl.exe", VdSwap, state); - Memory* memory = kernel_state->memory(); // VdGlobalDevice (4b)