Fixed a bug with readback_resolve and readback_memexport that was responsible for a large portion of their overhead. readback_memexport and resolve are now usable for games, depending on your hardware. in my case games that were slideshows now run at like 20-30 fps, and my hardware isnt the best for xenia.
add split_map class for mapping keys to values in a way that optimizes for frequent searches and infrequent insertions/removals remove jump table implementation of GetColorRenderTargetFormatComponentCount, it was appearing relatively high in profiles. instead pack the component counts into a single 32 bit word, which is indexed by shifting Add cvar to align all basic blocks to a boundary Add mmio aware load paths liberally apply XE_RESTRICT in ringbuffer related code Removed the IS_TRUE and IS_FALSE opcodes, they were pointless duplicates of COMPARE_EQ/COMPARE_NE and i want to simplify our set of opcodes for future backends More work on LVSR/LVSL/STVR/STVL opcodes Optimized X64 translated code emission, now only compute instrkey once Add code for pre-computing integer division magic numbers Optimized GetHostViewportInfo a little Move args for GetHostViewportInfo into a class, cache the result and compare for future queries. moved GetHostViewportInfo far lower on the profile Add (currently not functional, and very racy) asynchronous memcpy code. will improve it and actually use it in future commits. Add non-temporal memcpy function for huge page-aligned allocations. Used for copying to shared memory/readback hoist are_accumulated_render_targets_valid_ check out of loop in render_target_cache already bound check. Add stosb/movsb code for small constant memcpys/memsets that arent worth the overhead of memcpy/memset
This commit is contained in:
@@ -672,25 +672,58 @@ static void Prefetch<PrefetchTag::Level1>(const void* addr) {
|
||||
#define XE_MSVC_REORDER_BARRIER() static_cast<void>(0)
|
||||
#endif
|
||||
#if XE_ARCH_AMD64 == 1
|
||||
|
||||
union alignas(XE_HOST_CACHE_LINE_SIZE) CacheLine {
|
||||
struct {
|
||||
__m256 low32;
|
||||
__m256 high32;
|
||||
};
|
||||
struct {
|
||||
__m128i xmms[4];
|
||||
};
|
||||
float floats[XE_HOST_CACHE_LINE_SIZE / sizeof(float)];
|
||||
};
|
||||
XE_FORCEINLINE
|
||||
static void WriteLineNT(void* destination, const void* source) {
|
||||
assert((reinterpret_cast<uintptr_t>(destination) & 63ULL) == 0);
|
||||
__m256i low = _mm256_loadu_si256((const __m256i*)source);
|
||||
__m256i high = _mm256_loadu_si256(&((const __m256i*)source)[1]);
|
||||
XE_MSVC_REORDER_BARRIER();
|
||||
_mm256_stream_si256((__m256i*)destination, low);
|
||||
_mm256_stream_si256(&((__m256i*)destination)[1], high);
|
||||
static void WriteLineNT(CacheLine* XE_RESTRICT destination,
|
||||
const CacheLine* XE_RESTRICT source) {
|
||||
assert_true((reinterpret_cast<uintptr_t>(destination) & 63ULL) == 0);
|
||||
__m256 low = _mm256_loadu_ps(&source->floats[0]);
|
||||
__m256 high = _mm256_loadu_ps(&source->floats[8]);
|
||||
_mm256_stream_ps(&destination->floats[0], low);
|
||||
_mm256_stream_ps(&destination->floats[8], high);
|
||||
}
|
||||
|
||||
XE_FORCEINLINE
|
||||
static void ReadLineNT(void* destination, const void* source) {
|
||||
assert((reinterpret_cast<uintptr_t>(source) & 63ULL) == 0);
|
||||
__m256i low = _mm256_stream_load_si256((const __m256i*)source);
|
||||
__m256i high = _mm256_stream_load_si256(&((const __m256i*)source)[1]);
|
||||
XE_MSVC_REORDER_BARRIER();
|
||||
_mm256_storeu_si256((__m256i*)destination, low);
|
||||
_mm256_storeu_si256(&((__m256i*)destination)[1], high);
|
||||
static void ReadLineNT(CacheLine* XE_RESTRICT destination,
|
||||
const CacheLine* XE_RESTRICT source) {
|
||||
assert_true((reinterpret_cast<uintptr_t>(source) & 63ULL) == 0);
|
||||
|
||||
__m128i first = _mm_stream_load_si128(&source->xmms[0]);
|
||||
__m128i second = _mm_stream_load_si128(&source->xmms[1]);
|
||||
__m128i third = _mm_stream_load_si128(&source->xmms[2]);
|
||||
__m128i fourth = _mm_stream_load_si128(&source->xmms[3]);
|
||||
|
||||
destination->xmms[0] = first;
|
||||
destination->xmms[1] = second;
|
||||
destination->xmms[2] = third;
|
||||
destination->xmms[3] = fourth;
|
||||
}
|
||||
XE_FORCEINLINE
|
||||
static void ReadLine(CacheLine* XE_RESTRICT destination,
|
||||
const CacheLine* XE_RESTRICT source) {
|
||||
assert_true((reinterpret_cast<uintptr_t>(source) & 63ULL) == 0);
|
||||
__m256 low = _mm256_loadu_ps(&source->floats[0]);
|
||||
__m256 high = _mm256_loadu_ps(&source->floats[8]);
|
||||
_mm256_storeu_ps(&destination->floats[0], low);
|
||||
_mm256_storeu_ps(&destination->floats[8], high);
|
||||
}
|
||||
XE_FORCEINLINE
|
||||
static void WriteLine(CacheLine* XE_RESTRICT destination,
|
||||
const CacheLine* XE_RESTRICT source) {
|
||||
assert_true((reinterpret_cast<uintptr_t>(destination) & 63ULL) == 0);
|
||||
__m256 low = _mm256_loadu_ps(&source->floats[0]);
|
||||
__m256 high = _mm256_loadu_ps(&source->floats[8]);
|
||||
_mm256_storeu_ps(&destination->floats[0], low);
|
||||
_mm256_storeu_ps(&destination->floats[8], high);
|
||||
}
|
||||
|
||||
XE_FORCEINLINE
|
||||
@@ -699,19 +732,29 @@ XE_FORCEINLINE
|
||||
static void ReadFence() { _mm_lfence(); }
|
||||
XE_FORCEINLINE
|
||||
static void ReadWriteFence() { _mm_mfence(); }
|
||||
|
||||
#else
|
||||
|
||||
union alignas(XE_HOST_CACHE_LINE_SIZE) CacheLine {
|
||||
uint8_t bvals[XE_HOST_CACHE_LINE_SIZE];
|
||||
};
|
||||
XE_FORCEINLINE
|
||||
static void WriteLineNT(void* destination, const void* source) {
|
||||
assert((reinterpret_cast<uintptr_t>(destination) & 63ULL) == 0);
|
||||
memcpy(destination, source, 64);
|
||||
static void WriteLineNT(CacheLine* destination, const CacheLine* source) {
|
||||
memcpy(destination, source, XE_HOST_CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
XE_FORCEINLINE
|
||||
static void ReadLineNT(void* destination, const void* source) {
|
||||
assert((reinterpret_cast<uintptr_t>(source) & 63ULL) == 0);
|
||||
memcpy(destination, source, 64);
|
||||
static void ReadLineNT(CacheLine* destination, const CacheLine* source) {
|
||||
memcpy(destination, source, XE_HOST_CACHE_LINE_SIZE);
|
||||
}
|
||||
XE_FORCEINLINE
|
||||
static void WriteLine(CacheLine* destination, const CacheLine* source) {
|
||||
memcpy(destination, source, XE_HOST_CACHE_LINE_SIZE);
|
||||
}
|
||||
XE_FORCEINLINE
|
||||
static void ReadLine(CacheLine* destination, const CacheLine* source) {
|
||||
memcpy(destination, source, XE_HOST_CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
XE_FORCEINLINE
|
||||
static void WriteFence() {}
|
||||
XE_FORCEINLINE
|
||||
@@ -720,6 +763,47 @@ XE_FORCEINLINE
|
||||
static void ReadWriteFence() {}
|
||||
#endif
|
||||
} // namespace swcache
|
||||
|
||||
template <unsigned Size>
|
||||
static void smallcpy_const(void* destination, const void* source) {
|
||||
#if XE_ARCH_AMD64 == 1 && XE_COMPILER_MSVC == 1
|
||||
if constexpr ((Size & 7) == 0) {
|
||||
__movsq((unsigned long long*)destination, (const unsigned long long*)source,
|
||||
Size / 8);
|
||||
} else if constexpr ((Size & 3) == 0) {
|
||||
__movsd((unsigned long*)destination, (const unsigned long*)source,
|
||||
Size / 4);
|
||||
// dont even bother with movsw, i think the operand size override prefix
|
||||
// slows it down
|
||||
} else {
|
||||
__movsb((unsigned char*)destination, (const unsigned char*)source, Size);
|
||||
}
|
||||
#else
|
||||
memcpy(destination, source, Size);
|
||||
#endif
|
||||
}
|
||||
template <unsigned Size>
|
||||
static void smallset_const(void* destination, unsigned char fill_value) {
|
||||
#if XE_ARCH_AMD64 == 1 && XE_COMPILER_MSVC == 1
|
||||
if constexpr ((Size & 7) == 0) {
|
||||
unsigned long long fill =
|
||||
static_cast<unsigned long long>(fill_value) * 0x0101010101010101ULL;
|
||||
|
||||
__stosq((unsigned long long*)destination, fill, Size / 8);
|
||||
} else if constexpr ((Size & 3) == 0) {
|
||||
static constexpr unsigned long fill =
|
||||
static_cast<unsigned long>(fill_value) * 0x01010101U;
|
||||
__stosd((unsigned long*)destination, fill, Size / 4);
|
||||
// dont even bother with movsw, i think the operand size override prefix
|
||||
// slows it down
|
||||
} else {
|
||||
__stosb((unsigned char*)destination, fill_value, Size);
|
||||
}
|
||||
#else
|
||||
memset(destination, fill_value, Size);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_MEMORY_H_
|
||||
|
||||
Reference in New Issue
Block a user