[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_command_processor.h"
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
#include "xenia/ui/d3d12/d3d12_provider.h"
|
||||
#include "xenia/xbox.h"
|
||||
|
||||
namespace xe {
|
||||
|
@ -24,9 +24,7 @@ D3D12GraphicsSystem::~D3D12GraphicsSystem() {}
|
|||
X_STATUS D3D12GraphicsSystem::Setup(cpu::Processor* processor,
|
||||
kernel::KernelState* kernel_state,
|
||||
ui::Window* target_window) {
|
||||
// This is a null graphics system, but we still setup vulkan because UI needs
|
||||
// it through us :|
|
||||
provider_ = xe::ui::vulkan::VulkanProvider::Create(target_window);
|
||||
provider_ = xe::ui::d3d12::D3D12Provider::Create(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 dxgi_factory = provider->get_dxgi_factory();
|
||||
auto device = provider->get_device();
|
||||
auto direct_queue = provider->get_direct_queue();
|
||||
|
||||
context_lost_ = false;
|
||||
|
||||
// Create fences for synchronization of reuse and destruction of transient
|
||||
// objects (like command lists) and for global shutdown.
|
||||
for (uint32_t i = 0; i < kFrameQueueLength; ++i) {
|
||||
auto& fence = fences_[i];
|
||||
if (FAILED(device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
|
||||
IID_PPV_ARGS(&fence.fence)))) {
|
||||
XELOGE("Failed to create a frame completion fence");
|
||||
fences_[i] = CPUFence::Create(device, direct_queue);
|
||||
if (fences_[i] == nullptr) {
|
||||
Shutdown();
|
||||
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_) {
|
||||
|
@ -114,15 +106,7 @@ void D3D12Context::Shutdown() {
|
|||
}
|
||||
|
||||
for (uint32_t i = 0; i < kFrameQueueLength; ++i) {
|
||||
auto& fence = fences_[i];
|
||||
if (fence.fence != nullptr) {
|
||||
fence.fence->Release();
|
||||
fence.fence = nullptr;
|
||||
}
|
||||
if (fence.completion_event != nullptr) {
|
||||
CloseHandle(fence.completion_event);
|
||||
fence.completion_event = nullptr;
|
||||
}
|
||||
fences_[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef 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/graphics_context.h"
|
||||
|
||||
|
@ -48,13 +49,7 @@ class D3D12Context : public GraphicsContext {
|
|||
|
||||
bool context_lost_ = false;
|
||||
|
||||
struct Fence {
|
||||
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];
|
||||
std::unique_ptr<CPUFence> fences_[kFrameQueueLength] = {};
|
||||
|
||||
static constexpr uint32_t kSwapChainBufferCount = 3;
|
||||
IDXGISwapChain3* swap_chain_ = nullptr;
|
||||
|
|
Loading…
Reference in New Issue