[D3D12] Move fences to a separate class, get rid of Vulkan provider

This commit is contained in:
Triang3l 2018-07-19 14:03:52 +03:00
parent d7701ae86b
commit ffcf18f193
5 changed files with 135 additions and 31 deletions

View File

@ -10,7 +10,7 @@
#include "xenia/gpu/d3d12/d3d12_graphics_system.h" #include "xenia/gpu/d3d12/d3d12_graphics_system.h"
#include "xenia/gpu/d3d12/d3d12_command_processor.h" #include "xenia/gpu/d3d12/d3d12_command_processor.h"
#include "xenia/ui/vulkan/vulkan_provider.h" #include "xenia/ui/d3d12/d3d12_provider.h"
#include "xenia/xbox.h" #include "xenia/xbox.h"
namespace xe { namespace xe {
@ -24,9 +24,7 @@ D3D12GraphicsSystem::~D3D12GraphicsSystem() {}
X_STATUS D3D12GraphicsSystem::Setup(cpu::Processor* processor, X_STATUS D3D12GraphicsSystem::Setup(cpu::Processor* processor,
kernel::KernelState* kernel_state, kernel::KernelState* kernel_state,
ui::Window* target_window) { ui::Window* target_window) {
// This is a null graphics system, but we still setup vulkan because UI needs provider_ = xe::ui::d3d12::D3D12Provider::Create(target_window);
// it through us :|
provider_ = xe::ui::vulkan::VulkanProvider::Create(target_window);
return GraphicsSystem::Setup(processor, kernel_state, target_window); return GraphicsSystem::Setup(processor, kernel_state, target_window);
} }

View File

@ -0,0 +1,75 @@
/**
******************************************************************************
* 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/cpu_fence.h"
#include "xenia/base/logging.h"
namespace xe {
namespace ui {
namespace d3d12 {
std::unique_ptr<CPUFence>
CPUFence::Create(ID3D12Device* device, ID3D12CommandQueue* queue) {
std::unique_ptr<CPUFence> fence(new CPUFence(device, queue));
if (!fence->Initialize()) {
return nullptr;
}
return fence;
}
CPUFence::CPUFence(ID3D12Device* device, ID3D12CommandQueue* queue)
: device_(device), queue_(queue) {}
CPUFence::~CPUFence() {
// First destroying the fence because it may reference the event.
if (fence_ != nullptr) {
fence_->Release();
}
if (completion_event_ != nullptr) {
CloseHandle(completion_event_);
}
}
bool CPUFence::Initialize() {
if (FAILED(device_->CreateFence(0, D3D12_FENCE_FLAG_NONE,
IID_PPV_ARGS(&fence_)))) {
XELOGE("Failed to create a Direct3D fence");
return false;
}
completion_event_ = CreateEvent(nullptr, false, false, nullptr);
if (completion_event_ == nullptr) {
XELOGE("Failed to create a fence completion event");
fence_->Release();
fence_ = nullptr;
return false;
}
queued_value_ = 0;
return true;
}
void CPUFence::Enqueue() {
++queued_value_;
queue_->Signal(fence_, queued_value_);
}
bool CPUFence::IsCompleted() {
return fence_->GetCompletedValue() >= queued_value_;
}
void CPUFence::Await() {
if (fence_->GetCompletedValue() < queued_value_) {
fence_->SetEventOnCompletion(queued_value_, completion_event_);
WaitForSingleObject(completion_event_, INFINITE);
}
}
} // namespace d3d12
} // namespace ui
} // namespace xe

View File

@ -0,0 +1,52 @@
/**
******************************************************************************
* 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_CPU_FENCE_H_
#define XENIA_UI_D3D12_CPU_FENCE_H_
#include <memory>
#include "xenia/ui/d3d12/d3d12_api.h"
namespace xe {
namespace ui {
namespace d3d12 {
class CPUFence {
public:
~CPUFence();
static std::unique_ptr<CPUFence> Create(ID3D12Device* device,
ID3D12CommandQueue* queue);
// Submits the fence to the GPU command queue.
void Enqueue();
// Immediately returns whether the GPU has reached the fence.
bool IsCompleted();
// Blocks until the fence has been reached.
void Await();
private:
CPUFence::CPUFence(ID3D12Device* device, ID3D12CommandQueue* queue);
bool Initialize();
ID3D12Device* device_;
ID3D12CommandQueue* queue_;
ID3D12Fence* fence_ = nullptr;
HANDLE completion_event_ = nullptr;
uint64_t queued_value_ = 0;
};
} // namespace d3d12
} // namespace ui
} // namespace xe
#endif // XENIA_UI_D3D12_CPU_FENCE_H_

View File

@ -27,26 +27,18 @@ bool D3D12Context::Initialize() {
auto provider = static_cast<D3D12Provider*>(provider_); auto provider = static_cast<D3D12Provider*>(provider_);
auto dxgi_factory = provider->get_dxgi_factory(); auto dxgi_factory = provider->get_dxgi_factory();
auto device = provider->get_device(); auto device = provider->get_device();
auto direct_queue = provider->get_direct_queue();
context_lost_ = false; context_lost_ = false;
// 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 < kFrameQueueLength; ++i) {
auto& fence = fences_[i]; fences_[i] = CPUFence::Create(device, direct_queue);
if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE, if (fences_[i] == nullptr) {
IID_PPV_ARGS(&fence.fence)))) {
XELOGE("Failed to create a frame completion fence");
Shutdown(); Shutdown();
return false; return false;
} }
fence.completion_event = CreateEvent(nullptr, false, false, nullptr);
if (fence.completion_event == nullptr) {
XELOGE("Failed to create a frame completion event");
Shutdown();
return false;
}
fence.queued_value = 0;
} }
if (target_window_) { if (target_window_) {
@ -114,15 +106,7 @@ void D3D12Context::Shutdown() {
} }
for (uint32_t i = 0; i < kFrameQueueLength; ++i) { for (uint32_t i = 0; i < kFrameQueueLength; ++i) {
auto& fence = fences_[i]; fences_[i].reset();
if (fence.fence != nullptr) {
fence.fence->Release();
fence.fence = nullptr;
}
if (fence.completion_event != nullptr) {
CloseHandle(fence.completion_event);
fence.completion_event = nullptr;
}
} }
} }

View File

@ -10,6 +10,7 @@
#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 "xenia/ui/d3d12/cpu_fence.h"
#include "xenia/ui/d3d12/d3d12_api.h" #include "xenia/ui/d3d12/d3d12_api.h"
#include "xenia/ui/graphics_context.h" #include "xenia/ui/graphics_context.h"
@ -48,13 +49,7 @@ class D3D12Context : public GraphicsContext {
bool context_lost_ = false; bool context_lost_ = false;
struct Fence { std::unique_ptr<CPUFence> fences_[kFrameQueueLength] = {};
ID3D12Fence* fence = nullptr;
HANDLE completion_event = nullptr;
// 0 means the fence signal command hasn't been submitted at all yet.
uint64_t queued_value = 0;
};
Fence fences_[kFrameQueueLength];
static constexpr uint32_t kSwapChainBufferCount = 3; static constexpr uint32_t kSwapChainBufferCount = 3;
IDXGISwapChain3* swap_chain_ = nullptr; IDXGISwapChain3* swap_chain_ = nullptr;