[LINT] Linted files + Added lint job to CI

This commit is contained in:
Gliniak 2024-03-12 08:59:10 +01:00 committed by Radosław Gliński
parent e8afad8f8a
commit b9061e6292
117 changed files with 1177 additions and 883 deletions

View File

@ -44,37 +44,51 @@ on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
lint:
name: Lint
runs-on: windows-2022
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check Clang-Format Version
run: clang-format --version
- name: Lint
run: .\xb lint --all
build-windows: build-windows:
name: Build (Windows) # runner.os can't be used here name: Build (Windows) # runner.os can't be used here
runs-on: windows-2022 runs-on: windows-2022
env: env:
POWERSHELL_TELEMETRY_OPTOUT: 1 POWERSHELL_TELEMETRY_OPTOUT: 1
needs: lint
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup - name: Setup
run: .\xb setup run: .\xb setup
- name: Build - name: Build
run: .\xb build --config=Release --target=src\xenia-app --target=src\xenia-vfs-dump run: .\xb build --config=Release --target=src\xenia-app
- name: Prepare artifacts - name: Prepare artifacts
run: | run: |
robocopy . build\bin\${{ runner.os }}\Release LICENSE /r:0 /w:0 robocopy . build\bin\${{ runner.os }}\Release LICENSE /r:0 /w:0
robocopy build\bin\${{ runner.os }}\Release artifacts\xenia_canary xenia_canary.exe xenia_canary.pdb LICENSE /r:0 /w:0 robocopy build\bin\${{ runner.os }}\Release artifacts\xenia_canary xenia_canary.exe xenia_canary.pdb LICENSE /r:0 /w:0
robocopy build\bin\${{ runner.os }}\Release artifacts\xenia-vfs-dump xenia-vfs-dump.exe xenia-vfs-dump.pdb LICENSE /r:0 /w:0
If ($LastExitCode -le 7) { echo "LastExitCode = $LastExitCode";$LastExitCode = 0 } If ($LastExitCode -le 7) { echo "LastExitCode = $LastExitCode";$LastExitCode = 0 }
- name: Upload xenia-vfs-dump artifacts
uses: actions/upload-artifact@v4
with:
name: xenia-vfs-dump_canary
path: artifacts\xenia-vfs-dump
if-no-files-found: error
- name: Upload xenia canary artifacts - name: Upload xenia canary artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: xenia_canary name: xenia_canary
path: artifacts\xenia_canary path: artifacts\xenia_canary
if-no-files-found: error if-no-files-found: error
- name: Create release - name: Create release
if: | if: |
github.repository == 'xenia-canary/xenia-canary' && github.repository == 'xenia-canary/xenia-canary' &&

View File

