[D3D12] Don't create multiple command lists as they're just encoders
This commit is contained in:
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 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();
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user