Merge pull request #3713 from stenzek/d3d12-more-fixes
D3D12: Bug fixes, implement bbox, realxfb, perfquery
This commit is contained in:
commit
bb6a04dc8e
|
@ -2,43 +2,151 @@
|
|||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "VideoBackends/D3D12/BoundingBox.h"
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DCommandListManager.h"
|
||||
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
|
||||
#include "VideoBackends/D3D12/D3DStreamBuffer.h"
|
||||
#include "VideoBackends/D3D12/D3DUtil.h"
|
||||
#include "VideoBackends/D3D12/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D12/Render.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
// D3D12TODO: Support bounding box behavior.
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
ID3D11UnorderedAccessView* BBox::GetUAV()
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
return nullptr;
|
||||
}
|
||||
constexpr size_t BBOX_BUFFER_SIZE = sizeof(int) * 4;
|
||||
constexpr size_t BBOX_STREAM_BUFFER_SIZE = BBOX_BUFFER_SIZE * 128;
|
||||
|
||||
static ID3D12Resource* s_bbox_buffer;
|
||||
static ID3D12Resource* s_bbox_staging_buffer;
|
||||
static void* s_bbox_staging_buffer_map;
|
||||
static std::unique_ptr<D3DStreamBuffer> s_bbox_stream_buffer;
|
||||
static D3D12_GPU_DESCRIPTOR_HANDLE s_bbox_descriptor_handle;
|
||||
|
||||
void BBox::Init()
|
||||
{
|
||||
if (g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
}
|
||||
CD3DX12_RESOURCE_DESC buffer_desc(CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, 0));
|
||||
CD3DX12_RESOURCE_DESC staging_buffer_desc(CD3DX12_RESOURCE_DESC::Buffer(BBOX_BUFFER_SIZE, D3D12_RESOURCE_FLAG_NONE, 0));
|
||||
|
||||
CheckHR(D3D::device12->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&buffer_desc,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&s_bbox_buffer)));
|
||||
|
||||
CheckHR(D3D::device12->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&staging_buffer_desc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&s_bbox_staging_buffer)));
|
||||
|
||||
s_bbox_stream_buffer = std::make_unique<D3DStreamBuffer>(BBOX_STREAM_BUFFER_SIZE, BBOX_STREAM_BUFFER_SIZE, nullptr);
|
||||
|
||||
// D3D12 root signature UAV must be raw or structured buffers, not typed. Since we used a typed buffer,
|
||||
// we have to use a descriptor table. Luckily, we only have to allocate this once, and it never changes.
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle;
|
||||
if (!D3D::gpu_descriptor_heap_mgr->Allocate(&cpu_descriptor_handle, &s_bbox_descriptor_handle, nullptr, false))
|
||||
PanicAlert("Failed to create bounding box UAV descriptor");
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC view_desc = { DXGI_FORMAT_R32_SINT, D3D12_UAV_DIMENSION_BUFFER };
|
||||
view_desc.Buffer.FirstElement = 0;
|
||||
view_desc.Buffer.NumElements = 4;
|
||||
view_desc.Buffer.StructureByteStride = 0;
|
||||
view_desc.Buffer.CounterOffsetInBytes = 0;
|
||||
view_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE;
|
||||
D3D::device12->CreateUnorderedAccessView(s_bbox_buffer, nullptr, &view_desc, cpu_descriptor_handle);
|
||||
|
||||
Bind();
|
||||
}
|
||||
|
||||
void BBox::Bind()
|
||||
{
|
||||
D3D::current_command_list->SetGraphicsRootDescriptorTable(DESCRIPTOR_TABLE_PS_UAV, s_bbox_descriptor_handle);
|
||||
}
|
||||
|
||||
void BBox::Invalidate()
|
||||
{
|
||||
if (!s_bbox_staging_buffer_map)
|
||||
return;
|
||||
|
||||
D3D12_RANGE write_range = {};
|
||||
s_bbox_staging_buffer->Unmap(0, &write_range);
|
||||
s_bbox_staging_buffer_map = nullptr;
|
||||
}
|
||||
|
||||
void BBox::Shutdown()
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
Invalidate();
|
||||
|
||||
if (s_bbox_buffer)
|
||||
{
|
||||
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_buffer);
|
||||
s_bbox_buffer = nullptr;
|
||||
}
|
||||
|
||||
if (s_bbox_staging_buffer)
|
||||
{
|
||||
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(s_bbox_staging_buffer);
|
||||
s_bbox_staging_buffer = nullptr;
|
||||
}
|
||||
|
||||
s_bbox_stream_buffer.reset();
|
||||
}
|
||||
|
||||
void BBox::Set(int index, int value)
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
// If the buffer is currently mapped, compare the value, and update the staging buffer.
|
||||
if (s_bbox_staging_buffer_map)
|
||||
{
|
||||
int current_value;
|
||||
memcpy(¤t_value, reinterpret_cast<u8*>(s_bbox_staging_buffer_map) + (index * sizeof(int)), sizeof(int));
|
||||
if (current_value == value)
|
||||
{
|
||||
// Value hasn't changed. So skip updating completely.
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(reinterpret_cast<u8*>(s_bbox_staging_buffer_map) + (index * sizeof(int)), &value, sizeof(int));
|
||||
}
|
||||
|
||||
s_bbox_stream_buffer->AllocateSpaceInBuffer(sizeof(int), sizeof(int));
|
||||
|
||||
// Allocate temporary bytes in upload buffer, then copy to real buffer.
|
||||
memcpy(s_bbox_stream_buffer->GetCPUAddressOfCurrentAllocation(), &value, sizeof(int));
|
||||
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, 0);
|
||||
D3D::current_command_list->CopyBufferRegion(s_bbox_buffer, index * sizeof(int), s_bbox_stream_buffer->GetBuffer(), s_bbox_stream_buffer->GetOffsetOfCurrentAllocation(), sizeof(int));
|
||||
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0);
|
||||
}
|
||||
|
||||
int BBox::Get(int index)
|
||||
{
|
||||
// D3D12TODO: Implement this;
|
||||
return 0;
|
||||
if (!s_bbox_staging_buffer_map)
|
||||
{
|
||||
D3D::command_list_mgr->CPUAccessNotify();
|
||||
|
||||
// Copy from real buffer to staging buffer, then block until we have the results.
|
||||
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_SOURCE, 0);
|
||||
D3D::current_command_list->CopyBufferRegion(s_bbox_staging_buffer, 0, s_bbox_buffer, 0, BBOX_BUFFER_SIZE);
|
||||
D3D::ResourceBarrier(D3D::current_command_list, s_bbox_buffer, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0);
|
||||
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
D3D12_RANGE read_range = { 0, BBOX_BUFFER_SIZE };
|
||||
CheckHR(s_bbox_staging_buffer->Map(0, &read_range, &s_bbox_staging_buffer_map));
|
||||
}
|
||||
|
||||
int value;
|
||||
memcpy(&value, &reinterpret_cast<int*>(s_bbox_staging_buffer_map)[index], sizeof(int));
|
||||
return value;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -11,8 +11,9 @@ namespace DX12
|
|||
class BBox
|
||||
{
|
||||
public:
|
||||
static ID3D11UnorderedAccessView* GetUAV();
|
||||
static void Init();
|
||||
static void Bind();
|
||||
static void Invalidate();
|
||||
static void Shutdown();
|
||||
|
||||
static void Set(int index, int value);
|
||||
|
|
|
@ -67,7 +67,6 @@
|
|||
<ClCompile Include="ShaderCache.cpp" />
|
||||
<ClCompile Include="ShaderConstantsManager.cpp" />
|
||||
<ClCompile Include="StaticShaderCache.cpp" />
|
||||
<ClCompile Include="Television.cpp" />
|
||||
<ClCompile Include="TextureCache.cpp" />
|
||||
<ClCompile Include="VertexManager.cpp" />
|
||||
<ClCompile Include="XFBEncoder.cpp" />
|
||||
|
@ -91,7 +90,6 @@
|
|||
<ClInclude Include="ShaderCache.h" />
|
||||
<ClInclude Include="ShaderConstantsManager.h" />
|
||||
<ClInclude Include="StaticShaderCache.h" />
|
||||
<ClInclude Include="Television.h" />
|
||||
<ClInclude Include="TextureCache.h" />
|
||||
<ClInclude Include="TextureEncoder.h" />
|
||||
<ClInclude Include="VertexManager.h" />
|
||||
|
|
|
@ -39,9 +39,6 @@
|
|||
<ClCompile Include="Render.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Television.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TextureCache.cpp">
|
||||
<Filter>Render</Filter>
|
||||
</ClCompile>
|
||||
|
@ -105,9 +102,6 @@
|
|||
<ClInclude Include="Render.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Television.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TextureCache.h">
|
||||
<Filter>Render</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "VideoBackends/D3D12/D3DDescriptorHeapManager.h"
|
||||
#include "VideoBackends/D3D12/D3DState.h"
|
||||
#include "VideoBackends/D3D12/D3DTexture.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
static const unsigned int SWAP_CHAIN_BUFFER_COUNT = 4;
|
||||
|
@ -72,18 +73,12 @@ static LARGE_INTEGER s_qpc_frequency;
|
|||
|
||||
static ID3D12DebugDevice* s_debug_device12 = nullptr;
|
||||
|
||||
static D3D_FEATURE_LEVEL s_feat_level;
|
||||
static D3DTexture2D* s_backbuf[SWAP_CHAIN_BUFFER_COUNT];
|
||||
static unsigned int s_current_back_buf = 0;
|
||||
static unsigned int s_xres = 0;
|
||||
static unsigned int s_yres = 0;
|
||||
static bool s_frame_in_progress = false;
|
||||
|
||||
static std::vector<DXGI_SAMPLE_DESC> s_aa_modes; // supported AA modes of the current adapter
|
||||
static const D3D_FEATURE_LEVEL s_supported_feature_levels[] = {
|
||||
D3D_FEATURE_LEVEL_11_0
|
||||
};
|
||||
|
||||
HRESULT LoadDXGI()
|
||||
{
|
||||
if (s_dxgi_dll_ref++ > 0)
|
||||
|
@ -233,108 +228,29 @@ void UnloadD3DCompiler()
|
|||
d3d_reflect = nullptr;
|
||||
}
|
||||
|
||||
bool AlertUserIfSelectedAdapterDoesNotSupportD3D12()
|
||||
{
|
||||
HRESULT hr = LoadDXGI();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = LoadD3D();
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// LoadDXGI / LoadD3D display a specific error message,
|
||||
// no need to do that here.
|
||||
return false;
|
||||
}
|
||||
|
||||
IDXGIFactory* factory = nullptr;
|
||||
IDXGIAdapter* adapter = nullptr;
|
||||
ID3D12Device* device = nullptr;
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
|
||||
|
||||
SAFE_RELEASE(device);
|
||||
SAFE_RELEASE(adapter);
|
||||
SAFE_RELEASE(factory);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
UnloadD3D();
|
||||
UnloadDXGI();
|
||||
MessageBoxA(nullptr, "Failed to create a D3D12 device on the selected adapter.\n\nPlease make sure it supports Direct3D 12, and that your graphics drivers are up-to-date.", "Critical error", MB_OK | MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If succeeded, leave DXGI and D3D libraries loaded since we'll use them in Create().
|
||||
return true;
|
||||
}
|
||||
|
||||
// DXGI failed to create factory/enumerate adapter. This should be very uncommon.
|
||||
MessageBoxA(nullptr, "Failed to create enumerate selected adapter. Please select a different graphics adapter.", "Critical error", MB_OK | MB_ICONERROR);
|
||||
SAFE_RELEASE(adapter);
|
||||
SAFE_RELEASE(factory);
|
||||
|
||||
UnloadD3D();
|
||||
UnloadDXGI();
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter)
|
||||
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(ID3D12Device* device)
|
||||
{
|
||||
std::vector<DXGI_SAMPLE_DESC> aa_modes;
|
||||
|
||||
bool d3d12_supported = AlertUserIfSelectedAdapterDoesNotSupportD3D12();
|
||||
|
||||
if (!d3d12_supported)
|
||||
return aa_modes;
|
||||
|
||||
ID3D12Device* device12 = nullptr;
|
||||
d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device12));
|
||||
|
||||
if (device12)
|
||||
{
|
||||
for (int samples = 0; samples < D3D12_MAX_MULTISAMPLE_SAMPLE_COUNT; ++samples)
|
||||
{
|
||||
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS multisample_quality_levels = {};
|
||||
multisample_quality_levels.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
multisample_quality_levels.SampleCount = samples;
|
||||
|
||||
device12->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &multisample_quality_levels, sizeof(multisample_quality_levels));
|
||||
device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &multisample_quality_levels, sizeof(multisample_quality_levels));
|
||||
|
||||
DXGI_SAMPLE_DESC desc;
|
||||
desc.Count = samples;
|
||||
desc.Quality = 0;
|
||||
|
||||
if (multisample_quality_levels.NumQualityLevels > 0)
|
||||
{
|
||||
aa_modes.push_back(desc);
|
||||
}
|
||||
}
|
||||
|
||||
device12->Release();
|
||||
}
|
||||
|
||||
return aa_modes;
|
||||
}
|
||||
|
||||
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter)
|
||||
{
|
||||
return D3D_FEATURE_LEVEL_11_0;
|
||||
}
|
||||
|
||||
HRESULT Create(HWND wnd)
|
||||
{
|
||||
hWnd = wnd;
|
||||
|
@ -346,17 +262,21 @@ HRESULT Create(HWND wnd)
|
|||
s_yres = client.bottom - client.top;
|
||||
|
||||
hr = LoadDXGI();
|
||||
if (SUCCEEDED(hr))
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = LoadD3D();
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = LoadD3DCompiler();
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
UnloadDXGI();
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = LoadD3DCompiler();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
UnloadD3D();
|
||||
UnloadD3DCompiler();
|
||||
UnloadDXGI();
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -364,7 +284,13 @@ HRESULT Create(HWND wnd)
|
|||
IDXGIAdapter* adapter;
|
||||
hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
MessageBox(wnd, _T("Failed to create IDXGIFactory object"), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR);
|
||||
UnloadD3DCompiler();
|
||||
UnloadD3D();
|
||||
UnloadDXGI();
|
||||
return hr;
|
||||
}
|
||||
|
||||
hr = factory->EnumAdapters(g_ActiveConfig.iAdapter, &adapter);
|
||||
if (FAILED(hr))
|
||||
|
@ -372,20 +298,13 @@ HRESULT Create(HWND wnd)
|
|||
// try using the first one
|
||||
hr = factory->EnumAdapters(0, &adapter);
|
||||
if (FAILED(hr))
|
||||
MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
// get supported AA modes
|
||||
s_aa_modes = EnumAAModes(adapter);
|
||||
|
||||
if (std::find_if(
|
||||
s_aa_modes.begin(),
|
||||
s_aa_modes.end(),
|
||||
[](const DXGI_SAMPLE_DESC& desc) {return desc.Count == g_Config.iMultisamples; }
|
||||
) == s_aa_modes.end())
|
||||
{
|
||||
g_Config.iMultisamples = 1;
|
||||
UpdateActiveConfig();
|
||||
MessageBox(wnd, _T("Failed to enumerate adapters"), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR);
|
||||
UnloadD3DCompiler();
|
||||
UnloadD3D();
|
||||
UnloadDXGI();
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC swap_chain_desc = {};
|
||||
|
@ -405,8 +324,6 @@ HRESULT Create(HWND wnd)
|
|||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST) || defined(USE_D3D12_DEBUG_LAYER)
|
||||
// Enabling the debug layer will fail if the Graphics Tools feature is not installed.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
ID3D12Debug* debug_controller;
|
||||
hr = d3d12_get_debug_interface(IID_PPV_ARGS(&debug_controller));
|
||||
if (SUCCEEDED(hr))
|
||||
|
@ -418,18 +335,32 @@ HRESULT Create(HWND wnd)
|
|||
{
|
||||
MessageBox(wnd, _T("WARNING: Failed to enable D3D12 debug layer, please ensure the Graphics Tools feature is installed."), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = d3d12_create_device(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device12));
|
||||
s_feat_level = D3D_FEATURE_LEVEL_11_0;
|
||||
if (FAILED(hr))
|
||||
{
|
||||
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports Direct3D 12 and your drivers are up-to-date."), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR);
|
||||
adapter->Release();
|
||||
UnloadD3DCompiler();
|
||||
UnloadD3D();
|
||||
UnloadDXGI();
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
// Ensure that the chosen AA mode is supported by the device.
|
||||
std::vector<DXGI_SAMPLE_DESC> aa_modes = EnumAAModes(device12);
|
||||
if (std::find_if(
|
||||
aa_modes.begin(),
|
||||
aa_modes.end(),
|
||||
[](const DXGI_SAMPLE_DESC& desc) {return desc.Count == g_Config.iMultisamples; }
|
||||
) == aa_modes.end())
|
||||
{
|
||||
g_Config.iMultisamples = 1;
|
||||
UpdateActiveConfig();
|
||||
}
|
||||
|
||||
D3D12_COMMAND_QUEUE_DESC command_queue_desc = {
|
||||
D3D12_COMMAND_LIST_TYPE_DIRECT, // D3D12_COMMAND_LIST_TYPE Type;
|
||||
0, // INT Priority;
|
||||
|
@ -439,18 +370,10 @@ HRESULT Create(HWND wnd)
|
|||
|
||||
CheckHR(device12->CreateCommandQueue(&command_queue_desc, IID_PPV_ARGS(&command_queue)));
|
||||
|
||||
IDXGIFactory* factory = nullptr;
|
||||
adapter->GetParent(IID_PPV_ARGS(&factory));
|
||||
|
||||
CheckHR(factory->CreateSwapChain(command_queue, &swap_chain_desc, &s_swap_chain));
|
||||
|
||||
s_current_back_buf = 0;
|
||||
|
||||
factory->Release();
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
// Query the monitor refresh rate, to ensure proper Present throttling behavior.
|
||||
DEVMODE dev_mode;
|
||||
memset(&dev_mode, 0, sizeof(DEVMODE));
|
||||
|
@ -466,14 +389,6 @@ HRESULT Create(HWND wnd)
|
|||
{
|
||||
s_monitor_refresh_rate = dev_mode.dmDisplayFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
MessageBox(wnd, _T("Failed to initialize Direct3D.\nMake sure your video card supports Direct3D 12 and your drivers are up-to-date."), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR);
|
||||
SAFE_RELEASE(s_swap_chain);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
ID3D12InfoQueue* info_queue = nullptr;
|
||||
if (SUCCEEDED(device12->QueryInterface(&info_queue)))
|
||||
|
@ -485,8 +400,7 @@ HRESULT Create(HWND wnd)
|
|||
D3D12_MESSAGE_ID id_list[] = {
|
||||
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_DEPTHSTENCILVIEW_NOT_SET, // Benign.
|
||||
D3D12_MESSAGE_ID_CREATEGRAPHICSPIPELINESTATE_RENDERTARGETVIEW_NOT_SET, // Benign.
|
||||
D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH, // Benign.
|
||||
D3D12_MESSAGE_ID_MAP_INVALID_NULLRANGE, // Benign.
|
||||
D3D12_MESSAGE_ID_CREATEINPUTLAYOUT_TYPE_MISMATCH // Benign.
|
||||
};
|
||||
filter.DenyList.NumIDs = ARRAYSIZE(id_list);
|
||||
filter.DenyList.pIDList = id_list;
|
||||
|
@ -505,9 +419,6 @@ HRESULT Create(HWND wnd)
|
|||
if (FAILED(hr))
|
||||
MessageBox(wnd, _T("Failed to associate the window"), _T("Dolphin Direct3D 12 backend"), MB_OK | MB_ICONERROR);
|
||||
|
||||
SAFE_RELEASE(factory);
|
||||
SAFE_RELEASE(adapter)
|
||||
|
||||
CreateDescriptorHeaps();
|
||||
CreateRootSignatures();
|
||||
|
||||
|
@ -528,7 +439,7 @@ HRESULT Create(HWND wnd)
|
|||
CHECK(SUCCEEDED(hr), "Retrieve back buffer texture");
|
||||
|
||||
s_backbuf[i] = new D3DTexture2D(buf12,
|
||||
D3D11_BIND_RENDER_TARGET,
|
||||
TEXTURE_BIND_FLAG_RENDER_TARGET,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
|
@ -545,6 +456,14 @@ HRESULT Create(HWND wnd)
|
|||
|
||||
QueryPerformanceFrequency(&s_qpc_frequency);
|
||||
|
||||
// Render the device name.
|
||||
DXGI_ADAPTER_DESC adapter_desc;
|
||||
CheckHR(adapter->GetDesc(&adapter_desc));
|
||||
OSD::AddMessage(StringFromFormat("Using D3D Adapter: %s.", UTF16ToUTF8(adapter_desc.Description).c_str()));
|
||||
|
||||
SAFE_RELEASE(factory);
|
||||
SAFE_RELEASE(adapter);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -637,7 +556,15 @@ void CreateRootSignatures()
|
|||
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;
|
||||
};
|
||||
|
||||
D3D12_ROOT_PARAMETER root_parameters[6];
|
||||
D3D12_DESCRIPTOR_RANGE desc_range_uav = {
|
||||
D3D12_DESCRIPTOR_RANGE_TYPE_UAV, // D3D12_DESCRIPTOR_RANGE_TYPE RangeType;
|
||||
1, // UINT NumDescriptors;
|
||||
2, // UINT BaseShaderRegister;
|
||||
0, // UINT RegisterSpace;
|
||||
D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND // UINT OffsetInDescriptorsFromTableStart;
|
||||
};
|
||||
|
||||
D3D12_ROOT_PARAMETER root_parameters[NUM_GRAPHICS_ROOT_PARAMETERS];
|
||||
|
||||
root_parameters[DESCRIPTOR_TABLE_PS_SRV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
root_parameters[DESCRIPTOR_TABLE_PS_SRV].DescriptorTable.NumDescriptorRanges = 1;
|
||||
|
@ -669,7 +596,10 @@ void CreateRootSignatures()
|
|||
root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].Descriptor.ShaderRegister = 1;
|
||||
root_parameters[DESCRIPTOR_TABLE_PS_CBVTWO].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
|
||||
// D3D12TODO: Add bounding box UAV to root signature.
|
||||
root_parameters[DESCRIPTOR_TABLE_PS_UAV].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.NumDescriptorRanges = 1;
|
||||
root_parameters[DESCRIPTOR_TABLE_PS_UAV].DescriptorTable.pDescriptorRanges = &desc_range_uav;
|
||||
root_parameters[DESCRIPTOR_TABLE_PS_UAV].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
|
||||
|
||||
D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {};
|
||||
root_signature_desc.pParameters = root_parameters;
|
||||
|
@ -746,9 +676,9 @@ void Close()
|
|||
current_command_list = nullptr;
|
||||
|
||||
// unload DLLs
|
||||
UnloadDXGI();
|
||||
UnloadD3DCompiler();
|
||||
UnloadD3D();
|
||||
UnloadDXGI();
|
||||
}
|
||||
|
||||
const std::string VertexShaderVersionString()
|
||||
|
@ -784,7 +714,7 @@ unsigned int GetBackBufferHeight()
|
|||
// Returns the maximum width/height of a texture.
|
||||
unsigned int GetMaxTextureSize()
|
||||
{
|
||||
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
|
@ -819,7 +749,7 @@ void Reset()
|
|||
CHECK(SUCCEEDED(hr), "Retrieve back buffer texture");
|
||||
|
||||
s_backbuf[i] = new D3DTexture2D(buf12,
|
||||
D3D11_BIND_RENDER_TARGET,
|
||||
TEXTURE_BIND_FLAG_RENDER_TARGET,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <d3d12.h>
|
||||
#include <d3dcompiler.h>
|
||||
#include <dxgi1_4.h>
|
||||
|
@ -44,17 +43,21 @@ class D3DCommandListManager;
|
|||
class D3DDescriptorHeapManager;
|
||||
class D3DTexture2D;
|
||||
|
||||
enum GRAPHICS_ROOT_PARAMETER : u32
|
||||
{
|
||||
DESCRIPTOR_TABLE_PS_SRV,
|
||||
DESCRIPTOR_TABLE_PS_SAMPLER,
|
||||
DESCRIPTOR_TABLE_GS_CBV,
|
||||
DESCRIPTOR_TABLE_VS_CBV,
|
||||
DESCRIPTOR_TABLE_PS_CBVONE,
|
||||
DESCRIPTOR_TABLE_PS_CBVTWO,
|
||||
DESCRIPTOR_TABLE_PS_UAV,
|
||||
NUM_GRAPHICS_ROOT_PARAMETERS
|
||||
};
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
|
||||
#define DESCRIPTOR_TABLE_PS_SRV 0
|
||||
#define DESCRIPTOR_TABLE_PS_SAMPLER 1
|
||||
#define DESCRIPTOR_TABLE_GS_CBV 2
|
||||
#define DESCRIPTOR_TABLE_VS_CBV 3
|
||||
// #define DESCRIPTOR_TABLE_PS_UAV 4
|
||||
#define DESCRIPTOR_TABLE_PS_CBVONE 4
|
||||
#define DESCRIPTOR_TABLE_PS_CBVTWO 5
|
||||
|
||||
HRESULT LoadDXGI();
|
||||
HRESULT LoadD3D();
|
||||
HRESULT LoadD3DCompiler();
|
||||
|
@ -62,10 +65,7 @@ void UnloadDXGI();
|
|||
void UnloadD3D();
|
||||
void UnloadD3DCompiler();
|
||||
|
||||
D3D_FEATURE_LEVEL GetFeatureLevel(IDXGIAdapter* adapter);
|
||||
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(IDXGIAdapter* adapter);
|
||||
|
||||
bool AlertUserIfSelectedAdapterDoesNotSupportD3D12();
|
||||
std::vector<DXGI_SAMPLE_DESC> EnumAAModes(ID3D12Device* device);
|
||||
|
||||
HRESULT Create(HWND wnd);
|
||||
|
||||
|
@ -146,6 +146,8 @@ using CREATEDXGIFACTORY = HRESULT(WINAPI*)(REFIID, void**);
|
|||
extern CREATEDXGIFACTORY create_dxgi_factory;
|
||||
|
||||
using D3D12CREATEDEVICE = HRESULT(WINAPI*)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**);
|
||||
extern D3D12CREATEDEVICE d3d12_create_device;
|
||||
|
||||
using D3D12SERIALIZEROOTSIGNATURE = HRESULT(WINAPI*)(const D3D12_ROOT_SIGNATURE_DESC* pRootSignature, D3D_ROOT_SIGNATURE_VERSION Version, ID3DBlob** ppBlob, ID3DBlob** ppErrorBlob);
|
||||
using D3D12GETDEBUGINTERFACE = HRESULT(WINAPI*)(REFIID riid, void** ppvDebug);
|
||||
|
||||
|
|
|
@ -90,8 +90,6 @@ private:
|
|||
ID3D12GraphicsCommandList* m_backing_command_list;
|
||||
ID3D12QueuedCommandList* m_queued_command_list;
|
||||
|
||||
ID3D12RootSignature* m_default_root_signature;
|
||||
|
||||
UINT m_current_deferred_destruction_list;
|
||||
std::array<std::vector<ID3D12Resource*>, 2> m_deferred_destruction_lists;
|
||||
std::array<UINT64, 2> m_deferred_destruction_list_fences;
|
||||
|
|
|
@ -274,6 +274,45 @@ void ID3D12QueuedCommandList::BackgroundThreadFunction(ID3D12QueuedCommandList*
|
|||
break;
|
||||
}
|
||||
|
||||
case D3DQueueItemType::BeginQuery:
|
||||
{
|
||||
command_list->BeginQuery(
|
||||
reinterpret_cast<D3DQueueItem*>(item)->BeginQuery.pQueryHeap,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->BeginQuery.Type,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->BeginQuery.Index
|
||||
);
|
||||
|
||||
item += BufferOffsetForQueueItemType<BeginQueryArguments>();
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DQueueItemType::EndQuery:
|
||||
{
|
||||
command_list->EndQuery(
|
||||
reinterpret_cast<D3DQueueItem*>(item)->EndQuery.pQueryHeap,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->EndQuery.Type,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->EndQuery.Index
|
||||
);
|
||||
|
||||
item += BufferOffsetForQueueItemType<EndQueryArguments>();
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DQueueItemType::ResolveQueryData:
|
||||
{
|
||||
command_list->ResolveQueryData(
|
||||
reinterpret_cast<D3DQueueItem*>(item)->ResolveQueryData.pQueryHeap,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->ResolveQueryData.Type,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->ResolveQueryData.StartElement,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->ResolveQueryData.ElementCount,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->ResolveQueryData.pDestinationBuffer,
|
||||
reinterpret_cast<D3DQueueItem*>(item)->ResolveQueryData.AlignedDestinationBufferOffset
|
||||
);
|
||||
|
||||
item += BufferOffsetForQueueItemType<ResolveQueryDataArguments>();
|
||||
break;
|
||||
}
|
||||
|
||||
case D3DQueueItemType::CloseCommandList:
|
||||
{
|
||||
CheckHR(command_list->Close());
|
||||
|
@ -804,7 +843,7 @@ void STDMETHODCALLTYPE ID3D12QueuedCommandList::ResolveSubresource(
|
|||
}
|
||||
|
||||
void STDMETHODCALLTYPE ID3D12QueuedCommandList::IASetPrimitiveTopology(
|
||||
_In_ D3D11_PRIMITIVE_TOPOLOGY PrimitiveTopology
|
||||
_In_ D3D12_PRIMITIVE_TOPOLOGY PrimitiveTopology
|
||||
)
|
||||
{
|
||||
// No ignored parameters, no assumptions to DEBUGCHECK.
|
||||
|
@ -818,7 +857,7 @@ void STDMETHODCALLTYPE ID3D12QueuedCommandList::IASetPrimitiveTopology(
|
|||
}
|
||||
|
||||
void STDMETHODCALLTYPE ID3D12QueuedCommandList::RSSetViewports(
|
||||
_In_range_(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count,
|
||||
_In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count,
|
||||
_In_reads_(Count) const D3D12_VIEWPORT* pViewports
|
||||
)
|
||||
{
|
||||
|
@ -838,7 +877,7 @@ void STDMETHODCALLTYPE ID3D12QueuedCommandList::RSSetViewports(
|
|||
}
|
||||
|
||||
void STDMETHODCALLTYPE ID3D12QueuedCommandList::RSSetScissorRects(
|
||||
_In_range_(0, D3D11_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count,
|
||||
_In_range_(0, D3D12_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE) UINT Count,
|
||||
_In_reads_(Count) const D3D12_RECT* pRects
|
||||
)
|
||||
{
|
||||
|
@ -916,8 +955,14 @@ void STDMETHODCALLTYPE ID3D12QueuedCommandList::BeginQuery(
|
|||
_In_ UINT Index
|
||||
)
|
||||
{
|
||||
// Function not implemented yet.
|
||||
DEBUGCHECK(0, "Function not implemented yet.");
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->Type = D3DQueueItemType::BeginQuery;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->BeginQuery.pQueryHeap = pQueryHeap;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->BeginQuery.Type = Type;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->BeginQuery.Index = Index;
|
||||
|
||||
m_queue_array_back += BufferOffsetForQueueItemType<BeginQueryArguments>();
|
||||
|
||||
CheckForOverflow();
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE ID3D12QueuedCommandList::EndQuery(
|
||||
|
@ -926,8 +971,14 @@ void STDMETHODCALLTYPE ID3D12QueuedCommandList::EndQuery(
|
|||
_In_ UINT Index
|
||||
)
|
||||
{
|
||||
// Function not implemented yet.
|
||||
DEBUGCHECK(0, "Function not implemented yet.");
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->Type = D3DQueueItemType::EndQuery;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->EndQuery.pQueryHeap = pQueryHeap;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->EndQuery.Type = Type;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->EndQuery.Index = Index;
|
||||
|
||||
m_queue_array_back += BufferOffsetForQueueItemType<EndQueryArguments>();
|
||||
|
||||
CheckForOverflow();
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE ID3D12QueuedCommandList::ResolveQueryData(
|
||||
|
@ -939,8 +990,17 @@ void STDMETHODCALLTYPE ID3D12QueuedCommandList::ResolveQueryData(
|
|||
_In_ UINT64 AlignedDestinationBufferOffset
|
||||
)
|
||||
{
|
||||
// Function not implemented yet.
|
||||
DEBUGCHECK(0, "Function not implemented yet.");
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->Type = D3DQueueItemType::ResolveQueryData;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->ResolveQueryData.pQueryHeap = pQueryHeap;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->ResolveQueryData.Type = Type;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->ResolveQueryData.StartElement = StartElement;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->ResolveQueryData.ElementCount = ElementCount;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->ResolveQueryData.pDestinationBuffer = pDestinationBuffer;
|
||||
reinterpret_cast<D3DQueueItem*>(m_queue_array_back)->ResolveQueryData.AlignedDestinationBufferOffset = AlignedDestinationBufferOffset;
|
||||
|
||||
m_queue_array_back += BufferOffsetForQueueItemType<ResolveQueryDataArguments>();
|
||||
|
||||
CheckForOverflow();
|
||||
}
|
||||
|
||||
void STDMETHODCALLTYPE ID3D12QueuedCommandList::SetPredication(
|
||||
|
@ -1199,7 +1259,7 @@ void STDMETHODCALLTYPE ID3D12QueuedCommandList::ClearDepthStencilView(
|
|||
_In_reads_opt_(NumRects) const D3D12_RECT* pRect
|
||||
)
|
||||
{
|
||||
DEBUGCHECK(ClearFlags == D3D11_CLEAR_DEPTH, "Error: Invalid assumption in ID3D12QueuedCommandList.");
|
||||
DEBUGCHECK(ClearFlags == D3D12_CLEAR_FLAG_DEPTH, "Error: Invalid assumption in ID3D12QueuedCommandList.");
|
||||
DEBUGCHECK(Depth == 0.0f, "Error: Invalid assumption in ID3D12QueuedCommandList.");
|
||||
DEBUGCHECK(Stencil == 0, "Error: Invalid assumption in ID3D12QueuedCommandList.");
|
||||
DEBUGCHECK(pRect == nullptr, "Error: Invalid assumption in ID3D12QueuedCommandList.");
|
||||
|
|
|
@ -35,6 +35,9 @@ enum D3DQueueItemType
|
|||
SetDescriptorHeaps,
|
||||
ResourceBarrier,
|
||||
ResolveSubresource,
|
||||
BeginQuery,
|
||||
EndQuery,
|
||||
ResolveQueryData,
|
||||
ExecuteCommandList,
|
||||
CloseCommandList,
|
||||
Present,
|
||||
|
@ -170,6 +173,30 @@ struct ResolveSubresourceArguments
|
|||
DXGI_FORMAT Format;
|
||||
};
|
||||
|
||||
struct BeginQueryArguments
|
||||
{
|
||||
ID3D12QueryHeap* pQueryHeap;
|
||||
D3D12_QUERY_TYPE Type;
|
||||
UINT Index;
|
||||
};
|
||||
|
||||
struct EndQueryArguments
|
||||
{
|
||||
ID3D12QueryHeap* pQueryHeap;
|
||||
D3D12_QUERY_TYPE Type;
|
||||
UINT Index;
|
||||
};
|
||||
|
||||
struct ResolveQueryDataArguments
|
||||
{
|
||||
ID3D12QueryHeap* pQueryHeap;
|
||||
D3D12_QUERY_TYPE Type;
|
||||
UINT StartElement;
|
||||
UINT ElementCount;
|
||||
ID3D12Resource* pDestinationBuffer;
|
||||
UINT64 AlignedDestinationBufferOffset;
|
||||
};
|
||||
|
||||
struct CloseCommandListArguments
|
||||
{
|
||||
};
|
||||
|
@ -239,6 +266,9 @@ struct D3DQueueItem
|
|||
SetDescriptorHeapsArguments SetDescriptorHeaps;
|
||||
ResourceBarrierArguments ResourceBarrier;
|
||||
ResolveSubresourceArguments ResolveSubresource;
|
||||
BeginQueryArguments BeginQuery;
|
||||
EndQueryArguments EndQuery;
|
||||
ResolveQueryDataArguments ResolveQueryData;
|
||||
CloseCommandListArguments CloseCommandList;
|
||||
ExecuteCommandListArguments ExecuteCommandList;
|
||||
PresentArguments Present;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace DX12
|
|||
namespace D3D
|
||||
{
|
||||
|
||||
bool CompileShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines, std::string shader_version_string)
|
||||
bool CompileShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MACRO* defines, const std::string& shader_version_string)
|
||||
{
|
||||
ID3D10Blob* shader_buffer = nullptr;
|
||||
ID3D10Blob* error_buffer = nullptr;
|
||||
|
@ -34,21 +34,26 @@ bool CompileShader(const std::string& code, ID3DBlob** blob, const D3D_SHADER_MA
|
|||
|
||||
if (error_buffer)
|
||||
{
|
||||
INFO_LOG(VIDEO, "Shader compiler messages:\n%s\n",
|
||||
WARN_LOG(VIDEO, "Warning generated when compiling %s shader:\n%s\n",
|
||||
shader_version_string.c_str(),
|
||||
static_cast<const char*>(error_buffer->GetBufferPointer()));
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
static int num_failures = 0;
|
||||
std::string filename = StringFromFormat("%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), shader_version_string, num_failures++);
|
||||
std::string filename = StringFromFormat("%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), shader_version_string.c_str(), num_failures++);
|
||||
std::ofstream file;
|
||||
OpenFStream(file, filename, std::ios_base::out);
|
||||
file << code;
|
||||
file << std::endl << "Errors:" << std::endl;
|
||||
file << static_cast<const char*>(error_buffer->GetBufferPointer());
|
||||
file.close();
|
||||
|
||||
PanicAlert("Failed to compile shader: %s\nDebug info (%s):\n%s",
|
||||
filename.c_str(), shader_version_string, static_cast<const char*>(error_buffer->GetBufferPointer()));
|
||||
filename.c_str(),
|
||||
shader_version_string.c_str(),
|
||||
static_cast<const char*>(error_buffer->GetBufferPointer()));
|
||||
|
||||
*blob = nullptr;
|
||||
error_buffer->Release();
|
||||
|
|
|
@ -343,8 +343,8 @@ inline D3D12_DEPTH_STENCIL_DESC StateCache::GetDesc12(ZMode state)
|
|||
D3D12_DEPTH_STENCIL_DESC depthdc;
|
||||
|
||||
depthdc.StencilEnable = FALSE;
|
||||
depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
|
||||
depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
|
||||
depthdc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
|
||||
depthdc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
|
||||
|
||||
D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
|
||||
depthdc.FrontFace = defaultStencilOp;
|
||||
|
|
|
@ -29,7 +29,8 @@ D3DStreamBuffer::~D3DStreamBuffer()
|
|||
{
|
||||
D3D::command_list_mgr->RemoveQueueFenceCallback(this);
|
||||
|
||||
m_buffer->Unmap(0, nullptr);
|
||||
D3D12_RANGE write_range = { 0, m_buffer_size };
|
||||
m_buffer->Unmap(0, &write_range);
|
||||
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer);
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,7 @@ bool D3DStreamBuffer::AllocateSpaceInBuffer(size_t allocation_size, size_t align
|
|||
{
|
||||
CHECK(allocation_size <= m_buffer_max_size, "Error: Requested allocation size in D3DStreamBuffer is greater than max allowed size of backing buffer.");
|
||||
|
||||
if (alignment)
|
||||
if (alignment && m_buffer_offset > 0)
|
||||
{
|
||||
size_t padding = m_buffer_offset % alignment;
|
||||
|
||||
|
@ -94,7 +95,8 @@ void D3DStreamBuffer::AllocateBuffer(size_t size)
|
|||
// First, put existing buffer (if it exists) in deferred destruction list.
|
||||
if (m_buffer)
|
||||
{
|
||||
m_buffer->Unmap(0, nullptr);
|
||||
D3D12_RANGE write_range = { 0, m_buffer_size };
|
||||
m_buffer->Unmap(0, &write_range);
|
||||
D3D::command_list_mgr->DestroyResourceAfterCurrentCommandListExecuted(m_buffer);
|
||||
m_buffer = nullptr;
|
||||
}
|
||||
|
@ -110,7 +112,8 @@ void D3DStreamBuffer::AllocateBuffer(size_t size)
|
|||
)
|
||||
);
|
||||
|
||||
CheckHR(m_buffer->Map(0, nullptr, &m_buffer_cpu_address));
|
||||
D3D12_RANGE read_range = {};
|
||||
CheckHR(m_buffer->Map(0, &read_range, &m_buffer_cpu_address));
|
||||
|
||||
m_buffer_gpu_address = m_buffer->GetGPUVirtualAddress();
|
||||
m_buffer_size = size;
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace DX12
|
|||
namespace D3D
|
||||
{
|
||||
|
||||
constexpr size_t INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE = 4 * 1024 * 1024;
|
||||
constexpr size_t MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE = 64 * 1024 * 1024;
|
||||
|
||||
static std::unique_ptr<D3DStreamBuffer> s_texture_upload_stream_buffer;
|
||||
|
||||
void CleanupPersistentD3DTextureResources()
|
||||
|
@ -32,16 +35,35 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned
|
|||
{
|
||||
const unsigned int upload_size = AlignValue(src_pitch, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * height;
|
||||
|
||||
if (!s_texture_upload_stream_buffer)
|
||||
{
|
||||
s_texture_upload_stream_buffer = std::make_unique<D3DStreamBuffer>(4 * 1024 * 1024, 64 * 1024 * 1024, nullptr);
|
||||
}
|
||||
ID3D12Resource* upload_buffer = nullptr;
|
||||
size_t upload_buffer_offset = 0;
|
||||
u8* dest_data = nullptr;
|
||||
|
||||
bool current_command_list_executed = s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
||||
if (current_command_list_executed)
|
||||
if (upload_size > MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE)
|
||||
{
|
||||
g_renderer->SetViewport();
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
// If the texture is too large to fit in the upload buffer, create a temporary buffer instead.
|
||||
// This will only be the case for large (e.g. 8192x8192) textures from custom texture packs.
|
||||
CheckHR(D3D::device12->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(upload_size),
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&upload_buffer)));
|
||||
|
||||
D3D12_RANGE read_range = {};
|
||||
CheckHR(upload_buffer->Map(0, &read_range, reinterpret_cast<void**>(&dest_data)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!s_texture_upload_stream_buffer)
|
||||
s_texture_upload_stream_buffer = std::make_unique<D3DStreamBuffer>(INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE, nullptr);
|
||||
|
||||
s_texture_upload_stream_buffer->AllocateSpaceInBuffer(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
||||
|
||||
upload_buffer = s_texture_upload_stream_buffer->GetBuffer();
|
||||
upload_buffer_offset = s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation();
|
||||
dest_data = reinterpret_cast<u8*>(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation());
|
||||
}
|
||||
|
||||
ResourceBarrier(current_command_list, texture12, current_resource_state, D3D12_RESOURCE_STATE_COPY_DEST, level);
|
||||
|
@ -51,9 +73,8 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned
|
|||
u64 upload_row_size_in_bytes = 0;
|
||||
u64 upload_total_bytes = 0;
|
||||
|
||||
D3D::device12->GetCopyableFootprints(&texture12->GetDesc(), level, 1, s_texture_upload_stream_buffer->GetOffsetOfCurrentAllocation(), &upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes);
|
||||
D3D::device12->GetCopyableFootprints(&texture12->GetDesc(), level, 1, upload_buffer_offset, &upload_footprint, &upload_rows, &upload_row_size_in_bytes, &upload_total_bytes);
|
||||
|
||||
u8* dest_data = reinterpret_cast<u8*>(s_texture_upload_stream_buffer->GetCPUAddressOfCurrentAllocation());
|
||||
const u8* src_data = reinterpret_cast<const u8*>(buffer);
|
||||
for (u32 y = 0; y < upload_rows; ++y)
|
||||
{
|
||||
|
@ -64,14 +85,26 @@ void ReplaceRGBATexture2D(ID3D12Resource* texture12, const u8* buffer, unsigned
|
|||
);
|
||||
}
|
||||
|
||||
D3D::current_command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(texture12, level), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(s_texture_upload_stream_buffer->GetBuffer(), upload_footprint), nullptr);
|
||||
D3D::current_command_list->CopyTextureRegion(&CD3DX12_TEXTURE_COPY_LOCATION(texture12, level), 0, 0, 0, &CD3DX12_TEXTURE_COPY_LOCATION(upload_buffer, upload_footprint), nullptr);
|
||||
|
||||
ResourceBarrier(D3D::current_command_list, texture12, D3D12_RESOURCE_STATE_COPY_DEST, current_resource_state, level);
|
||||
|
||||
// Release temporary buffer after commands complete.
|
||||
// We block here because otherwise if there was a large number of texture uploads, we may run out of memory.
|
||||
if (!s_texture_upload_stream_buffer || upload_buffer != s_texture_upload_stream_buffer->GetBuffer())
|
||||
{
|
||||
D3D12_RANGE write_range = { 0, upload_size };
|
||||
upload_buffer->Unmap(0, &write_range);
|
||||
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
upload_buffer->Release();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, D3D12_SUBRESOURCE_DATA* data)
|
||||
D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, u32 bind, DXGI_FORMAT fmt, unsigned int levels, unsigned int slices, D3D12_SUBRESOURCE_DATA* data)
|
||||
{
|
||||
ID3D12Resource* texture12 = nullptr;
|
||||
|
||||
|
@ -86,7 +119,7 @@ D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D1
|
|||
D3D12_CLEAR_VALUE optimized_clear_value = {};
|
||||
optimized_clear_value.Format = fmt;
|
||||
|
||||
if (bind & D3D11_BIND_RENDER_TARGET)
|
||||
if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET)
|
||||
{
|
||||
texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
|
||||
optimized_clear_value.Color[0] = 0.0f;
|
||||
|
@ -95,7 +128,7 @@ D3DTexture2D* D3DTexture2D::Create(unsigned int width, unsigned int height, D3D1
|
|||
optimized_clear_value.Color[3] = 1.0f;
|
||||
}
|
||||
|
||||
if (bind & D3D11_BIND_DEPTH_STENCIL)
|
||||
if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL)
|
||||
{
|
||||
texdesc12.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
|
||||
optimized_clear_value.DepthStencil.Depth = 0.0f;
|
||||
|
@ -181,7 +214,7 @@ D3D12_CPU_DESCRIPTOR_HANDLE D3DTexture2D::GetRTV12() const
|
|||
return m_rtv12;
|
||||
}
|
||||
|
||||
D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind,
|
||||
D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, u32 bind,
|
||||
DXGI_FORMAT srv_format, DXGI_FORMAT dsv_format, DXGI_FORMAT rtv_format, bool multisampled, D3D12_RESOURCE_STATES resource_state)
|
||||
: m_tex12(texptr), m_resource_state(resource_state), m_multisampled(multisampled)
|
||||
{
|
||||
|
@ -189,7 +222,7 @@ D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind,
|
|||
D3D12_DSV_DIMENSION dsv_dim12 = multisampled ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
|
||||
D3D12_RTV_DIMENSION rtv_dim12 = multisampled ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
|
||||
|
||||
if (bind & D3D11_BIND_SHADER_RESOURCE)
|
||||
if (bind & TEXTURE_BIND_FLAG_SHADER_RESOURCE)
|
||||
{
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {
|
||||
srv_format, // DXGI_FORMAT Format
|
||||
|
@ -216,7 +249,7 @@ D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind,
|
|||
D3D::device12->CreateShaderResourceView(m_tex12, &srv_desc, m_srv12_gpu_cpu_shadow);
|
||||
}
|
||||
|
||||
if (bind & D3D11_BIND_DEPTH_STENCIL)
|
||||
if (bind & TEXTURE_BIND_FLAG_DEPTH_STENCIL)
|
||||
{
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {
|
||||
dsv_format, // DXGI_FORMAT Format
|
||||
|
@ -233,7 +266,7 @@ D3DTexture2D::D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind,
|
|||
D3D::device12->CreateDepthStencilView(m_tex12, &dsv_desc, m_dsv12);
|
||||
}
|
||||
|
||||
if (bind & D3D11_BIND_RENDER_TARGET)
|
||||
if (bind & TEXTURE_BIND_FLAG_RENDER_TARGET)
|
||||
{
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {
|
||||
rtv_format, // DXGI_FORMAT Format
|
||||
|
|
|
@ -5,11 +5,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <d3d11.h>
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
enum TEXTURE_BIND_FLAG : u32
|
||||
{
|
||||
TEXTURE_BIND_FLAG_SHADER_RESOURCE = (1 << 0),
|
||||
TEXTURE_BIND_FLAG_RENDER_TARGET = (1 << 1),
|
||||
TEXTURE_BIND_FLAG_DEPTH_STENCIL = (1 << 2)
|
||||
};
|
||||
|
||||
namespace D3D
|
||||
{
|
||||
void ReplaceRGBATexture2D(ID3D12Resource* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int src_pitch, unsigned int level, D3D12_RESOURCE_STATES current_resource_state = D3D12_RESOURCE_STATE_COMMON);
|
||||
|
@ -24,8 +30,8 @@ public:
|
|||
// either create an ID3D12Resource object, pass it to the constructor and specify what views to create
|
||||
// or let the texture automatically be created by D3DTexture2D::Create
|
||||
|
||||
D3DTexture2D(ID3D12Resource* texptr, D3D11_BIND_FLAG bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false, D3D12_RESOURCE_STATES resource_state = D3D12_RESOURCE_STATE_COMMON);
|
||||
static D3DTexture2D* Create(unsigned int width, unsigned int height, D3D11_BIND_FLAG bind, D3D11_USAGE usage, DXGI_FORMAT, unsigned int levels = 1, unsigned int slices = 1, D3D12_SUBRESOURCE_DATA* data = nullptr);
|
||||
D3DTexture2D(ID3D12Resource* texptr, u32 bind, DXGI_FORMAT srv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT dsv_format = DXGI_FORMAT_UNKNOWN, DXGI_FORMAT rtv_format = DXGI_FORMAT_UNKNOWN, bool multisampled = false, D3D12_RESOURCE_STATES resource_state = D3D12_RESOURCE_STATE_COMMON);
|
||||
static D3DTexture2D* Create(unsigned int width, unsigned int height, u32 bind, DXGI_FORMAT fmt, unsigned int levels = 1, unsigned int slices = 1, D3D12_SUBRESOURCE_DATA* data = nullptr);
|
||||
void TransitionToResourceState(ID3D12GraphicsCommandList* command_list, D3D12_RESOURCE_STATES state_after);
|
||||
|
||||
// reference counting, use AddRef() when creating a new reference and Release() it when you don't need it anymore
|
||||
|
|
|
@ -26,11 +26,6 @@ namespace DX12
|
|||
namespace D3D
|
||||
{
|
||||
|
||||
unsigned int AlignValue(unsigned int value, unsigned int alignment)
|
||||
{
|
||||
return (value + (alignment - 1)) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
void ResourceBarrier(ID3D12GraphicsCommandList* command_list, ID3D12Resource* resource, D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after, UINT subresource)
|
||||
{
|
||||
if (state_before == state_after)
|
||||
|
@ -104,7 +99,6 @@ private:
|
|||
|
||||
CD3DFont font;
|
||||
static std::unique_ptr<UtilVertexBuffer> util_vbuf_stq;
|
||||
static std::unique_ptr<UtilVertexBuffer> util_vbuf_cq;
|
||||
static std::unique_ptr<UtilVertexBuffer> util_vbuf_clearq;
|
||||
static std::unique_ptr<UtilVertexBuffer> util_vbuf_efbpokequads;
|
||||
|
||||
|
@ -502,12 +496,6 @@ struct
|
|||
float u1, v1, u2, v2, S, G;
|
||||
} tex_quad_data;
|
||||
|
||||
struct
|
||||
{
|
||||
float x1, y1, x2, y2, z;
|
||||
u32 col;
|
||||
} draw_quad_data;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 col;
|
||||
|
@ -516,13 +504,11 @@ struct
|
|||
|
||||
// ring buffer offsets
|
||||
static size_t stq_offset;
|
||||
static size_t cq_offset;
|
||||
static size_t clearq_offset;
|
||||
|
||||
void InitUtils()
|
||||
{
|
||||
util_vbuf_stq = std::make_unique<UtilVertexBuffer>(0x10000);
|
||||
util_vbuf_cq = std::make_unique<UtilVertexBuffer>(0x10000);
|
||||
util_vbuf_clearq = std::make_unique<UtilVertexBuffer>(0x10000);
|
||||
util_vbuf_efbpokequads = std::make_unique<UtilVertexBuffer>(0x100000);
|
||||
|
||||
|
@ -560,7 +546,6 @@ void InitUtils()
|
|||
|
||||
// cached data used to avoid unnecessarily reloading the vertex buffers
|
||||
memset(&tex_quad_data, 0, sizeof(tex_quad_data));
|
||||
memset(&draw_quad_data, 0, sizeof(draw_quad_data));
|
||||
memset(&clear_quad_data, 0, sizeof(clear_quad_data));
|
||||
|
||||
font.Init();
|
||||
|
@ -571,7 +556,6 @@ void ShutdownUtils()
|
|||
font.Shutdown();
|
||||
|
||||
util_vbuf_stq.reset();
|
||||
util_vbuf_cq.reset();
|
||||
util_vbuf_clearq.reset();
|
||||
util_vbuf_efbpokequads.reset();
|
||||
}
|
||||
|
@ -588,7 +572,7 @@ void SetLinearCopySampler()
|
|||
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_SAMPLERS, true);
|
||||
}
|
||||
|
||||
void SetViewportAndScissor(u32 top_left_x, u32 top_left_y, u32 width, u32 height, float min_depth, float max_depth)
|
||||
void SetViewportAndScissor(int top_left_x, int top_left_y, int width, int height, float min_depth, float max_depth)
|
||||
{
|
||||
D3D12_VIEWPORT viewport = {
|
||||
static_cast<float>(top_left_x),
|
||||
|
@ -707,89 +691,6 @@ void DrawShadedTexQuad(D3DTexture2D* texture,
|
|||
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true);
|
||||
|
||||
D3D::current_command_list->DrawInstanced(4, 1, static_cast<UINT>(stq_offset), 0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
// Fills a certain area of the current render target with the specified color
|
||||
// destination coordinates normalized to (-1;1)
|
||||
void DrawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2, D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled)
|
||||
{
|
||||
ColVertex coords[4] = {
|
||||
{ x1, y2, z, Color },
|
||||
{ x2, y2, z, Color },
|
||||
{ x1, y1, z, Color },
|
||||
{ x2, y1, z, Color },
|
||||
};
|
||||
|
||||
if (draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 ||
|
||||
draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 ||
|
||||
draw_quad_data.col != Color || draw_quad_data.z != z)
|
||||
{
|
||||
cq_offset = util_vbuf_cq->AppendData(coords, sizeof(coords), sizeof(ColVertex));
|
||||
|
||||
draw_quad_data.x1 = x1;
|
||||
draw_quad_data.y1 = y1;
|
||||
draw_quad_data.x2 = x2;
|
||||
draw_quad_data.y2 = y2;
|
||||
draw_quad_data.col = Color;
|
||||
draw_quad_data.z = z;
|
||||
}
|
||||
|
||||
D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vb_view = {
|
||||
util_vbuf_cq->GetBuffer12()->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
|
||||
static_cast<UINT>(util_vbuf_cq->GetSize()), // UINT SizeInBytes; This is the size of the entire buffer, not just the size of the vertex data for one draw call, since the offsetting is done in the draw call itself.
|
||||
sizeof(ColVertex) // UINT StrideInBytes;
|
||||
};
|
||||
|
||||
D3D::current_command_list->IASetVertexBuffers(0, 1, &vb_view);
|
||||
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_VERTEX_BUFFER, true);
|
||||
|
||||
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = {
|
||||
default_root_signature, // ID3D12RootSignature *pRootSignature;
|
||||
StaticShaderCache::GetClearVertexShader(), // D3D12_SHADER_BYTECODE VS;
|
||||
StaticShaderCache::GetClearPixelShader(), // D3D12_SHADER_BYTECODE PS;
|
||||
{}, // D3D12_SHADER_BYTECODE DS;
|
||||
{}, // D3D12_SHADER_BYTECODE HS;
|
||||
StaticShaderCache::GetClearGeometryShader(), // D3D12_SHADER_BYTECODE GS;
|
||||
{}, // D3D12_STREAM_OUTPUT_DESC StreamOutput
|
||||
*blend_desc, // D3D12_BLEND_DESC BlendState;
|
||||
UINT_MAX, // UINT SampleMask;
|
||||
Renderer::GetResetRasterizerDesc(), // D3D12_RASTERIZER_DESC RasterizerState
|
||||
*depth_stencil_desc, // D3D12_DEPTH_STENCIL_DESC DepthStencilState
|
||||
StaticShaderCache::GetClearVertexShaderInputLayout(), // D3D12_INPUT_LAYOUT_DESC InputLayout
|
||||
D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF, // D3D12_INDEX_BUFFER_PROPERTIES IndexBufferProperties
|
||||
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE, // D3D12_PRIMITIVE_TOPOLOGY_TYPE PrimitiveTopologyType
|
||||
1, // UINT NumRenderTargets
|
||||
{ DXGI_FORMAT_R8G8B8A8_UNORM }, // DXGI_FORMAT RTVFormats[8]
|
||||
DXGI_FORMAT_D32_FLOAT, // DXGI_FORMAT DSVFormat
|
||||
{ 1 /* UINT Count */, 0 /* UINT Quality */ } // DXGI_SAMPLE_DESC SampleDesc
|
||||
};
|
||||
|
||||
if (rt_multisampled)
|
||||
{
|
||||
pso_desc.SampleDesc.Count = g_ActiveConfig.iMultisamples;
|
||||
}
|
||||
|
||||
ID3D12PipelineState* pso = nullptr;
|
||||
CheckHR(DX12::gx_state_cache.GetPipelineStateObjectFromCache(&pso_desc, &pso));
|
||||
|
||||
D3D::current_command_list->SetPipelineState(pso);
|
||||
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true);
|
||||
|
||||
// In D3D11, the 'resetraststate' has ScissorEnable disabled. In D3D12, scissor testing is always enabled.
|
||||
// Thus, set the scissor rect to the max texture size, then reset it to the current scissor rect to avoid
|
||||
// dirtying state.
|
||||
|
||||
// 2 ^ D3D12_MAX_TEXTURE_DIMENSION_2_TO_EXP = 131072
|
||||
D3D::current_command_list->RSSetScissorRects(1, &CD3DX12_RECT(0, 0, 131072, 131072));
|
||||
|
||||
D3D::current_command_list->DrawInstanced(4, 1, static_cast<UINT>(cq_offset), 0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void DrawClearQuad(u32 Color, float z, D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled)
|
||||
|
@ -856,8 +757,6 @@ void DrawClearQuad(u32 Color, float z, D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH
|
|||
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true);
|
||||
|
||||
D3D::current_command_list->DrawInstanced(4, 1, static_cast<UINT>(clearq_offset), 0);
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
static void InitColVertex(ColVertex* vert, float x, float y, float z, u32 col)
|
||||
|
@ -933,6 +832,7 @@ void DrawEFBPokeQuads(EFBAccessType type,
|
|||
// Corresponding dirty flags set outside loop.
|
||||
D3D::current_command_list->OMSetRenderTargets(1, render_target, FALSE, depth_buffer);
|
||||
D3D::current_command_list->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
D3D::command_list_mgr->SetCommandListPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
|
||||
|
||||
D3D12_VERTEX_BUFFER_VIEW vb_view = {
|
||||
util_vbuf_efbpokequads->GetBuffer12()->GetGPUVirtualAddress(), // D3D12_GPU_VIRTUAL_ADDRESS BufferLocation;
|
||||
|
@ -946,9 +846,6 @@ void DrawEFBPokeQuads(EFBAccessType type,
|
|||
D3D::current_command_list->SetPipelineState(pso);
|
||||
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PSO, true);
|
||||
|
||||
// Disable scissor testing.
|
||||
D3D::current_command_list->RSSetScissorRects(1, &CD3DX12_RECT(0, 0, 131072, 131072));
|
||||
|
||||
// generate quads for each efb point
|
||||
ColVertex* base_vertex_ptr = reinterpret_cast<ColVertex*>(buffer_ptr);
|
||||
for (size_t i = 0; i < points_to_draw; i++)
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <d3d11.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
@ -22,7 +21,11 @@ extern StateCache gx_state_cache;
|
|||
namespace D3D
|
||||
{
|
||||
|
||||
unsigned int AlignValue(unsigned int value, unsigned int alignment);
|
||||
constexpr unsigned int AlignValue(unsigned int value, unsigned int alignment)
|
||||
{
|
||||
return (value + (alignment - 1)) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
void ResourceBarrier(ID3D12GraphicsCommandList* command_list, ID3D12Resource* resource, D3D12_RESOURCE_STATES state_before, D3D12_RESOURCE_STATES state_after, UINT subresource);
|
||||
|
||||
// Font creation flags
|
||||
|
@ -74,7 +77,7 @@ void ShutdownUtils();
|
|||
void SetPointCopySampler();
|
||||
void SetLinearCopySampler();
|
||||
|
||||
void SetViewportAndScissor(u32 top_left_x, u32 top_left_y, u32 width, u32 height, float min_depth = D3D12_MIN_DEPTH, float max_depth = D3D12_MAX_DEPTH);
|
||||
void SetViewportAndScissor(int top_left_x, int top_left_y, int width, int height, float min_depth = D3D12_MIN_DEPTH, float max_depth = D3D12_MAX_DEPTH);
|
||||
|
||||
void DrawShadedTexQuad(D3DTexture2D* texture,
|
||||
const D3D12_RECT* source,
|
||||
|
@ -92,7 +95,6 @@ void DrawShadedTexQuad(D3DTexture2D* texture,
|
|||
);
|
||||
|
||||
void DrawClearQuad(u32 Color, float z, D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled);
|
||||
void DrawColorQuad(u32 Color, float z, float x1, float y1, float x2, float y2, D3D12_BLEND_DESC* blend_desc, D3D12_DEPTH_STENCIL_DESC* depth_stencil_desc, bool rt_multisampled);
|
||||
|
||||
void DrawEFBPokeQuads(EFBAccessType type,
|
||||
const EfbPokeData* points,
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
namespace DX12
|
||||
{
|
||||
|
||||
static XFBEncoder s_xfbEncoder;
|
||||
|
||||
FramebufferManager::Efb FramebufferManager::m_efb;
|
||||
unsigned int FramebufferManager::m_target_width;
|
||||
unsigned int FramebufferManager::m_target_height;
|
||||
|
@ -42,7 +40,12 @@ D3DTexture2D*& FramebufferManager::GetResolvedEFBColorTexture()
|
|||
|
||||
for (int i = 0; i < m_efb.slices; i++)
|
||||
{
|
||||
D3D::current_command_list->ResolveSubresource(m_efb.resolved_color_tex->GetTex12(), D3D11CalcSubresource(0, i, 1), m_efb.color_tex->GetTex12(), D3D11CalcSubresource(0, i, 1), DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
D3D::current_command_list->ResolveSubresource(
|
||||
m_efb.resolved_color_tex->GetTex12(),
|
||||
D3D12CalcSubresource(0, i, 0, 1, m_efb.slices),
|
||||
m_efb.color_tex->GetTex12(),
|
||||
D3D12CalcSubresource(0, i, 0, 1, m_efb.slices),
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
}
|
||||
|
||||
m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
|
@ -91,13 +94,13 @@ FramebufferManager::FramebufferManager()
|
|||
texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
|
||||
hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueRTV, IID_PPV_ARGS(&buf12));
|
||||
|
||||
m_efb.color_tex = new D3DTexture2D(buf12, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON);
|
||||
m_efb.color_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON);
|
||||
SAFE_RELEASE(buf12);
|
||||
|
||||
// Temporary EFB color texture - used in ReinterpretPixelData
|
||||
texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1, sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
|
||||
CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueRTV, IID_PPV_ARGS(&buf12)));
|
||||
m_efb.color_temp_tex = new D3DTexture2D(buf12, (D3D11_BIND_FLAG)(D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET), DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON);
|
||||
m_efb.color_temp_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON);
|
||||
SAFE_RELEASE(buf12);
|
||||
D3D::SetDebugObjectName12(m_efb.color_temp_tex->GetTex12(), "EFB color temp texture");
|
||||
|
||||
|
@ -105,7 +108,7 @@ FramebufferManager::FramebufferManager()
|
|||
texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_TYPELESS, m_target_width, m_target_height, m_efb.slices, 1, sample_desc.Count, sample_desc.Quality, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL);
|
||||
CheckHR(D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_clear_valueDSV, IID_PPV_ARGS(&buf12)));
|
||||
|
||||
m_efb.depth_tex = new D3DTexture2D(buf12, (D3D11_BIND_FLAG)(D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE), DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON);
|
||||
m_efb.depth_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_DEPTH_STENCIL, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_UNKNOWN, (sample_desc.Count > 1), D3D12_RESOURCE_STATE_COMMON);
|
||||
SAFE_RELEASE(buf12);
|
||||
D3D::SetDebugObjectName12(m_efb.depth_tex->GetTex12(), "EFB depth texture");
|
||||
|
||||
|
@ -115,14 +118,14 @@ FramebufferManager::FramebufferManager()
|
|||
texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, m_target_width, m_target_height, m_efb.slices, 1);
|
||||
hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buf12));
|
||||
CHECK(hr == S_OK, "create EFB color resolve texture (size: %dx%d)", m_target_width, m_target_height);
|
||||
m_efb.resolved_color_tex = new D3DTexture2D(buf12, D3D11_BIND_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_COMMON);
|
||||
m_efb.resolved_color_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_COMMON);
|
||||
SAFE_RELEASE(buf12);
|
||||
D3D::SetDebugObjectName12(m_efb.resolved_color_tex->GetTex12(), "EFB color resolve texture shader resource view");
|
||||
|
||||
texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_FLOAT, m_target_width, m_target_height, m_efb.slices, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
|
||||
hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, nullptr, IID_PPV_ARGS(&buf12));
|
||||
CHECK(hr == S_OK, "create EFB depth resolve texture (size: %dx%d; hr=%#x)", m_target_width, m_target_height, hr);
|
||||
m_efb.resolved_depth_tex = new D3DTexture2D(buf12, (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_COMMON);
|
||||
m_efb.resolved_depth_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R32_FLOAT, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, false, D3D12_RESOURCE_STATE_COMMON);
|
||||
SAFE_RELEASE(buf12);
|
||||
D3D::SetDebugObjectName12(m_efb.resolved_depth_tex->GetTex12(), "EFB depth resolve texture shader resource view");
|
||||
}
|
||||
|
@ -133,14 +136,10 @@ FramebufferManager::FramebufferManager()
|
|||
}
|
||||
|
||||
InitializeEFBAccessCopies();
|
||||
|
||||
s_xfbEncoder.Init();
|
||||
}
|
||||
|
||||
FramebufferManager::~FramebufferManager()
|
||||
{
|
||||
s_xfbEncoder.Shutdown();
|
||||
|
||||
DestroyEFBAccessCopies();
|
||||
|
||||
SAFE_RELEASE(m_efb.color_tex);
|
||||
|
@ -153,14 +152,16 @@ FramebufferManager::~FramebufferManager()
|
|||
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, float gamma)
|
||||
{
|
||||
u8* dst = Memory::GetPointer(xfbAddr);
|
||||
s_xfbEncoder.Encode(dst, fbStride/2, fbHeight, sourceRc, gamma);
|
||||
D3DTexture2D* src_texture = GetResolvedEFBColorTexture();
|
||||
TargetRectangle scaled_rect = g_renderer->ConvertEFBRectangle(sourceRc);
|
||||
g_xfb_encoder->EncodeTextureToRam(dst, fbStride, fbHeight, src_texture, scaled_rect, m_target_width, m_target_height, gamma);
|
||||
}
|
||||
|
||||
std::unique_ptr<XFBSourceBase> FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers)
|
||||
{
|
||||
return std::make_unique<XFBSource>(D3DTexture2D::Create(target_width, target_height,
|
||||
(D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET|D3D11_BIND_SHADER_RESOURCE),
|
||||
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), layers);
|
||||
TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), layers);
|
||||
}
|
||||
|
||||
void FramebufferManager::GetTargetSize(unsigned int* width, unsigned int* height)
|
||||
|
@ -197,12 +198,18 @@ void FramebufferManager::ResolveDepthTexture()
|
|||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
|
||||
// Restores proper viewport/scissor settings.
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void FramebufferManager::RestoreEFBRenderTargets()
|
||||
{
|
||||
D3D::current_command_list->OMSetRenderTargets(1,
|
||||
&FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE,
|
||||
&FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
}
|
||||
|
||||
u32 FramebufferManager::ReadEFBColorAccessCopy(u32 x, u32 y)
|
||||
{
|
||||
if (!m_efb.color_access_readback_map)
|
||||
|
@ -255,7 +262,7 @@ void FramebufferManager::InitializeEFBAccessCopies()
|
|||
texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0);
|
||||
hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_color_clear_value, IID_PPV_ARGS(&buf12));
|
||||
CHECK(hr == S_OK, "create EFB access color resize buffer (hr=%#x)", hr);
|
||||
m_efb.color_access_resize_tex = new D3DTexture2D(buf12, D3D11_BIND_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
m_efb.color_access_resize_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
D3D::SetDebugObjectName12(m_efb.color_access_resize_tex->GetTex12(), "EFB access color resize buffer");
|
||||
buf12->Release();
|
||||
|
||||
|
@ -269,7 +276,7 @@ void FramebufferManager::InitializeEFBAccessCopies()
|
|||
texdesc12 = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_FLOAT, EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_TEXTURE_LAYOUT_UNKNOWN, 0);
|
||||
hr = D3D::device12->CreateCommittedResource(&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE, &texdesc12, D3D12_RESOURCE_STATE_COMMON, &optimized_depth_clear_value, IID_PPV_ARGS(&buf12));
|
||||
CHECK(hr == S_OK, "create EFB access depth resize buffer (hr=%#x)", hr);
|
||||
m_efb.depth_access_resize_tex = new D3DTexture2D(buf12, D3D11_BIND_RENDER_TARGET, DXGI_FORMAT_R32_FLOAT);
|
||||
m_efb.depth_access_resize_tex = new D3DTexture2D(buf12, TEXTURE_BIND_FLAG_RENDER_TARGET, DXGI_FORMAT_R32_FLOAT);
|
||||
D3D::SetDebugObjectName12(m_efb.color_access_resize_tex->GetTex12(), "EFB access depth resize buffer");
|
||||
buf12->Release();
|
||||
|
||||
|
@ -317,19 +324,16 @@ void FramebufferManager::MapEFBColorAccessCopy()
|
|||
CD3DX12_TEXTURE_COPY_LOCATION src_location(src_resource, 0);
|
||||
D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr);
|
||||
|
||||
// Block until completion
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// Restore EFB resource state if it was sourced from here
|
||||
if (src_resource == m_efb.color_tex->GetTex12())
|
||||
m_efb.color_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
|
||||
// Restore state after resetting command list
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
g_renderer->RestoreAPIState();
|
||||
// Block until completion - state is automatically restored
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// Resource copy has finished, so safe to map now
|
||||
m_efb.color_access_readback_buffer->Map(0, nullptr, reinterpret_cast<void**>(&m_efb.color_access_readback_map));
|
||||
D3D12_RANGE read_range = { 0, m_efb.color_access_readback_pitch * EFB_HEIGHT };
|
||||
m_efb.color_access_readback_buffer->Map(0, &read_range, reinterpret_cast<void**>(&m_efb.color_access_readback_map));
|
||||
}
|
||||
|
||||
void FramebufferManager::MapEFBDepthAccessCopy()
|
||||
|
@ -344,7 +348,7 @@ void FramebufferManager::MapEFBDepthAccessCopy()
|
|||
|
||||
D3D::SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT);
|
||||
D3D::SetPointCopySampler();
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &m_efb.color_access_resize_tex->GetRTV12(), FALSE, nullptr);
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &m_efb.depth_access_resize_tex->GetRTV12(), FALSE, nullptr);
|
||||
|
||||
CD3DX12_RECT src_rect(0, 0, m_target_width, m_target_height);
|
||||
D3D::DrawShadedTexQuad(m_efb.depth_tex, &src_rect, m_target_width, m_target_height,
|
||||
|
@ -369,32 +373,31 @@ void FramebufferManager::MapEFBDepthAccessCopy()
|
|||
CD3DX12_TEXTURE_COPY_LOCATION src_location(src_resource, 0);
|
||||
D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, nullptr);
|
||||
|
||||
// Block until completion
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// Restore EFB resource state if it was sourced from here
|
||||
if (src_resource == m_efb.depth_tex->GetTex12())
|
||||
m_efb.depth_tex->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
|
||||
// Restore state after resetting command list
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
g_renderer->RestoreAPIState();
|
||||
// Block until completion - state is automatically restored
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// Resource copy has finished, so safe to map now
|
||||
m_efb.depth_access_readback_buffer->Map(0, nullptr, reinterpret_cast<void**>(&m_efb.depth_access_readback_map));
|
||||
D3D12_RANGE read_range = { 0, m_efb.depth_access_readback_pitch * EFB_HEIGHT };
|
||||
m_efb.depth_access_readback_buffer->Map(0, &read_range, reinterpret_cast<void**>(&m_efb.depth_access_readback_map));
|
||||
}
|
||||
|
||||
void FramebufferManager::InvalidateEFBAccessCopies()
|
||||
{
|
||||
D3D12_RANGE write_range = {};
|
||||
|
||||
if (m_efb.color_access_readback_map)
|
||||
{
|
||||
m_efb.color_access_readback_buffer->Unmap(0, nullptr);
|
||||
m_efb.color_access_readback_buffer->Unmap(0, &write_range);
|
||||
m_efb.color_access_readback_map = nullptr;
|
||||
}
|
||||
|
||||
if (m_efb.depth_access_readback_map)
|
||||
{
|
||||
m_efb.depth_access_readback_buffer->Unmap(0, nullptr);
|
||||
m_efb.depth_access_readback_buffer->Unmap(0, &write_range);
|
||||
m_efb.depth_access_readback_map = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -414,8 +417,8 @@ void FramebufferManager::DestroyEFBAccessCopies()
|
|||
|
||||
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
// DX12's XFB decoder does not use this function.
|
||||
// YUYV data is decoded in Render::Swap.
|
||||
u8* src = Memory::GetPointer(xfbAddr);
|
||||
g_xfb_encoder->DecodeToTexture(m_tex, src, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
void XFBSource::CopyEFB(float gamma)
|
||||
|
@ -448,7 +451,6 @@ void XFBSource::CopyEFB(float gamma)
|
|||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE );
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
|
||||
// Restores proper viewport/scissor settings.
|
||||
g_renderer->RestoreAPIState();
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
|
||||
static void ResolveDepthTexture();
|
||||
|
||||
static void RestoreEFBRenderTargets();
|
||||
|
||||
// Access EFB from CPU
|
||||
static u32 ReadEFBColorAccessCopy(u32 x, u32 y);
|
||||
static float ReadEFBDepthAccessCopy(u32 x, u32 y);
|
||||
|
|
|
@ -105,7 +105,9 @@ void PSTextureEncoder::Init()
|
|||
|
||||
D3D::SetDebugObjectName12(m_encode_params_buffer, "efb encoder params buffer");
|
||||
|
||||
CheckHR(m_encode_params_buffer->Map(0, nullptr, &m_encode_params_buffer_data));
|
||||
// NOTE: This upload buffer is okay to overwrite each time, since we block until completion when it's used anyway.
|
||||
D3D12_RANGE read_range = {};
|
||||
CheckHR(m_encode_params_buffer->Map(0, &read_range, &m_encode_params_buffer_data));
|
||||
|
||||
m_ready = true;
|
||||
}
|
||||
|
@ -215,11 +217,16 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p
|
|||
D3D::ResourceBarrier(D3D::current_command_list, m_out, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE, 0);
|
||||
D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box);
|
||||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
|
||||
// State is automatically restored after executing command list.
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// Transfer staging buffer to GameCube/Wii RAM
|
||||
void* readback_data_map;
|
||||
CheckHR(m_out_readback_buffer->Map(0, nullptr, &readback_data_map));
|
||||
D3D12_RANGE read_range = { 0, dst_location.PlacedFootprint.Footprint.RowPitch * num_blocks_y };
|
||||
CheckHR(m_out_readback_buffer->Map(0, &read_range, &readback_data_map));
|
||||
|
||||
u8* src = static_cast<u8*>(readback_data_map);
|
||||
u32 read_stride = std::min(bytes_per_row, dst_location.PlacedFootprint.Footprint.RowPitch);
|
||||
|
@ -231,14 +238,8 @@ void PSTextureEncoder::Encode(u8* dst, u32 format, u32 native_width, u32 bytes_p
|
|||
src += dst_location.PlacedFootprint.Footprint.RowPitch;
|
||||
}
|
||||
|
||||
m_out_readback_buffer->Unmap(0, nullptr);
|
||||
|
||||
// Restores proper viewport/scissor settings.
|
||||
g_renderer->RestoreAPIState();
|
||||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE );
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
D3D12_RANGE write_range = {};
|
||||
m_out_readback_buffer->Unmap(0, &write_range);
|
||||
}
|
||||
|
||||
D3D12_SHADER_BYTECODE PSTextureEncoder::SetStaticShader(unsigned int dst_format, PEControl::PixelFormat src_format,
|
||||
|
|
|
@ -2,68 +2,215 @@
|
|||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DCommandListManager.h"
|
||||
#include "VideoBackends/D3D12/PerfQuery.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
//D3D12TODO: Implement PerfQuery class.
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
PerfQuery::PerfQuery()
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
D3D12_QUERY_HEAP_DESC desc = { D3D12_QUERY_HEAP_TYPE_OCCLUSION, PERF_QUERY_BUFFER_SIZE, 0 };
|
||||
CheckHR(D3D::device12->CreateQueryHeap(&desc, IID_PPV_ARGS(&m_query_heap)));
|
||||
|
||||
CheckHR(D3D::device12->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(QUERY_READBACK_BUFFER_SIZE),
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&m_query_readback_buffer)));
|
||||
|
||||
m_tracking_fence = D3D::command_list_mgr->RegisterQueueFenceCallback(this, &PerfQuery::QueueFenceCallback);
|
||||
}
|
||||
|
||||
PerfQuery::~PerfQuery()
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
D3D::command_list_mgr->RemoveQueueFenceCallback(this);
|
||||
|
||||
SAFE_RELEASE(m_query_heap);
|
||||
SAFE_RELEASE(m_query_readback_buffer);
|
||||
}
|
||||
|
||||
void PerfQuery::EnableQuery(PerfQueryGroup type)
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
if (m_query_count > m_query_buffer.size() / 2)
|
||||
WeakFlush();
|
||||
|
||||
// all queries already used?
|
||||
if (m_query_buffer.size() == m_query_count)
|
||||
{
|
||||
FlushOne();
|
||||
//WARN_LOG(VIDEO, "Flushed query buffer early!");
|
||||
}
|
||||
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
size_t index = (m_query_read_pos + m_query_count) % m_query_buffer.size();
|
||||
auto& entry = m_query_buffer[index];
|
||||
|
||||
D3D::current_command_list->BeginQuery(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, static_cast<UINT>(index));
|
||||
entry.query_type = type;
|
||||
entry.fence_value = -1;
|
||||
|
||||
++m_query_count;
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::DisableQuery(PerfQueryGroup type)
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
if (type == PQG_ZCOMP_ZCOMPLOC || type == PQG_ZCOMP)
|
||||
{
|
||||
size_t index = (m_query_read_pos + m_query_count + m_query_buffer.size() - 1) % m_query_buffer.size();
|
||||
auto& entry = m_query_buffer[index];
|
||||
|
||||
D3D::current_command_list->EndQuery(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, static_cast<UINT>(index));
|
||||
D3D::current_command_list->ResolveQueryData(m_query_heap, D3D12_QUERY_TYPE_OCCLUSION, static_cast<UINT>(index), 1, m_query_readback_buffer, index * sizeof(UINT64));
|
||||
entry.fence_value = m_next_fence_value;
|
||||
}
|
||||
}
|
||||
|
||||
void PerfQuery::ResetQuery()
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
m_query_count = 0;
|
||||
std::fill_n(m_results, ArraySize(m_results), 0);
|
||||
}
|
||||
|
||||
u32 PerfQuery::GetQueryResult(PerfQueryType type)
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
return 0;
|
||||
u32 result = 0;
|
||||
|
||||
if (type == PQ_ZCOMP_INPUT_ZCOMPLOC || type == PQ_ZCOMP_OUTPUT_ZCOMPLOC)
|
||||
result = m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
else if (type == PQ_ZCOMP_INPUT || type == PQ_ZCOMP_OUTPUT)
|
||||
result = m_results[PQG_ZCOMP];
|
||||
else if (type == PQ_BLEND_INPUT)
|
||||
result = m_results[PQG_ZCOMP] + m_results[PQG_ZCOMP_ZCOMPLOC];
|
||||
else if (type == PQ_EFB_COPY_CLOCKS)
|
||||
result = m_results[PQG_EFB_COPY_CLOCKS];
|
||||
|
||||
return result / 4;
|
||||
}
|
||||
|
||||
void PerfQuery::FlushOne()
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
size_t index = m_query_read_pos;
|
||||
ActiveQuery& entry = m_query_buffer[index];
|
||||
|
||||
// Has the command list been executed yet?
|
||||
if (entry.fence_value == m_next_fence_value)
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(false);
|
||||
|
||||
// Block until the fence is reached
|
||||
D3D::command_list_mgr->WaitOnCPUForFence(m_tracking_fence, entry.fence_value);
|
||||
|
||||
// Copy from readback buffer to local
|
||||
void* readback_buffer_map;
|
||||
D3D12_RANGE read_range = { sizeof(UINT64) * index, sizeof(UINT64) * (index + 1) };
|
||||
CheckHR(m_query_readback_buffer->Map(0, &read_range, &readback_buffer_map));
|
||||
|
||||
UINT64 result;
|
||||
memcpy(&result, reinterpret_cast<u8*>(readback_buffer_map) + sizeof(UINT64) * index, sizeof(UINT64));
|
||||
|
||||
D3D12_RANGE write_range = {};
|
||||
m_query_readback_buffer->Unmap(0, &write_range);
|
||||
|
||||
// NOTE: Reported pixel metrics should be referenced to native resolution
|
||||
m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight());
|
||||
|
||||
m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
|
||||
m_query_count--;
|
||||
}
|
||||
|
||||
UINT64 PerfQuery::FindLastPendingFenceValue() const
|
||||
{
|
||||
UINT64 last_fence_value = 0;
|
||||
u32 query_count = m_query_count;
|
||||
u32 query_read_pos = m_query_read_pos;
|
||||
while (query_count > 0)
|
||||
{
|
||||
const ActiveQuery& entry = m_query_buffer[query_read_pos];
|
||||
|
||||
last_fence_value = std::max(entry.fence_value, last_fence_value);
|
||||
query_read_pos = (query_read_pos + 1) % m_query_buffer.size();
|
||||
query_count--;
|
||||
}
|
||||
|
||||
return last_fence_value;
|
||||
}
|
||||
|
||||
void PerfQuery::FlushResults()
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
if (IsFlushed())
|
||||
return;
|
||||
|
||||
// Find the fence value we have to wait for.
|
||||
UINT64 last_fence_value = FindLastPendingFenceValue();
|
||||
if (last_fence_value == m_next_fence_value)
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(false);
|
||||
|
||||
// Wait for all queries to be resolved.
|
||||
D3D::command_list_mgr->WaitOnCPUForFence(m_tracking_fence, last_fence_value);
|
||||
|
||||
// Map the whole readback buffer. Shouldn't have much overhead, and saves taking the wrapped-around cases into consideration.
|
||||
void* readback_buffer_map;
|
||||
D3D12_RANGE read_range = { 0, QUERY_READBACK_BUFFER_SIZE };
|
||||
CheckHR(m_query_readback_buffer->Map(0, &read_range, &readback_buffer_map));
|
||||
|
||||
// Read all pending queries.
|
||||
while (m_query_count > 0)
|
||||
{
|
||||
ActiveQuery& entry = m_query_buffer[m_query_read_pos];
|
||||
|
||||
UINT64 result;
|
||||
memcpy(&result, reinterpret_cast<u8*>(readback_buffer_map) + sizeof(UINT64) * m_query_read_pos, sizeof(UINT64));
|
||||
|
||||
// NOTE: Reported pixel metrics should be referenced to native resolution
|
||||
m_results[entry.query_type] += (u32)(result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT / g_renderer->GetTargetHeight());
|
||||
|
||||
m_query_read_pos = (m_query_read_pos + 1) % m_query_buffer.size();
|
||||
m_query_count--;
|
||||
}
|
||||
|
||||
D3D12_RANGE write_range = {};
|
||||
m_query_readback_buffer->Unmap(0, &write_range);
|
||||
}
|
||||
|
||||
void PerfQuery::WeakFlush()
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
UINT64 completed_fence = m_tracking_fence->GetCompletedValue();
|
||||
|
||||
while (!IsFlushed())
|
||||
{
|
||||
ActiveQuery& entry = m_query_buffer[m_query_read_pos];
|
||||
if (entry.fence_value > completed_fence)
|
||||
break;
|
||||
|
||||
FlushOne();
|
||||
}
|
||||
}
|
||||
|
||||
bool PerfQuery::IsFlushed() const
|
||||
{
|
||||
//D3D12TODO: Add implementation
|
||||
return true;
|
||||
return m_query_count == 0;
|
||||
}
|
||||
|
||||
void PerfQuery::QueueFenceCallback(void* owning_object, UINT64 fence_value)
|
||||
{
|
||||
PerfQuery* owning_perf_query = static_cast<PerfQuery*>(owning_object);
|
||||
owning_perf_query->QueueFence(fence_value);
|
||||
}
|
||||
|
||||
void PerfQuery::QueueFence(UINT64 fence_value)
|
||||
{
|
||||
m_next_fence_value = fence_value + 1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <d3d12.h>
|
||||
|
||||
#include "VideoCommon/PerfQueryBase.h"
|
||||
|
||||
|
@ -27,20 +28,33 @@ public:
|
|||
private:
|
||||
struct ActiveQuery
|
||||
{
|
||||
ID3D11Query* query;
|
||||
PerfQueryGroup query_type;
|
||||
UINT64 fence_value;
|
||||
};
|
||||
|
||||
void WeakFlush();
|
||||
|
||||
// Find the last fence value of all pending queries.
|
||||
UINT64 FindLastPendingFenceValue() const;
|
||||
|
||||
// Only use when non-empty
|
||||
void FlushOne();
|
||||
|
||||
// when testing in SMS: 64 was too small, 128 was ok
|
||||
static const int s_perf_query_buffer_size = 512;
|
||||
static void QueueFenceCallback(void* owning_object, UINT64 fence_value);
|
||||
void QueueFence(UINT64 fence_value);
|
||||
|
||||
std::array<ActiveQuery, s_perf_query_buffer_size> m_query_buffer;
|
||||
// when testing in SMS: 64 was too small, 128 was ok
|
||||
static constexpr size_t PERF_QUERY_BUFFER_SIZE = 512;
|
||||
static constexpr size_t QUERY_READBACK_BUFFER_SIZE = PERF_QUERY_BUFFER_SIZE * sizeof(UINT64);
|
||||
|
||||
std::array<ActiveQuery, PERF_QUERY_BUFFER_SIZE> m_query_buffer;
|
||||
int m_query_read_pos = 0;
|
||||
|
||||
ID3D12QueryHeap* m_query_heap = nullptr;
|
||||
ID3D12Resource* m_query_readback_buffer = nullptr;
|
||||
|
||||
ID3D12Fence* m_tracking_fence = nullptr;
|
||||
UINT64 m_next_fence_value = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include "VideoBackends/D3D12/ShaderCache.h"
|
||||
#include "VideoBackends/D3D12/ShaderConstantsManager.h"
|
||||
#include "VideoBackends/D3D12/StaticShaderCache.h"
|
||||
#include "VideoBackends/D3D12/Television.h"
|
||||
#include "VideoBackends/D3D12/TextureCache.h"
|
||||
|
||||
#include "VideoCommon/AVIDump.h"
|
||||
|
@ -50,8 +49,6 @@ static u32 s_last_multisamples = 1;
|
|||
static bool s_last_stereo_mode = false;
|
||||
static bool s_last_xfb_mode = false;
|
||||
|
||||
static Television s_television;
|
||||
|
||||
enum CLEAR_BLEND_DESC
|
||||
{
|
||||
CLEAR_BLEND_DESC_ALL_CHANNELS_ENABLED = 0,
|
||||
|
@ -104,8 +101,6 @@ StateCache gx_state_cache;
|
|||
|
||||
static void SetupDeviceObjects()
|
||||
{
|
||||
s_television.Init();
|
||||
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
|
||||
D3D12_DEPTH_STENCIL_DESC depth_desc;
|
||||
|
@ -175,8 +170,6 @@ static void TeardownDeviceObjects()
|
|||
s_screenshot_texture = nullptr;
|
||||
}
|
||||
|
||||
s_television.Shutdown();
|
||||
|
||||
gx_state_cache.Clear();
|
||||
}
|
||||
|
||||
|
@ -231,8 +224,6 @@ Renderer::Renderer(void*& window_handle)
|
|||
return;
|
||||
}
|
||||
|
||||
D3D::Create((HWND)window_handle);
|
||||
|
||||
s_backbuffer_width = D3D::GetBackBufferWidth();
|
||||
s_backbuffer_height = D3D::GetBackBufferHeight();
|
||||
|
||||
|
@ -252,7 +243,7 @@ Renderer::Renderer(void*& window_handle)
|
|||
|
||||
// Setup GX pipeline state
|
||||
gx_state.blend.blend_enable = false;
|
||||
gx_state.blend.write_mask = D3D11_COLOR_WRITE_ENABLE_ALL;
|
||||
gx_state.blend.write_mask = D3D12_COLOR_WRITE_ENABLE_ALL;
|
||||
gx_state.blend.src_blend = D3D12_BLEND_ONE;
|
||||
gx_state.blend.dst_blend = D3D12_BLEND_ZERO;
|
||||
gx_state.blend.blend_op = D3D12_BLEND_OP_ADD;
|
||||
|
@ -280,7 +271,7 @@ Renderer::Renderer(void*& window_handle)
|
|||
D3D::current_command_list->RSSetViewports(1, &vp);
|
||||
|
||||
// Already transitioned to appropriate states a few lines up for the clears.
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
FramebufferManager::RestoreEFBRenderTargets();
|
||||
|
||||
D3D::BeginFrame();
|
||||
}
|
||||
|
@ -290,7 +281,6 @@ Renderer::~Renderer()
|
|||
D3D::EndFrame();
|
||||
D3D::WaitForOutstandingRenderingToComplete();
|
||||
TeardownDeviceObjects();
|
||||
D3D::Close();
|
||||
}
|
||||
|
||||
void Renderer::RenderText(const std::string& text, int left, int top, u32 color)
|
||||
|
@ -534,7 +524,8 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha
|
|||
D3D::DrawClearQuad(rgba_color, 1.0f - (z & 0xFFFFFF) / 16777216.0f, blend_desc, depth_stencil_desc, FramebufferManager::GetEFBColorTexture()->GetMultisampled());
|
||||
|
||||
// Restores proper viewport/scissor settings.
|
||||
g_renderer->RestoreAPIState();
|
||||
g_renderer->SetViewport();
|
||||
BPFunctions::SetScissor();
|
||||
|
||||
FramebufferManager::InvalidateEFBAccessCopies();
|
||||
}
|
||||
|
@ -582,14 +573,13 @@ void Renderer::ReinterpretPixelData(unsigned int convtype)
|
|||
FramebufferManager::GetEFBColorTempTexture()->GetMultisampled()
|
||||
);
|
||||
|
||||
// Restores proper viewport/scissor settings.
|
||||
g_renderer->RestoreAPIState();
|
||||
|
||||
FramebufferManager::SwapReinterpretTexture();
|
||||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE );
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
|
||||
// Restores proper viewport/scissor settings.
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
void Renderer::SetBlendMode(bool force_update)
|
||||
|
@ -675,11 +665,13 @@ bool Renderer::SaveScreenshot(const std::string& filename, const TargetRectangle
|
|||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
void* screenshot_texture_map;
|
||||
CheckHR(s_screenshot_texture->Map(0, nullptr, &screenshot_texture_map));
|
||||
D3D12_RANGE read_range = { 0, dst_location.PlacedFootprint.Footprint.RowPitch * (source_box.bottom - source_box.top) };
|
||||
CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map));
|
||||
|
||||
saved_png = TextureToPng(static_cast<u8*>(screenshot_texture_map), dst_location.PlacedFootprint.Footprint.RowPitch, filename, source_box.right - source_box.left, source_box.bottom - source_box.top, false);
|
||||
|
||||
s_screenshot_texture->Unmap(0, nullptr);
|
||||
D3D12_RANGE write_range = {};
|
||||
s_screenshot_texture->Unmap(0, &write_range);
|
||||
|
||||
if (saved_png)
|
||||
{
|
||||
|
@ -735,6 +727,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
|
||||
// Invalidate EFB access copies. Not strictly necessary, but this avoids having the buffers mapped when calling Present().
|
||||
FramebufferManager::InvalidateEFBAccessCopies();
|
||||
BBox::Invalidate();
|
||||
|
||||
// Prepare to copy the XFBs to our backbuffer
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
|
@ -749,15 +742,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
// activate linear filtering for the buffer copies
|
||||
D3D::SetLinearCopySampler();
|
||||
|
||||
if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
// EXISTINGD3D11TODO: Television should be used to render Virtual XFB mode as well.
|
||||
D3D::SetViewportAndScissor(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight());
|
||||
|
||||
s_television.Submit(xfb_addr, fb_stride, fb_width, fb_height);
|
||||
s_television.Render();
|
||||
}
|
||||
else if (g_ActiveConfig.bUseXFB)
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
const XFBSource* xfb_source;
|
||||
|
||||
|
@ -767,12 +752,24 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
xfb_source = static_cast<const XFBSource*>(xfb_source_list[i]);
|
||||
|
||||
TargetRectangle drawRc;
|
||||
TargetRectangle source_rc;
|
||||
source_rc.left = xfb_source->sourceRc.left;
|
||||
source_rc.top = xfb_source->sourceRc.top;
|
||||
source_rc.right = xfb_source->sourceRc.right;
|
||||
source_rc.bottom = xfb_source->sourceRc.bottom;
|
||||
|
||||
// use virtual xfb with offset
|
||||
int xfb_height = xfb_source->srcHeight;
|
||||
int xfb_width = xfb_source->srcWidth;
|
||||
int hOffset = (static_cast<s32>(xfb_source->srcAddr) - static_cast<s32>(xfb_addr)) / (static_cast<s32>(fb_stride) * 2);
|
||||
|
||||
if (g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
drawRc = target_rc;
|
||||
source_rc.right -= fb_stride - fb_width;
|
||||
}
|
||||
else
|
||||
{
|
||||
drawRc.top = target_rc.top + hOffset * target_rc.GetHeight() / static_cast<s32>(fb_height);
|
||||
drawRc.bottom = target_rc.top + (hOffset + xfb_height) * target_rc.GetHeight() / static_cast<s32>(fb_height);
|
||||
drawRc.left = target_rc.left + (target_rc.GetWidth() - xfb_width * target_rc.GetWidth() / static_cast<s32>(fb_stride)) / 2;
|
||||
|
@ -787,13 +784,8 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
//drawRc.left *= hScale;
|
||||
//drawRc.right *= hScale;
|
||||
|
||||
TargetRectangle source_rc;
|
||||
source_rc.left = xfb_source->sourceRc.left;
|
||||
source_rc.top = xfb_source->sourceRc.top;
|
||||
source_rc.right = xfb_source->sourceRc.right;
|
||||
source_rc.bottom = xfb_source->sourceRc.bottom;
|
||||
|
||||
source_rc.right -= Renderer::EFBToScaledX(fb_stride - fb_width);
|
||||
}
|
||||
|
||||
BlitScreen(source_rc, drawRc, xfb_source->m_tex, xfb_source->texWidth, xfb_source->texHeight, gamma);
|
||||
}
|
||||
|
@ -881,9 +873,12 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
}
|
||||
|
||||
void* screenshot_texture_map;
|
||||
CheckHR(s_screenshot_texture->Map(0, nullptr, &screenshot_texture_map));
|
||||
D3D12_RANGE read_range = { 0, dst_location.PlacedFootprint.Footprint.RowPitch * source_height };
|
||||
CheckHR(s_screenshot_texture->Map(0, &read_range, &screenshot_texture_map));
|
||||
formatBufferDump(static_cast<u8*>(screenshot_texture_map), &frame_data[0], source_width, source_height, dst_location.PlacedFootprint.Footprint.RowPitch);
|
||||
s_screenshot_texture->Unmap(0, nullptr);
|
||||
|
||||
D3D12_RANGE write_range = {};
|
||||
s_screenshot_texture->Unmap(0, &write_range);
|
||||
|
||||
FlipImageData(&frame_data[0], w, h);
|
||||
AVIDump::AddFrame(&frame_data[0], source_width, source_height);
|
||||
|
@ -995,14 +990,12 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
}
|
||||
|
||||
// begin next frame
|
||||
RestoreAPIState();
|
||||
D3D::BeginFrame();
|
||||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE );
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
|
||||
SetViewport();
|
||||
RestoreAPIState();
|
||||
}
|
||||
|
||||
void Renderer::ResetAPIState()
|
||||
|
@ -1016,6 +1009,9 @@ void Renderer::RestoreAPIState()
|
|||
// overwritten elsewhere (particularly the viewport).
|
||||
SetViewport();
|
||||
BPFunctions::SetScissor();
|
||||
|
||||
FramebufferManager::RestoreEFBRenderTargets();
|
||||
BBox::Bind();
|
||||
}
|
||||
|
||||
static bool s_previous_use_dst_alpha = false;
|
||||
|
|
|
@ -18,6 +18,8 @@ static ID3DBlob* s_depth_matrix_program_blob[2] = {};
|
|||
static ID3DBlob* s_depth_resolve_to_color_program_blob = {};
|
||||
static ID3DBlob* s_clear_program_blob = {};
|
||||
static ID3DBlob* s_anaglyph_program_blob = {};
|
||||
static ID3DBlob* s_xfb_encode_shader_blob = {};
|
||||
static ID3DBlob* s_xfb_decode_shader_blob = {};
|
||||
static ID3DBlob* s_rgba6_to_rgb8_program_blob[2] = {};
|
||||
static ID3DBlob* s_rgb8_to_rgba6_program_blob[2] = {};
|
||||
|
||||
|
@ -411,6 +413,93 @@ static constexpr const char s_copy_geometry_shader_hlsl[] = {
|
|||
"}\n"
|
||||
};
|
||||
|
||||
static const char s_xfb_encode_shader_hlsl[] = R"(
|
||||
|
||||
Texture2DArray tex0 : register(t0);
|
||||
SamplerState samp0 : register(s0);
|
||||
|
||||
cbuffer EncodeParams : register(b0)
|
||||
{
|
||||
float4 srcRect;
|
||||
float2 texelSize;
|
||||
}
|
||||
|
||||
// GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see
|
||||
// <http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion>
|
||||
static const float3x4 RGB_TO_YCBCR = float3x4(
|
||||
0.257, 0.504, 0.098, 16.0/255.0,
|
||||
-0.148, -0.291, 0.439, 128.0/255.0,
|
||||
0.439, -0.368, -0.071, 128.0/255.0
|
||||
);
|
||||
|
||||
void main(
|
||||
out float4 ocol0 : SV_Target,
|
||||
in float4 pos : SV_Position,
|
||||
in float3 uv0 : TEXCOORD0,
|
||||
in float gamma : TEXCOORD1)
|
||||
{
|
||||
// Load three input pixels, emulate clamp sampler by clamping to the source rectangle.
|
||||
// Subtract 0.5 from the x coordinate because we're doubling the width, and want the pixel center shifted back to 0.5.
|
||||
// The native resolution is used as a reference here so bilinear filtering works as expected.
|
||||
float2 baseCoords = lerp(srcRect.xy, srcRect.zw, float2(uv0.x - 0.5 * texelSize.x, uv0.y));
|
||||
float3 sampleL = tex0.Sample(samp0, float3(max(srcRect.xy, baseCoords - float2(texelSize.x, 0)), 0)).rgb;
|
||||
float3 sampleM = tex0.Sample(samp0, float3(baseCoords, 0)).rgb;
|
||||
float3 sampleR = tex0.Sample(samp0, float3(min(srcRect.zw, baseCoords + float2(texelSize.x, 0)), 0)).rgb;
|
||||
|
||||
// Gamma correction (gamma is already rcp(gamma))
|
||||
// abs() here because the HLSL compiler throws a warning otherwise.
|
||||
sampleL = pow(abs(sampleL), gamma);
|
||||
sampleM = pow(abs(sampleM), gamma);
|
||||
sampleR = pow(abs(sampleR), gamma);
|
||||
|
||||
// RGB -> YUV
|
||||
float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));
|
||||
float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));
|
||||
float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));
|
||||
|
||||
// The Y components correspond to two EFB pixels, while the U and V are
|
||||
// made from a blend of three EFB pixels.
|
||||
float y0 = yuvM.r;
|
||||
float y1 = yuvR.r;
|
||||
float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;
|
||||
float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;
|
||||
ocol0 = float4(y0, u0, y1, v0);
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
static const char s_xfb_decode_shader_hlsl[] = R"(
|
||||
|
||||
Texture2DArray tex0 : register(t0);
|
||||
|
||||
static const float3x3 YCBCR_TO_RGB = float3x3(
|
||||
1.164, 0.000, 1.596,
|
||||
1.164, -0.392, -0.813,
|
||||
1.164, 2.017, 0.000
|
||||
);
|
||||
|
||||
void main(
|
||||
out float4 ocol0 : SV_Target,
|
||||
in float4 pos : SV_Position,
|
||||
in float3 uv0 : TEXCOORD0)
|
||||
{
|
||||
// Divide coordinates by 2 due to half-width YUYV texure.
|
||||
int2 ipos = int2(pos.xy);
|
||||
int2 texpos = int2(ipos.x >> 1, ipos.y);
|
||||
float4 yuyv = tex0.Load(int4(texpos, 0, 0));
|
||||
|
||||
// Select U for even pixels, V for odd pixels.
|
||||
float y = lerp(yuyv.r, yuyv.b, float(ipos.x & 1));
|
||||
|
||||
// Recover RGB components
|
||||
float3 yuv_601_sub = float3(y, yuyv.ga) - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);
|
||||
float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);
|
||||
|
||||
ocol0 = float4(rgb_601, 1);
|
||||
}
|
||||
|
||||
)";
|
||||
|
||||
D3D12_SHADER_BYTECODE StaticShaderCache::GetReinterpRGBA6ToRGB8PixelShader(bool multisampled)
|
||||
{
|
||||
D3D12_SHADER_BYTECODE bytecode = {};
|
||||
|
@ -625,6 +714,28 @@ D3D12_SHADER_BYTECODE StaticShaderCache::GetCopyGeometryShader()
|
|||
return bytecode;
|
||||
}
|
||||
|
||||
D3D12_SHADER_BYTECODE StaticShaderCache::GetXFBEncodePixelShader()
|
||||
{
|
||||
D3D12_SHADER_BYTECODE bytecode =
|
||||
{
|
||||
s_xfb_encode_shader_blob->GetBufferPointer(),
|
||||
s_xfb_encode_shader_blob->GetBufferSize()
|
||||
};
|
||||
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
D3D12_SHADER_BYTECODE StaticShaderCache::GetXFBDecodePixelShader()
|
||||
{
|
||||
D3D12_SHADER_BYTECODE bytecode =
|
||||
{
|
||||
s_xfb_decode_shader_blob->GetBufferPointer(),
|
||||
s_xfb_decode_shader_blob->GetBufferSize()
|
||||
};
|
||||
|
||||
return bytecode;
|
||||
}
|
||||
|
||||
void StaticShaderCache::Init()
|
||||
{
|
||||
// Compile static pixel shaders
|
||||
|
@ -633,6 +744,8 @@ void StaticShaderCache::Init()
|
|||
D3D::CompilePixelShader(s_color_copy_program_hlsl, &s_color_copy_program_blob[0]);
|
||||
D3D::CompilePixelShader(s_color_matrix_program_hlsl, &s_color_matrix_program_blob[0]);
|
||||
D3D::CompilePixelShader(s_depth_matrix_program_hlsl, &s_depth_matrix_program_blob[0]);
|
||||
D3D::CompilePixelShader(s_xfb_encode_shader_hlsl, &s_xfb_encode_shader_blob);
|
||||
D3D::CompilePixelShader(s_xfb_decode_shader_hlsl, &s_xfb_decode_shader_blob);
|
||||
|
||||
// Compile static vertex shaders
|
||||
D3D::CompileVertexShader(s_simple_vertex_shader_hlsl, &s_simple_vertex_shader_blob);
|
||||
|
@ -657,7 +770,8 @@ void StaticShaderCache::InvalidateMSAAShaders()
|
|||
void StaticShaderCache::Shutdown()
|
||||
{
|
||||
// Free pixel shader blobs
|
||||
|
||||
SAFE_RELEASE(s_xfb_decode_shader_blob);
|
||||
SAFE_RELEASE(s_xfb_encode_shader_blob);
|
||||
SAFE_RELEASE(s_clear_program_blob);
|
||||
SAFE_RELEASE(s_anaglyph_program_blob);
|
||||
SAFE_RELEASE(s_depth_resolve_to_color_program_blob);
|
||||
|
|
|
@ -23,6 +23,8 @@ public:
|
|||
static D3D12_SHADER_BYTECODE GetAnaglyphPixelShader();
|
||||
static D3D12_SHADER_BYTECODE GetReinterpRGBA6ToRGB8PixelShader(bool multisampled);
|
||||
static D3D12_SHADER_BYTECODE GetReinterpRGB8ToRGBA6PixelShader(bool multisampled);
|
||||
static D3D12_SHADER_BYTECODE GetXFBEncodePixelShader();
|
||||
static D3D12_SHADER_BYTECODE GetXFBDecodePixelShader();
|
||||
|
||||
// Vertex shaders
|
||||
static D3D12_SHADER_BYTECODE GetSimpleVertexShader();
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright 2011 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DShader.h"
|
||||
#include "VideoBackends/D3D12/D3DState.h"
|
||||
#include "VideoBackends/D3D12/D3DUtil.h"
|
||||
#include "VideoBackends/D3D12/Television.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
// D3D12TODO: Add DX12 path for this file.
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
Television::Television()
|
||||
{
|
||||
// D3D12TODO: Add DX12 path for this file.
|
||||
}
|
||||
|
||||
void Television::Init()
|
||||
{
|
||||
// D3D12TODO: Add DX12 path for this file.
|
||||
}
|
||||
|
||||
void Television::Shutdown()
|
||||
{
|
||||
// D3D12TODO: Add DX12 path for this file.
|
||||
}
|
||||
|
||||
void Television::Submit(u32 xfb_address, u32 stride, u32 width, u32 height)
|
||||
{
|
||||
// D3D12TODO: Add DX12 path for this file.
|
||||
}
|
||||
|
||||
void Television::Render()
|
||||
{
|
||||
// D3D12TODO: Add DX12 path for this file.
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright 2011 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
// D3D12TODO: Add DX12 path for this file.
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
class Television final
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Television();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
|
||||
// Submit video data to be drawn. This will change the current state of the
|
||||
// TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB
|
||||
// may be virtualized when rendering so the RAM may not actually be read.
|
||||
void Submit(u32 xfb_address, u32 stride, u32 width, u32 height);
|
||||
|
||||
// Render the current state of the TV.
|
||||
void Render();
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -83,7 +83,8 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l
|
|||
|
||||
// Map readback buffer and save to file.
|
||||
void* readback_texture_map;
|
||||
CheckHR(s_texture_cache_entry_readback_buffer->Map(0, nullptr, &readback_texture_map));
|
||||
D3D12_RANGE read_range = { 0, required_readback_buffer_size };
|
||||
CheckHR(s_texture_cache_entry_readback_buffer->Map(0, &read_range, &readback_texture_map));
|
||||
|
||||
bool saved = TextureToPng(
|
||||
static_cast<u8*>(readback_texture_map),
|
||||
|
@ -93,7 +94,8 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l
|
|||
dst_location.PlacedFootprint.Footprint.Height
|
||||
);
|
||||
|
||||
s_texture_cache_entry_readback_buffer->Unmap(0, nullptr);
|
||||
D3D12_RANGE write_range = {};
|
||||
s_texture_cache_entry_readback_buffer->Unmap(0, &write_range);
|
||||
return saved;
|
||||
}
|
||||
|
||||
|
@ -106,33 +108,24 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(
|
|||
if (src_rect.GetWidth() == dst_rect.GetWidth()
|
||||
&& src_rect.GetHeight() == dst_rect.GetHeight())
|
||||
{
|
||||
D3D12_BOX srcbox;
|
||||
srcbox.left = src_rect.left;
|
||||
srcbox.top = src_rect.top;
|
||||
srcbox.right = src_rect.right;
|
||||
srcbox.bottom = src_rect.bottom;
|
||||
srcbox.front = 0;
|
||||
srcbox.back = srcentry->config.layers;
|
||||
// These assertions should hold true unless the base code is passing us sizes too large, in which case it should be fixed instead.
|
||||
_assert_msg_(VIDEO,
|
||||
static_cast<u32>(src_rect.GetWidth()) <= source->config.width &&
|
||||
static_cast<u32>(src_rect.GetHeight()) <= source->config.height,
|
||||
"Source rect is too large for CopyRectangleFromTexture");
|
||||
|
||||
if (static_cast<u32>(src_rect.GetHeight()) > config.height ||
|
||||
static_cast<u32>(src_rect.GetWidth()) > config.width)
|
||||
{
|
||||
// To mimic D3D11 behavior, we're just going to drop the clear since it is invalid.
|
||||
// This invalid copy needs to be fixed above the Backend level.
|
||||
|
||||
// On D3D12, instead of silently dropping this invalid clear, the runtime throws an exception
|
||||
// so we need to filter it out ourselves.
|
||||
|
||||
return;
|
||||
}
|
||||
_assert_msg_(VIDEO,
|
||||
static_cast<u32>(dst_rect.GetWidth()) <= config.width &&
|
||||
static_cast<u32>(dst_rect.GetHeight()) <= config.height,
|
||||
"Dest rect is too large for CopyRectangleFromTexture");
|
||||
|
||||
CD3DX12_BOX src_box(src_rect.left, src_rect.top, 0, src_rect.right, src_rect.bottom, srcentry->config.layers);
|
||||
D3D12_TEXTURE_COPY_LOCATION dst_location = CD3DX12_TEXTURE_COPY_LOCATION(m_texture->GetTex12(), 0);
|
||||
D3D12_TEXTURE_COPY_LOCATION src_location = CD3DX12_TEXTURE_COPY_LOCATION(srcentry->m_texture->GetTex12(), 0);
|
||||
|
||||
m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
|
||||
D3D::current_command_list->CopyTextureRegion(&dst_location, dst_rect.left, dst_rect.top, 0, &src_location, &srcbox);
|
||||
D3D::current_command_list->CopyTextureRegion(&dst_location, dst_rect.left, dst_rect.top, 0, &src_location, &src_box);
|
||||
|
||||
m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
srcentry->m_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
|
@ -168,7 +161,6 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(
|
|||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
@ -185,8 +177,8 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry
|
|||
if (config.rendertarget)
|
||||
{
|
||||
D3DTexture2D* texture = D3DTexture2D::Create(config.width, config.height,
|
||||
static_cast<D3D11_BIND_FLAG>((static_cast<int>(D3D11_BIND_RENDER_TARGET) | static_cast<int>(D3D11_BIND_SHADER_RESOURCE))),
|
||||
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers);
|
||||
TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers);
|
||||
|
||||
TCacheEntry* entry = new TCacheEntry(config, texture);
|
||||
|
||||
|
@ -216,7 +208,7 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry
|
|||
|
||||
D3DTexture2D* texture = new D3DTexture2D(
|
||||
texture_resource,
|
||||
D3D11_BIND_SHADER_RESOURCE,
|
||||
TEXTURE_BIND_FLAG_SHADER_RESOURCE,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
DXGI_FORMAT_UNKNOWN,
|
||||
|
@ -308,7 +300,6 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat
|
|||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE);
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
@ -490,7 +481,6 @@ void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* uncon
|
|||
|
||||
FramebufferManager::GetEFBColorTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
FramebufferManager::GetEFBDepthTexture()->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_DEPTH_WRITE );
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
|
|
@ -137,10 +137,7 @@ void VertexManager::vFlush(bool use_dst_alpha)
|
|||
ShaderCache::LoadAndSetActiveShaders(use_dst_alpha ? DSTALPHA_DUAL_SOURCE_BLEND : DSTALPHA_NONE, current_primitive_type);
|
||||
|
||||
if (g_ActiveConfig.backend_info.bSupportsBBox && BoundingBox::active)
|
||||
{
|
||||
// D3D12TODO: Support GPU-side bounding box.
|
||||
// D3D::context->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 2, 1, &BBox::GetUAV(), nullptr);
|
||||
}
|
||||
BBox::Invalidate();
|
||||
|
||||
u32 stride = VertexLoaderManager::GetCurrentVertexFormat()->GetVertexStride();
|
||||
|
||||
|
@ -161,15 +158,15 @@ void VertexManager::vFlush(bool use_dst_alpha)
|
|||
// D3D12TODO: Decide right threshold for drawCountSinceAsyncFlush at runtime depending on
|
||||
// amount of stall measured in AccessEFB.
|
||||
|
||||
if (D3D::command_list_mgr->m_draws_since_last_execution > 100 && D3D::command_list_mgr->m_cpu_access_last_frame)
|
||||
// We can't do this with perf queries enabled since it can leave queries open.
|
||||
|
||||
if (D3D::command_list_mgr->m_cpu_access_last_frame &&
|
||||
D3D::command_list_mgr->m_draws_since_last_execution > 100 &&
|
||||
!PerfQueryBase::ShouldEmulate())
|
||||
{
|
||||
D3D::command_list_mgr->m_draws_since_last_execution = 0;
|
||||
|
||||
D3D::command_list_mgr->ExecuteQueuedWork();
|
||||
|
||||
g_renderer->SetViewport();
|
||||
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,7 +182,7 @@ void VertexManager::ResetBuffer(u32 stride)
|
|||
return;
|
||||
}
|
||||
|
||||
bool command_list_executed = m_vertex_stream_buffer->AllocateSpaceInBuffer(MAXVBUFFERSIZE, stride);
|
||||
m_vertex_stream_buffer->AllocateSpaceInBuffer(MAXVBUFFERSIZE, stride);
|
||||
|
||||
if (m_vertex_stream_buffer_reallocated)
|
||||
{
|
||||
|
@ -198,12 +195,7 @@ void VertexManager::ResetBuffer(u32 stride)
|
|||
s_pCurBufferPointer = static_cast<u8*>(m_vertex_stream_buffer->GetCPUAddressOfCurrentAllocation());
|
||||
m_vertex_draw_offset = static_cast<u32>(m_vertex_stream_buffer->GetOffsetOfCurrentAllocation());
|
||||
|
||||
command_list_executed |= m_index_stream_buffer->AllocateSpaceInBuffer(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16));
|
||||
if (command_list_executed)
|
||||
{
|
||||
g_renderer->SetViewport();
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV12(), FALSE, &FramebufferManager::GetEFBDepthTexture()->GetDSV12());
|
||||
}
|
||||
m_index_stream_buffer->AllocateSpaceInBuffer(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16));
|
||||
|
||||
if (m_index_stream_buffer_reallocated)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2011 Dolphin Emulator Project
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
@ -6,33 +6,180 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "VideoBackends/D3D12/D3DBase.h"
|
||||
#include "VideoBackends/D3D12/D3DCommandListManager.h"
|
||||
#include "VideoBackends/D3D12/D3DShader.h"
|
||||
#include "VideoBackends/D3D12/D3DState.h"
|
||||
#include "VideoBackends/D3D12/D3DUtil.h"
|
||||
#include "VideoBackends/D3D12/FramebufferManager.h"
|
||||
#include "VideoBackends/D3D12/Render.h"
|
||||
#include "VideoBackends/D3D12/StaticShaderCache.h"
|
||||
#include "VideoBackends/D3D12/XFBEncoder.h"
|
||||
|
||||
// D3D12TODO: Convert this file..
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
// YUYV data is packed into half-width RGBA, with Y values in (R,B) and UV in (G,A)
|
||||
constexpr size_t XFB_TEXTURE_WIDTH = MAX_XFB_WIDTH / 2;
|
||||
constexpr size_t XFB_TEXTURE_HEIGHT = MAX_XFB_HEIGHT;
|
||||
|
||||
// Buffer enough space for 2 XFB buffers (our frame latency)
|
||||
constexpr size_t XFB_UPLOAD_BUFFER_SIZE = D3D::AlignValue(XFB_TEXTURE_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * XFB_TEXTURE_HEIGHT * 2;
|
||||
constexpr size_t XFB_ENCODER_PARAMS_BUFFER_SIZE = 64 * 1024;
|
||||
|
||||
std::unique_ptr<XFBEncoder> g_xfb_encoder;
|
||||
|
||||
XFBEncoder::XFBEncoder()
|
||||
{ }
|
||||
|
||||
void XFBEncoder::Init()
|
||||
{
|
||||
// D3D12TODO: Convert this file..
|
||||
ID3D12Resource* texture;
|
||||
|
||||
CheckHR(D3D::device12->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, XFB_TEXTURE_WIDTH, XFB_TEXTURE_HEIGHT, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET),
|
||||
D3D12_RESOURCE_STATE_RENDER_TARGET,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&texture)));
|
||||
|
||||
m_yuyv_texture = new D3DTexture2D(texture,
|
||||
TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_R8G8B8A8_UNORM);
|
||||
SAFE_RELEASE(texture);
|
||||
|
||||
CheckHR(D3D::device12->CreateCommittedResource(
|
||||
&CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_READBACK),
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&CD3DX12_RESOURCE_DESC::Buffer(D3D::AlignValue(XFB_TEXTURE_WIDTH * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT) * MAX_XFB_HEIGHT),
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&m_readback_buffer)));
|
||||
|
||||
m_upload_buffer = std::make_unique<D3DStreamBuffer>(XFB_UPLOAD_BUFFER_SIZE, XFB_UPLOAD_BUFFER_SIZE, nullptr);
|
||||
m_encode_params_buffer = std::make_unique<D3DStreamBuffer>(XFB_ENCODER_PARAMS_BUFFER_SIZE, XFB_ENCODER_PARAMS_BUFFER_SIZE, nullptr);
|
||||
}
|
||||
|
||||
void XFBEncoder::Shutdown()
|
||||
XFBEncoder::~XFBEncoder()
|
||||
{
|
||||
// D3D12TODO: Convert this file..
|
||||
SAFE_RELEASE(m_yuyv_texture);
|
||||
SAFE_RELEASE(m_readback_buffer);
|
||||
}
|
||||
|
||||
void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma)
|
||||
void XFBEncoder::EncodeTextureToRam(u8* dst, u32 dst_pitch, u32 dst_height,
|
||||
D3DTexture2D* src_texture, const TargetRectangle& src_rect,
|
||||
u32 src_width, u32 src_height, float gamma)
|
||||
{
|
||||
// D3D12TODO: Convert this file..
|
||||
// src_rect is in native coordinates
|
||||
// dst_pitch is in words
|
||||
u32 dst_width = dst_pitch / 2;
|
||||
u32 dst_texture_width = dst_width / 2;
|
||||
_assert_msg_(VIDEO, dst_width <= MAX_XFB_WIDTH && dst_height <= MAX_XFB_HEIGHT, "XFB destination does not exceed maximum size");
|
||||
|
||||
// Encode parameters constant buffer used by shader
|
||||
struct EncodeParameters
|
||||
{
|
||||
float srcRect[4];
|
||||
float texelSize[2];
|
||||
float pad[2];
|
||||
};
|
||||
EncodeParameters parameters =
|
||||
{
|
||||
{
|
||||
static_cast<float>(src_rect.left) / static_cast<float>(src_width),
|
||||
static_cast<float>(src_rect.top) / static_cast<float>(src_height),
|
||||
static_cast<float>(src_rect.right) / static_cast<float>(src_width),
|
||||
static_cast<float>(src_rect.bottom) / static_cast<float>(src_height)
|
||||
},
|
||||
{
|
||||
1.0f / EFB_WIDTH,
|
||||
1.0f / EFB_HEIGHT
|
||||
},
|
||||
{
|
||||
0.0f,
|
||||
0.0f
|
||||
}
|
||||
};
|
||||
m_encode_params_buffer->AllocateSpaceInBuffer(sizeof(parameters), D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
|
||||
memcpy(m_encode_params_buffer->GetCPUAddressOfCurrentAllocation(), ¶meters, sizeof(parameters));
|
||||
|
||||
// Convert RGBA texture to YUYV intermediate texture.
|
||||
// Performs downscaling through a linear filter. Probably not ideal, but it's not going to look perfect anyway.
|
||||
CD3DX12_RECT src_texture_rect(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom);
|
||||
D3D12_RESOURCE_STATES src_texture_state = src_texture->GetResourceUsageState();
|
||||
m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &m_yuyv_texture->GetRTV12(), FALSE, nullptr);
|
||||
D3D::current_command_list->SetGraphicsRootConstantBufferView(DESCRIPTOR_TABLE_PS_CBVONE, m_encode_params_buffer->GetGPUAddressOfCurrentAllocation());
|
||||
D3D::command_list_mgr->SetCommandListDirtyState(COMMAND_LIST_STATE_PS_CBV, true);
|
||||
D3D::SetViewportAndScissor(0, 0, dst_texture_width, dst_height);
|
||||
D3D::SetLinearCopySampler();
|
||||
D3D::DrawShadedTexQuad(
|
||||
src_texture, &src_texture_rect, src_rect.GetWidth(), src_rect.GetHeight(),
|
||||
StaticShaderCache::GetXFBEncodePixelShader(), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(),
|
||||
{}, gamma, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, false);
|
||||
|
||||
src_texture->TransitionToResourceState(D3D::current_command_list, src_texture_state);
|
||||
|
||||
// Copy from YUYV intermediate texture to readback buffer. It's likely the pitch here is going to be different to dst_pitch.
|
||||
u32 readback_pitch = D3D::AlignValue(dst_width * sizeof(u16), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = { 0, { DXGI_FORMAT_R8G8B8A8_UNORM, dst_texture_width, dst_height, 1, readback_pitch } };
|
||||
CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_readback_buffer, dst_footprint);
|
||||
CD3DX12_TEXTURE_COPY_LOCATION src_location(m_yuyv_texture->GetTex12(), 0);
|
||||
CD3DX12_BOX src_box(0, 0, dst_texture_width, dst_height);
|
||||
m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box);
|
||||
|
||||
// Wait until the GPU completes the copy. Resets back to known state automatically.
|
||||
D3D::command_list_mgr->ExecuteQueuedWork(true);
|
||||
|
||||
// Copy from the readback buffer to dst.
|
||||
// Can't be done as one memcpy due to pitch difference.
|
||||
void* readback_texture_map;
|
||||
D3D12_RANGE read_range = { 0, readback_pitch * dst_height };
|
||||
CheckHR(m_readback_buffer->Map(0, &read_range, &readback_texture_map));
|
||||
|
||||
for (u32 row = 0; row < dst_height; row++)
|
||||
{
|
||||
const u8* row_src = reinterpret_cast<u8*>(readback_texture_map) + readback_pitch * row;
|
||||
u8* row_dst = dst + dst_pitch * row;
|
||||
memcpy(row_dst, row_src, std::min(dst_pitch, readback_pitch));
|
||||
}
|
||||
|
||||
D3D12_RANGE write_range = {};
|
||||
m_readback_buffer->Unmap(0, &write_range);
|
||||
}
|
||||
|
||||
void XFBEncoder::DecodeToTexture(D3DTexture2D* dst_texture, const u8* src, u32 src_width, u32 src_height)
|
||||
{
|
||||
_assert_msg_(VIDEO, src_width <= MAX_XFB_WIDTH && src_height <= MAX_XFB_HEIGHT, "XFB source does not exceed maximum size");
|
||||
|
||||
// Copy to XFB upload buffer. Each row has to be done separately due to pitch differences.
|
||||
u32 buffer_pitch = D3D::AlignValue(src_width / 2 * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
m_upload_buffer->AllocateSpaceInBuffer(buffer_pitch * src_height, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
|
||||
for (u32 row = 0; row < src_height; row++)
|
||||
{
|
||||
const u8* row_src = src + (src_width * 2) * row;
|
||||
u8* row_dst = reinterpret_cast<u8*>(m_upload_buffer->GetCPUAddressOfCurrentAllocation()) + buffer_pitch * row;
|
||||
memcpy(row_dst, row_src, src_width * 2);
|
||||
}
|
||||
|
||||
// Copy from upload buffer to intermediate YUYV texture.
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = { m_upload_buffer->GetOffsetOfCurrentAllocation(), { DXGI_FORMAT_R8G8B8A8_UNORM, src_width / 2, src_height, 1, buffer_pitch } };
|
||||
CD3DX12_TEXTURE_COPY_LOCATION src_location(m_upload_buffer->GetBuffer(), src_footprint);
|
||||
CD3DX12_TEXTURE_COPY_LOCATION dst_location(m_yuyv_texture->GetTex12(), 0);
|
||||
CD3DX12_BOX src_box(0, 0, src_width / 2, src_height);
|
||||
m_yuyv_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
D3D::current_command_list->CopyTextureRegion(&dst_location, 0, 0, 0, &src_location, &src_box);
|
||||
|
||||
// Convert YUYV texture to RGBA texture with pixel shader.
|
||||
CD3DX12_RECT src_texture_rect(0, 0, src_width / 2, src_height);
|
||||
dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_RENDER_TARGET);
|
||||
D3D::current_command_list->OMSetRenderTargets(1, &dst_texture->GetRTV12(), FALSE, nullptr);
|
||||
D3D::SetViewportAndScissor(0, 0, src_width, src_height);
|
||||
D3D::DrawShadedTexQuad(
|
||||
m_yuyv_texture, &src_texture_rect, XFB_TEXTURE_WIDTH, XFB_TEXTURE_HEIGHT,
|
||||
StaticShaderCache::GetXFBDecodePixelShader(), StaticShaderCache::GetSimpleVertexShader(), StaticShaderCache::GetSimpleVertexShaderInputLayout(),
|
||||
{}, 1.0f, 0, DXGI_FORMAT_R8G8B8A8_UNORM, false, false);
|
||||
|
||||
// XFB source textures are expected to be in shader resource state.
|
||||
dst_texture->TransitionToResourceState(D3D::current_command_list, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,28 +1,42 @@
|
|||
// Copyright 2011 Dolphin Emulator Project
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <d3d12.h>
|
||||
#include <memory>
|
||||
|
||||
#include "VideoBackends/D3D12/D3DStreamBuffer.h"
|
||||
#include "VideoBackends/D3D12/D3DTexture.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
||||
namespace DX12
|
||||
{
|
||||
|
||||
class D3DTexture2D;
|
||||
|
||||
class XFBEncoder
|
||||
{
|
||||
|
||||
public:
|
||||
XFBEncoder();
|
||||
~XFBEncoder();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void EncodeTextureToRam(u8* dst, u32 dst_pitch, u32 dst_height,
|
||||
D3DTexture2D* src_texture, const TargetRectangle& src_rect,
|
||||
u32 src_width, u32 src_height, float gamma);
|
||||
|
||||
void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& src_rect, float gamma);
|
||||
void DecodeToTexture(D3DTexture2D* dst_texture, const u8* src, u32 src_width, u32 src_height);
|
||||
|
||||
private:
|
||||
// D3D12TODO: Implement this class
|
||||
D3DTexture2D* m_yuyv_texture;
|
||||
|
||||
ID3D12Resource* m_readback_buffer;
|
||||
|
||||
std::unique_ptr<D3DStreamBuffer> m_upload_buffer;
|
||||
std::unique_ptr<D3DStreamBuffer> m_encode_params_buffer;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<XFBEncoder> g_xfb_encoder;
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "VideoBackends/D3D12/TextureCache.h"
|
||||
#include "VideoBackends/D3D12/VertexManager.h"
|
||||
#include "VideoBackends/D3D12/VideoBackend.h"
|
||||
#include "VideoBackends/D3D12/XFBEncoder.h"
|
||||
|
||||
#include "VideoCommon/BPStructs.h"
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
|
@ -64,11 +65,14 @@ std::string VideoBackend::GetDisplayName() const
|
|||
|
||||
void InitBackendInfo()
|
||||
{
|
||||
HRESULT hr = DX12::D3D::LoadDXGI();
|
||||
if (SUCCEEDED(hr)) hr = DX12::D3D::LoadD3D();
|
||||
HRESULT hr = D3D::LoadDXGI();
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
hr = D3D::LoadD3D();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DX12::D3D::UnloadDXGI();
|
||||
D3D::UnloadDXGI();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -85,9 +89,14 @@ void InitBackendInfo()
|
|||
|
||||
IDXGIFactory* factory;
|
||||
IDXGIAdapter* ad;
|
||||
hr = DX12::create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory);
|
||||
hr = create_dxgi_factory(__uuidof(IDXGIFactory), (void**)&factory);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
PanicAlert("Failed to create IDXGIFactory object");
|
||||
D3D::UnloadD3D();
|
||||
D3D::UnloadDXGI();
|
||||
return;
|
||||
}
|
||||
|
||||
// adapters
|
||||
g_Config.backend_info.Adapters.clear();
|
||||
|
@ -101,29 +110,35 @@ void InitBackendInfo()
|
|||
|
||||
// TODO: These don't get updated on adapter change, yet
|
||||
if (adapter_index == g_Config.iAdapter)
|
||||
{
|
||||
ID3D12Device* temp_device;
|
||||
hr = d3d12_create_device(ad, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&temp_device));
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
std::string samples;
|
||||
std::vector<DXGI_SAMPLE_DESC> modes = DX12::D3D::EnumAAModes(ad);
|
||||
std::vector<DXGI_SAMPLE_DESC> modes = D3D::EnumAAModes(temp_device);
|
||||
// First iteration will be 1. This equals no AA.
|
||||
for (unsigned int i = 0; i < modes.size(); ++i)
|
||||
{
|
||||
g_Config.backend_info.AAModes.push_back(modes[i].Count);
|
||||
}
|
||||
|
||||
bool shader_model_5_supported = (DX12::D3D::GetFeatureLevel(ad) >= D3D_FEATURE_LEVEL_11_0);
|
||||
|
||||
// Requires the earlydepthstencil attribute (only available in shader model 5)
|
||||
g_Config.backend_info.bSupportsEarlyZ = shader_model_5_supported;
|
||||
g_Config.backend_info.bSupportsEarlyZ = true;
|
||||
|
||||
// Requires full UAV functionality (only available in shader model 5)
|
||||
g_Config.backend_info.bSupportsBBox = false;
|
||||
g_Config.backend_info.bSupportsBBox = true;
|
||||
|
||||
// Requires the instance attribute (only available in shader model 5)
|
||||
g_Config.backend_info.bSupportsGSInstancing = shader_model_5_supported;
|
||||
g_Config.backend_info.bSupportsGSInstancing = true;
|
||||
|
||||
// Sample shading requires shader model 5
|
||||
g_Config.backend_info.bSupportsSSAA = shader_model_5_supported;
|
||||
g_Config.backend_info.bSupportsSSAA = true;
|
||||
|
||||
temp_device->Release();
|
||||
}
|
||||
}
|
||||
|
||||
g_Config.backend_info.Adapters.push_back(UTF16ToUTF8(desc.Description));
|
||||
ad->Release();
|
||||
}
|
||||
|
@ -133,8 +148,8 @@ void InitBackendInfo()
|
|||
g_Config.backend_info.PPShaders.clear();
|
||||
g_Config.backend_info.AnaglyphShaders.clear();
|
||||
|
||||
DX12::D3D::UnloadDXGI();
|
||||
DX12::D3D::UnloadD3D();
|
||||
D3D::UnloadD3D();
|
||||
D3D::UnloadDXGI();
|
||||
}
|
||||
|
||||
void VideoBackend::ShowConfig(void *hParent)
|
||||
|
@ -145,11 +160,6 @@ void VideoBackend::ShowConfig(void *hParent)
|
|||
|
||||
bool VideoBackend::Initialize(void *window_handle)
|
||||
{
|
||||
bool d3d12_supported = D3D::AlertUserIfSelectedAdapterDoesNotSupportD3D12();
|
||||
|
||||
if (!d3d12_supported)
|
||||
return false;
|
||||
|
||||
if (window_handle == nullptr)
|
||||
return false;
|
||||
|
||||
|
@ -168,6 +178,9 @@ bool VideoBackend::Initialize(void *window_handle)
|
|||
g_Config.VerifyValidity();
|
||||
UpdateActiveConfig();
|
||||
|
||||
if (FAILED(D3D::Create((HWND)window_handle)))
|
||||
return false;
|
||||
|
||||
m_window_handle = window_handle;
|
||||
m_initialized = true;
|
||||
|
||||
|
@ -181,6 +194,7 @@ void VideoBackend::Video_Prepare()
|
|||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
g_vertex_manager = std::make_unique<VertexManager>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
g_xfb_encoder = std::make_unique<XFBEncoder>();
|
||||
ShaderCache::Init();
|
||||
ShaderConstantsManager::Init();
|
||||
StaticShaderCache::Init();
|
||||
|
@ -230,10 +244,13 @@ void VideoBackend::Shutdown()
|
|||
StaticShaderCache::Shutdown();
|
||||
BBox::Shutdown();
|
||||
|
||||
g_xfb_encoder.reset();
|
||||
g_perf_query.reset();
|
||||
g_vertex_manager.reset();
|
||||
g_texture_cache.reset();
|
||||
g_renderer.reset();
|
||||
|
||||
D3D::Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1309,6 +1309,11 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, co
|
|||
{
|
||||
drawRc = flipped_trc;
|
||||
sourceRc.right -= fbStride - fbWidth;
|
||||
|
||||
// RealXFB doesn't call ConvertEFBRectangle for sourceRc, therefore it is still assuming a top-left origin.
|
||||
// The top offset is always zero (see FramebufferManagerBase::GetRealXFBSource).
|
||||
sourceRc.top = sourceRc.bottom;
|
||||
sourceRc.bottom = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -67,12 +67,10 @@ const XFBSourceBase* const* FramebufferManagerBase::GetRealXFBSource(u32 xfbAddr
|
|||
m_realXFBSource->texWidth = fbWidth;
|
||||
m_realXFBSource->texHeight = fbHeight;
|
||||
|
||||
// OpenGL texture coordinates originate at the lower left, which is why
|
||||
// sourceRc.top = fbHeight and sourceRc.bottom = 0.
|
||||
m_realXFBSource->sourceRc.left = 0;
|
||||
m_realXFBSource->sourceRc.top = fbHeight;
|
||||
m_realXFBSource->sourceRc.top = 0;
|
||||
m_realXFBSource->sourceRc.right = fbWidth;
|
||||
m_realXFBSource->sourceRc.bottom = 0;
|
||||
m_realXFBSource->sourceRc.bottom = fbHeight;
|
||||
|
||||
// Decode YUYV data from GameCube RAM
|
||||
m_realXFBSource->DecodeToTexture(xfbAddr, fbWidth, fbHeight);
|
||||
|
|
Loading…
Reference in New Issue