#include "RenderAPI.h" #include "PlatformBase.h" #include // Direct3D 12 implementation of RenderAPI. #if SUPPORT_D3D12 #include #include #include #include #include "d3dx12.h" #include "Unity/IUnityGraphicsD3D12.h" #include #include #include #include #include #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 D3D12Buffers; typedef std::map DeleteQueue; typedef std::unordered_map 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 m_render_texture; std::atomic 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 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(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(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(&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(&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(); 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(&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(viewport->Width); scissor.bottom = static_cast(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(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(bufferHandle); D3D12_RESOURCE_DESC desc = unity_vertex_buffer->GetDesc(); *outBufferSize = static_cast(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(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(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(m_texture_width); viewport.Height = static_cast(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(m_texture_width); viewport.Height = static_cast(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(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