Initial experiment with new kernel export format.
This commit is contained in:
@@ -159,6 +159,7 @@
|
|||||||
<ClCompile Include="src\xenia\kernel\objects\xuser_module.cc" />
|
<ClCompile Include="src\xenia\kernel\objects\xuser_module.cc" />
|
||||||
<ClCompile Include="src\xenia\kernel\object_table.cc" />
|
<ClCompile Include="src\xenia\kernel\object_table.cc" />
|
||||||
<ClCompile Include="src\xenia\kernel\user_profile.cc" />
|
<ClCompile Include="src\xenia\kernel\user_profile.cc" />
|
||||||
|
<ClCompile Include="src\xenia\kernel\util\shim_utils.cc" />
|
||||||
<ClCompile Include="src\xenia\kernel\util\xex2.cc" />
|
<ClCompile Include="src\xenia\kernel\util\xex2.cc" />
|
||||||
<ClCompile Include="src\xenia\kernel\xam_content.cc" />
|
<ClCompile Include="src\xenia\kernel\xam_content.cc" />
|
||||||
<ClCompile Include="src\xenia\kernel\xam_info.cc" />
|
<ClCompile Include="src\xenia\kernel\xam_info.cc" />
|
||||||
|
|||||||
@@ -709,6 +709,9 @@
|
|||||||
<ClCompile Include="src\xenia\base\clock.cc">
|
<ClCompile Include="src\xenia\base\clock.cc">
|
||||||
<Filter>src\xenia\base</Filter>
|
<Filter>src\xenia\base</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\xenia\kernel\util\shim_utils.cc">
|
||||||
|
<Filter>src\xenia\kernel\util</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\xenia\emulator.h">
|
<ClInclude Include="src\xenia\emulator.h">
|
||||||
|
|||||||
@@ -21,10 +21,16 @@ namespace cpu {
|
|||||||
struct ExportTag {
|
struct ExportTag {
|
||||||
typedef uint32_t type;
|
typedef uint32_t type;
|
||||||
|
|
||||||
|
// Export is implemented in some form and can be used.
|
||||||
static const type kImplemented = 1 << 0;
|
static const type kImplemented = 1 << 0;
|
||||||
static const type kSketchy = 1 << 1;
|
// Export is a stub and is probably bad.
|
||||||
static const type kHighFrequency = 1 << 2;
|
static const type kStub = 1 << 1;
|
||||||
static const type kImportant = 1 << 3;
|
// 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 kThreading = 1 << 10;
|
||||||
static const type kInput = 1 << 11;
|
static const type kInput = 1 << 11;
|
||||||
@@ -34,7 +40,10 @@ struct ExportTag {
|
|||||||
static const type kModules = 1 << 15;
|
static const type kModules = 1 << 15;
|
||||||
static const type kUserProfiles = 1 << 16;
|
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
|
// DEPRECATED
|
||||||
@@ -49,11 +58,12 @@ class Export {
|
|||||||
kVariable = 1,
|
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),
|
: ordinal(ordinal),
|
||||||
type(type),
|
type(type),
|
||||||
name(name),
|
name(name),
|
||||||
tags(0),
|
tags(tags),
|
||||||
variable_ptr(0),
|
variable_ptr(0),
|
||||||
function_data({nullptr, nullptr, 0}) {}
|
function_data({nullptr, nullptr, 0}) {}
|
||||||
|
|
||||||
|
|||||||
22
src/xenia/kernel/util/shim_utils.cc
Normal file
22
src/xenia/kernel/util/shim_utils.cc
Normal file
@@ -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
|
||||||
@@ -10,6 +10,9 @@
|
|||||||
#ifndef XENIA_KERNEL_UTIL_SHIM_UTILS_H_
|
#ifndef XENIA_KERNEL_UTIL_SHIM_UTILS_H_
|
||||||
#define 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/export_resolver.h"
|
||||||
#include "xenia/cpu/frontend/ppc_context.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<uint64_t>(SHIM_MEM_ADDR(a), v)
|
#define SHIM_SET_MEM_64(a, v) xe::store_and_swap<uint64_t>(SHIM_MEM_ADDR(a), v)
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
inline uint32_t get_arg_stack_ptr(PPCContext* ppc_context, uint8_t index) {
|
inline uint32_t get_arg_stack_ptr(PPCContext* ppc_context, uint8_t index) {
|
||||||
return ((uint32_t)ppc_context->r[1]) + 0x54 + index * 8;
|
return ((uint32_t)ppc_context->r[1]) + 0x54 + index * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t get_arg_8(PPCContext* ppc_context, uint8_t index) {
|
inline uint8_t get_arg_8(PPCContext* ppc_context, uint8_t index) {
|
||||||
if (index <= 7) {
|
if (index <= 7) {
|
||||||
return (uint8_t)ppc_context->r[3 + index];
|
return (uint8_t)ppc_context->r[3 + index];
|
||||||
}
|
|
||||||
return SHIM_MEM_8(get_arg_stack_ptr(ppc_context, index - 7));
|
|
||||||
}
|
}
|
||||||
|
return SHIM_MEM_8(get_arg_stack_ptr(ppc_context, index - 7));
|
||||||
|
}
|
||||||
|
|
||||||
inline uint16_t get_arg_16(PPCContext* ppc_context, uint8_t index) {
|
inline uint16_t get_arg_16(PPCContext* ppc_context, uint8_t index) {
|
||||||
if (index <= 7) {
|
if (index <= 7) {
|
||||||
return (uint16_t)ppc_context->r[3 + index];
|
return (uint16_t)ppc_context->r[3 + index];
|
||||||
}
|
|
||||||
return SHIM_MEM_16(get_arg_stack_ptr(ppc_context, index - 7));
|
|
||||||
}
|
}
|
||||||
|
return SHIM_MEM_16(get_arg_stack_ptr(ppc_context, index - 7));
|
||||||
|
}
|
||||||
|
|
||||||
inline uint32_t get_arg_32(PPCContext* ppc_context, uint8_t index) {
|
inline uint32_t get_arg_32(PPCContext* ppc_context, uint8_t index) {
|
||||||
if (index <= 7) {
|
if (index <= 7) {
|
||||||
return (uint32_t)ppc_context->r[3 + index];
|
return (uint32_t)ppc_context->r[3 + index];
|
||||||
}
|
|
||||||
return SHIM_MEM_32(get_arg_stack_ptr(ppc_context, index - 7));
|
|
||||||
}
|
}
|
||||||
|
return SHIM_MEM_32(get_arg_stack_ptr(ppc_context, index - 7));
|
||||||
|
}
|
||||||
|
|
||||||
inline uint64_t get_arg_64(PPCContext* ppc_context, uint8_t index) {
|
inline uint64_t get_arg_64(PPCContext* ppc_context, uint8_t index) {
|
||||||
if (index <= 7) {
|
if (index <= 7) {
|
||||||
return ppc_context->r[3 + index];
|
return ppc_context->r[3 + index];
|
||||||
}
|
|
||||||
return SHIM_MEM_64(get_arg_stack_ptr(ppc_context, index - 7));
|
|
||||||
}
|
}
|
||||||
|
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)
|
#define SHIM_GET_ARG_8(n) util::get_arg_8(ppc_context, n)
|
||||||
@@ -79,6 +82,354 @@ namespace util {
|
|||||||
#define SHIM_STRUCT(type, address) \
|
#define SHIM_STRUCT(type, address) \
|
||||||
reinterpret_cast<type*>(SHIM_MEM_ADDR(address))
|
reinterpret_cast<type*>(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 <typename T>
|
||||||
|
class ParamBase : public Param {
|
||||||
|
public:
|
||||||
|
ParamBase() : Param(), value_(0) {}
|
||||||
|
ParamBase(Init& init) : Param(init) { LoadValue<T>(init); }
|
||||||
|
ParamBase& operator=(const T& other) {
|
||||||
|
value_ = other;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
operator T() const { return value_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename V>
|
||||||
|
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<T>(init.ppc_context->virtual_membase + stack_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
void LoadValue<float>(Init& init) {
|
||||||
|
value_ = init.ppc_context->f[1 + ++init.float_ordinal];
|
||||||
|
}
|
||||||
|
template <>
|
||||||
|
void LoadValue<double>(Init& init) {
|
||||||
|
value_ = init.ppc_context->f[1 + ++init.float_ordinal];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
T value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PointerParam : public ParamBase<uint32_t> {
|
||||||
|
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<uintptr_t>(host_ptr_);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
T as() const {
|
||||||
|
return reinterpret_cast<T>(host_ptr_);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
xe::be<T>* as_array() const {
|
||||||
|
return reinterpret_cast<xe::be<T>*>(host_ptr_);
|
||||||
|
}
|
||||||
|
operator void*() const { return host_ptr_; }
|
||||||
|
operator uint8_t*() const { return reinterpret_cast<uint8_t*>(host_ptr_); }
|
||||||
|
operator bool() const { return host_ptr_ != nullptr; }
|
||||||
|
void* operator+(int offset) const {
|
||||||
|
return reinterpret_cast<uint8_t*>(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 <typename T>
|
||||||
|
class PrimitivePointerParam : public ParamBase<uint32_t> {
|
||||||
|
public:
|
||||||
|
PrimitivePointerParam(Init& init) : ParamBase(init) {
|
||||||
|
host_ptr_ = value_ ? reinterpret_cast<xe::be<T>*>(
|
||||||
|
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<uintptr_t>(host_ptr_);
|
||||||
|
}
|
||||||
|
T value() const { return *host_ptr_; }
|
||||||
|
operator T() const { return *host_ptr_; }
|
||||||
|
operator xe::be<T>*() 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<T>* host_ptr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TypedPointerParam : public ParamBase<uint32_t> {
|
||||||
|
public:
|
||||||
|
TypedPointerParam(Init& init) : ParamBase(init) {
|
||||||
|
host_ptr_ =
|
||||||
|
value_
|
||||||
|
? reinterpret_cast<T*>(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<uintptr_t>(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 <typename T>
|
||||||
|
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<int32_t>&;
|
||||||
|
using dword_param_t = const shim::ParamBase<uint32_t>&;
|
||||||
|
using qword_param_t = const shim::ParamBase<uint64_t>&;
|
||||||
|
using float_param_t = const shim::ParamBase<float>&;
|
||||||
|
using double_param_t = const shim::ParamBase<double>&;
|
||||||
|
using lpvoid_param_t = const shim::PointerParam&;
|
||||||
|
using lpdword_param_t = const shim::PrimitivePointerParam<uint32_t>&;
|
||||||
|
using lpqword_param_t = const shim::PrimitivePointerParam<uint64_t>&;
|
||||||
|
using lpfloat_param_t = const shim::PrimitivePointerParam<float>&;
|
||||||
|
using lpdouble_param_t = const shim::PrimitivePointerParam<double>&;
|
||||||
|
using fn_param_t = const shim::ParamBase<uint32_t>&;
|
||||||
|
using unknown_param_t = const shim::ParamBase<uint32_t>&;
|
||||||
|
using unknown_pointer_param_t = const shim::PointerParam&;
|
||||||
|
template <typename T>
|
||||||
|
using typed_param_t = const shim::TypedPointerParam<T>&;
|
||||||
|
|
||||||
|
using dword_result_t = shim::Result<uint32_t>;
|
||||||
|
using pointer_result_t = shim::Result<uint32_t>;
|
||||||
|
|
||||||
|
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 <typename T>
|
||||||
|
void AppendParam(StringBuffer& string_buffer, typed_param_t<T> param) {
|
||||||
|
string_buffer.AppendFormat("%.8X", param.guest_address());
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class KernelModuleId {
|
||||||
|
xboxkrnl,
|
||||||
|
xam,
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename F, typename Tuple, std::size_t... I>
|
||||||
|
auto KernelTrampoline(F&& f, PPCContext* ppc_context, KernelState* kernel_state,
|
||||||
|
Tuple&& t, std::index_sequence<I...>) {
|
||||||
|
return std::forward<F>(f)(ppc_context, kernel_state,
|
||||||
|
std::get<I>(std::forward<Tuple>(t))...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t I = 0, typename... Ps>
|
||||||
|
typename std::enable_if<I == sizeof...(Ps)>::type AppendKernelCallParams(
|
||||||
|
StringBuffer& string_buffer, xe::cpu::Export* export, const std::tuple<Ps...>&) {}
|
||||||
|
|
||||||
|
template <size_t I = 0, typename... Ps>
|
||||||
|
typename std::enable_if <
|
||||||
|
I<sizeof...(Ps)>::type AppendKernelCallParams(
|
||||||
|
StringBuffer& string_buffer, xe::cpu::Export* export, const std::tuple<Ps...>& params) {
|
||||||
|
if (I) {
|
||||||
|
string_buffer.Append(", ");
|
||||||
|
}
|
||||||
|
auto param = std::get<I>(params);
|
||||||
|
AppendParam(string_buffer, param);
|
||||||
|
AppendKernelCallParams<I + 1>(string_buffer, export, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuffer* thread_local_string_buffer();
|
||||||
|
|
||||||
|
template <typename Tuple>
|
||||||
|
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 <KernelModuleId MODULE, uint16_t ORDINAL, typename R, typename... Ps>
|
||||||
|
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...>(Ps(init)...);
|
||||||
|
if (export->tags & ExportTag::kLog) {
|
||||||
|
PrintKernelCall(export, params);
|
||||||
|
}
|
||||||
|
auto result = KernelTrampoline(FN, ppc_context, ppc_context->kernel_state,
|
||||||
|
std::forward<std::tuple<Ps...>>(params),
|
||||||
|
std::make_index_sequence<sizeof...(Ps)>());
|
||||||
|
result.Store(ppc_context);
|
||||||
|
if (export->tags & (ExportTag::kLog | ExportTag::kLogResult)) {
|
||||||
|
// TODO(benvanik): log result.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export->function_data.trampoline = &X::Trampoline;
|
||||||
|
return export;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <KernelModuleId MODULE, uint16_t ORDINAL, typename... Ps>
|
||||||
|
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...>(Ps(init)...);
|
||||||
|
if (export->tags & ExportTag::kLog) {
|
||||||
|
PrintKernelCall(export, params);
|
||||||
|
}
|
||||||
|
KernelTrampoline(FN, ppc_context, ppc_context->kernel_state,
|
||||||
|
std::forward<std::tuple<Ps...>>(params),
|
||||||
|
std::make_index_sequence<sizeof...(Ps)>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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 kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ namespace xe {
|
|||||||
namespace kernel {
|
namespace kernel {
|
||||||
|
|
||||||
// TODO(benvanik): actually check to see if these are the same.
|
// 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<X_VIDEO_MODE> video_mode);
|
||||||
SHIM_CALL XGetVideoMode_shim(PPCContext* ppc_context,
|
SHIM_CALL XGetVideoMode_shim(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state) {
|
||||||
uint32_t video_mode_ptr = SHIM_GET_ARG_32(0);
|
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);
|
XELOGD("XGetVideoMode(%.8X)", video_mode_ptr);
|
||||||
|
|
||||||
xeVdQueryVideoMode(video_mode);
|
VdQueryVideoMode(ppc_context, kernel_state, video_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHIM_CALL XGetVideoCapabilities_shim(PPCContext* ppc_context,
|
SHIM_CALL XGetVideoCapabilities_shim(PPCContext* ppc_context,
|
||||||
|
|||||||
@@ -36,71 +36,49 @@ using xe::gpu::GraphicsSystem;
|
|||||||
// http://www.microsoft.com/en-za/download/details.aspx?id=5313 -- "Stripped
|
// http://www.microsoft.com/en-za/download/details.aspx?id=5313 -- "Stripped
|
||||||
// Down Direct3D: Xbox 360 Command Buffer and Resource Management"
|
// Down Direct3D: Xbox 360 Command Buffer and Resource Management"
|
||||||
|
|
||||||
SHIM_CALL VdGetCurrentDisplayGamma_shim(PPCContext* ppc_context,
|
void VdGetCurrentDisplayGamma(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t arg0_ptr = SHIM_GET_ARG_32(0);
|
lpdword_param_t arg0_ptr,
|
||||||
uint32_t arg1_ptr = SHIM_GET_ARG_32(1);
|
lpfloat_param_t arg1_ptr) {
|
||||||
|
*arg0_ptr = 2;
|
||||||
XELOGD("VdGetCurrentDisplayGamma(%.8X, %.8X)", arg0_ptr, arg1_ptr);
|
*arg1_ptr = 2.22222233f;
|
||||||
|
|
||||||
SHIM_SET_MEM_32(arg0_ptr, 2);
|
|
||||||
xe::store_and_swap<float>(SHIM_MEM_ADDR(arg1_ptr), 2.22222233f);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdGetCurrentDisplayGamma, ExportTag::kVideo);
|
||||||
|
|
||||||
SHIM_CALL VdGetCurrentDisplayInformation_shim(PPCContext* ppc_context,
|
void VdGetCurrentDisplayInformation(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t ptr = SHIM_GET_ARG_32(0);
|
lpvoid_param_t info_ptr) {
|
||||||
|
auto info = info_ptr.as_array<uint32_t>();
|
||||||
XELOGD("VdGetCurrentDisplayInformation(%.8X)", ptr);
|
|
||||||
|
|
||||||
// Expecting a length 0x58 struct of stuff.
|
// Expecting a length 0x58 struct of stuff.
|
||||||
SHIM_SET_MEM_32(ptr + 0, (1280 << 16) | 720);
|
info[0 / 4] = (1280 << 16) | 720;
|
||||||
SHIM_SET_MEM_32(ptr + 4, 0);
|
info[4 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 8, 0);
|
info[8 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 12, 0);
|
info[12 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 16, 1280); // backbuffer width?
|
info[16 / 4] = 1280; // backbuffer width?
|
||||||
SHIM_SET_MEM_32(ptr + 20, 720); // backbuffer height?
|
info[20 / 4] = 720; // backbuffer height?
|
||||||
SHIM_SET_MEM_32(ptr + 24, 1280);
|
info[24 / 4] = 1280;
|
||||||
SHIM_SET_MEM_32(ptr + 28, 720);
|
info[28 / 4] = 720;
|
||||||
SHIM_SET_MEM_32(ptr + 32, 1);
|
info[32 / 4] = 1;
|
||||||
SHIM_SET_MEM_32(ptr + 36, 0);
|
info[36 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 40, 0);
|
info[40 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 44, 0);
|
info[44 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 48, 1);
|
info[48 / 4] = 1;
|
||||||
SHIM_SET_MEM_32(ptr + 52, 0);
|
info[52 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 56, 0);
|
info[56 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 60, 0);
|
info[60 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 64, 0x014000B4); // ?
|
info[64 / 4] = 0x014000B4; // ?
|
||||||
SHIM_SET_MEM_32(ptr + 68, 0x014000B4); // ?
|
info[68 / 4] = 0x014000B4; // ?
|
||||||
SHIM_SET_MEM_32(ptr + 72, (1280 << 16) | 720); // actual display size?
|
info[72 / 4] = (1280 << 16) | 720; // actual display size?
|
||||||
SHIM_SET_MEM_32(ptr + 76, 0x42700000);
|
info[76 / 4] = 0x42700000;
|
||||||
SHIM_SET_MEM_32(ptr + 80, 0);
|
info[80 / 4] = 0;
|
||||||
SHIM_SET_MEM_32(ptr + 84, 1280); // display width
|
info[84 / 4] = 1280; // display width
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdGetCurrentDisplayInformation, ExportTag::kVideo);
|
||||||
|
|
||||||
void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode);
|
void VdQueryVideoMode(PPCContext* ppc_context, KernelState* kernel_state,
|
||||||
|
typed_param_t<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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: get info from actual display
|
// TODO: get info from actual display
|
||||||
|
video_mode.Zero();
|
||||||
video_mode->display_width = 1280;
|
video_mode->display_width = 1280;
|
||||||
video_mode->display_height = 720;
|
video_mode->display_height = 720;
|
||||||
video_mode->is_interlaced = 0;
|
video_mode->is_interlaced = 0;
|
||||||
@@ -110,274 +88,226 @@ void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode) {
|
|||||||
video_mode->video_standard = 1; // NTSC
|
video_mode->video_standard = 1; // NTSC
|
||||||
video_mode->unknown_0x8a = 0x4A;
|
video_mode->unknown_0x8a = 0x4A;
|
||||||
video_mode->unknown_0x01 = 0x01;
|
video_mode->unknown_0x01 = 0x01;
|
||||||
video_mode->reserved[0] = video_mode->reserved[1] = video_mode->reserved[2] =
|
video_mode->reserved[0] = 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,
|
dword_result_t VdQueryVideoFlags(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state) {
|
||||||
uint32_t video_mode_ptr = SHIM_GET_ARG_32(0);
|
X_VIDEO_MODE mode;
|
||||||
X_VIDEO_MODE* video_mode = (X_VIDEO_MODE*)SHIM_MEM_ADDR(video_mode_ptr);
|
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,
|
dword_result_t VdSetDisplayMode(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state, dword_param_t mode) {
|
||||||
uint32_t mode = SHIM_GET_ARG_32(0);
|
// Often 0x40000000.
|
||||||
|
return 0;
|
||||||
// 40000000
|
|
||||||
XELOGD("VdSetDisplayMode(%.8X)", mode);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(0);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdSetDisplayMode,
|
||||||
|
ExportTag::kVideo | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL VdSetDisplayModeOverride_shim(PPCContext* ppc_context,
|
dword_result_t VdSetDisplayModeOverride(
|
||||||
KernelState* kernel_state) {
|
PPCContext* ppc_context, KernelState* kernel_state, unknown_param_t unk0,
|
||||||
uint32_t unk0 = SHIM_GET_ARG_32(0);
|
unknown_param_t unk1, double_param_t refresh_rate, unknown_param_t unk3,
|
||||||
uint32_t unk1 = SHIM_GET_ARG_32(1);
|
unknown_param_t unk4) {
|
||||||
double refresh_rate = ppc_context->f[1]; // 0, 50, 59.9, etc.
|
// refresh_rate = 0, 50, 59.9, etc.
|
||||||
uint32_t unk3 = SHIM_GET_ARG_32(3);
|
return 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdSetDisplayModeOverride,
|
||||||
|
ExportTag::kVideo | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL VdInitializeEngines_shim(PPCContext* ppc_context,
|
dword_result_t VdInitializeEngines(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t unk0 = SHIM_GET_ARG_32(0);
|
unknown_param_t unk0, fn_param_t callback,
|
||||||
uint32_t callback = SHIM_GET_ARG_32(1);
|
unknown_param_t unk1,
|
||||||
uint32_t unk1 = SHIM_GET_ARG_32(2);
|
unknown_pointer_param_t unk2_ptr,
|
||||||
uint32_t unk2_ptr = SHIM_GET_ARG_32(3);
|
unknown_pointer_param_t unk3_ptr) {
|
||||||
uint32_t unk3_ptr = SHIM_GET_ARG_32(4);
|
|
||||||
|
|
||||||
XELOGD("VdInitializeEngines(%.8X, %.8X, %.8X, %.8X, %.8X)", unk0, callback,
|
|
||||||
unk1, unk2_ptr, unk3_ptr);
|
|
||||||
|
|
||||||
// r3 = 0x4F810000
|
// r3 = 0x4F810000
|
||||||
// r4 = function ptr (cleanup callback?)
|
// r4 = function ptr (cleanup callback?)
|
||||||
// r5 = 0
|
// r5 = 0
|
||||||
// r6/r7 = some binary data in .data
|
// r6/r7 = some binary data in .data
|
||||||
|
return 1;
|
||||||
SHIM_SET_RETURN_32(1);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdInitializeEngines,
|
||||||
|
ExportTag::kVideo | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL VdShutdownEngines_shim(PPCContext* ppc_context,
|
void VdShutdownEngines(PPCContext* ppc_context, KernelState* kernel_state) {
|
||||||
KernelState* kernel_state) {
|
|
||||||
XELOGD("VdShutdownEngines()");
|
|
||||||
|
|
||||||
// Ignored for now.
|
// Ignored for now.
|
||||||
// Games seem to call an Initialize/Shutdown pair to query info, then
|
// Games seem to call an Initialize/Shutdown pair to query info, then
|
||||||
// re-initialize.
|
// 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) {
|
KernelState* kernel_state) {
|
||||||
XELOGD("VdGetGraphicsAsicID()");
|
|
||||||
|
|
||||||
// Games compare for < 0x10 and do VdInitializeEDRAM, else other
|
// Games compare for < 0x10 and do VdInitializeEDRAM, else other
|
||||||
// (retrain/etc).
|
// (retrain/etc).
|
||||||
SHIM_SET_RETURN_32(0x11);
|
return 0x11;
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdGetGraphicsAsicID, ExportTag::kVideo);
|
||||||
|
|
||||||
SHIM_CALL VdEnableDisableClockGating_shim(PPCContext* ppc_context,
|
dword_result_t VdEnableDisableClockGating(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t enabled = SHIM_GET_ARG_32(0);
|
dword_param_t enabled) {
|
||||||
|
|
||||||
XELOGD("VdEnableDisableClockGating(%d)", enabled);
|
|
||||||
|
|
||||||
// Ignored, as it really doesn't matter.
|
// Ignored, as it really doesn't matter.
|
||||||
|
return 0;
|
||||||
SHIM_SET_RETURN_32(0);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdEnableDisableClockGating, ExportTag::kVideo);
|
||||||
|
|
||||||
SHIM_CALL VdSetGraphicsInterruptCallback_shim(PPCContext* ppc_context,
|
void VdSetGraphicsInterruptCallback(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t callback = SHIM_GET_ARG_32(0);
|
fn_param_t callback,
|
||||||
uint32_t user_data = SHIM_GET_ARG_32(1);
|
lpvoid_param_t user_data) {
|
||||||
|
|
||||||
XELOGD("VdSetGraphicsInterruptCallback(%.8X, %.8X)", callback, user_data);
|
|
||||||
|
|
||||||
GraphicsSystem* gs = kernel_state->emulator()->graphics_system();
|
|
||||||
if (!gs) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// callback takes 2 params
|
// callback takes 2 params
|
||||||
// r3 = bool 0/1 - 0 is normal interrupt, 1 is some acquire/lock mumble
|
// r3 = bool 0/1 - 0 is normal interrupt, 1 is some acquire/lock mumble
|
||||||
// r4 = user_data (r4 of VdSetGraphicsInterruptCallback)
|
// r4 = user_data (r4 of VdSetGraphicsInterruptCallback)
|
||||||
|
auto gs = kernel_state->emulator()->graphics_system();
|
||||||
gs->SetInterruptCallback(callback, user_data);
|
if (gs) {
|
||||||
}
|
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;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
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
|
// r3 = result of MmGetPhysicalAddress
|
||||||
// r4 = number of pages? page size?
|
// r4 = number of pages? page size?
|
||||||
// 0x8000 -> cntlzw=16 -> 0x1C - 16 = 12
|
// 0x8000 -> cntlzw=16 -> 0x1C - 16 = 12
|
||||||
// Buffer pointers are from MmAllocatePhysicalMemory with WRITE_COMBINE.
|
// Buffer pointers are from MmAllocatePhysicalMemory with WRITE_COMBINE.
|
||||||
// Sizes could be zero? XBLA games seem to do this. Default sizes?
|
// Sizes could be zero? XBLA games seem to do this. Default sizes?
|
||||||
// D3D does size / region_count - must be > 1024
|
// D3D does size / region_count - must be > 1024
|
||||||
|
auto gs = kernel_state->emulator()->graphics_system();
|
||||||
gs->InitializeRingBuffer(ptr, page_count);
|
if (gs) {
|
||||||
|
gs->InitializeRingBuffer(ptr, page_count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdInitializeRingBuffer, ExportTag::kVideo);
|
||||||
|
|
||||||
SHIM_CALL VdEnableRingBufferRPtrWriteBack_shim(PPCContext* ppc_context,
|
void VdEnableRingBufferRPtrWriteBack(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t ptr = SHIM_GET_ARG_32(0);
|
lpvoid_param_t ptr,
|
||||||
uint32_t block_size = SHIM_GET_ARG_32(1);
|
int_param_t block_size) {
|
||||||
|
auto gs = kernel_state->emulator()->graphics_system();
|
||||||
XELOGD("VdEnableRingBufferRPtrWriteBack(%.8X, %.8X)", ptr, block_size);
|
|
||||||
|
|
||||||
GraphicsSystem* gs = kernel_state->emulator()->graphics_system();
|
|
||||||
if (!gs) {
|
if (!gs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// r4 = 6, usually --- <=19
|
// r4 = 6, usually --- <=19
|
||||||
gs->EnableReadPointerWriteBack(ptr, block_size);
|
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,
|
void VdGetSystemCommandBuffer(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t p0_ptr = SHIM_GET_ARG_32(0);
|
unknown_pointer_param_t p0_ptr,
|
||||||
uint32_t p1_ptr = SHIM_GET_ARG_32(1);
|
unknown_pointer_param_t p1_ptr) {
|
||||||
|
p0_ptr.Zero(0x94);
|
||||||
XELOGD("VdGetSystemCommandBuffer(%.8X, %.8X)", p0_ptr, p1_ptr);
|
xe::store_and_swap<uint32_t>(p0_ptr, 0xBEEF0000);
|
||||||
|
xe::store_and_swap<uint32_t>(p1_ptr, 0xBEEF0001);
|
||||||
std::memset(SHIM_MEM_ADDR(p0_ptr), 0, 0x94);
|
|
||||||
SHIM_SET_MEM_32(p0_ptr, 0xBEEF0000);
|
|
||||||
SHIM_SET_MEM_32(p1_ptr, 0xBEEF0001);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdGetSystemCommandBuffer,
|
||||||
|
ExportTag::kVideo | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL VdSetSystemCommandBufferGpuIdentifierAddress_shim(
|
void VdSetSystemCommandBufferGpuIdentifierAddress(PPCContext* ppc_context,
|
||||||
PPCContext* ppc_context, KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t unk = SHIM_GET_ARG_32(0);
|
unknown_pointer_param_t unk) {
|
||||||
|
|
||||||
XELOGD("VdSetSystemCommandBufferGpuIdentifierAddress(%.8X)", unk);
|
|
||||||
|
|
||||||
// r3 = 0x2B10(d3d?) + 8
|
// r3 = 0x2B10(d3d?) + 8
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdSetSystemCommandBufferGpuIdentifierAddress,
|
||||||
|
ExportTag::kVideo | ExportTag::kStub);
|
||||||
|
|
||||||
// VdVerifyMEInitCommand
|
// VdVerifyMEInitCommand
|
||||||
// r3
|
// r3
|
||||||
// r4 = 19
|
// r4 = 19
|
||||||
// no op?
|
// no op?
|
||||||
|
|
||||||
SHIM_CALL VdInitializeScalerCommandBuffer_shim(PPCContext* ppc_context,
|
dword_result_t VdInitializeScalerCommandBuffer(
|
||||||
KernelState* kernel_state) {
|
PPCContext* ppc_context, KernelState* kernel_state,
|
||||||
uint32_t unk0 = SHIM_GET_ARG_32(0); // 0?
|
unknown_param_t unk0, // 0?
|
||||||
uint32_t unk1 = SHIM_GET_ARG_32(1); // 0x050002d0 size of ?
|
unknown_param_t unk1, // 0x050002d0 size of ?
|
||||||
uint32_t unk2 = SHIM_GET_ARG_32(2); // 0?
|
unknown_param_t unk2, // 0?
|
||||||
uint32_t unk3 = SHIM_GET_ARG_32(3); // 0x050002d0 size of ?
|
unknown_param_t unk3, // 0x050002d0 size of ?
|
||||||
uint32_t unk4 = SHIM_GET_ARG_32(4); // 0x050002d0 size of ?
|
unknown_param_t unk4, // 0x050002d0 size of ?
|
||||||
uint32_t unk5 = SHIM_GET_ARG_32(5); // 7?
|
unknown_param_t unk5, // 7?
|
||||||
uint32_t unk6 = SHIM_GET_ARG_32(6); // 0x2004909c <-- points to zeros?
|
unknown_pointer_param_t unk6, // 0x2004909c <-- points to zeros?
|
||||||
uint32_t unk7 = SHIM_GET_ARG_32(7); // 7?
|
unknown_param_t unk7, // 7?
|
||||||
uint32_t dest_ptr = SHIM_GET_ARG_32(8); // Points to the first 80000000h where the memcpy sources from.
|
lpvoid_param_t dest_ptr // 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);
|
|
||||||
|
|
||||||
// We could fake the commands here, but I'm not sure the game checks for
|
// We could fake the commands here, but I'm not sure the game checks for
|
||||||
// anything but success (non-zero ret).
|
// anything but success (non-zero ret).
|
||||||
// For now, we just fill it with NOPs.
|
// For now, we just fill it with NOPs.
|
||||||
size_t total_words = 0x1CC / 4;
|
uint32_t total_words = 0x1CC / 4;
|
||||||
uint8_t* p = SHIM_MEM_ADDR(dest_ptr);
|
auto dest = dest_ptr.as_array<uint32_t>();
|
||||||
for (size_t i = 0; i < total_words; ++i, p += 4) {
|
for (size_t i = 0; i < total_words; ++i) {
|
||||||
xe::store_and_swap(p, 0x80000000);
|
dest[i] = 0x80000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns memcpy size >> 2 for memcpy(...,...,ret << 2)
|
// 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.
|
// We use these to shuffle data to VdSwap.
|
||||||
// This way it gets properly stored in the command buffer (for replay/etc).
|
// This way it gets properly stored in the command buffer (for replay/etc).
|
||||||
static uint32_t last_frontbuffer_width_ = 1280;
|
uint32_t last_frontbuffer_width_ = 1280;
|
||||||
static uint32_t last_frontbuffer_height_ = 720;
|
uint32_t last_frontbuffer_height_ = 720;
|
||||||
|
|
||||||
SHIM_CALL VdCallGraphicsNotificationRoutines_shim(PPCContext* ppc_context,
|
struct BufferScaling {
|
||||||
KernelState* kernel_state) {
|
xe::be<uint16_t> fb_width;
|
||||||
uint32_t unk_1 = SHIM_GET_ARG_32(0);
|
xe::be<uint16_t> fb_height;
|
||||||
uint32_t args_ptr = SHIM_GET_ARG_32(1);
|
xe::be<uint16_t> bb_width;
|
||||||
|
xe::be<uint16_t> bb_height;
|
||||||
|
};
|
||||||
|
void AppendParam(StringBuffer& string_buffer,
|
||||||
|
typed_param_t<BufferScaling> 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);
|
dword_result_t VdCallGraphicsNotificationRoutines(
|
||||||
|
PPCContext* ppc_context, KernelState* kernel_state, unknown_param_t unk0,
|
||||||
uint16_t fb_width = SHIM_MEM_16(args_ptr + 0);
|
typed_param_t<BufferScaling> args_ptr) {
|
||||||
uint16_t fb_height = SHIM_MEM_16(args_ptr + 2);
|
assert_true(unk0 == 1);
|
||||||
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);
|
|
||||||
|
|
||||||
// TODO(benvanik): what does this mean, I forget:
|
// TODO(benvanik): what does this mean, I forget:
|
||||||
// callbacks get 0, r3, r4
|
// callbacks get 0, r3, r4
|
||||||
|
|
||||||
// For use by VdSwap.
|
// For use by VdSwap.
|
||||||
last_frontbuffer_width_ = fb_width;
|
last_frontbuffer_width_ = args_ptr->fb_width;
|
||||||
last_frontbuffer_height_ = fb_height;
|
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) {
|
KernelState* kernel_state) {
|
||||||
XELOGD("VdIsHSIOTrainingSucceeded()");
|
|
||||||
|
|
||||||
// Not really sure what this should be - code does weird stuff here:
|
// Not really sure what this should be - code does weird stuff here:
|
||||||
// (cntlzw r11, r3 / extrwi r11, r11, 1, 26)
|
// (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,
|
dword_result_t VdPersistDisplay(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state, unknown_param_t unk0,
|
||||||
uint32_t unk0 = SHIM_GET_ARG_32(0);
|
lpdword_param_t unk1_ptr) {
|
||||||
uint32_t unk1_ptr = SHIM_GET_ARG_32(1);
|
|
||||||
|
|
||||||
XELOGD("VdPersistDisplay(%.8X, %.8X)", unk0, unk1_ptr);
|
|
||||||
|
|
||||||
// unk1_ptr needs to be populated with a pointer passed to
|
// unk1_ptr needs to be populated with a pointer passed to
|
||||||
// MmFreePhysicalMemory(1, *unk1_ptr).
|
// MmFreePhysicalMemory(1, *unk1_ptr).
|
||||||
if (unk1_ptr) {
|
if (unk1_ptr) {
|
||||||
@@ -385,112 +315,77 @@ SHIM_CALL VdPersistDisplay_shim(PPCContext* ppc_context,
|
|||||||
uint32_t unk1_value;
|
uint32_t unk1_value;
|
||||||
heap->Alloc(64, 32, kMemoryAllocationReserve | kMemoryAllocationCommit,
|
heap->Alloc(64, 32, kMemoryAllocationReserve | kMemoryAllocationCommit,
|
||||||
kMemoryProtectNoAccess, false, &unk1_value);
|
kMemoryProtectNoAccess, false, &unk1_value);
|
||||||
SHIM_SET_MEM_32(unk1_ptr, unk1_value);
|
*unk1_ptr = unk1_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ?
|
return 1;
|
||||||
SHIM_SET_RETURN_32(1);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdPersistDisplay,
|
||||||
|
ExportTag::kVideo | ExportTag::kSketchy);
|
||||||
|
|
||||||
SHIM_CALL VdRetrainEDRAMWorker_shim(PPCContext* ppc_context,
|
dword_result_t VdRetrainEDRAMWorker(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state,
|
||||||
uint32_t unk0 = SHIM_GET_ARG_32(0);
|
unknown_param_t unk0) {
|
||||||
|
return 0;
|
||||||
XELOGD("VdRetrainEDRAMWorker(%.8X)", unk0);
|
|
||||||
|
|
||||||
SHIM_SET_RETURN_32(0);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdRetrainEDRAMWorker,
|
||||||
|
ExportTag::kVideo | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL VdRetrainEDRAM_shim(PPCContext* ppc_context,
|
dword_result_t VdRetrainEDRAM(PPCContext* ppc_context,
|
||||||
KernelState* kernel_state) {
|
KernelState* kernel_state, unknown_param_t unk0,
|
||||||
uint32_t unk0 = SHIM_GET_ARG_32(0);
|
unknown_param_t unk1, unknown_param_t unk2,
|
||||||
uint32_t unk1 = SHIM_GET_ARG_32(1);
|
unknown_param_t unk3, unknown_param_t unk4,
|
||||||
uint32_t unk2 = SHIM_GET_ARG_32(2);
|
unknown_param_t unk5) {
|
||||||
uint32_t unk3 = SHIM_GET_ARG_32(3);
|
return 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdRetrainEDRAM, ExportTag::kVideo | ExportTag::kStub);
|
||||||
|
|
||||||
SHIM_CALL VdSwap_shim(PPCContext* ppc_context, KernelState* kernel_state) {
|
void VdSwap(
|
||||||
uint32_t buffer_ptr = SHIM_GET_ARG_32(0); // ptr into primary ringbuffer
|
PPCContext* ppc_context, KernelState* kernel_state,
|
||||||
uint32_t fetch_ptr = SHIM_GET_ARG_32(1); // frontbuffer texture fetch
|
lpvoid_param_t buffer_ptr, // ptr into primary ringbuffer
|
||||||
uint32_t unk2 = SHIM_GET_ARG_32(2);
|
lpvoid_param_t fetch_ptr, // frontbuffer texture fetch
|
||||||
uint32_t unk3 = SHIM_GET_ARG_32(3); // buffer from VdGetSystemCommandBuffer
|
unknown_param_t unk2, //
|
||||||
uint32_t unk4 =
|
unknown_pointer_param_t unk3, // buffer from VdGetSystemCommandBuffer
|
||||||
SHIM_GET_ARG_32(4); // pointer from VdGetSystemCommandBuffer (0xBEEF0001)
|
unknown_pointer_param_t unk4, // from VdGetSystemCommandBuffer (0xBEEF0001)
|
||||||
uint32_t frontbuffer_ptr = SHIM_GET_ARG_32(5); // ptr to frontbuffer address
|
lpdword_param_t frontbuffer_ptr, // ptr to frontbuffer address
|
||||||
uint32_t color_format_ptr = SHIM_GET_ARG_32(6);
|
lpdword_param_t color_format_ptr, lpdword_param_t color_space_ptr) {
|
||||||
uint32_t color_space_ptr = SHIM_GET_ARG_32(7);
|
|
||||||
|
|
||||||
uint32_t frontbuffer = SHIM_MEM_32(frontbuffer_ptr);
|
|
||||||
|
|
||||||
gpu::xenos::xe_gpu_texture_fetch_t fetch;
|
gpu::xenos::xe_gpu_texture_fetch_t fetch;
|
||||||
xe::copy_and_swap_32_unaligned((uint32_t*)&fetch,
|
xe::copy_and_swap_32_unaligned(
|
||||||
(uint32_t*)SHIM_MEM_ADDR(fetch_ptr), 6);
|
reinterpret_cast<uint32_t*>(&fetch),
|
||||||
|
reinterpret_cast<uint32_t*>(fetch_ptr.host_address()), 6);
|
||||||
|
|
||||||
auto color_format = (gpu::xenos::ColorFormat)SHIM_MEM_32(color_format_ptr);
|
auto color_format = gpu::xenos::ColorFormat(color_format_ptr.value());
|
||||||
auto color_space = SHIM_MEM_32(color_space_ptr);
|
auto color_space = *color_space_ptr;
|
||||||
assert_true(color_format == gpu::xenos::ColorFormat::k_8_8_8_8);
|
assert_true(color_format == gpu::xenos::ColorFormat::k_8_8_8_8);
|
||||||
assert_true(color_space == 0);
|
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_width_ == 1 + fetch.size_2d.width);
|
||||||
assert_true(last_frontbuffer_height_ == 1 + fetch.size_2d.height);
|
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
|
// 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
|
// 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
|
// 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
|
// that we could simulate it, though due to TCR I bet all games need to
|
||||||
// use this method.
|
// use this method.
|
||||||
std::memset(SHIM_MEM_ADDR(buffer_ptr), 0, 64 * 4);
|
buffer_ptr.Zero(64 * 4);
|
||||||
auto dwords = reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(buffer_ptr));
|
|
||||||
dwords[0] = xe::byte_swap((0x3 << 30) | ((63 - 1) << 16) |
|
auto dwords = buffer_ptr.as_array<uint32_t>();
|
||||||
(xe::gpu::xenos::PM4_XE_SWAP << 8));
|
dwords[0] =
|
||||||
dwords[1] = xe::byte_swap('SWAP');
|
(0x3 << 30) | ((63 - 1) << 16) | (xe::gpu::xenos::PM4_XE_SWAP << 8);
|
||||||
dwords[2] = xe::byte_swap(frontbuffer);
|
dwords[1] = 'SWAP';
|
||||||
|
dwords[2] = *frontbuffer_ptr;
|
||||||
|
|
||||||
// Set by VdCallGraphicsNotificationRoutines.
|
// Set by VdCallGraphicsNotificationRoutines.
|
||||||
dwords[3] = xe::byte_swap(last_frontbuffer_width_);
|
dwords[3] = last_frontbuffer_width_;
|
||||||
dwords[4] = xe::byte_swap(last_frontbuffer_height_);
|
dwords[4] = last_frontbuffer_height_;
|
||||||
}
|
}
|
||||||
|
DECLARE_EXPORT(xboxkrnl, VdSwap, ExportTag::kVideo | ExportTag::kImportant);
|
||||||
|
|
||||||
} // namespace kernel
|
} // namespace kernel
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
void xe::kernel::xboxkrnl::RegisterVideoExports(
|
void xe::kernel::xboxkrnl::RegisterVideoExports(
|
||||||
xe::cpu::ExportResolver* export_resolver, KernelState* kernel_state) {
|
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();
|
Memory* memory = kernel_state->memory();
|
||||||
|
|
||||||
// VdGlobalDevice (4b)
|
// VdGlobalDevice (4b)
|
||||||
|
|||||||
Reference in New Issue
Block a user