fixed wine crash from use of NtSetEventPriorityBoost

add xe::clear_lowest_bit, use it in place of shift-andnot in some bit iteration code
make is_allocated_ and is_enabled_ volatile in xma_context
preallocate avpacket buffer in XMAContext::Setup, the reallocations of the buffer in ffmpeg were showing up on profiles
check is_enabled and is_allocated BEFORE locking an xmacontext. XMA worker was spending most of its time locking and unlocking contexts
Removed XeDMAC, dma:: namespace. It was a bad idea and I couldn't make it work in the end. Kept vastcpy and moved it to the memory namespace instead
Made the rest of global_critical_region's members static. They never needed an instance.
Removed ifdef'ed out code from ring_buffer.h
Added EventInfo struct to threading, added Event::Query to aid with implementing NtQueryEvent.
Removed vector from WaitMultiple, instead use a fixed array of 64 handles that we populate. WaitForMultipleObjects cannot handle more than 64 objects.
Remove XE_MSVC_OPTIMIZE_SMALL() use in x64_sequences, x64 backend is now always size optimized because of premake
Make global_critical_region_ static constexpr in shared_memory.h to get rid of wasteage of 8 bytes (empty class=1byte, +alignment for next member=8)
Move trace-related data to the tail of SharedMemory to keep more important data together
In IssueDraw build an array of fetch constant addresses/sizes, then pre-lock the global lock before doing requestrange for each instead of individually locking within requestrange for each of them
Consistent access specifier protected for pm4_command_processor_declare
Devirtualize WriteOneRegisterFromRing.
Move ExecutePacket and ExecutePrimaryBuffer to pm4_command_buffer_x
Remove many redundant header inclusions access xenia-gpu
Minor microoptimization of ExecutePacketType0

Add TextureCache::RequestTextures for batch invocation of LoadTexturesData

Add TextureCache::LoadTexturesData for reducing the number of times we release and reacquire the global lock.
Ideally you should hold the global lock for as little time as possible, but if you are constantly acquiring and releasing it you are actually more likely to have contention
Add already_locked param to ObjectTable::LookupObject to help with reducing lock acquire/release pairs
Add missing checks to XAudioRegisterRenderDriverClient_entry. this is unlikely to fix anything, it was just an easy thing to do
Add NtQueryEvent system call implementation. I don't actually know of any games that need it.
Instead of using std::vector + push_back in KeWaitForMultipleObjects and xeNtWaitForMultipleObjectsEx use a fixed size array of 64 and track the count. More than 64 objects is not permitted by the kernel. The repeated reallocations from push_back were appearing unusually high on the profiler, but were masked until now by waitformultipleobjects natural overhead
Pre-lock the global lock before looking up each handle for xeNtWaitForMultipleObjectsEx and KeWaitForMultipleObjects.
Pre-lock before looking up the signal and waiter in NtSignalAndWaitForSingleObjectEx
add missing checks to NtWaitForMultipleObjectsEx
Support pre-locking in XObject::GetNativeObject
This commit is contained in:
chss95cs@gmail.com
2022-10-08 09:55:17 -07:00
parent bae63b95c5
commit 8f7f7dc6ad
50 changed files with 722 additions and 788 deletions

View File

