[D3D12] Make something buildable
This commit is contained in:
parent
0ded51f894
commit
cd1cf3a857
|
@ -92,6 +92,13 @@ std::unique_ptr<gpu::GraphicsSystem> CreateGraphicsSystem() {
|
||||||
// Create best available.
|
// Create best available.
|
||||||
std::unique_ptr<gpu::GraphicsSystem> best;
|
std::unique_ptr<gpu::GraphicsSystem> best;
|
||||||
|
|
||||||
|
#if XE_PLATFORM_WIN32
|
||||||
|
best = std::unique_ptr<gpu::GraphicsSystem>(
|
||||||
|
new xe::gpu::d3d12::D3D12GraphicsSystem());
|
||||||
|
if (best) {
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
#endif // XE_PLATFORM_WIN32
|
||||||
best = std::unique_ptr<gpu::GraphicsSystem>(
|
best = std::unique_ptr<gpu::GraphicsSystem>(
|
||||||
new xe::gpu::vulkan::VulkanGraphicsSystem());
|
new xe::gpu::vulkan::VulkanGraphicsSystem());
|
||||||
if (best) {
|
if (best) {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/math.h"
|
#include "xenia/base/math.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/window.h"
|
#include "xenia/ui/window.h"
|
||||||
|
|
||||||
|
@ -30,18 +31,22 @@ D3D12Context::D3D12Context(D3D12Provider* provider, Window* target_window)
|
||||||
D3D12Context::~D3D12Context() { Shutdown(); }
|
D3D12Context::~D3D12Context() { Shutdown(); }
|
||||||
|
|
||||||
bool D3D12Context::Initialize() {
|
bool D3D12Context::Initialize() {
|
||||||
auto provider = static_cast<D3D12Provider*>(provider_);
|
auto provider = GetD3D12Provider();
|
||||||
auto dxgi_factory = provider->GetDXGIFactory();
|
auto dxgi_factory = provider->GetDXGIFactory();
|
||||||
auto device = provider->GetDevice();
|
auto device = provider->GetDevice();
|
||||||
auto direct_queue = provider->GetDirectQueue();
|
auto direct_queue = provider->GetDirectQueue();
|
||||||
|
|
||||||
context_lost_ = false;
|
context_lost_ = false;
|
||||||
|
|
||||||
current_queue_frame_ = 0;
|
current_frame_ = 1;
|
||||||
|
// No frames have been completed yet.
|
||||||
|
last_completed_frame_ = 0;
|
||||||
|
// Keep in sync with the modulo because why not.
|
||||||
|
current_queue_frame_ = 1;
|
||||||
|
|
||||||
// Create fences for synchronization of reuse and destruction of transient
|
// Create fences for synchronization of reuse and destruction of transient
|
||||||
// objects (like command lists) and for global shutdown.
|
// objects (like command lists) and for global shutdown.
|
||||||
for (uint32_t i = 0; i < kFrameQueueLength; ++i) {
|
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
|
||||||
fences_[i] = CPUFence::Create(device, direct_queue);
|
fences_[i] = CPUFence::Create(device, direct_queue);
|
||||||
if (fences_[i] == nullptr) {
|
if (fences_[i] == nullptr) {
|
||||||
Shutdown();
|
Shutdown();
|
||||||
|
@ -94,6 +99,8 @@ bool D3D12Context::Initialize() {
|
||||||
Shutdown();
|
Shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
swap_chain_rtv_heap_start_ =
|
||||||
|
swap_chain_rtv_heap_->GetCPUDescriptorHandleForHeapStart();
|
||||||
|
|
||||||
// Get the buffers and create their RTV descriptors.
|
// Get the buffers and create their RTV descriptors.
|
||||||
if (!InitializeSwapChainBuffers()) {
|
if (!InitializeSwapChainBuffers()) {
|
||||||
|
@ -102,7 +109,7 @@ bool D3D12Context::Initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create command lists for swap chain back buffer state transitions.
|
// Create command lists for swap chain back buffer state transitions.
|
||||||
for (uint32_t i = 0; i < kFrameQueueLength; ++i) {
|
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
|
||||||
swap_command_lists_begin_[i] = CommandList::Create(
|
swap_command_lists_begin_[i] = CommandList::Create(
|
||||||
device, direct_queue, D3D12_COMMAND_LIST_TYPE_DIRECT);
|
device, direct_queue, D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||||
swap_command_lists_end_[i] = CommandList::Create(
|
swap_command_lists_end_[i] = CommandList::Create(
|
||||||
|
@ -113,9 +120,17 @@ bool D3D12Context::Initialize() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the immediate mode drawer if not offscreen.
|
||||||
|
immediate_drawer_ = std::make_unique<D3D12ImmediateDrawer>(this);
|
||||||
|
if (!immediate_drawer_->Initialize()) {
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized_fully_ = true;
|
initialized_fully_ = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D12Context::InitializeSwapChainBuffers() {
|
bool D3D12Context::InitializeSwapChainBuffers() {
|
||||||
|
@ -132,7 +147,7 @@ bool D3D12Context::InitializeSwapChainBuffers() {
|
||||||
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();
|
swap_chain_back_buffer_index_ = swap_chain_->GetCurrentBackBufferIndex();
|
||||||
|
|
||||||
// Create RTV descriptors for the swap chain buffers.
|
// Create RTV descriptors for the swap chain buffers.
|
||||||
auto device = static_cast<D3D12Provider*>(provider_)->GetDevice();
|
auto device = GetD3D12Provider()->GetDevice();
|
||||||
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
|
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc;
|
||||||
rtv_desc.Format = kSwapChainFormat;
|
rtv_desc.Format = kSwapChainFormat;
|
||||||
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
|
||||||
|
@ -142,6 +157,8 @@ bool D3D12Context::InitializeSwapChainBuffers() {
|
||||||
device->CreateRenderTargetView(swap_chain_buffers_[i], &rtv_desc,
|
device->CreateRenderTargetView(swap_chain_buffers_[i], &rtv_desc,
|
||||||
GetSwapChainBufferRTV(i));
|
GetSwapChainBufferRTV(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Context::Shutdown() {
|
void D3D12Context::Shutdown() {
|
||||||
|
@ -154,7 +171,7 @@ void D3D12Context::Shutdown() {
|
||||||
immediate_drawer_.reset();
|
immediate_drawer_.reset();
|
||||||
|
|
||||||
if (swap_chain_ != nullptr) {
|
if (swap_chain_ != nullptr) {
|
||||||
for (uint32_t i = 0; i < kFrameQueueLength; ++i) {
|
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
|
||||||
swap_command_lists_end_[i].reset();
|
swap_command_lists_end_[i].reset();
|
||||||
swap_command_lists_begin_[i].reset();
|
swap_command_lists_begin_[i].reset();
|
||||||
}
|
}
|
||||||
|
@ -176,7 +193,7 @@ void D3D12Context::Shutdown() {
|
||||||
swap_chain_->Release();
|
swap_chain_->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t i = 0; i < kFrameQueueLength; ++i) {
|
for (uint32_t i = 0; i < kQueuedFrames; ++i) {
|
||||||
fences_[i].reset();
|
fences_[i].reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,10 +214,14 @@ void D3D12Context::BeginSwap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Await the availability of transient objects for the new frame.
|
// Await the availability of transient objects for the new frame.
|
||||||
// The frame number is incremented in EndSwap so they can be treated the same
|
// The frame number is incremented in EndSwap so it can be treated the same
|
||||||
// way both when inside a frame and when outside of it (it's tied to actual
|
// way both when inside a frame and when outside of it (it's tied to actual
|
||||||
// submissions).
|
// submissions).
|
||||||
fences_[current_queue_frame_]->Await();
|
fences_[current_queue_frame_]->Await();
|
||||||
|
// Update the completed frame if didn't explicitly await all queued frames.
|
||||||
|
if (last_completed_frame_ + kQueuedFrames < current_frame_) {
|
||||||
|
last_completed_frame_ = current_frame_ - kQueuedFrames;
|
||||||
|
}
|
||||||
|
|
||||||
if (target_window_ != nullptr) {
|
if (target_window_ != nullptr) {
|
||||||
// Resize the swap chain if the window is resized.
|
// Resize the swap chain if the window is resized.
|
||||||
|
@ -282,9 +303,10 @@ void D3D12Context::EndSwap() {
|
||||||
// Go to the next transient object frame.
|
// Go to the next transient object frame.
|
||||||
fences_[current_queue_frame_]->Enqueue();
|
fences_[current_queue_frame_]->Enqueue();
|
||||||
++current_queue_frame_;
|
++current_queue_frame_;
|
||||||
if (current_queue_frame_ >= kFrameQueueLength) {
|
if (current_queue_frame_ >= kQueuedFrames) {
|
||||||
current_queue_frame_ -= kFrameQueueLength;
|
current_queue_frame_ -= kQueuedFrames;
|
||||||
}
|
}
|
||||||
|
++current_frame_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<RawImage> D3D12Context::Capture() {
|
std::unique_ptr<RawImage> D3D12Context::Capture() {
|
||||||
|
@ -294,19 +316,18 @@ std::unique_ptr<RawImage> D3D12Context::Capture() {
|
||||||
|
|
||||||
void D3D12Context::AwaitAllFramesCompletion() {
|
void D3D12Context::AwaitAllFramesCompletion() {
|
||||||
// Await the last frame since previous frames must be completed before it.
|
// Await the last frame since previous frames must be completed before it.
|
||||||
uint32_t await_frame = current_queue_frame_ + (kFrameQueueLength - 1);
|
uint32_t await_frame = current_queue_frame_ + (kQueuedFrames - 1);
|
||||||
if (await_frame >= kFrameQueueLength) {
|
if (await_frame >= kQueuedFrames) {
|
||||||
await_frame -= kFrameQueueLength;
|
await_frame -= kQueuedFrames;
|
||||||
}
|
}
|
||||||
fences_[await_frame]->Await();
|
fences_[await_frame]->Await();
|
||||||
|
last_completed_frame_ = current_frame_ - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE D3D12Context::GetSwapChainBufferRTV(
|
D3D12_CPU_DESCRIPTOR_HANDLE D3D12Context::GetSwapChainBufferRTV(
|
||||||
uint32_t buffer_index) const {
|
uint32_t buffer_index) const {
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE handle = swap_chain_rtv_heap_start_;
|
D3D12_CPU_DESCRIPTOR_HANDLE handle = swap_chain_rtv_heap_start_;
|
||||||
handle.ptr +=
|
handle.ptr += buffer_index * GetD3D12Provider()->GetDescriptorSizeRTV();
|
||||||
buffer_index *
|
|
||||||
static_cast<const D3D12Provider*>(provider_)->GetDescriptorSizeRTV();
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,20 @@
|
||||||
#ifndef XENIA_UI_D3D12_D3D12_CONTEXT_H_
|
#ifndef XENIA_UI_D3D12_D3D12_CONTEXT_H_
|
||||||
#define XENIA_UI_D3D12_D3D12_CONTEXT_H_
|
#define XENIA_UI_D3D12_D3D12_CONTEXT_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "xenia/ui/d3d12/command_list.h"
|
#include "xenia/ui/d3d12/command_list.h"
|
||||||
#include "xenia/ui/d3d12/cpu_fence.h"
|
#include "xenia/ui/d3d12/cpu_fence.h"
|
||||||
#include "xenia/ui/d3d12/d3d12_api.h"
|
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||||
|
#include "xenia/ui/d3d12/d3d12_provider.h"
|
||||||
#include "xenia/ui/graphics_context.h"
|
#include "xenia/ui/graphics_context.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
namespace d3d12 {
|
namespace d3d12 {
|
||||||
|
|
||||||
|
class D3D12ImmediateDrawer;
|
||||||
|
|
||||||
class D3D12Context : public GraphicsContext {
|
class D3D12Context : public GraphicsContext {
|
||||||
public:
|
public:
|
||||||
~D3D12Context() override;
|
~D3D12Context() override;
|
||||||
|
@ -36,9 +41,17 @@ class D3D12Context : public GraphicsContext {
|
||||||
|
|
||||||
std::unique_ptr<RawImage> Capture() override;
|
std::unique_ptr<RawImage> Capture() override;
|
||||||
|
|
||||||
|
D3D12Provider* GetD3D12Provider() const {
|
||||||
|
return static_cast<D3D12Provider*>(provider_);
|
||||||
|
}
|
||||||
|
|
||||||
// The count of copies of transient objects (like command lists, dynamic
|
// The count of copies of transient objects (like command lists, dynamic
|
||||||
// descriptor heaps) that must be kept when rendering with this context.
|
// descriptor heaps) that must be kept when rendering with this context.
|
||||||
static constexpr uint32_t kFrameQueueLength = 3;
|
static constexpr uint32_t kQueuedFrames = 3;
|
||||||
|
// The current absolute frame number.
|
||||||
|
uint64_t GetCurrentFrame() { return current_frame_; }
|
||||||
|
// The last completed frame - it's fine to destroy objects used in it.
|
||||||
|
uint64_t GetLastCompletedFrame() { return last_completed_frame_; }
|
||||||
uint32_t GetCurrentQueueFrame() { return current_queue_frame_; }
|
uint32_t GetCurrentQueueFrame() { return current_queue_frame_; }
|
||||||
void AwaitAllFramesCompletion();
|
void AwaitAllFramesCompletion();
|
||||||
|
|
||||||
|
@ -51,6 +64,9 @@ class D3D12Context : public GraphicsContext {
|
||||||
}
|
}
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE GetSwapChainBufferRTV(
|
D3D12_CPU_DESCRIPTOR_HANDLE GetSwapChainBufferRTV(
|
||||||
uint32_t buffer_index) const;
|
uint32_t buffer_index) const;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE GetSwapChainBackBufferRTV() const {
|
||||||
|
return GetSwapChainBufferRTV(GetSwapChainBackBufferIndex());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class D3D12Provider;
|
friend class D3D12Provider;
|
||||||
|
@ -66,8 +82,10 @@ class D3D12Context : public GraphicsContext {
|
||||||
|
|
||||||
bool context_lost_ = false;
|
bool context_lost_ = false;
|
||||||
|
|
||||||
uint32_t current_queue_frame_ = 0;
|
uint64_t current_frame_ = 1;
|
||||||
std::unique_ptr<CPUFence> fences_[kFrameQueueLength] = {};
|
uint64_t last_completed_frame_ = 0;
|
||||||
|
uint32_t current_queue_frame_ = 1;
|
||||||
|
std::unique_ptr<CPUFence> fences_[kQueuedFrames] = {};
|
||||||
|
|
||||||
static constexpr uint32_t kSwapChainBufferCount = 3;
|
static constexpr uint32_t kSwapChainBufferCount = 3;
|
||||||
IDXGISwapChain3* swap_chain_ = nullptr;
|
IDXGISwapChain3* swap_chain_ = nullptr;
|
||||||
|
@ -76,9 +94,8 @@ class D3D12Context : public GraphicsContext {
|
||||||
uint32_t swap_chain_back_buffer_index_ = 0;
|
uint32_t swap_chain_back_buffer_index_ = 0;
|
||||||
ID3D12DescriptorHeap* swap_chain_rtv_heap_ = nullptr;
|
ID3D12DescriptorHeap* swap_chain_rtv_heap_ = nullptr;
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE swap_chain_rtv_heap_start_;
|
D3D12_CPU_DESCRIPTOR_HANDLE swap_chain_rtv_heap_start_;
|
||||||
std::unique_ptr<CommandList> swap_command_lists_begin_[kFrameQueueLength] =
|
std::unique_ptr<CommandList> swap_command_lists_begin_[kQueuedFrames] = {};
|
||||||
{};
|
std::unique_ptr<CommandList> swap_command_lists_end_[kQueuedFrames] = {};
|
||||||
std::unique_ptr<CommandList> swap_command_lists_end_[kFrameQueueLength] = {};
|
|
||||||
|
|
||||||
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_ = nullptr;
|
std::unique_ptr<D3D12ImmediateDrawer> immediate_drawer_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,171 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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/d3d12_immediate_drawer.h"
|
||||||
|
|
||||||
|
#include "xenia/base/logging.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace ui {
|
||||||
|
namespace d3d12 {
|
||||||
|
|
||||||
|
class D3D12ImmediateTexture : public ImmediateTexture {
|
||||||
|
public:
|
||||||
|
D3D12ImmediateTexture(uint32_t width, uint32_t height)
|
||||||
|
: ImmediateTexture(width, height) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
D3D12ImmediateDrawer::D3D12ImmediateDrawer(D3D12Context* graphics_context)
|
||||||
|
: ImmediateDrawer(graphics_context), context_(graphics_context) {}
|
||||||
|
|
||||||
|
D3D12ImmediateDrawer::~D3D12ImmediateDrawer() { Shutdown(); }
|
||||||
|
|
||||||
|
bool D3D12ImmediateDrawer::Initialize() {
|
||||||
|
auto provider = context_->GetD3D12Provider();
|
||||||
|
auto device = provider->GetDevice();
|
||||||
|
|
||||||
|
// Create the samplers.
|
||||||
|
D3D12_DESCRIPTOR_HEAP_DESC sampler_heap_desc;
|
||||||
|
sampler_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER;
|
||||||
|
sampler_heap_desc.NumDescriptors = uint32_t(SamplerIndex::kSamplerCount);
|
||||||
|
sampler_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||||
|
sampler_heap_desc.NodeMask = 0;
|
||||||
|
if (FAILED(device->CreateDescriptorHeap(&sampler_heap_desc,
|
||||||
|
IID_PPV_ARGS(&sampler_heap_)))) {
|
||||||
|
XELOGE("Failed to create immediate drawer sampler descriptor heap");
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sampler_heap_cpu_start_ = sampler_heap_->GetCPUDescriptorHandleForHeapStart();
|
||||||
|
sampler_heap_gpu_start_ = sampler_heap_->GetGPUDescriptorHandleForHeapStart();
|
||||||
|
uint32_t sampler_size = provider->GetDescriptorSizeSampler();
|
||||||
|
// Nearest neighbor, clamp.
|
||||||
|
D3D12_SAMPLER_DESC sampler_desc;
|
||||||
|
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||||
|
sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||||
|
sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||||
|
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||||
|
sampler_desc.MipLODBias = 0.0f;
|
||||||
|
sampler_desc.MaxAnisotropy = 1;
|
||||||
|
sampler_desc.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
||||||
|
sampler_desc.BorderColor[0] = 0.0f;
|
||||||
|
sampler_desc.BorderColor[1] = 0.0f;
|
||||||
|
sampler_desc.BorderColor[2] = 0.0f;
|
||||||
|
sampler_desc.BorderColor[3] = 0.0f;
|
||||||
|
sampler_desc.MinLOD = 0.0f;
|
||||||
|
sampler_desc.MaxLOD = 0.0f;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE sampler_handle;
|
||||||
|
sampler_handle.ptr = sampler_heap_cpu_start_.ptr +
|
||||||
|
uint32_t(SamplerIndex::kNearestClamp) * sampler_size;
|
||||||
|
device->CreateSampler(&sampler_desc, sampler_handle);
|
||||||
|
// Bilinear, clamp.
|
||||||
|
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
sampler_handle.ptr = sampler_heap_cpu_start_.ptr +
|
||||||
|
uint32_t(SamplerIndex::kLinearClamp) * sampler_size;
|
||||||
|
device->CreateSampler(&sampler_desc, sampler_handle);
|
||||||
|
// Nearest neighbor, repeat.
|
||||||
|
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_POINT;
|
||||||
|
sampler_desc.AddressU = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
sampler_desc.AddressV = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
sampler_desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_WRAP;
|
||||||
|
sampler_handle.ptr = sampler_heap_cpu_start_.ptr +
|
||||||
|
uint32_t(SamplerIndex::kNearestRepeat) * sampler_size;
|
||||||
|
device->CreateSampler(&sampler_desc, sampler_handle);
|
||||||
|
// Bilinear, repeat.
|
||||||
|
sampler_desc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
|
sampler_handle.ptr = sampler_heap_cpu_start_.ptr +
|
||||||
|
uint32_t(SamplerIndex::kLinearRepeat) * sampler_size;
|
||||||
|
device->CreateSampler(&sampler_desc, sampler_handle);
|
||||||
|
|
||||||
|
// Create the command lists.
|
||||||
|
ID3D12CommandQueue* direct_queue = provider->GetDirectQueue();
|
||||||
|
for (uint32_t i = 0; i < D3D12Context::kQueuedFrames; ++i) {
|
||||||
|
command_lists_[i] = CommandList::Create(device, direct_queue,
|
||||||
|
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||||
|
if (command_lists_[i] == nullptr) {
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ImmediateDrawer::Shutdown() {
|
||||||
|
for (auto& texture_upload : texture_uploads_submitted_) {
|
||||||
|
texture_upload.data_resource->Release();
|
||||||
|
}
|
||||||
|
texture_uploads_submitted_.clear();
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < D3D12Context::kQueuedFrames; ++i) {
|
||||||
|
command_lists_[i].reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sampler_heap_ != nullptr) {
|
||||||
|
sampler_heap_->Release();
|
||||||
|
sampler_heap_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ImmediateTexture> D3D12ImmediateDrawer::CreateTexture(
|
||||||
|
uint32_t width, uint32_t height, ImmediateTextureFilter filter, bool repeat,
|
||||||
|
const uint8_t* data) {
|
||||||
|
// TODO(Triang3l): Implement CreateTexture.
|
||||||
|
auto texture = std::make_unique<D3D12ImmediateTexture>(width, height);
|
||||||
|
return std::unique_ptr<ImmediateTexture>(texture.release());
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ImmediateDrawer::UpdateTexture(ImmediateTexture* texture,
|
||||||
|
const uint8_t* data) {
|
||||||
|
// TODO(Triang3l): Implement UpdateTexture.
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ImmediateDrawer::Begin(int render_target_width,
|
||||||
|
int render_target_height) {
|
||||||
|
uint32_t queue_frame = context_->GetCurrentQueueFrame();
|
||||||
|
uint64_t last_completed_frame = context_->GetLastCompletedFrame();
|
||||||
|
|
||||||
|
// Remove temporary buffers for completed texture uploads.
|
||||||
|
auto erase_uploads_end = texture_uploads_submitted_.begin();
|
||||||
|
while (erase_uploads_end != texture_uploads_submitted_.end()) {
|
||||||
|
uint64_t upload_frame = erase_uploads_end->frame;
|
||||||
|
if (upload_frame > last_completed_frame) {
|
||||||
|
++erase_uploads_end;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
erase_uploads_end->data_resource->Release();
|
||||||
|
++erase_uploads_end;
|
||||||
|
}
|
||||||
|
texture_uploads_submitted_.erase(texture_uploads_submitted_.begin(),
|
||||||
|
erase_uploads_end);
|
||||||
|
|
||||||
|
// Start a command list recording.
|
||||||
|
ID3D12GraphicsCommandList* command_list =
|
||||||
|
command_lists_[queue_frame]->BeginRecording();
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ImmediateDrawer::BeginDrawBatch(const ImmediateDrawBatch& batch) {
|
||||||
|
// TODO(Triang3l): Implement BeginDrawBatch.
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ImmediateDrawer::Draw(const ImmediateDraw& draw) {
|
||||||
|
// TODO(Triang3l): Implement Draw.
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ImmediateDrawer::EndDrawBatch() {
|
||||||
|
// TODO(Triang3l): Implement EndDrawBatch.
|
||||||
|
}
|
||||||
|
|
||||||
|
void D3D12ImmediateDrawer::End() {
|
||||||
|
command_lists_[context_->GetCurrentQueueFrame()]->Execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace d3d12
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace xe
|
|
@ -0,0 +1,72 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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_D3D12_IMMEDIATE_DRAWER_H_
|
||||||
|
#define XENIA_UI_D3D12_D3D12_IMMEDIATE_DRAWER_H_
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "xenia/ui/d3d12/command_list.h"
|
||||||
|
#include "xenia/ui/d3d12/d3d12_api.h"
|
||||||
|
#include "xenia/ui/d3d12/d3d12_context.h"
|
||||||
|
#include "xenia/ui/immediate_drawer.h"
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace ui {
|
||||||
|
namespace d3d12 {
|
||||||
|
|
||||||
|
class D3D12ImmediateDrawer : public ImmediateDrawer {
|
||||||
|
public:
|
||||||
|
D3D12ImmediateDrawer(D3D12Context* graphics_context);
|
||||||
|
~D3D12ImmediateDrawer() override;
|
||||||
|
|
||||||
|
bool Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
std::unique_ptr<ImmediateTexture> CreateTexture(
|
||||||
|
uint32_t width, uint32_t height, ImmediateTextureFilter filter,
|
||||||
|
bool repeat, const uint8_t* data) override;
|
||||||
|
void UpdateTexture(ImmediateTexture* texture, const uint8_t* data) override;
|
||||||
|
|
||||||
|
void Begin(int render_target_width, int render_target_height) override;
|
||||||
|
void BeginDrawBatch(const ImmediateDrawBatch& batch) override;
|
||||||
|
void Draw(const ImmediateDraw& draw) override;
|
||||||
|
void EndDrawBatch() override;
|
||||||
|
void End();
|
||||||
|
|
||||||
|
private:
|
||||||
|
D3D12Context* context_ = nullptr;
|
||||||
|
|
||||||
|
enum class SamplerIndex {
|
||||||
|
kNearestClamp,
|
||||||
|
kLinearClamp,
|
||||||
|
kNearestRepeat,
|
||||||
|
kLinearRepeat,
|
||||||
|
|
||||||
|
kSamplerCount
|
||||||
|
};
|
||||||
|
ID3D12DescriptorHeap* sampler_heap_ = nullptr;
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE sampler_heap_cpu_start_;
|
||||||
|
D3D12_GPU_DESCRIPTOR_HANDLE sampler_heap_gpu_start_;
|
||||||
|
|
||||||
|
std::unique_ptr<CommandList> command_lists_[D3D12Context::kQueuedFrames] = {};
|
||||||
|
|
||||||
|
struct SubmittedTextureUpload {
|
||||||
|
ID3D12Resource* data_resource;
|
||||||
|
uint64_t frame;
|
||||||
|
};
|
||||||
|
std::deque<SubmittedTextureUpload> texture_uploads_submitted_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace d3d12
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
#endif // XENIA_UI_D3D12_D3D12_IMMEDIATE_DRAWER_H_
|
|
@ -14,7 +14,7 @@
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/ui/d3d12/d3d12_context.h"
|
#include "xenia/ui/d3d12/d3d12_context.h"
|
||||||
|
|
||||||
DEFINE_bool(d3d12_debug, false, "Enable Direct3D 12 and DXGI debug layer.");
|
DEFINE_bool(d3d12_debug, true, "Enable Direct3D 12 and DXGI debug layer.");
|
||||||
DEFINE_int32(d3d12_adapter_index, -1, "Index of the DXGI adapter to use. "
|
DEFINE_int32(d3d12_adapter_index, -1, "Index of the DXGI adapter to use. "
|
||||||
"-1 for any physical adapter, -2 for WARP software rendering.");
|
"-1 for any physical adapter, -2 for WARP software rendering.");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue