Merge branch 'master' into vulkan

This commit is contained in:
Triang3l 2021-07-03 20:59:25 +03:00
commit 9bb104b354
73 changed files with 1611 additions and 873 deletions

View File

@ -8,6 +8,7 @@ skip_tags: true
skip_commits:
files:
- .drone.yml
- .github/**
- .travis.yml
- docs/**

214
.drone.yml Normal file
View File

@ -0,0 +1,214 @@
---
kind: pipeline
type: docker
name: lint
# Run this in a separate pipeline so that it will build even if this fails
steps:
- name: lint
image: xeniaproject/buildenv:2021-06-21
commands:
- clang-format --version
- ./xenia-build lint --all
---
kind: pipeline
type: docker
name: x86_64-linux
platform:
os: linux
arch: amd64
# Some expressions in this file are duplicates. Scripting support is
# available using jsonnet but increases complexity
# https://docs.drone.io/pipeline/scripting/jsonnet/
# These volumes will be mounted at the build directory, allowing to
# run different premake toolchains from the same source tree
volumes:
- name: build-premake
temp: {}
- name: build-cmake
temp: {}
steps:
#
# Setup the source tree
#
- name: clone-submodules
image: xeniaproject/buildenv:2021-06-21
commands:
- pwd
# May miss recursive submodules (but faster than xb setup)
- git submodule update --init --depth 1 -j $(nproc)
#
# Setup the two build systems
#
# Native premake Makefiles for production
- name: toolchain-premake
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-premake
path: /drone/src/build
commands:
- $CXX --version
- $AR --version
- python3 --version
- ./xenia-build premake
depends_on:
- clone-submodules
# Development toolchain
- name: toolchain-cmake
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-cmake
path: /drone/src/build
commands:
- |
./xenia-build premake --devenv=cmake
cd build
for c in Debug Release
do
mkdir cmake-$c
cd cmake-$c
cmake -DCMAKE_BUILD_TYPE=$c ..
cd ..
done
depends_on:
# Premake itself needs to be build first:
- toolchain-premake
#
# Building
#
- name: build-premake-debug-all
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-premake
path: /drone/src/build
commands:
- ./xenia-build build --no_premake -j$(nproc) --config=Debug
depends_on:
- toolchain-premake
- name: build-premake-release-tests
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-premake
path: /drone/src/build
commands:
- ./xenia-build build --no_premake -j$(nproc) --config=Release --target=xenia-base-tests
depends_on:
- toolchain-premake
- name: build-premake-release-all
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-premake
path: /drone/src/build
commands:
- ./xenia-build build --no_premake -j$(nproc) --config=Release
depends_on:
- build-premake-release-tests
- name: build-cmake-debug-all
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-cmake
path: /drone/src/build
commands:
- cd build/cmake-Debug
- cmake --build . -j$(nproc)
depends_on:
- toolchain-cmake
- name: build-cmake-release-tests
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-cmake
path: /drone/src/build
commands:
- cd build/cmake-Release
- cmake --build . -j$(nproc) --target xenia-base-tests
depends_on:
- toolchain-cmake
- name: build-cmake-release-all
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-cmake
path: /drone/src/build
commands:
- cd build/cmake-Release
- cmake --build . -j$(nproc)
depends_on:
- build-cmake-release-tests
#
# Tests
#
- name: test-premake
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-premake
path: /drone/src/build
commands:
- ./build/bin/Linux/Release/xenia-base-tests
depends_on:
- build-premake-release-tests
- name: test-cmake
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-cmake
path: /drone/src/build
commands:
- ./build/bin/Linux/Release/xenia-base-tests
depends_on:
- build-cmake-release-tests
#
# Stat
#
- name: stat
image: xeniaproject/buildenv:2021-06-21
volumes:
- name: build-premake
path: /build-premake
- name: build-cmake
path: /build-cmake
commands:
- |
header() {
SEP='============================================================'
echo
echo $SEP
echo $@
echo $SEP
}
for v in premake cmake
do
for c in Debug Release
do
header $v $c
p=/build-$v/bin/Linux/$c
ls -la $p
sha256sum $p/*
done
done
depends_on:
- build-premake-debug-all
- build-premake-release-all
- build-cmake-debug-all
- build-cmake-release-all

View File

@ -1,73 +0,0 @@
# Make Travis use docker (for faster builds, in theory).
language: cpp
os:
- linux
dist: bionic
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-9
packages:
- clang-9
- clang-format-9
- llvm-9-dev
- g++-8
- python3
- libc++-dev
- libc++abi-dev
- libgtk-3-dev
- libpthread-stubs0-dev
- libsdl2-dev
#- libvulkan1
#- libvulkan-dev
- libx11-dev
- liblz4-dev
jobs:
include:
- env: C_COMPILER=clang-9 CXX_COMPILER=clang++-9 AR_COMPILER=llvm-ar-9 LINT=true
- env: C_COMPILER=clang-9 CXX_COMPILER=clang++-9 AR_COMPILER=llvm-ar-9 BUILD=true CONFIG=Debug
- env: C_COMPILER=clang-9 CXX_COMPILER=clang++-9 AR_COMPILER=llvm-ar-9 BUILD=true CONFIG=Release
git:
# We handle submodules ourselves in xenia-build setup.
submodules: false
before_script:
- export LIBVULKAN_VERSION=1.1.70
- export CXX=$CXX_COMPILER
- export CC=$C_COMPILER
- export AR=$AR_COMPILER
# Dump useful info.
- $CXX --version
- $AR_COMPILER --version
- python3 --version
- clang-format-9 --version
- clang-format-9 -style=file -dump-config
# Add Vulkan dependencies.
- travis_retry wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan1_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb
- travis_retry wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan-dev_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb
- if [[ $BUILD == true ]]; then sudo dpkg -i libvulkan1_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb libvulkan-dev_$LIBVULKAN_VERSION+dfsg1-1_amd64.deb; fi
# Prepare environment (pull dependencies, build tools).
- travis_retry ./xenia-build setup
script:
# Run linter.
- if [[ $LINT == true ]]; then ./xenia-build lint --all; fi
# Build and run base tests.
- if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-base-tests; fi
- if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-base-tests; fi
# Build and run ppc tests.
- if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG --target=xenia-cpu-ppc-tests; fi
# - if [[ $BUILD == true ]]; then ./build/bin/Linux/$CONFIG/xenia-cpu-ppc-tests --log_file=stdout; fi
# Build all of xenia.
- if [[ $BUILD == true ]]; then ./xenia-build build --config=$CONFIG; fi
# All tests (without haswell support).
#- ./xenia-build test --config=debug --no-build -- --enable_haswell_instructions=false
# All tests (with haswell support).
#- ./xenia-build test --config=debug --no-build -- --enable_haswell_instructions=true

View File

@ -24,7 +24,7 @@ Discussing illegal activities will get you banned.
Buildbot | Status
-------- | ------
[Windows](https://ci.appveyor.com/project/benvanik/xenia/branch/master) | [![Build status](https://ci.appveyor.com/api/projects/status/ftqiy86kdfawyx3a/branch/master?svg=true)](https://ci.appveyor.com/project/benvanik/xenia/branch/master)
[Linux](https://travis-ci.org/xenia-project/xenia) | [![Build status](https://travis-ci.org/xenia-project/xenia.svg?branch=master)](https://travis-ci.org/xenia-project/xenia)
[Linux](https://cloud.drone.io/xenia-project/xenia) | [![Build status](https://cloud.drone.io/api/badges/xenia-project/xenia/status.svg)](https://cloud.drone.io/xenia-project/xenia)
Quite a few real games run. Quite a few don't.
See the [Game compatibility list](https://github.com/xenia-project/game-compatibility/issues)

View File

@ -24,6 +24,7 @@
#include "xenia/ui/file_picker.h"
#include "xenia/ui/imgui_dialog.h"
#include "xenia/ui/imgui_drawer.h"
#include "xenia/ui/virtual_key.h"
// Autogenerated by `xb premake`.
#include "build/version.h"
@ -93,49 +94,49 @@ bool EmulatorWindow::Initialize() {
window_->on_key_down.AddListener([this](KeyEvent* e) {
bool handled = true;
switch (e->key_code()) {
case 0x4F: { // o
switch (e->virtual_key()) {
case ui::VirtualKey::kO: {
if (e->is_ctrl_pressed()) {
FileOpen();
}
} break;
case 0x6A: { // numpad *
case ui::VirtualKey::kMultiply: {
CpuTimeScalarReset();
} break;
case 0x6D: { // numpad minus
case ui::VirtualKey::kSubtract: {
CpuTimeScalarSetHalf();
} break;
case 0x6B: { // numpad plus
case ui::VirtualKey::kAdd: {
CpuTimeScalarSetDouble();
} break;
case 0x72: { // F3
case ui::VirtualKey::kF3: {
Profiler::ToggleDisplay();
} break;
case 0x73: { // VK_F4
case ui::VirtualKey::kF4: {
GpuTraceFrame();
} break;
case 0x74: { // VK_F5
case ui::VirtualKey::kF5: {
GpuClearCaches();
} break;
case 0x76: { // VK_F7
case ui::VirtualKey::kF7: {
// Save to file
// TODO: Choose path based on user input, or from options
// TODO: Spawn a new thread to do this.
emulator()->SaveToFile("test.sav");
} break;
case 0x77: { // VK_F8
case ui::VirtualKey::kF8: {
// Restore from file
// TODO: Choose path from user
// TODO: Spawn a new thread to do this.
emulator()->RestoreFromFile("test.sav");
} break;
case 0x7A: { // VK_F11
case ui::VirtualKey::kF11: {
ToggleFullscreen();
} break;
case 0x1B: { // VK_ESCAPE
// Allow users to escape fullscreen (but not enter it).
case ui::VirtualKey::kEscape: {
// Allow users to escape fullscreen (but not enter it).
if (window_->is_fullscreen()) {
window_->ToggleFullscreen(false);
} else {
@ -143,18 +144,18 @@ bool EmulatorWindow::Initialize() {
}
} break;
case 0x13: { // VK_PAUSE
case ui::VirtualKey::kPause: {
CpuBreakIntoDebugger();
} break;
case 0x03: { // VK_CANCEL
case ui::VirtualKey::kCancel: {
CpuBreakIntoHostDebugger();
} break;
case 0x70: { // VK_F1
case ui::VirtualKey::kF1: {
ShowHelpWebsite();
} break;
case 0x71: { // VK_F2
case ui::VirtualKey::kF2: {
ShowCommitID();
} break;

View File

@ -123,7 +123,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
sizeof(XMA_CONTEXT_DATA) * kContextCount, 256, kSystemHeapPhysical);
context_data_last_ptr_ =
context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
register_file_[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32 =
register_file_[XmaRegister::ContextArrayAddress] =
memory()->GetPhysicalAddress(context_data_first_ptr_);
// Setup XMA contexts.
@ -134,7 +134,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
assert_always();
}
}
register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32 = 1;
register_file_[XmaRegister::NextContextIndex] = 1;
context_bitmap_.Resize(kContextCount);
worker_running_ = true;
@ -254,27 +254,29 @@ bool XmaDecoder::BlockOnContext(uint32_t guest_ptr, bool poll) {
}
uint32_t XmaDecoder::ReadRegister(uint32_t addr) {
uint32_t r = (addr & 0xFFFF) / 4;
auto r = (addr & 0xFFFF) / 4;
assert_true(r < XmaRegisterFile::kRegisterCount);
switch (r) {
case XE_XMA_REG_CURRENT_CONTEXT_INDEX: {
case XmaRegister::ContextArrayAddress:
break;
case XmaRegister::CurrentContextIndex: {
// 0606h (1818h) is rotating context processing # set to hardware ID of
// context being processed.
// If bit 200h is set, the locking code will possibly collide on hardware
// IDs and error out, so we should never set it (I think?).
uint32_t& current_context_index =
register_file_[XE_XMA_REG_CURRENT_CONTEXT_INDEX].u32;
register_file_[XmaRegister::CurrentContextIndex];
uint32_t& next_context_index =
register_file_[XE_XMA_REG_NEXT_CONTEXT_INDEX].u32;
register_file_[XmaRegister::NextContextIndex];
// To prevent games from seeing a stuck XMA context, return a rotating
// number.
current_context_index = next_context_index;
next_context_index = (next_context_index + 1) % kContextCount;
break;
}
default: {
default:
const auto register_info = register_file_.GetRegisterInfo(r);
if (register_info) {
XELOGW("XMA: Read from unhandled register ({:04X}, {})", r,
@ -283,10 +285,9 @@ uint32_t XmaDecoder::ReadRegister(uint32_t addr) {
XELOGW("XMA: Read from unknown register ({:04X})", r);
}
break;
}
}
return xe::byte_swap(register_file_.values[r].u32);
return xe::byte_swap(register_file_[r]);
}
void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
@ -296,16 +297,16 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
value = xe::byte_swap(value);
assert_true(r < XmaRegisterFile::kRegisterCount);
register_file_.values[r].u32 = value;
register_file_[r] = value;
if (r >= XE_XMA_REG_CONTEXT_KICK_0 && r <= XE_XMA_REG_CONTEXT_KICK_9) {
if (r >= XmaRegister::Context0Kick && r <= XmaRegister::Context9Kick) {
// Context kick command.
// This will kick off the given hardware contexts.
// Basically, this kicks the SPU and says "hey, decode that audio!"
// XMAEnableContext
// The context ID is a bit in the range of the entire context array.
uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_KICK_0) * 32;
uint32_t base_context_id = (r - XmaRegister::Context0Kick) * 32;
for (int i = 0; value && i < 32; ++i, value >>= 1) {
if (value & 1) {
uint32_t context_id = base_context_id + i;
@ -315,11 +316,11 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
}
// Signal the decoder thread to start processing.
work_event_->Set();
} else if (r >= XE_XMA_REG_CONTEXT_LOCK_0 && r <= XE_XMA_REG_CONTEXT_LOCK_9) {
} else if (r >= XmaRegister::Context0Lock && r <= XmaRegister::Context9Lock) {
// Context lock command.
// This requests a lock by flagging the context.
// XMADisableContext
uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_LOCK_0) * 32;
uint32_t base_context_id = (r - XmaRegister::Context0Lock) * 32;
for (int i = 0; value && i < 32; ++i, value >>= 1) {
if (value & 1) {
uint32_t context_id = base_context_id + i;
@ -328,12 +329,12 @@ void XmaDecoder::WriteRegister(uint32_t addr, uint32_t value) {
}
}
// Signal the decoder thread to start processing.
work_event_->Set();
} else if (r >= XE_XMA_REG_CONTEXT_CLEAR_0 &&
r <= XE_XMA_REG_CONTEXT_CLEAR_9) {
// work_event_->Set();
} else if (r >= XmaRegister::Context0Clear &&
r <= XmaRegister::Context9Clear) {
// Context clear command.
// This will reset the given hardware contexts.
uint32_t base_context_id = (r - XE_XMA_REG_CONTEXT_CLEAR_0) * 32;
uint32_t base_context_id = (r - XmaRegister::Context0Clear) * 32;
for (int i = 0; value && i < 32; ++i, value >>= 1) {
if (value & 1) {
uint32_t context_id = base_context_id + i;

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -37,7 +37,7 @@ class XmaDecoder {
void Shutdown();
uint32_t context_array_ptr() const {
return register_file_.values[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32;
return register_file_[XmaRegister::ContextArrayAddress];
}
uint32_t AllocateContext();

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -20,10 +20,9 @@ XmaRegisterFile::XmaRegisterFile() { std::memset(values, 0, sizeof(values)); }
const XmaRegisterInfo* XmaRegisterFile::GetRegisterInfo(uint32_t index) {
switch (index) {
#define XE_XMA_REGISTER(index, type, name) \
#define XE_XMA_REGISTER(index, name) \
case index: { \
static const XmaRegisterInfo reg_info = { \
XmaRegisterInfo::Type::type, \
#name, \
}; \
return &reg_info; \

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -16,18 +16,13 @@
namespace xe {
namespace apu {
enum XmaRegister {
#define XE_XMA_REGISTER(index, type, name) XE_XMA_REG_##name = index,
struct XmaRegister {
#define XE_XMA_REGISTER(index, name) static const uint32_t name = index;
#include "xenia/apu/xma_register_table.inc"
#undef XE_XMA_REGISTER
};
struct XmaRegisterInfo {
enum class Type {
kDword,
kFloat,
};
Type type;
const char* name;
};
@ -38,14 +33,10 @@ class XmaRegisterFile {
static const XmaRegisterInfo* GetRegisterInfo(uint32_t index);
static const size_t kRegisterCount = (0xFFFF + 1) / 4;
union RegisterValue {
uint32_t u32;
float f32;
};
RegisterValue values[kRegisterCount];
uint32_t values[kRegisterCount];
RegisterValue& operator[](int reg) { return values[reg]; }
RegisterValue& operator[](XmaRegister reg) { return values[reg]; }
uint32_t operator[](uint32_t reg) const { return values[reg]; }
uint32_t& operator[](uint32_t reg) { return values[reg]; }
};
} // namespace apu

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -10,42 +10,72 @@
// This is a partial file designed to be included by other files when
// constructing various tables.
//#define XE_XMA_REGISTER(index, type, name)
#ifndef XE_XMA_REGISTER
#define XE_XMA_REGISTER(index, name)
#define __XE_XMA_REGISTER_UNSET
#endif
XE_XMA_REGISTER(0x0600, kDword, CONTEXT_ARRAY_ADDRESS)
#ifndef XE_XMA_REGISTER_CONTEXT_GROUP
#define XE_XMA_REGISTER_CONTEXT_GROUP(index, suffix) \
XE_XMA_REGISTER(index + 0, Context0##suffix) \
XE_XMA_REGISTER(index + 1, Context1##suffix) \
XE_XMA_REGISTER(index + 2, Context2##suffix) \
XE_XMA_REGISTER(index + 3, Context3##suffix) \
XE_XMA_REGISTER(index + 4, Context4##suffix) \
XE_XMA_REGISTER(index + 5, Context5##suffix) \
XE_XMA_REGISTER(index + 6, Context6##suffix) \
XE_XMA_REGISTER(index + 7, Context7##suffix) \
XE_XMA_REGISTER(index + 8, Context8##suffix) \
XE_XMA_REGISTER(index + 9, Context9##suffix)
#endif
XE_XMA_REGISTER(0x0606, kDword, CURRENT_CONTEXT_INDEX)
XE_XMA_REGISTER(0x0607, kDword, NEXT_CONTEXT_INDEX)
// 0x0000..0x001F : ???
// 0x0020..0x03FF : all 0xFFs?
// 0x0400..0x043F : ???
// 0x0440..0x047F : all 0xFFs?
// 0x0480..0x048B : ???
// 0x048C..0x04C0 : all 0xFFs?
// 0x04C1..0x04CB : ???
// 0x04CC..0x04FF : all 0xFFs?
// 0x0500..0x051F : ???
// 0x0520..0x057F : all 0xFFs?
// 0x0580..0x058F : ???
// 0x0590..0x05FF : all 0xFFs?
XE_XMA_REGISTER(0x0650, kDword, CONTEXT_KICK_0)
XE_XMA_REGISTER(0x0651, kDword, CONTEXT_KICK_1)
XE_XMA_REGISTER(0x0652, kDword, CONTEXT_KICK_2)
XE_XMA_REGISTER(0x0653, kDword, CONTEXT_KICK_3)
XE_XMA_REGISTER(0x0654, kDword, CONTEXT_KICK_4)
XE_XMA_REGISTER(0x0655, kDword, CONTEXT_KICK_5)
XE_XMA_REGISTER(0x0656, kDword, CONTEXT_KICK_6)
XE_XMA_REGISTER(0x0657, kDword, CONTEXT_KICK_7)
XE_XMA_REGISTER(0x0658, kDword, CONTEXT_KICK_8)
XE_XMA_REGISTER(0x0659, kDword, CONTEXT_KICK_9)
// XMA stuff is probably only 0x0600..0x06FF
//---------------------------------------------------------------------------//
XE_XMA_REGISTER(0x0690, kDword, CONTEXT_LOCK_0)
XE_XMA_REGISTER(0x0691, kDword, CONTEXT_LOCK_1)
XE_XMA_REGISTER(0x0692, kDword, CONTEXT_LOCK_2)
XE_XMA_REGISTER(0x0693, kDword, CONTEXT_LOCK_3)
XE_XMA_REGISTER(0x0694, kDword, CONTEXT_LOCK_4)
XE_XMA_REGISTER(0x0695, kDword, CONTEXT_LOCK_5)
XE_XMA_REGISTER(0x0696, kDword, CONTEXT_LOCK_6)
XE_XMA_REGISTER(0x0697, kDword, CONTEXT_LOCK_7)
XE_XMA_REGISTER(0x0698, kDword, CONTEXT_LOCK_8)
XE_XMA_REGISTER(0x0699, kDword, CONTEXT_LOCK_9)
XE_XMA_REGISTER(0x0600, ContextArrayAddress)
// 0x0601..0x0605 : ???
XE_XMA_REGISTER(0x0606, CurrentContextIndex)
XE_XMA_REGISTER(0x0607, NextContextIndex)
// 0x0608 : ???
// 0x0609..0x060F : zero?
XE_XMA_REGISTER_CONTEXT_GROUP(0x0610, Unknown610)
// 0x061A..0x061F : zero?
XE_XMA_REGISTER_CONTEXT_GROUP(0x0620, Unknown620)
// 0x062A..0x0641 : zero?
// 0x0642..0x0644 : ???
// 0x0645..0x064F : zero?
XE_XMA_REGISTER_CONTEXT_GROUP(0x0650, Kick)
// 0x065A..0x065F : zero?
XE_XMA_REGISTER_CONTEXT_GROUP(0x0660, Unknown660)
// 0x066A..0x0681 : zero?
// 0x0682..0x0684 : ???
// 0x0685..0x068F : zero?
XE_XMA_REGISTER_CONTEXT_GROUP(0x0690, Lock)
// 0x069A..0x069F : zero?
XE_XMA_REGISTER_CONTEXT_GROUP(0x06A0, Clear)
XE_XMA_REGISTER(0x06A0, kDword, CONTEXT_CLEAR_0)
XE_XMA_REGISTER(0x06A1, kDword, CONTEXT_CLEAR_1)
XE_XMA_REGISTER(0x06A2, kDword, CONTEXT_CLEAR_2)
XE_XMA_REGISTER(0x06A3, kDword, CONTEXT_CLEAR_3)
XE_XMA_REGISTER(0x06A4, kDword, CONTEXT_CLEAR_4)
XE_XMA_REGISTER(0x06A5, kDword, CONTEXT_CLEAR_5)
XE_XMA_REGISTER(0x06A6, kDword, CONTEXT_CLEAR_6)
XE_XMA_REGISTER(0x06A7, kDword, CONTEXT_CLEAR_7)
XE_XMA_REGISTER(0x06A8, kDword, CONTEXT_CLEAR_8)
XE_XMA_REGISTER(0x06A9, kDword, CONTEXT_CLEAR_9)
//---------------------------------------------------------------------------//
// 0x0700..0x07FF : all 0xFFs?
// 0x0800..0x17FF : ???
// 0x1800..0x2FFF : all 0xFFs?
// 0x3000..0x30FF : ???
// 0x3100..0x3FFF : all 0xFFs?
#ifdef __XE_XMA_REGISTER_UNSET
#undef __XE_XMA_REGISTER_UNSET
#undef XE_XMA_REGISTER
#endif

View File

@ -81,20 +81,23 @@ inline T byte_swap(T value) {
template <typename T, std::endian E>
struct endian_store {
endian_store() = default;
endian_store(const T& src) {
endian_store(const T& src) { set(src); }
endian_store(const endian_store& other) { set(other); }
operator T() const { return get(); }
void set(const T& src) {
if constexpr (std::endian::native == E) {
value = src;
} else {
value = xe::byte_swap(src);
}
}
endian_store(const endian_store& other) { value = other.value; }
operator T() const {
void set(const endian_store& other) { value = other.value; }
T get() const {
if constexpr (std::endian::native == E) {
return value;
} else {
return xe::byte_swap(value);
}
return xe::byte_swap(value);
}
endian_store<T, E>& operator+=(int a) {

View File

@ -20,18 +20,19 @@ ByteStream::ByteStream(uint8_t* data, size_t data_length, size_t offset)
ByteStream::~ByteStream() = default;
void ByteStream::Advance(size_t num_bytes) { offset_ += num_bytes; }
void ByteStream::Advance(size_t num_bytes) {
assert_true(offset_ + num_bytes <= data_length_);
offset_ += num_bytes;
}
void ByteStream::Read(uint8_t* buf, size_t len) {
assert_true(offset_ < data_length_);
assert_true(offset_ + len <= data_length_);
std::memcpy(buf, data_ + offset_, len);
Advance(len);
}
void ByteStream::Write(const uint8_t* buf, size_t len) {
assert_true(offset_ < data_length_);
assert_true(offset_ + len <= data_length_);
std::memcpy(data_ + offset_, buf, len);
Advance(len);
}
@ -41,7 +42,6 @@ std::string ByteStream::Read() {
std::string str;
uint32_t len = Read<uint32_t>();
str.resize(len);
Read(reinterpret_cast<uint8_t*>(&str[0]), len);
return str;
}
@ -49,9 +49,8 @@ std::string ByteStream::Read() {
template <>
std::u16string ByteStream::Read() {
std::u16string str;
uint32_t len = Read<uint32_t>();
size_t len = Read<uint32_t>();
str.resize(len);
Read(reinterpret_cast<uint8_t*>(&str[0]), len * 2);
return str;
}

View File

@ -14,6 +14,10 @@
#define UTF_CPP_CPLUSPLUS 201703L
#include "third_party/utfcpp/source/utf8.h"
#include "xenia/base/logging.h"
#include "xenia/base/main.h"
#include "xenia/base/system.h"
namespace utfcpp = utf8;
using u8_citer = utfcpp::iterator<std::string_view::const_iterator>;
@ -61,7 +65,14 @@ void ParseLaunchArguments(int& argc, char**& argv,
auto result = options.parse(argc, argv);
if (result.count("help")) {
PrintHelpAndExit();
xe::AttachConsole();
if (xe::has_console_attached()) {
PrintHelpAndExit();
} else {
xe::ShowSimpleMessageBox(xe::SimpleMessageBoxType::Help,
options.help({""}));
exit(0);
}
}
for (auto& it : *CmdVars) {
@ -78,8 +89,16 @@ void ParseLaunchArguments(int& argc, char**& argv,
}
}
} catch (const cxxopts::OptionException& e) {
std::cout << e.what() << std::endl;
PrintHelpAndExit();
xe::AttachConsole();
if (xe::has_console_attached()) {
std::cout << e.what() << std::endl;
PrintHelpAndExit();
} else {
std::string m =
"Invalid launch options were given.\n" + options.help({""});
xe::ShowSimpleMessageBox(xe::SimpleMessageBoxType::Error, m);
exit(0);
}
}
}

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- Automatically convert endianness for xe::be -->
<Type Name="xe::be&lt;unsigned __int64&gt;">
<!-- Automatically convert endianness for xe::endian_store<,1> -->
<Type Name="xe::endian_store&lt;unsigned __int64, 1&gt;">
<DisplayString>
{(((value &amp; 0xFF00000000000000) &gt;&gt; 56) |
((value &amp; 0x00FF000000000000) &gt;&gt; 40) |
@ -14,7 +14,7 @@
((value &amp; 0x00000000000000FF) &lt;&lt; 56))}
</DisplayString>
</Type>
<Type Name="xe::be&lt;__int64&gt;">
<Type Name="xe::endian_store&lt;__int64, 1&gt;">
<DisplayString>
{(((value &amp; 0xFF00000000000000) &gt;&gt; 56) |
((value &amp; 0x00FF000000000000) &gt;&gt; 40) |
@ -27,7 +27,7 @@
</DisplayString>
</Type>
<Type Name="xe::be&lt;unsigned int&gt;">
<Type Name="xe::endian_store&lt;unsigned int, 1&gt;">
<DisplayString>
{(((value &amp; 0xFF000000) &gt;&gt; 24) |
((value &amp; 0x00FF0000) &gt;&gt; 8) |
@ -35,7 +35,7 @@
((value &amp; 0x000000FF) &lt;&lt; 24))}
</DisplayString>
</Type>
<Type Name="xe::be&lt;int&gt;">
<Type Name="xe::endian_store&lt;int, 1&gt;">
<DisplayString>
{(((value &amp; 0xFF000000) &gt;&gt; 24) |
((value &amp; 0x00FF0000) &gt;&gt; 8) |
@ -44,25 +44,25 @@
</DisplayString>
</Type>
<Type Name="xe::be&lt;unsigned short&gt;">
<Type Name="xe::endian_store&lt;unsigned short, 1&gt;">
<DisplayString>
{(((value &amp; 0xFF00) &gt;&gt; 8) |
((value &amp; 0x00FF) &lt;&lt; 8))}
</DisplayString>
</Type>
<Type Name="xe::be&lt;short&gt;">
<Type Name="xe::endian_store&lt;short, 1&gt;">
<DisplayString>
{(((value &amp; 0xFF00) &gt;&gt; 8) |
((value &amp; 0x00FF) &lt;&lt; 8))}
</DisplayString>
</Type>
<Type Name="xe::be&lt;unsigned char&gt;">
<Type Name="xe::endian_store&lt;unsigned char, 1&gt;">
<DisplayString>
{value}
</DisplayString>
</Type>
<Type Name="xe::be&lt;char&gt;">
<Type Name="xe::endian_store&lt;char, 1&gt;">
<DisplayString>
{value}
</DisplayString>

View File

@ -26,6 +26,7 @@
#include "xenia/base/memory.h"
#include "xenia/base/ring_buffer.h"
#include "xenia/base/string.h"
#include "xenia/base/system.h"
#include "xenia/base/threading.h"
// For MessageBox:
@ -58,7 +59,7 @@ struct LogLine {
size_t buffer_length;
uint32_t thread_id;
uint16_t _pad_0; // (2b) padding
uint8_t _pad_1; // (1b) padding
bool terminate;
char prefix_char;
};
@ -81,8 +82,7 @@ class Logger {
explicit Logger(const std::string_view app_name)
: wait_strategy_(),
claim_strategy_(kBlockCount, wait_strategy_),
consumed_(wait_strategy_),
running_(true) {
consumed_(wait_strategy_) {
claim_strategy_.add_claim_barrier(consumed_);
write_thread_ =
@ -91,7 +91,7 @@ class Logger {
}
~Logger() {
running_ = false;
AppendLine(0, '\0', nullptr, 0, true); // append a terminator
xe::threading::Wait(write_thread_.get(), true);
}
@ -124,7 +124,6 @@ class Logger {
std::vector<std::unique_ptr<LogSink>> sinks_;
std::atomic<bool> running_;
std::unique_ptr<xe::threading::Thread> write_thread_;
void Write(const char* buf, size_t size) {
@ -153,35 +152,30 @@ class Logger {
auto available_sequence = claim_strategy_.wait_until_published(
next_range.last(), last_sequence);
auto available_difference =
dp::difference(available_sequence, next_sequence);
size_t read_count = 0;
auto available_range = next_range;
auto available_count = available_range.size();
if (available_difference > 0 &&
static_cast<size_t>(available_difference) >= desired_count) {
auto available_range = dp::sequence_range(
next_sequence, static_cast<size_t>(available_difference));
auto available_count = available_range.size();
rb.set_write_offset(BlockOffset(available_range.end()));
rb.set_write_offset(BlockOffset(available_range.end()));
bool terminate = false;
for (size_t i = available_range.first(); i != available_range.end();) {
rb.set_read_offset(BlockOffset(i));
for (size_t i = available_range.first(); i != available_range.end();) {
rb.set_read_offset(BlockOffset(i));
LogLine line;
rb.Read(&line, sizeof(line));
LogLine line;
rb.Read(&line, sizeof(line));
auto needed_count = BlockCount(sizeof(LogLine) + line.buffer_length);
if (read_count + needed_count > available_count) {
// More blocks are needed for a complete line.
desired_count = needed_count;
break;
} else {
// Enough blocks to read this log line, advance by that many.
read_count += needed_count;
i += needed_count;
auto needed_count = BlockCount(sizeof(LogLine) + line.buffer_length);
if (read_count + needed_count > available_count) {
// More blocks are needed for a complete line.
desired_count = needed_count;
break;
} else {
// Enough blocks to read this log line, advance by that many.
read_count += needed_count;
i += needed_count;
if (line.prefix_char) {
char prefix[] = {
line.prefix_char,
'>',
@ -200,44 +194,53 @@ class Logger {
fmt::format_to_n(prefix + 3, sizeof(prefix) - 3, "{:08X}",
line.thread_id);
Write(prefix, sizeof(prefix) - 1);
}
if (line.buffer_length) {
// Get access to the line data - which may be split in the ring
// buffer - and write it out in parts.
auto line_range = rb.BeginRead(line.buffer_length);
Write(reinterpret_cast<const char*>(line_range.first),
line_range.first_length);
if (line_range.second_length) {
Write(reinterpret_cast<const char*>(line_range.second),
line_range.second_length);
}
if (line.buffer_length) {
// Get access to the line data - which may be split in the ring
// buffer - and write it out in parts.
auto line_range = rb.BeginRead(line.buffer_length);
Write(reinterpret_cast<const char*>(line_range.first),
line_range.first_length);
if (line_range.second_length) {
Write(reinterpret_cast<const char*>(line_range.second),
line_range.second_length);
}
// Always ensure there is a newline.
char last_char =
line_range.second
? line_range.second[line_range.second_length - 1]
: line_range.first[line_range.first_length - 1];
if (last_char != '\n') {
const char suffix[1] = {'\n'};
Write(suffix, 1);
}
rb.EndRead(std::move(line_range));
} else {
// Always ensure there is a newline.
// Always ensure there is a newline.
char last_char =
line_range.second
? line_range.second[line_range.second_length - 1]
: line_range.first[line_range.first_length - 1];
if (last_char != '\n') {
const char suffix[1] = {'\n'};
Write(suffix, 1);
}
rb.EndRead(std::move(line_range));
} else {
// Always ensure there is a newline.
const char suffix[1] = {'\n'};
Write(suffix, 1);
}
if (line.terminate) {
terminate = true;
break;
}
}
}
if (terminate) {
break;
}
if (read_count) {
// Advance by the number of blocks we read.
auto read_range = dp::sequence_range(next_sequence, read_count);
next_sequence = read_range.end();
last_sequence = read_range.last();
consumed_.publish(read_range.last());
consumed_.publish(last_sequence);
desired_count = 1;
@ -249,9 +252,6 @@ class Logger {
idle_loops = 0;
} else {
if (!running_) {
break;
}
if (idle_loops >= 1000) {
// Introduce a waiting period.
xe::threading::Sleep(std::chrono::milliseconds(50));
@ -264,7 +264,8 @@ class Logger {
public:
void AppendLine(uint32_t thread_id, const char prefix_char,
const char* buffer_data, size_t buffer_length) {
const char* buffer_data, size_t buffer_length,
bool terminate = false) {
size_t count = BlockCount(sizeof(LogLine) + buffer_length);
auto range = claim_strategy_.claim(count);
@ -278,9 +279,12 @@ class Logger {
line.buffer_length = buffer_length;
line.thread_id = thread_id;
line.prefix_char = prefix_char;
line.terminate = terminate;
rb.Write(&line, sizeof(LogLine));
rb.Write(buffer_data, buffer_length);
if (buffer_length) {
rb.Write(buffer_data, buffer_length);
}
claim_strategy_.publish(range);
}
@ -350,12 +354,10 @@ void logging::AppendLogLine(LogLevel log_level, const char prefix_char,
void FatalError(const std::string_view str) {
logging::AppendLogLine(LogLevel::Error, 'X', str);
#if XE_PLATFORM_WIN32
if (!xe::has_console_attached()) {
MessageBoxW(NULL, (LPCWSTR)xe::to_utf16(str).c_str(), L"Xenia Error",
MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
ShowSimpleMessageBox(SimpleMessageBoxType::Error, str);
}
#endif // WIN32
ShutdownLogging();
std::exit(1);
}

View File

@ -22,6 +22,8 @@ namespace xe {
// Returns true if there is a user-visible console attached to receive stdout.
bool has_console_attached();
void AttachConsole();
// Extern defined by user code. This must be present for the application to
// launch.
struct EntryInfo {

View File

@ -7,6 +7,9 @@
******************************************************************************
*/
#include <stdio.h>
#include <unistd.h>
#include "xenia/base/cvar.h"
#include "xenia/base/main.h"
@ -16,7 +19,9 @@
namespace xe {
bool has_console_attached() { return true; }
bool has_console_attached() { return isatty(fileno(stdin)) == 1; }
void AttachConsole() {}
} // namespace xe

View File

@ -38,8 +38,22 @@ bool has_console_attached_ = true;
bool has_console_attached() { return has_console_attached_; }
bool has_shell_environment_variable() {
size_t size = 0;
// Check if SHELL exists
// If it doesn't, then we are in a Windows Terminal
auto error = getenv_s(&size, nullptr, 0, "SHELL");
if (error) {
return false;
}
return !!size;
}
void AttachConsole() {
if (!cvars::enable_console) {
bool has_console = ::AttachConsole(ATTACH_PARENT_PROCESS) == TRUE;
if (!has_console || !has_shell_environment_variable()) {
// We weren't launched from a console, so just return.
has_console_attached_ = false;
return;
}
@ -127,7 +141,9 @@ int Main() {
// Attach a console so we can write output to stdout. If the user hasn't
// redirected output themselves it'll pop up a window.
xe::AttachConsole();
if (cvars::enable_console) {
xe::AttachConsole();
}
// Setup COM on the main thread.
// NOTE: this may fail if COM has already been initialized - that's OK.

View File

@ -30,6 +30,7 @@
#include "xenia/base/assert.h"
#include "xenia/base/cvar.h"
#include "xenia/base/profiling.h"
#include "xenia/ui/virtual_key.h"
#include "xenia/ui/window.h"
#if XE_OPTION_PROFILING
@ -112,31 +113,35 @@ void Profiler::ThreadEnter(const char* name) {
void Profiler::ThreadExit() { MicroProfileOnThreadExit(); }
bool Profiler::OnKeyDown(int key_code) {
bool Profiler::OnKeyDown(ui::VirtualKey virtual_key) {
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
switch (key_code) {
case VK_OEM_3: // `
switch (virtual_key) {
case ui::VirtualKey::kOem3: // `
MicroProfileTogglePause();
return true;
#if XE_OPTION_PROFILING_UI
case VK_TAB:
case ui::VirtualKey::kTab:
MicroProfileToggleDisplayMode();
return true;
case 0x31: // 1
case ui::VirtualKey::k1:
MicroProfileModKey(1);
return true;
#endif // XE_OPTION_PROFILING_UI
default:
break;
}
return false;
}
bool Profiler::OnKeyUp(int key_code) {
switch (key_code) {
bool Profiler::OnKeyUp(ui::VirtualKey virtual_key) {
switch (virtual_key) {
#if XE_OPTION_PROFILING_UI
case 0x31: // 1
case ui::VirtualKey::k1:
MicroProfileModKey(0);
return true;
#endif // XE_OPTION_PROFILING_UI
default:
break;
}
return false;
}
@ -219,14 +224,14 @@ void Profiler::set_window(ui::Window* window) {
// Watch for toggle/mode keys and such.
window_->on_key_down.AddListener([](ui::KeyEvent* e) {
if (Profiler::is_visible()) {
Profiler::OnKeyDown(e->key_code());
Profiler::OnKeyDown(e->virtual_key());
e->set_handled(true);
window_->Invalidate();
}
});
window_->on_key_up.AddListener([](ui::KeyEvent* e) {
if (Profiler::is_visible()) {
Profiler::OnKeyUp(e->key_code());
Profiler::OnKeyUp(e->virtual_key());
e->set_handled(true);
window_->Invalidate();
}
@ -257,8 +262,8 @@ void Profiler::Shutdown() {}
uint32_t Profiler::GetColor(const char* str) { return 0; }
void Profiler::ThreadEnter(const char* name) {}
void Profiler::ThreadExit() {}
bool Profiler::OnKeyDown(int key_code) { return false; }
bool Profiler::OnKeyUp(int key_code) { return false; }
bool Profiler::OnKeyDown(ui::VirtualKey virtual_key) { return false; }
bool Profiler::OnKeyUp(ui::VirtualKey virtual_key) { return false; }
void Profiler::OnMouseDown(bool left_button, bool right_button) {}
void Profiler::OnMouseUp() {}
void Profiler::OnMouseMove(int x, int y) {}

View File

@ -13,6 +13,7 @@
#include <memory>
#include "xenia/base/string.h"
#include "xenia/ui/virtual_key.h"
#if XE_PLATFORM_WIN32
#define XE_OPTION_PROFILING 1
@ -171,8 +172,8 @@ class Profiler {
// Deactivates the calling thread for profiling.
static void ThreadExit();
static bool OnKeyDown(int key_code);
static bool OnKeyUp(int key_code);
static bool OnKeyDown(ui::VirtualKey virtual_key);
static bool OnKeyUp(ui::VirtualKey virtual_key);
static void OnMouseDown(bool left_button, bool right_button);
static void OnMouseUp();
static void OnMouseMove(int x, int y);

View File

@ -11,15 +11,24 @@
#define XENIA_BASE_SYSTEM_H_
#include <filesystem>
#include <string>
#include <string_view>
#include "xenia/base/string.h"
namespace xe {
void LaunchWebBrowser(const std::string& url);
void LaunchWebBrowser(const std::string_view url);
void LaunchFileExplorer(const std::filesystem::path& path);
enum class SimpleMessageBoxType {
Help,
Warning,
Error,
};
// This is expected to block the caller until the message box is closed.
void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message);
} // namespace xe
#endif // XENIA_BASE_SYSTEM_H_

View File

@ -7,22 +7,64 @@
******************************************************************************
*/
#include <alloca.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include "xenia/base/assert.h"
#include "xenia/base/platform_linux.h"
#include "xenia/base/logging.h"
#include "xenia/base/string.h"
#include "xenia/base/system.h"
// Use headers in third party to not depend on system sdl headers for building
#include "third_party/SDL2/include/SDL.h"
namespace xe {
void LaunchWebBrowser(const std::string& url) {
auto cmd = "xdg-open " + url;
void LaunchWebBrowser(const std::string_view url) {
auto cmd = std::string("xdg-open ");
cmd.append(url);
system(cmd.c_str());
}
void LaunchFileExplorer(const std::filesystem::path& path) { assert_always(); }
void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) {
void* libsdl2 = dlopen("libSDL2.so", RTLD_LAZY | RTLD_LOCAL);
assert_not_null(libsdl2);
if (libsdl2) {
auto* pSDL_ShowSimpleMessageBox =
reinterpret_cast<decltype(SDL_ShowSimpleMessageBox)*>(
dlsym(libsdl2, "SDL_ShowSimpleMessageBox"));
assert_not_null(pSDL_ShowSimpleMessageBox);
if (pSDL_ShowSimpleMessageBox) {
Uint32 flags;
const char* title;
char* message_copy = reinterpret_cast<char*>(alloca(message.size() + 1));
std::memcpy(message_copy, message.data(), message.size());
message_copy[message.size()] = '\0';
switch (type) {
default:
case SimpleMessageBoxType::Help:
title = "Xenia Help";
flags = SDL_MESSAGEBOX_INFORMATION;
break;
case SimpleMessageBoxType::Warning:
title = "Xenia Warning";
flags = SDL_MESSAGEBOX_WARNING;
break;
case SimpleMessageBoxType::Error:
title = "Xenia Error";
flags = SDL_MESSAGEBOX_ERROR;
break;
}
pSDL_ShowSimpleMessageBox(flags, title, message_copy, NULL);
}
dlclose(libsdl2);
}
}
} // namespace xe

View File

@ -13,9 +13,9 @@
namespace xe {
void LaunchWebBrowser(const std::string& url) {
auto temp = xe::to_utf16(url);
ShellExecuteW(nullptr, L"open", reinterpret_cast<LPCWSTR>(temp.c_str()),
void LaunchWebBrowser(const std::string_view url) {
auto wide_url = xe::to_utf16(url);
ShellExecuteW(nullptr, L"open", reinterpret_cast<LPCWSTR>(wide_url.c_str()),
nullptr, nullptr, SW_SHOWNORMAL);
}
@ -24,4 +24,28 @@ void LaunchFileExplorer(const std::filesystem::path& url) {
SW_SHOWNORMAL);
}
void ShowSimpleMessageBox(SimpleMessageBoxType type,
const std::string_view message) {
const wchar_t* title;
std::u16string wide_message = xe::to_utf16(message);
DWORD type_flags = MB_OK | MB_APPLMODAL | MB_SETFOREGROUND;
switch (type) {
default:
case SimpleMessageBoxType::Help:
title = L"Xenia Help";
type_flags |= MB_ICONINFORMATION;
break;
case SimpleMessageBoxType::Warning:
title = L"Xenia Warning";
type_flags |= MB_ICONWARNING;
break;
case SimpleMessageBoxType::Error:
title = L"Xenia Error";
type_flags |= MB_ICONERROR;
break;
}
MessageBoxW(nullptr, reinterpret_cast<LPCWSTR>(wide_message.c_str()), title,
type_flags);
}
} // namespace xe

View File

@ -25,6 +25,14 @@ std::shared_ptr<cpptoml::table> ParseFile(
throw cpptoml::parse_exception(xe::path_to_utf8(filename) +
" could not be opened for parsing");
}
// since cpptoml can't parse files with a UTF-8 BOM we need to skip them
char bom[3];
file.read(bom, sizeof(bom));
if (file.fail() || bom[0] != '\xEF' || bom[1] != '\xBB' || bom[2] != '\xBF') {
file.clear();
file.seekg(0);
}
cpptoml::parser p(file);
return p.parse();
}

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -245,65 +245,34 @@ void Value::Convert(TypeName target_type, RoundMode round_mode) {
}
}
template <typename T>
T __inline RoundValue(RoundMode round_mode, T value) {
switch (round_mode) {
case ROUND_TO_ZERO:
return std::trunc(value);
case ROUND_TO_NEAREST:
return std::round(value);
case ROUND_TO_MINUS_INFINITY:
return std::floor(value);
case ROUND_TO_POSITIVE_INFINITY:
return std::ceil(value);
default:
assert_unhandled_case(round_mode);
return value;
}
}
void Value::Round(RoundMode round_mode) {
switch (type) {
case FLOAT32_TYPE:
switch (round_mode) {
case ROUND_TO_ZERO:
constant.f32 = std::trunc(constant.f32);
break;
case ROUND_TO_NEAREST:
constant.f32 = std::round(constant.f32);
return;
case ROUND_TO_MINUS_INFINITY:
constant.f32 = std::floor(constant.f32);
break;
case ROUND_TO_POSITIVE_INFINITY:
constant.f32 = std::ceil(constant.f32);
break;
default:
assert_unhandled_case(round_mode);
return;
}
constant.f32 = RoundValue(round_mode, constant.f32);
return;
case FLOAT64_TYPE:
switch (round_mode) {
case ROUND_TO_ZERO:
constant.f64 = std::trunc(constant.f64);
break;
case ROUND_TO_NEAREST:
constant.f64 = std::round(constant.f64);
return;
case ROUND_TO_MINUS_INFINITY:
constant.f64 = std::floor(constant.f64);
break;
case ROUND_TO_POSITIVE_INFINITY:
constant.f64 = std::ceil(constant.f64);
break;
default:
assert_unhandled_case(round_mode);
return;
}
constant.f64 = RoundValue(round_mode, constant.f64);
return;
case VEC128_TYPE:
for (int i = 0; i < 4; i++) {
switch (round_mode) {
case ROUND_TO_ZERO:
constant.v128.f32[i] = std::trunc(constant.v128.f32[i]);
break;
case ROUND_TO_NEAREST:
constant.v128.f32[i] = std::round(constant.v128.f32[i]);
break;
case ROUND_TO_MINUS_INFINITY:
constant.v128.f32[i] = std::floor(constant.v128.f32[i]);
break;
case ROUND_TO_POSITIVE_INFINITY:
constant.v128.f32[i] = std::ceil(constant.v128.f32[i]);
break;
default:
assert_unhandled_case(round_mode);
return;
}
constant.v128.f32[i] = RoundValue(round_mode, constant.v128.f32[i]);
}
return;
default:
@ -426,8 +395,9 @@ void Value::MulHi(Value* other, bool is_unsigned) {
(uint32_t)other->constant.i32) >>
32);
} else {
constant.i32 = (int32_t)(
((int64_t)constant.i32 * (int64_t)other->constant.i32) >> 32);
constant.i32 =
(int32_t)(((int64_t)constant.i32 * (int64_t)other->constant.i32) >>
32);
}
break;
case INT64_TYPE:

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -426,6 +426,10 @@ int InstrEmit_sc(PPCHIRBuilder& f, const InstrData& i) {
// Game code should only ever use LEV=0.
// LEV=2 is to signify 'call import' from Xenia.
// TODO(gibbed): syscalls!
if (i.SC.LEV == 0) {
f.CallExtern(f.builtins()->syscall_handler);
return 0;
}
if (i.SC.LEV == 2) {
f.CallExtern(f.function());
return 0;
@ -806,6 +810,6 @@ void RegisterEmitCategoryControl() {
XEREGISTERINSTR(mtmsrd);
}
} // namespace ppc
} // namespace cpu
} // namespace xe
} // namespace xe

View File

@ -10,6 +10,7 @@
#include "xenia/cpu/ppc/ppc_frontend.h"
#include "xenia/base/atomic.h"
#include "xenia/base/logging.h"
#include "xenia/cpu/ppc/ppc_context.h"
#include "xenia/cpu/ppc/ppc_emit.h"
#include "xenia/cpu/ppc/ppc_opcode_info.h"
@ -78,6 +79,17 @@ void LeaveGlobalLock(PPCContext* ppc_context, void* arg0, void* arg1) {
global_mutex->unlock();
}
void SyscallHandler(PPCContext* ppc_context, void* arg0, void* arg1) {
uint64_t syscall_number = ppc_context->r[0];
switch (syscall_number) {
default:
assert_unhandled_case(syscall_number);
XELOGE("Unhandled syscall {}!", syscall_number);
break;
#pragma warning(suppress : 4065)
}
}
bool PPCFrontend::Initialize() {
void* arg0 = reinterpret_cast<void*>(&xe::global_critical_region::mutex());
void* arg1 = reinterpret_cast<void*>(&builtins_.global_lock_count);
@ -87,6 +99,8 @@ bool PPCFrontend::Initialize() {
processor_->DefineBuiltin("EnterGlobalLock", EnterGlobalLock, arg0, arg1);
builtins_.leave_global_lock =
processor_->DefineBuiltin("LeaveGlobalLock", LeaveGlobalLock, arg0, arg1);
builtins_.syscall_handler = processor_->DefineBuiltin(
"SyscallHandler", SyscallHandler, nullptr, nullptr);
return true;
}

View File

@ -33,6 +33,7 @@ struct PPCBuiltins {
Function* check_global_lock;
Function* enter_global_lock;
Function* leave_global_lock;
Function* syscall_handler;
};
class PPCFrontend {

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -832,9 +832,10 @@ int XexModule::ReadPEHeaders() {
// offsetof seems to be unable to find OptionalHeader.
#define offsetof1(type, member) ((std::size_t) & (((type*)0)->member))
#define IMAGE_FIRST_SECTION1(ntheader) \
((PIMAGE_SECTION_HEADER)( \
(uint8_t*)ntheader + offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \
((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader))
((PIMAGE_SECTION_HEADER)((uint8_t*)ntheader + \
offsetof1(IMAGE_NT_HEADERS, OptionalHeader) + \
((PIMAGE_NT_HEADERS)(ntheader)) \
->FileHeader.SizeOfOptionalHeader))
// Quick scan to determine bounds of sections.
size_t upper_address = 0;

View File

@ -517,6 +517,10 @@ bool CommandProcessor::ExecutePacket(RingBuffer* reader) {
return true;
}
if (packet == 0xCDCDCDCD) {
XELOGW("GPU packet is CDCDCDCD - probably read uninitialized memory!");
}
switch (packet_type) {
case 0x00:
return ExecutePacketType0(reader, packet);

View File

@ -507,10 +507,15 @@ union alignas(uint32_t) PA_SC_WINDOW_SCISSOR_BR {
static_assert_size(PA_SC_WINDOW_SCISSOR_BR, sizeof(uint32_t));
/*******************************************************************************
___ ___
| _ \ _ )
| / _ \
|_|_\___/
___ ___ _ _ ___ ___ ___
| _ \ __| \| | \| __| _ \
| / _|| .` | |) | _|| /
|_|_\___|_|\_|___/|___|_|_\
___ _ ___ _ _____ _ _ ___
| _ ) /_\ / __| |/ / __| \| | \
| _ \/ _ \ (__| ' <| _|| .` | |) |
|___/_/ \_\___|_|\_\___|_|\_|___/
*******************************************************************************/

View File

@ -28,6 +28,7 @@
#include "xenia/memory.h"
#include "xenia/ui/file_picker.h"
#include "xenia/ui/imgui_drawer.h"
#include "xenia/ui/virtual_key.h"
#include "xenia/ui/window.h"
#include "xenia/xbox.h"
@ -135,7 +136,7 @@ bool TraceViewer::Setup() {
window_->set_imgui_input_enabled(true);
window_->on_key_char.AddListener([&](xe::ui::KeyEvent* e) {
if (e->key_code() == 0x74 /* VK_F5 */) {
if (e->virtual_key() == xe::ui::VirtualKey::kF5) {
graphics_system_->ClearCaches();
e->set_handled(true);
}

View File

@ -194,10 +194,10 @@ enum class SurfaceNumFormat : uint32_t {
kFloat = 7,
};
// The EDRAM is an opaque block of memory accessible by the RB pipeline stage of
// the GPU, which performs output-merger functionality (color render target
// writing and blending, depth and stencil testing) and resolve (copy)
// operations.
// The EDRAM is an opaque block of memory accessible by the RB (render backend)
// pipeline stage of the GPU, which performs output-merger functionality (color
// render target writing and blending, depth and stencil testing) and resolve
// (copy) operations.
//
// Data in the 10 MiB of EDRAM is laid out as 2048 tiles on 80x16 32bpp MSAA
// samples. With 2x MSAA, one pixel consists of 1x2 samples, and with 4x, it

View File

@ -10,8 +10,8 @@
#include <array>
#include <cstring>
#include <forward_list>
#include <map>
#include <tuple>
#include <unordered_map>
#include "third_party/fmt/include/fmt/format.h"
#include "third_party/imgui/imgui.h"
@ -23,6 +23,7 @@
#include "xenia/hid/hid_flags.h"
#include "xenia/hid/input_system.h"
#include "xenia/ui/imgui_drawer.h"
#include "xenia/ui/virtual_key.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
#include "xenia/ui/window.h"
@ -281,44 +282,42 @@ void DrawInputGetState() {
ImGui::EndChild();
}
static const std::map<std::underlying_type<X_INPUT_GAMEPAD_VK>::type,
const std::string>
vk_pretty = {
{X_INPUT_GAMEPAD_VK_A, "A"},
{X_INPUT_GAMEPAD_VK_B, "B"},
{X_INPUT_GAMEPAD_VK_X, "X"},
{X_INPUT_GAMEPAD_VK_Y, "Y"},
{X_INPUT_GAMEPAD_VK_RSHOULDER, "R Shoulder"},
{X_INPUT_GAMEPAD_VK_LSHOULDER, "L Shoulder"},
{X_INPUT_GAMEPAD_VK_LTRIGGER, "L Trigger"},
{X_INPUT_GAMEPAD_VK_RTRIGGER, "R Trigger"},
static const std::unordered_map<ui::VirtualKey, const std::string> kVkPretty = {
{ui::VirtualKey::kXInputPadA, "A"},
{ui::VirtualKey::kXInputPadB, "B"},
{ui::VirtualKey::kXInputPadX, "X"},
{ui::VirtualKey::kXInputPadY, "Y"},
{ui::VirtualKey::kXInputPadRShoulder, "R Shoulder"},
{ui::VirtualKey::kXInputPadLShoulder, "L Shoulder"},
{ui::VirtualKey::kXInputPadLTrigger, "L Trigger"},
{ui::VirtualKey::kXInputPadRTrigger, "R Trigger"},
{X_INPUT_GAMEPAD_VK_DPAD_UP, "DPad up"},
{X_INPUT_GAMEPAD_VK_DPAD_DOWN, "DPad down"},
{X_INPUT_GAMEPAD_VK_DPAD_LEFT, "DPad left"},
{X_INPUT_GAMEPAD_VK_DPAD_RIGHT, "DPad right"},
{X_INPUT_GAMEPAD_VK_START, "Start"},
{X_INPUT_GAMEPAD_VK_BACK, "Back"},
{X_INPUT_GAMEPAD_VK_LTHUMB_PRESS, "L Thumb press"},
{X_INPUT_GAMEPAD_VK_RTHUMB_PRESS, "R Thumb press"},
{ui::VirtualKey::kXInputPadDpadUp, "DPad up"},
{ui::VirtualKey::kXInputPadDpadDown, "DPad down"},
{ui::VirtualKey::kXInputPadDpadLeft, "DPad left"},
{ui::VirtualKey::kXInputPadDpadRight, "DPad right"},
{ui::VirtualKey::kXInputPadStart, "Start"},
{ui::VirtualKey::kXInputPadBack, "Back"},
{ui::VirtualKey::kXInputPadLThumbPress, "L Thumb press"},
{ui::VirtualKey::kXInputPadRThumbPress, "R Thumb press"},
{X_INPUT_GAMEPAD_VK_LTHUMB_UP, "L Thumb up"},
{X_INPUT_GAMEPAD_VK_LTHUMB_DOWN, "L Thumb down"},
{X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT, "L Thumb right"},
{X_INPUT_GAMEPAD_VK_LTHUMB_LEFT, "L Thumb left"},
{X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT, "L Thumb up & left"},
{X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT, "L Thumb up & right"},
{X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT, "L Thumb down & right"},
{X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT, "L Thumb down & left"},
{ui::VirtualKey::kXInputPadLThumbUp, "L Thumb up"},
{ui::VirtualKey::kXInputPadLThumbDown, "L Thumb down"},
{ui::VirtualKey::kXInputPadLThumbRight, "L Thumb right"},
{ui::VirtualKey::kXInputPadLThumbLeft, "L Thumb left"},
{ui::VirtualKey::kXInputPadLThumbUpLeft, "L Thumb up & left"},
{ui::VirtualKey::kXInputPadLThumbUpRight, "L Thumb up & right"},
{ui::VirtualKey::kXInputPadLThumbDownRight, "L Thumb down & right"},
{ui::VirtualKey::kXInputPadLThumbDownLeft, "L Thumb down & left"},
{X_INPUT_GAMEPAD_VK_RTHUMB_UP, "R Thumb up"},
{X_INPUT_GAMEPAD_VK_RTHUMB_DOWN, "R Thumb down"},
{X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT, "R Thumb right"},
{X_INPUT_GAMEPAD_VK_RTHUMB_LEFT, "R Thumb left"},
{X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT, "R Thumb up & left"},
{X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT, "R Thumb up & right"},
{X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT, "R Thumb down & right"},
{X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT, "R Thumb down & left"},
{ui::VirtualKey::kXInputPadRThumbUp, "R Thumb up"},
{ui::VirtualKey::kXInputPadRThumbDown, "R Thumb down"},
{ui::VirtualKey::kXInputPadRThumbRight, "R Thumb right"},
{ui::VirtualKey::kXInputPadRThumbLeft, "R Thumb left"},
{ui::VirtualKey::kXInputPadRThumbUpLeft, "R Thumb up & left"},
{ui::VirtualKey::kXInputPadRThumbUpRight, "R Thumb up & right"},
{ui::VirtualKey::kXInputPadRThumbDownRight, "R Thumb down & right"},
{ui::VirtualKey::kXInputPadRThumbDownLeft, "R Thumb down & left"},
};
void DrawUserInputGetKeystroke(uint32_t user_index, bool poll,
@ -354,10 +353,12 @@ void DrawUserInputGetKeystroke(uint32_t user_index, bool poll,
break;
}
const auto key_search = vk_pretty.find(stroke.virtual_key);
const auto key = key_search != vk_pretty.end()
? key_search->second
: fmt::format("0x{:04x}", stroke.virtual_key);
ui::VirtualKey virtual_key = ui::VirtualKey(stroke.virtual_key.get());
const auto key_search = kVkPretty.find(virtual_key);
std::string key =
key_search != kVkPretty.cend()
? key_search->second
: fmt::format("0x{:04x}", uint16_t(virtual_key));
event_log.emplace_front(fmt::format(
"{:>6} {:>9}ms {:<20} {} {} {}", ImGui::GetFrameCount(),
dur, key,

View File

@ -46,43 +46,7 @@ enum X_INPUT_GAMEPAD_BUTTON {
X_INPUT_GAMEPAD_Y = 0x8000,
};
enum X_INPUT_GAMEPAD_VK {
X_INPUT_GAMEPAD_VK_A = 0x5800,
X_INPUT_GAMEPAD_VK_B = 0x5801,
X_INPUT_GAMEPAD_VK_X = 0x5802,
X_INPUT_GAMEPAD_VK_Y = 0x5803,
X_INPUT_GAMEPAD_VK_RSHOULDER = 0x5804,
X_INPUT_GAMEPAD_VK_LSHOULDER = 0x5805,
X_INPUT_GAMEPAD_VK_LTRIGGER = 0x5806,
X_INPUT_GAMEPAD_VK_RTRIGGER = 0x5807,
X_INPUT_GAMEPAD_VK_DPAD_UP = 0x5810,
X_INPUT_GAMEPAD_VK_DPAD_DOWN = 0x5811,
X_INPUT_GAMEPAD_VK_DPAD_LEFT = 0x5812,
X_INPUT_GAMEPAD_VK_DPAD_RIGHT = 0x5813,
X_INPUT_GAMEPAD_VK_START = 0x5814,
X_INPUT_GAMEPAD_VK_BACK = 0x5815,
X_INPUT_GAMEPAD_VK_LTHUMB_PRESS = 0x5816,
X_INPUT_GAMEPAD_VK_RTHUMB_PRESS = 0x5817,
X_INPUT_GAMEPAD_VK_LTHUMB_UP = 0x5820,
X_INPUT_GAMEPAD_VK_LTHUMB_DOWN = 0x5821,
X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT = 0x5822,
X_INPUT_GAMEPAD_VK_LTHUMB_LEFT = 0x5823,
X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT = 0x5824,
X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT = 0x5825,
X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT = 0x5826,
X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT = 0x5827,
X_INPUT_GAMEPAD_VK_RTHUMB_UP = 0x5830,
X_INPUT_GAMEPAD_VK_RTHUMB_DOWN = 0x5831,
X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT = 0x5832,
X_INPUT_GAMEPAD_VK_RTHUMB_LEFT = 0x5833,
X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT = 0x5834,
X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT = 0x5835,
X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT = 0x5836,
X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT = 0x5837,
};
// For VK_PAD, use ui::VirtualKey.
enum X_INPUT_KEYSTROKE_FLAGS {
X_INPUT_KEYSTROKE_KEYDOWN = 0x0001,

View File

@ -20,6 +20,7 @@
#include "xenia/base/logging.h"
#include "xenia/helper/sdl/sdl_helper.h"
#include "xenia/hid/hid_flags.h"
#include "xenia/ui/virtual_key.h"
#include "xenia/ui/window.h"
// TODO(joellinn) make this path relative to the config folder.
@ -238,48 +239,46 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
// The order of this list is also the order in which events are send if
// multiple buttons change at once.
static_assert(sizeof(X_INPUT_GAMEPAD::buttons) == 2);
static constexpr std::array<std::underlying_type<X_INPUT_GAMEPAD_VK>::type,
34>
vk_lookup = {
// 00 - True buttons from xinput button field
X_INPUT_GAMEPAD_VK_DPAD_UP,
X_INPUT_GAMEPAD_VK_DPAD_DOWN,
X_INPUT_GAMEPAD_VK_DPAD_LEFT,
X_INPUT_GAMEPAD_VK_DPAD_RIGHT,
X_INPUT_GAMEPAD_VK_START,
X_INPUT_GAMEPAD_VK_BACK,
X_INPUT_GAMEPAD_VK_LTHUMB_PRESS,
X_INPUT_GAMEPAD_VK_RTHUMB_PRESS,
X_INPUT_GAMEPAD_VK_LSHOULDER,
X_INPUT_GAMEPAD_VK_RSHOULDER,
0, /* Guide has no VK */
0, /* Unknown */
X_INPUT_GAMEPAD_VK_A,
X_INPUT_GAMEPAD_VK_B,
X_INPUT_GAMEPAD_VK_X,
X_INPUT_GAMEPAD_VK_Y,
// 16 - Fake buttons generated from analog inputs
X_INPUT_GAMEPAD_VK_LTRIGGER,
X_INPUT_GAMEPAD_VK_RTRIGGER,
// 18
X_INPUT_GAMEPAD_VK_LTHUMB_UP,
X_INPUT_GAMEPAD_VK_LTHUMB_DOWN,
X_INPUT_GAMEPAD_VK_LTHUMB_RIGHT,
X_INPUT_GAMEPAD_VK_LTHUMB_LEFT,
X_INPUT_GAMEPAD_VK_LTHUMB_UPLEFT,
X_INPUT_GAMEPAD_VK_LTHUMB_UPRIGHT,
X_INPUT_GAMEPAD_VK_LTHUMB_DOWNRIGHT,
X_INPUT_GAMEPAD_VK_LTHUMB_DOWNLEFT,
// 26
X_INPUT_GAMEPAD_VK_RTHUMB_UP,
X_INPUT_GAMEPAD_VK_RTHUMB_DOWN,
X_INPUT_GAMEPAD_VK_RTHUMB_RIGHT,
X_INPUT_GAMEPAD_VK_RTHUMB_LEFT,
X_INPUT_GAMEPAD_VK_RTHUMB_UPLEFT,
X_INPUT_GAMEPAD_VK_RTHUMB_UPRIGHT,
X_INPUT_GAMEPAD_VK_RTHUMB_DOWNRIGHT,
X_INPUT_GAMEPAD_VK_RTHUMB_DOWNLEFT,
};
static constexpr std::array<ui::VirtualKey, 34> kVkLookup = {
// 00 - True buttons from xinput button field
ui::VirtualKey::kXInputPadDpadUp,
ui::VirtualKey::kXInputPadDpadDown,
ui::VirtualKey::kXInputPadDpadLeft,
ui::VirtualKey::kXInputPadDpadRight,
ui::VirtualKey::kXInputPadStart,
ui::VirtualKey::kXInputPadBack,
ui::VirtualKey::kXInputPadLThumbPress,
ui::VirtualKey::kXInputPadRThumbPress,
ui::VirtualKey::kXInputPadLShoulder,
ui::VirtualKey::kXInputPadRShoulder,
ui::VirtualKey::kNone, /* Guide has no VK */
ui::VirtualKey::kNone, /* Unknown */
ui::VirtualKey::kXInputPadA,
ui::VirtualKey::kXInputPadB,
ui::VirtualKey::kXInputPadX,
ui::VirtualKey::kXInputPadY,
// 16 - Fake buttons generated from analog inputs
ui::VirtualKey::kXInputPadLTrigger,
ui::VirtualKey::kXInputPadRTrigger,
// 18
ui::VirtualKey::kXInputPadLThumbUp,
ui::VirtualKey::kXInputPadLThumbDown,
ui::VirtualKey::kXInputPadLThumbRight,
ui::VirtualKey::kXInputPadLThumbLeft,
ui::VirtualKey::kXInputPadLThumbUpLeft,
ui::VirtualKey::kXInputPadLThumbUpRight,
ui::VirtualKey::kXInputPadLThumbDownRight,
ui::VirtualKey::kXInputPadLThumbDownLeft,
// 26
ui::VirtualKey::kXInputPadRThumbUp,
ui::VirtualKey::kXInputPadRThumbDown,
ui::VirtualKey::kXInputPadRThumbRight,
ui::VirtualKey::kXInputPadRThumbLeft,
ui::VirtualKey::kXInputPadRThumbUpLeft,
ui::VirtualKey::kXInputPadRThumbUpRight,
ui::VirtualKey::kXInputPadRThumbDownRight,
ui::VirtualKey::kXInputPadRThumbDownLeft,
};
auto is_active = this->is_active();
@ -319,9 +318,9 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
if (last.repeat_state == RepeatState::Repeating &&
(last.repeat_time + HID_SDL_REPEAT_RATE < guest_now)) {
last.repeat_time = guest_now;
auto vk = vk_lookup.at(last.repeat_butt_idx);
assert_not_zero(vk);
out_keystroke->virtual_key = vk;
ui::VirtualKey vk = kVkLookup.at(last.repeat_butt_idx);
assert_true(vk != ui::VirtualKey::kNone);
out_keystroke->virtual_key = uint16_t(vk);
out_keystroke->unicode = 0;
out_keystroke->user_index = user_index;
out_keystroke->hid_code = 0;
@ -340,17 +339,17 @@ X_RESULT SDLInputDriver::GetKeystroke(uint32_t users, uint32_t flags,
// up before THUMB_LEFT is down.
for (auto [clear_pass, i] = std::tuple{true, 0}; i < 2;
clear_pass = false, i++) {
for (uint8_t i = 0; i < std::size(vk_lookup); i++) {
for (uint8_t i = 0; i < uint8_t(std::size(kVkLookup)); i++) {
auto fbutton = uint64_t(1) << i;
if (!(butts_changed & fbutton)) {
continue;
}
auto vk = vk_lookup.at(i);
if (!vk) {
ui::VirtualKey vk = kVkLookup.at(last.repeat_butt_idx);
if (vk == ui::VirtualKey::kNone) {
continue;
}
out_keystroke->virtual_key = vk;
out_keystroke->virtual_key = uint16_t(vk);
out_keystroke->unicode = 0;
out_keystroke->user_index = user_index;
out_keystroke->hid_code = 0;

View File

@ -12,6 +12,7 @@
#include "xenia/base/platform_win.h"
#include "xenia/hid/hid_flags.h"
#include "xenia/hid/input_system.h"
#include "xenia/ui/virtual_key.h"
#include "xenia/ui/window.h"
namespace xe {
@ -29,7 +30,7 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window)
auto global_lock = global_critical_region_.Acquire();
KeyEvent key;
key.vkey = evt->key_code();
key.virtual_key = evt->virtual_key();
key.transition = true;
key.prev_state = evt->prev_state();
key.repeat_count = evt->repeat_count();
@ -43,7 +44,7 @@ WinKeyInputDriver::WinKeyInputDriver(xe::ui::Window* window)
auto global_lock = global_critical_region_.Acquire();
KeyEvent key;
key.vkey = evt->key_code();
key.virtual_key = evt->virtual_key();
key.transition = false;
key.prev_state = evt->prev_state();
key.repeat_count = evt->repeat_count();
@ -241,7 +242,7 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
X_RESULT result = X_ERROR_EMPTY;
uint16_t virtual_key = 0;
ui::VirtualKey xinput_virtual_key = ui::VirtualKey::kNone;
uint16_t unicode = 0;
uint16_t keystroke_flags = 0;
uint8_t hid_code = 0;
@ -258,100 +259,93 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
key_events_.pop();
}
// TODO(DrChat): Some other way to toggle this...
if (IS_KEY_TOGGLED(VK_CAPITAL)) {
// dpad toggled
if (evt.vkey == (0x41)) {
// A
virtual_key = 0x5812; // VK_PAD_DPAD_LEFT
} else if (evt.vkey == (0x44)) {
// D
virtual_key = 0x5813; // VK_PAD_DPAD_RIGHT
} else if (evt.vkey == (0x53)) {
// S
virtual_key = 0x5811; // VK_PAD_DPAD_DOWN
} else if (evt.vkey == (0x57)) {
// W
virtual_key = 0x5810; // VK_PAD_DPAD_UP
}
} else {
// left stick
if (evt.vkey == (0x57)) {
// W
virtual_key = 0x5820; // VK_PAD_LTHUMB_UP
}
if (evt.vkey == (0x53)) {
// S
virtual_key = 0x5821; // VK_PAD_LTHUMB_DOWN
}
if (evt.vkey == (0x44)) {
// D
virtual_key = 0x5822; // VK_PAD_LTHUMB_RIGHT
}
if (evt.vkey == (0x41)) {
// A
virtual_key = 0x5823; // VK_PAD_LTHUMB_LEFT
}
switch (evt.virtual_key) {
case ui::VirtualKey::kOem1: // ;
xinput_virtual_key = ui::VirtualKey::kXInputPadA;
break;
case ui::VirtualKey::kOem7: // '
xinput_virtual_key = ui::VirtualKey::kXInputPadB;
break;
case ui::VirtualKey::kL:
xinput_virtual_key = ui::VirtualKey::kXInputPadX;
break;
case ui::VirtualKey::kP:
xinput_virtual_key = ui::VirtualKey::kXInputPadY;
break;
case ui::VirtualKey::k3:
xinput_virtual_key = ui::VirtualKey::kXInputPadRShoulder;
break;
case ui::VirtualKey::k1:
xinput_virtual_key = ui::VirtualKey::kXInputPadLShoulder;
break;
case ui::VirtualKey::kQ:
case ui::VirtualKey::kI:
xinput_virtual_key = ui::VirtualKey::kXInputPadLTrigger;
break;
case ui::VirtualKey::kE:
case ui::VirtualKey::kO:
xinput_virtual_key = ui::VirtualKey::kXInputPadRTrigger;
break;
case ui::VirtualKey::kX:
xinput_virtual_key = ui::VirtualKey::kXInputPadStart;
break;
case ui::VirtualKey::kZ:
xinput_virtual_key = ui::VirtualKey::kXInputPadBack;
break;
case ui::VirtualKey::kUp:
xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbUp;
break;
case ui::VirtualKey::kDown:
xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbDown;
break;
case ui::VirtualKey::kRight:
xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbRight;
break;
case ui::VirtualKey::kLeft:
xinput_virtual_key = ui::VirtualKey::kXInputPadRThumbLeft;
break;
default:
// TODO(DrChat): Some other way to toggle this...
if (IS_KEY_TOGGLED(VK_CAPITAL) || IS_KEY_DOWN(VK_SHIFT)) {
// D-pad toggled.
switch (evt.virtual_key) {
case ui::VirtualKey::kW:
xinput_virtual_key = ui::VirtualKey::kXInputPadDpadUp;
break;
case ui::VirtualKey::kS:
xinput_virtual_key = ui::VirtualKey::kXInputPadDpadDown;
break;
case ui::VirtualKey::kA:
xinput_virtual_key = ui::VirtualKey::kXInputPadDpadLeft;
break;
case ui::VirtualKey::kD:
xinput_virtual_key = ui::VirtualKey::kXInputPadDpadRight;
break;
default:
break;
}
} else {
// Left thumbstick.
switch (evt.virtual_key) {
case ui::VirtualKey::kW:
xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbUp;
break;
case ui::VirtualKey::kS:
xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbDown;
break;
case ui::VirtualKey::kA:
xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbLeft;
break;
case ui::VirtualKey::kD:
xinput_virtual_key = ui::VirtualKey::kXInputPadLThumbRight;
break;
default:
break;
}
}
}
// Right stick
if (evt.vkey == (0x26)) {
// Up
virtual_key = 0x5830;
}
if (evt.vkey == (0x28)) {
// Down
virtual_key = 0x5831;
}
if (evt.vkey == (0x27)) {
// Right
virtual_key = 0x5832;
}
if (evt.vkey == (0x25)) {
// Left
virtual_key = 0x5833;
}
if (evt.vkey == (0x4C)) {
// L
virtual_key = 0x5802; // VK_PAD_X
} else if (evt.vkey == (VK_OEM_7)) {
// '
virtual_key = 0x5801; // VK_PAD_B
} else if (evt.vkey == (VK_OEM_1)) {
// ;
virtual_key = 0x5800; // VK_PAD_A
} else if (evt.vkey == (0x50)) {
// P
virtual_key = 0x5803; // VK_PAD_Y
}
if (evt.vkey == (0x58)) {
// X
virtual_key = 0x5814; // VK_PAD_START
}
if (evt.vkey == (0x5A)) {
// Z
virtual_key = 0x5815; // VK_PAD_BACK
}
if (evt.vkey == (0x51) || evt.vkey == (0x49)) {
// Q / I
virtual_key = 0x5806; // VK_PAD_LTRIGGER
}
if (evt.vkey == (0x45) || evt.vkey == (0x4F)) {
// E / O
virtual_key = 0x5807; // VK_PAD_RTRIGGER
}
if (evt.vkey == (0x31)) {
// 1
virtual_key = 0x5805; // VK_PAD_LSHOULDER
}
if (evt.vkey == (0x33)) {
// 3
virtual_key = 0x5804; // VK_PAD_RSHOULDER
}
if (virtual_key != 0) {
if (xinput_virtual_key != ui::VirtualKey::kNone) {
if (evt.transition == true) {
keystroke_flags |= 0x0001; // XINPUT_KEYSTROKE_KEYDOWN
} else if (evt.transition == false) {
@ -365,7 +359,7 @@ X_RESULT WinKeyInputDriver::GetKeystroke(uint32_t user_index, uint32_t flags,
result = X_ERROR_SUCCESS;
}
out_keystroke->virtual_key = virtual_key;
out_keystroke->virtual_key = uint16_t(xinput_virtual_key);
out_keystroke->unicode = unicode;
out_keystroke->flags = keystroke_flags;
out_keystroke->user_index = 0;

View File

@ -14,6 +14,7 @@
#include "xenia/base/mutex.h"
#include "xenia/hid/input_driver.h"
#include "xenia/ui/virtual_key.h"
namespace xe {
namespace hid {
@ -35,7 +36,7 @@ class WinKeyInputDriver : public InputDriver {
protected:
struct KeyEvent {
int vkey = 0;
ui::VirtualKey virtual_key = ui::VirtualKey::kNone;
int repeat_count = 0;
bool transition = false; // going up(false) or going down(true)
bool prev_state = false; // down(true) or up(false)

View File

@ -2,13 +2,12 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
// Post-include file for an export table.
#undef FLAG
#undef XE_EXPORT

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -22,8 +22,7 @@
* my_module_export_table, xe::countof(my_module_export_table));
*/
#define XE_EXPORT(module, ordinal, name, type) \
xe::cpu::Export(ordinal, xe::cpu::Export::Type::type, #name)
#define FLAG(t) kXEKernelExportFlag##t
#define FLAG(t) kXEKernelExportFlag##t

View File

@ -2,12 +2,11 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
// Post-include file for an ordinal table.
#undef XE_EXPORT

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -21,7 +21,4 @@
* #include "xenia/kernel/util/ordinal_table_post.inc"
*/
#define XE_EXPORT(module, ordinal, name, type) \
name = ordinal
#define XE_EXPORT(module, ordinal, name, type) name = ordinal

View File

@ -57,8 +57,7 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
std::memset(buffer, 0, data->buffer_size);
}
uint32_t item_count = 0;
auto result = e->WriteItems(data->buffer_ptr, buffer, data->buffer_size,
&item_count);
auto result = e->WriteItems(data->buffer_ptr, buffer, &item_count);
if (result == X_ERROR_SUCCESS && item_count >= 1) {
if (data->length_ptr) {

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -80,8 +80,10 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
return X_E_SUCCESS;
}
case 0x000B0011: {
// TODO(DrChat): Figure out what this is again
} break;
// TODO(PermaNull): reverse buffer contents.
XELOGD("XGISessionDelete");
return X_STATUS_SUCCESS;
}
case 0x000B0012: {
assert_true(buffer_length == 0x14);
uint32_t session_ptr = xe::load_and_swap<uint32_t>(buffer + 0x0);
@ -95,6 +97,17 @@ X_HRESULT XgiApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
user_count, unk_0, user_index_array, private_slots_array);
return X_E_SUCCESS;
}
case 0x000B0014: {
// Gets Jetpac XBLA in game
// get high score table?
XELOGD("XGI_unknown");
return X_STATUS_SUCCESS;
}
case 0x000B0015: {
// send high scores?
XELOGD("XGI_unknown");
return X_STATUS_SUCCESS;
}
case 0x000B0041: {
assert_true(!buffer_length || buffer_length == 32);
// 00000000 2789fecc 00000000 00000000 200491e0 00000000 200491f0 20049340

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2015 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -41,18 +41,28 @@ X_HRESULT XLiveBaseApp::DispatchMessageSync(uint32_t message,
xe::store_and_swap<uint32_t>(buffer + 0, 1); // XONLINE_NAT_OPEN
return X_E_SUCCESS;
}
case 0x00058007: {
// Occurs if title calls XOnlineGetServiceInfo, expects dwServiceId
// and pServiceInfo. pServiceInfo should contain pointer to
// XONLINE_SERVICE_INFO structure.
XELOGD("CXLiveLogon::GetServiceInfo({:08X}, {:08X})", buffer_ptr,
buffer_length);
return 1229; // ERROR_CONNECTION_INVALID
}
case 0x00058020: {
// 0x00058004 is called right before this.
// We should create a XamEnumerate-able empty list here, but I'm not
// sure of the format.
// buffer_length seems to be the same ptr sent to 0x00058004.
XELOGD("XLiveBaseFriendsCreateEnumerator({:08X}, {:08X}) unimplemented",
XELOGD("CXLiveFriends::Enumerate({:08X}, {:08X}) unimplemented",
buffer_ptr, buffer_length);
return X_E_FAIL;
}
case 0x00058023: {
XELOGD("XliveBaseUnk58023({:08X}, {:08X}) unimplemented", buffer_ptr,
buffer_length);
XELOGD(
"CXLiveMessaging::XMessageGameInviteGetAcceptedInfo({:08X}, {:08X}) "
"unimplemented",
buffer_ptr, buffer_length);
return X_E_FAIL;
}
case 0x00058046: {

View File

@ -86,8 +86,8 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id,
*buffer_size_ptr = sizeof(XCONTENT_DATA) * items_per_enumerate;
}
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
kernel_state(), items_per_enumerate, sizeof(XCONTENT_DATA)));
auto e = make_object<XStaticEnumerator<XCONTENT_DATA>>(kernel_state(),
items_per_enumerate);
auto result = e->Initialize(0xFF, 0xFE, 0x20005, 0x20007, 0);
if (XFAILED(result)) {
return result;
@ -99,8 +99,7 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id,
static_cast<uint32_t>(DummyDeviceId::HDD),
XContentType(uint32_t(content_type)));
for (const auto& content_data : content_datas) {
auto item = reinterpret_cast<XCONTENT_DATA*>(e->AppendItem());
assert_not_null(item);
auto item = e->AppendItem();
*item = content_data;
}
}
@ -124,7 +123,6 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name,
lpdword_t license_mask_ptr,
dword_t cache_size, qword_t content_size,
lpvoid_t overlapped_ptr) {
X_RESULT result = X_ERROR_INVALID_PARAMETER;
XCONTENT_AGGREGATE_DATA content_data;
if (content_data_size == sizeof(XCONTENT_DATA)) {
content_data = *content_data_ptr.as<XCONTENT_DATA*>();
@ -132,91 +130,99 @@ dword_result_t xeXamContentCreate(dword_t user_index, lpstring_t root_name,
content_data = *content_data_ptr.as<XCONTENT_AGGREGATE_DATA*>();
} else {
assert_always();
return result;
return X_ERROR_INVALID_PARAMETER;
}
auto content_manager = kernel_state()->content_manager();
bool create = false;
bool open = false;
switch (flags & 0xF) {
case 1: // CREATE_NEW
// Fail if exists.
if (content_manager->ContentExists(content_data)) {
result = X_ERROR_ALREADY_EXISTS;
} else {
create = true;
}
break;
case 2: // CREATE_ALWAYS
// Overwrite existing, if any.
if (content_manager->ContentExists(content_data)) {
content_manager->DeleteContent(content_data);
create = true;
} else {
create = true;
}
break;
case 3: // OPEN_EXISTING
// Open only if exists.
if (!content_manager->ContentExists(content_data)) {
result = X_ERROR_PATH_NOT_FOUND;
} else {
open = true;
}
break;
case 4: // OPEN_ALWAYS
// Create if needed.
if (!content_manager->ContentExists(content_data)) {
create = true;
} else {
open = true;
}
break;
case 5: // TRUNCATE_EXISTING
// Fail if doesn't exist, if does exist delete and recreate.
if (!content_manager->ContentExists(content_data)) {
result = X_ERROR_PATH_NOT_FOUND;
} else {
content_manager->DeleteContent(content_data);
create = true;
}
break;
default:
assert_unhandled_case(flags & 0xF);
break;
if (overlapped_ptr && disposition_ptr) {
*disposition_ptr = 0;
}
// creation result
// 0 = ?
// 1 = created
// 2 = opened
uint32_t disposition = create ? 1 : 2;
if (disposition_ptr) {
// In case when overlapped_ptr exist we should clear disposition_ptr first
// however we're executing it immediately, so it's not required
*disposition_ptr = disposition;
}
if (create) {
result = content_manager->CreateContent(root_name.value(), content_data);
} else if (open) {
result = content_manager->OpenContent(root_name.value(), content_data);
}
if (license_mask_ptr && XSUCCEEDED(result)) {
*license_mask_ptr = 0; // Stub!
}
if (overlapped_ptr) {
X_RESULT extended_error = X_HRESULT_FROM_WIN32(result);
if (int32_t(extended_error) < 0) {
result = X_ERROR_FUNCTION_FAILED;
auto run = [content_manager, root_name, flags, content_data, disposition_ptr,
license_mask_ptr](uint32_t& extended_error,
uint32_t& length) -> X_RESULT {
X_RESULT result = X_ERROR_INVALID_PARAMETER;
bool create = false;
bool open = false;
switch (flags & 0xF) {
case 1: // CREATE_NEW
// Fail if exists.
if (content_manager->ContentExists(content_data)) {
result = X_ERROR_ALREADY_EXISTS;
} else {
create = true;
}
break;
case 2: // CREATE_ALWAYS
// Overwrite existing, if any.
if (content_manager->ContentExists(content_data)) {
content_manager->DeleteContent(content_data);
create = true;
} else {
create = true;
}
break;
case 3: // OPEN_EXISTING
// Open only if exists.
if (!content_manager->ContentExists(content_data)) {
result = X_ERROR_PATH_NOT_FOUND;
} else {
open = true;
}
break;
case 4: // OPEN_ALWAYS
// Create if needed.
if (!content_manager->ContentExists(content_data)) {
create = true;
} else {
open = true;
}
break;
case 5: // TRUNCATE_EXISTING
// Fail if doesn't exist, if does exist delete and recreate.
if (!content_manager->ContentExists(content_data)) {
result = X_ERROR_PATH_NOT_FOUND;
} else {
content_manager->DeleteContent(content_data);
create = true;
}
break;
default:
assert_unhandled_case(flags & 0xF);
break;
}
kernel_state()->CompleteOverlappedImmediateEx(overlapped_ptr, result,
extended_error, disposition);
return X_ERROR_IO_PENDING;
} else {
// creation result
// 0 = ?
// 1 = created
// 2 = opened
uint32_t disposition = create ? 1 : 2;
if (disposition_ptr) {
*disposition_ptr = disposition;
}
if (create) {
result = content_manager->CreateContent(root_name.value(), content_data);
} else if (open) {
result = content_manager->OpenContent(root_name.value(), content_data);
}
if (license_mask_ptr && XSUCCEEDED(result)) {
*license_mask_ptr = 0; // Stub!
}
extended_error = X_HRESULT_FROM_WIN32(result);
length = disposition;
return result;
};
if (!overlapped_ptr) {
uint32_t extended_error, length;
return run(extended_error, length);
} else {
kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr);
return X_ERROR_IO_PENDING;
}
}

View File

@ -23,7 +23,7 @@ namespace xe {
namespace kernel {
namespace xam {
void AddODDContentTest(object_ref<XStaticEnumerator> e,
void AddODDContentTest(object_ref<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>> e,
XContentType content_type) {
auto root_entry = kernel_state()->file_system()->ResolvePath(
"game:\\Content\\0000000000000000");
@ -62,13 +62,15 @@ void AddODDContentTest(object_ref<XStaticEnumerator> e,
break;
}
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
auto item = e->AppendItem();
assert_not_null(item);
item->device_id = static_cast<uint32_t>(DummyDeviceId::ODD);
item->content_type = content_type;
item->set_display_name(to_utf16(content_entry->name()));
item->set_file_name(content_entry->name());
item->title_id = title_id;
if (item) {
item->device_id = static_cast<uint32_t>(DummyDeviceId::ODD);
item->content_type = content_type;
item->set_display_name(to_utf16(content_entry->name()));
item->set_file_name(content_entry->name());
item->title_id = title_id;
}
}
}
}
@ -86,8 +88,8 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid,
return X_E_INVALIDARG;
}
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
kernel_state(), 1, sizeof(XCONTENT_AGGREGATE_DATA)));
auto e = make_object<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>>(
kernel_state(), 1);
X_KENUMERATOR_CONTENT_AGGREGATE* extra;
auto result = e->Initialize(0xFF, 0xFE, 0x2000E, 0x20010, 0, &extra);
if (XFAILED(result)) {
@ -116,9 +118,11 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid,
static_cast<uint32_t>(DummyDeviceId::HDD), content_type_enum,
title_id);
for (const auto& content_data : content_datas) {
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
auto item = e->AppendItem();
assert_not_null(item);
*item = content_data;
if (item) {
*item = content_data;
}
}
}
}

View File

@ -139,8 +139,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type,
*buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count;
}
auto e = object_ref<XStaticEnumerator>(new XStaticEnumerator(
kernel_state(), max_count, sizeof(X_CONTENT_DEVICE_DATA)));
auto e = make_object<XStaticEnumerator<X_CONTENT_DEVICE_DATA>>(kernel_state(),
max_count);
auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0);
if (XFAILED(result)) {
return result;
@ -148,7 +148,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type,
for (const auto& device_info : dummy_device_infos_) {
// Copy our dummy device into the enumerator
auto device_data = (X_CONTENT_DEVICE_DATA*)e->AppendItem();
auto device_data = e->AppendItem();
assert_not_null(device_data);
if (device_data) {
device_data->device_id = static_cast<uint32_t>(device_info->device_id);
device_data->device_type =

View File

@ -32,49 +32,37 @@ uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr,
uint32_t overlapped_ptr) {
assert_true(flags == 0);
X_RESULT result;
uint32_t item_count = 0;
auto e = kernel_state()->object_table()->LookupObject<XEnumerator>(handle);
if (!e) {
result = X_ERROR_INVALID_HANDLE;
} else if (!buffer_ptr) {
result = X_ERROR_INVALID_PARAMETER;
} else {
size_t needed_buffer_size = e->item_size() * e->items_per_enumerate();
uint32_t actual_buffer_size = buffer_size;
if (buffer_size == e->items_per_enumerate()) {
actual_buffer_size = static_cast<uint32_t>(needed_buffer_size);
// Known culprits:
// Final Fight: Double Impact (saves)
XELOGW(
"Broken usage of XamEnumerate! buffer size={:X} vs actual "
"size={:X} (item size={:X}, items per enumerate={})",
buffer_size, actual_buffer_size, e->item_size(),
e->items_per_enumerate());
}
result = X_ERROR_INSUFFICIENT_BUFFER;
if (actual_buffer_size >= needed_buffer_size) {
buffer_ptr.Zero(actual_buffer_size);
result =
e->WriteItems(buffer_ptr.guest_address(), buffer_ptr.as<uint8_t*>(),
actual_buffer_size, &item_count);
}
return X_ERROR_INVALID_HANDLE;
}
auto run = [e, buffer_ptr](uint32_t& extended_error,
uint32_t& length) -> X_RESULT {
X_RESULT result;
uint32_t item_count;
if (!buffer_ptr) {
result = X_ERROR_INVALID_PARAMETER;
item_count = 0;
} else {
result = e->WriteItems(buffer_ptr.guest_address(),
buffer_ptr.as<uint8_t*>(), &item_count);
}
extended_error = X_HRESULT_FROM_WIN32(result);
length = item_count;
return result;
};
if (items_returned) {
assert_true(!overlapped_ptr);
uint32_t extended_error;
uint32_t item_count;
X_RESULT result = run(extended_error, item_count);
*items_returned = result == X_ERROR_SUCCESS ? item_count : 0;
return result;
} else if (overlapped_ptr) {
assert_true(!items_returned);
kernel_state()->CompleteOverlappedImmediateEx(
overlapped_ptr,
result == X_ERROR_SUCCESS ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED,
X_HRESULT_FROM_WIN32(result),
result == X_ERROR_SUCCESS ? item_count : 0);
kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr);
return X_ERROR_IO_PENDING;
} else {
assert_always();

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2020 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -306,9 +306,11 @@ dword_result_t NetDll_WSARecvFrom(dword_t caller, dword_t socket,
//}
}
return 0;
// we're not going to be receiving packets any time soon
// return error so we don't wait on that - Cancerous
return -1;
}
DECLARE_XAM_EXPORT1(NetDll_WSARecvFrom, kNetworking, kStub);
DECLARE_XAM_EXPORT2(NetDll_WSARecvFrom, kNetworking, kStub, kHighFrequency);
// If the socket is a VDP socket, buffer 0 is the game data length, and buffer 1
// is the unencrypted game data.

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -10,6 +10,7 @@
// This is a partial file designed to be included by other files when
// constructing various tables.
// clang-format off
XE_EXPORT(xam, 0x00000001, NetDll_WSAStartup, kFunction),
XE_EXPORT(xam, 0x00000002, NetDll_WSACleanup, kFunction),

View File

@ -277,8 +277,9 @@ uint32_t xeXamUserReadProfileSettingsEx(uint32_t title_id, uint32_t user_index,
auto setting = user_profile->GetSetting(setting_id);
std::memset(out_setting, 0, sizeof(X_USER_READ_PROFILE_SETTING));
out_setting->from =
!setting || !setting->is_set ? 0 : setting->is_title_specific() ? 2 : 1;
out_setting->from = !setting || !setting->is_set ? 0
: setting->is_title_specific() ? 2
: 1;
out_setting->user_index = static_cast<uint32_t>(user_index);
out_setting->setting_id = setting_id;
@ -547,7 +548,8 @@ DECLARE_XAM_EXPORT1(XamUserAreUsersFriends, kUserProfiles, kStub);
dword_result_t XamShowSigninUI(dword_t unk, dword_t unk_mask) {
// Mask values vary. Probably matching user types? Local/remote?
// To fix game modes that display a 4 profile signin UI (even if playing alone):
// To fix game modes that display a 4 profile signin UI (even if playing
// alone):
// XN_SYS_SIGNINCHANGED
kernel_state()->BroadcastNotification(0x0000000A, 1);
// Games seem to sit and loop until we trigger this notification:
@ -606,7 +608,7 @@ class XStaticAchievementEnumerator : public XEnumerator {
}
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
uint32_t buffer_size, uint32_t* written_count) override {
uint32_t* written_count) override {
size_t count =
std::min(items_.size() - current_item_, items_per_enumerate());
if (!count) {
@ -614,9 +616,6 @@ class XStaticAchievementEnumerator : public XEnumerator {
}
size_t size = count * item_size();
if (size > buffer_size) {
return X_ERROR_INSUFFICIENT_BUFFER;
}
auto details = reinterpret_cast<X_ACHIEVEMENT_DETAILS*>(buffer_data);
size_t string_offset =
@ -778,8 +777,10 @@ DECLARE_XAM_EXPORT1(XamSessionCreateHandle, kUserProfiles, kStub);
dword_result_t XamSessionRefObjByHandle(dword_t handle, lpdword_t obj_ptr) {
assert_true(handle == 0xCAFEDEAD);
*obj_ptr = 0;
return X_ERROR_FUNCTION_FAILED;
// TODO(PermaNull): Implement this properly,
// For the time being returning 0xDEADF00D will prevent crashing.
*obj_ptr = 0xDEADF00D;
return X_ERROR_SUCCESS;
}
DECLARE_XAM_EXPORT1(XamSessionRefObjByHandle, kUserProfiles, kStub);

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -10,6 +10,7 @@
// This is a partial file designed to be included by other files when
// constructing various tables.
// clang-format off
XE_EXPORT(xbdm, 0x00000001, DmAllocatePool, kFunction),
XE_EXPORT(xbdm, 0x00000002, DmAllocatePoolWithTag, kFunction),

View File

@ -997,7 +997,7 @@ uint32_t xeRtlNtStatusToDosError(uint32_t source_status) {
if (!result) {
break;
}
XELOGI("RtlNtStatusToDosError {:X} => {:X}", status, result);
XELOGI("xeRtlNtStatusToDosError {:X} => {:X}", status, result);
return result;
}
++error_table;
@ -1007,7 +1007,7 @@ uint32_t xeRtlNtStatusToDosError(uint32_t source_status) {
return status & 0xFFFF;
}
XELOGE("RtlNtStatusToDosError lookup NOT IMPLEMENTED");
XELOGE("xeRtlNtStatusToDosError lookup NOT IMPLEMENTED");
return 317; // ERROR_MR_MID_NOT_FOUND
}

View File

@ -357,11 +357,7 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
pointer_t<X_IO_STATUS_BLOCK> io_status_block,
lpvoid_t buffer, dword_t buffer_length,
lpqword_t byte_offset_ptr) {
// Async not supported yet.
assert_zero(apc_routine);
X_STATUS result = X_STATUS_SUCCESS;
uint32_t info = 0;
// Grab event to signal.
bool signal_event = false;
@ -386,30 +382,37 @@ dword_result_t NtWriteFile(dword_t file_handle, dword_t event_handle,
buffer.guest_address(), buffer_length,
byte_offset_ptr ? static_cast<uint64_t>(*byte_offset_ptr) : -1,
&bytes_written, apc_context);
if (XSUCCEEDED(result)) {
info = bytes_written;
if (io_status_block) {
io_status_block->status = result;
io_status_block->information = static_cast<uint32_t>(bytes_written);
}
// Queue the APC callback. It must be delivered via the APC mechanism even
// though were are completing immediately.
// Low bit probably means do not queue to IO ports.
if ((uint32_t)apc_routine & ~1) {
if (apc_context) {
auto thread = XThread::GetCurrentThread();
thread->EnqueueApc(static_cast<uint32_t>(apc_routine) & ~1u,
apc_context, io_status_block, 0);
}
}
if (!file->is_synchronous()) {
result = X_STATUS_PENDING;
}
if (io_status_block) {
io_status_block->status = X_STATUS_SUCCESS;
io_status_block->information = info;
}
// Mark that we should signal the event now. We do this after
// we have written the info out.
signal_event = true;
} else {
// X_STATUS_PENDING if not returning immediately.
result = X_STATUS_PENDING;
info = 0;
if (io_status_block) {
io_status_block->status = X_STATUS_SUCCESS;
io_status_block->information = info;
io_status_block->status = X_STATUS_PENDING;
io_status_block->information = 0;
}
}
}
@ -458,7 +461,8 @@ dword_result_t NtSetIoCompletion(dword_t handle, dword_t key_context,
port->QueueNotification(notification);
return X_STATUS_SUCCESS;
}
DECLARE_XBOXKRNL_EXPORT1(NtSetIoCompletion, kFileSystem, kImplemented);
DECLARE_XBOXKRNL_EXPORT2(NtSetIoCompletion, kFileSystem, kImplemented,
kHighFrequency);
// Dequeues a packet from the completion port.
dword_result_t NtRemoveIoCompletion(
@ -473,7 +477,9 @@ dword_result_t NtRemoveIoCompletion(
status = X_STATUS_INVALID_HANDLE;
}
uint64_t timeout_ticks = timeout ? static_cast<uint32_t>(*timeout) : 0u;
uint64_t timeout_ticks =
timeout ? static_cast<uint32_t>(*timeout)
: static_cast<uint64_t>(std::numeric_limits<int64_t>::min());
XIOCompletion::IONotification notification;
if (port->WaitForNotification(timeout_ticks, &notification)) {
if (key_context) {
@ -493,7 +499,8 @@ dword_result_t NtRemoveIoCompletion(
return status;
}
DECLARE_XBOXKRNL_EXPORT1(NtRemoveIoCompletion, kFileSystem, kImplemented);
DECLARE_XBOXKRNL_EXPORT2(NtRemoveIoCompletion, kFileSystem, kImplemented,
kHighFrequency);
dword_result_t NtQueryFullAttributesFile(
pointer_t<X_OBJECT_ATTRIBUTES> obj_attribs,

View File

@ -19,6 +19,9 @@
#include "xenia/kernel/xthread.h"
#include "xenia/xbox.h"
DEFINE_bool(log_string_format_kernel_calls, false,
"Log kernel calls with the kHighFrequency tag.", "Logging");
namespace xe {
namespace kernel {
namespace xboxkrnl {
@ -830,7 +833,14 @@ SHIM_CALL DbgPrint_shim(PPCContext* ppc_context, KernelState* kernel_state) {
return;
}
XELOGD("(DbgPrint) {}", data.str());
// trim whitespace from end of message
auto str = data.str();
str.erase(std::find_if(str.rbegin(), str.rend(),
[](uint8_t c) { return !std::isspace(c); })
.base(),
str.end());
XELOGI("(DbgPrint) {}", str);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
@ -841,8 +851,11 @@ SHIM_CALL _snprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
int32_t buffer_count = SHIM_GET_ARG_32(1);
uint32_t format_ptr = SHIM_GET_ARG_32(2);
XELOGD("_snprintf({:08X}, {}, {:08X}, ...)", buffer_ptr, buffer_count,
format_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("_snprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count,
format_ptr,
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)));
}
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -877,7 +890,10 @@ SHIM_CALL sprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
uint32_t format_ptr = SHIM_GET_ARG_32(1);
XELOGD("sprintf({:08X}, {:08X}, ...)", buffer_ptr, format_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("sprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr,
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)));
}
if (buffer_ptr == 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -906,8 +922,12 @@ SHIM_CALL _snwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
int32_t buffer_count = SHIM_GET_ARG_32(1);
uint32_t format_ptr = SHIM_GET_ARG_32(2);
XELOGD("_snwprintf({:08X}, {}, {:08X}, ...)", buffer_ptr, buffer_count,
format_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("_snwprintf({:08X}, {}, {:08X}({}), ...)", buffer_ptr, buffer_count,
format_ptr,
xe::to_utf8(
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))));
}
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -942,7 +962,11 @@ SHIM_CALL swprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
uint32_t buffer_ptr = SHIM_GET_ARG_32(0);
uint32_t format_ptr = SHIM_GET_ARG_32(1);
XELOGD("swprintf({:08X}, {:08X}, ...)", buffer_ptr, format_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("swprintf({:08X}, {:08X}({}), ...)", buffer_ptr, format_ptr,
xe::to_utf8(
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))));
}
if (buffer_ptr == 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -972,8 +996,11 @@ SHIM_CALL _vsnprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
uint32_t format_ptr = SHIM_GET_ARG_32(2);
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
XELOGD("_vsnprintf({:08X}, {}, {:08X}, {:08X})", buffer_ptr, buffer_count,
format_ptr, arg_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("_vsnprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr,
buffer_count, format_ptr,
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)), arg_ptr);
}
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -1012,8 +1039,13 @@ SHIM_CALL _vsnwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
uint32_t format_ptr = SHIM_GET_ARG_32(2);
uint32_t arg_ptr = SHIM_GET_ARG_32(3);
XELOGD("_vsnwprintf({:08X}, {}, {:08X}, {:08X})", buffer_ptr, buffer_count,
format_ptr, arg_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("_vsnwprintf({:08X}, {}, {:08X}({}), {:08X})", buffer_ptr,
buffer_count, format_ptr,
xe::to_utf8(
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))),
arg_ptr);
}
if (buffer_ptr == 0 || buffer_count <= 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -1051,7 +1083,10 @@ SHIM_CALL vsprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
uint32_t format_ptr = SHIM_GET_ARG_32(1);
uint32_t arg_ptr = SHIM_GET_ARG_32(2);
XELOGD("vsprintf({:08X}, {:08X}, {:08X})", buffer_ptr, format_ptr, arg_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("vsprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr,
xe::load_and_swap<std::string>(SHIM_MEM_ADDR(format_ptr)), arg_ptr);
}
if (buffer_ptr == 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -1079,7 +1114,12 @@ SHIM_CALL _vscwprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
uint32_t format_ptr = SHIM_GET_ARG_32(0);
uint32_t arg_ptr = SHIM_GET_ARG_32(1);
XELOGD("_vscwprintf({:08X}, {:08X})", format_ptr, arg_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("_vscwprintf({:08X}({}), {:08X})", format_ptr,
xe::to_utf8(
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))),
arg_ptr);
}
if (format_ptr == 0) {
SHIM_SET_RETURN_32(-1);
@ -1102,7 +1142,12 @@ SHIM_CALL vswprintf_shim(PPCContext* ppc_context, KernelState* kernel_state) {
uint32_t format_ptr = SHIM_GET_ARG_32(1);
uint32_t arg_ptr = SHIM_GET_ARG_32(2);
XELOGD("vswprintf({:08X}, {:08X}, {:08X})", buffer_ptr, format_ptr, arg_ptr);
if (cvars::log_high_frequency_kernel_calls) {
XELOGD("vswprintf({:08X}, {:08X}({}), {:08X})", buffer_ptr, format_ptr,
xe::to_utf8(
xe::load_and_swap<std::u16string>(SHIM_MEM_ADDR(format_ptr))),
arg_ptr);
}
if (buffer_ptr == 0 || format_ptr == 0) {
SHIM_SET_RETURN_32(-1);

View File

@ -2,7 +2,7 @@
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
@ -10,6 +10,7 @@
// This is a partial file designed to be included by other files when
// constructing various tables.
// clang-format off
XE_EXPORT(xboxkrnl, 0x00000001, DbgBreakPoint, kFunction),
XE_EXPORT(xboxkrnl, 0x00000002, DbgBreakPointWithStatus, kFunction),

View File

@ -21,7 +21,7 @@ XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
XEnumerator::~XEnumerator() = default;
X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
uint32_t message, uint32_t message2,
uint32_t open_message, uint32_t close_message,
uint32_t flags, uint32_t extra_size,
void** extra_buffer) {
auto native_object = CreateNative(sizeof(X_KENUMERATOR) + extra_size);
@ -30,8 +30,8 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
}
auto guest_object = reinterpret_cast<X_KENUMERATOR*>(native_object);
guest_object->app_id = app_id;
guest_object->message = message;
guest_object->message2 = message2;
guest_object->open_message = open_message;
guest_object->close_message = close_message;
guest_object->user_index = user_index;
guest_object->items_per_enumerate =
static_cast<uint32_t>(items_per_enumerate_);
@ -44,32 +44,28 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
}
X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id,
uint32_t message, uint32_t message2,
uint32_t open_message, uint32_t close_message,
uint32_t flags) {
return Initialize(user_index, app_id, message, message2, flags, 0, nullptr);
return Initialize(user_index, app_id, open_message, close_message, flags, 0,
nullptr);
}
uint8_t* XStaticEnumerator::AppendItem() {
buffer_.resize(++item_count_ * item_size());
auto ptr =
const_cast<uint8_t*>(buffer_.data() + (item_count_ - 1) * item_size());
return ptr;
uint8_t* XStaticUntypedEnumerator::AppendItem() {
size_t offset = buffer_.size();
buffer_.resize(offset + item_size());
item_count_++;
return const_cast<uint8_t*>(&buffer_.data()[offset]);
}
uint32_t XStaticEnumerator::WriteItems(uint32_t buffer_ptr,
uint8_t* buffer_data,
uint32_t buffer_size,
uint32_t* written_count) {
uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr,
uint8_t* buffer_data,
uint32_t* written_count) {
size_t count = std::min(item_count_ - current_item_, items_per_enumerate());
if (!count) {
return X_ERROR_NO_MORE_FILES;
}
size_t size = count * item_size();
if (size > buffer_size) {
return X_ERROR_INSUFFICIENT_BUFFER;
}
size_t offset = current_item_ * item_size();
std::memcpy(buffer_data, buffer_.data() + offset, size);

View File

@ -22,8 +22,8 @@ namespace kernel {
struct X_KENUMERATOR {
be<uint32_t> app_id;
be<uint32_t> message;
be<uint32_t> message2;
be<uint32_t> open_message;
be<uint32_t> close_message;
be<uint32_t> user_index;
be<uint32_t> items_per_enumerate;
be<uint32_t> flags;
@ -43,19 +43,21 @@ class XEnumerator : public XObject {
size_t item_size);
virtual ~XEnumerator();
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
uint32_t message2, uint32_t flags, uint32_t extra_size,
void** extra_buffer);
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
uint32_t open_message, uint32_t close_message,
uint32_t flags, uint32_t extra_size, void** extra_buffer);
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
uint32_t message2, uint32_t flags);
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
uint32_t open_message, uint32_t close_message,
uint32_t flags);
template <typename T>
X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message,
uint32_t message2, uint32_t flags, T** extra) {
X_STATUS Initialize(uint32_t user_index, uint32_t app_id,
uint32_t open_message, uint32_t close_message,
uint32_t flags, T** extra) {
void* dummy;
auto result = Initialize(user_index, app_id, message, message2, flags,
static_cast<uint32_t>(sizeof(T)), &dummy);
auto result = Initialize(user_index, app_id, open_message, close_message,
flags, static_cast<uint32_t>(sizeof(T)), &dummy);
if (extra) {
*extra = XFAILED(result) ? nullptr : static_cast<T*>(dummy);
}
@ -63,7 +65,6 @@ class XEnumerator : public XObject {
}
virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
uint32_t buffer_size,
uint32_t* written_count) = 0;
size_t item_size() const { return item_size_; }
@ -74,10 +75,10 @@ class XEnumerator : public XObject {
size_t item_size_;
};
class XStaticEnumerator : public XEnumerator {
class XStaticUntypedEnumerator : public XEnumerator {
public:
XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate,
size_t item_size)
XStaticUntypedEnumerator(KernelState* kernel_state,
size_t items_per_enumerate, size_t item_size)
: XEnumerator(kernel_state, items_per_enumerate, item_size),
item_count_(0),
current_item_(0) {}
@ -87,7 +88,7 @@ class XStaticEnumerator : public XEnumerator {
uint8_t* AppendItem();
uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data,
uint32_t buffer_size, uint32_t* written_count) override;
uint32_t* written_count) override;
private:
size_t item_count_;
@ -95,6 +96,23 @@ class XStaticEnumerator : public XEnumerator {
std::vector<uint8_t> buffer_;
};
template <typename T>
class XStaticEnumerator : public XStaticUntypedEnumerator {
public:
XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate)
: XStaticUntypedEnumerator(kernel_state, items_per_enumerate, sizeof(T)) {
}
T* AppendItem() {
return reinterpret_cast<T*>(XStaticUntypedEnumerator::AppendItem());
}
void AppendItem(const T& item) {
auto ptr = AppendItem();
item.Write(ptr);
}
};
} // namespace kernel
} // namespace xe

View File

@ -30,7 +30,7 @@ bool XIOCompletion::WaitForNotification(uint64_t wait_ticks,
IONotification* notify) {
auto ms = std::chrono::milliseconds(TimeoutTicksToMs(wait_ticks));
auto res = threading::Wait(notification_semaphore_.get(), false, ms);
if (res == threading::WaitResult::kSuccess || !wait_ticks) {
if (res == threading::WaitResult::kSuccess) {
std::unique_lock<std::mutex> lock(notification_lock_);
assert_false(notifications_.empty());

View File

@ -348,6 +348,12 @@ bool operator!=(std::nullptr_t _Left, const object_ref<_Ty>& _Right) noexcept {
return (!(_Left == _Right));
}
template <class T, class... Args>
std::enable_if_t<!std::is_array<T>::value, object_ref<T>> make_object(
Args&&... args) {
return object_ref<T>(new T(std::forward<Args>(args)...));
}
template <typename T>
object_ref<T> retain_object(T* ptr) {
if (ptr) ptr->Retain();

View File

@ -12,6 +12,7 @@
#include "third_party/imgui/imgui.h"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/ui/window.h"
namespace xe {
@ -107,23 +108,23 @@ void ImGuiDrawer::Initialize() {
style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 1.00f, 0.00f, 0.21f);
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f);
io.KeyMap[ImGuiKey_Tab] = 0x09; // VK_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = 0x25;
io.KeyMap[ImGuiKey_RightArrow] = 0x27;
io.KeyMap[ImGuiKey_UpArrow] = 0x26;
io.KeyMap[ImGuiKey_DownArrow] = 0x28;
io.KeyMap[ImGuiKey_Home] = 0x24;
io.KeyMap[ImGuiKey_End] = 0x23;
io.KeyMap[ImGuiKey_Delete] = 0x2E;
io.KeyMap[ImGuiKey_Backspace] = 0x08;
io.KeyMap[ImGuiKey_Enter] = 0x0D;
io.KeyMap[ImGuiKey_Escape] = 0x1B;
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
io.KeyMap[ImGuiKey_Tab] = int(ui::VirtualKey::kTab);
io.KeyMap[ImGuiKey_LeftArrow] = int(ui::VirtualKey::kLeft);
io.KeyMap[ImGuiKey_RightArrow] = int(ui::VirtualKey::kRight);
io.KeyMap[ImGuiKey_UpArrow] = int(ui::VirtualKey::kUp);
io.KeyMap[ImGuiKey_DownArrow] = int(ui::VirtualKey::kDown);
io.KeyMap[ImGuiKey_Home] = int(ui::VirtualKey::kHome);
io.KeyMap[ImGuiKey_End] = int(ui::VirtualKey::kEnd);
io.KeyMap[ImGuiKey_Delete] = int(ui::VirtualKey::kDelete);
io.KeyMap[ImGuiKey_Backspace] = int(ui::VirtualKey::kBack);
io.KeyMap[ImGuiKey_Enter] = int(ui::VirtualKey::kReturn);
io.KeyMap[ImGuiKey_Escape] = int(ui::VirtualKey::kEscape);
io.KeyMap[ImGuiKey_A] = int(ui::VirtualKey::kA);
io.KeyMap[ImGuiKey_C] = int(ui::VirtualKey::kC);
io.KeyMap[ImGuiKey_V] = int(ui::VirtualKey::kV);
io.KeyMap[ImGuiKey_X] = int(ui::VirtualKey::kX);
io.KeyMap[ImGuiKey_Y] = int(ui::VirtualKey::kY);
io.KeyMap[ImGuiKey_Z] = int(ui::VirtualKey::kZ);
}
void ImGuiDrawer::SetupFont() {
@ -228,36 +229,16 @@ void ImGuiDrawer::RenderDrawLists() {
}
}
void ImGuiDrawer::OnKeyDown(KeyEvent* e) {
auto& io = GetIO();
io.KeysDown[e->key_code()] = true;
switch (e->key_code()) {
case 16: {
io.KeyShift = true;
} break;
case 17: {
io.KeyCtrl = true;
} break;
}
}
void ImGuiDrawer::OnKeyDown(KeyEvent* e) { OnKey(e, true); }
void ImGuiDrawer::OnKeyUp(KeyEvent* e) {
auto& io = GetIO();
io.KeysDown[e->key_code()] = false;
switch (e->key_code()) {
case 16: {
io.KeyShift = false;
} break;
case 17: {
io.KeyCtrl = false;
} break;
}
}
void ImGuiDrawer::OnKeyUp(KeyEvent* e) { OnKey(e, false); }
void ImGuiDrawer::OnKeyChar(KeyEvent* e) {
auto& io = GetIO();
if (e->key_code() > 0 && e->key_code() < 0x10000) {
io.AddInputCharacter(e->key_code());
// TODO(Triang3l): Accept the Unicode character.
unsigned int character = static_cast<unsigned int>(e->virtual_key());
if (character > 0 && character < 0x10000) {
io.AddInputCharacter(character);
e->set_handled(true);
}
}
@ -327,5 +308,30 @@ void ImGuiDrawer::OnMouseWheel(MouseEvent* e) {
io.MouseWheel += float(e->dy() / 120.0f);
}
void ImGuiDrawer::OnKey(KeyEvent* e, bool is_down) {
auto& io = GetIO();
VirtualKey virtual_key = e->virtual_key();
if (size_t(virtual_key) < xe::countof(io.KeysDown)) {
io.KeysDown[size_t(virtual_key)] = is_down;
}
switch (virtual_key) {
case VirtualKey::kShift:
io.KeyShift = is_down;
break;
case VirtualKey::kControl:
io.KeyCtrl = is_down;
break;
case VirtualKey::kMenu:
// FIXME(Triang3l): Doesn't work in xenia-ui-window-demo.
io.KeyAlt = is_down;
break;
case VirtualKey::kLWin:
io.KeySuper = is_down;
break;
default:
break;
}
}
} // namespace ui
} // namespace xe

View File

@ -57,6 +57,9 @@ class ImGuiDrawer : public WindowListener {
ImGuiContext* internal_state_ = nullptr;
std::unique_ptr<ImmediateTexture> font_texture_;
private:
void OnKey(KeyEvent* e, bool is_down);
};
} // namespace ui

View File

@ -12,6 +12,8 @@
#include <filesystem>
#include "xenia/ui/virtual_key.h"
namespace xe {
namespace ui {
@ -42,11 +44,12 @@ class FileDropEvent : public UIEvent {
class KeyEvent : public UIEvent {
public:
KeyEvent(Window* target, int key_code, int repeat_count, bool prev_state,
bool modifier_shift_pressed, bool modifier_ctrl_pressed,
bool modifier_alt_pressed, bool modifier_super_pressed)
KeyEvent(Window* target, VirtualKey virtual_key, int repeat_count,
bool prev_state, bool modifier_shift_pressed,
bool modifier_ctrl_pressed, bool modifier_alt_pressed,
bool modifier_super_pressed)
: UIEvent(target),
key_code_(key_code),
virtual_key_(virtual_key),
repeat_count_(repeat_count),
prev_state_(prev_state),
modifier_shift_pressed_(modifier_shift_pressed),
@ -58,7 +61,7 @@ class KeyEvent : public UIEvent {
bool is_handled() const { return handled_; }
void set_handled(bool value) { handled_ = value; }
int key_code() const { return key_code_; }
VirtualKey virtual_key() const { return virtual_key_; }
int repeat_count() const { return repeat_count_; }
bool prev_state() const { return prev_state_; }
@ -70,7 +73,7 @@ class KeyEvent : public UIEvent {
private:
bool handled_ = false;
int key_code_ = 0;
VirtualKey virtual_key_ = VirtualKey::kNone;
int repeat_count_ = 0;
bool prev_state_ = false; // Key previously down(true) or up(false)

362
src/xenia/ui/virtual_key.h Normal file
View File

@ -0,0 +1,362 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2021 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_VIRTUAL_KEY_H_
#define XENIA_UI_VIRTUAL_KEY_H_
#include <cstdint>
namespace xe {
namespace ui {
// Windows and Xbox 360 / XInput virtual key enumeration.
// This is what platform-specific keys should be translated to, for both HID
// keystroke emulation and Xenia-internal UI events. On Windows, the translation
// is a simple cast.
// This is uint16_t as it's WPARAM (which was 16-bit back in Win16 days, where
// virtual key codes were added), and XINPUT_KEYSTROKE stores the virtual key as
// a WORD. In some cases (see kPacket), bits above 16 may be used as well, but
// VK_ on Windows are defined up to 0xFF (0xFE not counting the reserved 0xFF)
// as of Windows SDK 10.0.19041.0, and XInput virtual key codes are 16-bit.
// Base virtual key codes as of _WIN32_WINNT 0x0500 (Windows 2000, which the
// Xbox 360's kernel is based on), virtual key codes added later are marked
// explicitly as such.
enum class VirtualKey : uint16_t {
// Not a valid key - MapVirtualKey returns zero when there is no translation.
kNone,
kLButton = 0x01,
kRButton = 0x02,
kCancel = 0x03, // Control-break.
kMButton = 0x04, // Not contiguous with kLButton and kRButton.
kXButton1 = 0x05, // Not contiguous with kLButton and kRButton.
kXButton2 = 0x06, // Not contiguous with kLButton and kRButton.
kBack = 0x08, // Backspace.
kTab = 0x09,
kClear = 0x0C,
kReturn = 0x0D, // Enter.
kShift = 0x10,
kControl = 0x11, // Ctrl.
kMenu = 0x12, // Alt.
kPause = 0x13,
kCapital = 0x14, // Caps Lock.
kKana = 0x15,
kHangeul = 0x15, // Old name.
kHangul = 0x15,
kImeOn = 0x16,
kJunja = 0x17,
kFinal = 0x18,
kHanja = 0x19,
kKanji = 0x19,
kImeOff = 0x1A,
kEscape = 0x1B,
kConvert = 0x1C,
kNonConvert = 0x1D,
kAccept = 0x1E,
kModeChange = 0x1F,
kSpace = 0x20,
kPrior = 0x21, // Page Up.
kNext = 0x22, // Page Down.
kEnd = 0x23,
kHome = 0x24,
kLeft = 0x25,
kUp = 0x26,
kRight = 0x27,
kDown = 0x28,
kSelect = 0x29,
kPrint = 0x2A,
kExecute = 0x2B,
kSnapshot = 0x2C,
kInsert = 0x2D,
kDelete = 0x2E,
kHelp = 0x2F,
// Same as ASCII '0' - '9'.
k0 = 0x30,
k1 = 0x31,
k2 = 0x32,
k3 = 0x33,
k4 = 0x34,
k5 = 0x35,
k6 = 0x36,
k7 = 0x37,
k8 = 0x38,
k9 = 0x39,
// Same as ASCII 'A' - 'Z'.
kA = 0x41,
kB = 0x42,
kC = 0x43,
kD = 0x44,
kE = 0x45,
kF = 0x46,
kG = 0x47,
kH = 0x48,
kI = 0x49,
kJ = 0x4A,
kK = 0x4B,
kL = 0x4C,
kM = 0x4D,
kN = 0x4E,
kO = 0x4F,
kP = 0x50,
kQ = 0x51,
kR = 0x52,
kS = 0x53,
kT = 0x54,
kU = 0x55,
kV = 0x56,
kW = 0x57,
kX = 0x58,
kY = 0x59,
kZ = 0x5A,
kLWin = 0x5B,
kRWin = 0x5C,
kApps = 0x5D,
kSleep = 0x5F,
kNumpad0 = 0x60,
kNumpad1 = 0x61,
kNumpad2 = 0x62,
kNumpad3 = 0x63,
kNumpad4 = 0x64,
kNumpad5 = 0x65,
kNumpad6 = 0x66,
kNumpad7 = 0x67,
kNumpad8 = 0x68,
kNumpad9 = 0x69,
kMultiply = 0x6A,
kAdd = 0x6B,
kSeparator = 0x6C,
kSubtract = 0x6D,
kDecimal = 0x6E,
kDivide = 0x6F,
kF1 = 0x70,
kF2 = 0x71,
kF3 = 0x72,
kF4 = 0x73,
kF5 = 0x74,
kF6 = 0x75,
kF7 = 0x76,
kF8 = 0x77,
kF9 = 0x78,
kF10 = 0x79,
kF11 = 0x7A,
kF12 = 0x7B,
kF13 = 0x7C,
kF14 = 0x7D,
kF15 = 0x7E,
kF16 = 0x7F,
kF17 = 0x80,
kF18 = 0x81,
kF19 = 0x82,
kF20 = 0x83,
kF21 = 0x84,
kF22 = 0x85,
kF23 = 0x86,
kF24 = 0x87,
// VK_NAVIGATION_* added in _WIN32_WINNT 0x0604, but marked as reserved in
// WinUser.h and not documented on MSDN.
kNavigationView = 0x88,
kNavigationMenu = 0x89,
kNavigationUp = 0x8A,
kNavigationDown = 0x8B,
kNavigationLeft = 0x8C,
kNavigationRight = 0x8D,
kNavigationAccept = 0x8E,
kNavigationCancel = 0x8F,
kNumLock = 0x90,
kScroll = 0x91,
// NEC PC-9800 keyboard.
kOemNecEqual = 0x92, // '=' key on the numpad.
// Fujitsu/OASYS keyboard.
kOemFjJisho = 0x92, // 'Dictionary' key.
kOemFjMasshou = 0x93, // 'Unregister word' key.
kOemFjTouroku = 0x94, // 'Register word' key.
kOemFjLOya = 0x95, // 'Left OYAYUBI' key.
kOemFjROya = 0x96, // 'Right OYAYUBI' key.
// Left and right Alt, Ctrl and Shift virtual keys.
// On Windows (from WinUser.h):
// "Used only as parameters to GetAsyncKeyState() and GetKeyState().
// No other API or message will distinguish left and right keys in this way."
kLShift = 0xA0,
kRShift = 0xA1,
kLControl = 0xA2,
kRControl = 0xA3,
kLMenu = 0xA4,
kRMenu = 0xA5,
kBrowserBack = 0xA6,
kBrowserForward = 0xA7,
kBrowserRefresh = 0xA8,
kBrowserStop = 0xA9,
kBrowserSearch = 0xAA,
kBrowserFavorites = 0xAB,
kBrowserHome = 0xAC,
kVolumeMute = 0xAD,
kVolumeDown = 0xAE,
kVolumeUp = 0xAF,
kMediaNextTrack = 0xB0,
kMediaPrevTrack = 0xB1,
kMediaStop = 0xB2,
kMediaPlayPause = 0xB3,
kLaunchMail = 0xB4,
kLaunchMediaSelect = 0xB5,
kLaunchApp1 = 0xB6,
kLaunchApp2 = 0xB7,
kOem1 = 0xBA, // ';:' for the US.
kOemPlus = 0xBB, // '+' for any country.
kOemComma = 0xBC, // ',' for any country.
kOemMinus = 0xBD, // '-' for any country.
kOemPeriod = 0xBE, // '.' for any country.
kOem2 = 0xBF, // '/?' for the US.
kOem3 = 0xC0, // '`~' for the US.
// VK_GAMEPAD_* (since _WIN32_WINNT 0x0604) virtual key codes are marked as
// reserved in WinUser.h and are mostly not documented on MSDN (with the
// exception of the Xbox Device Portal Remote Input REST API in the "UWP on
// Xbox One" section).
// Xenia uses VK_PAD_* (kXInputPad*) for HID emulation internally instead
// because XInput is the API used for the Xbox 360 controller.
// To avoid confusion between VK_GAMEPAD_* and VK_PAD_*, here they are
// prefixed with kXboxOne and kXInput respectively.
kXboxOneGamepadA = 0xC3,
kXboxOneGamepadB = 0xC4,
kXboxOneGamepadX = 0xC5,
kXboxOneGamepadY = 0xC6,
kXboxOneGamepadRightShoulder = 0xC7,
kXboxOneGamepadLeftShoulder = 0xC8,
kXboxOneGamepadLeftTrigger = 0xC9,
kXboxOneGamepadRightTrigger = 0xCA,
kXboxOneGamepadDpadUp = 0xCB,
kXboxOneGamepadDpadDown = 0xCC,
kXboxOneGamepadDpadLeft = 0xCD,
kXboxOneGamepadDpadRight = 0xCE,
kXboxOneGamepadMenu = 0xCF,
kXboxOneGamepadView = 0xD0,
kXboxOneGamepadLeftThumbstickButton = 0xD1,
kXboxOneGamepadRightThumbstickButton = 0xD2,
kXboxOneGamepadLeftThumbstickUp = 0xD3,
kXboxOneGamepadLeftThumbstickDown = 0xD4,
kXboxOneGamepadLeftThumbstickRight = 0xD5,
kXboxOneGamepadLeftThumbstickLeft = 0xD6,
kXboxOneGamepadRightThumbstickUp = 0xD7,
kXboxOneGamepadRightThumbstickDown = 0xD8,
kXboxOneGamepadRightThumbstickRight = 0xD9,
kXboxOneGamepadRightThumbstickLeft = 0xDA,
kOem4 = 0xDB, // '[{' for the US.
kOem5 = 0xDC, // '\|' for the US.
kOem6 = 0xDD, // ']}' for the US.
kOem7 = 0xDE, // ''"' for the US.
kOem8 = 0xDF,
kOemAx = 0xE1, // 'AX' key on the Japanese AX keyboard.
kOem102 = 0xE2, // "<>" or "\|" on the RT 102-key keyboard.
kIcoHelp = 0xE3, // Help key on the Olivetti keyboard (ICO).
kIco00 = 0xE4, // 00 key on the ICO.
kProcessKey = 0xE5,
kIcoClear = 0xE6,
// From MSDN:
// "Used to pass Unicode characters as if they were keystrokes. The VK_PACKET
// key is the low word of a 32-bit Virtual Key value used for non-keyboard
// input methods."
kPacket = 0xE7,
// Nokia/Ericsson.
kOemReset = 0xE9,
kOemJump = 0xEA,
kOemPa1 = 0xEB,
kOemPa2 = 0xEC,
kOemPa3 = 0xED,
kOemWsCtrl = 0xEE,
kOemCuSel = 0xEF,
kOemAttn = 0xF0,
kOemFinish = 0xF1,
kOemCopy = 0xF2,
kOemAuto = 0xF3,
kOemEnlW = 0xF4,
kOemBackTab = 0xF5,
kAttn = 0xF6,
kCrSel = 0xF7,
kExSel = 0xF8,
kErEof = 0xF9,
kPlay = 0xFA,
kZoom = 0xFB,
kNoName = 0xFC,
kPa1 = 0xFD,
kOemClear = 0xFE,
// VK_PAD_* from XInput.h for XInputGetKeystroke. kXInput prefix added to
// distinguish from VK_GAMEPAD_*, added much later for the Xbox One
// controller.
kXInputPadA = 0x5800,
kXInputPadB = 0x5801,
kXInputPadX = 0x5802,
kXInputPadY = 0x5803,
// RShoulder before LShoulder, not a typo.
kXInputPadRShoulder = 0x5804,
kXInputPadLShoulder = 0x5805,
kXInputPadLTrigger = 0x5806,
kXInputPadRTrigger = 0x5807,
kXInputPadDpadUp = 0x5810,
kXInputPadDpadDown = 0x5811,
kXInputPadDpadLeft = 0x5812,
kXInputPadDpadRight = 0x5813,
kXInputPadStart = 0x5814,
kXInputPadBack = 0x5815,
kXInputPadLThumbPress = 0x5816,
kXInputPadRThumbPress = 0x5817,
kXInputPadLThumbUp = 0x5820,
kXInputPadLThumbDown = 0x5821,
kXInputPadLThumbRight = 0x5822,
kXInputPadLThumbLeft = 0x5823,
kXInputPadLThumbUpLeft = 0x5824,
kXInputPadLThumbUpRight = 0x5825,
kXInputPadLThumbDownRight = 0x5826,
kXInputPadLThumbDownLeft = 0x5827,
kXInputPadRThumbUp = 0x5830,
kXInputPadRThumbDown = 0x5831,
kXInputPadRThumbRight = 0x5832,
kXInputPadRThumbLeft = 0x5833,
kXInputPadRThumbUpLeft = 0x5834,
kXInputPadRThumbUpRight = 0x5835,
kXInputPadRThumbDownRight = 0x5836,
kXInputPadRThumbDownLeft = 0x5837,
};
} // namespace ui
} // namespace xe
#endif // XENIA_UI_VIRTUAL_KEY_H_

View File

@ -259,20 +259,21 @@ void Window::OnLostFocus(UIEvent* e) {
void Window::OnKeyPress(KeyEvent* e, bool is_down, bool is_char) {
if (!is_char) {
switch (e->key_code()) {
case 16:
switch (e->virtual_key()) {
case VirtualKey::kShift:
modifier_shift_pressed_ = is_down;
break;
case 17:
case VirtualKey::kControl:
modifier_cntrl_pressed_ = is_down;
break;
// case xx:
// // alt ??
// modifier_alt_pressed_ = is_down;
// break;
case 91:
case VirtualKey::kMenu:
modifier_alt_pressed_ = is_down;
break;
case VirtualKey::kLWin:
modifier_super_pressed_ = is_down;
break;
default:
break;
}
}
}

View File

@ -18,6 +18,7 @@
#include "xenia/ui/graphics_provider.h"
#include "xenia/ui/imgui_dialog.h"
#include "xenia/ui/imgui_drawer.h"
#include "xenia/ui/virtual_key.h"
#include "xenia/ui/window.h"
namespace xe {
@ -92,10 +93,12 @@ int window_demo_main(const std::vector<std::string>& args) {
loop->on_quit.AddListener([&window](xe::ui::UIEvent* e) { window.reset(); });
window->on_key_down.AddListener([](xe::ui::KeyEvent* e) {
switch (e->key_code()) {
case 0x72: { // F3
switch (e->virtual_key()) {
case VirtualKey::kF3:
Profiler::ToggleDisplay();
} break;
break;
default:
break;
}
});

View File

@ -12,6 +12,7 @@
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/platform_linux.h"
#include "xenia/ui/virtual_key.h"
#include "xenia/ui/window_gtk.h"
namespace xe {
@ -350,9 +351,10 @@ bool GTKWindow::HandleKeyboard(GdkEventKey* event) {
bool ctrl_pressed = modifiers & GDK_CONTROL_MASK;
bool alt_pressed = modifiers & GDK_META_MASK;
bool super_pressed = modifiers & GDK_SUPER_MASK;
auto e =
KeyEvent(this, event->hardware_keycode, 1, event->type == GDK_KEY_RELEASE,
shift_pressed, ctrl_pressed, alt_pressed, super_pressed);
// TODO(Triang3l): event->hardware_keycode to VirtualKey translation.
auto e = KeyEvent(this, VirtualKey(event->hardware_keycode), 1,
event->type == GDK_KEY_RELEASE, shift_pressed, ctrl_pressed,
alt_pressed, super_pressed);
switch (event->type) {
case GDK_KEY_PRESS:
OnKeyDown(&e);

View File

@ -17,6 +17,7 @@
#include "xenia/base/filesystem.h"
#include "xenia/base/logging.h"
#include "xenia/base/platform_win.h"
#include "xenia/ui/virtual_key.h"
namespace xe {
namespace ui {
@ -706,7 +707,7 @@ bool Win32Window::HandleMouse(UINT message, WPARAM wParam, LPARAM lParam) {
bool Win32Window::HandleKeyboard(UINT message, WPARAM wParam, LPARAM lParam) {
auto e = KeyEvent(
this, static_cast<int>(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2),
this, VirtualKey(wParam), lParam & 0xFFFF0000, !!(lParam & 0x2),
!!(GetKeyState(VK_SHIFT) & 0x80), !!(GetKeyState(VK_CONTROL) & 0x80),
!!(GetKeyState(VK_MENU) & 0x80), !!(GetKeyState(VK_LWIN) & 0x80));
switch (message) {

View File

@ -25,7 +25,8 @@ void HostPathFile::Destroy() { delete this; }
X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
size_t byte_offset, size_t* out_bytes_read) {
if (!(file_access_ & FileAccess::kFileReadData)) {
if (!(file_access_ &
(FileAccess::kGenericRead | FileAccess::kFileReadData))) {
return X_STATUS_ACCESS_DENIED;
}
@ -39,8 +40,8 @@ X_STATUS HostPathFile::ReadSync(void* buffer, size_t buffer_length,
X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length,
size_t byte_offset,
size_t* out_bytes_written) {
if (!(file_access_ &
(FileAccess::kFileWriteData | FileAccess::kFileAppendData))) {
if (!(file_access_ & (FileAccess::kGenericWrite | FileAccess::kFileWriteData |
FileAccess::kFileAppendData))) {
return X_STATUS_ACCESS_DENIED;
}
@ -53,7 +54,8 @@ X_STATUS HostPathFile::WriteSync(const void* buffer, size_t buffer_length,
}
X_STATUS HostPathFile::SetLength(size_t length) {
if (!(file_access_ & FileAccess::kFileWriteData)) {
if (!(file_access_ &
(FileAccess::kGenericWrite | FileAccess::kFileWriteData))) {
return X_STATUS_ACCESS_DENIED;
}

View File

@ -117,7 +117,11 @@ Entry* VirtualFileSystem::ResolvePath(const std::string_view path) {
return xe::utf8::starts_with(normalized_path, d->mount_path());
});
if (it == devices_.cend()) {
XELOGE("ResolvePath({}) failed - device not found", path);
// Supress logging the error for ShaderDumpxe:\CompareBackEnds as this is
// not an actual problem nor something we care about.
if (path != "ShaderDumpxe:\\CompareBackEnds") {
XELOGE("ResolvePath({}) failed - device not found", path);
}
return nullptr;
}

View File

@ -1321,7 +1321,7 @@ def find_xenia_source_files():
return [os.path.join(root, name)
for root, dirs, files in os.walk('src')
for name in files
if name.endswith(('.cc', '.c', '.h', '.inl'))]
if name.endswith(('.cc', '.c', '.h', '.inl', '.inc'))]
def find_all_source_files():