@@ -2672,45 +2672,66 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
// validity is tracked.
const Shader::ConstantRegisterMap& constant_map_vertex =
vertex_shader->constant_register_map();
for (uint32_t i = 0; i < xe::countof(constant_map_vertex.vertex_fetch_bitmap);
++i) {
uint32_t vfetch_bits_remaining = constant_map_vertex.vertex_fetch_bitmap[i];
uint32_t j;
while (xe::bit_scan_forward(vfetch_bits_remaining, &j)) {
vfetch_bits_remaining &= ~(uint32_t(1) << j);
uint32_t vfetch_index = i * 32 + j;
const auto& vfetch_constant = regs.Get<xenos::xe_gpu_vertex_fetch_t>(
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + vfetch_index * 2);
switch (vfetch_constant.type) {
case xenos::FetchConstantType::kVertex:
break;
case xenos::FetchConstantType::kInvalidVertex:
if (cvars::gpu_allow_invalid_fetch_constants) {
{
uint32_t vfetch_addresses[96];
uint32_t vfetch_sizes[96];
uint32_t vfetch_current_queued = 0;
for (uint32_t i = 0;
i < xe::countof(constant_map_vertex.vertex_fetch_bitmap); ++i) {
uint32_t vfetch_bits_remaining =
constant_map_vertex.vertex_fetch_bitmap[i];
uint32_t j;
while (xe::bit_scan_forward(vfetch_bits_remaining, &j)) {
vfetch_bits_remaining = xe::clear_lowest_bit(vfetch_bits_remaining);
uint32_t vfetch_index = i * 32 + j;
const auto& vfetch_constant = regs.Get<xenos::xe_gpu_vertex_fetch_t>(
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + vfetch_index * 2);
switch (vfetch_constant.type) {
case xenos::FetchConstantType::kVertex:
break;
}
XELOGW(
"Vertex fetch constant {} ({:08X} {:08X}) has \"invalid\" type! "
"This is incorrect behavior, but you can try bypassing this by "
"launching Xenia with --gpu_allow_invalid_fetch_constants=true.",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1);
return false;
default:
XELOGW(
"Vertex fetch constant {} ({:08X} {:08X}) is completely invalid!",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1);
return false;
case xenos::FetchConstantType::kInvalidVertex:
if (cvars::gpu_allow_invalid_fetch_constants) {
break;
}
XELOGW(
"Vertex fetch constant {} ({:08X} {:08X}) has \"invalid\" "
"type! "
"This is incorrect behavior, but you can try bypassing this by "
"launching Xenia with "
"--gpu_allow_invalid_fetch_constants=true.",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1);
return false;
default:
XELOGW(
"Vertex fetch constant {} ({:08X} {:08X}) is completely "
"invalid!",
vfetch_index, vfetch_constant.dword_0, vfetch_constant.dword_1);
return false;
}
vfetch_addresses[vfetch_current_queued] = vfetch_constant.address;
vfetch_sizes[vfetch_current_queued++] = vfetch_constant.size;
}
if (!shared_memory_->RequestRange(vfetch_constant.address << 2,
vfetch_constant.size << 2)) {
XELOGE(
"Failed to request vertex buffer at 0x{:08X} (size {}) in the "
"shared memory",
vfetch_constant.address << 2, vfetch_constant.size << 2);
return false;
}
if (vfetch_current_queued) {
// so far, i have never seen vfetch_current_queued > 4. 1 is most common, 2 happens occasionally. did not test many games though
// pre-acquire the critical region so we're not repeatedly re-acquiring it
// in requestrange
auto shared_memory_request_range_hoisted =
global_critical_region::Acquire();
for (uint32_t i = 0; i < vfetch_current_queued; ++i) {
if (!shared_memory_->RequestRange(vfetch_addresses[i] << 2,
vfetch_sizes[i] << 2)) {
XELOGE(
"Failed to request vertex buffer at 0x{:08X} (size {}) in the "
"shared memory",
vfetch_addresses[i] << 2, vfetch_sizes[i] << 2);
return false;
}
}
}
}
// Gather memexport ranges and ensure the heaps for them are resident, and
// also load the data surrounding the export and to fill the regions that
// won't be modified by the shaders.
@@ -3076,24 +3097,6 @@ void D3D12CommandProcessor::InitializeTrace() {
shared_memory_->InitializeTraceCompleteDownloads();
}
}
static void DmaPrefunc(dma::XeDMAJob* job) {
D3D12_RANGE readback_range;
readback_range.Begin = 0;
readback_range.End = job->size;
void* readback_mapping;
ID3D12Resource* readback_buffer = (ID3D12Resource*)job->userdata1;
HRESULT mapres = readback_buffer->Map(0, &readback_range, &readback_mapping);
xenia_assert(SUCCEEDED(mapres));
job->source = (uint8_t*)readback_mapping;
}
static void DmaPostfunc(dma::XeDMAJob* job) {
D3D12_RANGE readback_write_range = {};
ID3D12Resource* readback_buffer = (ID3D12Resource*)job->userdata1;
readback_buffer->Unmap(0, &readback_write_range);
}
bool D3D12CommandProcessor::IssueCopy() {
#if XE_UI_D3D12_FINE_GRAINED_DRAW_SCOPES
@@ -3102,7 +3105,6 @@ bool D3D12CommandProcessor::IssueCopy() {
if (!BeginSubmission(true)) {
return false;
}
if (!cvars::d3d12_readback_resolve) {
uint32_t written_address, written_length;
return render_target_cache_->Resolve(*memory_, *shared_memory_,
@@ -3129,34 +3131,21 @@ bool D3D12CommandProcessor::IssueCopy_ReadbackResolvePath() {
readback_buffer, 0, shared_memory_buffer, written_address,
written_length);
if (AwaitAllQueueOperationsCompletion()) {
#if 1
D3D12_RANGE readback_range;
readback_range.Begin = 0;
readback_range.End = written_length;
void* readback_mapping;
if (SUCCEEDED(
readback_buffer->Map(0, &readback_range, &readback_mapping))) {
// chrispy: this memcpy needs to be optimized as much as possible
D3D12_RANGE readback_range;
readback_range.Begin = 0;
readback_range.End = written_length;
void* readback_mapping;
if (SUCCEEDED(readback_buffer->Map(0, &readback_range,
&readback_mapping))) {
// chrispy: this memcpy needs to be optimized as much as possible
auto physaddr = memory_->TranslatePhysical(written_address);
dma::vastcpy(physaddr, (uint8_t*)readback_mapping, written_length);
// XEDmaCpy(physaddr, readback_mapping, written_length);
D3D12_RANGE readback_write_range = {};
readback_buffer->Unmap(0, &readback_write_range);
}
#else
dma::XeDMAJob job{};
job.destination = memory_->TranslatePhysical(written_address);
job.size = written_length;
job.source = nullptr;
job.userdata1 = (void*)readback_buffer;
job.precall = DmaPrefunc;
job.postcall = DmaPostfunc;
readback_available_ = GetDMAC()->PushDMAJob(&job);
#endif
auto physaddr = memory_->TranslatePhysical(written_address);
memory::vastcpy(physaddr, (uint8_t*)readback_mapping,
written_length);
// XEDmaCpy(physaddr, readback_mapping, written_length);
D3D12_RANGE readback_write_range = {};
readback_buffer->Unmap(0, &readback_write_range);
}
}
}
}
@@ -3833,7 +3822,8 @@ XE_NOINLINE void D3D12CommandProcessor::UpdateSystemConstantValues_Impl(
uint32_t user_clip_plane_index;
while (xe::bit_scan_forward(user_clip_planes_remaining,
&user_clip_plane_index)) {
user_clip_planes_remaining &= ~(UINT32_C(1) << user_clip_plane_index);
user_clip_planes_remaining =
xe::clear_lowest_bit(user_clip_planes_remaining);
const float* user_clip_plane =
&regs[XE_GPU_REG_PA_CL_UCP_0_X + user_clip_plane_index * 4].f32;
if (std::memcmp(user_clip_plane_write_ptr, user_clip_plane,
@@ -3917,7 +3907,7 @@ XE_NOINLINE void D3D12CommandProcessor::UpdateSystemConstantValues_Impl(
uint32_t textures_remaining = used_texture_mask;
uint32_t texture_index;
while (xe::bit_scan_forward(textures_remaining, &texture_index)) {
textures_remaining &= ~(uint32_t(1) << texture_index);
textures_remaining = xe::clear_lowest_bit(textures_remaining);
uint32_t& texture_signs_uint =
system_constants_.texture_swizzled_signs[texture_index >> 2];
uint32_t texture_signs_shift = (texture_index & 3) * 8;
@@ -5116,12 +5106,6 @@ ID3D12Resource* D3D12CommandProcessor::RequestReadbackBuffer(uint32_t size) {
if (size == 0) {
return nullptr;
}
#if 1
if (readback_available_) {
GetDMAC()->WaitJobDone(readback_available_);
readback_available_ = 0;
}
#endif
size = xe::align(size, kReadbackBufferSizeIncrement);
if (size > readback_buffer_size_) {
const ui::d3d12::D3D12Provider& provider = GetD3D12Provider();