nasty commit with a bunch of test code left in, will clean up and pr
Remove the logger_ != nullptr check from shouldlog, it will nearly always be true except on initialization and gets checked later anyway, this shrinks the size of the generated code for some Select specialized vastcpy for current cpu, for now only have paths for MOVDIR64B and generic avx1 Add XE_UNLIKELY/LIKELY if, they map better to the c++ unlikely/likely attributes which we will need to use soon Finished reimplementing STVL/STVR/LVL/LVR as their own opcodes. we now generate far less code for these instructions. this also means optimization passes can be written to simplify/remove/replace these instructions in some cases. Found that a good deal of the X86 we were emitting for these instructions was dead code or redundant. the reduction in generated HIR/x86 should help a lot with compilation times and make function precompilation more feasible as a default Don't static assert in default prefetch impl, in c++20 the assertion will be triggered even without an instantiation Reorder some if/else to prod msvc into ordering the branches optimally. it somewhat worked... Added some notes about which opcodes should be removed/refactored Dispatch in WriteRegister via vector compares for the bounds. still not very optimal, we ought to be checking whether any register in a range may be special A lot of work on trying to optimize writeregister, moved wraparound path into a noinline function based on profiling info Hoist the IsUcodeAnalyzed check out of AnalyzeShader, instead check it before each call. Profiler recorded many hits in the stack frame setup of the function, but none in the actual body of it, so the check is often true but the stack frame setup is run unconditionally Pre-check whether we're about to write a single register from a ring Replace more jump tables from draw_util/texture_info with popcnt based sparse indexing/bit tables/shuffle lookups Place the GPU register file on its own VAD/virtual allocation, it is no longer a member of graphics system
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
#include "dma.h"
|
||||
#include "logging.h"
|
||||
#include "xbyak/xbyak/xbyak_util.h"
|
||||
|
||||
template <size_t N, typename... Ts>
|
||||
static void xedmaloghelper(const char (&fmt)[N], Ts... args) {
|
||||
@@ -14,8 +16,8 @@ using xe::swcache::CacheLine;
|
||||
static constexpr unsigned NUM_CACHELINES_IN_PAGE = 4096 / sizeof(CacheLine);
|
||||
|
||||
XE_FORCEINLINE
|
||||
static void XeCopy16384Streaming(CacheLine* XE_RESTRICT to,
|
||||
CacheLine* XE_RESTRICT from) {
|
||||
static void XeCopy16384StreamingAVX(CacheLine* XE_RESTRICT to,
|
||||
CacheLine* XE_RESTRICT from) {
|
||||
uint32_t num_lines_for_8k = 4096 / XE_HOST_CACHE_LINE_SIZE;
|
||||
|
||||
CacheLine* dest1 = to;
|
||||
@@ -46,16 +48,58 @@ static void XeCopy16384Streaming(CacheLine* XE_RESTRICT to,
|
||||
}
|
||||
XE_MSVC_REORDER_BARRIER();
|
||||
}
|
||||
XE_FORCEINLINE
|
||||
static void XeCopy16384Movdir64M(CacheLine* XE_RESTRICT to,
|
||||
CacheLine* XE_RESTRICT from) {
|
||||
uint32_t num_lines_for_8k = 4096 / XE_HOST_CACHE_LINE_SIZE;
|
||||
|
||||
CacheLine* dest1 = to;
|
||||
CacheLine* src1 = from;
|
||||
|
||||
CacheLine* dest2 = to + NUM_CACHELINES_IN_PAGE;
|
||||
CacheLine* src2 = from + NUM_CACHELINES_IN_PAGE;
|
||||
|
||||
CacheLine* dest3 = to + (NUM_CACHELINES_IN_PAGE * 2);
|
||||
CacheLine* src3 = from + (NUM_CACHELINES_IN_PAGE * 2);
|
||||
|
||||
CacheLine* dest4 = to + (NUM_CACHELINES_IN_PAGE * 3);
|
||||
CacheLine* src4 = from + (NUM_CACHELINES_IN_PAGE * 3);
|
||||
#pragma loop(no_vector)
|
||||
for (uint32_t i = 0; i < num_lines_for_8k; ++i) {
|
||||
#if 0
|
||||
xe::swcache::CacheLine line0, line1, line2, line3;
|
||||
|
||||
xe::swcache::ReadLine(&line0, src1 + i);
|
||||
xe::swcache::ReadLine(&line1, src2 + i);
|
||||
xe::swcache::ReadLine(&line2, src3 + i);
|
||||
xe::swcache::ReadLine(&line3, src4 + i);
|
||||
XE_MSVC_REORDER_BARRIER();
|
||||
xe::swcache::WriteLineNT(dest1 + i, &line0);
|
||||
xe::swcache::WriteLineNT(dest2 + i, &line1);
|
||||
|
||||
xe::swcache::WriteLineNT(dest3 + i, &line2);
|
||||
xe::swcache::WriteLineNT(dest4 + i, &line3);
|
||||
#else
|
||||
_movdir64b(dest1 + i, src1 + i);
|
||||
_movdir64b(dest2 + i, src2 + i);
|
||||
_movdir64b(dest3 + i, src3 + i);
|
||||
_movdir64b(dest4 + i, src4 + i);
|
||||
#endif
|
||||
}
|
||||
XE_MSVC_REORDER_BARRIER();
|
||||
}
|
||||
|
||||
namespace xe::dma {
|
||||
XE_FORCEINLINE
|
||||
static void vastcpy_impl(CacheLine* XE_RESTRICT physaddr,
|
||||
CacheLine* XE_RESTRICT rdmapping,
|
||||
uint32_t written_length) {
|
||||
using VastCpyDispatch = void (*)(CacheLine* XE_RESTRICT physaddr,
|
||||
CacheLine* XE_RESTRICT rdmapping,
|
||||
uint32_t written_length);
|
||||
static void vastcpy_impl_avx(CacheLine* XE_RESTRICT physaddr,
|
||||
CacheLine* XE_RESTRICT rdmapping,
|
||||
uint32_t written_length) {
|
||||
static constexpr unsigned NUM_LINES_FOR_16K = 16384 / XE_HOST_CACHE_LINE_SIZE;
|
||||
|
||||
while (written_length >= 16384) {
|
||||
XeCopy16384Streaming(physaddr, rdmapping);
|
||||
XeCopy16384StreamingAVX(physaddr, rdmapping);
|
||||
|
||||
physaddr += NUM_LINES_FOR_16K;
|
||||
rdmapping += NUM_LINES_FOR_16K;
|
||||
@@ -88,12 +132,85 @@ static void vastcpy_impl(CacheLine* XE_RESTRICT physaddr,
|
||||
xe::swcache::WriteLineNT(physaddr + i, &line0);
|
||||
}
|
||||
}
|
||||
static void vastcpy_impl_movdir64m(CacheLine* XE_RESTRICT physaddr,
|
||||
CacheLine* XE_RESTRICT rdmapping,
|
||||
uint32_t written_length) {
|
||||
static constexpr unsigned NUM_LINES_FOR_16K = 16384 / XE_HOST_CACHE_LINE_SIZE;
|
||||
|
||||
while (written_length >= 16384) {
|
||||
XeCopy16384Movdir64M(physaddr, rdmapping);
|
||||
|
||||
physaddr += NUM_LINES_FOR_16K;
|
||||
rdmapping += NUM_LINES_FOR_16K;
|
||||
|
||||
written_length -= 16384;
|
||||
}
|
||||
|
||||
if (!written_length) {
|
||||
return;
|
||||
}
|
||||
uint32_t num_written_lines = written_length / XE_HOST_CACHE_LINE_SIZE;
|
||||
|
||||
uint32_t i = 0;
|
||||
|
||||
for (; i + 1 < num_written_lines; i += 2) {
|
||||
_movdir64b(physaddr + i, rdmapping + i);
|
||||
_movdir64b(physaddr + i + 1, rdmapping + i + 1);
|
||||
}
|
||||
|
||||
if (i < num_written_lines) {
|
||||
_movdir64b(physaddr + i, rdmapping + i);
|
||||
}
|
||||
}
|
||||
|
||||
static class DMAFeatures {
|
||||
public:
|
||||
uint32_t has_fast_rep_movsb : 1;
|
||||
uint32_t has_movdir64b : 1;
|
||||
|
||||
DMAFeatures() {
|
||||
unsigned int data[4];
|
||||
memset(data, 0, sizeof(data));
|
||||
// intel extended features
|
||||
Xbyak::util::Cpu::getCpuidEx(7, 0, data);
|
||||
if (data[2] & (1 << 28)) {
|
||||
has_movdir64b = 1;
|
||||
}
|
||||
if (data[1] & (1 << 9)) {
|
||||
has_fast_rep_movsb = 1;
|
||||
}
|
||||
}
|
||||
} dma_x86_features;
|
||||
XE_COLD
|
||||
static void first_vastcpy(CacheLine* XE_RESTRICT physaddr,
|
||||
CacheLine* XE_RESTRICT rdmapping,
|
||||
uint32_t written_length);
|
||||
|
||||
static VastCpyDispatch vastcpy_dispatch = first_vastcpy;
|
||||
|
||||
XE_COLD
|
||||
static void first_vastcpy(CacheLine* XE_RESTRICT physaddr,
|
||||
CacheLine* XE_RESTRICT rdmapping,
|
||||
uint32_t written_length) {
|
||||
VastCpyDispatch dispatch_to_use = nullptr;
|
||||
if (dma_x86_features.has_movdir64b) {
|
||||
XELOGI("Selecting MOVDIR64M vastcpy.");
|
||||
dispatch_to_use = vastcpy_impl_movdir64m;
|
||||
} else {
|
||||
XELOGI("Selecting generic AVX vastcpy.");
|
||||
dispatch_to_use = vastcpy_impl_avx;
|
||||
}
|
||||
|
||||
vastcpy_dispatch =
|
||||
dispatch_to_use; // all future calls will go through our selected path
|
||||
return vastcpy_dispatch(physaddr, rdmapping, written_length);
|
||||
}
|
||||
|
||||
XE_NOINLINE
|
||||
void vastcpy(uint8_t* XE_RESTRICT physaddr, uint8_t* XE_RESTRICT rdmapping,
|
||||
uint32_t written_length) {
|
||||
return vastcpy_impl((CacheLine*)physaddr, (CacheLine*)rdmapping,
|
||||
written_length);
|
||||
return vastcpy_dispatch((CacheLine*)physaddr, (CacheLine*)rdmapping,
|
||||
written_length);
|
||||
}
|
||||
|
||||
#define XEDMA_NUM_WORKERS 4
|
||||
|
||||
@@ -466,8 +466,7 @@ void ShutdownLogging() {
|
||||
}
|
||||
|
||||
bool logging::internal::ShouldLog(LogLevel log_level) {
|
||||
return logger_ != nullptr &&
|
||||
static_cast<int32_t>(log_level) <= cvars::log_level;
|
||||
return static_cast<int32_t>(log_level) <= cvars::log_level;
|
||||
}
|
||||
|
||||
std::pair<char*, size_t> logging::internal::GetThreadBuffer() {
|
||||
@@ -476,7 +475,7 @@ std::pair<char*, size_t> logging::internal::GetThreadBuffer() {
|
||||
|
||||
void logging::internal::AppendLogLine(LogLevel log_level,
|
||||
const char prefix_char, size_t written) {
|
||||
if (!ShouldLog(log_level) || !written) {
|
||||
if (!logger_ || !ShouldLog(log_level) || !written) {
|
||||
return;
|
||||
}
|
||||
logger_->AppendLine(xe::threading::current_thread_id(), prefix_char,
|
||||
|
||||
@@ -612,7 +612,7 @@ enum class PrefetchTag { Write, Nontemporal, Level3, Level2, Level1 };
|
||||
|
||||
template <PrefetchTag tag>
|
||||
static void Prefetch(const void* addr) {
|
||||
static_assert(false, "Unknown tag");
|
||||
xenia_assert(false && "Unknown tag");
|
||||
}
|
||||
|
||||
template <>
|
||||
|
||||
@@ -127,8 +127,22 @@
|
||||
#define XE_FORCEINLINE inline
|
||||
#define XE_NOINLINE
|
||||
#define XE_COLD
|
||||
#define XE_LIKELY(...) (!!(__VA_ARGS__))
|
||||
#define XE_UNLIKELY(...) (!!(__VA_ARGS__))
|
||||
|
||||
#define XE_LIKELY_IF(...) if (!!(__VA_ARGS__)) [[likely]]
|
||||
#define XE_UNLIKELY_IF(...) if (!!(__VA_ARGS__)) [[unlikely]]
|
||||
#endif
|
||||
|
||||
#if XE_COMPILER_HAS_GNU_EXTENSIONS == 1
|
||||
#define XE_LIKELY_IF(...) if (XE_LIKELY(__VA_ARGS__))
|
||||
#define XE_UNLIKELY_IF(...) if (XE_UNLIKELY(__VA_ARGS__))
|
||||
#else
|
||||
#if __cplusplus >= 202002
|
||||
#define XE_LIKELY_IF(...) if (!!(__VA_ARGS__)) [[likely]]
|
||||
#define XE_UNLIKELY_IF(...) if (!!(__VA_ARGS__)) [[unlikely]]
|
||||
#else
|
||||
#define XE_LIKELY_IF(...) if (!!(__VA_ARGS__))
|
||||
#define XE_UNLIKELY_IF(...) if (!!(__VA_ARGS__))
|
||||
#endif
|
||||
#endif
|
||||
// only use __restrict if MSVC, for clang/gcc we can use -fstrict-aliasing which
|
||||
// acts as __restrict across the board todo: __restrict is part of the type
|
||||
|
||||
@@ -45,15 +45,17 @@ void RingBuffer::AdvanceWrite(size_t _count) {
|
||||
RingBuffer::ReadRange RingBuffer::BeginRead(size_t _count) {
|
||||
ring_size_t count =
|
||||
std::min<ring_size_t>(static_cast<ring_size_t>(_count), capacity_);
|
||||
if (!count) {
|
||||
return {0};
|
||||
XE_LIKELY_IF(count) {
|
||||
if (read_offset_ + count < capacity_) {
|
||||
return {buffer_ + read_offset_, nullptr, count, 0};
|
||||
} else {
|
||||
ring_size_t left_half = capacity_ - read_offset_;
|
||||
ring_size_t right_half = count - left_half;
|
||||
return {buffer_ + read_offset_, buffer_, left_half, right_half};
|
||||
}
|
||||
}
|
||||
if (read_offset_ + count < capacity_) {
|
||||
return {buffer_ + read_offset_, nullptr, count, 0};
|
||||
} else {
|
||||
ring_size_t left_half = capacity_ - read_offset_;
|
||||
ring_size_t right_half = count - left_half;
|
||||
return {buffer_ + read_offset_, buffer_, left_half, right_half};
|
||||
else {
|
||||
return {0};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user