#include "RenderAPI.h" #include "PlatformBase.h" // Direct3D 12 implementation of RenderAPI. #if SUPPORT_D3D12 #include #include #include #include #include #include "Unity/IUnityGraphicsD3D12.h" #include #include #include #include #include #include "xess1/xess.h" #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(int vrsEnum) override; virtual void disableVRS() override; virtual void initSupportFeature() override; virtual void enableXESS1(void* data) override; virtual void doXESS1(void* data) override; virtual void disableXESS1() override; virtual void configXESS1(void* data) override; virtual bool getInputResolution(uint32_t outw, uint32_t outh, int quality, uint32_t& width, uint32_t& height) override; IUnityGraphicsD3D12v7* s_d3d12; XessV13* xess; 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(); 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); xess = new XessV13(s_d3d12->GetDevice()); 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(int vrsEnum) { UnityGraphicsD3D12RecordingState recordingState; if (!s_d3d12->CommandRecordingState(&recordingState)) { return; } ID3D12GraphicsCommandList* cmdLst = recordingState.commandList; reinterpret_cast(cmdLst)->RSSetShadingRate(vrs_argment_size_table[vrsEnum], nullptr); } void RenderAPI_D3D12::disableVRS() { UnityGraphicsD3D12RecordingState recordingState; if (!s_d3d12->CommandRecordingState(&recordingState)) { return; } ID3D12GraphicsCommandList* cmdLst = recordingState.commandList; reinterpret_cast(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 } support_features[GraphicsFeature::XESS13] = true; } void RenderAPI_D3D12::enableXESS1(void* data) { xess->enable([](const char* msg) { unityLog(msg); } ); } void RenderAPI_D3D12::doXESS1(void* data) { UnityGraphicsD3D12RecordingState recordingState; if (!s_d3d12->CommandRecordingState(&recordingState)) { return; } xess->execute(data, recordingState.commandList); } void RenderAPI_D3D12::disableXESS1() { xess->disable(); } void RenderAPI_D3D12::configXESS1(void* data) { //s_d3d12->GetCommandQueue()->Wait(s_d3d12->GetFrameFence(), 5); xess->configxess(data); } bool RenderAPI_D3D12::getInputResolution(uint32_t outw, uint32_t outh, int quality, uint32_t& width, uint32_t& height) { return xess->get_input_resolution(outw, outh, quality, width, height); } #undef ReturnOnFail #endif // #if SUPPORT_D3D12