[D3D12] Move fences to a separate class, get rid of Vulkan provider
This commit is contained in:
parent
d7701ae86b
commit
ffcf18f193
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue