[D3D12] Only await submission fence in one place
This commit is contained in:
parent
0156d3ef26
commit
1014458783
|
@ -799,10 +799,9 @@ std::unique_ptr<xe::ui::RawImage> D3D12CommandProcessor::Capture() {
|
|||
deferred_command_list_->CopyTexture(location_dest, location_source);
|
||||
PushTransitionBarrier(swap_texture_, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
if (!EndSubmission(false)) {
|
||||
if (!AwaitAllQueueOperationsCompletion()) {
|
||||
return nullptr;
|
||||
}
|
||||
AwaitAllQueueOperationsCompletion();
|
||||
D3D12_RANGE readback_range;
|
||||
readback_range.Begin = swap_texture_copy_footprint_.Offset;
|
||||
readback_range.End = swap_texture_copy_size_;
|
||||
|
@ -862,7 +861,7 @@ bool D3D12CommandProcessor::SetupContext() {
|
|||
}
|
||||
if (FAILED(device->CreateFence(
|
||||
0, D3D12_FENCE_FLAG_NONE,
|
||||
IID_PPV_ARGS(&queue_operations_since_submission_signal_fence_)))) {
|
||||
IID_PPV_ARGS(&queue_operations_since_submission_fence_)))) {
|
||||
XELOGE(
|
||||
"Failed to create the fence for awaiting queue operations done since "
|
||||
"the latest submission");
|
||||
|
@ -1557,8 +1556,8 @@ void D3D12CommandProcessor::ShutdownContext() {
|
|||
// First release the fences since they may reference fence_completion_event_.
|
||||
|
||||
queue_operations_done_since_submission_signal_ = false;
|
||||
ui::d3d12::util::ReleaseAndNull(
|
||||
queue_operations_since_submission_signal_fence_);
|
||||
queue_operations_since_submission_fence_last_ = 0;
|
||||
ui::d3d12::util::ReleaseAndNull(queue_operations_since_submission_fence_);
|
||||
|
||||
ui::d3d12::util::ReleaseAndNull(submission_fence_);
|
||||
submission_open_ = false;
|
||||
|
@ -2286,24 +2285,25 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type,
|
|||
memexport_range.base_address_dwords << 2, memexport_range_size);
|
||||
readback_buffer_offset += memexport_range_size;
|
||||
}
|
||||
AwaitAllQueueOperationsCompletion();
|
||||
D3D12_RANGE readback_range;
|
||||
readback_range.Begin = 0;
|
||||
readback_range.End = memexport_total_size;
|
||||
void* readback_mapping;
|
||||
if (SUCCEEDED(readback_buffer->Map(0, &readback_range,
|
||||
&readback_mapping))) {
|
||||
const uint32_t* readback_dwords =
|
||||
reinterpret_cast<const uint32_t*>(readback_mapping);
|
||||
for (uint32_t i = 0; i < memexport_range_count; ++i) {
|
||||
const MemExportRange& memexport_range = memexport_ranges[i];
|
||||
std::memcpy(memory_->TranslatePhysical(
|
||||
memexport_range.base_address_dwords << 2),
|
||||
readback_dwords, memexport_range.size_dwords << 2);
|
||||
readback_dwords += memexport_range.size_dwords;
|
||||
if (AwaitAllQueueOperationsCompletion()) {
|
||||
D3D12_RANGE readback_range;
|
||||
readback_range.Begin = 0;
|
||||
readback_range.End = memexport_total_size;
|
||||
void* readback_mapping;
|
||||
if (SUCCEEDED(readback_buffer->Map(0, &readback_range,
|
||||
&readback_mapping))) {
|
||||
const uint32_t* readback_dwords =
|
||||
reinterpret_cast<const uint32_t*>(readback_mapping);
|
||||
for (uint32_t i = 0; i < memexport_range_count; ++i) {
|
||||
const MemExportRange& memexport_range = memexport_ranges[i];
|
||||
std::memcpy(memory_->TranslatePhysical(
|
||||
memexport_range.base_address_dwords << 2),
|
||||
readback_dwords, memexport_range.size_dwords << 2);
|
||||
readback_dwords += memexport_range.size_dwords;
|
||||
}
|
||||
D3D12_RANGE readback_write_range = {};
|
||||
readback_buffer->Unmap(0, &readback_write_range);
|
||||
}
|
||||
D3D12_RANGE readback_write_range = {};
|
||||
readback_buffer->Unmap(0, &readback_write_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2322,10 +2322,9 @@ void D3D12CommandProcessor::InitializeTrace() {
|
|||
if (!render_target_cache_submitted && !shared_memory_submitted) {
|
||||
return;
|
||||
}
|
||||
if (!EndSubmission(false)) {
|
||||
if (!AwaitAllQueueOperationsCompletion()) {
|
||||
return;
|
||||
}
|
||||
AwaitAllQueueOperationsCompletion();
|
||||
if (render_target_cache_submitted) {
|
||||
render_target_cache_->InitializeTraceCompleteDownloads();
|
||||
}
|
||||
|
@ -2357,8 +2356,7 @@ bool D3D12CommandProcessor::IssueCopy() {
|
|||
deferred_command_list_->D3DCopyBufferRegion(
|
||||
readback_buffer, 0, shared_memory_buffer, written_address,
|
||||
written_length);
|
||||
if (EndSubmission(false)) {
|
||||
AwaitAllQueueOperationsCompletion();
|
||||
if (AwaitAllQueueOperationsCompletion()) {
|
||||
D3D12_RANGE readback_range;
|
||||
readback_range.Begin = 0;
|
||||
readback_range.End = written_length;
|
||||
|
@ -2377,19 +2375,48 @@ bool D3D12CommandProcessor::IssueCopy() {
|
|||
}
|
||||
|
||||
void D3D12CommandProcessor::CheckSubmissionFence(uint64_t await_submission) {
|
||||
assert_true(await_submission <= submission_current_);
|
||||
if (await_submission == submission_current_) {
|
||||
assert_true(submission_open_);
|
||||
EndSubmission(false);
|
||||
if (await_submission >= submission_current_) {
|
||||
if (submission_open_) {
|
||||
EndSubmission(false);
|
||||
}
|
||||
// Ending an open submission should result in queue operations done directly
|
||||
// (like UpdateTileMappings) to be tracked within the scope of that
|
||||
// submission, but just in case of a failure, or queue operations being done
|
||||
// outside of a submission, await explicitly.
|
||||
if (queue_operations_done_since_submission_signal_) {
|
||||
UINT64 fence_value = ++queue_operations_since_submission_fence_last_;
|
||||
ID3D12CommandQueue* direct_queue =
|
||||
GetD3D12Context().GetD3D12Provider().GetDirectQueue();
|
||||
if (SUCCEEDED(
|
||||
direct_queue->Signal(queue_operations_since_submission_fence_,
|
||||
fence_value) &&
|
||||
SUCCEEDED(queue_operations_since_submission_fence_
|
||||
->SetEventOnCompletion(fence_value,
|
||||
fence_completion_event_)))) {
|
||||
WaitForSingleObject(fence_completion_event_, INFINITE);
|
||||
queue_operations_done_since_submission_signal_ = false;
|
||||
} else {
|
||||
XELOGE(
|
||||
"Failed to await an out-of-submission queue operation completion "
|
||||
"Direct3D 12 fence");
|
||||
}
|
||||
}
|
||||
// A submission won't be ended if it hasn't been started, or if ending
|
||||
// has failed - clamp the index.
|
||||
await_submission = submission_current_ - 1;
|
||||
}
|
||||
|
||||
uint64_t submission_completed_before = submission_completed_;
|
||||
submission_completed_ = submission_fence_->GetCompletedValue();
|
||||
if (submission_completed_ < await_submission) {
|
||||
submission_fence_->SetEventOnCompletion(await_submission,
|
||||
fence_completion_event_);
|
||||
WaitForSingleObject(fence_completion_event_, INFINITE);
|
||||
submission_completed_ = submission_fence_->GetCompletedValue();
|
||||
if (SUCCEEDED(submission_fence_->SetEventOnCompletion(
|
||||
await_submission, fence_completion_event_))) {
|
||||
WaitForSingleObject(fence_completion_event_, INFINITE);
|
||||
submission_completed_ = submission_fence_->GetCompletedValue();
|
||||
}
|
||||
}
|
||||
if (submission_completed_ < await_submission) {
|
||||
XELOGE("Failed to await a submission completion Direct3D 12 fence");
|
||||
}
|
||||
if (submission_completed_ <= submission_completed_before) {
|
||||
// Not updated - no need to reclaim or download things.
|
||||
|
@ -2461,6 +2488,9 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
|
|||
is_opening_frame
|
||||
? closed_frame_submissions_[frame_current_ % kQueueFrames]
|
||||
: 0);
|
||||
// TODO(Triang3l): If failed to await (completed submission < awaited frame
|
||||
// submission), do something like dropping the draw command that wanted to
|
||||
// open the frame.
|
||||
if (is_opening_frame) {
|
||||
// Update the completed frame index, also obtaining the actual completed
|
||||
// frame number (since the CPU may be actually less than 3 frames behind)
|
||||
|
@ -2645,9 +2675,8 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) {
|
|||
closed_frame_submissions_[(frame_current_++) % kQueueFrames] =
|
||||
submission_current_ - 1;
|
||||
|
||||
if (cache_clear_requested_) {
|
||||
if (cache_clear_requested_ && AwaitAllQueueOperationsCompletion()) {
|
||||
cache_clear_requested_ = false;
|
||||
AwaitAllQueueOperationsCompletion();
|
||||
|
||||
ClearCommandAllocatorCache();
|
||||
|
||||
|
@ -2692,34 +2721,6 @@ bool D3D12CommandProcessor::CanEndSubmissionImmediately() const {
|
|||
return !submission_open_ || !pipeline_cache_->IsCreatingPipelineStates();
|
||||
}
|
||||
|
||||
void D3D12CommandProcessor::AwaitAllQueueOperationsCompletion() {
|
||||
ui::d3d12::D3D12Context& context = GetD3D12Context();
|
||||
if (context.WasLost()) {
|
||||
return;
|
||||
}
|
||||
if (queue_operations_done_since_submission_signal_) {
|
||||
assert_not_null(queue_operations_since_submission_signal_fence_);
|
||||
UINT64 fence_value =
|
||||
queue_operations_since_submission_signal_fence_->GetCompletedValue() +
|
||||
1;
|
||||
context.GetD3D12Provider().GetDirectQueue()->Signal(
|
||||
queue_operations_since_submission_signal_fence_, fence_value);
|
||||
queue_operations_since_submission_signal_fence_->SetEventOnCompletion(
|
||||
fence_value, fence_completion_event_);
|
||||
queue_operations_done_since_submission_signal_ = false;
|
||||
// Since this indicates operations made after the last submission was done,
|
||||
// it will await all the preceding submissions too.
|
||||
} else if ((submission_completed_ + 1) < submission_current_) {
|
||||
assert_not_null(submission_fence_);
|
||||
submission_fence_->SetEventOnCompletion(submission_current_ - 1,
|
||||
fence_completion_event_);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
WaitForSingleObject(fence_completion_event_, INFINITE);
|
||||
submission_completed_ = submission_current_ - 1;
|
||||
}
|
||||
|
||||
void D3D12CommandProcessor::ClearCommandAllocatorCache() {
|
||||
while (command_allocator_submitted_first_) {
|
||||
auto next = command_allocator_submitted_first_->next;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/gpu/command_processor.h"
|
||||
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
||||
#include "xenia/gpu/d3d12/deferred_command_list.h"
|
||||
|
@ -54,7 +55,6 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
|
||||
void RestoreEdramSnapshot(const void* snapshot) override;
|
||||
|
||||
// Needed by everything that owns transient objects.
|
||||
ui::d3d12::D3D12Context& GetD3D12Context() const {
|
||||
return static_cast<ui::d3d12::D3D12Context&>(*context_);
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
// Returns the deferred drawing command list for the currently open
|
||||
// submission.
|
||||
DeferredCommandList& GetDeferredCommandList() {
|
||||
assert_true(submission_open_);
|
||||
return *deferred_command_list_;
|
||||
}
|
||||
|
||||
|
@ -69,8 +70,8 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
uint64_t GetCompletedSubmission() const { return submission_completed_; }
|
||||
|
||||
// Must be called when a subsystem does something like UpdateTileMappings so
|
||||
// it can be awaited in AwaitAllQueueOperationsCompletion if it was done after
|
||||
// the latest ExecuteCommandLists + Signal.
|
||||
// it can be awaited in CheckSubmissionFence(submission_current_) if it was
|
||||
// done after the latest ExecuteCommandLists + Signal.
|
||||
void NotifyQueueOperationsDoneDirectly() {
|
||||
queue_operations_done_since_submission_signal_ = true;
|
||||
}
|
||||
|
@ -299,7 +300,8 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
// submission has already been closed.
|
||||
|
||||
// Rechecks submission number and reclaims per-submission resources. Pass 0 as
|
||||
// the submission to await to simply check status.
|
||||
// the submission to await to simply check status, or pass submission_current_
|
||||
// to wait for all queue operations to be completed.
|
||||
void CheckSubmissionFence(uint64_t await_submission);
|
||||
// If is_guest_command is true, a new full frame - with full cleanup of
|
||||
// resources and, if needed, starting capturing - is opened if pending (as
|
||||
|
@ -314,7 +316,10 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
// as when there are unfinished graphics pipeline state creation requests that
|
||||
// would need to be fulfilled before actually submitting the command list.
|
||||
bool CanEndSubmissionImmediately() const;
|
||||
void AwaitAllQueueOperationsCompletion();
|
||||
bool AwaitAllQueueOperationsCompletion() {
|
||||
CheckSubmissionFence(submission_current_);
|
||||
return submission_completed_ + 1 >= submission_current_;
|
||||
}
|
||||
// Need to await submission completion before calling.
|
||||
void ClearCommandAllocatorCache();
|
||||
|
||||
|
@ -369,7 +374,8 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
// AwaitAllQueueOperationsCompletion when they're queued after the latest
|
||||
// ExecuteCommandLists + Signal, thus won't be awaited by just awaiting the
|
||||
// submission.
|
||||
ID3D12Fence* queue_operations_since_submission_signal_fence_ = nullptr;
|
||||
ID3D12Fence* queue_operations_since_submission_fence_ = nullptr;
|
||||
uint64_t queue_operations_since_submission_fence_last_ = 0;
|
||||
bool queue_operations_done_since_submission_signal_ = false;
|
||||
|
||||
bool frame_open_ = false;
|
||||
|
|
Loading…
Reference in New Issue