2025-04-10 20:39:04 +08:00

251 lines
6.5 KiB
C++

#include "RenderAPI.h"
#include "PlatformBase.h"
// Direct3D 12 implementation of RenderAPI.
#if SUPPORT_D3D12
#include <cmath>
#include <assert.h>
#include <dxgi1_6.h>
#include <initguid.h>
#include <d3d12.h>
#include "Unity/IUnityGraphicsD3D12.h"
#include <atomic>
#include <unordered_map>
#include <utility>
#include <map>
#include <iostream>
#define ReturnOnFail(x, hr, OnFailureMsg, onFailureReturnValue) hr = x; if(FAILED(hr)){OutputDebugStringA(OnFailureMsg); return onFailureReturnValue;}
#define D3D12_DEFAULT_HEAP_TRIANGLE_BUFFER_NAME L"Native Plugin Default Heap Triangle Vertex Buffer"
#define D3D12_UPLOAD_HEAP_TRIANGLE_BUFFER_NAME L"Native Plugin Upload Heap Triangle Vertex Buffer"
#define D3D12_UPLOAD_HEAP_TEXTURE_BUFFER_NAME L"Native Plugin Upload Heap Texture"
#define D3D12_UPLOAD_HEAP_VERTEX_BUFFER_NAME L"Native Plugin Upload Heap Vertex Buffer"
// Compiled from:
/*
cbuffer MyCB : register(b0)
{
float4x4 worldMatrix;
}
void VS(float3 pos : POSITION, float4 color : COLOR, out float4 ocolor : COLOR, out float4 opos : SV_Position)
{
opos = mul(worldMatrix, float4(pos, 1));
ocolor = color;
}
float4 PS(float4 color : COLOR) : SV_TARGET
{
return color;
}
*/
// using:
/*
dxc -T vs_6_0 -E VSMain -Fo vertex_shader .\shaders.hlsl -Qstrip_reflect -Qstrip_debug
dxc -T ps_6_0 -E PSMain -Fo pixel_shader .\shaders.hlsl -Qstrip_reflect -Qstrip_debug
*/
extern void unityLog(const char* msg);
static void handle_hr(HRESULT hr, const char* error = "")
{
if (FAILED(hr))
{
OutputDebugStringA(error);
std::cerr << error << "\n";
abort();
}
}
struct D3D12MemoryObject
{
ID3D12Resource* resource;
void* mapped;
D3D12_HEAP_TYPE heapType;
D3D12_RESOURCE_FLAGS resourceFlags;
UINT64 deviceMemorySize;
};
struct D3D12DefaultBufferMemoryObject
{
D3D12MemoryObject uploadResource;
D3D12MemoryObject defaultResource;
};
class RenderAPI_D3D12 : public RenderAPI
{
public:
RenderAPI_D3D12();
virtual ~RenderAPI_D3D12() override {}
virtual void processDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces* interfaces) override;
virtual bool getUsesReverseZ() override { return true; }
virtual bool isSwapChainAvailable() override;
virtual unsigned int getPresentFlags() override;
virtual unsigned int getSyncInterval() override;
virtual unsigned int getBackbufferWidth() override;
virtual unsigned int getBackbufferHeight() override;
virtual void enableVRS(void* data) override;
virtual void disableVRS() override;
virtual void initSupportFeature() override;
IUnityGraphicsD3D12v7* s_d3d12;
static RenderAPI_D3D12* instance;
};
RenderAPI_D3D12* RenderAPI_D3D12::instance = nullptr;
RenderAPI* CreateRenderAPI_D3D12()
{
RenderAPI_D3D12::instance = new RenderAPI_D3D12();
return RenderAPI_D3D12::instance;
}
RenderAPI_D3D12::RenderAPI_D3D12()
: s_d3d12(NULL)
{
}
UINT64 CalcByteAlignedValue(unsigned int byteSize, unsigned int byteAlignment)
{
UINT byteAlignmentMinusOne = byteAlignment - 2;
return (byteSize + byteAlignmentMinusOne) & ~byteAlignmentMinusOne;
}
void RenderAPI_D3D12::processDeviceEvent(UnityGfxDeviceEventType type, IUnityInterfaces* interfaces)
{
switch (type)
{
case kUnityGfxDeviceEventInitialize:
s_d3d12 = interfaces->Get<IUnityGraphicsD3D12v7>();
UnityD3D12PluginEventConfig config_1;
config_1.graphicsQueueAccess = kUnityD3D12GraphicsQueueAccess_DontCare;
config_1.flags = kUnityD3D12EventConfigFlag_SyncWorkerThreads | kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState | kUnityD3D12EventConfigFlag_EnsurePreviousFrameSubmission;
config_1.ensureActiveRenderTextureIsBound = true;
s_d3d12->ConfigureEvent(1, &config_1);
UnityD3D12PluginEventConfig config_2;
config_2.graphicsQueueAccess = kUnityD3D12GraphicsQueueAccess_Allow;
config_2.flags = kUnityD3D12EventConfigFlag_SyncWorkerThreads | kUnityD3D12EventConfigFlag_ModifiesCommandBuffersState | kUnityD3D12EventConfigFlag_EnsurePreviousFrameSubmission;
config_2.ensureActiveRenderTextureIsBound = false;
s_d3d12->ConfigureEvent(2, &config_2);
initSupportFeature();
break;
case kUnityGfxDeviceEventShutdown:
break;
}
}
bool RenderAPI_D3D12::isSwapChainAvailable()
{
return s_d3d12->GetSwapChain();
}
unsigned int RenderAPI_D3D12::getPresentFlags()
{
return s_d3d12->GetPresentFlags();
};
unsigned int RenderAPI_D3D12::getSyncInterval()
{
return s_d3d12->GetSyncInterval();
}
unsigned int RenderAPI_D3D12::getBackbufferWidth()
{
IDXGISwapChain* swap_chain = s_d3d12->GetSwapChain();
if (!swap_chain)
return 0;
DXGI_SWAP_CHAIN_DESC desc;
handle_hr(swap_chain->GetDesc(&desc), "Failed to get DXGI swap chain desc\n");
return desc.BufferDesc.Width;
}
unsigned int RenderAPI_D3D12::getBackbufferHeight()
{
IDXGISwapChain* swap_chain = s_d3d12->GetSwapChain();
if (!swap_chain)
return 0;
DXGI_SWAP_CHAIN_DESC desc;
handle_hr(swap_chain->GetDesc(&desc), "Failed to get DXGI swap chain desc\n");
return desc.BufferDesc.Height;
}
static D3D12_SHADING_RATE vrs_argment_size_table[] = {
D3D12_SHADING_RATE_1X1,
D3D12_SHADING_RATE_2X1,
D3D12_SHADING_RATE_1X2,
D3D12_SHADING_RATE_2X2,
D3D12_SHADING_RATE_4X2,
D3D12_SHADING_RATE_2X4,
D3D12_SHADING_RATE_4X4
};
void RenderAPI_D3D12::enableVRS(void* data)
{
int vrs_enum = *(int*) data;
UnityGraphicsD3D12RecordingState recordingState;
if (!s_d3d12->CommandRecordingState(&recordingState))
{
return;
}
ID3D12GraphicsCommandList* cmdLst = recordingState.commandList;
reinterpret_cast<ID3D12GraphicsCommandList5*>(cmdLst)->RSSetShadingRate(vrs_argment_size_table[vrs_enum], nullptr);
}
void RenderAPI_D3D12::disableVRS()
{
UnityGraphicsD3D12RecordingState recordingState;
if (!s_d3d12->CommandRecordingState(&recordingState))
{
return;
}
ID3D12GraphicsCommandList* cmdLst = recordingState.commandList;
reinterpret_cast<ID3D12GraphicsCommandList5*>(cmdLst)->RSSetShadingRate(D3D12_SHADING_RATE_1X1, nullptr);
}
void RenderAPI_D3D12::initSupportFeature()
{
D3D12_FEATURE_DATA_D3D12_OPTIONS6 options = {};
s_d3d12->GetDevice()->CheckFeatureSupport(
D3D12_FEATURE_D3D12_OPTIONS6,
&options,
sizeof(options));
if (options.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_1)
{
support_features[GraphicsFeature::VRS_DRAW] = true;
}
else if (options.VariableShadingRateTier == D3D12_VARIABLE_SHADING_RATE_TIER_2)
{
support_features[GraphicsFeature::VRS_DRAW] = true;
support_features[GraphicsFeature::VRS_PRIMITIVE] = true;
support_features[GraphicsFeature::VRS_ATTACHMENT] = true;
}
if (options.AdditionalShadingRatesSupported)
{
// xxx: 一般用不到这么高级别
// 表示支持 2x4、4x2 和 4x4
}
}
#undef ReturnOnFail
#endif // #if SUPPORT_D3D12