[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
// 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) {

View File

@ -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;

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 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();

View File

@ -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;
};