1672 lines
68 KiB
C++
Raw Normal View History

2024-11-01 16:55:46 +08:00
#include "RenderAPI.h"
#include "PlatformBase.h"
// Direct3D 12 implementation of RenderAPI.
#if SUPPORT_D3D12
2024-11-22 12:09:31 +08:00
#include <cmath>
2024-11-01 16:55:46 +08:00
#include <assert.h>
#include <dxgi1_6.h>
#include <initguid.h>
#include <d3d12.h>
#include "d3dx12.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
*/
const BYTE vertex_shader[] =
{
68,88,66,67,128,57,232,34,242,147,249,9,179,113,162,105,42,26,31,
250,1,0,0,0,109,9,0,0,6,0,0,0,56,0,0,0,72,0,0,
0,167,0,0,0,9,1,0,0,237,1,0,0,9,2,0,0,83,70,73,
48,8,0,0,0,0,0,0,0,0,0,0,0,73,83,71,49,87,0,0,
0,2,0,0,0,8,0,0,0,0,0,0,0,72,0,0,0,0,0,0,
0,0,0,0,0,3,0,0,0,0,0,0,0,7,7,0,0,0,0,0,
0,0,0,0,0,81,0,0,0,0,0,0,0,0,0,0,0,3,0,0,
0,1,0,0,0,15,15,0,0,0,0,0,0,80,79,83,73,84,73,79,
78,0,67,79,76,79,82,0,79,83,71,49,90,0,0,0,2,0,0,0,
8,0,0,0,0,0,0,0,72,0,0,0,0,0,0,0,0,0,0,0,
3,0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,
78,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,
15,0,0,0,0,0,0,0,67,79,76,79,82,0,83,86,95,80,111,115,
105,116,105,111,110,0,80,83,86,48,220,0,0,0,48,0,0,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,
255,255,1,0,0,0,2,2,0,2,2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,0,0,0,24,0,0,0,2,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,24,0,
0,0,0,80,79,83,73,84,73,79,78,0,67,79,76,79,82,0,67,79,
76,79,82,0,0,0,1,0,0,0,0,0,0,0,16,0,0,0,1,0,
0,0,0,0,0,0,1,0,67,0,3,0,0,0,10,0,0,0,0,0,
0,0,1,1,68,0,3,0,0,0,16,0,0,0,0,0,0,0,1,0,
68,0,3,2,0,0,0,0,0,0,0,0,0,0,1,1,68,3,3,4,
0,0,240,0,0,0,240,0,0,0,240,0,0,0,0,0,0,0,1,0,
0,0,2,0,0,0,4,0,0,0,8,0,0,0,72,65,83,72,20,0,
0,0,0,0,0,0,104,176,13,123,21,10,21,217,124,92,148,133,249,234,
46,114,68,88,73,76,92,7,0,0,96,0,1,0,215,1,0,0,68,88,
73,76,0,1,0,0,16,0,0,0,68,7,0,0,66,67,192,222,33,12,
0,0,206,1,0,0,11,130,32,0,2,0,0,0,19,0,0,0,7,129,
35,145,65,200,4,73,6,16,50,57,146,1,132,12,37,5,8,25,30,4,
139,98,128,20,69,2,66,146,11,66,164,16,50,20,56,8,24,75,10,50,
82,136,72,144,20,32,67,70,136,165,0,25,50,66,228,72,14,144,145,34,
196,80,65,81,129,140,225,131,229,138,4,41,70,6,81,24,0,0,8,0,
0,0,27,140,224,255,255,255,255,7,64,2,168,13,132,240,255,255,255,255,
3,32,109,48,134,255,255,255,255,31,0,9,168,0,73,24,0,0,3,0,
0,0,19,130,96,66,32,76,8,6,0,0,0,0,137,32,0,0,35,0,
0,0,50,34,72,9,32,100,133,4,147,34,164,132,4,147,34,227,132,161,
144,20,18,76,138,140,11,132,164,76,16,104,35,0,37,0,20,102,0,230,
8,192,96,142,0,41,198,32,132,20,66,166,24,128,16,82,6,161,163,134,
203,159,176,135,144,124,110,163,138,149,152,252,226,182,17,49,198,24,84,238,
25,46,127,194,30,66,242,67,160,25,22,2,5,171,16,138,48,66,173,20,
131,140,49,232,205,17,4,197,96,164,16,18,73,14,4,12,35,16,67,18,
212,123,14,71,154,22,0,115,168,201,55,49,110,67,129,165,155,10,4,0,
0,0,19,20,114,192,135,116,96,135,54,104,135,121,104,3,114,192,135,13,
175,80,14,109,208,14,122,80,14,109,0,15,122,48,7,114,160,7,115,32,
7,109,144,14,113,160,7,115,32,7,109,144,14,120,160,7,115,32,7,109,
144,14,113,96,7,122,48,7,114,208,6,233,48,7,114,160,7,115,32,7,
109,144,14,118,64,7,122,96,7,116,208,6,230,16,7,118,160,7,115,32,
7,109,96,14,115,32,7,122,48,7,114,208,6,230,96,7,116,160,7,118,
64,7,109,224,14,120,160,7,113,96,7,122,48,7,114,160,7,118,64,7,
67,158,0,0,0,0,0,0,0,0,0,0,0,134,60,6,16,0,1,0,
0,0,0,0,0,0,12,121,16,32,0,4,0,0,0,0,0,0,0,24,
242,52,64,0,12,0,0,0,0,0,0,0,48,228,121,128,0,8,0,0,
0,0,0,0,0,96,200,35,1,1,48,0,0,0,0,0,0,0,64,22,
8,0,14,0,0,0,50,30,152,20,25,17,76,144,140,9,38,71,198,4,
67,34,37,48,2,80,12,5,24,80,6,229,80,30,84,74,98,4,160,12,
10,161,8,8,207,0,80,30,75,65,16,248,128,15,248,0,2,129,64,0,
0,0,121,24,0,0,87,0,0,0,26,3,76,144,70,2,19,196,49,32,
195,27,67,129,147,75,179,11,163,43,75,1,137,113,185,113,129,113,153,193,
201,177,1,65,129,145,137,49,195,49,155,41,139,73,217,16,4,19,4,194,
152,32,16,199,6,97,32,38,8,4,178,65,24,12,10,118,115,27,6,196,
32,38,8,152,68,96,130,64,36,27,16,66,89,8,98,96,128,13,65,179,
129,0,0,7,152,32,100,211,134,0,154,32,8,0,5,171,41,34,80,79,
83,73,84,73,79,78,19,132,162,153,32,20,206,134,128,152,32,20,207,4,
129,80,38,8,196,178,65,200,180,13,11,65,85,214,101,13,24,97,109,44,
134,158,152,158,164,38,8,5,52,65,32,152,13,66,246,109,88,134,174,178,
46,107,240,6,11,12,54,8,92,24,76,16,138,104,195,66,116,149,117,141,
193,224,17,22,24,112,153,178,250,130,122,155,75,163,75,123,115,219,176,12,
101,80,97,151,55,120,131,5,6,27,4,50,48,131,13,131,24,156,1,176,
161,144,38,52,120,128,42,108,108,118,109,46,105,100,101,110,116,83,130,160,
10,25,158,139,93,153,220,92,218,155,219,148,128,104,66,134,231,98,23,198,
102,87,38,55,37,48,234,144,225,185,204,161,133,145,149,201,53,189,145,149,
177,77,9,144,50,100,120,46,114,101,115,111,117,114,99,101,115,83,2,167,
14,25,158,139,93,90,217,93,18,217,20,93,24,93,217,148,0,170,67,134,
231,82,230,70,39,151,7,245,150,230,70,55,55,37,64,3,0,0,121,24,
0,0,76,0,0,0,51,8,128,28,196,225,28,102,20,1,61,136,67,56,
132,195,140,66,128,7,121,120,7,115,152,113,12,230,0,15,237,16,14,244,
128,14,51,12,66,30,194,193,29,206,161,28,102,48,5,61,136,67,56,132,
131,27,204,3,61,200,67,61,140,3,61,204,120,140,116,112,7,123,8,7,
121,72,135,112,112,7,122,112,3,118,120,135,112,32,135,25,204,17,14,236,
144,14,225,48,15,110,48,15,227,240,14,240,80,14,51,16,196,29,222,33,
28,216,33,29,194,97,30,102,48,137,59,188,131,59,208,67,57,180,3,60,
188,131,60,132,3,59,204,240,20,118,96,7,123,104,7,55,104,135,114,104,
7,55,128,135,112,144,135,112,96,7,118,40,7,118,248,5,118,120,135,119,
128,135,95,8,135,113,24,135,114,152,135,121,152,129,44,238,240,14,238,224,
14,245,192,14,236,48,3,98,200,161,28,228,161,28,204,161,28,228,161,28,
220,97,28,202,33,28,196,129,29,202,97,6,214,144,67,57,200,67,57,152,
67,57,200,67,57,184,195,56,148,67,56,136,3,59,148,195,47,188,131,60,
252,130,59,212,3,59,176,195,12,196,33,7,124,112,3,122,40,135,118,128,
135,25,209,67,14,248,224,6,228,32,14,231,224,6,246,16,14,242,192,14,
225,144,15,239,80,15,244,0,0,0,113,32,0,0,24,0,0,0,6,32,
188,172,13,108,195,229,59,143,47,4,84,81,16,81,233,0,67,73,24,128,
128,249,197,109,91,129,52,92,190,243,248,66,68,0,19,17,2,205,176,16,
22,48,13,151,239,60,254,226,0,131,216,60,212,228,23,183,109,2,213,112,
249,206,227,75,147,19,17,40,53,61,212,228,23,183,109,4,210,112,249,206,
227,79,68,52,33,64,132,249,197,109,3,0,0,0,97,32,0,0,122,0,
0,0,19,4,65,44,16,0,0,0,5,0,0,0,68,138,171,20,10,97,
6,160,236,74,174,8,168,148,0,197,17,0,0,0,35,6,9,0,130,96,
32,97,4,99,89,193,136,65,2,128,32,24,24,29,130,93,208,49,98,144,
0,32,8,6,134,151,100,24,129,140,24,36,0,8,130,129,241,41,90,246,
36,35,6,9,0,130,96,96,128,193,178,105,146,50,98,144,0,32,8,6,
70,24,48,219,70,45,35,6,9,0,130,96,96,136,65,195,113,8,51,98,
144,0,32,8,6,198,24,56,93,55,53,35,6,7,0,130,96,208,136,65,
131,120,163,9,1,48,154,32,4,163,9,131,48,154,64,12,35,6,7,0,
130,96,208,156,129,212,144,193,104,66,0,140,38,8,193,104,194,32,140,38,
16,195,136,193,1,128,32,24,52,108,112,73,213,104,66,0,140,38,8,193,
104,194,32,140,38,16,195,136,193,1,128,32,24,52,113,192,93,106,48,154,
16,0,163,9,66,48,154,48,8,163,9,196,96,211,37,159,17,3,4,0,
65,48,120,236,192,12,158,43,24,49,64,0,16,4,131,231,14,206,96,185,
2,11,14,232,152,181,201,103,196,0,1,64,16,12,30,61,80,3,105,11,
70,12,16,0,4,193,224,217,131,53,112,182,192,2,5,58,150,125,242,25,
49,64,0,16,4,131,199,15,220,160,250,130,17,3,4,0,65,48,120,254,
224,13,162,47,176,160,129,142,113,99,32,159,17,3,4,0,65,48,120,68,
65,14,176,49,8,70,12,16,0,4,193,224,25,133,57,160,198,32,176,0,
130,206,136,65,2,128,32,24,32,167,64,7,163,32,10,123,208,140,24,36,
0,8,130,1,114,10,116,48,10,162,224,6,201,136,65,2,128,32,24,32,
167,64,7,163,32,10,120,80,140,24,36,0,8,130,1,114,10,116,48,10,
162,160,7,193,136,65,2,128,32,24,32,167,64,7,162,32,10,123,176,6,
35,6,9,0,130,96,128,156,2,29,136,130,40,184,129,26,140,24,36,0,
8,130,1,114,10,116,32,10,162,128,7,105,48,98,144,0,32,8,6,200,
41,208,129,40,136,130,30,160,1,2,0,0,0,0
};
const BYTE pixel_shader[] =
{
68,88,66,67,155,38,61,235,152,175,36,0,5,163,174,225,114,25,46,
165,1,0,0,0,48,6,0,0,6,0,0,0,56,0,0,0,72,0,0,
0,126,0,0,0,184,0,0,0,64,1,0,0,92,1,0,0,83,70,73,
48,8,0,0,0,0,0,0,0,0,0,0,0,73,83,71,49,46,0,0,
0,1,0,0,0,8,0,0,0,0,0,0,0,40,0,0,0,0,0,0,
0,0,0,0,0,3,0,0,0,0,0,0,0,15,15,0,0,0,0,0,
0,67,79,76,79,82,0,79,83,71,49,50,0,0,0,1,0,0,0,8,
0,0,0,0,0,0,0,40,0,0,0,0,0,0,0,64,0,0,0,3,
0,0,0,0,0,0,0,15,0,0,0,0,0,0,0,83,86,95,84,97,
114,103,101,116,0,80,83,86,48,128,0,0,0,48,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,
255,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,8,0,0,0,0,67,79,76,79,82,0,
0,1,0,0,0,0,0,0,0,16,0,0,0,1,0,0,0,0,0,0,
0,1,0,68,0,3,2,0,0,0,0,0,0,0,0,0,0,1,0,68,
16,3,0,0,0,1,0,0,0,2,0,0,0,4,0,0,0,8,0,0,
0,72,65,83,72,20,0,0,0,0,0,0,0,12,2,178,107,86,235,87,
236,39,12,117,190,13,71,209,140,68,88,73,76,204,4,0,0,96,0,0,
0,51,1,0,0,68,88,73,76,0,1,0,0,16,0,0,0,180,4,0,
0,66,67,192,222,33,12,0,0,42,1,0,0,11,130,32,0,2,0,0,
0,19,0,0,0,7,129,35,145,65,200,4,73,6,16,50,57,146,1,132,
12,37,5,8,25,30,4,139,98,128,16,69,2,66,146,11,66,132,16,50,
20,56,8,24,75,10,50,66,136,72,144,20,32,67,70,136,165,0,25,50,
66,228,72,14,144,17,34,196,80,65,81,129,140,225,131,229,138,4,33,70,
6,81,24,0,0,6,0,0,0,27,140,224,255,255,255,255,7,64,2,168,
13,132,240,255,255,255,255,3,32,1,0,0,0,73,24,0,0,2,0,0,
0,19,130,96,66,32,0,0,0,137,32,0,0,15,0,0,0,50,34,8,
9,32,100,133,4,19,34,164,132,4,19,34,227,132,161,144,20,18,76,136,
140,11,132,132,76,16,48,35,0,37,0,138,25,128,57,2,48,152,35,64,
138,49,68,84,68,86,12,32,162,26,194,129,128,52,32,0,0,19,20,114,
192,135,116,96,135,54,104,135,121,104,3,114,192,135,13,175,80,14,109,208,
14,122,80,14,109,0,15,122,48,7,114,160,7,115,32,7,109,144,14,113,
160,7,115,32,7,109,144,14,120,160,7,115,32,7,109,144,14,113,96,7,
122,48,7,114,208,6,233,48,7,114,160,7,115,32,7,109,144,14,118,64,
7,122,96,7,116,208,6,230,16,7,118,160,7,115,32,7,109,96,14,115,
32,7,122,48,7,114,208,6,230,96,7,116,160,7,118,64,7,109,224,14,
120,160,7,113,96,7,122,48,7,114,160,7,118,64,7,67,158,0,0,0,
0,0,0,0,0,0,0,0,134,60,6,16,0,1,0,0,0,0,0,0,
0,12,121,16,32,0,4,0,0,0,0,0,0,0,200,2,1,11,0,0,
0,50,30,152,16,25,17,76,144,140,9,38,71,198,4,67,162,18,24,1,
40,134,50,40,15,170,146,24,1,40,130,66,40,16,218,177,12,130,8,4,
2,1,0,0,0,121,24,0,0,65,0,0,0,26,3,76,144,70,2,19,
196,49,32,195,27,67,129,147,75,179,11,163,43,75,1,137,113,185,113,129,
113,153,193,201,177,1,65,129,145,137,49,195,49,155,41,139,73,217,16,4,
19,4,98,152,32,16,196,6,97,32,38,8,68,177,65,24,12,10,112,115,
27,6,196,32,38,8,75,179,33,80,38,8,2,64,1,106,138,197,208,19,
211,147,212,4,161,64,38,8,69,178,33,32,38,8,133,50,65,40,150,9,
2,97,76,16,136,99,131,64,85,27,22,194,121,160,72,26,38,2,178,54,
4,23,147,41,171,47,170,48,185,179,50,186,9,66,193,108,88,136,236,209,
34,104,152,8,200,218,16,108,27,6,140,3,54,20,76,211,1,64,21,54,
54,187,54,151,52,178,50,55,186,41,65,80,133,12,207,197,174,76,110,46,
237,205,109,74,64,52,33,195,115,177,11,99,179,43,147,155,18,24,117,200,
240,92,230,208,194,200,202,228,154,222,200,202,216,166,4,72,29,50,60,23,
187,180,178,187,36,178,41,186,48,186,178,41,129,82,135,12,207,165,204,141,
78,46,15,234,45,205,141,110,110,74,208,1,0,121,24,0,0,76,0,0,
0,51,8,128,28,196,225,28,102,20,1,61,136,67,56,132,195,140,66,128,
7,121,120,7,115,152,113,12,230,0,15,237,16,14,244,128,14,51,12,66,
30,194,193,29,206,161,28,102,48,5,61,136,67,56,132,131,27,204,3,61,
200,67,61,140,3,61,204,120,140,116,112,7,123,8,7,121,72,135,112,112,
7,122,112,3,118,120,135,112,32,135,25,204,17,14,236,144,14,225,48,15,
110,48,15,227,240,14,240,80,14,51,16,196,29,222,33,28,216,33,29,194,
97,30,102,48,137,59,188,131,59,208,67,57,180,3,60,188,131,60,132,3,
59,204,240,20,118,96,7,123,104,7,55,104,135,114,104,7,55,128,135,112,
144,135,112,96,7,118,40,7,118,248,5,118,120,135,119,128,135,95,8,135,
113,24,135,114,152,135,121,152,129,44,238,240,14,238,224,14,245,192,14,236,
48,3,98,200,161,28,228,161,28,204,161,28,228,161,28,220,97,28,202,33,
28,196,129,29,202,97,6,214,144,67,57,200,67,57,152,67,57,200,67,57,
184,195,56,148,67,56,136,3,59,148,195,47,188,131,60,252,130,59,212,3,
59,176,195,12,196,33,7,124,112,3,122,40,135,118,128,135,25,209,67,14,
248,224,6,228,32,14,231,224,6,246,16,14,242,192,14,225,144,15,239,80,
15,244,0,0,0,113,32,0,0,10,0,0,0,6,32,164,172,5,76,195,
229,59,143,191,56,192,32,54,15,53,249,197,109,155,64,53,92,190,243,248,
210,228,68,4,74,77,15,53,249,197,109,3,0,97,32,0,0,30,0,0,
0,19,4,65,44,16,0,0,0,3,0,0,0,68,133,48,3,80,10,84,
37,80,6,0,0,35,6,9,0,130,96,96,72,197,243,40,196,136,65,2,
128,32,24,24,147,1,65,67,49,98,144,0,32,8,6,6,117,68,209,98,
140,24,36,0,8,130,129,81,33,146,68,28,35,6,9,0,130,96,128,84,
199,52,57,196,136,65,2,128,32,24,32,213,49,77,198,48,98,144,0,32,
8,6,72,117,76,83,35,140,24,36,0,8,130,1,82,29,211,84,4,8,
0,0,0,0,0
};
struct Vec3
{
float x;
float y;
float z;
};
struct Vec4
{
float x;
float y;
float z;
float w;
};
struct Vertex
{
Vec3 position;
Vec4 color;
};
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; }
//-----------------------------------------------------------
// These functions will be called from unity render thread,
// see kUnityD3D12GraphicsQueueAccess_DontCare
// Demonstrates how to use the CommandRecordingState
virtual void DrawSimpleTriangles(const float worldMatrix[16], int triangleCount, const void* verticesFloat3Byte4) override;
// These demonstrate how to submit work via ExecuteCommandList
virtual void* BeginModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int* outRowPitch) override;
virtual void EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr) override;
virtual void* BeginModifyVertexBuffer(void* bufferHandle, size_t* outBufferSize) override;
virtual void EndModifyVertexBuffer(void* bufferHandle) override;
virtual void drawToRenderTexture() override;
//-----------------------------------------------------------
//-----------------------------------------------------------
// These functions will be called from unity submission thread,
// see kUnityD3D12GraphicsQueueAccess_Allow
// Demonstrates how to submit work to unity command queue
// directly via GetCommandQueue
virtual void drawToPluginTexture() override;
//-----------------------------------------------------------
virtual void* getRenderTexture() override;
virtual void setRenderTextureResource(UnityRenderBuffer rb) override;
virtual bool isSwapChainAvailable() override;
virtual unsigned int getPresentFlags() override;
virtual unsigned int getSyncInterval() override;
virtual unsigned int getBackbufferWidth() override;
virtual unsigned int getBackbufferHeight() override;
private:
UINT64 align_pow2(UINT64 value);
// Aligns texture to power of 2 boundary
UINT64 get_aligned_size(int width, int height, int pixelSize, int rowPitch);
// Creates a new buffer on D3D12_HEAP_TYPE_UPLOAD when resource points to a nullptr.
// When resource points to a existing ID3D12Resource* we only check if it's big enough
// to hold the size, if not return false
bool get_upload_resource(ID3D12Resource** resource, UINT64 size, LPCWSTR name);
// Creates dx12 buffer, if heapType allows CPU-access the resource will be also mapped
bool create_D3D12_buffer(size_t sizeInBytes, D3D12_HEAP_TYPE heapType, D3D12_RESOURCE_FLAGS resourceFlags, D3D12_RESOURCE_STATES initialResourceState, LPCWSTR resourceName, D3D12MemoryObject* buffer);
// Creates two buffers; one on D3D12_HEAP_TYPE_UPLOAD and one on D3D12_HEAP_TYPE_DEFAULT,
// copies contents from initData to -> upload buffer -> default buffer
bool create_D3D12_default_buffer(ID3D12GraphicsCommandList* cmdLst, const void* initData, unsigned int bufferSizeInBytes, LPCWSTR uploadHeapResourceName, LPCWSTR defaultHeapResourceName, D3D12DefaultBufferMemoryObject& outMemoryObj);
ID3D12PipelineState* create_triangle_pipeline();
void create_triangle_input_layout();
bool create_triangle_root_signature();
// Push buffer to deletion queue
void safe_destroy(unsigned long long frameNumber, const D3D12MemoryObject& buffer);
// Processes deletion queue
void garbage_collect(bool force = false);
// Destroy buffer without deletion queue
void immediate_destroy_d3d12_buffer(D3D12MemoryObject& buffer);
// Creates and initializes all resources that are used across multiple frames
void initialize_and_create_resources();
void release_resources();
// Records commands that draw a single triangle to target_texture
void record_draw_cmd_list(ID3D12CommandAllocator* cmd_alloc, ID3D12GraphicsCommandList* cmd, ID3D12RootSignature* rootsig, D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle, D3D12_VERTEX_BUFFER_VIEW* vbview, const float* world_matrix, D3D12_VIEWPORT* viewport, ID3D12PipelineState* pso, ID3D12Resource* target_texture, D3D12_RESOURCE_STATES target_state);
// Demonstrates how to submit work to unity worker thread via ExecuteCommandList API
UINT64 submit_cmd_to_unity_worker(ID3D12GraphicsCommandList* cmd, UnityGraphicsD3D12ResourceState* resource_states, int state_count);
// Creates a texture that can be used as render target
ID3D12Resource* create_render_texture();
void create_render_texture_rtv(ID3D12DescriptorHeap* desc_heap, ID3D12Resource* target, UINT offset);
void transition_barrier(ID3D12GraphicsCommandList* cmd, ID3D12Resource* resource, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after);
// When unity frame fence changes we can be sure that previously submitted command lists have finished executing
void wait_for_unity_frame_fence(UINT64 fence_value);
// Wait on any user provided fence
void wait_on_fence(UINT64 fence_value, ID3D12Fence* fence, HANDLE fence_event);
DXGI_FORMAT typeless_fmt_to_typed(DXGI_FORMAT format);
typedef std::vector<D3D12MemoryObject> D3D12Buffers;
typedef std::map<unsigned long long, D3D12Buffers> DeleteQueue;
typedef std::unordered_map<void*, void*> MappedVertexBuffers;
IUnityGraphicsD3D12v7* s_d3d12;
ID3D12Resource* s_upload_texture;
ID3D12Resource* s_upload_buffer;
ID3D12PipelineState* m_triangle_pso;
D3D12_INPUT_ELEMENT_DESC m_triangle_layout[2];
ID3D12RootSignature* m_triangle_rootsig;
D3D12DefaultBufferMemoryObject m_triangle_vertex_buffer;
ID3D12DescriptorHeap* m_triangle_rtv_desc_heap;
ID3D12DescriptorHeap* m_triangle_dsv_desc_heap;
DeleteQueue m_DeleteQueue;
MappedVertexBuffers m_mapped_triangle_vertex_buffers;
ID3D12DescriptorHeap* m_texture_rtv_desc_heap;
UINT m_texture_rtv_desc_size;
ID3D12Resource* m_render_texture_vertex_buffer;
D3D12_VERTEX_BUFFER_VIEW m_texture_vertex_buffer_view;
std::atomic<ID3D12Resource*> m_render_texture;
std::atomic<ID3D12Resource*> m_plugin_texture;
UINT m_texture_width = 256;
UINT m_texture_height = 256;
ID3D12CommandAllocator* m_render_texture_cmd_allocator;
ID3D12GraphicsCommandList* m_render_texture_cmd_list;
ID3D12CommandAllocator* m_plugin_texture_cmd_allocator;
ID3D12GraphicsCommandList* m_plugin_texture_cmd_list;
ID3DBlob* m_render_texture_root_blob;
ID3D12RootSignature* m_texture_root_sig;
ID3D12PipelineState* m_texture_pso;
std::atomic<bool> m_are_resources_initialized = false;
UINT64 m_plugin_texture_fence_value = 0;
ID3D12Fence* m_plugin_texture_fence;
HANDLE m_plugin_texture_fence_event;
ID3D12CommandAllocator* m_vertex_copy_cmd_allocator;
ID3D12GraphicsCommandList* m_vertex_copy_cmd_list;
ID3D12CommandAllocator* m_texture_copy_cmd_allocator;
ID3D12GraphicsCommandList* m_texture_copy_cmd_list;
UINT64 m_vertex_copy_fence = 0;
UINT64 m_texture_copy_fence = 0;
UINT64 m_render_texture_draw_fence = 0;
HANDLE m_fence_event;
bool m_is_render_texture_created_by_unity = false;
};
RenderAPI* CreateRenderAPI_D3D12()
{
return new RenderAPI_D3D12();
}
const UINT kNodeMask = 0;
RenderAPI_D3D12::RenderAPI_D3D12()
: s_d3d12(NULL)
, s_upload_texture(NULL)
, s_upload_buffer(NULL)
, m_triangle_pso(NULL)
, m_triangle_rootsig(NULL)
, m_triangle_rtv_desc_heap(NULL)
, m_triangle_dsv_desc_heap(NULL)
, m_texture_rtv_desc_heap(NULL)
, m_texture_rtv_desc_size(NULL)
, m_render_texture_vertex_buffer(NULL)
, m_render_texture_cmd_allocator(NULL)
, m_render_texture_cmd_list(NULL)
{
}
UINT64 CalcByteAlignedValue(unsigned int byteSize, unsigned int byteAlignment)
{
UINT byteAlignmentMinusOne = byteAlignment - 2;
return (byteSize + byteAlignmentMinusOne) & ~byteAlignmentMinusOne;
}
UINT64 RenderAPI_D3D12::align_pow2(UINT64 value)
{
UINT64 aligned = static_cast<UINT64>(pow(2, (int)log2(value)));
return aligned >= value ? aligned : aligned * 2;
}
UINT64 RenderAPI_D3D12::get_aligned_size(int width, int height, int pixelSize, int rowPitch)
{
UINT64 size = width * height * pixelSize;
size = align_pow2(size);
if (size < D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT)
{
return D3D12_SMALL_RESOURCE_PLACEMENT_ALIGNMENT;
}
else if (width * pixelSize < rowPitch)
{
return rowPitch * height;
}
else
{
return size;
}
}
bool RenderAPI_D3D12::create_D3D12_default_buffer(ID3D12GraphicsCommandList* cmdLst, const void* initData, unsigned int bufferSizeInBytes, LPCWSTR uploadHeapResourceName, LPCWSTR defaultHeapResourceName, D3D12DefaultBufferMemoryObject& outMemoryObj)
{
if (!cmdLst)
return false;
if (!create_D3D12_buffer(bufferSizeInBytes, D3D12_HEAP_TYPE_UPLOAD, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_GENERIC_READ, uploadHeapResourceName, &outMemoryObj.uploadResource))
return false;
if (!create_D3D12_buffer(bufferSizeInBytes, D3D12_HEAP_TYPE_DEFAULT, D3D12_RESOURCE_FLAG_NONE, D3D12_RESOURCE_STATE_COMMON, defaultHeapResourceName, &outMemoryObj.defaultResource))
return false;
ID3D12Resource* uploadResource = outMemoryObj.uploadResource.resource;
ID3D12Resource* defaultResource = outMemoryObj.defaultResource.resource;
D3D12_SUBRESOURCE_DATA subResourceDataDesc;
subResourceDataDesc.pData = initData;
subResourceDataDesc.RowPitch = outMemoryObj.uploadResource.deviceMemorySize;
subResourceDataDesc.SlicePitch = subResourceDataDesc.RowPitch;
transition_barrier(cmdLst, defaultResource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
UpdateSubresources<1>(cmdLst, defaultResource, uploadResource, 0, 0, 1, &subResourceDataDesc);
transition_barrier(cmdLst, defaultResource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
return true;
}
bool RenderAPI_D3D12::create_D3D12_buffer(size_t sizeInBytes, D3D12_HEAP_TYPE heapType, D3D12_RESOURCE_FLAGS resourceFlags, D3D12_RESOURCE_STATES initialResourceState, LPCWSTR resourceName, D3D12MemoryObject* buffer)
{
ID3D12Device* device = s_d3d12->GetDevice();
UINT64 alignedBufferSizeInBytes = CalcByteAlignedValue(static_cast<unsigned int>(sizeInBytes), 256);
HRESULT hr = S_OK;
CD3DX12_HEAP_PROPERTIES heap_props = CD3DX12_HEAP_PROPERTIES(heapType);
CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(alignedBufferSizeInBytes, resourceFlags);
ReturnOnFail(
device->CreateCommittedResource(
&heap_props,
D3D12_HEAP_FLAG_NONE,
&resource_desc,
initialResourceState,
NULL,
IID_PPV_ARGS(&buffer->resource)),
hr,
"CreateD3D12Buffer Failed\n",
false
);
if (heapType == D3D12_HEAP_TYPE_UPLOAD)
{
hr = buffer->resource->Map(0, NULL, &buffer->mapped);
if (FAILED(hr))
{
OutputDebugStringA("Failed to map buffer.\n");
buffer->resource->Release();
buffer->resource = NULL;
return false;
}
}
else
buffer->mapped = NULL;
buffer->heapType = heapType;
buffer->resourceFlags = resourceFlags;
buffer->deviceMemorySize = alignedBufferSizeInBytes;
buffer->resourceFlags = resourceFlags;
if (resourceName != NULL)
buffer->resource->SetName(resourceName);
return true;
}
void RenderAPI_D3D12::create_triangle_input_layout()
{
m_triangle_layout[0] = D3D12_INPUT_ELEMENT_DESC(
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
);
m_triangle_layout[1] = D3D12_INPUT_ELEMENT_DESC(
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
);
}
bool RenderAPI_D3D12::create_triangle_root_signature()
{
HRESULT hr = S_OK;
CD3DX12_ROOT_PARAMETER slotRootParameter[1];
slotRootParameter[0].InitAsConstants(64, 0, 0, D3D12_SHADER_VISIBILITY_ALL);
CD3DX12_ROOT_SIGNATURE_DESC rsDesc(1, slotRootParameter, 0, NULL, D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
ID3DBlob* serializedRootSigBlob = NULL;
ID3DBlob* errorBlob = NULL;
ReturnOnFail(
D3D12SerializeRootSignature(&rsDesc, D3D_ROOT_SIGNATURE_VERSION_1, &serializedRootSigBlob, &errorBlob),
hr,
"D3D12SerializeRootSignature Failed\n",
false
);
ID3D12Device* device = s_d3d12->GetDevice();
ReturnOnFail(
device->CreateRootSignature(0, serializedRootSigBlob->GetBufferPointer(), serializedRootSigBlob->GetBufferSize(), __uuidof(ID3D12RootSignature), reinterpret_cast<void**>(&m_triangle_rootsig)); ,
hr,
"CreateRootSignature Failed\n",
false
);
return true;
}
ID3D12PipelineState* RenderAPI_D3D12::create_triangle_pipeline()
{
HRESULT hr = S_OK;
if (!create_triangle_root_signature())
return NULL;
create_triangle_input_layout();
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc;
ZeroMemory(&desc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
desc.InputLayout = { m_triangle_layout, 2 };
desc.pRootSignature = m_triangle_rootsig;
desc.VS = {
vertex_shader,
sizeof(vertex_shader)
};
desc.PS = {
pixel_shader,
sizeof(pixel_shader)
};
desc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
desc.RasterizerState.MultisampleEnable = true;
desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
desc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
desc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
desc.DepthStencilState.DepthEnable = true;
desc.DepthStencilState.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; // Unity uses reverse z depth
desc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;
desc.SampleMask = UINT_MAX;
desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
desc.NumRenderTargets = 1;
desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.DSVFormat = DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
ID3D12Device* device = s_d3d12->GetDevice();
ReturnOnFail(
device->CreateGraphicsPipelineState(&desc, __uuidof(ID3D12PipelineState), reinterpret_cast<void**>(&m_triangle_pso)),
hr,
"CreateGraphicsPipelineState Failed\n",
NULL
);
return m_triangle_pso;
}
bool RenderAPI_D3D12::get_upload_resource(ID3D12Resource** outResource, UINT64 size, LPCWSTR name)
{
ID3D12Resource*& resource = *outResource;
if (resource)
{
D3D12_RESOURCE_DESC desc = resource->GetDesc();
if (desc.Width == size)
return true;
else
{
resource->Release();
return false;
}
}
// Texture upload buffer
D3D12_HEAP_PROPERTIES heapProps = {};
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapProps.CreationNodeMask = kNodeMask;
heapProps.VisibleNodeMask = kNodeMask;
D3D12_RESOURCE_DESC heapDesc = {};
heapDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
heapDesc.Alignment = 0;
heapDesc.Width = size;
heapDesc.Height = 1;
heapDesc.DepthOrArraySize = 1;
heapDesc.MipLevels = 1;
heapDesc.Format = DXGI_FORMAT_UNKNOWN;
heapDesc.SampleDesc.Count = 1;
heapDesc.SampleDesc.Quality = 0;
heapDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
heapDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
HRESULT hr = S_OK;
ID3D12Device* device = s_d3d12->GetDevice();
ReturnOnFail(
device->CreateCommittedResource(
&heapProps,
D3D12_HEAP_FLAG_NONE,
&heapDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&resource)),
hr,
"CreateCommittedResource Failed\n",
false
);
if (name != NULL)
resource->SetName(name);
return true;
}
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);
initialize_and_create_resources();
break;
case kUnityGfxDeviceEventShutdown:
release_resources();
break;
}
}
void RenderAPI_D3D12::DrawSimpleTriangles(const float worldMatrix[16], int triangleCount, const void* verticesFloat3Byte4)
{
UnityGraphicsD3D12RecordingState recordingState;
if (!s_d3d12->CommandRecordingState(&recordingState))
return;
if (m_triangle_pso == NULL)
{
m_triangle_pso = create_triangle_pipeline();
}
if (m_triangle_pso != NULL)
{
ID3D12GraphicsCommandList* cmdLst = recordingState.commandList;
garbage_collect();
const int kVertexSize = 12 + 4; // 12 bytes for position and 4 bytes for color
const UINT vertexBufferSizeInBytes = kVertexSize * 3 * triangleCount;
if (!create_D3D12_default_buffer(cmdLst, verticesFloat3Byte4, vertexBufferSizeInBytes, D3D12_UPLOAD_HEAP_TRIANGLE_BUFFER_NAME, D3D12_DEFAULT_HEAP_TRIANGLE_BUFFER_NAME, m_triangle_vertex_buffer))
return;
cmdLst->SetPipelineState(m_triangle_pso);
cmdLst->SetGraphicsRootSignature(m_triangle_rootsig);
cmdLst->SetGraphicsRoot32BitConstants(0, 64, worldMatrix, 0);
D3D12_VERTEX_BUFFER_VIEW vbView;
vbView.BufferLocation = m_triangle_vertex_buffer.defaultResource.resource->GetGPUVirtualAddress();
vbView.SizeInBytes = vertexBufferSizeInBytes;
vbView.StrideInBytes = kVertexSize;
cmdLst->IASetVertexBuffers(0, 1, &vbView);
cmdLst->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cmdLst->DrawInstanced(triangleCount * 3, 1, 0, 0);
UINT64 nextval = s_d3d12->GetNextFrameFenceValue();
ID3D12Fence* fence = s_d3d12->GetFrameFence();
UINT64 lastCompletedFenceValue = fence->GetCompletedValue();
lastCompletedFenceValue += 3;
safe_destroy(lastCompletedFenceValue, m_triangle_vertex_buffer.uploadResource);
safe_destroy(lastCompletedFenceValue, m_triangle_vertex_buffer.defaultResource);
}
}
void RenderAPI_D3D12::safe_destroy(unsigned long long frameNumber, const D3D12MemoryObject& buffer)
{
m_DeleteQueue[frameNumber].push_back(buffer);
}
void RenderAPI_D3D12::garbage_collect(bool force /*= false*/)
{
ID3D12Fence* fence = s_d3d12->GetFrameFence();
UINT64 lastCompletedFenceValue = fence->GetCompletedValue();
DeleteQueue::iterator it = m_DeleteQueue.begin();
while (it != m_DeleteQueue.end())
{
if (force || it->first <= lastCompletedFenceValue)
{
for (size_t i = 0; i < it->second.size(); ++i)
immediate_destroy_d3d12_buffer(it->second[i]);
m_DeleteQueue.erase(it++);
}
else
++it;
}
}
void RenderAPI_D3D12::immediate_destroy_d3d12_buffer(D3D12MemoryObject& buffer)
{
if (buffer.resource == NULL)
return;
if (buffer.mapped)
{
buffer.resource->Unmap(0, NULL);
buffer.mapped = 0;
}
SAFE_RELEASE(buffer.resource);
}
void RenderAPI_D3D12::initialize_and_create_resources()
{
if (m_are_resources_initialized)
return;
ID3D12Device* device = s_d3d12->GetDevice();
assert(device != nullptr);
UnityGraphicsD3D12PhysicalVideoMemoryControlValues control_values;
control_values.reservation = 64000000;
control_values.systemMemoryThreshold = 64000000;
control_values.residencyHysteresisThreshold = 128000000;
control_values.nonEvictableRelativeThreshold = 0.25;
s_d3d12->SetPhysicalVideoMemoryControlValues(&control_values);
constexpr Vertex vertices[] {
// position color
// <---------------> <-------------------->
{{ 0.0f, 1.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
{{ 1.0f, -1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
{{ -1.0f, -1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
};
D3D12_INPUT_ELEMENT_DESC position = {};
position.SemanticName = "POSITION";
position.SemanticIndex = 0;
position.Format = DXGI_FORMAT_R32G32B32_FLOAT;
position.AlignedByteOffset = 0;
position.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
position.InstanceDataStepRate = 0;
D3D12_INPUT_ELEMENT_DESC color = {};
color.SemanticName = "COLOR";
color.SemanticIndex = 0;
color.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
color.AlignedByteOffset = 12;
color.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
color.InstanceDataStepRate = 0;
D3D12_INPUT_ELEMENT_DESC input_element_desc[] = {position, color};
D3D12_RESOURCE_DESC vertex_buffer_desc = {};
vertex_buffer_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
vertex_buffer_desc.Alignment = 0;
vertex_buffer_desc.Width = sizeof(vertices);
vertex_buffer_desc.Height = 1;
vertex_buffer_desc.DepthOrArraySize = 1;
vertex_buffer_desc.MipLevels = 1;
vertex_buffer_desc.Format = DXGI_FORMAT_UNKNOWN;
vertex_buffer_desc.SampleDesc.Count = 1;
vertex_buffer_desc.SampleDesc.Quality = 0;
vertex_buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
vertex_buffer_desc.Flags = D3D12_RESOURCE_FLAG_NONE;
D3D12_HEAP_PROPERTIES vertex_buffer_heap_props = {};
vertex_buffer_heap_props.Type = D3D12_HEAP_TYPE_UPLOAD;
vertex_buffer_heap_props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
vertex_buffer_heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
vertex_buffer_heap_props.CreationNodeMask = 1;
vertex_buffer_heap_props.VisibleNodeMask = 1;
handle_hr(device->CreateCommittedResource(&vertex_buffer_heap_props, D3D12_HEAP_FLAG_NONE, &vertex_buffer_desc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_render_texture_vertex_buffer)),
"Failed to create vertex buffer for render texture\n");
char* data;
D3D12_RANGE read_range{ 0, 0 };
handle_hr(m_render_texture_vertex_buffer->Map(0, &read_range, reinterpret_cast<void**>(&data)));
memcpy(data, vertices, sizeof(vertices));
m_render_texture_vertex_buffer->Unmap(0, nullptr);
m_texture_vertex_buffer_view = {};
m_texture_vertex_buffer_view.BufferLocation = m_render_texture_vertex_buffer->GetGPUVirtualAddress();
m_texture_vertex_buffer_view.SizeInBytes = sizeof(vertices);
m_texture_vertex_buffer_view.StrideInBytes = sizeof(Vertex);
// 1st descriptor is for m_render_texture and 2nd one is for m_plugin_texture
D3D12_DESCRIPTOR_HEAP_DESC rtv_heap_desc = {};
rtv_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtv_heap_desc.NumDescriptors = 2;
rtv_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
rtv_heap_desc.NodeMask = 0;
handle_hr(device->CreateDescriptorHeap(&rtv_heap_desc, IID_PPV_ARGS(&m_texture_rtv_desc_heap)),
"Failed to create descriptor heap for render texture RTVs\n");
m_texture_rtv_desc_size = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
// When Unity does create it's own RenderBuffer and passes it to the plugin
// using setRenderTexture() we don't have to create one here.
if (!m_is_render_texture_created_by_unity)
m_render_texture = create_render_texture();
m_plugin_texture = create_render_texture();
create_render_texture_rtv(m_texture_rtv_desc_heap, m_render_texture, 0);
create_render_texture_rtv(m_texture_rtv_desc_heap, m_plugin_texture, 1);
m_render_texture.load()->SetName(L"plugin render texture\n");
// we store the world matrix in the root signature
D3D12_ROOT_CONSTANTS root_constants = {};
root_constants.ShaderRegister = 0;
root_constants.RegisterSpace = 0;
root_constants.Num32BitValues = 64; // maximum size for root sig
D3D12_ROOT_PARAMETER root_param = {};
root_param.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
root_param.Constants = root_constants;
root_param.ShaderVisibility = D3D12_SHADER_VISIBILITY_VERTEX;
D3D12_ROOT_SIGNATURE_DESC root_signature_desc = {};
root_signature_desc.NumParameters = 1;
root_signature_desc.pParameters = &root_param;
root_signature_desc.NumStaticSamplers = 0;
root_signature_desc.pStaticSamplers = nullptr;
root_signature_desc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
handle_hr(D3D12SerializeRootSignature(&root_signature_desc, D3D_ROOT_SIGNATURE_VERSION_1, &m_render_texture_root_blob, nullptr),
"Failed to serialize root signature for render texture\n");
handle_hr(device->CreateRootSignature(0, m_render_texture_root_blob->GetBufferPointer(), m_render_texture_root_blob->GetBufferSize(), IID_PPV_ARGS(&m_texture_root_sig)),
"Failed to create root signature for render texture\n");
D3D12_RASTERIZER_DESC rasterizer_desc = {};
rasterizer_desc.FillMode = D3D12_FILL_MODE_SOLID;
rasterizer_desc.CullMode = D3D12_CULL_MODE_NONE;
rasterizer_desc.FrontCounterClockwise = FALSE;
rasterizer_desc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
rasterizer_desc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
rasterizer_desc.SlopeScaledDepthBias = 0;
rasterizer_desc.MultisampleEnable = FALSE;
rasterizer_desc.MultisampleEnable = FALSE;
rasterizer_desc.AntialiasedLineEnable = FALSE;
rasterizer_desc.ForcedSampleCount = 0;
rasterizer_desc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
D3D12_RENDER_TARGET_BLEND_DESC render_target_blend_desc = {};
render_target_blend_desc.BlendEnable = FALSE;
render_target_blend_desc.LogicOpEnable = FALSE;
render_target_blend_desc.SrcBlend = D3D12_BLEND_ONE;
render_target_blend_desc.DestBlend = D3D12_BLEND_ZERO;
render_target_blend_desc.BlendOp = D3D12_BLEND_OP_ADD;
render_target_blend_desc.SrcBlendAlpha = D3D12_BLEND_ONE;
render_target_blend_desc.DestBlendAlpha = D3D12_BLEND_ZERO;
render_target_blend_desc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
render_target_blend_desc.LogicOp = D3D12_LOGIC_OP_NOOP;
render_target_blend_desc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
D3D12_BLEND_DESC blend_desc = {};
blend_desc.AlphaToCoverageEnable = FALSE;
blend_desc.IndependentBlendEnable = FALSE;
blend_desc.RenderTarget[0] = render_target_blend_desc;
D3D12_DEPTH_STENCIL_DESC depth_stencil_desc = {};
depth_stencil_desc.DepthEnable = FALSE;
depth_stencil_desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
depth_stencil_desc.DepthFunc = D3D12_COMPARISON_FUNC_NEVER;
depth_stencil_desc.StencilEnable = FALSE;
D3D12_SHADER_BYTECODE vertex_bytecode = {};
vertex_bytecode.pShaderBytecode = (void*)(vertex_shader);
vertex_bytecode.BytecodeLength = sizeof(vertex_shader);
D3D12_SHADER_BYTECODE pixel_bytecode = {};
pixel_bytecode.pShaderBytecode = (void*)(pixel_shader);
pixel_bytecode.BytecodeLength = sizeof(pixel_shader);
D3D12_INPUT_LAYOUT_DESC input_layout_desc = {};
input_layout_desc.pInputElementDescs = input_element_desc;
input_layout_desc.NumElements = _countof(input_element_desc);
DXGI_SAMPLE_DESC dxgi_sample_desc = {};
dxgi_sample_desc.Count = 1;
dxgi_sample_desc.Quality = 0;
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = {};
pso_desc.pRootSignature = m_texture_root_sig;
pso_desc.VS = vertex_bytecode;
pso_desc.PS = pixel_bytecode;
pso_desc.DS = { nullptr, 0 };
pso_desc.HS = { nullptr, 0 };
pso_desc.GS = { nullptr, 0 };
pso_desc.StreamOutput = {};
pso_desc.BlendState = blend_desc;
pso_desc.SampleMask = 1;
pso_desc.RasterizerState = rasterizer_desc;
pso_desc.DepthStencilState = depth_stencil_desc;
pso_desc.InputLayout = input_layout_desc;
pso_desc.IBStripCutValue = {};
pso_desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
pso_desc.NumRenderTargets = 1;
pso_desc.RTVFormats[0] = {DXGI_FORMAT_R8G8B8A8_UNORM};
pso_desc.DSVFormat = {};
pso_desc.SampleDesc = dxgi_sample_desc;
pso_desc.NodeMask = 0;
pso_desc.CachedPSO = { nullptr, 0 };
pso_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
handle_hr(device->CreateGraphicsPipelineState(&pso_desc, IID_PPV_ARGS(&m_texture_pso)),
"Failed to create PSO for render texture\n");
handle_hr(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_render_texture_cmd_allocator)),
"Failed to create cmd allocator for render texture\n");
handle_hr(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_render_texture_cmd_allocator, nullptr, IID_PPV_ARGS(&m_render_texture_cmd_list)),
"Failed to create cmd list for render texture\n");
handle_hr(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_plugin_texture_cmd_allocator)),
"Failed to create cmd allocator for plugin texture\n");
handle_hr(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_plugin_texture_cmd_allocator, nullptr, IID_PPV_ARGS(&m_plugin_texture_cmd_list)),
"Failed to create cmd list for render texture2\n");
handle_hr(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_texture_copy_cmd_allocator)),
"Failed to create cmd allocator for texture copy\n");
handle_hr(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_vertex_copy_cmd_allocator)),
"Failed to create cmd allocator for vertex copy\n");
handle_hr(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_texture_copy_cmd_allocator, nullptr, IID_PPV_ARGS(&m_texture_copy_cmd_list)),
"Failed to create texture copy cmd list\n");
handle_hr(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_vertex_copy_cmd_allocator, nullptr, IID_PPV_ARGS(&m_vertex_copy_cmd_list)),
"Failed to create vertex copy cmd list\n");
handle_hr(device->CreateFence(m_plugin_texture_fence_value, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_plugin_texture_fence)),
"Failed to create fence for plugin texture");
m_texture_copy_cmd_allocator->SetName(L"texture copy cmd allocator");
m_vertex_copy_cmd_allocator->SetName(L"vertex copy cmd allocator");
m_render_texture_cmd_allocator->SetName(L"render texture cmd allocator");
m_vertex_copy_cmd_list->SetName(L"vertex copy cmd list");
m_texture_copy_cmd_list->SetName(L"texture copy cmd list");
m_render_texture_cmd_list->SetName(L"render texture cmd list");
handle_hr(m_vertex_copy_cmd_list->Close(), "Failed to close cmd list for vertex copy\n");
handle_hr(m_texture_copy_cmd_list->Close(), "Failed to close cmd list for texture copy\n");
handle_hr(m_render_texture_cmd_list->Close(), "Failed to close cmd list for render texture\n");
handle_hr(m_plugin_texture_cmd_list->Close(), "Failed to close cmd list for plugin texture\n");
m_fence_event = CreateEvent(NULL, false, false, nullptr);
m_plugin_texture_fence_event = CreateEvent(NULL, false, false, nullptr);
D3D12_DESCRIPTOR_HEAP_DESC rtvDesc = {};
rtvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvDesc.NumDescriptors = 1;
rtvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
rtvDesc.NodeMask = 0;
handle_hr(device->CreateDescriptorHeap(&rtvDesc, IID_PPV_ARGS(&m_triangle_rtv_desc_heap)),
"CreateDescriptorHeap Failed\n");
D3D12_DESCRIPTOR_HEAP_DESC dsvDesc = {};
dsvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
dsvDesc.NumDescriptors = 1;
dsvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
dsvDesc.NodeMask = 0;
handle_hr(device->CreateDescriptorHeap(&dsvDesc, IID_PPV_ARGS(&m_triangle_dsv_desc_heap)),
"CreateDescriptorHeap Failed\n");
m_are_resources_initialized = true;
}
void RenderAPI_D3D12::release_resources()
{
SAFE_RELEASE(m_render_texture_cmd_list);
SAFE_RELEASE(m_render_texture_cmd_allocator);
SAFE_RELEASE(m_plugin_texture_cmd_list);
SAFE_RELEASE(m_plugin_texture_cmd_allocator);
SAFE_RELEASE(m_texture_pso);
SAFE_RELEASE(m_texture_root_sig);
SAFE_RELEASE(m_render_texture_root_blob);
SAFE_RELEASE(m_texture_rtv_desc_heap);
if (!m_is_render_texture_created_by_unity)
{
ID3D12Resource* render_texture = m_render_texture.load();
if (render_texture)
{
render_texture->Release();
m_render_texture = nullptr;
}
}
SAFE_RELEASE(m_render_texture_vertex_buffer);
SAFE_RELEASE(m_triangle_pso);
SAFE_RELEASE(m_triangle_rootsig);
SAFE_RELEASE(m_triangle_rtv_desc_heap);
SAFE_RELEASE(m_triangle_dsv_desc_heap);
SAFE_RELEASE(s_upload_texture);
SAFE_RELEASE(s_upload_buffer);
SAFE_RELEASE(m_vertex_copy_cmd_list);
SAFE_RELEASE(m_texture_copy_cmd_list);
SAFE_RELEASE(m_vertex_copy_cmd_allocator);
SAFE_RELEASE(m_texture_copy_cmd_allocator);
if (ID3D12Resource* plugin_texture = m_plugin_texture.load())
{
plugin_texture->Release();
m_plugin_texture = nullptr;
}
CloseHandle(m_fence_event);
CloseHandle(m_plugin_texture_fence_event);
garbage_collect(true);
m_mapped_triangle_vertex_buffers.clear();
}
void RenderAPI_D3D12::record_draw_cmd_list(ID3D12CommandAllocator* cmd_alloc, ID3D12GraphicsCommandList* cmd, ID3D12RootSignature* rootsig, D3D12_CPU_DESCRIPTOR_HANDLE rtv_handle, D3D12_VERTEX_BUFFER_VIEW* vbview, const float* world_matrix, D3D12_VIEWPORT* viewport, ID3D12PipelineState* pso, ID3D12Resource* target, D3D12_RESOURCE_STATES target_state)
{
constexpr FLOAT clear_color[4] = { 0.5f, 0.5f, 0.5f, 1.f };
handle_hr(cmd_alloc->Reset(), "Failed to reset cmd allocator\n");
handle_hr(cmd->Reset(cmd_alloc, pso), "Failed to reset cmd list\n");
cmd->SetGraphicsRootSignature(rootsig);
cmd->SetGraphicsRoot32BitConstants(0, 64, world_matrix, 0);
if (target_state != D3D12_RESOURCE_STATE_RENDER_TARGET)
{
transition_barrier(cmd, target, target_state, D3D12_RESOURCE_STATE_RENDER_TARGET);
}
cmd->OMSetRenderTargets(1, &rtv_handle, FALSE, nullptr);
cmd->ClearRenderTargetView(rtv_handle, clear_color, 0, nullptr);
D3D12_RECT scissor;
scissor.left = 0;
scissor.top = 0;
scissor.right = static_cast<LONG>(viewport->Width);
scissor.bottom = static_cast<LONG>(viewport->Height);
cmd->RSSetViewports(1, viewport);
cmd->RSSetScissorRects(1, &scissor);
cmd->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cmd->IASetVertexBuffers(0, 1, vbview);
const UINT vertices = vbview->SizeInBytes / vbview->StrideInBytes;
cmd->DrawInstanced(vertices, 1, 0, 0);
if (target_state != D3D12_RESOURCE_STATE_RENDER_TARGET)
{
transition_barrier(cmd, target, D3D12_RESOURCE_STATE_RENDER_TARGET, target_state);
}
handle_hr(cmd->Close(), "Failed to close draw cmd list\n");
}
UINT64 RenderAPI_D3D12::submit_cmd_to_unity_worker(ID3D12GraphicsCommandList* cmd, UnityGraphicsD3D12ResourceState* resource_states, int state_count)
{
return s_d3d12->ExecuteCommandList(cmd, state_count, resource_states);
}
ID3D12Resource* RenderAPI_D3D12::create_render_texture()
{
ID3D12Device* device = s_d3d12->GetDevice();
DXGI_SAMPLE_DESC dxgi_sample_desc = {};
dxgi_sample_desc.Count = 1;
dxgi_sample_desc.Quality = 0;
D3D12_RESOURCE_DESC render_texture_desc = {};
render_texture_desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
render_texture_desc.Width = m_texture_width;
render_texture_desc.Height = m_texture_height;
render_texture_desc.DepthOrArraySize = 1;
render_texture_desc.MipLevels = 1;
render_texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
render_texture_desc.SampleDesc = dxgi_sample_desc;
render_texture_desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
render_texture_desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
D3D12_HEAP_PROPERTIES render_texture_heap_props = {};
render_texture_heap_props.Type = D3D12_HEAP_TYPE_DEFAULT;
render_texture_heap_props.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
render_texture_heap_props.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
render_texture_heap_props.CreationNodeMask = 1;
render_texture_heap_props.VisibleNodeMask = 1;
ID3D12Resource* pRendertex;
handle_hr(device->CreateCommittedResource(&render_texture_heap_props, D3D12_HEAP_FLAG_NONE, &render_texture_desc, D3D12_RESOURCE_STATE_RENDER_TARGET, nullptr, IID_PPV_ARGS(&pRendertex)),
"Failed to create a render texture\n");
return pRendertex;
}
void RenderAPI_D3D12::create_render_texture_rtv(ID3D12DescriptorHeap* heap, ID3D12Resource* target, UINT offset)
{
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle{ heap->GetCPUDescriptorHandleForHeapStart() };
rtv_handle.Offset(offset, m_texture_rtv_desc_size);
D3D12_TEX2D_RTV rtv;
rtv.MipSlice = 0;
rtv.PlaneSlice = 0;
D3D12_RENDER_TARGET_VIEW_DESC desc;
desc.Format = typeless_fmt_to_typed(target->GetDesc().Format);
desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
desc.Texture2D = rtv;
s_d3d12->GetDevice()->CreateRenderTargetView(target, &desc, rtv_handle);
}
void RenderAPI_D3D12::transition_barrier(ID3D12GraphicsCommandList* cmd, ID3D12Resource* resource, D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after)
{
D3D12_RESOURCE_TRANSITION_BARRIER transition = {};
transition.pResource = resource;
transition.Subresource = 0;
transition.StateBefore = before;
transition.StateAfter = after;
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition = transition;
cmd->ResourceBarrier(1, &barrier);
}
void RenderAPI_D3D12::wait_for_unity_frame_fence(UINT64 fence_value)
{
ID3D12Fence* unity_fence = s_d3d12->GetFrameFence();
UINT64 current_fence_value = unity_fence->GetCompletedValue();
if (current_fence_value < fence_value)
{
handle_hr(unity_fence->SetEventOnCompletion(fence_value, m_fence_event), "Failed to set fence event on completion\n");
WaitForSingleObject(m_fence_event, INFINITE);
}
}
void RenderAPI_D3D12::wait_on_fence(UINT64 fence_value, ID3D12Fence* fence, HANDLE fence_event)
{
UINT64 current_fence_value = fence->GetCompletedValue();
if (current_fence_value < fence_value)
{
handle_hr(fence->SetEventOnCompletion(fence_value, fence_event));
WaitForSingleObject(fence_event, INFINITE);
}
}
DXGI_FORMAT RenderAPI_D3D12::typeless_fmt_to_typed(DXGI_FORMAT format)
{
switch (format)
{
case DXGI_FORMAT_R32G32B32A32_TYPELESS:
return DXGI_FORMAT_R32G32B32A32_UINT;
case DXGI_FORMAT_R32G32B32_TYPELESS:
return DXGI_FORMAT_R32G32B32_UINT;
case DXGI_FORMAT_R16G16B16A16_TYPELESS:
return DXGI_FORMAT_R16G16B16A16_UNORM;
case DXGI_FORMAT_R32G32_TYPELESS:
return DXGI_FORMAT_R32G32_UINT;
case DXGI_FORMAT_R32G8X24_TYPELESS:
return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
case DXGI_FORMAT_R10G10B10A2_TYPELESS:
return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT;
case DXGI_FORMAT_R8G8B8A8_TYPELESS:
return DXGI_FORMAT_R8G8B8A8_UNORM;
case DXGI_FORMAT_R16G16_TYPELESS:
return DXGI_FORMAT_R16G16_UNORM;
case DXGI_FORMAT_R32_TYPELESS:
return DXGI_FORMAT_R32_UINT;
case DXGI_FORMAT_R24G8_TYPELESS:
return DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
case DXGI_FORMAT_R8G8_TYPELESS:
return DXGI_FORMAT_R8G8_UNORM;
case DXGI_FORMAT_R16_TYPELESS:
return DXGI_FORMAT_R16_UNORM;
case DXGI_FORMAT_R8_TYPELESS:
return DXGI_FORMAT_R8_UNORM;
case DXGI_FORMAT_BC1_TYPELESS:
return DXGI_FORMAT_BC1_UNORM;
case DXGI_FORMAT_BC2_TYPELESS:
return DXGI_FORMAT_BC2_UNORM;
case DXGI_FORMAT_BC3_TYPELESS:
return DXGI_FORMAT_BC3_UNORM;
case DXGI_FORMAT_BC4_TYPELESS:
return DXGI_FORMAT_BC4_UNORM;
case DXGI_FORMAT_BC5_TYPELESS:
return DXGI_FORMAT_BC5_UNORM;
case DXGI_FORMAT_B8G8R8A8_TYPELESS:
return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;
case DXGI_FORMAT_B8G8R8X8_TYPELESS:
return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB;
case DXGI_FORMAT_BC6H_TYPELESS:
return DXGI_FORMAT_BC6H_UF16;
case DXGI_FORMAT_BC7_TYPELESS:
return DXGI_FORMAT_BC7_UNORM;
default:
return format;
}
}
void* RenderAPI_D3D12::BeginModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int* outRowPitch)
{
wait_for_unity_frame_fence(m_texture_copy_fence);
// Fill data
// Clamp to minimum rowPitch of RGBA32
*outRowPitch = static_cast<int>(max(align_pow2(textureWidth * 4), 256));
const UINT64 kDataSize = get_aligned_size(textureWidth, textureHeight, 4, *outRowPitch);
if (!get_upload_resource(&s_upload_texture, kDataSize, D3D12_UPLOAD_HEAP_TEXTURE_BUFFER_NAME))
return NULL;
void* mapped = NULL;
s_upload_texture->Map(0, NULL, &mapped);
return mapped;
}
void RenderAPI_D3D12::EndModifyTexture(void* textureHandle, int textureWidth, int textureHeight, int rowPitch, void* dataPtr)
{
ID3D12Device* device = s_d3d12->GetDevice();
const UINT64 kDataSize = get_aligned_size(textureWidth, textureHeight, 4, rowPitch);
if (!get_upload_resource(&s_upload_texture, kDataSize, D3D12_UPLOAD_HEAP_TEXTURE_BUFFER_NAME))
return;
s_upload_texture->Unmap(0, 0);
ID3D12Resource* resource = (ID3D12Resource*)textureHandle;
D3D12_RESOURCE_DESC desc = resource->GetDesc();
assert(desc.Width == textureWidth);
assert(desc.Height == textureHeight);
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
srcLoc.pResource = s_upload_texture;
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
device->GetCopyableFootprints(&desc, 0, 1, 0, &srcLoc.PlacedFootprint, nullptr, nullptr, nullptr);
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
dstLoc.pResource = resource;
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dstLoc.SubresourceIndex = 0;
m_texture_copy_cmd_allocator->Reset();
m_texture_copy_cmd_list->Reset(m_texture_copy_cmd_allocator, nullptr);
transition_barrier(m_texture_copy_cmd_list, resource, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
m_texture_copy_cmd_list->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, nullptr);
transition_barrier(m_texture_copy_cmd_list, resource, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
m_texture_copy_cmd_list->Close();
UnityGraphicsD3D12ResourceState resource_states = {};
resource_states.resource = resource;
resource_states.expected = D3D12_RESOURCE_STATE_COMMON;
resource_states.current = D3D12_RESOURCE_STATE_COMMON;
m_texture_copy_fence = submit_cmd_to_unity_worker(m_texture_copy_cmd_list, &resource_states, 1);
}
void* RenderAPI_D3D12::BeginModifyVertexBuffer(void* bufferHandle, size_t* outBufferSize)
{
wait_for_unity_frame_fence(m_vertex_copy_fence);
if (bufferHandle == NULL)
return NULL;
ID3D12Resource* unity_vertex_buffer = reinterpret_cast<ID3D12Resource*>(bufferHandle);
D3D12_RESOURCE_DESC desc = unity_vertex_buffer->GetDesc();
*outBufferSize = static_cast<size_t>(desc.Width);
if (!get_upload_resource(&s_upload_buffer, desc.Width, D3D12_UPLOAD_HEAP_VERTEX_BUFFER_NAME))
return NULL;
MappedVertexBuffers::iterator it = m_mapped_triangle_vertex_buffers.find(bufferHandle);
if (it == m_mapped_triangle_vertex_buffers.end())
m_mapped_triangle_vertex_buffers.insert(std::make_pair(bufferHandle, reinterpret_cast<void*>(new int())));
HRESULT hr = s_upload_buffer->Map(0, 0, &m_mapped_triangle_vertex_buffers[bufferHandle]);
return m_mapped_triangle_vertex_buffers[bufferHandle];
}
void RenderAPI_D3D12::EndModifyVertexBuffer(void* bufferHandle)
{
m_vertex_copy_cmd_allocator->Reset();
m_vertex_copy_cmd_list->Reset(m_vertex_copy_cmd_allocator, nullptr);
if (bufferHandle == NULL)
return;
UnityGraphicsD3D12RecordingState recordingState;
if (!s_d3d12->CommandRecordingState(&recordingState))
return;
ID3D12Resource* unity_vertex_buffer = reinterpret_cast<ID3D12Resource*>(bufferHandle);
D3D12_RESOURCE_DESC desc = unity_vertex_buffer->GetDesc();
if (!get_upload_resource(&s_upload_buffer, desc.Width, D3D12_UPLOAD_HEAP_VERTEX_BUFFER_NAME))
return;
assert(desc.Height == 1);
s_upload_buffer->Unmap(0, 0);
D3D12_HEAP_PROPERTIES heap_props;
handle_hr(unity_vertex_buffer->GetHeapProperties(&heap_props, nullptr), "Failed to get heap properties for unitys vertex buffer");
// On DX12 Mesh.MarkDynamic() doesn't guarantee the underlying resource to be CPU mappable. In the case when it's not we need to
// place correct transition barriers before and after the copy command.
if (heap_props.Type == D3D12_HEAP_TYPE_DEFAULT)
transition_barrier(m_vertex_copy_cmd_list, unity_vertex_buffer, D3D12_RESOURCE_STATE_COMMON, D3D12_RESOURCE_STATE_COPY_DEST);
m_vertex_copy_cmd_list->CopyBufferRegion(unity_vertex_buffer, 0, s_upload_buffer, 0, desc.Width);
if (heap_props.Type == D3D12_HEAP_TYPE_DEFAULT)
transition_barrier(m_vertex_copy_cmd_list, unity_vertex_buffer, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COMMON);
handle_hr(m_vertex_copy_cmd_list->Close(), "Failed to close vertex copy cmd list");
UnityGraphicsD3D12ResourceState resource_states = {};
if (heap_props.Type == D3D12_HEAP_TYPE_DEFAULT)
{
resource_states.resource = unity_vertex_buffer;
resource_states.expected = D3D12_RESOURCE_STATE_COMMON;
resource_states.current = D3D12_RESOURCE_STATE_COMMON;
}
m_vertex_copy_fence = submit_cmd_to_unity_worker(m_vertex_copy_cmd_list, &resource_states, 1);
}
void RenderAPI_D3D12::drawToPluginTexture()
{
if (!m_plugin_texture)
return;
wait_on_fence(m_plugin_texture_fence_value, m_plugin_texture_fence, m_plugin_texture_fence_event);
// Draw the triangle upside down
constexpr float world_matrix[16] = { 1, 0, 0, 0,
0,-1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
D3D12_VIEWPORT viewport = {};
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(m_texture_width);
viewport.Height = static_cast<FLOAT>(m_texture_height);
viewport.MinDepth = D3D12_MIN_DEPTH;
viewport.MaxDepth = D3D12_MAX_DEPTH;
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle { m_texture_rtv_desc_heap->GetCPUDescriptorHandleForHeapStart() };
rtv_handle.Offset(1, m_texture_rtv_desc_size);
// We can reuse some of the resources for both plugin_texture and render_texture
record_draw_cmd_list(m_plugin_texture_cmd_allocator,
m_plugin_texture_cmd_list,
m_texture_root_sig,
rtv_handle,
&m_texture_vertex_buffer_view,
world_matrix, &viewport,
m_texture_pso,
m_plugin_texture,
D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12CommandQueue* unity_command_queue = s_d3d12->GetCommandQueue();
unity_command_queue->ExecuteCommandLists(1, (ID3D12CommandList**)&m_plugin_texture_cmd_list);
unity_command_queue->Signal(m_plugin_texture_fence, ++m_plugin_texture_fence_value);
}
void RenderAPI_D3D12::drawToRenderTexture()
{
wait_for_unity_frame_fence(m_render_texture_draw_fence);
if (!m_render_texture)
return;
// Draw the triangle upright
constexpr float world_matrix[16] = { 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
D3D12_VIEWPORT viewport = {};
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = static_cast<FLOAT>(m_texture_width);
viewport.Height = static_cast<FLOAT>(m_texture_height);
viewport.MinDepth = D3D12_MIN_DEPTH;
viewport.MaxDepth = D3D12_MAX_DEPTH;
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle { m_texture_rtv_desc_heap->GetCPUDescriptorHandleForHeapStart() };
rtv_handle.Offset(0, m_texture_rtv_desc_size);
D3D12_RESOURCE_STATES target_state;
if (m_is_render_texture_created_by_unity)
{
target_state = D3D12_RESOURCE_STATE_COMMON;
}
else
{
target_state = D3D12_RESOURCE_STATE_RENDER_TARGET;
}
record_draw_cmd_list(m_render_texture_cmd_allocator,
m_render_texture_cmd_list,
m_texture_root_sig,
rtv_handle,
&m_texture_vertex_buffer_view,
world_matrix, &viewport,
m_texture_pso,
m_render_texture,
target_state);
UnityGraphicsD3D12ResourceState resource_states;
resource_states.resource = m_render_texture;
resource_states.expected = D3D12_RESOURCE_STATE_COMMON;
resource_states.current = D3D12_RESOURCE_STATE_COMMON;
m_render_texture_draw_fence = submit_cmd_to_unity_worker(m_render_texture_cmd_list, &resource_states, 1);
}
void* RenderAPI_D3D12::getRenderTexture()
{
return reinterpret_cast<void*>(m_render_texture.load());
}
void RenderAPI_D3D12::setRenderTextureResource(UnityRenderBuffer rb)
{
// Release existing resource if there is already one that wasn't created by Unity C# script
if (!m_is_render_texture_created_by_unity && m_render_texture)
{
m_render_texture.load()->Release();
m_render_texture = nullptr;
}
// rb == nullptr is used to signal that the previously used UnityRenderBuffer
// is not available anymore (i.e when it gets destroyed)
if (!rb)
{
m_render_texture = nullptr;
m_is_render_texture_created_by_unity = false;
return;
}
// TextureFromRenderBuffer might not be immediately available when this function is called.
ID3D12Resource* rb_resource = nullptr;
while (!rb_resource)
{
rb_resource = s_d3d12->TextureFromRenderBuffer(rb);
}
D3D12_RESOURCE_DESC desc = rb_resource->GetDesc();
m_texture_width = desc.Width;
m_texture_height = desc.Height;
assert(desc.Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D);
assert(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET);
m_render_texture = rb_resource;
// we need to update the rtv if we won't be calling initialize_render_texture_resources() after
// (when it's already initialized)
if (m_are_resources_initialized)
create_render_texture_rtv(m_texture_rtv_desc_heap, m_render_texture, 0);
m_is_render_texture_created_by_unity = true;
}
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;
}
#undef ReturnOnFail
#endif // #if SUPPORT_D3D12