[D3D12] Don't create multiple command lists as they're just encoders

This commit is contained in:
Triang3l
2019-11-06 08:06:12 +03:00
parent 00116fad2d
commit c8f3c93802
6 changed files with 166 additions and 250 deletions

View File

@@ -555,7 +555,8 @@ void D3D12CommandProcessor::SetSamplePositions(MsaaSamples sample_positions) {
// for ROV output. There's hardly any difference between 2,6 (of 0 and 3 with // for ROV output. There's hardly any difference between 2,6 (of 0 and 3 with
// 4x MSAA) and 4,4 anyway. // 4x MSAA) and 4,4 anyway.
// https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/nf-d3d12-id3d12graphicscommandlist1-setsamplepositions // https://docs.microsoft.com/en-us/windows/desktop/api/d3d12/nf-d3d12-id3d12graphicscommandlist1-setsamplepositions
if (cvars::d3d12_ssaa_custom_sample_positions && !IsROVUsedForEDRAM()) { if (cvars::d3d12_ssaa_custom_sample_positions && !IsROVUsedForEDRAM() &&
command_list_1_) {
auto provider = GetD3D12Context()->GetD3D12Provider(); auto provider = GetD3D12Context()->GetD3D12Provider();
auto tier = provider->GetProgrammableSamplePositionsTier(); auto tier = provider->GetProgrammableSamplePositionsTier();
if (tier >= 2) { if (tier >= 2) {
@@ -738,10 +739,31 @@ bool D3D12CommandProcessor::SetupContext() {
frame_completed_ = 0; frame_completed_ = 0;
std::memset(closed_frame_submissions_, 0, sizeof(closed_frame_submissions_)); std::memset(closed_frame_submissions_, 0, sizeof(closed_frame_submissions_));
command_list_writable_first_ = nullptr; // Create the command list and one allocator because it's needed for a command
command_list_writable_last_ = nullptr; // list.
command_list_submitted_first_ = nullptr; ID3D12CommandAllocator* command_allocator;
command_list_submitted_last_ = nullptr; if (FAILED(device->CreateCommandAllocator(
D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&command_allocator)))) {
XELOGE("Failed to create a command allocator");
return false;
}
command_allocator_writable_first_ = new CommandAllocator;
command_allocator_writable_first_->command_allocator = command_allocator;
command_allocator_writable_first_->last_usage_submission = 0;
command_allocator_writable_first_->next = nullptr;
command_allocator_writable_last_ = command_allocator_writable_first_;
command_allocator_submitted_first_ = nullptr;
command_allocator_submitted_last_ = nullptr;
if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
command_allocator, nullptr,
IID_PPV_ARGS(&command_list_)))) {
XELOGE("Failed to create the graphics command list");
return false;
}
// Initially in open state, wait until a deferred command list submission.
command_list_->Close();
// Optional - added in Creators Update (SDK 10.0.15063.0).
command_list_->QueryInterface(IID_PPV_ARGS(&command_list_1_));
deferred_command_list_ = std::make_unique<DeferredCommandList>(this); deferred_command_list_ = std::make_unique<DeferredCommandList>(this);
constant_buffer_pool_ = constant_buffer_pool_ =
@@ -974,7 +996,9 @@ void D3D12CommandProcessor::ShutdownContext() {
shared_memory_.reset(); shared_memory_.reset();
deferred_command_list_.reset(); deferred_command_list_.reset();
ClearCommandListCache(); ui::d3d12::util::ReleaseAndNull(command_list_1_);
ui::d3d12::util::ReleaseAndNull(command_list_);
ClearCommandAllocatorCache();
frame_open_ = false; frame_open_ = false;
frame_current_ = 1; frame_current_ = 1;
@@ -1824,23 +1848,25 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
} }
} }
// Reclaim command lists. // Reclaim command allocators.
while (command_list_submitted_first_) { while (command_allocator_submitted_first_) {
if (command_list_submitted_first_->last_usage_submission > if (command_allocator_submitted_first_->last_usage_submission >
submission_completed_) { submission_completed_) {
break; break;
} }
if (command_list_writable_last_) { if (command_allocator_writable_last_) {
command_list_writable_last_->next = command_list_submitted_first_; command_allocator_writable_last_->next =
command_allocator_submitted_first_;
} else { } else {
command_list_writable_first_ = command_list_submitted_first_; command_allocator_writable_first_ = command_allocator_submitted_first_;
} }
command_list_writable_last_ = command_list_submitted_first_; command_allocator_writable_last_ = command_allocator_submitted_first_;
command_list_submitted_first_ = command_list_submitted_first_->next; command_allocator_submitted_first_ =
command_list_writable_last_->next = nullptr; command_allocator_submitted_first_->next;
command_allocator_writable_last_->next = nullptr;
} }
if (!command_list_submitted_first_) { if (!command_allocator_submitted_first_) {
command_list_submitted_last_ = nullptr; command_allocator_submitted_last_ = nullptr;
} }
// Delete transient buffers marked for deletion. // Delete transient buffers marked for deletion.
@@ -1858,8 +1884,9 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
if (!submission_open_) { if (!submission_open_) {
submission_open_ = true; submission_open_ = true;
// Start a new deferred command list - will create the real one in the end // Start a new deferred command list - will submit it to the real one in the
// of submission. // end of the submission (when async pipeline state object creation requests
// are fulfilled).
deferred_command_list_->Reset(); deferred_command_list_->Reset();
// Reset cached state of the command list. // Reset cached state of the command list.
@@ -1928,22 +1955,22 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
bool D3D12CommandProcessor::EndSubmission(bool is_swap) { bool D3D12CommandProcessor::EndSubmission(bool is_swap) {
auto provider = GetD3D12Context()->GetD3D12Provider(); auto provider = GetD3D12Context()->GetD3D12Provider();
// Make sure there is a command list to submit to. // Make sure there is a command allocator to write commands to.
if (submission_open_ && !command_list_writable_first_) { if (submission_open_ && !command_allocator_writable_first_) {
std::unique_ptr<ui::d3d12::CommandList> new_command_list = ID3D12CommandAllocator* command_allocator;
ui::d3d12::CommandList::Create(provider->GetDevice(), if (FAILED(provider->GetDevice()->CreateCommandAllocator(
provider->GetDirectQueue(), D3D12_COMMAND_LIST_TYPE_DIRECT,
D3D12_COMMAND_LIST_TYPE_DIRECT); IID_PPV_ARGS(&command_allocator)))) {
if (!new_command_list) { XELOGE("Failed to create a command allocator");
// Try to submit later. Completely dropping the submission is not // Try to submit later. Completely dropping the submission is not
// permitted because resources would be left in an undefined state. // permitted because resources would be left in an undefined state.
return false; return false;
} }
command_list_writable_first_ = new CommandList; command_allocator_writable_first_ = new CommandAllocator;
command_list_writable_first_->command_list = std::move(new_command_list); command_allocator_writable_first_->command_allocator = command_allocator;
command_list_writable_first_->last_usage_submission = 0; command_allocator_writable_first_->last_usage_submission = 0;
command_list_writable_first_->next = nullptr; command_allocator_writable_first_->next = nullptr;
command_list_writable_last_ = command_list_writable_first_; command_allocator_writable_last_ = command_allocator_writable_first_;
} }
bool is_closing_frame = is_swap && frame_open_; bool is_closing_frame = is_swap && frame_open_;
@@ -1961,28 +1988,33 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) {
// destroyed between frames. // destroyed between frames.
SubmitBarriers(); SubmitBarriers();
auto direct_queue = provider->GetDirectQueue();
// Submit the command list. // Submit the command list.
auto current_command_list = ID3D12CommandAllocator* command_allocator =
command_list_writable_first_->command_list.get(); command_allocator_writable_first_->command_allocator;
current_command_list->BeginRecording(); command_allocator->Reset();
deferred_command_list_->Execute(current_command_list->GetCommandList(), command_list_->Reset(command_allocator, nullptr);
current_command_list->GetCommandList1()); deferred_command_list_->Execute(command_list_, command_list_1_);
current_command_list->Execute(); command_list_->Close();
command_list_writable_first_->last_usage_submission = submission_current_; ID3D12CommandList* execute_command_lists[] = {command_list_};
if (command_list_submitted_last_) { direct_queue->ExecuteCommandLists(1, execute_command_lists);
command_list_submitted_last_->next = command_list_writable_first_; command_allocator_writable_first_->last_usage_submission =
submission_current_;
if (command_allocator_submitted_last_) {
command_allocator_submitted_last_->next =
command_allocator_writable_first_;
} else { } else {
command_list_submitted_first_ = command_list_writable_first_; command_allocator_submitted_first_ = command_allocator_writable_first_;
} }
command_list_submitted_last_ = command_list_writable_first_; command_allocator_submitted_last_ = command_allocator_writable_first_;
command_list_writable_first_ = command_list_writable_first_->next; command_allocator_writable_first_ = command_allocator_writable_first_->next;
command_list_submitted_last_->next = nullptr; command_allocator_submitted_last_->next = nullptr;
if (!command_list_writable_first_) { if (!command_allocator_writable_first_) {
command_list_writable_last_ = nullptr; command_allocator_writable_last_ = nullptr;
} }
provider->GetDirectQueue()->Signal(submission_fence_, direct_queue->Signal(submission_fence_, submission_current_++);
submission_current_++);
submission_open_ = false; submission_open_ = false;
} }
@@ -2005,7 +2037,7 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) {
cache_clear_requested_ = false; cache_clear_requested_ = false;
AwaitAllSubmissionsCompletion(); AwaitAllSubmissionsCompletion();
ClearCommandListCache(); ClearCommandAllocatorCache();
ui::d3d12::util::ReleaseAndNull(scratch_buffer_); ui::d3d12::util::ReleaseAndNull(scratch_buffer_);
scratch_buffer_size_ = 0; scratch_buffer_size_ = 0;
@@ -2047,19 +2079,21 @@ void D3D12CommandProcessor::AwaitAllSubmissionsCompletion() {
submission_completed_ = submission_current_ - 1; submission_completed_ = submission_current_ - 1;
} }
void D3D12CommandProcessor::ClearCommandListCache() { void D3D12CommandProcessor::ClearCommandAllocatorCache() {
while (command_list_submitted_first_) { while (command_allocator_submitted_first_) {
auto next = command_list_submitted_first_->next; auto next = command_allocator_submitted_first_->next;
delete command_list_submitted_first_; command_allocator_submitted_first_->command_allocator->Release();
command_list_submitted_first_ = next; delete command_allocator_submitted_first_;
command_allocator_submitted_first_ = next;
} }
command_list_submitted_last_ = nullptr; command_allocator_submitted_last_ = nullptr;
while (command_list_writable_first_) { while (command_allocator_writable_first_) {
auto next = command_list_writable_first_->next; auto next = command_allocator_writable_first_->next;
delete command_list_writable_first_; command_allocator_writable_first_->command_allocator->Release();
command_list_writable_first_ = next; delete command_allocator_writable_first_;
command_allocator_writable_first_ = next;
} }
command_list_writable_last_ = nullptr; command_allocator_writable_last_ = nullptr;
} }
void D3D12CommandProcessor::UpdateFixedFunctionState(bool primitive_two_faced) { void D3D12CommandProcessor::UpdateFixedFunctionState(bool primitive_two_faced) {

View File

@@ -28,7 +28,6 @@
#include "xenia/gpu/dxbc_shader_translator.h" #include "xenia/gpu/dxbc_shader_translator.h"
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
#include "xenia/kernel/kernel_state.h" #include "xenia/kernel/kernel_state.h"
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/ui/d3d12/d3d12_context.h" #include "xenia/ui/d3d12/d3d12_context.h"
#include "xenia/ui/d3d12/pools.h" #include "xenia/ui/d3d12/pools.h"
@@ -238,7 +237,7 @@ class D3D12CommandProcessor : public CommandProcessor {
bool EndSubmission(bool is_swap); bool EndSubmission(bool is_swap);
void AwaitAllSubmissionsCompletion(); void AwaitAllSubmissionsCompletion();
// Need to await submission completion before calling. // Need to await submission completion before calling.
void ClearCommandListCache(); void ClearCommandAllocatorCache();
void UpdateFixedFunctionState(bool primitive_two_faced); void UpdateFixedFunctionState(bool primitive_two_faced);
void UpdateSystemConstantValues( void UpdateSystemConstantValues(
@@ -278,15 +277,17 @@ class D3D12CommandProcessor : public CommandProcessor {
// Submission indices of frames that have already been submitted. // Submission indices of frames that have already been submitted.
uint64_t closed_frame_submissions_[kQueueFrames] = {}; uint64_t closed_frame_submissions_[kQueueFrames] = {};
struct CommandList { struct CommandAllocator {
std::unique_ptr<ui::d3d12::CommandList> command_list; ID3D12CommandAllocator* command_allocator;
uint64_t last_usage_submission; uint64_t last_usage_submission;
CommandList* next; CommandAllocator* next;
}; };
CommandList* command_list_writable_first_ = nullptr; CommandAllocator* command_allocator_writable_first_ = nullptr;
CommandList* command_list_writable_last_ = nullptr; CommandAllocator* command_allocator_writable_last_ = nullptr;
CommandList* command_list_submitted_first_ = nullptr; CommandAllocator* command_allocator_submitted_first_ = nullptr;
CommandList* command_list_submitted_last_ = nullptr; CommandAllocator* command_allocator_submitted_last_ = nullptr;
ID3D12GraphicsCommandList* command_list_ = nullptr;
ID3D12GraphicsCommandList1* command_list_1_ = nullptr;
std::unique_ptr<DeferredCommandList> deferred_command_list_ = nullptr; std::unique_ptr<DeferredCommandList> deferred_command_list_ = nullptr;
std::unique_ptr<SharedMemory> shared_memory_ = nullptr; std::unique_ptr<SharedMemory> shared_memory_ = nullptr;

View File

@@ -1,81 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/base/logging.h"
namespace xe {
namespace ui {
namespace d3d12 {
std::unique_ptr<CommandList> CommandList::Create(ID3D12Device* device,
ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type) {
std::unique_ptr<CommandList> command_list(
new CommandList(device, queue, type));
if (!command_list->Initialize()) {
return nullptr;
}
return command_list;
}
CommandList::CommandList(ID3D12Device* device, ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type)
: device_(device), queue_(queue), type_(type) {}
CommandList::~CommandList() {
if (command_list_1_ != nullptr) {
command_list_1_->Release();
}
if (command_list_ != nullptr) {
command_list_->Release();
}
if (command_allocator_ != nullptr) {
command_allocator_->Release();
}
}
bool CommandList::Initialize() {
if (FAILED(device_->CreateCommandAllocator(
type_, IID_PPV_ARGS(&command_allocator_)))) {
XELOGE("Failed to create a command allocator");
return false;
}
if (FAILED(device_->CreateCommandList(0, type_, command_allocator_, nullptr,
IID_PPV_ARGS(&command_list_)))) {
XELOGE("Failed to create a graphics command list");
command_allocator_->Release();
command_allocator_ = nullptr;
return false;
}
// Optional - added in Creators Update (SDK 10.0.15063.0).
command_list_->QueryInterface(IID_PPV_ARGS(&command_list_1_));
// A command list is initially open, need to close it before resetting.
command_list_->Close();
return true;
}
ID3D12GraphicsCommandList* CommandList::BeginRecording() {
command_allocator_->Reset();
command_list_->Reset(command_allocator_, nullptr);
return command_list_;
}
void CommandList::AbortRecording() { command_list_->Close(); }
void CommandList::Execute() {
command_list_->Close();
ID3D12CommandList* execute_lists[] = {command_list_};
queue_->ExecuteCommandLists(1, execute_lists);
}
} // namespace d3d12
} // namespace ui
} // namespace xe

View File

@@ -1,56 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2018 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_UI_D3D12_COMMAND_LIST_H_
#define XENIA_UI_D3D12_COMMAND_LIST_H_
#include <memory>
#include "xenia/ui/d3d12/d3d12_api.h"
namespace xe {
namespace ui {
namespace d3d12 {
class CommandList {
public:
~CommandList();
static std::unique_ptr<CommandList> Create(ID3D12Device* device,
ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type);
ID3D12GraphicsCommandList* GetCommandList() const { return command_list_; }
ID3D12GraphicsCommandList1* GetCommandList1() const {
return command_list_1_;
}
ID3D12GraphicsCommandList* BeginRecording();
void AbortRecording();
void Execute();
protected:
CommandList(ID3D12Device* device, ID3D12CommandQueue* queue,
D3D12_COMMAND_LIST_TYPE type);
bool Initialize();
ID3D12Device* device_;
ID3D12CommandQueue* queue_;
D3D12_COMMAND_LIST_TYPE type_;
ID3D12CommandAllocator* command_allocator_ = nullptr;
ID3D12GraphicsCommandList* command_list_ = nullptr;
ID3D12GraphicsCommandList1* command_list_1_ = nullptr;
};
} // namespace d3d12
} // namespace ui
} // namespace xe
#endif // XENIA_UI_D3D12_CPU_FENCE_H_

View File

@@ -26,7 +26,7 @@ namespace xe {
namespace ui { namespace ui {
namespace d3d12 { namespace d3d12 {
constexpr uint32_t D3D12Context::kSwapCommandListCount; constexpr uint32_t D3D12Context::kSwapCommandAllocatorCount;
constexpr uint32_t D3D12Context::kSwapChainBufferCount; constexpr uint32_t D3D12Context::kSwapChainBufferCount;
D3D12Context::D3D12Context(D3D12Provider* provider, Window* target_window) D3D12Context::D3D12Context(D3D12Provider* provider, Window* target_window)
@@ -113,15 +113,25 @@ bool D3D12Context::Initialize() {
return false; return false;
} }
// Create command lists for compositing. // Create the command list for compositing.
for (uint32_t i = 0; i < kSwapCommandListCount; ++i) { for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
swap_command_lists_[i] = CommandList::Create( if (FAILED(device->CreateCommandAllocator(
device, direct_queue, D3D12_COMMAND_LIST_TYPE_DIRECT); D3D12_COMMAND_LIST_TYPE_DIRECT,
if (swap_command_lists_[i] == nullptr) { IID_PPV_ARGS(&swap_command_allocators_[i])))) {
XELOGE("Failed to create a composition command allocator");
Shutdown(); Shutdown();
return false; return false;
} }
} }
if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
swap_command_allocators_[0], nullptr,
IID_PPV_ARGS(&swap_command_list_)))) {
XELOGE("Failed to create the composition graphics command list");
Shutdown();
return false;
}
// Initially in open state, wait until BeginSwap.
swap_command_list_->Close();
// Initialize the immediate mode drawer if not offscreen. // Initialize the immediate mode drawer if not offscreen.
immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(this); immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(this);
@@ -163,6 +173,10 @@ bool D3D12Context::InitializeSwapChainBuffers() {
} }
void D3D12Context::Shutdown() { void D3D12Context::Shutdown() {
if (!target_window_) {
return;
}
if (!context_lost_ && swap_fence_ && if (!context_lost_ && swap_fence_ &&
swap_fence_->GetCompletedValue() + 1 < swap_fence_current_value_) { swap_fence_->GetCompletedValue() + 1 < swap_fence_current_value_) {
swap_fence_->SetEventOnCompletion(swap_fence_current_value_ - 1, swap_fence_->SetEventOnCompletion(swap_fence_current_value_ - 1,
@@ -172,8 +186,14 @@ void D3D12Context::Shutdown() {
immediate_drawer_.reset(); immediate_drawer_.reset();
for (uint32_t i = 0; i < kSwapCommandListCount; ++i) { util::ReleaseAndNull(swap_command_list_);
swap_command_lists_[i].reset(); for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
auto& swap_command_allocator = swap_command_allocators_[i];
if (!swap_command_allocator) {
break;
}
swap_command_allocator->Release();
swap_command_allocator = nullptr;
} }
if (swap_chain_) { if (swap_chain_) {
@@ -186,12 +206,10 @@ void D3D12Context::Shutdown() {
swap_chain_buffer = nullptr; swap_chain_buffer = nullptr;
} }
if (swap_chain_rtv_heap_) { util::ReleaseAndNull(swap_chain_rtv_heap_);
swap_chain_rtv_heap_->Release();
swap_chain_rtv_heap_ = nullptr;
}
swap_chain_->Release(); swap_chain_->Release();
swap_chain_ = nullptr;
} }
// First release the fence since it may reference the event. // First release the fence since it may reference the event.
@@ -253,24 +271,27 @@ void D3D12Context::BeginSwap() {
} }
} }
// Wait for a swap command list to become free. // Wait for a swap command allocator to become free.
// Command list 0 is used when swap_fence_current_value_ is 1, 4, 7... // Command allocator 0 is used when swap_fence_current_value_ is 1, 4, 7...
swap_fence_completed_value_ = swap_fence_->GetCompletedValue(); swap_fence_completed_value_ = swap_fence_->GetCompletedValue();
if (swap_fence_completed_value_ + kSwapCommandListCount < if (swap_fence_completed_value_ + kSwapCommandAllocatorCount <
swap_fence_current_value_) { swap_fence_current_value_) {
swap_fence_->SetEventOnCompletion( swap_fence_->SetEventOnCompletion(
swap_fence_current_value_ - kSwapCommandListCount, swap_fence_current_value_ - kSwapCommandAllocatorCount,
swap_fence_completion_event_); swap_fence_completion_event_);
WaitForSingleObject(swap_fence_completion_event_, INFINITE); WaitForSingleObject(swap_fence_completion_event_, INFINITE);
swap_fence_completed_value_ = swap_fence_->GetCompletedValue(); swap_fence_completed_value_ = swap_fence_->GetCompletedValue();
} }
// Start the command list.
uint32_t command_allocator_index =
uint32_t((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1)) %
kSwapCommandAllocatorCount);
auto command_allocator = swap_command_allocators_[command_allocator_index];
command_allocator->Reset();
swap_command_list_->Reset(command_allocator, nullptr);
// Bind the back buffer as a render target and clear it. // Bind the back buffer as a render target and clear it.
uint32_t command_list_index =
uint32_t((swap_fence_current_value_ + (kSwapCommandListCount - 1)) %
kSwapCommandListCount);
auto command_list = swap_command_lists_[command_list_index].get();
auto graphics_command_list = command_list->BeginRecording();
D3D12_RESOURCE_BARRIER barrier; D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
@@ -279,9 +300,9 @@ void D3D12Context::BeginSwap() {
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
graphics_command_list->ResourceBarrier(1, &barrier); swap_command_list_->ResourceBarrier(1, &barrier);
D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV(); D3D12_CPU_DESCRIPTOR_HANDLE back_buffer_rtv = GetSwapChainBackBufferRTV();
graphics_command_list->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr); swap_command_list_->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr);
float clear_color[4]; float clear_color[4];
if (cvars::d3d12_random_clear_color) { if (cvars::d3d12_random_clear_color) {
clear_color[0] = rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn) clear_color[0] = rand() / float(RAND_MAX); // NOLINT(runtime/threadsafe_fn)
@@ -293,8 +314,8 @@ void D3D12Context::BeginSwap() {
clear_color[2] = 238.0f / 255.0f; clear_color[2] = 238.0f / 255.0f;
} }
clear_color[3] = 1.0f; clear_color[3] = 1.0f;
graphics_command_list->ClearRenderTargetView(back_buffer_rtv, clear_color, 0, swap_command_list_->ClearRenderTargetView(back_buffer_rtv, clear_color, 0,
nullptr); nullptr);
} }
void D3D12Context::EndSwap() { void D3D12Context::EndSwap() {
@@ -302,12 +323,9 @@ void D3D12Context::EndSwap() {
return; return;
} }
auto direct_queue = GetD3D12Provider()->GetDirectQueue();
// Switch the back buffer to presentation state. // Switch the back buffer to presentation state.
uint32_t command_list_index =
uint32_t((swap_fence_current_value_ + (kSwapCommandListCount - 1)) %
kSwapCommandListCount);
auto command_list = swap_command_lists_[command_list_index].get();
auto graphics_command_list = command_list->GetCommandList();
D3D12_RESOURCE_BARRIER barrier; D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
@@ -316,9 +334,12 @@ void D3D12Context::EndSwap() {
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
graphics_command_list->ResourceBarrier(1, &barrier); swap_command_list_->ResourceBarrier(1, &barrier);
command_list->Execute(); // Submit the command list.
swap_command_list_->Close();
ID3D12CommandList* execute_command_lists[] = {swap_command_list_};
direct_queue->ExecuteCommandLists(1, execute_command_lists);
// Present and check if the context was lost. // Present and check if the context was lost.
HRESULT result = swap_chain_->Present(0, 0); HRESULT result = swap_chain_->Present(0, 0);
@@ -329,8 +350,7 @@ void D3D12Context::EndSwap() {
} }
// Signal the fence to wait for frame resources to become free again. // Signal the fence to wait for frame resources to become free again.
GetD3D12Provider()->GetDirectQueue()->Signal(swap_fence_, direct_queue->Signal(swap_fence_, swap_fence_current_value_++);
swap_fence_current_value_++);
// Get the back buffer index for the next frame. // Get the back buffer index for the next frame.
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex(); swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();

View File

@@ -12,7 +12,6 @@
#include <memory> #include <memory>
#include "xenia/ui/d3d12/command_list.h"
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h" #include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
#include "xenia/ui/d3d12/d3d12_provider.h" #include "xenia/ui/d3d12/d3d12_provider.h"
#include "xenia/ui/graphics_context.h" #include "xenia/ui/graphics_context.h"
@@ -68,10 +67,7 @@ class D3D12Context : public GraphicsContext {
return swap_fence_completed_value_; return swap_fence_completed_value_;
} }
ID3D12GraphicsCommandList* GetSwapCommandList() const { ID3D12GraphicsCommandList* GetSwapCommandList() const {
uint32_t command_list_index = return swap_command_list_;
uint32_t((swap_fence_current_value_ + (kSwapCommandListCount - 1)) %
kSwapCommandListCount);
return swap_command_lists_[command_list_index]->GetCommandList();
} }
private: private:
@@ -99,11 +95,13 @@ class D3D12Context : public GraphicsContext {
HANDLE swap_fence_completion_event_ = nullptr; HANDLE swap_fence_completion_event_ = nullptr;
ID3D12Fence* swap_fence_ = nullptr; ID3D12Fence* swap_fence_ = nullptr;
static constexpr uint32_t kSwapCommandListCount = 3; static constexpr uint32_t kSwapCommandAllocatorCount = 3;
std::unique_ptr<CommandList> swap_command_lists_[kSwapCommandListCount] = {}; ID3D12CommandAllocator* swap_command_allocators_[kSwapCommandAllocatorCount] =
// Current is {};
// ((swap_fence_current_value_ + (kSwapCommandListCount - 1))) % // Current command allocator is:
// kSwapCommandListCount. // ((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1))) %
// kSwapCommandAllocatorCount.
ID3D12GraphicsCommandList* swap_command_list_ = nullptr;
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_ = nullptr; std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_ = nullptr;
}; };