forked from dolphin-emu/dolphin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
38 changed files
with
5,132 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -336,6 +336,7 @@ if(WIN32) | |
) | ||
target_link_libraries(core PUBLIC | ||
videod3d | ||
videod3d12 | ||
setupapi.lib | ||
iphlpapi.lib | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
// Copyright 2019 Dolphin Emulator Project | ||
// Licensed under GPLv2+ | ||
// Refer to the license.txt file included. | ||
|
||
#include "VideoBackends/D3D12/BoundingBox.h" | ||
#include "Common/Logging/Log.h" | ||
#include "VideoBackends/D3D12/DXContext.h" | ||
#include "VideoBackends/D3D12/Renderer.h" | ||
|
||
namespace DX12 | ||
{ | ||
BoundingBox::BoundingBox() = default; | ||
|
||
BoundingBox::~BoundingBox() | ||
{ | ||
if (m_gpu_descriptor) | ||
g_dx_context->GetDescriptorHeapManager().Free(m_gpu_descriptor); | ||
} | ||
|
||
std::unique_ptr<BoundingBox> BoundingBox::Create() | ||
{ | ||
auto bbox = std::unique_ptr<BoundingBox>(new BoundingBox()); | ||
if (!bbox->CreateBuffers()) | ||
return nullptr; | ||
|
||
return bbox; | ||
} | ||
|
||
bool BoundingBox::CreateBuffers() | ||
{ | ||
static constexpr D3D12_HEAP_PROPERTIES gpu_heap_properties = {D3D12_HEAP_TYPE_DEFAULT}; | ||
static constexpr D3D12_HEAP_PROPERTIES cpu_heap_properties = {D3D12_HEAP_TYPE_READBACK}; | ||
D3D12_RESOURCE_DESC buffer_desc = {D3D12_RESOURCE_DIMENSION_BUFFER, | ||
0, | ||
BUFFER_SIZE, | ||
1, | ||
1, | ||
1, | ||
DXGI_FORMAT_UNKNOWN, | ||
{1, 0}, | ||
D3D12_TEXTURE_LAYOUT_ROW_MAJOR, | ||
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS}; | ||
|
||
HRESULT hr = g_dx_context->GetDevice()->CreateCommittedResource( | ||
&gpu_heap_properties, D3D12_HEAP_FLAG_NONE, &buffer_desc, | ||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&m_gpu_buffer)); | ||
CHECK(SUCCEEDED(hr), "Creating bounding box GPU buffer failed"); | ||
if (FAILED(hr) || !g_dx_context->GetDescriptorHeapManager().Allocate(&m_gpu_descriptor)) | ||
return false; | ||
|
||
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {DXGI_FORMAT_R32_SINT, D3D12_UAV_DIMENSION_BUFFER}; | ||
uav_desc.Buffer.NumElements = NUM_VALUES; | ||
g_dx_context->GetDevice()->CreateUnorderedAccessView(m_gpu_buffer.Get(), nullptr, &uav_desc, | ||
m_gpu_descriptor.cpu_handle); | ||
|
||
buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE; | ||
hr = g_dx_context->GetDevice()->CreateCommittedResource( | ||
&cpu_heap_properties, D3D12_HEAP_FLAG_NONE, &buffer_desc, D3D12_RESOURCE_STATE_COPY_DEST, | ||
nullptr, IID_PPV_ARGS(&m_readback_buffer)); | ||
CHECK(SUCCEEDED(hr), "Creating bounding box CPU buffer failed"); | ||
if (FAILED(hr)) | ||
return false; | ||
|
||
if (!m_upload_buffer.AllocateBuffer(STREAM_BUFFER_SIZE)) | ||
return false; | ||
|
||
// Both the CPU and GPU buffer's contents is unknown, so force a flush the first time. | ||
m_values.fill(0); | ||
m_dirty.fill(true); | ||
m_valid = true; | ||
return true; | ||
} | ||
|
||
void BoundingBox::Readback() | ||
{ | ||
// Copy from GPU->CPU buffer, and wait for the GPU to finish the copy. | ||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(), | ||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE); | ||
g_dx_context->GetCommandList()->CopyBufferRegion(m_readback_buffer.Get(), 0, m_gpu_buffer.Get(), | ||
0, BUFFER_SIZE); | ||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(), | ||
D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | ||
Renderer::GetInstance()->ExecuteCommandList(true); | ||
|
||
// Read back to cached values. | ||
static constexpr D3D12_RANGE read_range = {0, BUFFER_SIZE}; | ||
void* mapped_pointer; | ||
HRESULT hr = m_readback_buffer->Map(0, &read_range, &mapped_pointer); | ||
CHECK(SUCCEEDED(hr), "Map bounding box CPU buffer"); | ||
if (FAILED(hr)) | ||
return; | ||
|
||
static constexpr D3D12_RANGE write_range = {0, 0}; | ||
std::array<s32, NUM_VALUES> new_values; | ||
std::memcpy(new_values.data(), mapped_pointer, BUFFER_SIZE); | ||
m_readback_buffer->Unmap(0, &write_range); | ||
|
||
// Preserve dirty values, that way we don't need to sync. | ||
for (u32 i = 0; i < NUM_VALUES; i++) | ||
{ | ||
if (!m_dirty[i]) | ||
m_values[i] = new_values[i]; | ||
} | ||
m_valid = true; | ||
} | ||
|
||
s32 BoundingBox::Get(size_t index) | ||
{ | ||
if (!m_valid) | ||
Readback(); | ||
|
||
return m_values[index]; | ||
} | ||
|
||
void BoundingBox::Set(size_t index, s32 value) | ||
{ | ||
m_values[index] = value; | ||
m_dirty[index] = true; | ||
} | ||
|
||
void BoundingBox::Invalidate() | ||
{ | ||
m_dirty.fill(false); | ||
m_valid = false; | ||
} | ||
|
||
void BoundingBox::Flush() | ||
{ | ||
bool in_copy_state = false; | ||
for (u32 start = 0; start < NUM_VALUES;) | ||
{ | ||
if (!m_dirty[start]) | ||
{ | ||
start++; | ||
continue; | ||
} | ||
|
||
u32 end = start + 1; | ||
m_dirty[start] = false; | ||
for (; end < NUM_VALUES; end++) | ||
{ | ||
if (!m_dirty[end]) | ||
break; | ||
|
||
m_dirty[end] = false; | ||
} | ||
|
||
const u32 copy_size = (end - start) * sizeof(ValueType); | ||
if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(ValueType))) | ||
{ | ||
WARN_LOG(VIDEO, "Executing command list while waiting for space in bbox stream buffer"); | ||
Renderer::GetInstance()->ExecuteCommandList(false); | ||
if (!m_upload_buffer.ReserveMemory(copy_size, sizeof(ValueType))) | ||
{ | ||
PanicAlert("Failed to allocate bbox stream buffer space"); | ||
return; | ||
} | ||
} | ||
|
||
const u32 upload_buffer_offset = m_upload_buffer.GetCurrentOffset(); | ||
std::memcpy(m_upload_buffer.GetCurrentHostPointer(), &m_values[start], copy_size); | ||
m_upload_buffer.CommitMemory(copy_size); | ||
|
||
if (!in_copy_state) | ||
{ | ||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(), | ||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST); | ||
in_copy_state = true; | ||
} | ||
|
||
g_dx_context->GetCommandList()->CopyBufferRegion(m_gpu_buffer.Get(), start * sizeof(ValueType), | ||
m_upload_buffer.GetBuffer(), | ||
upload_buffer_offset, copy_size); | ||
start = end; | ||
} | ||
|
||
if (in_copy_state) | ||
{ | ||
ResourceBarrier(g_dx_context->GetCommandList(), m_gpu_buffer.Get(), | ||
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); | ||
} | ||
} | ||
}; // namespace DX12 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Copyright 2019 Dolphin Emulator Project | ||
// Licensed under GPLv2+ | ||
// Refer to the license.txt file included. | ||
|
||
#pragma once | ||
#include <memory> | ||
#include "VideoBackends/D3D12/Common.h" | ||
#include "VideoBackends/D3D12/DescriptorHeapManager.h" | ||
#include "VideoBackends/D3D12/StreamBuffer.h" | ||
|
||
namespace DX12 | ||
{ | ||
class BoundingBox | ||
{ | ||
public: | ||
~BoundingBox(); | ||
|
||
static std::unique_ptr<BoundingBox> Create(); | ||
|
||
const DescriptorHandle& GetGPUDescriptor() const { return m_gpu_descriptor; } | ||
|
||
s32 Get(size_t index); | ||
void Set(size_t index, s32 value); | ||
|
||
void Invalidate(); | ||
void Flush(); | ||
|
||
private: | ||
using ValueType = s32; | ||
static const u32 NUM_VALUES = 4; | ||
static const u32 BUFFER_SIZE = sizeof(ValueType) * NUM_VALUES; | ||
static const u32 MAX_UPDATES_PER_FRAME = 128; | ||
static const u32 STREAM_BUFFER_SIZE = BUFFER_SIZE * MAX_UPDATES_PER_FRAME; | ||
|
||
BoundingBox(); | ||
|
||
bool CreateBuffers(); | ||
void Readback(); | ||
|
||
// Three buffers: GPU for read/write, CPU for reading back, and CPU for staging changes. | ||
ComPtr<ID3D12Resource> m_gpu_buffer; | ||
ComPtr<ID3D12Resource> m_readback_buffer; | ||
StreamBuffer m_upload_buffer; | ||
DescriptorHandle m_gpu_descriptor; | ||
std::array<ValueType, NUM_VALUES> m_values = {}; | ||
std::array<bool, NUM_VALUES> m_dirty = {}; | ||
bool m_valid = true; | ||
}; | ||
}; // namespace DX12 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
add_library(videod3d12 | ||
BoundingBox.cpp | ||
BoundingBox.h | ||
DescriptorAllocator.cpp | ||
DescriptorAllocator.h | ||
DescriptorHeapManager.cpp | ||
DescriptorHeapManager.h | ||
DXContext.cpp | ||
DXContext.h | ||
DXPipeline.cpp | ||
DXPipeline.h | ||
DXShader.cpp | ||
DXShader.h | ||
DXTexture.cpp | ||
DXTexture.h | ||
DXVertexFormat.cpp | ||
DXVertexFormat.h | ||
PerfQuery.cpp | ||
PerfQuery.h | ||
Renderer.cpp | ||
Renderer.h | ||
StreamBuffer.cpp | ||
StreamBuffer.h | ||
SwapChain.cpp | ||
SwapChain.h | ||
VertexManager.cpp | ||
VertexManager.h | ||
VideoBackend.cpp | ||
VideoBackend.h | ||
) | ||
|
||
target_link_libraries(videod3d12 | ||
PUBLIC | ||
common | ||
videocommon | ||
videod3dcommon | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright 2019 Dolphin Emulator Project | ||
// Licensed under GPLv2+ | ||
// Refer to the license.txt file included. | ||
#pragma once | ||
|
||
#include <d3d12.h> | ||
#include <wrl/client.h> | ||
|
||
#include "Common/MsgHandler.h" | ||
#include "VideoBackends/D3DCommon/Common.h" | ||
|
||
#define CHECK(cond, Message, ...) \ | ||
if (!(cond)) \ | ||
{ \ | ||
PanicAlert(__FUNCTION__ " failed in %s at line %d: " Message, __FILE__, __LINE__, \ | ||
__VA_ARGS__); \ | ||
} | ||
|
||
namespace DX12 | ||
{ | ||
using Microsoft::WRL::ComPtr; | ||
|
||
static void ResourceBarrier(ID3D12GraphicsCommandList* cmdlist, ID3D12Resource* resource, | ||
D3D12_RESOURCE_STATES from_state, D3D12_RESOURCE_STATES to_state) | ||
{ | ||
const D3D12_RESOURCE_BARRIER barrier = { | ||
D3D12_RESOURCE_BARRIER_TYPE_TRANSITION, | ||
D3D12_RESOURCE_BARRIER_FLAG_NONE, | ||
{{resource, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, from_state, to_state}}}; | ||
cmdlist->ResourceBarrier(1, &barrier); | ||
} | ||
} // namespace DX12 |
Oops, something went wrong.