@ -35,9 +35,10 @@
// and let the normal AudioSystem handling take it, to prevent duplicate // and let the normal AudioSystem handling take it, to prevent duplicate
// implementations. They can be found in xboxkrnl_audio_xma.cc // implementations. They can be found in xboxkrnl_audio_xma.cc
DEFINE_uint32( DEFINE_uint32(apu_max_queued_frames, 64,
apu_max_queued_frames, 64, "Allows changing max buffered audio frames to reduce audio "
"Allows changing max buffered audio frames to reduce audio delay. Minimum is 16.", "APU"); "delay. Minimum is 16.",
"APU");
namespace xe { namespace xe {
namespace apu { namespace apu {
@ -76,11 +77,14 @@ X_STATUS AudioSystem::Setup(kernel::KernelState* kernel_state) {
} }
worker_running_ = true; worker_running_ = true;
worker_thread_ = kernel::object_ref<kernel::XHostThread>( worker_thread_ =
new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() { kernel::object_ref<kernel::XHostThread>(new kernel::XHostThread(
kernel_state, 128 * 1024, 0,
[this]() {
WorkerThreadMain(); WorkerThreadMain();
return 0; return 0;
}, kernel_state->GetSystemProcess())); },
kernel_state->GetSystemProcess()));
// As we run audio callbacks the debugger must be able to suspend us. // As we run audio callbacks the debugger must be able to suspend us.
worker_thread_->set_can_debugger_suspend(true); worker_thread_->set_can_debugger_suspend(true);
worker_thread_->set_name("Audio Worker"); worker_thread_->set_name("Audio Worker");

View File

@ -21,7 +21,6 @@ namespace conversion {
#if XE_ARCH_AMD64 #if XE_ARCH_AMD64
XE_NOINLINE XE_NOINLINE
static void _generic_sequential_6_BE_to_interleaved_6_LE( static void _generic_sequential_6_BE_to_interleaved_6_LE(
float* XE_RESTRICT output, const float* XE_RESTRICT input, float* XE_RESTRICT output, const float* XE_RESTRICT input,

View File

@ -18,8 +18,8 @@
#include "xenia/base/string_buffer.h" #include "xenia/base/string_buffer.h"
#include "xenia/cpu/processor.h" #include "xenia/cpu/processor.h"
#include "xenia/cpu/thread_state.h" #include "xenia/cpu/thread_state.h"
#include "xenia/kernel/xthread.h"
#include "xenia/kernel/kernel_state.h" #include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/xthread.h"
extern "C" { extern "C" {
#include "third_party/FFmpeg/libavutil/log.h" #include "third_party/FFmpeg/libavutil/log.h"
} // extern "C" } // extern "C"
@ -102,8 +102,7 @@ void av_log_callback(void* avcl, int level, const char* fmt, va_list va) {
StringBuffer buff; StringBuffer buff;
buff.AppendVarargs(fmt, va); buff.AppendVarargs(fmt, va);
xe::logging::AppendLogLineFormat(LogSrc::Apu, log_level, level_char, xe::logging::AppendLogLineFormat(LogSrc::Apu, log_level, level_char,
"ffmpeg: {}", "ffmpeg: {}", buff.to_string_view());
buff.to_string_view());
} }
X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) { X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
@ -141,11 +140,16 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
worker_running_ = true; worker_running_ = true;
work_event_ = xe::threading::Event::CreateAutoResetEvent(false); work_event_ = xe::threading::Event::CreateAutoResetEvent(false);
assert_not_null(work_event_); assert_not_null(work_event_);
worker_thread_ = kernel::object_ref<kernel::XHostThread>( worker_thread_ =
new kernel::XHostThread(kernel_state, 128 * 1024, 0, [this]() { kernel::object_ref<kernel::XHostThread>(new kernel::XHostThread(
kernel_state, 128 * 1024, 0,
[this]() {
WorkerThreadMain(); WorkerThreadMain();
return 0; return 0;
}, kernel_state->GetIdleProcess()));//this one doesnt need any process actually. never calls any guest code },
kernel_state
->GetIdleProcess())); // this one doesnt need any process
// actually. never calls any guest code
worker_thread_->set_name("XMA Decoder"); worker_thread_->set_name("XMA Decoder");
worker_thread_->set_can_debugger_suspend(true); worker_thread_->set_can_debugger_suspend(true);
worker_thread_->Create(); worker_thread_->Create();

View File

@ -39,8 +39,8 @@ class Clock {
// Host tick count. Generally QueryHostTickCount() should be used. // Host tick count. Generally QueryHostTickCount() should be used.
static uint64_t host_tick_count_platform(); static uint64_t host_tick_count_platform();
#if XE_CLOCK_RAW_AVAILABLE #if XE_CLOCK_RAW_AVAILABLE
//chrispy: the way msvc was ordering the branches was causing rdtsc to be speculatively executed each time // chrispy: the way msvc was ordering the branches was causing rdtsc to be
//the branch history was lost // speculatively executed each time the branch history was lost
XE_NOINLINE XE_NOINLINE
static uint64_t host_tick_count_raw(); static uint64_t host_tick_count_raw();
#endif #endif

View File

@ -41,9 +41,6 @@
"\n" \ "\n" \
"Set the cvar 'clock_source_raw' to 'false'."); "Set the cvar 'clock_source_raw' to 'false'.");
namespace xe { namespace xe {
// Getting the TSC frequency can be a bit tricky. This method here only works on // Getting the TSC frequency can be a bit tricky. This method here only works on
// Intel as it seems. There is no easy way to get the frequency outside of ring0 // Intel as it seems. There is no easy way to get the frequency outside of ring0
@ -75,8 +72,6 @@ uint64_t Clock::host_tick_frequency_raw() {
return 0; return 0;
} }
if (max_cpuid >= 0x15) { if (max_cpuid >= 0x15) {
// 15H Get TSC/Crystal ratio and Crystal Hz. // 15H Get TSC/Crystal ratio and Crystal Hz.
xe_cpu_cpuid(0x15, eax, ebx, ecx, edx); xe_cpu_cpuid(0x15, eax, ebx, ecx, edx);
@ -98,7 +93,6 @@ uint64_t Clock::host_tick_frequency_raw() {
return cpu_base_freq; return cpu_base_freq;
} }
CLOCK_FATAL("The clock frequency could not be determined."); CLOCK_FATAL("The clock frequency could not be determined.");
return 0; return 0;
} }

View File

@ -35,7 +35,6 @@ static bool has_shell_environment_variable() {
} }
void AttachConsole() { void AttachConsole() {
bool has_console = ::AttachConsole(ATTACH_PARENT_PROCESS) == TRUE; bool has_console = ::AttachConsole(ATTACH_PARENT_PROCESS) == TRUE;
#if 0 #if 0
if (!has_console || !has_shell_environment_variable()) { if (!has_console || !has_shell_environment_variable()) {

View File

@ -172,8 +172,7 @@ CommandVar<T>::CommandVar(const char* name, T* default_value,
default_value_(*default_value), default_value_(*default_value),
current_value_(default_value), current_value_(default_value),
commandline_value_(), commandline_value_(),
description_(description) description_(description) {}
{}
template <class T> template <class T>
ConfigVar<T>::ConfigVar(const char* name, T* default_value, ConfigVar<T>::ConfigVar(const char* name, T* default_value,

View File

@ -606,7 +606,8 @@ union IDivExtraInfo {
} info; } info;
}; };
// returns magicnum multiplier // returns magicnum multiplier
static constexpr uint32_t PregenerateUint32Div(uint32_t _denom, uint32_t& out_extra) { static constexpr uint32_t PregenerateUint32Div(uint32_t _denom,
uint32_t& out_extra) {
IDivExtraInfo extra{}; IDivExtraInfo extra{};
uint32_t d = _denom; uint32_t d = _denom;
@ -662,7 +663,8 @@ static constexpr uint32_t ApplyUint32Div(uint32_t num, uint32_t mul,
extra.value_ = extradata; extra.value_ = extradata;
uint32_t result = static_cast<uint32_t>((static_cast<uint64_t>(num) * static_cast<uint64_t>(mul)) >> 32); uint32_t result = static_cast<uint32_t>(
(static_cast<uint64_t>(num) * static_cast<uint64_t>(mul)) >> 32);
if (extra.info.add_) { if (extra.info.add_) {
uint32_t addend = result + num; uint32_t addend = result + num;
addend = ((addend < result ? 0x80000000 : 0) | addend); addend = ((addend < result ? 0x80000000 : 0) | addend);
@ -672,7 +674,8 @@ static constexpr uint32_t ApplyUint32Div(uint32_t num, uint32_t mul,
} }
static constexpr uint32_t ApplyUint32UMod(uint32_t num, uint32_t mul, static constexpr uint32_t ApplyUint32UMod(uint32_t num, uint32_t mul,
uint32_t extradata, uint32_t original) { uint32_t extradata,
uint32_t original) {
uint32_t dived = ApplyUint32Div(num, mul, extradata); uint32_t dived = ApplyUint32Div(num, mul, extradata);
unsigned result = num - (dived * original); unsigned result = num - (dived * original);
@ -701,8 +704,7 @@ struct MagicDiv {
return extra.info.shift_; return extra.info.shift_;
} }
constexpr uint32_t GetMultiplier() const { return multiplier_; constexpr uint32_t GetMultiplier() const { return multiplier_; }
}
constexpr uint32_t Apply(uint32_t numerator) const { constexpr uint32_t Apply(uint32_t numerator) const {
return ApplyUint32Div(numerator, multiplier_, extradata_); return ApplyUint32Div(numerator, multiplier_, extradata_);
} }

View File

@ -180,7 +180,8 @@ static void vastcpy_impl_repmovs(CacheLine* XE_RESTRICT physaddr,
__movsq((unsigned long long*)physaddr, (unsigned long long*)rdmapping, __movsq((unsigned long long*)physaddr, (unsigned long long*)rdmapping,
written_length / 8); written_length / 8);
#else #else
memcpy((unsigned char*)physaddr, (const unsigned char*)rdmapping, written_length); memcpy((unsigned char*)physaddr, (const unsigned char*)rdmapping,
written_length);
#endif #endif
} }
XE_COLD XE_COLD
@ -331,9 +332,9 @@ void copy_and_swap_32_unaligned(void* dest_ptr, const void* src_ptr,
__m256i output1 = _mm256_shuffle_epi8(input1, shufmask); __m256i output1 = _mm256_shuffle_epi8(input1, shufmask);
__m256i output2 = _mm256_shuffle_epi8(input2, shufmask); __m256i output2 = _mm256_shuffle_epi8(input2, shufmask);
//chrispy: todo, benchmark this w/ and w/out these prefetches here on multiple machines // chrispy: todo, benchmark this w/ and w/out these prefetches here on multiple
//finding a good distance for prefetchw in particular is probably important // machines finding a good distance for prefetchw in particular is probably
//for when we're writing across 2 cachelines // important for when we're writing across 2 cachelines
#if 0 #if 0
if (i + 48 <= count) { if (i + 48 <= count) {
swcache::PrefetchNTA(&src[i + 32]); swcache::PrefetchNTA(&src[i + 32]);

View File

@ -17,10 +17,8 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include "xenia/base/byte_order.h" #include "xenia/base/byte_order.h"
namespace xe { namespace xe {
namespace memory { namespace memory {

View File

@ -10,8 +10,8 @@
#ifndef XENIA_BASE_MUTEX_H_ #ifndef XENIA_BASE_MUTEX_H_
#define XENIA_BASE_MUTEX_H_ #define XENIA_BASE_MUTEX_H_
#include <mutex> #include <mutex>
#include "platform.h"
#include "memory.h" #include "memory.h"
#include "platform.h"
#define XE_ENABLE_FAST_WIN32_MUTEX 1 #define XE_ENABLE_FAST_WIN32_MUTEX 1
namespace xe { namespace xe {

View File

@ -68,7 +68,6 @@ class RingBuffer {
ring_size_t offset_delta = write_offs - read_offs; ring_size_t offset_delta = write_offs - read_offs;
ring_size_t wrap_read_count = (cap - read_offs) + write_offs; ring_size_t wrap_read_count = (cap - read_offs) + write_offs;
if (XE_LIKELY(read_offs <= write_offs)) { if (XE_LIKELY(read_offs <= write_offs)) {
return offset_delta; // will be 0 if they are equal, semantically return offset_delta; // will be 0 if they are equal, semantically
// identical to old code (i checked the asm, msvc // identical to old code (i checked the asm, msvc

View File

@ -34,7 +34,6 @@ struct SimpleFreelist {
node->next_ = head_; node->next_ = head_;
head_ = node; head_ = node;
} }
void Reset() { head_ = nullptr; void Reset() { head_ = nullptr; }
}
}; };
} // namespace xe } // namespace xe

View File

@ -33,7 +33,9 @@ using WaitItem = TimerQueueWaitItem;
*/ */
/* /*
edit: actually had to change it back, when i was testing it only worked because i fixed disruptorplus' code to compile (it gives wrong args to condition_variable::wait_until) but now builds edit: actually had to change it back, when i was testing it only worked
because i fixed disruptorplus' code to compile (it gives wrong args to
condition_variable::wait_until) but now builds
*/ */
using WaitStrat = dp::blocking_wait_strategy; using WaitStrat = dp::blocking_wait_strategy;

View File

@ -78,7 +78,8 @@ class Backend {
virtual void InitializeBackendContext(void* ctx) {} virtual void InitializeBackendContext(void* ctx) {}
/* /*
Free any dynamically allocated data/resources that the backendcontext uses Free any dynamically allocated data/resources that the backendcontext
uses
*/ */
virtual void DeinitializeBackendContext(void* ctx) {} virtual void DeinitializeBackendContext(void* ctx) {}
virtual void SetGuestRoundingMode(void* ctx, unsigned int mode){}; virtual void SetGuestRoundingMode(void* ctx, unsigned int mode){};

View File

@ -314,7 +314,6 @@ SIMPLE_THREEOPERAND(vpshaw, xop_VPSHAW)
SIMPLE_THREEOPERAND(vpshad, xop_VPSHAD) SIMPLE_THREEOPERAND(vpshad, xop_VPSHAD)
SIMPLE_THREEOPERAND(vpshaq, xop_VPSHAQ) SIMPLE_THREEOPERAND(vpshaq, xop_VPSHAQ)
SIMPLE_THREEOPERAND(vpshlb, xop_VPSHLB) SIMPLE_THREEOPERAND(vpshlb, xop_VPSHLB)
SIMPLE_THREEOPERAND(vpshlw, xop_VPSHLW) SIMPLE_THREEOPERAND(vpshlw, xop_VPSHLW)
SIMPLE_THREEOPERAND(vpshld, xop_VPSHLD) SIMPLE_THREEOPERAND(vpshld, xop_VPSHLD)

View File

@ -924,7 +924,8 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
Xbyak::Label L18, L2, L35, L4, L9, L8, L10, L11, L12, L13, L1; Xbyak::Label L18, L2, L35, L4, L9, L8, L10, L11, L12, L13, L1;
Xbyak::Label LC1, _LCPI3_1; Xbyak::Label LC1, _LCPI3_1;
Xbyak::Label handle_denormal_input; Xbyak::Label handle_denormal_input;
Xbyak::Label specialcheck_1, convert_to_signed_inf_and_ret, handle_oddball_denormal; Xbyak::Label specialcheck_1, convert_to_signed_inf_and_ret,
handle_oddball_denormal;
auto emulate_lzcnt_helper_unary_reg = [this](auto& reg, auto& scratch_reg) { auto emulate_lzcnt_helper_unary_reg = [this](auto& reg, auto& scratch_reg) {
inLocalLabel(); inLocalLabel();
@ -1107,7 +1108,8 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
xchg(ecx, edx); xchg(ecx, edx);
// esi is just the value of xmm0's low word, so we can restore it from there // esi is just the value of xmm0's low word, so we can restore it from there
shl(r8d, cl); shl(r8d, cl);
mov(ecx, edx); // restore ecx, dont xchg because we're going to spoil edx anyway mov(ecx,
edx); // restore ecx, dont xchg because we're going to spoil edx anyway
mov(edx, r8d); mov(edx, r8d);
vmovd(r8d, xmm0); vmovd(r8d, xmm0);
} }
@ -1131,7 +1133,8 @@ void* X64HelperEmitter::EmitScalarVRsqrteHelper() {
dd(0xFF800000); dd(0xFF800000);
dd(0x7F800000); dd(0x7F800000);
L(LC1); L(LC1);
//the position of 7FC00000 here matters, this address will be indexed in handle_oddball_denormal // the position of 7FC00000 here matters, this address will be indexed in
// handle_oddball_denormal
dd(0x7FC00000); dd(0x7FC00000);
dd(0x5F34FD00); dd(0x5F34FD00);
@ -1148,11 +1151,13 @@ void* X64HelperEmitter::EmitVectorVRsqrteHelper(void* scalar_helper) {
Xbyak::Label check_scalar_operation_in_vmx, actual_vector_version; Xbyak::Label check_scalar_operation_in_vmx, actual_vector_version;
auto result_ptr = auto result_ptr =
GetBackendCtxPtr(offsetof(X64BackendContext, helper_scratch_xmms[0])); GetBackendCtxPtr(offsetof(X64BackendContext, helper_scratch_xmms[0]));
auto counter_ptr = GetBackendCtxPtr(offsetof(X64BackendContext, helper_scratch_u64s[2])); auto counter_ptr =
GetBackendCtxPtr(offsetof(X64BackendContext, helper_scratch_u64s[2]));
counter_ptr.setBit(64); counter_ptr.setBit(64);
// shuffle and xor to check whether all lanes are equal // shuffle and xor to check whether all lanes are equal
//sadly has to leave the float pipeline for the vptest, which is moderate yikes // sadly has to leave the float pipeline for the vptest, which is moderate
// yikes
vmovhlps(xmm2, xmm0, xmm0); vmovhlps(xmm2, xmm0, xmm0);
vmovsldup(xmm1, xmm0); vmovsldup(xmm1, xmm0);
vxorps(xmm1, xmm1, xmm0); vxorps(xmm1, xmm1, xmm0);

View File

@ -12,8 +12,8 @@
#include <memory> #include <memory>
#include "xenia/base/cvar.h"
#include "xenia/base/bit_map.h" #include "xenia/base/bit_map.h"
#include "xenia/base/cvar.h"
#include "xenia/cpu/backend/backend.h" #include "xenia/cpu/backend/backend.h"
#if XE_PLATFORM_WIN32 == 1 #if XE_PLATFORM_WIN32 == 1
@ -45,8 +45,9 @@ typedef void (*ResolveFunctionThunk)();
/* /*
place guest trampolines in the memory range that the HV normally occupies. place guest trampolines in the memory range that the HV normally occupies.
This way guests can call in via the indirection table and we don't have to clobber/reuse an existing memory range This way guests can call in via the indirection table and we don't have to
The xboxkrnl range is already used by export trampolines (see kernel/kernel_module.cc) clobber/reuse an existing memory range The xboxkrnl range is already used by
export trampolines (see kernel/kernel_module.cc)
*/ */
static constexpr uint32_t GUEST_TRAMPOLINE_BASE = 0x80000000; static constexpr uint32_t GUEST_TRAMPOLINE_BASE = 0x80000000;
static constexpr uint32_t GUEST_TRAMPOLINE_END = 0x80040000; static constexpr uint32_t GUEST_TRAMPOLINE_END = 0x80040000;
@ -78,8 +79,10 @@ struct X64BackendStackpoint {
enum : uint32_t { enum : uint32_t {
kX64BackendMXCSRModeBit = 0, kX64BackendMXCSRModeBit = 0,
kX64BackendHasReserveBit = 1, kX64BackendHasReserveBit = 1,
kX64BackendNJMOn = 2, //non-java mode bit is currently set. for use in software fp routines kX64BackendNJMOn =
kX64BackendNonIEEEMode = 3, //non-ieee mode is currently enabled for scalar fpu. 2, // non-java mode bit is currently set. for use in software fp routines
kX64BackendNonIEEEMode =
3, // non-ieee mode is currently enabled for scalar fpu.
}; };
// located prior to the ctx register // located prior to the ctx register
// some things it would be nice to have be per-emulator instance instead of per // some things it would be nice to have be per-emulator instance instead of per
@ -170,8 +173,8 @@ class X64Backend : public Backend {
reinterpret_cast<intptr_t>(ctx) - sizeof(X64BackendContext)); reinterpret_cast<intptr_t>(ctx) - sizeof(X64BackendContext));
} }
virtual uint32_t CreateGuestTrampoline(GuestTrampolineProc proc, virtual uint32_t CreateGuestTrampoline(GuestTrampolineProc proc,
void* userdata1, void* userdata1, void* userdata2,
void* userdata2, bool long_term) override; bool long_term) override;
virtual void FreeGuestTrampoline(uint32_t trampoline_addr) override; virtual void FreeGuestTrampoline(uint32_t trampoline_addr) override;
virtual void SetGuestRoundingMode(void* ctx, unsigned int mode) override; virtual void SetGuestRoundingMode(void* ctx, unsigned int mode) override;
@ -213,6 +216,7 @@ class X64Backend : public Backend {
void* vrsqrtefp_vector_helper = nullptr; void* vrsqrtefp_vector_helper = nullptr;
void* vrsqrtefp_scalar_helper = nullptr; void* vrsqrtefp_scalar_helper = nullptr;
void* frsqrtefp_helper = nullptr; void* frsqrtefp_helper = nullptr;
private: private:
#if XE_X64_PROFILER_AVAILABLE == 1 #if XE_X64_PROFILER_AVAILABLE == 1
GuestProfilerData profiler_data_; GuestProfilerData profiler_data_;

View File

@ -93,7 +93,8 @@ class X64CodeCache : public CodeCache {
// This is picked to be high enough to cover whatever we can reasonably // This is picked to be high enough to cover whatever we can reasonably
// expect. If we hit issues with this it probably means some corner case // expect. If we hit issues with this it probably means some corner case
// in analysis triggering. // in analysis triggering.
//chrispy: raised this, some games that were compiled with low optimization levels can exceed this // chrispy: raised this, some games that were compiled with low optimization
// levels can exceed this
static const size_t kMaximumFunctionCount = 1000000; static const size_t kMaximumFunctionCount = 1000000;
struct UnwindReservation { struct UnwindReservation {

View File

@ -213,7 +213,8 @@ Win32X64CodeCache::RequestUnwindReservation(uint8_t* entry_address) {
if (unwind_table_count_ >= kMaximumFunctionCount) { if (unwind_table_count_ >= kMaximumFunctionCount) {
// we should not just be ignoring this in release if it happens // we should not just be ignoring this in release if it happens
xe::FatalError( xe::FatalError(
"Unwind table count (unwind_table_count_) exceeded maximum! Please report this to " "Unwind table count (unwind_table_count_) exceeded maximum! Please "
"report this to "
"Xenia/Canary developers"); "Xenia/Canary developers");
} }
#else #else

View File

@ -210,13 +210,15 @@ bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
// Adding or changing anything here must be matched! // Adding or changing anything here must be matched!
/* /*
pick a page to use as the local base as close to the commonly accessed page that contains most backend fields pick a page to use as the local base as close to the commonly accessed page
the sizes that are checked are chosen based on PTE coalescing sizes. zen does 16k or 32k that contains most backend fields the sizes that are checked are chosen
based on PTE coalescing sizes. zen does 16k or 32k
*/ */
size_t stack_size = StackLayout::GUEST_STACK_SIZE; size_t stack_size = StackLayout::GUEST_STACK_SIZE;
if (stack_offset < (4096 - sizeof(X64BackendContext))) { if (stack_offset < (4096 - sizeof(X64BackendContext))) {
locals_page_delta_ = 4096; locals_page_delta_ = 4096;
} else if (stack_offset < (16384 - sizeof(X64BackendContext))) {//16k PTE coalescing } else if (stack_offset <
(16384 - sizeof(X64BackendContext))) { // 16k PTE coalescing
locals_page_delta_ = 16384; locals_page_delta_ = 16384;
} else if (stack_offset < (32768 - sizeof(X64BackendContext))) { } else if (stack_offset < (32768 - sizeof(X64BackendContext))) {
locals_page_delta_ = 32768; locals_page_delta_ = 32768;
@ -224,7 +226,8 @@ bool X64Emitter::Emit(HIRBuilder* builder, EmitFunctionInfo& func_info) {
locals_page_delta_ = 65536; locals_page_delta_ = 65536;
} else { } else {
// extremely unlikely, fall back to stack // extremely unlikely, fall back to stack
stack_size = xe::align<size_t>(StackLayout::GUEST_STACK_SIZE + stack_offset, 16); stack_size =
xe::align<size_t>(StackLayout::GUEST_STACK_SIZE + stack_offset, 16);
locals_page_delta_ = 0; locals_page_delta_ = 0;
} }
@ -1267,12 +1270,13 @@ uintptr_t X64Emitter::PlaceConstData() {
std::memcpy(mem, xmm_consts, sizeof(xmm_consts)); std::memcpy(mem, xmm_consts, sizeof(xmm_consts));
/* /*
set each 32-bit element of the constant XMMVRsqrteTableBase to be the address of the start of the constant XMMVRsqrteTableStart set each 32-bit element of the constant XMMVRsqrteTableBase to be the
this address of the start of the constant XMMVRsqrteTableStart this
*/ */
vec128_t* deferred_constants = reinterpret_cast<vec128_t*>(mem); vec128_t* deferred_constants = reinterpret_cast<vec128_t*>(mem);
vec128_t* vrsqrte_table_base = &deferred_constants[XMMVRsqrteTableBase]; vec128_t* vrsqrte_table_base = &deferred_constants[XMMVRsqrteTableBase];
uint32_t ptr_to_vrsqrte_table32 = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&deferred_constants[XMMVRsqrteTableStart])); uint32_t ptr_to_vrsqrte_table32 = static_cast<uint32_t>(
reinterpret_cast<uintptr_t>(&deferred_constants[XMMVRsqrteTableStart]));
*vrsqrte_table_base = vec128i(ptr_to_vrsqrte_table32); *vrsqrte_table_base = vec128i(ptr_to_vrsqrte_table32);
memory::Protect(mem, kConstDataSize, memory::PageAccess::kReadOnly, nullptr); memory::Protect(mem, kConstDataSize, memory::PageAccess::kReadOnly, nullptr);
@ -1288,8 +1292,10 @@ void X64Emitter::FreeConstData(uintptr_t data) {
Xbyak::Address X64Emitter::GetXmmConstPtr(XmmConst id) { Xbyak::Address X64Emitter::GetXmmConstPtr(XmmConst id) {
// Load through fixed constant table setup by PlaceConstData. // Load through fixed constant table setup by PlaceConstData.
// It's important that the pointer is not signed, as it will be sign-extended. // It's important that the pointer is not signed, as it will be sign-extended.
void* emitter_data_ptr = backend_->LookupXMMConstantAddress(static_cast<unsigned>(id)); void* emitter_data_ptr =
xenia_assert(reinterpret_cast<uintptr_t>(emitter_data_ptr) < (1ULL << 31));//must not have signbit set backend_->LookupXMMConstantAddress(static_cast<unsigned>(id));
xenia_assert(reinterpret_cast<uintptr_t>(emitter_data_ptr) <
(1ULL << 31)); // must not have signbit set
return ptr[emitter_data_ptr]; return ptr[emitter_data_ptr];
} }
// Implies possible StashXmm(0, ...)! // Implies possible StashXmm(0, ...)!

View File

@ -176,7 +176,10 @@ enum XmmConst {
XMMVSRShlByteshuf, XMMVSRShlByteshuf,
XMMVSRMask, XMMVSRMask,
XMMVRsqrteTableStart, XMMVRsqrteTableStart,
XMMVRsqrteTableBase = XMMVRsqrteTableStart + (32 / 4), //32 4-byte elements in table, 4 4-byte elements fit in each xmm XMMVRsqrteTableBase =
XMMVRsqrteTableStart +
(32 /
4), // 32 4-byte elements in table, 4 4-byte elements fit in each xmm
}; };
using amdfx::xopcompare_e; using amdfx::xopcompare_e;
@ -390,6 +393,7 @@ class X64Emitter : public Xbyak::CodeGenerator {
void EmitGetCurrentThreadId(); void EmitGetCurrentThreadId();
void EmitTraceUserCallReturn(); void EmitTraceUserCallReturn();
static void HandleStackpointOverflowError(ppc::PPCContext* context); static void HandleStackpointOverflowError(ppc::PPCContext* context);
protected: protected:
Processor* processor_ = nullptr; Processor* processor_ = nullptr;
X64Backend* backend_ = nullptr; X64Backend* backend_ = nullptr;

View File

@ -398,8 +398,7 @@ struct I<OPCODE, DEST, SRC1, SRC2, SRC3> : DestField<DEST> {
}; };
template <typename T> template <typename T>
XE_MAYBE_UNUSED XE_MAYBE_UNUSED static const T GetTempReg(X64Emitter& e);
static const T GetTempReg(X64Emitter& e);
template <> template <>
XE_MAYBE_UNUSED const Reg8 GetTempReg<Reg8>(X64Emitter& e) { XE_MAYBE_UNUSED const Reg8 GetTempReg<Reg8>(X64Emitter& e) {
return e.al; return e.al;

View File

@ -705,7 +705,8 @@ struct STORE_LOCAL_I16
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
// e.TraceStoreI16(DATA_LOCAL, i.src1.constant, i.src2); // e.TraceStoreI16(DATA_LOCAL, i.src1.constant, i.src2);
if (LocalStoreMayUseMembaseLow(e, i)) { if (LocalStoreMayUseMembaseLow(e, i)) {
e.mov(e.word[e.GetLocalsBase() + i.src1.constant()], e.GetMembaseReg().cvt16()); e.mov(e.word[e.GetLocalsBase() + i.src1.constant()],
e.GetMembaseReg().cvt16());
} else { } else {
e.mov(e.word[e.GetLocalsBase() + i.src1.constant()], i.src2); e.mov(e.word[e.GetLocalsBase() + i.src1.constant()], i.src2);
} }
@ -716,7 +717,8 @@ struct STORE_LOCAL_I32
static void Emit(X64Emitter& e, const EmitArgType& i) { static void Emit(X64Emitter& e, const EmitArgType& i) {
// e.TraceStoreI32(DATA_LOCAL, i.src1.constant, i.src2); // e.TraceStoreI32(DATA_LOCAL, i.src1.constant, i.src2);
if (LocalStoreMayUseMembaseLow(e, i)) { if (LocalStoreMayUseMembaseLow(e, i)) {
e.mov(e.dword[e.GetLocalsBase() + i.src1.constant()], e.GetMembaseReg().cvt32()); e.mov(e.dword[e.GetLocalsBase() + i.src1.constant()],
e.GetMembaseReg().cvt32());
} else { } else {
e.mov(e.dword[e.GetLocalsBase() + i.src1.constant()], i.src2); e.mov(e.dword[e.GetLocalsBase() + i.src1.constant()], i.src2);
} }

View File

@ -2120,9 +2120,9 @@ struct RSQRT_V128 : Sequence<RSQRT_V128, I<OPCODE_RSQRT, V128Op, V128Op>> {
e.ChangeMxcsrMode(MXCSRMode::Vmx); e.ChangeMxcsrMode(MXCSRMode::Vmx);
Xmm src1 = GetInputRegOrConstant(e, i.src1, e.xmm3); Xmm src1 = GetInputRegOrConstant(e, i.src1, e.xmm3);
/* /*
the vast majority of inputs to vrsqrte come from vmsum3 or vmsum4 as part the vast majority of inputs to vrsqrte come from vmsum3 or vmsum4 as
of a vector normalization sequence. in fact, its difficult to find uses of vrsqrte in titles part of a vector normalization sequence. in fact, its difficult to find
that have inputs which do not come from vmsum. uses of vrsqrte in titles that have inputs which do not come from vmsum.
*/ */
if (i.src1.value && i.src1.value->AllFloatVectorLanesSameValue()) { if (i.src1.value && i.src1.value->AllFloatVectorLanesSameValue()) {
e.vmovss(e.xmm0, src1); e.vmovss(e.xmm0, src1);
@ -3193,8 +3193,7 @@ struct SET_ROUNDING_MODE_I32
if (constant_value & 4) { if (constant_value & 4) {
e.or_(flags_ptr, 1U << kX64BackendNonIEEEMode); e.or_(flags_ptr, 1U << kX64BackendNonIEEEMode);
} } else {
else {
e.btr(flags_ptr, kX64BackendNonIEEEMode); e.btr(flags_ptr, kX64BackendNonIEEEMode);
} }
e.mov(e.dword[e.rsp + StackLayout::GUEST_SCRATCH], e.eax); e.mov(e.dword[e.rsp + StackLayout::GUEST_SCRATCH], e.eax);

View File

@ -122,10 +122,12 @@ class StackLayout {
* *
*/ */
static const size_t GUEST_STACK_SIZE = 104; static const size_t GUEST_STACK_SIZE = 104;
//was GUEST_CTX_HOME, can't remove because that'd throw stack alignment off. instead, can be used as a temporary in sequences // was GUEST_CTX_HOME, can't remove because that'd throw stack alignment off.
// instead, can be used as a temporary in sequences
static const size_t GUEST_SCRATCH = 0; static const size_t GUEST_SCRATCH = 0;
//when profiling is on, this stores the nanosecond time at the start of the function // when profiling is on, this stores the nanosecond time at the start of the
// function
static const size_t GUEST_PROFILER_START = 80; static const size_t GUEST_PROFILER_START = 80;
static const size_t GUEST_RET_ADDR = 88; static const size_t GUEST_RET_ADDR = 88;
static const size_t GUEST_CALL_RET_ADDR = 96; static const size_t GUEST_CALL_RET_ADDR = 96;

View File

@ -29,8 +29,7 @@ namespace x64 {
bool trace_enabled = true; bool trace_enabled = true;
#define THREAD_MATCH \ #define THREAD_MATCH (!TARGET_THREAD || ppc_context->thread_id == TARGET_THREAD)
(!TARGET_THREAD || ppc_context->thread_id == TARGET_THREAD)
#define IFLUSH() #define IFLUSH()
#define IPRINT(s) \ #define IPRINT(s) \
if (trace_enabled && THREAD_MATCH) \ if (trace_enabled && THREAD_MATCH) \

View File

@ -1372,9 +1372,10 @@ bool SimplificationPass::SimplifyVectorOps(hir::Instr* i,
} }
/* /*
splatting a 32-bit value extracted from a vector where all 4 32-bit values are the same should be eliminated and splatting a 32-bit value extracted from a vector where all 4 32-bit values
instead use the vector extracted from, which will be identical are the same should be eliminated and instead use the vector extracted from,
have seen this happen, some games vmsum and then splat the low float to all 4 floats, even though it already is there which will be identical have seen this happen, some games vmsum and then
splat the low float to all 4 floats, even though it already is there
*/ */
if (opc == OPCODE_SPLAT) { if (opc == OPCODE_SPLAT) {
if (i->dest->type == VEC128_TYPE) { if (i->dest->type == VEC128_TYPE) {
@ -1388,7 +1389,6 @@ bool SimplificationPass::SimplifyVectorOps(hir::Instr* i,
if (defining_opcode == OPCODE_EXTRACT) { if (defining_opcode == OPCODE_EXTRACT) {
auto value_extracted_from = splat_input_definition->src1.value; auto value_extracted_from = splat_input_definition->src1.value;
if (value_extracted_from->type == VEC128_TYPE) { if (value_extracted_from->type == VEC128_TYPE) {
xenia_assert(splat_input_definition->dest->type == splat_type); xenia_assert(splat_input_definition->dest->type == splat_type);
if (value_extracted_from->AllFloatVectorLanesSameValue()) { if (value_extracted_from->AllFloatVectorLanesSameValue()) {

View File

@ -95,7 +95,6 @@ class Export {
uint32_t variable_ptr; uint32_t variable_ptr;
struct { struct {
// Trampoline that is called from the guest-to-host thunk. // Trampoline that is called from the guest-to-host thunk.
// Expects only PPC context as first arg. // Expects only PPC context as first arg.
ExportTrampoline trampoline; ExportTrampoline trampoline;

View File

@ -115,7 +115,6 @@ uintptr_t GuestFunction::MapGuestAddressToMachineCode(
return reinterpret_cast<uintptr_t>(machine_code()) + entry->code_offset; return reinterpret_cast<uintptr_t>(machine_code()) + entry->code_offset;
} else { } else {
return 0; return 0;
} }
} }

View File

@ -79,10 +79,11 @@ class Instr {
void MoveBefore(Instr* other); void MoveBefore(Instr* other);
void Replace(const OpcodeInfo* new_opcode, uint16_t new_flags); void Replace(const OpcodeInfo* new_opcode, uint16_t new_flags);
void UnlinkAndNOP(); void UnlinkAndNOP();
//chrispy: wanted to change this one to Remove, but i changed Remove's name to UnlinkAndNOP, // chrispy: wanted to change this one to Remove, but i changed Remove's name
//so if changes happened in master that we wanted to port over, and those changes used Remove, then we would have a lot of issues that the cause of would // to UnlinkAndNOP, so if changes happened in master that we wanted to port
//be difficult to track // over, and those changes used Remove, then we would have a lot of issues
//^todo: rework this comment, im frazzled // that the cause of would be difficult to track ^todo: rework this comment,
// im frazzled
void Deallocate(); void Deallocate();
const OpcodeInfo* GetOpcodeInfo() const { return opcode; } const OpcodeInfo* GetOpcodeInfo() const { return opcode; }
// if opcode is null, we have bigger problems // if opcode is null, we have bigger problems

View File

@ -30,9 +30,7 @@ class Label {
// this will later be used as an input to xbyak. xbyak only accepts // this will later be used as an input to xbyak. xbyak only accepts
// std::string as a value, not passed by reference, so precomputing the // std::string as a value, not passed by reference, so precomputing the
// stringification does not help // stringification does not help
std::string GetIdString() { std::string GetIdString() { return std::to_string(id); }
return std::to_string(id);
}
}; };
} // namespace hir } // namespace hir

View File

@ -1819,7 +1819,8 @@ re_enter:
xenia_assert(for_value->IsConstant()); xenia_assert(for_value->IsConstant());
auto&& constant_value = for_value->constant.v128; auto&& constant_value = for_value->constant.v128;
for (unsigned constant_lane_index = 1; constant_lane_index < 4; ++constant_lane_index) { for (unsigned constant_lane_index = 1; constant_lane_index < 4;
++constant_lane_index) {
if (constant_value.u32[0] != constant_value.u32[constant_lane_index]) { if (constant_value.u32[0] != constant_value.u32[constant_lane_index]) {
return false; return false;
} }
@ -1845,8 +1846,9 @@ re_enter:
return true; return true;
} }
// if splat of 32-bit value type, return true // if splat of 32-bit value type, return true
//technically a splat of int16 or int8 would also produce the same "float" in all lanes // technically a splat of int16 or int8 would also produce the same "float" in
//but i think its best to keep this function focused on specifically float data // all lanes but i think its best to keep this function focused on
// specifically float data
if (definition_opcode_number == OPCODE_SPLAT) { if (definition_opcode_number == OPCODE_SPLAT) {
if (definition->dest->type == VEC128_TYPE) { if (definition->dest->type == VEC128_TYPE) {
auto splat_src_value_type = definition->src1.value->type; auto splat_src_value_type = definition->src1.value->type;
@ -1883,7 +1885,6 @@ re_enter:
return false; return false;
} }
} // namespace hir } // namespace hir
} // namespace cpu } // namespace cpu
} // namespace xe } // namespace xe

View File

@ -621,6 +621,7 @@ class Value {
bool AllFloatVectorLanesSameValue() const { bool AllFloatVectorLanesSameValue() const {
return Value::AllFloatVectorLanesSameValue(this); return Value::AllFloatVectorLanesSameValue(this);
} }
private: private:
/* /*
returns true if for_value (which must be VEC128_TYPE) has the same value in returns true if for_value (which must be VEC128_TYPE) has the same value in

View File

@ -48,7 +48,9 @@ class MMIOHandler {
typedef uint32_t (*HostToGuestVirtual)(const void* context, typedef uint32_t (*HostToGuestVirtual)(const void* context,
const void* host_address); const void* host_address);
typedef bool (*AccessViolationCallback)( typedef bool (*AccessViolationCallback)(
global_unique_lock_type global_lock_locked_once, //not passed by reference with const like the others? global_unique_lock_type
global_lock_locked_once, // not passed by reference with const like
// the others?
void* context, void* host_address, bool is_write); void* context, void* host_address, bool is_write);
// access_violation_callback is called with global_critical_region locked once // access_violation_callback is called with global_critical_region locked once

View File

@ -55,6 +55,7 @@ class Module {
bool ReadMap(const char* file_name); bool ReadMap(const char* file_name);
virtual void Precompile() {} virtual void Precompile() {}
protected: protected:
virtual std::unique_ptr<Function> CreateFunction(uint32_t address) = 0; virtual std::unique_ptr<Function> CreateFunction(uint32_t address) = 0;

View File

@ -789,7 +789,6 @@ int InstrEmit_mtspr(PPCHIRBuilder& f, const InstrData& i) {
// code requires it. Sequences of mtmsr/lwar/stcw/mtmsr come up a lot, and // code requires it. Sequences of mtmsr/lwar/stcw/mtmsr come up a lot, and
// without the lock here threads can livelock. // without the lock here threads can livelock.
// 0x400 = debug singlestep i think // 0x400 = debug singlestep i think
// ive seen 0x8000 used in kernel code // ive seen 0x8000 used in kernel code
int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) { int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) {

View File

@ -106,11 +106,12 @@ bool PPCFrontend::Initialize() {
} }
bool PPCFrontend::DeclareFunction(GuestFunction* function) { bool PPCFrontend::DeclareFunction(GuestFunction* function) {
// chrispy: make sure we aren't declaring a function that is actually padding
//chrispy: make sure we aren't declaring a function that is actually padding data, this will mess up PPCScanner and is hard to debug // data, this will mess up PPCScanner and is hard to debug wow, this halo
//wow, this halo reach actually has branches into 0 opcodes, look into further // reach actually has branches into 0 opcodes, look into further
// xenia_assert(*reinterpret_cast<const uint32_t*>( // xenia_assert(*reinterpret_cast<const uint32_t*>(
// this->memory()->TranslateVirtual(function->address())) != 0); // this->memory()->TranslateVirtual(function->address())) !=
// 0);
// Could scan or something here. // Could scan or something here.
// Could also check to see if it's a well-known function type and classify // Could also check to see if it's a well-known function type and classify
// for later. // for later.

View File

@ -80,8 +80,10 @@ class PPCHIRBuilder : public hir::HIRBuilder {
void StoreReserved(Value* val); void StoreReserved(Value* val);
Value* LoadReserved(); Value* LoadReserved();
//calls original impl in hirbuilder, but also records the is_return_site bit into flags in the guestmodule // calls original impl in hirbuilder, but also records the is_return_site bit
// into flags in the guestmodule
void SetReturnAddress(Value* value); void SetReturnAddress(Value* value);
private: private:
void MaybeBreakOnInstruction(uint32_t address); void MaybeBreakOnInstruction(uint32_t address);
void AnnotateLabel(uint32_t address, Label* label); void AnnotateLabel(uint32_t address, Label* label);

View File

@ -1326,8 +1326,8 @@ uint32_t Processor::GuestAtomicDecrement32(ppc::PPCContext* context,
uint32_t Processor::GuestAtomicOr32(ppc::PPCContext* context, uint32_t Processor::GuestAtomicOr32(ppc::PPCContext* context,
uint32_t guest_address, uint32_t mask) { uint32_t guest_address, uint32_t mask) {
return xe::byte_swap(xe::atomic_or( return xe::byte_swap(
context->TranslateVirtual<volatile int32_t*>(guest_address), xe::atomic_or(context->TranslateVirtual<volatile int32_t*>(guest_address),
xe::byte_swap(mask))); xe::byte_swap(mask)));
} }
uint32_t Processor::GuestAtomicXor32(ppc::PPCContext* context, uint32_t Processor::GuestAtomicXor32(ppc::PPCContext* context,

View File

@ -77,8 +77,7 @@ ThreadState::ThreadState(Processor* processor, uint32_t thread_id,
// Allocate with 64b alignment. // Allocate with 64b alignment.
context_ = reinterpret_cast<ppc::PPCContext*>( context_ = reinterpret_cast<ppc::PPCContext*>(AllocateContext());
AllocateContext());
processor->backend()->InitializeBackendContext(context_); processor->backend()->InitializeBackendContext(context_);
assert_true(((uint64_t)context_ & 0x3F) == 0); assert_true(((uint64_t)context_ & 0x3F) == 0);
std::memset(context_, 0, sizeof(ppc::PPCContext)); std::memset(context_, 0, sizeof(ppc::PPCContext));
@ -98,8 +97,10 @@ ThreadState::ThreadState(Processor* processor, uint32_t thread_id,
context_->msr = 0x9030; // dumped from a real 360, 0x8000 context_->msr = 0x9030; // dumped from a real 360, 0x8000
// this register can be used for arbitrary data according to the PPC docs // this register can be used for arbitrary data according to the PPC docs
//but the suggested use is to mark which vector registers are in use, for faster save/restore // but the suggested use is to mark which vector registers are in use, for
//it seems unlikely anything uses this, especially since we have way more than 32 vrs, but setting it to all ones seems closer to correct than 0 // faster save/restore it seems unlikely anything uses this, especially since
// we have way more than 32 vrs, but setting it to all ones seems closer to
// correct than 0
context_->vrsave = ~0u; context_->vrsave = ~0u;
} }

View File

@ -230,9 +230,7 @@ class Emulator {
xe::Delegate<> on_exit; xe::Delegate<> on_exit;
private: private:
enum : uint64_t { enum : uint64_t { EmulatorFlagDisclaimerAcknowledged = 1ULL << 0 };
EmulatorFlagDisclaimerAcknowledged = 1ULL << 0
};
static uint64_t GetPersistentEmulatorFlags(); static uint64_t GetPersistentEmulatorFlags();
static void SetPersistentEmulatorFlags(uint64_t new_flags); static void SetPersistentEmulatorFlags(uint64_t new_flags);
static std::string CanonicalizeFileExtension( static std::string CanonicalizeFileExtension(

View File

@ -100,11 +100,14 @@ bool CommandProcessor::Initialize() {
} }
worker_running_ = true; worker_running_ = true;
worker_thread_ = kernel::object_ref<kernel::XHostThread>( worker_thread_ =
new kernel::XHostThread(kernel_state_, 128 * 1024, 0, [this]() { kernel::object_ref<kernel::XHostThread>(new kernel::XHostThread(
kernel_state_, 128 * 1024, 0,
[this]() {
WorkerThreadMain(); WorkerThreadMain();
return 0; return 0;
}, kernel_state_->GetIdleProcess())); },
kernel_state_->GetIdleProcess()));
worker_thread_->set_name("GPU Commands"); worker_thread_->set_name("GPU Commands");
worker_thread_->Create(); worker_thread_->Create();
@ -270,7 +273,8 @@ void CommandProcessor::WorkerThreadMain() {
// TODO(benvanik): use reader->Read_update_freq_ and only issue after moving // TODO(benvanik): use reader->Read_update_freq_ and only issue after moving
// that many indices. // that many indices.
// Keep in mind that the gpu also updates the cpu-side copy if the write pointer and read pointer would be equal // Keep in mind that the gpu also updates the cpu-side copy if the write
// pointer and read pointer would be equal
if (read_ptr_writeback_ptr_) { if (read_ptr_writeback_ptr_) {
xe::store_and_swap<uint32_t>( xe::store_and_swap<uint32_t>(
memory_->TranslatePhysical(read_ptr_writeback_ptr_), read_ptr_index_); memory_->TranslatePhysical(read_ptr_writeback_ptr_), read_ptr_index_);
@ -360,9 +364,8 @@ void CommandProcessor::EnableReadPointerWriteBack(uint32_t ptr,
XE_NOINLINE XE_COLD void CommandProcessor::LogKickoffInitator(uint32_t value) { XE_NOINLINE XE_COLD void CommandProcessor::LogKickoffInitator(uint32_t value) {
cpu::backend::GuestPseudoStackTrace st; cpu::backend::GuestPseudoStackTrace st;
if (logging::internal::ShouldLog(LogLevel::Debug) && kernel_state_->processor() if (logging::internal::ShouldLog(LogLevel::Debug) &&
->backend() kernel_state_->processor()->backend()->PopulatePseudoStacktrace(&st)) {
->PopulatePseudoStacktrace(&st)) {
logging::LoggerBatch<LogLevel::Debug> log_initiator{}; logging::LoggerBatch<LogLevel::Debug> log_initiator{};
log_initiator("Updating read ptr to {}, initiator stacktrace below\n", log_initiator("Updating read ptr to {}, initiator stacktrace below\n",
@ -390,7 +393,8 @@ void CommandProcessor::UpdateWritePointer(uint32_t value) {
void CommandProcessor::LogRegisterSet(uint32_t register_index, uint32_t value) { void CommandProcessor::LogRegisterSet(uint32_t register_index, uint32_t value) {
#if XE_ENABLE_GPU_REG_WRITE_LOGGING == 1 #if XE_ENABLE_GPU_REG_WRITE_LOGGING == 1
if (cvars::log_guest_driven_gpu_register_written_values && logging::internal::ShouldLog(LogLevel::Debug)) { if (cvars::log_guest_driven_gpu_register_written_values &&
logging::internal::ShouldLog(LogLevel::Debug)) {
const RegisterInfo* reginfo = RegisterFile::GetRegisterInfo(register_index); const RegisterInfo* reginfo = RegisterFile::GetRegisterInfo(register_index);
if (!reginfo) { if (!reginfo) {
@ -734,7 +738,6 @@ void CommandProcessor::PrepareForWait() { trace_writer_.Flush(); }
void CommandProcessor::ReturnFromWait() {} void CommandProcessor::ReturnFromWait() {}
void CommandProcessor::InitializeTrace() { void CommandProcessor::InitializeTrace() {
// Write the initial register values, to be loaded directly into the // Write the initial register values, to be loaded directly into the
// RegisterFile since all registers, including those that may have side // RegisterFile since all registers, including those that may have side

View File

@ -225,7 +225,6 @@ class CommandProcessor {
virtual void PrepareForWait(); virtual void PrepareForWait();
virtual void ReturnFromWait(); virtual void ReturnFromWait();
virtual void OnPrimaryBufferEnd() {} virtual void OnPrimaryBufferEnd() {}
#include "pm4_command_processor_declare.h" #include "pm4_command_processor_declare.h"

View File

@ -22,9 +22,9 @@
#include "xenia/gpu/d3d12/d3d12_shader.h" #include "xenia/gpu/d3d12/d3d12_shader.h"
#include "xenia/gpu/draw_util.h" #include "xenia/gpu/draw_util.h"
#include "xenia/gpu/gpu_flags.h" #include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/packet_disassembler.h"
#include "xenia/gpu/registers.h" #include "xenia/gpu/registers.h"
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
#include "xenia/gpu/packet_disassembler.h"
#include "xenia/ui/d3d12/d3d12_presenter.h" #include "xenia/ui/d3d12/d3d12_presenter.h"
#include "xenia/ui/d3d12/d3d12_util.h" #include "xenia/ui/d3d12/d3d12_util.h"
@ -65,7 +65,6 @@ void D3D12SaveGPUSetting(D3D12GPUSetting setting, uint64_t value) {
namespace d3d12 { namespace d3d12 {
// Generated with `xb buildshaders`. // Generated with `xb buildshaders`.
namespace shaders { namespace shaders {
#include "xenia/gpu/shaders/bytecode/d3d12_5_1/apply_gamma_pwl_cs.h" #include "xenia/gpu/shaders/bytecode/d3d12_5_1/apply_gamma_pwl_cs.h"
@ -4992,7 +4991,8 @@ bool D3D12CommandProcessor::UpdateBindings_BindfulPath(
} }
// Null SRV + UAV + EDRAM. // Null SRV + UAV + EDRAM.
gpu_handle_shared_memory_uav_and_edram_ = view_gpu_handle; gpu_handle_shared_memory_uav_and_edram_ = view_gpu_handle;
ui::d3d12::util::CreateBufferRawSRV(provider.GetDevice(), view_cpu_handle, nullptr, 0); ui::d3d12::util::CreateBufferRawSRV(provider.GetDevice(), view_cpu_handle,
nullptr, 0);
view_cpu_handle.ptr += descriptor_size_view; view_cpu_handle.ptr += descriptor_size_view;
view_gpu_handle.ptr += descriptor_size_view; view_gpu_handle.ptr += descriptor_size_view;
shared_memory_->WriteRawUAVDescriptor(view_cpu_handle); shared_memory_->WriteRawUAVDescriptor(view_cpu_handle);

View File

@ -245,7 +245,8 @@ class D3D12CommandProcessor final : public CommandProcessor {
void WriteFetchFromMem(uint32_t start_index, uint32_t* base, void WriteFetchFromMem(uint32_t start_index, uint32_t* base,
uint32_t num_registers); uint32_t num_registers);
void WritePossiblySpecialRegistersFromMem(uint32_t start_index, uint32_t* base, void WritePossiblySpecialRegistersFromMem(uint32_t start_index,
uint32_t* base,
uint32_t num_registers); uint32_t num_registers);
template <uint32_t register_lower_bound, uint32_t register_upper_bound> template <uint32_t register_lower_bound, uint32_t register_upper_bound>
XE_FORCEINLINE void WriteRegisterRangeFromMem_WithKnownBound( XE_FORCEINLINE void WriteRegisterRangeFromMem_WithKnownBound(
@ -262,8 +263,7 @@ class D3D12CommandProcessor final : public CommandProcessor {
uint32_t base, uint32_t base,
uint32_t num_registers); uint32_t num_registers);
XE_NOINLINE XE_NOINLINE
void WriteOneRegisterFromRing(uint32_t base, void WriteOneRegisterFromRing(uint32_t base, uint32_t num_times);
uint32_t num_times);
XE_FORCEINLINE XE_FORCEINLINE
void WriteALURangeFromRing(xe::RingBuffer* ring, uint32_t base, void WriteALURangeFromRing(xe::RingBuffer* ring, uint32_t base,
@ -795,7 +795,6 @@ class D3D12CommandProcessor final : public CommandProcessor {
draw_util::GetViewportInfoArgs previous_viewport_info_args_; draw_util::GetViewportInfoArgs previous_viewport_info_args_;
draw_util::ViewportInfo previous_viewport_info_; draw_util::ViewportInfo previous_viewport_info_;
std::atomic<bool> pix_capture_requested_ = false; std::atomic<bool> pix_capture_requested_ = false;
bool pix_capturing_; bool pix_capturing_;

View File

@ -18,8 +18,8 @@
#include "xenia/base/assert.h" #include "xenia/base/assert.h"
#include "xenia/base/literals.h" #include "xenia/base/literals.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/ui/d3d12/d3d12_api.h"
#include "xenia/base/memory.h" #include "xenia/base/memory.h"
#include "xenia/ui/d3d12/d3d12_api.h"
namespace xe { namespace xe {
namespace gpu { namespace gpu {
namespace d3d12 { namespace d3d12 {
@ -32,7 +32,8 @@ class DeferredCommandList {
public: public:
static constexpr size_t MAX_SIZEOF_COMMANDLIST = 65536 * 128; // around 8 mb static constexpr size_t MAX_SIZEOF_COMMANDLIST = 65536 * 128; // around 8 mb
/* /*
chrispy: upped from 1_MiB to 4_MiB, m:durandal hits frequent resizes in large open maps chrispy: upped from 1_MiB to 4_MiB, m:durandal hits frequent resizes in
large open maps
*/ */
DeferredCommandList(const D3D12CommandProcessor& command_processor, DeferredCommandList(const D3D12CommandProcessor& command_processor,
size_t initial_size_bytes = MAX_SIZEOF_COMMANDLIST); size_t initial_size_bytes = MAX_SIZEOF_COMMANDLIST);

View File

@ -552,8 +552,7 @@ void GetHostViewportInfo(GetViewportInfoArgs* XE_RESTRICT args,
} }
} }
template <bool clamp_to_surface_pitch> template <bool clamp_to_surface_pitch>
static inline static inline void GetScissorTmpl(const RegisterFile& XE_RESTRICT regs,
void GetScissorTmpl(const RegisterFile& XE_RESTRICT regs,
Scissor& XE_RESTRICT scissor_out) { Scissor& XE_RESTRICT scissor_out) {
#if XE_ARCH_AMD64 == 1 #if XE_ARCH_AMD64 == 1
auto pa_sc_window_scissor_tl = regs.Get<reg::PA_SC_WINDOW_SCISSOR_TL>(); auto pa_sc_window_scissor_tl = regs.Get<reg::PA_SC_WINDOW_SCISSOR_TL>();
@ -623,8 +622,7 @@ void GetScissorTmpl(const RegisterFile& XE_RESTRICT regs,
// interlock-based custom RB implementations) and using conventional render // interlock-based custom RB implementations) and using conventional render
// targets, but padded to EDRAM tiles. // targets, but padded to EDRAM tiles.
tmp1 = _mm_blend_epi16( tmp1 = _mm_blend_epi16(
tmp1, _mm_min_epi32(tmp1, _mm_set1_epi32(surface_pitch)), tmp1, _mm_min_epi32(tmp1, _mm_set1_epi32(surface_pitch)), 0b00110011);
0b00110011);
} }
tmp1 = _mm_max_epi32(tmp1, _mm_setzero_si128()); tmp1 = _mm_max_epi32(tmp1, _mm_setzero_si128());

View File

@ -25,10 +25,10 @@
#include "xenia/base/threading.h" #include "xenia/base/threading.h"
#include "xenia/gpu/command_processor.h" #include "xenia/gpu/command_processor.h"
#include "xenia/gpu/gpu_flags.h" #include "xenia/gpu/gpu_flags.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/ui/graphics_provider.h" #include "xenia/ui/graphics_provider.h"
#include "xenia/ui/window.h" #include "xenia/ui/window.h"
#include "xenia/ui/windowed_app_context.h" #include "xenia/ui/windowed_app_context.h"
#include "xenia/kernel/kernel_state.h"
DEFINE_bool( DEFINE_bool(
store_shaders, true, store_shaders, true,
"Store shaders persistently and load them when loading games to avoid " "Store shaders persistently and load them when loading games to avoid "
@ -102,8 +102,10 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
// 60hz vsync timer. // 60hz vsync timer.
vsync_worker_running_ = true; vsync_worker_running_ = true;
vsync_worker_thread_ = kernel::object_ref<kernel::XHostThread>( vsync_worker_thread_ =
new kernel::XHostThread(kernel_state_, 128 * 1024, 0, [this]() { kernel::object_ref<kernel::XHostThread>(new kernel::XHostThread(
kernel_state_, 128 * 1024, 0,
[this]() {
const double vsync_duration_d = const double vsync_duration_d =
cvars::vsync cvars::vsync
? std::max<double>( ? std::max<double>(
@ -117,13 +119,15 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
const uint64_t current_time = Clock::QueryGuestTickCount(); const uint64_t current_time = Clock::QueryGuestTickCount();
const uint64_t tick_freq = Clock::guest_tick_frequency(); const uint64_t tick_freq = Clock::guest_tick_frequency();
const uint64_t time_delta = current_time - last_frame_time; const uint64_t time_delta = current_time - last_frame_time;
const double elapsed_d = static_cast<double>(time_delta) / const double elapsed_d =
static_cast<double>(time_delta) /
(static_cast<double>(tick_freq) / 1000.0); (static_cast<double>(tick_freq) / 1000.0);
if (elapsed_d >= vsync_duration_d) { if (elapsed_d >= vsync_duration_d) {
last_frame_time = current_time; last_frame_time = current_time;
// TODO(disjtqz): should recalculate the remaining time to a vblank // TODO(disjtqz): should recalculate the remaining time to a
// after MarkVblank, no idea how long the guest code normally takes // vblank after MarkVblank, no idea how long the guest code
// normally takes
MarkVblank(); MarkVblank();
if (cvars::vsync) { if (cvars::vsync) {
const uint64_t estimated_nanoseconds = static_cast<uint64_t>( const uint64_t estimated_nanoseconds = static_cast<uint64_t>(
@ -138,7 +142,8 @@ X_STATUS GraphicsSystem::Setup(cpu::Processor* processor,
} }
} }
return 0; return 0;
}, kernel_state->GetIdleProcess())); },
kernel_state->GetIdleProcess()));
// As we run vblank interrupts the debugger must be able to suspend us. // As we run vblank interrupts the debugger must be able to suspend us.
vsync_worker_thread_->set_can_debugger_suspend(true); vsync_worker_thread_->set_can_debugger_suspend(true);
vsync_worker_thread_->set_name("GPU VSync"); vsync_worker_thread_->set_name("GPU VSync");
@ -267,7 +272,8 @@ void GraphicsSystem::SetInterruptCallback(uint32_t callback,
} }
void GraphicsSystem::DispatchInterruptCallback(uint32_t source, uint32_t cpu) { void GraphicsSystem::DispatchInterruptCallback(uint32_t source, uint32_t cpu) {
kernel_state()->EmulateCPInterruptDPC(interrupt_callback_,interrupt_callback_data_, source, cpu); kernel_state()->EmulateCPInterruptDPC(interrupt_callback_,
interrupt_callback_data_, source, cpu);
} }
void GraphicsSystem::MarkVblank() { void GraphicsSystem::MarkVblank() {

View File

@ -5,8 +5,7 @@
#else #else
#define PM4_OVERRIDE #define PM4_OVERRIDE
#endif #endif
void ExecuteIndirectBuffer(uint32_t ptr, void ExecuteIndirectBuffer(uint32_t ptr, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
virtual uint32_t ExecutePrimaryBuffer(uint32_t start_index, uint32_t end_index) virtual uint32_t ExecutePrimaryBuffer(uint32_t start_index, uint32_t end_index)
XE_RESTRICT PM4_OVERRIDE; XE_RESTRICT PM4_OVERRIDE;
virtual bool ExecutePacket() PM4_OVERRIDE; virtual bool ExecutePacket() PM4_OVERRIDE;
@ -26,16 +25,12 @@ bool ExecutePacketType2( uint32_t packet) XE_RESTRICT;
XE_NOINLINE XE_NOINLINE
bool ExecutePacketType3(uint32_t packet) XE_RESTRICT; bool ExecutePacketType3(uint32_t packet) XE_RESTRICT;
XE_NOINLINE XE_NOINLINE
bool ExecutePacketType3_ME_INIT( uint32_t packet, bool ExecutePacketType3_ME_INIT(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT; bool ExecutePacketType3_NOP(uint32_t packet, uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_NOP( uint32_t packet,
uint32_t count) XE_RESTRICT;
XE_NOINLINE XE_NOINLINE
bool ExecutePacketType3_INTERRUPT( uint32_t packet, bool ExecutePacketType3_INTERRUPT(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
XE_NOINLINE XE_NOINLINE
bool ExecutePacketType3_XE_SWAP( uint32_t packet, bool ExecutePacketType3_XE_SWAP(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_INDIRECT_BUFFER(uint32_t packet, bool ExecutePacketType3_INDIRECT_BUFFER(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
@ -43,17 +38,13 @@ XE_NOINLINE
bool ExecutePacketType3_WAIT_REG_MEM(uint32_t packet, bool ExecutePacketType3_WAIT_REG_MEM(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
XE_NOINLINE XE_NOINLINE
bool ExecutePacketType3_REG_RMW( uint32_t packet, bool ExecutePacketType3_REG_RMW(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_REG_TO_MEM( uint32_t packet, bool ExecutePacketType3_REG_TO_MEM(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
XE_NOINLINE XE_NOINLINE
bool ExecutePacketType3_MEM_WRITE( uint32_t packet, bool ExecutePacketType3_MEM_WRITE(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
XE_NOINLINE XE_NOINLINE
bool ExecutePacketType3_COND_WRITE( uint32_t packet, bool ExecutePacketType3_COND_WRITE(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_EVENT_WRITE(uint32_t packet, bool ExecutePacketType3_EVENT_WRITE(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
@ -67,13 +58,11 @@ XE_NOINLINE
bool ExecutePacketType3_EVENT_WRITE_ZPD(uint32_t packet, bool ExecutePacketType3_EVENT_WRITE_ZPD(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
bool ExecutePacketType3Draw( uint32_t packet, bool ExecutePacketType3Draw(uint32_t packet, const char* opcode_name,
const char* opcode_name,
uint32_t viz_query_condition, uint32_t viz_query_condition,
uint32_t count_remaining) XE_RESTRICT; uint32_t count_remaining) XE_RESTRICT;
bool ExecutePacketType3_DRAW_INDX( uint32_t packet, bool ExecutePacketType3_DRAW_INDX(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_DRAW_INDX_2(uint32_t packet, bool ExecutePacketType3_DRAW_INDX_2(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
@ -87,12 +76,10 @@ XE_FORCEINLINE
bool ExecutePacketType3_LOAD_ALU_CONSTANT(uint32_t packet, bool ExecutePacketType3_LOAD_ALU_CONSTANT(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_SET_SHADER_CONSTANTS( bool ExecutePacketType3_SET_SHADER_CONSTANTS(uint32_t packet,
uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_IM_LOAD( uint32_t packet, bool ExecutePacketType3_IM_LOAD(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_IM_LOAD_IMMEDIATE(uint32_t packet, bool ExecutePacketType3_IM_LOAD_IMMEDIATE(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
@ -100,9 +87,7 @@ bool ExecutePacketType3_IM_LOAD_IMMEDIATE( uint32_t packet,
bool ExecutePacketType3_INVALIDATE_STATE(uint32_t packet, bool ExecutePacketType3_INVALIDATE_STATE(uint32_t packet,
uint32_t count) XE_RESTRICT; uint32_t count) XE_RESTRICT;
bool ExecutePacketType3_VIZ_QUERY( uint32_t packet, bool ExecutePacketType3_VIZ_QUERY(uint32_t packet, uint32_t count) XE_RESTRICT;
uint32_t count) XE_RESTRICT;
XE_FORCEINLINE XE_FORCEINLINE
void WriteEventInitiator(uint32_t value) XE_RESTRICT; void WriteEventInitiator(uint32_t value) XE_RESTRICT;

View File

@ -683,11 +683,10 @@ bool COMMAND_PROCESSOR::ExecutePacketType3_INDIRECT_BUFFER(
to 54 bytes to 54 bytes
*/ */
static bool MatchValueAndRef(uint32_t value, uint32_t ref, uint32_t wait_info) { static bool MatchValueAndRef(uint32_t value, uint32_t ref, uint32_t wait_info) {
// smaller code is generated than the #else path, although whether it is faster // smaller code is generated than the #else path, although whether it is
// i do not know. i don't think games do an enormous number of cond_write // faster i do not know. i don't think games do an enormous number of
// though, so we have picked // cond_write though, so we have picked the path with the smaller codegen. we
// the path with the smaller codegen. // do technically have more instructions executed vs the switch case method,
// we do technically have more instructions executed vs the switch case method,
// but we have no mispredicts and most of our instructions are 0.25/0.3 // but we have no mispredicts and most of our instructions are 0.25/0.3
// throughput // throughput
return ((((value < ref) << 1) | ((value <= ref) << 2) | return ((((value < ref) << 1) | ((value <= ref) << 2) |
@ -899,12 +898,16 @@ bool COMMAND_PROCESSOR::ExecutePacketType3_EVENT_WRITE_SHD(
data_value = GpuSwap(data_value, endianness); data_value = GpuSwap(data_value, endianness);
uint8_t* write_destination = memory_->TranslatePhysical(address); uint8_t* write_destination = memory_->TranslatePhysical(address);
if (address > 0x1FFFFFFF) { if (address > 0x1FFFFFFF) {
uint32_t writeback_base = register_file_->values[XE_GPU_REG_WRITEBACK_BASE].u32; uint32_t writeback_base =
uint32_t writeback_size = register_file_->values[XE_GPU_REG_WRITEBACK_SIZE].u32; register_file_->values[XE_GPU_REG_WRITEBACK_BASE].u32;
uint32_t writeback_size =
register_file_->values[XE_GPU_REG_WRITEBACK_SIZE].u32;
uint32_t writeback_offset = address - writeback_base; uint32_t writeback_offset = address - writeback_base;
//check whether the guest has written writeback base. if they haven't, skip the offset check // check whether the guest has written writeback base. if they haven't, skip
// the offset check
if (writeback_base != 0 && writeback_offset < writeback_size) { if (writeback_base != 0 && writeback_offset < writeback_size) {
write_destination = memory_->TranslateVirtual(0x7F000000 + writeback_offset); write_destination =
memory_->TranslateVirtual(0x7F000000 + writeback_offset);
} }
} }
xe::store(write_destination, data_value); xe::store(write_destination, data_value);

View File

@ -883,8 +883,7 @@ class PrimitiveProcessor {
// Must be called in a global critical region. // Must be called in a global critical region.
void UpdateCacheBucketsNonEmptyL2( void UpdateCacheBucketsNonEmptyL2(
uint32_t bucket_index_div_64, uint32_t bucket_index_div_64,
[[maybe_unused]] const global_unique_lock_type& [[maybe_unused]] const global_unique_lock_type& global_lock) {
global_lock) {
uint64_t& cache_buckets_non_empty_l2_ref = uint64_t& cache_buckets_non_empty_l2_ref =
cache_buckets_non_empty_l2_[bucket_index_div_64 >> 6]; cache_buckets_non_empty_l2_[bucket_index_div_64 >> 6];
uint64_t cache_buckets_non_empty_l2_bit = uint64_t(1) uint64_t cache_buckets_non_empty_l2_bit = uint64_t(1)

View File

@ -36,16 +36,18 @@ XE_GPU_REGISTER(0x0398, kDword, RBBM_PERFCOUNTER0_HI)
XE_GPU_REGISTER(0x0399, kDword, RBBM_PERFCOUNTER1_LOW) XE_GPU_REGISTER(0x0399, kDword, RBBM_PERFCOUNTER1_LOW)
XE_GPU_REGISTER(0x039A, kDword, RBBM_PERFCOUNTER1_HI) XE_GPU_REGISTER(0x039A, kDword, RBBM_PERFCOUNTER1_HI)
//XAM reads this directly and stores it to a struct, have not tracked where it goes from there // XAM reads this directly and stores it to a struct, have not tracked where it
//PM4 command PM4_MEM_WRITE_CNTR is supposed to write this to memory // goes from there PM4 command PM4_MEM_WRITE_CNTR is supposed to write this to
//XE_GPU_REGISTER(0x44b, kDword,CP_PROG_COUNTER ) // memory XE_GPU_REGISTER(0x44b, kDword,CP_PROG_COUNTER )
XE_GPU_REGISTER(0x045E, kDword, CALLBACK_ACK) XE_GPU_REGISTER(0x045E, kDword, CALLBACK_ACK)
XE_GPU_REGISTER(0x0578, kDword, SCRATCH_REG0) // interrupt sync XE_GPU_REGISTER(0x0578, kDword, SCRATCH_REG0) // interrupt sync
XE_GPU_REGISTER(0x0579, kDword, SCRATCH_REG1) // present interval XE_GPU_REGISTER(0x0579, kDword, SCRATCH_REG1) // present interval
XE_GPU_REGISTER(0x057A, kDword, SCRATCH_REG2) XE_GPU_REGISTER(0x057A, kDword, SCRATCH_REG2)
XE_GPU_REGISTER(0x057B, kDword, SCRATCH_REG3) XE_GPU_REGISTER(0x057B, kDword, SCRATCH_REG3)
XE_GPU_REGISTER(0x057C, kDword, SCRATCH_REG4) //originally this was named CALLBACK_ADDRESS, but that didnt make sense XE_GPU_REGISTER(0x057C, kDword,
SCRATCH_REG4) // originally this was named CALLBACK_ADDRESS,
// but that didnt make sense
XE_GPU_REGISTER(0x057D, kDword, SCRATCH_REG5) XE_GPU_REGISTER(0x057D, kDword, SCRATCH_REG5)
XE_GPU_REGISTER(0x057E, kDword, SCRATCH_REG6) XE_GPU_REGISTER(0x057E, kDword, SCRATCH_REG6)
XE_GPU_REGISTER(0x057F, kDword, SCRATCH_REG7) XE_GPU_REGISTER(0x057F, kDword, SCRATCH_REG7)
@ -56,7 +58,6 @@ XE_GPU_REGISTER(0x05C8, kDword, WAIT_UNTIL)
// seems to have a negative value while the gpu is busy // seems to have a negative value while the gpu is busy
// XE_GPU_REGISTER(0x05D0, kDword, RBBM_STATUS) // XE_GPU_REGISTER(0x05D0, kDword, RBBM_STATUS)
// update count = 6 bit field, bits 8- 14 // update count = 6 bit field, bits 8- 14
// there are several other fields here, they have an unknown purpose // there are several other fields here, they have an unknown purpose
// XE_GPU_REGISTER(0x704, kDword, CP_RB_CNTL) // XE_GPU_REGISTER(0x704, kDword, CP_RB_CNTL)

View File

@ -231,8 +231,7 @@ class RenderTargetCache {
: register_file_(register_file), : register_file_(register_file),
draw_resolution_scale_x_(draw_resolution_scale_x), draw_resolution_scale_x_(draw_resolution_scale_x),
draw_resolution_scale_y_(draw_resolution_scale_y), draw_resolution_scale_y_(draw_resolution_scale_y),
draw_extent_estimator_(register_file, memory, trace_writer) draw_extent_estimator_(register_file, memory, trace_writer) {
{
assert_not_zero(draw_resolution_scale_x); assert_not_zero(draw_resolution_scale_x);
assert_not_zero(draw_resolution_scale_y); assert_not_zero(draw_resolution_scale_y);
} }

View File

@ -108,7 +108,8 @@ class TextureCache {
// generate a mask of all bits from before the first index, and xor it with // generate a mask of all bits from before the first index, and xor it with
// all bits before the last index this produces a mask covering only the // all bits before the last index this produces a mask covering only the
// bits between first and last // bits between first and last
uint32_t res = ((1U << first_index) - 1) ^ static_cast<uint32_t>((1ULL << (last_index + 1)) - 1ULL); uint32_t res = ((1U << first_index) - 1) ^
static_cast<uint32_t>((1ULL << (last_index + 1)) - 1ULL);
// todo: check that this is right // todo: check that this is right
texture_bindings_in_sync_ &= ~res; texture_bindings_in_sync_ &= ~res;

View File

@ -24,6 +24,7 @@
#include "xenia/base/profiling.h" #include "xenia/base/profiling.h"
#include "xenia/gpu/draw_util.h" #include "xenia/gpu/draw_util.h"
#include "xenia/gpu/gpu_flags.h" #include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/packet_disassembler.h"
#include "xenia/gpu/registers.h" #include "xenia/gpu/registers.h"
#include "xenia/gpu/shader.h" #include "xenia/gpu/shader.h"
#include "xenia/gpu/spirv_shader_translator.h" #include "xenia/gpu/spirv_shader_translator.h"
@ -32,7 +33,6 @@
#include "xenia/gpu/vulkan/vulkan_shader.h" #include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/vulkan/vulkan_shared_memory.h" #include "xenia/gpu/vulkan/vulkan_shared_memory.h"
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
#include "xenia/gpu/packet_disassembler.h"
#include "xenia/kernel/kernel_state.h" #include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/user_module.h" #include "xenia/kernel/user_module.h"
#include "xenia/ui/vulkan/vulkan_presenter.h" #include "xenia/ui/vulkan/vulkan_presenter.h"

View File

@ -10,10 +10,8 @@
#ifndef XENIA_GPU_XENOS_H_ #ifndef XENIA_GPU_XENOS_H_
#define XENIA_GPU_XENOS_H_ #define XENIA_GPU_XENOS_H_
#include "xenia/base/memory.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/base/memory.h"
namespace xe { namespace xe {
namespace gpu { namespace gpu {

View File

@ -54,9 +54,7 @@ struct X_FILE_FS_ATTRIBUTE_INFORMATION {
}; };
static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16); static_assert_size(X_FILE_FS_ATTRIBUTE_INFORMATION, 16);
enum X_FILE_DEVICE_TYPE : uint32_t { enum X_FILE_DEVICE_TYPE : uint32_t { FILE_DEVICE_UNKNOWN = 0x22 };
FILE_DEVICE_UNKNOWN = 0x22
};
struct X_FILE_FS_DEVICE_INFORMATION { struct X_FILE_FS_DEVICE_INFORMATION {
be<X_FILE_DEVICE_TYPE> device_type; be<X_FILE_DEVICE_TYPE> device_type;

View File

@ -651,7 +651,8 @@ void UserModule::Dump() {
for (uint32_t i = 0; i < opt_alternate_title_id->count(); i++) { for (uint32_t i = 0; i < opt_alternate_title_id->count(); i++) {
if (opt_alternate_title_id->values[i] != 0) { if (opt_alternate_title_id->values[i] != 0) {
title_ids.append(fmt::format(" {:08X},", opt_alternate_title_id->values[i])); title_ids.append(
fmt::format(" {:08X},", opt_alternate_title_id->values[i]));
} }
} }
// Remove last character as it is not necessary // Remove last character as it is not necessary

View File

@ -2,8 +2,8 @@
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2023 Xenia Canary. All rights reserved. * * Copyright 2023 Xenia Canary. All rights reserved. * Released under the BSD
* Released under the BSD license - see LICENSE in the root for more details. * *license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */
@ -95,7 +95,8 @@ bool GrowHandleTable(uint32_t table_ptr, PPCContext* context) {
/* /*
copy old bucket list contents to new, larger bucket list copy old bucket list contents to new, larger bucket list
*/ */
memcpy(context->TranslateVirtual(new_dynamic_buckets), memcpy(
context->TranslateVirtual(new_dynamic_buckets),
context->TranslateVirtual(table->table_dynamic_buckets), context->TranslateVirtual(table->table_dynamic_buckets),
sizeof(uint32_t) * (new_bucket_handle_base / SIZE_PER_HANDLE_BUCKET)); sizeof(uint32_t) * (new_bucket_handle_base / SIZE_PER_HANDLE_BUCKET));

View File

@ -2,8 +2,8 @@
****************************************************************************** ******************************************************************************
* Xenia : Xbox 360 Emulator Research Project * * Xenia : Xbox 360 Emulator Research Project *
****************************************************************************** ******************************************************************************
* Copyright 2023 Xenia Canary. All rights reserved. * * Copyright 2023 Xenia Canary. All rights reserved. * Released under the BSD
* Released under the BSD license - see LICENSE in the root for more details. * *license - see LICENSE in the root for more details. *
****************************************************************************** ******************************************************************************
*/ */

View File

@ -25,5 +25,5 @@ struct X_OBJECT_CREATE_INFORMATION;
namespace xe::kernel::util { namespace xe::kernel::util {
class NativeList; class NativeList;
class ObjectTable; class ObjectTable;
} } // namespace xe::kernel::util
#endif #endif

View File

@ -168,8 +168,8 @@ static void XeInsertHeadList(uint32_t list_head, X_LIST_ENTRY* entry,
template <typename VirtualTranslator> template <typename VirtualTranslator>
static void XeInsertHeadList(X_LIST_ENTRY* list_head, X_LIST_ENTRY* entry, static void XeInsertHeadList(X_LIST_ENTRY* list_head, X_LIST_ENTRY* entry,
VirtualTranslator context) { VirtualTranslator context) {
XeInsertHeadList(list_head, XeGuestList(list_head, context), XeInsertHeadList(list_head, XeGuestList(list_head, context), entry,
entry, XeGuestList(entry, context), context); XeGuestList(entry, context), context);
} }
template <typename TObject, size_t EntryListOffset> template <typename TObject, size_t EntryListOffset>
@ -227,7 +227,8 @@ struct X_TYPED_LIST : public X_LIST_ENTRY {
} }
template <typename VirtualTranslator> template <typename VirtualTranslator>
void InsertHead(TObject* entry, VirtualTranslator translator) { void InsertHead(TObject* entry, VirtualTranslator translator) {
XeInsertHeadList(static_cast<X_LIST_ENTRY*>(this), ObjectListEntry(entry), translator); XeInsertHeadList(static_cast<X_LIST_ENTRY*>(this), ObjectListEntry(entry),
translator);
} }
template <typename VirtualTranslator> template <typename VirtualTranslator>
void InsertTail(TObject* entry, VirtualTranslator translator) { void InsertTail(TObject* entry, VirtualTranslator translator) {

View File

@ -111,8 +111,8 @@ class ObjectTable {
// Generic lookup // Generic lookup
template <> template <>
object_ref<XObject> ObjectTable::LookupObject<XObject>( object_ref<XObject> ObjectTable::LookupObject<XObject>(X_HANDLE handle,
X_HANDLE handle, bool already_locked); bool already_locked);
} // namespace util } // namespace util
} // namespace kernel } // namespace kernel

View File

@ -35,8 +35,7 @@ using PPCContext = xe::cpu::ppc::PPCContext;
library_name, ordinals::export_name, \ library_name, ordinals::export_name, \
(xe::cpu::xe_kernel_export_shim_fn)export_name##_entry); (xe::cpu::xe_kernel_export_shim_fn)export_name##_entry);
#define SHIM_MEM_ADDR(a) \ #define SHIM_MEM_ADDR(a) ((a) ? ppc_context->TranslateVirtual(a) : nullptr)
((a) ? ppc_context->TranslateVirtual(a) : nullptr)
#define SHIM_MEM_8(a) xe::load_and_swap<uint8_t>(SHIM_MEM_ADDR(a)) #define SHIM_MEM_8(a) xe::load_and_swap<uint8_t>(SHIM_MEM_ADDR(a))
#define SHIM_MEM_16(a) xe::load_and_swap<uint16_t>(SHIM_MEM_ADDR(a)) #define SHIM_MEM_16(a) xe::load_and_swap<uint16_t>(SHIM_MEM_ADDR(a))
@ -158,9 +157,8 @@ class Param {
} else { } else {
uint32_t stack_ptr = uint32_t stack_ptr =
uint32_t(init.ppc_context->r[1]) + 0x54 + (ordinal_ - 8) * 8; uint32_t(init.ppc_context->r[1]) + 0x54 + (ordinal_ - 8) * 8;
*out_value = xe::load_and_swap<V>( *out_value =
init.ppc_context->TranslateVirtual( xe::load_and_swap<V>(init.ppc_context->TranslateVirtual(stack_ptr));
stack_ptr));
} }
} }
@ -216,6 +214,7 @@ class ContextParam : public Param {
X_KPCR* GetPCR() const { return TranslateGPR<X_KPCR*>(13); } X_KPCR* GetPCR() const { return TranslateGPR<X_KPCR*>(13); }
XThread* CurrentXThread() const; XThread* CurrentXThread() const;
protected: protected:
PPCContext* XE_RESTRICT ctx_; PPCContext* XE_RESTRICT ctx_;
}; };
@ -223,10 +222,7 @@ class ContextParam : public Param {
class PointerParam : public ParamBase<uint32_t> { class PointerParam : public ParamBase<uint32_t> {
public: public:
PointerParam(Init& init) : ParamBase(init) { PointerParam(Init& init) : ParamBase(init) {
host_ptr_ = host_ptr_ = value_ ? init.ppc_context->TranslateVirtual(value_) : nullptr;
value_
? init.ppc_context->TranslateVirtual(value_)
: nullptr;
} }
PointerParam(void* host_ptr) : ParamBase(), host_ptr_(host_ptr) {} PointerParam(void* host_ptr) : ParamBase(), host_ptr_(host_ptr) {}
PointerParam& operator=(void*& other) { PointerParam& operator=(void*& other) {
@ -296,10 +292,7 @@ class StringPointerParam : public ParamBase<uint32_t> {
public: public:
StringPointerParam(Init& init) : ParamBase(init) { StringPointerParam(Init& init) : ParamBase(init) {
host_ptr_ = host_ptr_ =
value_ value_ ? init.ppc_context->TranslateVirtual<CHAR*>(value_) : nullptr;
? init.ppc_context->TranslateVirtual<CHAR*>(
value_)
: nullptr;
} }
StringPointerParam(CHAR* host_ptr) : ParamBase(), host_ptr_(host_ptr) {} StringPointerParam(CHAR* host_ptr) : ParamBase(), host_ptr_(host_ptr) {}
StringPointerParam& operator=(const CHAR*& other) { StringPointerParam& operator=(const CHAR*& other) {
@ -323,9 +316,7 @@ class TypedPointerParam : public ParamBase<uint32_t> {
public: public:
TypedPointerParam(Init& init) : ParamBase(init) { TypedPointerParam(Init& init) : ParamBase(init) {
host_ptr_ = host_ptr_ =
value_ ? init.ppc_context->TranslateVirtual<T*>( value_ ? init.ppc_context->TranslateVirtual<T*>(value_) : nullptr;
value_)
: nullptr;
} }
TypedPointerParam(T* host_ptr) : ParamBase(), host_ptr_(host_ptr) {} TypedPointerParam(T* host_ptr) : ParamBase(), host_ptr_(host_ptr) {}
TypedPointerParam& operator=(const T*& other) { TypedPointerParam& operator=(const T*& other) {

View File

@ -187,8 +187,7 @@ class XdbfWrapper {
XdbfPropertyTableEntry GetProperty(const uint32_t id) const; XdbfPropertyTableEntry GetProperty(const uint32_t id) const;
XdbfContextTableEntry GetContext(const uint32_t id) const; XdbfContextTableEntry GetContext(const uint32_t id) const;
std::vector<XdbfViewTable> GetStatsView() const; std::vector<XdbfViewTable> GetStatsView() const;
XdbfSharedView GetSharedView(const uint8_t* ptr, XdbfSharedView GetSharedView(const uint8_t* ptr, uint32_t& byte_count) const;
uint32_t& byte_count) const;
void GetPropertyBagMetadata(const uint8_t* ptr, uint32_t& byte_count, void GetPropertyBagMetadata(const uint8_t* ptr, uint32_t& byte_count,
std::vector<xe::be<uint32_t>>& contexts, std::vector<xe::be<uint32_t>>& contexts,
@ -196,7 +195,8 @@ class XdbfWrapper {
XdbfPropertyBag GetMatchCollection() const; XdbfPropertyBag GetMatchCollection() const;
const uint8_t* ReadXLast(uint32_t& compressed_size, uint32_t& decompressed_size) const; const uint8_t* ReadXLast(uint32_t& compressed_size,
uint32_t& decompressed_size) const;
private: private:
const uint8_t* data_ = nullptr; const uint8_t* data_ = nullptr;

View File

@ -10,8 +10,8 @@
#include "xenia/kernel/xam/content_manager.h" #include "xenia/kernel/xam/content_manager.h"
#include <array> #include <array>
#include <string>
#include <set> #include <set>
#include <string>
#include "third_party/fmt/include/fmt/format.h" #include "third_party/fmt/include/fmt/format.h"
#include "xenia/base/filesystem.h" #include "xenia/base/filesystem.h"

View File

@ -33,8 +33,7 @@
#include "third_party/fmt/include/fmt/format.h" #include "third_party/fmt/include/fmt/format.h"
DEFINE_int32( DEFINE_int32(avpack, 8,
avpack, 8,
"Video modes\n" "Video modes\n"
" 0 = PAL-60 Component (SD)\n" " 0 = PAL-60 Component (SD)\n"
" 1 = Unused\n" " 1 = Unused\n"

View File

@ -431,7 +431,8 @@ dword_result_t XamGetLocaleEx_entry(dword_t max_country_id,
static_cast<uint8_t>(max_locale_id)); static_cast<uint8_t>(max_locale_id));
} }
DECLARE_XAM_EXPORT1(XamGetLocaleEx, kLocale, kImplemented); DECLARE_XAM_EXPORT1(XamGetLocaleEx, kLocale, kImplemented);
//originally a switch table, wrote a script to extract the values for all possible cases // originally a switch table, wrote a script to extract the values for all
// possible cases
static constexpr uint8_t XamLocaleDateFmtTable[] = { static constexpr uint8_t XamLocaleDateFmtTable[] = {
2, 1, 3, 1, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 1, 4, 2, 3, 1, 2, 2, 3, 2, 1, 3, 1, 3, 3, 3, 3, 3, 3, 3, 2, 3, 2, 1, 4, 2, 3, 1, 2, 2, 3,

View File

@ -66,9 +66,9 @@ dword_result_t XamTaskSchedule_entry(lpvoid_t callback,
// Stack must be aligned to 16kb pages // Stack must be aligned to 16kb pages
stack_size = std::max((uint32_t)0x4000, ((stack_size + 0xFFF) & 0xFFFFF000)); stack_size = std::max((uint32_t)0x4000, ((stack_size + 0xFFF) & 0xFFFFF000));
auto thread = auto thread = object_ref<XThread>(new XThread(
object_ref<XThread>(new XThread(kernel_state(), stack_size, 0, callback, kernel_state(), stack_size, 0, callback, message.guest_address(), 0, true,
message.guest_address(), 0, true, false, kernel_state()->GetSystemProcess())); false, kernel_state()->GetSystemProcess()));
X_STATUS result = thread->Create(); X_STATUS result = thread->Create();

View File

@ -140,7 +140,8 @@ void RtlRaiseException_entry(pointer_t<X_EXCEPTION_RECORD> record) {
// This is going to suck. // This is going to suck.
// xe::debugging::Break(); // xe::debugging::Break();
//RtlRaiseException definitely wasn't a noreturn function, we can return safe-ish // RtlRaiseException definitely wasn't a noreturn function, we can return
// safe-ish
XELOGE("Guest attempted to trigger a breakpoint!"); XELOGE("Guest attempted to trigger a breakpoint!");
} }
DECLARE_XBOXKRNL_EXPORT2(RtlRaiseException, kDebug, kStub, kImportant); DECLARE_XBOXKRNL_EXPORT2(RtlRaiseException, kDebug, kStub, kImportant);

View File

@ -723,8 +723,9 @@ dword_result_t IoCreateDevice_entry(dword_t driver_object,
} }
DECLARE_XBOXKRNL_EXPORT1(IoCreateDevice, kFileSystem, kStub); DECLARE_XBOXKRNL_EXPORT1(IoCreateDevice, kFileSystem, kStub);
//supposed to invoke a callback on the driver object! its some sort of destructor function // supposed to invoke a callback on the driver object! its some sort of
//intended to be called for all devices created from the driver // destructor function intended to be called for all devices created from the
// driver
void IoDeleteDevice_entry(dword_t device_ptr, const ppc_context_t& ctx) { void IoDeleteDevice_entry(dword_t device_ptr, const ppc_context_t& ctx) {
if (device_ptr) { if (device_ptr) {
auto kernel_mem = ctx->kernel_state->memory(); auto kernel_mem = ctx->kernel_state->memory();

View File

@ -16,7 +16,6 @@
namespace xe { namespace xe {
namespace kernel { namespace kernel {
namespace xboxkrnl { namespace xboxkrnl {
uint32_t xeMmAllocatePhysicalMemoryEx(uint32_t flags, uint32_t region_size, uint32_t xeMmAllocatePhysicalMemoryEx(uint32_t flags, uint32_t region_size,

View File

@ -434,8 +434,10 @@ pointer_result_t RtlImageNtHeader_entry(lpvoid_t module) {
} }
DECLARE_XBOXKRNL_EXPORT1(RtlImageNtHeader, kNone, kImplemented); DECLARE_XBOXKRNL_EXPORT1(RtlImageNtHeader, kNone, kImplemented);
// https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagedirectoryentrytodata // https://learn.microsoft.com/en-us/windows/win32/api/dbghelp/nf-dbghelp-imagedirectoryentrytodata
dword_result_t RtlImageDirectoryEntryToData_entry(dword_t Base, dword_t MappedAsImage_, dword_result_t RtlImageDirectoryEntryToData_entry(dword_t Base,
word_t DirectoryEntry, dword_t Size, dword_t MappedAsImage_,
word_t DirectoryEntry,
dword_t Size,
const ppc_context_t& ctx) { const ppc_context_t& ctx) {
bool MappedAsImage = static_cast<unsigned char>(MappedAsImage_); bool MappedAsImage = static_cast<unsigned char>(MappedAsImage_);
uint32_t aligned_base = Base; uint32_t aligned_base = Base;

View File

@ -63,7 +63,8 @@ uint32_t xeNtQueueApcThread(uint32_t thread_handle, uint32_t apc_routine,
void xeKfLowerIrql(PPCContext* ctx, unsigned char new_irql); void xeKfLowerIrql(PPCContext* ctx, unsigned char new_irql);
unsigned char xeKfRaiseIrql(PPCContext* ctx, unsigned char new_irql); unsigned char xeKfRaiseIrql(PPCContext* ctx, unsigned char new_irql);
void xeKeKfReleaseSpinLock(PPCContext* ctx, X_KSPINLOCK* lock, uint32_t old_irql, bool change_irql=true); void xeKeKfReleaseSpinLock(PPCContext* ctx, X_KSPINLOCK* lock,
uint32_t old_irql, bool change_irql = true);
uint32_t xeKeKfAcquireSpinLock(PPCContext* ctx, X_KSPINLOCK* lock, uint32_t xeKeKfAcquireSpinLock(PPCContext* ctx, X_KSPINLOCK* lock,
bool change_irql = true); bool change_irql = true);

View File

@ -388,7 +388,9 @@ object_ref<XObject> XObject::GetNativeObject(KernelState* kernel_state,
// Already initialized. // Already initialized.
// TODO: assert if the type of the object != as_type // TODO: assert if the type of the object != as_type
uint32_t handle = header->wait_list_blink; uint32_t handle = header->wait_list_blink;
result = kernel_state->object_table()->LookupObject<XObject>(handle, true).release(); result = kernel_state->object_table()
->LookupObject<XObject>(handle, true)
.release();
} else { } else {
// First use, create new. // First use, create new.
// https://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html // https://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html

View File

@ -12,8 +12,8 @@
#include "xenia/base/threading.h" #include "xenia/base/threading.h"
#include "xenia/kernel/xobject.h" #include "xenia/kernel/xobject.h"
#include "xenia/xbox.h"
#include "xenia/kernel/xthread.h" #include "xenia/kernel/xthread.h"
#include "xenia/xbox.h"
namespace xe { namespace xe {
namespace kernel { namespace kernel {

View File

@ -358,6 +358,7 @@ class XThread : public XObject, public cpu::Thread {
pending_mutant_acquires_.push_back(mutant); pending_mutant_acquires_.push_back(mutant);
} }
void SetCurrentThread(); void SetCurrentThread();
protected: protected:
bool AllocateStack(uint32_t size); bool AllocateStack(uint32_t size);
void FreeStack(); void FreeStack();
@ -391,7 +392,8 @@ class XThread : public XObject, public cpu::Thread {
class XHostThread : public XThread { class XHostThread : public XThread {
public: public:
XHostThread(KernelState* kernel_state, uint32_t stack_size, XHostThread(KernelState* kernel_state, uint32_t stack_size,
uint32_t creation_flags, std::function<int()> host_fn, uint32_t guest_process=0); uint32_t creation_flags, std::function<int()> host_fn,
uint32_t guest_process = 0);
virtual void Execute(); virtual void Execute();

View File

@ -21,6 +21,7 @@
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/base/threading.h" #include "xenia/base/threading.h"
#include "xenia/cpu/mmio_handler.h" #include "xenia/cpu/mmio_handler.h"
// TODO(benvanik): move xbox.h out // TODO(benvanik): move xbox.h out

View File

@ -8,10 +8,10 @@
*/ */
#include <regex> #include <regex>
#include "xenia/config.h"
#include "xenia/base/cvar.h" #include "xenia/base/cvar.h"
#include "xenia/base/filesystem.h" #include "xenia/base/filesystem.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/config.h"
#include "xenia/memory.h" #include "xenia/memory.h"
#include "xenia/patcher/patch_db.h" #include "xenia/patcher/patch_db.h"

View File

@ -1,5 +1,5 @@
#include <vector>
#include <utility> #include <utility>
#include <vector>
static const uint8_t player_one_notification_icon[] = { static const uint8_t player_one_notification_icon[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
@ -4269,8 +4269,8 @@ static const uint8_t player_any_notification_icon[] = {
0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82}; 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
static const uint32_t player_any_notification_icon_len = 10320; static const uint32_t player_any_notification_icon_len = 10320;
static const std::vector<std::pair<const uint8_t*, uint32_t>>
static const std::vector<std::pair<const uint8_t*, uint32_t>> notification_icons = { notification_icons = {
{player_one_notification_icon, player_one_notification_icon_len}, {player_one_notification_icon, player_one_notification_icon_len},
{player_two_notification_icon, player_two_notification_icon_len}, {player_two_notification_icon, player_two_notification_icon_len},
{player_three_notification_icon, player_three_notification_icon_len}, {player_three_notification_icon, player_three_notification_icon_len},

View File

@ -12,9 +12,9 @@
#include <time.h> #include <time.h>
#include "xenia/xbox.h"
#include "xenia/base/string_util.h" #include "xenia/base/string_util.h"
#include "xenia/kernel/util/xex2_info.h" #include "xenia/kernel/util/xex2_info.h"
#include "xenia/xbox.h"
namespace xe { namespace xe {
namespace vfs { namespace vfs {

View File

@ -7,8 +7,8 @@
****************************************************************************** ******************************************************************************
*/ */
#include "xenia/base/logging.h"
#include "xenia/vfs/devices/xcontent_container_device.h" #include "xenia/vfs/devices/xcontent_container_device.h"
#include "xenia/base/logging.h"
#include "xenia/vfs/devices/xcontent_devices/stfs_container_device.h" #include "xenia/vfs/devices/xcontent_devices/stfs_container_device.h"
#include "xenia/vfs/devices/xcontent_devices/svod_container_device.h" #include "xenia/vfs/devices/xcontent_devices/svod_container_device.h"

View File

@ -16,9 +16,9 @@
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/kernel/util/xex2_info.h" #include "xenia/kernel/util/xex2_info.h"
#include "xenia/kernel/xam/content_manager.h"
#include "xenia/vfs/device.h" #include "xenia/vfs/device.h"
#include "xenia/vfs/devices/stfs_xbox.h" #include "xenia/vfs/devices/stfs_xbox.h"
#include "xenia/kernel/xam/content_manager.h"
namespace xe { namespace xe {
namespace vfs { namespace vfs {
@ -71,7 +71,8 @@ class XContentContainerDevice : public Device {
}; };
virtual Result Read() = 0; virtual Result Read() = 0;
// Load all host files. Usually STFS is only 1 file, meanwhile SVOD is usually multiple file. // Load all host files. Usually STFS is only 1 file, meanwhile SVOD is usually
// multiple file.
virtual Result LoadHostFiles(FILE* header_file) = 0; virtual Result LoadHostFiles(FILE* header_file) = 0;
// Initialize any container specific fields. // Initialize any container specific fields.
virtual void SetupContainer(){}; virtual void SetupContainer(){};
@ -89,7 +90,9 @@ class XContentContainerDevice : public Device {
const std::filesystem::path& GetHostPath() const { return host_path_; } const std::filesystem::path& GetHostPath() const { return host_path_; }
const XContentContainerHeader* GetContainerHeader() const { return header_.get(); } const XContentContainerHeader* GetContainerHeader() const {
return header_.get();
}
std::string name_; std::string name_;
std::filesystem::path host_path_; std::filesystem::path host_path_;

View File

@ -312,7 +312,6 @@ struct X_EX_TITLE_TERMINATE_REGISTRATION {
}; };
static_assert_size(X_EX_TITLE_TERMINATE_REGISTRATION, 16); static_assert_size(X_EX_TITLE_TERMINATE_REGISTRATION, 16);
enum X_OBJECT_HEADER_FLAGS : uint16_t { enum X_OBJECT_HEADER_FLAGS : uint16_t {
OBJECT_HEADER_FLAG_NAMED_OBJECT = OBJECT_HEADER_FLAG_NAMED_OBJECT =
1, // if set, has X_OBJECT_HEADER_NAME_INFO prior to X_OBJECT_HEADER 1, // if set, has X_OBJECT_HEADER_NAME_INFO prior to X_OBJECT_HEADER

View File

@ -2,120 +2,192 @@
# #
# ===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===# # ===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
# #
# The LLVM Compiler Infrastructure # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# # See https://llvm.org/LICENSE.txt for license information.
# This file is distributed under the University of Illinois Open Source # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# License. See LICENSE.TXT for details.
# #
# ===------------------------------------------------------------------------===# # ===------------------------------------------------------------------------===#
r""" """
ClangFormat Diff Reformatter
============================
This script reads input from a unified diff and reformats all the changed This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch. lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users: Example usage for git/svn users:
git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i git diff -U0 --no-color --relative HEAD^ | {clang_format_diff} -p1 -i
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i svn diff --diff-cmd=diff -x-U0 | {clang_format_diff} -i
It should be noted that the filename contained in the diff is used unmodified
to determine the source file to update. Users calling this script directly
should be careful to ensure that the path in the diff is correct relative to the
current working directory.
""" """
from __future__ import absolute_import, division, print_function
import argparse import argparse
import difflib import difflib
import re import re
import string
import subprocess import subprocess
import StringIO
import sys import sys
if sys.version_info.major >= 3:
from io import StringIO
else:
from io import BytesIO as StringIO
def main(): def main():
parser = argparse.ArgumentParser(description= parser = argparse.ArgumentParser(
'Reformat changed lines in diff. Without -i ' description=__doc__.format(clang_format_diff="%(prog)s"),
'option just output the diff that would be ' formatter_class=argparse.RawDescriptionHelpFormatter,
'introduced.') )
parser.add_argument('-i', action='store_true', default=False, parser.add_argument(
help='apply edits to files instead of displaying a diff') "-i",
parser.add_argument('-p', metavar='NUM', default=0, action="store_true",
help='strip the smallest prefix containing P slashes') default=False,
parser.add_argument('-regex', metavar='PATTERN', default=None, help="apply edits to files instead of displaying a diff",
help='custom pattern selecting file paths to reformat ' )
'(case sensitive, overrides -iregex)') parser.add_argument(
parser.add_argument('-iregex', metavar='PATTERN', default= "-p",
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|ts|proto' metavar="NUM",
r'|protodevel|java)', default=0,
help='custom pattern selecting file paths to reformat ' help="strip the smallest prefix containing P slashes",
'(case insensitive, overridden by -regex)') )
parser.add_argument('-sort-includes', action='store_true', default=False, parser.add_argument(
help='let clang-format sort include blocks') "-regex",
parser.add_argument('-v', '--verbose', action='store_true', metavar="PATTERN",
help='be more verbose, ineffective without -i') default=None,
parser.add_argument('-style', help="custom pattern selecting file paths to reformat "
help='formatting style to apply (LLVM, Google, Chromium, ' "(case sensitive, overrides -iregex)",
'Mozilla, WebKit)') )
parser.add_argument('-binary', default='clang-format', parser.add_argument(
help='location of binary to use for clang-format') "-iregex",
metavar="PATTERN",
default=r".*\.(?:cpp|cc|c\+\+|cxx|cppm|ccm|cxxm|c\+\+m|c|cl|h|hh|hpp"
r"|hxx|m|mm|inc|js|ts|proto|protodevel|java|cs|json|s?vh?)",
help="custom pattern selecting file paths to reformat "
"(case insensitive, overridden by -regex)",
)
parser.add_argument(
"-sort-includes",
action="store_true",
default=False,
help="let clang-format sort include blocks",
)
parser.add_argument(
"-v",
"--verbose",
action="store_true",
help="be more verbose, ineffective without -i",
)
parser.add_argument(
"-style",
help="formatting style to apply (LLVM, GNU, Google, Chromium, "
"Microsoft, Mozilla, WebKit)",
)
parser.add_argument(
"-fallback-style",
help="The name of the predefined style used as a"
"fallback in case clang-format is invoked with"
"-style=file, but can not find the .clang-format"
"file to use.",
)
parser.add_argument(
"-binary",
default="clang-format",
help="location of binary to use for clang-format",
)
args = parser.parse_args() args = parser.parse_args()
# Extract changed lines for each file. # Extract changed lines for each file.
filename = None filename = None
lines_by_file = {} lines_by_file = {}
for line in sys.stdin: for line in sys.stdin:
match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line) match = re.search(r"^\+\+\+\ (.*?/){%s}(\S*)" % args.p, line)
if match: if match:
filename = match.group(2) filename = match.group(2)
if filename == None: if filename is None:
continue continue
if args.regex is not None: if args.regex is not None:
if not re.match('^%s$' % args.regex, filename): if not re.match("^%s$" % args.regex, filename):
continue continue
else: else:
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE): if not re.match("^%s$" % args.iregex, filename, re.IGNORECASE):
continue continue
match = re.search('^@@.*\+(\d+)(,(\d+))?', line) match = re.search(r"^@@.*\+(\d+)(?:,(\d+))?", line)
if match: if match:
start_line = int(match.group(1)) start_line = int(match.group(1))
line_count = 1 line_count = 1
if match.group(3): if match.group(2):
line_count = int(match.group(3)) line_count = int(match.group(2))
# The input is something like
#
# @@ -1, +0,0 @@
#
# which means no lines were added.
if line_count == 0: if line_count == 0:
continue continue
end_line = start_line + line_count - 1; # Also format lines range if line_count is 0 in case of deleting
# surrounding statements.
end_line = start_line
if line_count != 0:
end_line += line_count - 1
lines_by_file.setdefault(filename, []).extend( lines_by_file.setdefault(filename, []).extend(
['-lines', str(start_line) + ':' + str(end_line)]) ["-lines", str(start_line) + ":" + str(end_line)]
)
# Reformat files containing changes in place. # Reformat files containing changes in place.
for filename, lines in lines_by_file.iteritems(): for filename, lines in lines_by_file.items():
if args.i and args.verbose: if args.i and args.verbose:
print 'Formatting', filename print("Formatting {}".format(filename))
command = [args.binary, filename] command = [args.binary, filename]
if args.i: if args.i:
command.append('-i') command.append("-i")
if args.sort_includes: if args.sort_includes:
command.append('-sort-includes') command.append("-sort-includes")
command.extend(lines) command.extend(lines)
if args.style: if args.style:
command.extend(['-style', args.style]) command.extend(["-style", args.style])
p = subprocess.Popen(command, stdout=subprocess.PIPE, if args.fallback_style:
stderr=None, stdin=subprocess.PIPE) command.extend(["-fallback-style", args.fallback_style])
try:
p = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=None,
stdin=subprocess.PIPE,
universal_newlines=True,
)
except OSError as e:
# Give the user more context when clang-format isn't
# found/isn't executable, etc.
raise RuntimeError(
'Failed to run "%s" - %s"' % (" ".join(command), e.strerror)
)
stdout, stderr = p.communicate() stdout, stderr = p.communicate()
if p.returncode != 0: if p.returncode != 0:
sys.exit(p.returncode); sys.exit(p.returncode)
if not args.i: if not args.i:
with open(filename) as f: with open(filename) as f:
code = f.readlines() code = f.readlines()
formatted_code = StringIO.StringIO(stdout).readlines() formatted_code = StringIO(stdout).readlines()
diff = difflib.unified_diff(code, formatted_code, diff = difflib.unified_diff(
filename, filename, code,
'(before formatting)', '(after formatting)') formatted_code,
diff_string = string.join(diff, '') filename,
filename,
"(before formatting)",
"(after formatting)",
)
diff_string = "".join(diff)
if len(diff_string) > 0: if len(diff_string) > 0:
sys.stdout.write(diff_string) sys.stdout.write(diff_string)
sys.exit(1)
if __name__ == '__main__':
if __name__ == "__main__":
main() main()

View File

@ -12,47 +12,62 @@
# It operates on the current, potentially unsaved buffer and does not create # It operates on the current, potentially unsaved buffer and does not create
# or save any files. To revert a formatting, just undo. # or save any files. To revert a formatting, just undo.
from __future__ import print_function from __future__ import absolute_import, division, print_function
import sublime import sublime
import sublime_plugin import sublime_plugin
import subprocess import subprocess
# Change this to the full path if clang-format is not on the path. # Change this to the full path if clang-format is not on the path.
binary = 'clang-format' binary = "clang-format"
# Change this to format according to other formatting styles. See the output of # Change this to format according to other formatting styles. See the output of
# 'clang-format --help' for a list of supported styles. The default looks for # 'clang-format --help' for a list of supported styles. The default looks for
# a '.clang-format' or '_clang-format' file to indicate the style that should be # a '.clang-format' or '_clang-format' file to indicate the style that should be
# used. # used.
style = 'file' style = None
class ClangFormatCommand(sublime_plugin.TextCommand): class ClangFormatCommand(sublime_plugin.TextCommand):
def run(self, edit): def run(self, edit):
encoding = self.view.encoding() encoding = self.view.encoding()
if encoding == 'Undefined': if encoding == "Undefined":
encoding = 'utf-8' encoding = "utf-8"
regions = [] regions = []
command = [binary, '-style', style] command = [binary]
if style:
command.extend(["-style", style])
for region in self.view.sel(): for region in self.view.sel():
regions.append(region) regions.append(region)
region_offset = min(region.a, region.b) region_offset = min(region.a, region.b)
region_length = abs(region.b - region.a) region_length = abs(region.b - region.a)
command.extend(['-offset', str(region_offset), command.extend(
'-length', str(region_length), [
'-assume-filename', str(self.view.file_name())]) "-offset",
str(region_offset),
"-length",
str(region_length),
"-assume-filename",
str(self.view.file_name()),
]
)
old_viewport_position = self.view.viewport_position() old_viewport_position = self.view.viewport_position()
buf = self.view.substr(sublime.Region(0, self.view.size())) buf = self.view.substr(sublime.Region(0, self.view.size()))
p = subprocess.Popen(command, stdout=subprocess.PIPE, p = subprocess.Popen(
stderr=subprocess.PIPE, stdin=subprocess.PIPE) command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
)
output, error = p.communicate(buf.encode(encoding)) output, error = p.communicate(buf.encode(encoding))
if error: if error:
print(error) print(error)
self.view.replace( self.view.replace(
edit, sublime.Region(0, self.view.size()), edit, sublime.Region(0, self.view.size()), output.decode(encoding)
output.decode(encoding)) )
self.view.sel().clear() self.view.sel().clear()
for region in regions: for region in regions:
self.view.sel().add(region) self.view.sel().add(region)
# FIXME: Without the 10ms delay, the viewport sometimes jumps. # FIXME: Without the 10ms delay, the viewport sometimes jumps.
sublime.set_timeout(lambda: self.view.set_viewport_position( sublime.set_timeout(
old_viewport_position, False), 10) lambda: self.view.set_viewport_position(old_viewport_position, False), 10
)

View File

@ -1,7 +1,9 @@
;;; clang-format.el --- Format code using clang-format -*- lexical-binding: t; -*- ;;; clang-format.el --- Format code using clang-format -*- lexical-binding: t; -*-
;; Version: 0.1.0
;; Keywords: tools, c ;; Keywords: tools, c
;; Package-Requires: ((cl-lib "0.3")) ;; Package-Requires: ((cl-lib "0.3"))
;; SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
;;; Commentary: ;;; Commentary:
@ -45,17 +47,29 @@ A string containing the name or the full path of the executable."
:type '(file :must-match t) :type '(file :must-match t)
:risky t) :risky t)
(defcustom clang-format-style "file" (defcustom clang-format-style nil
"Style argument to pass to clang-format. "Style argument to pass to clang-format.
By default clang-format will load the style configuration from By default clang-format will load the style configuration from
a file named .clang-format located in one of the parent directories a file named .clang-format located in one of the parent directories
of the buffer." of the buffer."
:group 'clang-format :group 'clang-format
:type 'string :type '(choice (string) (const nil))
:safe #'stringp) :safe #'stringp)
(make-variable-buffer-local 'clang-format-style) (make-variable-buffer-local 'clang-format-style)
(defcustom clang-format-fallback-style "none"
"Fallback style to pass to clang-format.
This style will be used if clang-format-style is set to \"file\"
and no .clang-format is found in the directory of the buffer or
one of parent directories. Set to \"none\" to disable formatting
in such buffers."
:group 'clang-format
:type 'string
:safe #'stringp)
(make-variable-buffer-local 'clang-format-fallback-style)
(defun clang-format--extract (xml-node) (defun clang-format--extract (xml-node)
"Extract replacements and cursor information from XML-NODE." "Extract replacements and cursor information from XML-NODE."
(unless (and (listp xml-node) (eq (xml-node-name xml-node) 'replacements)) (unless (and (listp xml-node) (eq (xml-node-name xml-node) 'replacements))
@ -69,7 +83,7 @@ of the buffer."
(let* ((children (xml-node-children node)) (let* ((children (xml-node-children node))
(text (car children))) (text (car children)))
(cl-case (xml-node-name node) (cl-case (xml-node-name node)
('replacement (replacement
(let* ((offset (xml-get-attribute-or-nil node 'offset)) (let* ((offset (xml-get-attribute-or-nil node 'offset))
(length (xml-get-attribute-or-nil node 'length))) (length (xml-get-attribute-or-nil node 'length)))
(when (or (null offset) (null length)) (when (or (null offset) (null length))
@ -80,7 +94,7 @@ of the buffer."
(setq offset (string-to-number offset)) (setq offset (string-to-number offset))
(setq length (string-to-number length)) (setq length (string-to-number length))
(push (list offset length text) replacements))) (push (list offset length text) replacements)))
('cursor (cursor
(setq cursor (string-to-number text))))))) (setq cursor (string-to-number text)))))))
;; Sort by decreasing offset, length. ;; Sort by decreasing offset, length.
@ -119,10 +133,12 @@ is a zero-based file offset, assuming utf-8-unix coding."
(byte-to-position (1+ byte))))) (byte-to-position (1+ byte)))))
;;;###autoload ;;;###autoload
(defun clang-format-region (start end &optional style) (defun clang-format-region (start end &optional style assume-file-name)
"Use clang-format to format the code between START and END according to STYLE. "Use clang-format to format the code between START and END according to STYLE.
If called interactively uses the region or the current statement if there If called interactively uses the region or the current statement if there is no
is no active region. If no style is given uses `clang-format-style'." no active region. If no STYLE is given uses `clang-format-style'. Use
ASSUME-FILE-NAME to locate a style config file, if no ASSUME-FILE-NAME is given
uses the function `buffer-file-name'."
(interactive (interactive
(if (use-region-p) (if (use-region-p)
(list (region-beginning) (region-end)) (list (region-beginning) (region-end))
@ -131,6 +147,9 @@ is no active region. If no style is given uses `clang-format-style'."
(unless style (unless style
(setq style clang-format-style)) (setq style clang-format-style))
(unless assume-file-name
(setq assume-file-name (buffer-file-name (buffer-base-buffer))))
(let ((file-start (clang-format--bufferpos-to-filepos start 'approximate (let ((file-start (clang-format--bufferpos-to-filepos start 'approximate
'utf-8-unix)) 'utf-8-unix))
(file-end (clang-format--bufferpos-to-filepos end 'approximate (file-end (clang-format--bufferpos-to-filepos end 'approximate
@ -144,16 +163,22 @@ is no active region. If no style is given uses `clang-format-style'."
;; always use utf-8-unix and ignore the buffer coding system. ;; always use utf-8-unix and ignore the buffer coding system.
(default-process-coding-system '(utf-8-unix . utf-8-unix))) (default-process-coding-system '(utf-8-unix . utf-8-unix)))
(unwind-protect (unwind-protect
(let ((status (call-process-region (let ((status (apply #'call-process-region
nil nil clang-format-executable nil nil clang-format-executable
nil `(,temp-buffer ,temp-file) nil nil `(,temp-buffer ,temp-file) nil
`("-output-replacements-xml"
"-output-replacements-xml" ;; Guard against a nil assume-file-name.
"-assume-filename" (or (buffer-file-name) "") ;; If the clang-format option -assume-filename
"-style" style ;; is given a blank string it will crash as per
"-offset" (number-to-string file-start) ;; the following bug report
"-length" (number-to-string (- file-end file-start)) ;; https://bugs.llvm.org/show_bug.cgi?id=34667
"-cursor" (number-to-string cursor))) ,@(and assume-file-name
(list "-assume-filename" assume-file-name))
,@(and style (list "-style" style))
"-fallback-style" ,clang-format-fallback-style
"-offset" ,(number-to-string file-start)
"-length" ,(number-to-string (- file-end file-start))
"-cursor" ,(number-to-string cursor))))
(stderr (with-temp-buffer (stderr (with-temp-buffer
(unless (zerop (cadr (insert-file-contents temp-file))) (unless (zerop (cadr (insert-file-contents temp-file)))
(insert ": ")) (insert ": "))
@ -181,10 +206,13 @@ is no active region. If no style is given uses `clang-format-style'."
(when (buffer-name temp-buffer) (kill-buffer temp-buffer))))) (when (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
;;;###autoload ;;;###autoload
(defun clang-format-buffer (&optional style) (defun clang-format-buffer (&optional style assume-file-name)
"Use clang-format to format the current buffer according to STYLE." "Use clang-format to format the current buffer according to STYLE.
If no STYLE is given uses `clang-format-style'. Use ASSUME-FILE-NAME
to locate a style config file. If no ASSUME-FILE-NAME is given uses
the function `buffer-file-name'."
(interactive) (interactive)
(clang-format-region (point-min) (point-max) style)) (clang-format-region (point-min) (point-max) style assume-file-name))
;;;###autoload ;;;###autoload
(defalias 'clang-format 'clang-format-region) (defalias 'clang-format 'clang-format-region)

View File

@ -2,11 +2,19 @@
# - Change 'binary' if clang-format is not on the path (see below). # - Change 'binary' if clang-format is not on the path (see below).
# - Add to your .vimrc: # - Add to your .vimrc:
# #
# if has('python')
# map <C-I> :pyf <path-to-this-file>/clang-format.py<cr> # map <C-I> :pyf <path-to-this-file>/clang-format.py<cr>
# imap <C-I> <c-o>:pyf <path-to-this-file>/clang-format.py<cr> # imap <C-I> <c-o>:pyf <path-to-this-file>/clang-format.py<cr>
# elseif has('python3')
# map <C-I> :py3f <path-to-this-file>/clang-format.py<cr>
# imap <C-I> <c-o>:py3f <path-to-this-file>/clang-format.py<cr>
# endif
# #
# The first line enables clang-format for NORMAL and VISUAL mode, the second # The if-elseif-endif conditional should pick either the python3 or python2
# line adds support for INSERT mode. Change "C-I" to another binding if you # integration depending on your vim setup.
#
# The first mapping enables clang-format for NORMAL and VISUAL mode, the second
# mapping adds support for INSERT mode. Change "C-I" to another binding if you
# need clang-format on a different key (C-I stands for Ctrl+i). # need clang-format on a different key (C-I stands for Ctrl+i).
# #
# With this integration you can press the bound key and clang-format will # With this integration you can press the bound key and clang-format will
@ -20,15 +28,20 @@
# like: # like:
# :function FormatFile() # :function FormatFile()
# : let l:lines="all" # : let l:lines="all"
# : if has('python')
# : pyf <path-to-this-file>/clang-format.py # : pyf <path-to-this-file>/clang-format.py
# : elseif has('python3')
# : py3f <path-to-this-file>/clang-format.py
# : endif
# :endfunction # :endfunction
# #
# It operates on the current, potentially unsaved buffer and does not create # It operates on the current, potentially unsaved buffer and does not create
# or save any files. To revert a formatting, just undo. # or save any files. To revert a formatting, just undo.
from __future__ import print_function from __future__ import absolute_import, division, print_function
import difflib import difflib
import json import json
import os.path
import platform import platform
import subprocess import subprocess
import sys import sys
@ -36,72 +49,90 @@ import vim
# set g:clang_format_path to the path to clang-format if it is not on the path # set g:clang_format_path to the path to clang-format if it is not on the path
# Change this to the full path if clang-format is not on the path. # Change this to the full path if clang-format is not on the path.
binary = 'clang-format' binary = "clang-format"
if vim.eval('exists("g:clang_format_path")') == "1": if vim.eval('exists("g:clang_format_path")') == "1":
binary = vim.eval('g:clang_format_path') binary = vim.eval("g:clang_format_path")
# Change this to format according to other formatting styles. See the output of # Change this to format according to other formatting styles. See the output of
# 'clang-format --help' for a list of supported styles. The default looks for # 'clang-format --help' for a list of supported styles. The default looks for
# a '.clang-format' or '_clang-format' file to indicate the style that should be # a '.clang-format' or '_clang-format' file to indicate the style that should be
# used. # used.
style = 'file' style = None
fallback_style = None fallback_style = None
if vim.eval('exists("g:clang_format_fallback_style")') == "1": if vim.eval('exists("g:clang_format_fallback_style")') == "1":
fallback_style = vim.eval('g:clang_format_fallback_style') fallback_style = vim.eval("g:clang_format_fallback_style")
def get_buffer(encoding): def get_buffer(encoding):
if platform.python_version_tuple()[0] == '3': if platform.python_version_tuple()[0] == "3":
return vim.current.buffer return vim.current.buffer
return [line.decode(encoding) for line in vim.current.buffer] return [line.decode(encoding) for line in vim.current.buffer]
def main(): def main():
# Get the current text. # Get the current text.
encoding = vim.eval("&encoding") encoding = vim.eval("&encoding")
buf = get_buffer(encoding) buf = get_buffer(encoding)
text = '\n'.join(buf) # Join the buffer into a single string with a terminating newline
text = ("\n".join(buf) + "\n").encode(encoding)
# Determine range to format. # Determine range to format.
if vim.eval('exists("l:lines")') == '1': if vim.eval('exists("l:lines")') == "1":
lines = vim.eval('l:lines') lines = ["-lines", vim.eval("l:lines")]
elif vim.eval('exists("l:formatdiff")') == '1': elif vim.eval('exists("l:formatdiff")') == "1" and os.path.exists(
with open(vim.current.buffer.name, 'r') as f: vim.current.buffer.name
ondisk = f.read().splitlines(); ):
with open(vim.current.buffer.name, "r") as f:
ondisk = f.read().splitlines()
sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer) sequence = difflib.SequenceMatcher(None, ondisk, vim.current.buffer)
lines = [] lines = []
for op in reversed(sequence.get_opcodes()): for op in reversed(sequence.get_opcodes()):
if op[0] not in ['equal', 'delete']: if op[0] not in ["equal", "delete"]:
lines += ['-lines', '%s:%s' % (op[3] + 1, op[4])] lines += ["-lines", "%s:%s" % (op[3] + 1, op[4])]
if lines == []: if lines == []:
return return
else: else:
lines = ['-lines', '%s:%s' % (vim.current.range.start + 1, lines = [
vim.current.range.end + 1)] "-lines",
"%s:%s" % (vim.current.range.start + 1, vim.current.range.end + 1),
]
# Determine the cursor position. # Convert cursor (line, col) to bytes.
cursor = int(vim.eval('line2byte(line("."))+col(".")')) - 2 # Don't use line2byte: https://github.com/vim/vim/issues/5930
if cursor < 0: _, cursor_line, cursor_col, _ = vim.eval('getpos(".")') # 1-based
print('Couldn\'t determine cursor position. Is your file empty?') cursor_byte = 0
for line in text.split(b"\n")[: int(cursor_line) - 1]:
cursor_byte += len(line) + 1
cursor_byte += int(cursor_col) - 1
if cursor_byte < 0:
print("Couldn't determine cursor position. Is your file empty?")
return return
# Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format. # Avoid flashing an ugly, ugly cmd prompt on Windows when invoking clang-format.
startupinfo = None startupinfo = None
if sys.platform.startswith('win32'): if sys.platform.startswith("win32"):
startupinfo = subprocess.STARTUPINFO() startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
startupinfo.wShowWindow = subprocess.SW_HIDE startupinfo.wShowWindow = subprocess.SW_HIDE
# Call formatter. # Call formatter.
command = [binary, '-style', style, '-cursor', str(cursor)] command = [binary, "-cursor", str(cursor_byte)]
if lines != 'all': if lines != ["-lines", "all"]:
command += lines command += lines
if style:
command.extend(["-style", style])
if fallback_style: if fallback_style:
command.extend(['-fallback-style', fallback_style]) command.extend(["-fallback-style", fallback_style])
if vim.current.buffer.name: if vim.current.buffer.name:
command.extend(['-assume-filename', vim.current.buffer.name]) command.extend(["-assume-filename", vim.current.buffer.name])
p = subprocess.Popen(command, p = subprocess.Popen(
stdout=subprocess.PIPE, stderr=subprocess.PIPE, command,
stdin=subprocess.PIPE, startupinfo=startupinfo) stdout=subprocess.PIPE,
stdout, stderr = p.communicate(input=text.encode(encoding)) stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
startupinfo=startupinfo,
)
stdout, stderr = p.communicate(input=text)
# If successful, replace buffer contents. # If successful, replace buffer contents.
if stderr: if stderr:
@ -109,19 +140,29 @@ def main():
if not stdout: if not stdout:
print( print(
'No output from clang-format (crashed?).\n' "No output from clang-format (crashed?).\n"
'Please report to bugs.llvm.org.' "Please report to bugs.llvm.org."
) )
else: else:
lines = stdout.decode(encoding).split('\n') header, content = stdout.split(b"\n", 1)
output = json.loads(lines[0]) header = json.loads(header.decode("utf-8"))
lines = lines[1:] # Strip off the trailing newline (added above).
# This maintains trailing empty lines present in the buffer if
# the -lines specification requests them to remain unchanged.
lines = content.decode(encoding).split("\n")[:-1]
sequence = difflib.SequenceMatcher(None, buf, lines) sequence = difflib.SequenceMatcher(None, buf, lines)
for op in reversed(sequence.get_opcodes()): for op in reversed(sequence.get_opcodes()):
if op[0] is not 'equal': if op[0] != "equal":
vim.current.buffer[op[1] : op[2]] = lines[op[3] : op[4]] vim.current.buffer[op[1] : op[2]] = lines[op[3] : op[4]]
if output.get('IncompleteFormat'): if header.get("IncompleteFormat"):
print('clang-format: incomplete (syntax errors)') print("clang-format: incomplete (syntax errors)")
vim.command('goto %d' % (output['Cursor'] + 1)) # Convert cursor bytes to (line, col)
# Don't use goto: https://github.com/vim/vim/issues/5930
cursor_byte = int(header["Cursor"])
prefix = content[0:cursor_byte]
cursor_line = 1 + prefix.count(b"\n")
cursor_column = 1 + len(prefix.rsplit(b"\n", 1)[-1])
vim.command("call cursor(%d, %d)" % (cursor_line, cursor_column))
main() main()

View File

@ -2,10 +2,9 @@
# #
#===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===# #===- git-clang-format - ClangFormat Git Integration ---------*- python -*--===#
# #
# The LLVM Compiler Infrastructure # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# # See https://llvm.org/LICENSE.txt for license information.
# This file is distributed under the University of Illinois Open Source # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
# License. See LICENSE.TXT for details.
# #
#===------------------------------------------------------------------------===# #===------------------------------------------------------------------------===#
@ -23,7 +22,7 @@ git clang-format -h
Requires Python 2.7 or Python 3 Requires Python 2.7 or Python 3
""" """
from __future__ import print_function from __future__ import absolute_import, division, print_function
import argparse import argparse
import collections import collections
import contextlib import contextlib
@ -33,12 +32,23 @@ import re
import subprocess import subprocess
import sys import sys
usage = 'git clang-format [OPTIONS] [<commit>] [<commit>] [--] [<file>...]' usage = ('git clang-format [OPTIONS] [<commit>] [<commit>|--staged] '
'[--] [<file>...]')
desc = ''' desc = '''
If zero or one commits are given, run clang-format on all lines that differ If zero or one commits are given, run clang-format on all lines that differ
between the working directory and <commit>, which defaults to HEAD. Changes are between the working directory and <commit>, which defaults to HEAD. Changes are
only applied to the working directory. only applied to the working directory, or in the stage/index.
Examples:
To format staged changes, i.e everything that's been `git add`ed:
git clang-format
To also format everything touched in the most recent commit:
git clang-format HEAD~1
If you're on a branch off main, to format everything touched on your branch:
git clang-format main
If two commits are given (requires --diff), run clang-format on all lines in the If two commits are given (requires --diff), run clang-format on all lines in the
second <commit> that differ from the first <commit>. second <commit> that differ from the first <commit>.
@ -46,7 +56,7 @@ second <commit> that differ from the first <commit>.
The following git-config settings set the default of the corresponding option: The following git-config settings set the default of the corresponding option:
clangFormat.binary clangFormat.binary
clangFormat.commit clangFormat.commit
clangFormat.extension clangFormat.extensions
clangFormat.style clangFormat.style
''' '''
@ -78,12 +88,17 @@ def main():
'c', 'h', # C 'c', 'h', # C
'm', # ObjC 'm', # ObjC
'mm', # ObjC++ 'mm', # ObjC++
'cc', 'cp', 'cpp', 'c++', 'cxx', 'hpp', # C++ 'cc', 'cp', 'cpp', 'c++', 'cxx', 'hh', 'hpp', 'hxx', 'inc', # C++
'ccm', 'cppm', 'cxxm', 'c++m', # C++ Modules
'cu', 'cuh', # CUDA
# Other languages that clang-format supports # Other languages that clang-format supports
'proto', 'protodevel', # Protocol Buffers 'proto', 'protodevel', # Protocol Buffers
'java', # Java 'java', # Java
'js', # JavaScript 'js', # JavaScript
'ts', # TypeScript 'ts', # TypeScript
'cs', # C Sharp
'json', # Json
'sv', 'svh', 'v', 'vh', # Verilog
]) ])
p = argparse.ArgumentParser( p = argparse.ArgumentParser(
@ -97,6 +112,8 @@ def main():
help='default commit to use if none is specified'), help='default commit to use if none is specified'),
p.add_argument('--diff', action='store_true', p.add_argument('--diff', action='store_true',
help='print a diff instead of applying the changes') help='print a diff instead of applying the changes')
p.add_argument('--diffstat', action='store_true',
help='print a diffstat instead of applying the changes')
p.add_argument('--extensions', p.add_argument('--extensions',
default=config.get('clangformat.extensions', default=config.get('clangformat.extensions',
default_extensions), default_extensions),
@ -108,11 +125,17 @@ def main():
help='select hunks interactively') help='select hunks interactively')
p.add_argument('-q', '--quiet', action='count', default=0, p.add_argument('-q', '--quiet', action='count', default=0,
help='print less information') help='print less information')
p.add_argument('--staged', '--cached', action='store_true',
help='format lines in the stage instead of the working dir')
p.add_argument('--style', p.add_argument('--style',
default=config.get('clangformat.style', None), default=config.get('clangformat.style', None),
help='passed to clang-format'), help='passed to clang-format'),
p.add_argument('-v', '--verbose', action='count', default=0, p.add_argument('-v', '--verbose', action='count', default=0,
help='print extra information') help='print extra information')
p.add_argument('--diff_from_common_commit', action='store_true',
help=('diff from the last common commit for commits in '
'separate branches rather than the exact point of the '
'commits'))
# We gather all the remaining positional arguments into 'args' since we need # We gather all the remaining positional arguments into 'args' since we need
# to use some heuristics to determine whether or not <commit> was present. # to use some heuristics to determine whether or not <commit> was present.
# However, to print pretty messages, we make use of metavar and help. # However, to print pretty messages, we make use of metavar and help.
@ -126,52 +149,74 @@ def main():
del opts.quiet del opts.quiet
commits, files = interpret_args(opts.args, dash_dash, opts.commit) commits, files = interpret_args(opts.args, dash_dash, opts.commit)
if len(commits) > 1:
if not opts.diff:
die('--diff is required when two commits are given')
else:
if len(commits) > 2: if len(commits) > 2:
die('at most two commits allowed; %d given' % len(commits)) die('at most two commits allowed; %d given' % len(commits))
changed_lines = compute_diff_and_extract_lines(commits, files) if len(commits) == 2:
if opts.staged:
die('--staged is not allowed when two commits are given')
if not opts.diff:
die('--diff is required when two commits are given')
elif opts.diff_from_common_commit:
die('--diff_from_common_commit is only allowed when two commits are given')
if os.path.dirname(opts.binary):
opts.binary = os.path.abspath(opts.binary)
changed_lines = compute_diff_and_extract_lines(commits,
files,
opts.staged,
opts.diff_from_common_commit)
if opts.verbose >= 1: if opts.verbose >= 1:
ignored_files = set(changed_lines) ignored_files = set(changed_lines)
filter_by_extension(changed_lines, opts.extensions.lower().split(',')) filter_by_extension(changed_lines, opts.extensions.lower().split(','))
# The computed diff outputs absolute paths, so we must cd before accessing
# those files.
cd_to_toplevel()
filter_symlinks(changed_lines)
if opts.verbose >= 1: if opts.verbose >= 1:
ignored_files.difference_update(changed_lines) ignored_files.difference_update(changed_lines)
if ignored_files: if ignored_files:
print('Ignoring changes in the following files (wrong extension):') print(
'Ignoring changes in the following files (wrong extension or symlink):')
for filename in ignored_files: for filename in ignored_files:
print(' %s' % filename) print(' %s' % filename)
if changed_lines: if changed_lines:
print('Running clang-format on the following files:') print('Running clang-format on the following files:')
for filename in changed_lines: for filename in changed_lines:
print(' %s' % filename) print(' %s' % filename)
if not changed_lines: if not changed_lines:
if opts.verbose >= 0:
print('no modified files to format') print('no modified files to format')
return return 0
# The computed diff outputs absolute paths, so we must cd before accessing
# those files.
cd_to_toplevel()
if len(commits) > 1: if len(commits) > 1:
old_tree = commits[1] old_tree = commits[1]
new_tree = run_clang_format_and_save_to_tree(changed_lines, revision = old_tree
revision=commits[1], elif opts.staged:
binary=opts.binary, old_tree = create_tree_from_index(changed_lines)
style=opts.style) revision = ''
else: else:
old_tree = create_tree_from_workdir(changed_lines) old_tree = create_tree_from_workdir(changed_lines)
revision = None
new_tree = run_clang_format_and_save_to_tree(changed_lines, new_tree = run_clang_format_and_save_to_tree(changed_lines,
revision,
binary=opts.binary, binary=opts.binary,
style=opts.style) style=opts.style)
if opts.verbose >= 1: if opts.verbose >= 1:
print('old tree: %s' % old_tree) print('old tree: %s' % old_tree)
print('new tree: %s' % new_tree) print('new tree: %s' % new_tree)
if old_tree == new_tree: if old_tree == new_tree:
if opts.verbose >= 0: if opts.verbose >= 0:
print('clang-format did not modify any files') print('clang-format did not modify any files')
elif opts.diff: return 0
print_diff(old_tree, new_tree)
else: if opts.diff:
return print_diff(old_tree, new_tree)
if opts.diffstat:
return print_diffstat(old_tree, new_tree)
changed_files = apply_changes(old_tree, new_tree, force=opts.force, changed_files = apply_changes(old_tree, new_tree, force=opts.force,
patch_mode=opts.patch) patch_mode=opts.patch)
if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1: if (opts.verbose >= 0 and not opts.patch) or opts.verbose >= 1:
@ -179,6 +224,8 @@ def main():
for filename in changed_files: for filename in changed_files:
print(' %s' % filename) print(' %s' % filename)
return 1
def load_git_config(non_string_options=None): def load_git_config(non_string_options=None):
"""Return the git configuration as a dictionary. """Return the git configuration as a dictionary.
@ -191,7 +238,12 @@ def load_git_config(non_string_options=None):
out = {} out = {}
for entry in run('git', 'config', '--list', '--null').split('\0'): for entry in run('git', 'config', '--list', '--null').split('\0'):
if entry: if entry:
if '\n' in entry:
name, value = entry.split('\n', 1) name, value = entry.split('\n', 1)
else:
# A setting with no '=' ('\n' with --null) is implicitly 'true'
name = entry
value = 'true'
if name in non_string_options: if name in non_string_options:
value = run('git', 'config', non_string_options[name], name) value = run('git', 'config', non_string_options[name], name)
out[name] = value out[name] = value
@ -261,9 +313,9 @@ def get_object_type(value):
return convert_string(stdout.strip()) return convert_string(stdout.strip())
def compute_diff_and_extract_lines(commits, files): def compute_diff_and_extract_lines(commits, files, staged, diff_common_commit):
"""Calls compute_diff() followed by extract_lines().""" """Calls compute_diff() followed by extract_lines()."""
diff_process = compute_diff(commits, files) diff_process = compute_diff(commits, files, staged, diff_common_commit)
changed_lines = extract_lines(diff_process.stdout) changed_lines = extract_lines(diff_process.stdout)
diff_process.stdout.close() diff_process.stdout.close()
diff_process.wait() diff_process.wait()
@ -273,17 +325,24 @@ def compute_diff_and_extract_lines(commits, files):
return changed_lines return changed_lines
def compute_diff(commits, files): def compute_diff(commits, files, staged, diff_common_commit):
"""Return a subprocess object producing the diff from `commits`. """Return a subprocess object producing the diff from `commits`.
The return value's `stdin` file object will produce a patch with the The return value's `stdin` file object will produce a patch with the
differences between the working directory and the first commit if a single differences between the working directory (or stage if --staged is used) and
one was specified, or the difference between both specified commits, filtered the first commit if a single one was specified, or the difference between
on `files` (if non-empty). Zero context lines are used in the patch.""" both specified commits, filtered on `files` (if non-empty).
Zero context lines are used in the patch."""
git_tool = 'diff-index' git_tool = 'diff-index'
if len(commits) > 1: extra_args = []
if len(commits) == 2:
git_tool = 'diff-tree' git_tool = 'diff-tree'
cmd = ['git', git_tool, '-p', '-U0'] + commits + ['--'] if diff_common_commit:
commits = [f'{commits[0]}...{commits[1]}']
elif staged:
extra_args += ['--cached']
cmd = ['git', git_tool, '-p', '-U0'] + extra_args + commits + ['--']
cmd.extend(files) cmd.extend(files)
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
p.stdin.close() p.stdin.close()
@ -304,14 +363,17 @@ def extract_lines(patch_file):
line = convert_string(line) line = convert_string(line)
match = re.search(r'^\+\+\+\ [^/]+/(.*)', line) match = re.search(r'^\+\+\+\ [^/]+/(.*)', line)
if match: if match:
filename = match.group(1).rstrip('\r\n') filename = match.group(1).rstrip('\r\n\t')
match = re.search(r'^@@ -[0-9,]+ \+(\d+)(,(\d+))?', line) match = re.search(r'^@@ -[0-9,]+ \+(\d+)(,(\d+))?', line)
if match: if match:
start_line = int(match.group(1)) start_line = int(match.group(1))
line_count = 1 line_count = 1
if match.group(3): if match.group(3):
line_count = int(match.group(3)) line_count = int(match.group(3))
if line_count > 0: if line_count == 0:
line_count = 1
if start_line == 0:
continue
matches.setdefault(filename, []).append(Range(start_line, line_count)) matches.setdefault(filename, []).append(Range(start_line, line_count))
return matches return matches
@ -330,6 +392,13 @@ def filter_by_extension(dictionary, allowed_extensions):
del dictionary[filename] del dictionary[filename]
def filter_symlinks(dictionary):
"""Delete every key in `dictionary` that is a symlink."""
for filename in list(dictionary.keys()):
if os.path.islink(filename):
del dictionary[filename]
def cd_to_toplevel(): def cd_to_toplevel():
"""Change to the top level of the git repository.""" """Change to the top level of the git repository."""
toplevel = run('git', 'rev-parse', '--show-toplevel') toplevel = run('git', 'rev-parse', '--show-toplevel')
@ -343,11 +412,29 @@ def create_tree_from_workdir(filenames):
return create_tree(filenames, '--stdin') return create_tree(filenames, '--stdin')
def create_tree_from_index(filenames):
# Copy the environment, because the files have to be read from the original
# index.
env = os.environ.copy()
def index_contents_generator():
for filename in filenames:
git_ls_files_cmd = ['git', 'ls-files', '--stage', '-z', '--', filename]
git_ls_files = subprocess.Popen(git_ls_files_cmd, env=env,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
stdout = git_ls_files.communicate()[0]
yield convert_string(stdout.split(b'\0')[0])
return create_tree(index_contents_generator(), '--index-info')
def run_clang_format_and_save_to_tree(changed_lines, revision=None, def run_clang_format_and_save_to_tree(changed_lines, revision=None,
binary='clang-format', style=None): binary='clang-format', style=None):
"""Run clang-format on each file and save the result to a git tree. """Run clang-format on each file and save the result to a git tree.
Returns the object ID (SHA-1) of the created tree.""" Returns the object ID (SHA-1) of the created tree."""
# Copy the environment when formatting the files in the index, because the
# files have to be read from the original index.
env = os.environ.copy() if revision == '' else None
def iteritems(container): def iteritems(container):
try: try:
return container.iteritems() # Python 2 return container.iteritems() # Python 2
@ -355,11 +442,15 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None,
return container.items() # Python 3 return container.items() # Python 3
def index_info_generator(): def index_info_generator():
for filename, line_ranges in iteritems(changed_lines): for filename, line_ranges in iteritems(changed_lines):
if revision: if revision is not None:
if len(revision) > 0:
git_metadata_cmd = ['git', 'ls-tree', git_metadata_cmd = ['git', 'ls-tree',
'%s:%s' % (revision, os.path.dirname(filename)), '%s:%s' % (revision, os.path.dirname(filename)),
os.path.basename(filename)] os.path.basename(filename)]
git_metadata = subprocess.Popen(git_metadata_cmd, stdin=subprocess.PIPE, else:
git_metadata_cmd = ['git', 'ls-files', '--stage', '--', filename]
git_metadata = subprocess.Popen(git_metadata_cmd, env=env,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE) stdout=subprocess.PIPE)
stdout = git_metadata.communicate()[0] stdout = git_metadata.communicate()[0]
mode = oct(int(stdout.split()[0], 8)) mode = oct(int(stdout.split()[0], 8))
@ -371,7 +462,8 @@ def run_clang_format_and_save_to_tree(changed_lines, revision=None,
blob_id = clang_format_to_blob(filename, line_ranges, blob_id = clang_format_to_blob(filename, line_ranges,
revision=revision, revision=revision,
binary=binary, binary=binary,
style=style) style=style,
env=env)
yield '%s %s\t%s' % (mode, blob_id, filename) yield '%s %s\t%s' % (mode, blob_id, filename)
return create_tree(index_info_generator(), '--index-info') return create_tree(index_info_generator(), '--index-info')
@ -397,11 +489,12 @@ def create_tree(input_lines, mode):
def clang_format_to_blob(filename, line_ranges, revision=None, def clang_format_to_blob(filename, line_ranges, revision=None,
binary='clang-format', style=None): binary='clang-format', style=None, env=None):
"""Run clang-format on the given file and save the result to a git blob. """Run clang-format on the given file and save the result to a git blob.
Runs on the file in `revision` if not None, or on the file in the working Runs on the file in `revision` if not None, or on the file in the working
directory if `revision` is None. directory if `revision` is None. Revision can be set to an empty string to run
clang-format on the file in the index.
Returns the object ID (SHA-1) of the created blob.""" Returns the object ID (SHA-1) of the created blob."""
clang_format_cmd = [binary] clang_format_cmd = [binary]
@ -410,10 +503,10 @@ def clang_format_to_blob(filename, line_ranges, revision=None,
clang_format_cmd.extend([ clang_format_cmd.extend([
'-lines=%s:%s' % (start_line, start_line+line_count-1) '-lines=%s:%s' % (start_line, start_line+line_count-1)
for start_line, line_count in line_ranges]) for start_line, line_count in line_ranges])
if revision: if revision is not None:
clang_format_cmd.extend(['-assume-filename='+filename]) clang_format_cmd.extend(['-assume-filename='+filename])
git_show_cmd = ['git', 'cat-file', 'blob', '%s:%s' % (revision, filename)] git_show_cmd = ['git', 'cat-file', 'blob', '%s:%s' % (revision, filename)]
git_show = subprocess.Popen(git_show_cmd, stdin=subprocess.PIPE, git_show = subprocess.Popen(git_show_cmd, env=env, stdin=subprocess.PIPE,
stdout=subprocess.PIPE) stdout=subprocess.PIPE)
git_show.stdin.close() git_show.stdin.close()
clang_format_stdin = git_show.stdout clang_format_stdin = git_show.stdout
@ -485,9 +578,20 @@ def print_diff(old_tree, new_tree):
# We also only print modified files since `new_tree` only contains the files # We also only print modified files since `new_tree` only contains the files
# that were modified, so unmodified files would show as deleted without the # that were modified, so unmodified files would show as deleted without the
# filter. # filter.
subprocess.check_call(['git', 'diff', '--diff-filter=M', old_tree, new_tree, return subprocess.run(['git', 'diff', '--diff-filter=M',
'--']) '--exit-code', old_tree, new_tree]).returncode
def print_diffstat(old_tree, new_tree):
"""Print the diffstat between the two trees to stdout."""
# We use the porcelain 'diff' and not plumbing 'diff-tree' because the output
# is expected to be viewed by the user, and only the former does nice things
# like color and pagination.
#
# We also only print modified files since `new_tree` only contains the files
# that were modified, so unmodified files would show as deleted without the
# filter.
return subprocess.run(['git', 'diff', '--diff-filter=M', '--exit-code',
'--stat', old_tree, new_tree]).returncode
def apply_changes(old_tree, new_tree, force=False, patch_mode=False): def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
"""Apply the changes in `new_tree` to the working directory. """Apply the changes in `new_tree` to the working directory.
@ -513,16 +617,16 @@ def apply_changes(old_tree, new_tree, force=False, patch_mode=False):
# better message, "Apply ... to index and worktree". This is not quite # better message, "Apply ... to index and worktree". This is not quite
# right, since it won't be applied to the user's index, but oh well. # right, since it won't be applied to the user's index, but oh well.
with temporary_index_file(old_tree): with temporary_index_file(old_tree):
subprocess.check_call(['git', 'checkout', '--patch', new_tree]) subprocess.run(['git', 'checkout', '--patch', new_tree], check=True)
index_tree = old_tree index_tree = old_tree
else: else:
with temporary_index_file(new_tree): with temporary_index_file(new_tree):
run('git', 'checkout-index', '-a', '-f') run('git', 'checkout-index', '-f', '--', *changed_files)
return changed_files return changed_files
def run(*args, **kwargs): def run(*args, **kwargs):
stdin = kwargs.pop('stdin', to_bytes('')) stdin = kwargs.pop('stdin', '')
verbose = kwargs.pop('verbose', True) verbose = kwargs.pop('verbose', True)
strip = kwargs.pop('strip', True) strip = kwargs.pop('strip', True)
for name in kwargs: for name in kwargs:
@ -576,4 +680,4 @@ def convert_string(bytes_input):
return str(bytes_input) return str(bytes_input)
if __name__ == '__main__': if __name__ == '__main__':
main() sys.exit(main())