[D3D12] Don't create multiple command lists as they're just encoders
This commit is contained in:
parent
00116fad2d
commit
c8f3c93802
|
@ -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
|
||||
// 4x MSAA) and 4,4 anyway.
|
||||
// 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 tier = provider->GetProgrammableSamplePositionsTier();
|
||||
if (tier >= 2) {
|
||||
|
@ -738,10 +739,31 @@ bool D3D12CommandProcessor::SetupContext() {
|
|||
frame_completed_ = 0;
|
||||
std::memset(closed_frame_submissions_, 0, sizeof(closed_frame_submissions_));
|
||||
|
||||
command_list_writable_first_ = nullptr;
|
||||
command_list_writable_last_ = nullptr;
|
||||
command_list_submitted_first_ = nullptr;
|
||||
command_list_submitted_last_ = nullptr;
|
||||
// Create the command list and one allocator because it's needed for a command
|
||||
// list.
|
||||
ID3D12CommandAllocator* command_allocator;
|
||||
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);
|
||||
|
||||
constant_buffer_pool_ =
|
||||
|
@ -974,7 +996,9 @@ void D3D12CommandProcessor::ShutdownContext() {
|
|||
shared_memory_.reset();
|
||||
|
||||
deferred_command_list_.reset();
|
||||
ClearCommandListCache();
|
||||
ui::d3d12::util::ReleaseAndNull(command_list_1_);
|
||||
ui::d3d12::util::ReleaseAndNull(command_list_);
|
||||
ClearCommandAllocatorCache();
|
||||
|
||||
frame_open_ = false;
|
||||
frame_current_ = 1;
|
||||
|
@ -1824,23 +1848,25 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
|
|||
}
|
||||
}
|
||||
|
||||
// Reclaim command lists.
|
||||
while (command_list_submitted_first_) {
|
||||
if (command_list_submitted_first_->last_usage_submission >
|
||||
// Reclaim command allocators.
|
||||
while (command_allocator_submitted_first_) {
|
||||
if (command_allocator_submitted_first_->last_usage_submission >
|
||||
submission_completed_) {
|
||||
break;
|
||||
}
|
||||
if (command_list_writable_last_) {
|
||||
command_list_writable_last_->next = command_list_submitted_first_;
|
||||
if (command_allocator_writable_last_) {
|
||||
command_allocator_writable_last_->next =
|
||||
command_allocator_submitted_first_;
|
||||
} 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_list_submitted_first_ = command_list_submitted_first_->next;
|
||||
command_list_writable_last_->next = nullptr;
|
||||
command_allocator_writable_last_ = command_allocator_submitted_first_;
|
||||
command_allocator_submitted_first_ =
|
||||
command_allocator_submitted_first_->next;
|
||||
command_allocator_writable_last_->next = nullptr;
|
||||
}
|
||||
if (!command_list_submitted_first_) {
|
||||
command_list_submitted_last_ = nullptr;
|
||||
if (!command_allocator_submitted_first_) {
|
||||
command_allocator_submitted_last_ = nullptr;
|
||||
}
|
||||
|
||||
// Delete transient buffers marked for deletion.
|
||||
|
@ -1858,8 +1884,9 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
|
|||
if (!submission_open_) {
|
||||
submission_open_ = true;
|
||||
|
||||
// Start a new deferred command list - will create the real one in the end
|
||||
// of submission.
|
||||
// Start a new deferred command list - will submit it to the real one in the
|
||||
// end of the submission (when async pipeline state object creation requests
|
||||
// are fulfilled).
|
||||
deferred_command_list_->Reset();
|
||||
|
||||
// Reset cached state of the command list.
|
||||
|
@ -1928,22 +1955,22 @@ void D3D12CommandProcessor::BeginSubmission(bool is_guest_command) {
|
|||
bool D3D12CommandProcessor::EndSubmission(bool is_swap) {
|
||||
auto provider = GetD3D12Context()->GetD3D12Provider();
|
||||
|
||||
// Make sure there is a command list to submit to.
|
||||
if (submission_open_ && !command_list_writable_first_) {
|
||||
std::unique_ptr<ui::d3d12::CommandList> new_command_list =
|
||||
ui::d3d12::CommandList::Create(provider->GetDevice(),
|
||||
provider->GetDirectQueue(),
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||
if (!new_command_list) {
|
||||
// Make sure there is a command allocator to write commands to.
|
||||
if (submission_open_ && !command_allocator_writable_first_) {
|
||||
ID3D12CommandAllocator* command_allocator;
|
||||
if (FAILED(provider->GetDevice()->CreateCommandAllocator(
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
IID_PPV_ARGS(&command_allocator)))) {
|
||||
XELOGE("Failed to create a command allocator");
|
||||
// Try to submit later. Completely dropping the submission is not
|
||||
// permitted because resources would be left in an undefined state.
|
||||
return false;
|
||||
}
|
||||
command_list_writable_first_ = new CommandList;
|
||||
command_list_writable_first_->command_list = std::move(new_command_list);
|
||||
command_list_writable_first_->last_usage_submission = 0;
|
||||
command_list_writable_first_->next = nullptr;
|
||||
command_list_writable_last_ = command_list_writable_first_;
|
||||
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_;
|
||||
}
|
||||
|
||||
bool is_closing_frame = is_swap && frame_open_;
|
||||
|
@ -1961,28 +1988,33 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) {
|
|||
// destroyed between frames.
|
||||
SubmitBarriers();
|
||||
|
||||
auto direct_queue = provider->GetDirectQueue();
|
||||
|
||||
// Submit the command list.
|
||||
auto current_command_list =
|
||||
command_list_writable_first_->command_list.get();
|
||||
current_command_list->BeginRecording();
|
||||
deferred_command_list_->Execute(current_command_list->GetCommandList(),
|
||||
current_command_list->GetCommandList1());
|
||||
current_command_list->Execute();
|
||||
command_list_writable_first_->last_usage_submission = submission_current_;
|
||||
if (command_list_submitted_last_) {
|
||||
command_list_submitted_last_->next = command_list_writable_first_;
|
||||
ID3D12CommandAllocator* command_allocator =
|
||||
command_allocator_writable_first_->command_allocator;
|
||||
command_allocator->Reset();
|
||||
command_list_->Reset(command_allocator, nullptr);
|
||||
deferred_command_list_->Execute(command_list_, command_list_1_);
|
||||
command_list_->Close();
|
||||
ID3D12CommandList* execute_command_lists[] = {command_list_};
|
||||
direct_queue->ExecuteCommandLists(1, execute_command_lists);
|
||||
command_allocator_writable_first_->last_usage_submission =
|
||||
submission_current_;
|
||||
if (command_allocator_submitted_last_) {
|
||||
command_allocator_submitted_last_->next =
|
||||
command_allocator_writable_first_;
|
||||
} 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_list_writable_first_ = command_list_writable_first_->next;
|
||||
command_list_submitted_last_->next = nullptr;
|
||||
if (!command_list_writable_first_) {
|
||||
command_list_writable_last_ = nullptr;
|
||||
command_allocator_submitted_last_ = command_allocator_writable_first_;
|
||||
command_allocator_writable_first_ = command_allocator_writable_first_->next;
|
||||
command_allocator_submitted_last_->next = nullptr;
|
||||
if (!command_allocator_writable_first_) {
|
||||
command_allocator_writable_last_ = nullptr;
|
||||
}
|
||||
|
||||
provider->GetDirectQueue()->Signal(submission_fence_,
|
||||
submission_current_++);
|
||||
direct_queue->Signal(submission_fence_, submission_current_++);
|
||||
|
||||
submission_open_ = false;
|
||||
}
|
||||
|
@ -2005,7 +2037,7 @@ bool D3D12CommandProcessor::EndSubmission(bool is_swap) {
|
|||
cache_clear_requested_ = false;
|
||||
AwaitAllSubmissionsCompletion();
|
||||
|
||||
ClearCommandListCache();
|
||||
ClearCommandAllocatorCache();
|
||||
|
||||
ui::d3d12::util::ReleaseAndNull(scratch_buffer_);
|
||||
scratch_buffer_size_ = 0;
|
||||
|
@ -2047,19 +2079,21 @@ void D3D12CommandProcessor::AwaitAllSubmissionsCompletion() {
|
|||
submission_completed_ = submission_current_ - 1;
|
||||
}
|
||||
|
||||
void D3D12CommandProcessor::ClearCommandListCache() {
|
||||
while (command_list_submitted_first_) {
|
||||
auto next = command_list_submitted_first_->next;
|
||||
delete command_list_submitted_first_;
|
||||
command_list_submitted_first_ = next;
|
||||
void D3D12CommandProcessor::ClearCommandAllocatorCache() {
|
||||
while (command_allocator_submitted_first_) {
|
||||
auto next = command_allocator_submitted_first_->next;
|
||||
command_allocator_submitted_first_->command_allocator->Release();
|
||||
delete command_allocator_submitted_first_;
|
||||
command_allocator_submitted_first_ = next;
|
||||
}
|
||||
command_list_submitted_last_ = nullptr;
|
||||
while (command_list_writable_first_) {
|
||||
auto next = command_list_writable_first_->next;
|
||||
delete command_list_writable_first_;
|
||||
command_list_writable_first_ = next;
|
||||
command_allocator_submitted_last_ = nullptr;
|
||||
while (command_allocator_writable_first_) {
|
||||
auto next = command_allocator_writable_first_->next;
|
||||
command_allocator_writable_first_->command_allocator->Release();
|
||||
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) {
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "xenia/gpu/dxbc_shader_translator.h"
|
||||
#include "xenia/gpu/xenos.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/pools.h"
|
||||
|
||||
|
@ -238,7 +237,7 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
bool EndSubmission(bool is_swap);
|
||||
void AwaitAllSubmissionsCompletion();
|
||||
// Need to await submission completion before calling.
|
||||
void ClearCommandListCache();
|
||||
void ClearCommandAllocatorCache();
|
||||
|
||||
void UpdateFixedFunctionState(bool primitive_two_faced);
|
||||
void UpdateSystemConstantValues(
|
||||
|
@ -278,15 +277,17 @@ class D3D12CommandProcessor : public CommandProcessor {
|
|||
// Submission indices of frames that have already been submitted.
|
||||
uint64_t closed_frame_submissions_[kQueueFrames] = {};
|
||||
|
||||
struct CommandList {
|
||||
std::unique_ptr<ui::d3d12::CommandList> command_list;
|
||||
struct CommandAllocator {
|
||||
ID3D12CommandAllocator* command_allocator;
|
||||
uint64_t last_usage_submission;
|
||||
CommandList* next;
|
||||
CommandAllocator* next;
|
||||
};
|
||||
CommandList* command_list_writable_first_ = nullptr;
|
||||
CommandList* command_list_writable_last_ = nullptr;
|
||||
CommandList* command_list_submitted_first_ = nullptr;
|
||||
CommandList* command_list_submitted_last_ = nullptr;
|
||||
CommandAllocator* command_allocator_writable_first_ = nullptr;
|
||||
CommandAllocator* command_allocator_writable_last_ = nullptr;
|
||||
CommandAllocator* command_allocator_submitted_first_ = 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<SharedMemory> shared_memory_ = nullptr;
|
||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -26,7 +26,7 @@ namespace xe {
|
|||
namespace ui {
|
||||
namespace d3d12 {
|
||||
|
||||
constexpr uint32_t D3D12Context::kSwapCommandListCount;
|
||||
constexpr uint32_t D3D12Context::kSwapCommandAllocatorCount;
|
||||
constexpr uint32_t D3D12Context::kSwapChainBufferCount;
|
||||
|
||||
D3D12Context::D3D12Context(D3D12Provider* provider, Window* target_window)
|
||||
|
@ -113,15 +113,25 @@ bool D3D12Context::Initialize() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Create command lists for compositing.
|
||||
for (uint32_t i = 0; i < kSwapCommandListCount; ++i) {
|
||||
swap_command_lists_[i] = CommandList::Create(
|
||||
device, direct_queue, D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||
if (swap_command_lists_[i] == nullptr) {
|
||||
// Create the command list for compositing.
|
||||
for (uint32_t i = 0; i < kSwapCommandAllocatorCount; ++i) {
|
||||
if (FAILED(device->CreateCommandAllocator(
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||
IID_PPV_ARGS(&swap_command_allocators_[i])))) {
|
||||
XELOGE("Failed to create a composition command allocator");
|
||||
Shutdown();
|
||||
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.
|
||||
immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(this);
|
||||
|
@ -163,6 +173,10 @@ bool D3D12Context::InitializeSwapChainBuffers() {
|
|||
}
|
||||
|
||||
void D3D12Context::Shutdown() {
|
||||
if (!target_window_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context_lost_ && swap_fence_ &&
|
||||
swap_fence_->GetCompletedValue() + 1 < swap_fence_current_value_) {
|
||||
swap_fence_->SetEventOnCompletion(swap_fence_current_value_ - 1,
|
||||
|
@ -172,8 +186,14 @@ void D3D12Context::Shutdown() {
|
|||
|
||||
immediate_drawer_.reset();
|
||||
|
||||
for (uint32_t i = 0; i < kSwapCommandListCount; ++i) {
|
||||
swap_command_lists_[i].reset();
|
||||
util::ReleaseAndNull(swap_command_list_);
|
||||
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_) {
|
||||
|
@ -186,12 +206,10 @@ void D3D12Context::Shutdown() {
|
|||
swap_chain_buffer = nullptr;
|
||||
}
|
||||
|
||||
if (swap_chain_rtv_heap_) {
|
||||
swap_chain_rtv_heap_->Release();
|
||||
swap_chain_rtv_heap_ = nullptr;
|
||||
}
|
||||
util::ReleaseAndNull(swap_chain_rtv_heap_);
|
||||
|
||||
swap_chain_->Release();
|
||||
swap_chain_ = nullptr;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Command list 0 is used when swap_fence_current_value_ is 1, 4, 7...
|
||||
// Wait for a swap command allocator to become free.
|
||||
// Command allocator 0 is used when swap_fence_current_value_ is 1, 4, 7...
|
||||
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_->SetEventOnCompletion(
|
||||
swap_fence_current_value_ - kSwapCommandListCount,
|
||||
swap_fence_current_value_ - kSwapCommandAllocatorCount,
|
||||
swap_fence_completion_event_);
|
||||
WaitForSingleObject(swap_fence_completion_event_, INFINITE);
|
||||
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.
|
||||
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;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
|
@ -279,9 +300,9 @@ void D3D12Context::BeginSwap() {
|
|||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
|
||||
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();
|
||||
graphics_command_list->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr);
|
||||
swap_command_list_->OMSetRenderTargets(1, &back_buffer_rtv, TRUE, nullptr);
|
||||
float clear_color[4];
|
||||
if (cvars::d3d12_random_clear_color) {
|
||||
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[3] = 1.0f;
|
||||
graphics_command_list->ClearRenderTargetView(back_buffer_rtv, clear_color, 0,
|
||||
nullptr);
|
||||
swap_command_list_->ClearRenderTargetView(back_buffer_rtv, clear_color, 0,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void D3D12Context::EndSwap() {
|
||||
|
@ -302,12 +323,9 @@ void D3D12Context::EndSwap() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto direct_queue = GetD3D12Provider()->GetDirectQueue();
|
||||
|
||||
// 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;
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
|
@ -316,9 +334,12 @@ void D3D12Context::EndSwap() {
|
|||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
|
||||
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.
|
||||
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.
|
||||
GetD3D12Provider()->GetDirectQueue()->Signal(swap_fence_,
|
||||
swap_fence_current_value_++);
|
||||
direct_queue->Signal(swap_fence_, swap_fence_current_value_++);
|
||||
|
||||
// Get the back buffer index for the next frame.
|
||||
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include "xenia/ui/d3d12/command_list.h"
|
||||
#include "xenia/ui/d3d12/d3d12_immediate_drawer.h"
|
||||
#include "xenia/ui/d3d12/d3d12_provider.h"
|
||||
#include "xenia/ui/graphics_context.h"
|
||||
|
@ -68,10 +67,7 @@ class D3D12Context : public GraphicsContext {
|
|||
return swap_fence_completed_value_;
|
||||
}
|
||||
ID3D12GraphicsCommandList* GetSwapCommandList() const {
|
||||
uint32_t command_list_index =
|
||||
uint32_t((swap_fence_current_value_ + (kSwapCommandListCount - 1)) %
|
||||
kSwapCommandListCount);
|
||||
return swap_command_lists_[command_list_index]->GetCommandList();
|
||||
return swap_command_list_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -99,11 +95,13 @@ class D3D12Context : public GraphicsContext {
|
|||
HANDLE swap_fence_completion_event_ = nullptr;
|
||||
ID3D12Fence* swap_fence_ = nullptr;
|
||||
|
||||
static constexpr uint32_t kSwapCommandListCount = 3;
|
||||
std::unique_ptr<CommandList> swap_command_lists_[kSwapCommandListCount] = {};
|
||||
// Current is
|
||||
// ((swap_fence_current_value_ + (kSwapCommandListCount - 1))) %
|
||||
// kSwapCommandListCount.
|
||||
static constexpr uint32_t kSwapCommandAllocatorCount = 3;
|
||||
ID3D12CommandAllocator* swap_command_allocators_[kSwapCommandAllocatorCount] =
|
||||
{};
|
||||
// Current command allocator is:
|
||||
// ((swap_fence_current_value_ + (kSwapCommandAllocatorCount - 1))) %
|
||||
// kSwapCommandAllocatorCount.
|
||||
ID3D12GraphicsCommandList* swap_command_list_ = nullptr;
|
||||
|
||||
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_ = nullptr;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue