Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/drivers/d3d12/rendering_device_driver_d3d12.cpp
21075 views
1
/**************************************************************************/
2
/* rendering_device_driver_d3d12.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#include "rendering_device_driver_d3d12.h"
32
33
#include "d3d12_hooks.h"
34
35
#include "core/config/project_settings.h"
36
#include "core/io/marshalls.h"
37
#include "servers/rendering/rendering_device.h"
38
#include "thirdparty/zlib/zlib.h"
39
40
#include "d3d12_godot_nir_bridge.h"
41
#include "rendering_context_driver_d3d12.h"
42
43
GODOT_GCC_WARNING_PUSH
44
GODOT_GCC_WARNING_IGNORE("-Wimplicit-fallthrough")
45
GODOT_GCC_WARNING_IGNORE("-Wlogical-not-parentheses")
46
GODOT_GCC_WARNING_IGNORE("-Wmissing-field-initializers")
47
GODOT_GCC_WARNING_IGNORE("-Wnon-virtual-dtor")
48
GODOT_GCC_WARNING_IGNORE("-Wshadow")
49
GODOT_GCC_WARNING_IGNORE("-Wswitch")
50
GODOT_CLANG_WARNING_PUSH
51
GODOT_CLANG_WARNING_IGNORE("-Wimplicit-fallthrough")
52
GODOT_CLANG_WARNING_IGNORE("-Wlogical-not-parentheses")
53
GODOT_CLANG_WARNING_IGNORE("-Wmissing-field-initializers")
54
GODOT_CLANG_WARNING_IGNORE("-Wnon-virtual-dtor")
55
GODOT_CLANG_WARNING_IGNORE("-Wstring-plus-int")
56
GODOT_CLANG_WARNING_IGNORE("-Wswitch")
57
GODOT_MSVC_WARNING_PUSH
58
GODOT_MSVC_WARNING_IGNORE(4200) // "nonstandard extension used: zero-sized array in struct/union".
59
GODOT_MSVC_WARNING_IGNORE(4806) // "'&': unsafe operation: no value of type 'bool' promoted to type 'uint32_t' can equal the given constant".
60
61
#include <dxgi1_6.h>
62
#define D3D12MA_D3D12_HEADERS_ALREADY_INCLUDED
63
#include <thirdparty/d3d12ma/D3D12MemAlloc.h>
64
65
#include <nir_spirv.h>
66
#include <nir_to_dxil.h>
67
#include <spirv_to_dxil.h>
68
extern "C" {
69
#include <dxil_spirv_nir.h>
70
}
71
72
GODOT_GCC_WARNING_POP
73
GODOT_CLANG_WARNING_POP
74
GODOT_MSVC_WARNING_POP
75
76
#if !defined(_MSC_VER)
77
#include <guiddef.h>
78
79
#include <thirdparty/directx_headers/include/dxguids/dxguids.h>
80
#endif
81
82
using Microsoft::WRL::ComPtr;
83
84
// Mesa may define this.
85
#ifdef UNUSED
86
#undef UNUSED
87
#endif
88
89
#ifdef PIX_ENABLED
90
#if defined(__GNUC__)
91
#define _MSC_VER 1800
92
#endif
93
#define USE_PIX
94
#include <WinPixEventRuntime/pix3.h>
95
#if defined(__GNUC__)
96
#undef _MSC_VER
97
#endif
98
#endif
99
100
// Runs constant sanity checks on the structure of the descriptor heap pools to catch implementation errors.
101
#define D3D12_DESCRIPTOR_HEAP_VERIFICATION 0
102
103
// Tracks additional information and prints information about the allocation of descriptor heaps.
104
#define D3D12_DESCRIPTOR_HEAP_VERBOSE 0
105
106
static const D3D12_RANGE VOID_RANGE = {};
107
108
static const uint32_t MAX_DYNAMIC_BUFFERS = 8u; // Minimum guaranteed by Vulkan.
109
110
/*****************/
111
/**** GENERIC ****/
112
/*****************/
113
114
// NOTE: RD's packed format names are reversed in relation to DXGI's; e.g.:.
115
// - DATA_FORMAT_A8B8G8R8_UNORM_PACK32 -> DXGI_FORMAT_R8G8B8A8_UNORM (packed; note ABGR vs. RGBA).
116
// - DATA_FORMAT_B8G8R8A8_UNORM -> DXGI_FORMAT_B8G8R8A8_UNORM (not packed; note BGRA order matches).
117
// TODO: Add YUV formats properly, which would require better support for planes in the RD API.
118
119
const RenderingDeviceDriverD3D12::D3D12Format RenderingDeviceDriverD3D12::RD_TO_D3D12_FORMAT[RDD::DATA_FORMAT_MAX] = {
120
/* DATA_FORMAT_R4G4_UNORM_PACK8 */ {},
121
/* DATA_FORMAT_R4G4B4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },
122
/* DATA_FORMAT_B4G4R4A4_UNORM_PACK16 */ { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B4G4R4A4_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },
123
/* DATA_FORMAT_R5G6B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM },
124
/* DATA_FORMAT_B5G6R5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G6R5_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
125
/* DATA_FORMAT_R5G5B5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(1, 2, 3, 0) },
126
/* DATA_FORMAT_B5G5R5A1_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(3, 2, 1, 0) },
127
/* DATA_FORMAT_A1R5G5B5_UNORM_PACK16 */ { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B5G5R5A1_UNORM },
128
/* DATA_FORMAT_R8_UNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM },
129
/* DATA_FORMAT_R8_SNORM */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SNORM },
130
/* DATA_FORMAT_R8_USCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },
131
/* DATA_FORMAT_R8_SSCALED */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },
132
/* DATA_FORMAT_R8_UINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UINT },
133
/* DATA_FORMAT_R8_SINT */ { DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_SINT },
134
/* DATA_FORMAT_R8_SRGB */ {},
135
/* DATA_FORMAT_R8G8_UNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM },
136
/* DATA_FORMAT_R8G8_SNORM */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SNORM },
137
/* DATA_FORMAT_R8G8_USCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },
138
/* DATA_FORMAT_R8G8_SSCALED */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },
139
/* DATA_FORMAT_R8G8_UINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UINT },
140
/* DATA_FORMAT_R8G8_SINT */ { DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_SINT },
141
/* DATA_FORMAT_R8G8_SRGB */ {},
142
/* DATA_FORMAT_R8G8B8_UNORM */ {},
143
/* DATA_FORMAT_R8G8B8_SNORM */ {},
144
/* DATA_FORMAT_R8G8B8_USCALED */ {},
145
/* DATA_FORMAT_R8G8B8_SSCALED */ {},
146
/* DATA_FORMAT_R8G8B8_UINT */ {},
147
/* DATA_FORMAT_R8G8B8_SINT */ {},
148
/* DATA_FORMAT_R8G8B8_SRGB */ {},
149
/* DATA_FORMAT_B8G8R8_UNORM */ {},
150
/* DATA_FORMAT_B8G8R8_SNORM */ {},
151
/* DATA_FORMAT_B8G8R8_USCALED */ {},
152
/* DATA_FORMAT_B8G8R8_SSCALED */ {},
153
/* DATA_FORMAT_B8G8R8_UINT */ {},
154
/* DATA_FORMAT_B8G8R8_SINT */ {},
155
/* DATA_FORMAT_B8G8R8_SRGB */ {},
156
/* DATA_FORMAT_R8G8B8A8_UNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },
157
/* DATA_FORMAT_R8G8B8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
158
/* DATA_FORMAT_R8G8B8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
159
/* DATA_FORMAT_R8G8B8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
160
/* DATA_FORMAT_R8G8B8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
161
/* DATA_FORMAT_R8G8B8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
162
/* DATA_FORMAT_R8G8B8A8_SRGB */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
163
/* DATA_FORMAT_B8G8R8A8_UNORM */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM },
164
/* DATA_FORMAT_B8G8R8A8_SNORM */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
165
/* DATA_FORMAT_B8G8R8A8_USCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
166
/* DATA_FORMAT_B8G8R8A8_SSCALED */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
167
/* DATA_FORMAT_B8G8R8A8_UINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
168
/* DATA_FORMAT_B8G8R8A8_SINT */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
169
/* DATA_FORMAT_B8G8R8A8_SRGB */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB },
170
/* DATA_FORMAT_A8B8G8R8_UNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM },
171
/* DATA_FORMAT_A8B8G8R8_SNORM_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SNORM },
172
/* DATA_FORMAT_A8B8G8R8_USCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
173
/* DATA_FORMAT_A8B8G8R8_SSCALED_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
174
/* DATA_FORMAT_A8B8G8R8_UINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UINT },
175
/* DATA_FORMAT_A8B8G8R8_SINT_PACK32 */ { DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_SINT },
176
/* DATA_FORMAT_A8B8G8R8_SRGB_PACK32 */ { DXGI_FORMAT_B8G8R8A8_TYPELESS, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB },
177
/* DATA_FORMAT_A2R10G10B10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
178
/* DATA_FORMAT_A2R10G10B10_SNORM_PACK32 */ {},
179
/* DATA_FORMAT_A2R10G10B10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
180
/* DATA_FORMAT_A2R10G10B10_SSCALED_PACK32 */ {},
181
/* DATA_FORMAT_A2R10G10B10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(2, 1, 0, 3) },
182
/* DATA_FORMAT_A2R10G10B10_SINT_PACK32 */ {},
183
/* DATA_FORMAT_A2B10G10R10_UNORM_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UNORM },
184
/* DATA_FORMAT_A2B10G10R10_SNORM_PACK32 */ {},
185
/* DATA_FORMAT_A2B10G10R10_USCALED_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },
186
/* DATA_FORMAT_A2B10G10R10_SSCALED_PACK32 */ {},
187
/* DATA_FORMAT_A2B10G10R10_UINT_PACK32 */ { DXGI_FORMAT_R10G10B10A2_TYPELESS, DXGI_FORMAT_R10G10B10A2_UINT },
188
/* DATA_FORMAT_A2B10G10R10_SINT_PACK32 */ {},
189
/* DATA_FORMAT_R16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM },
190
/* DATA_FORMAT_R16_SNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SNORM },
191
/* DATA_FORMAT_R16_USCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },
192
/* DATA_FORMAT_R16_SSCALED */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },
193
/* DATA_FORMAT_R16_UINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UINT },
194
/* DATA_FORMAT_R16_SINT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_SINT },
195
/* DATA_FORMAT_R16_SFLOAT */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_FLOAT },
196
/* DATA_FORMAT_R16G16_UNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UNORM },
197
/* DATA_FORMAT_R16G16_SNORM */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SNORM },
198
/* DATA_FORMAT_R16G16_USCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },
199
/* DATA_FORMAT_R16G16_SSCALED */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },
200
/* DATA_FORMAT_R16G16_UINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_UINT },
201
/* DATA_FORMAT_R16G16_SINT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_SINT },
202
/* DATA_FORMAT_R16G16_SFLOAT */ { DXGI_FORMAT_R16G16_TYPELESS, DXGI_FORMAT_R16G16_FLOAT },
203
/* DATA_FORMAT_R16G16B16_UNORM */ {},
204
/* DATA_FORMAT_R16G16B16_SNORM */ {},
205
/* DATA_FORMAT_R16G16B16_USCALED */ {},
206
/* DATA_FORMAT_R16G16B16_SSCALED */ {},
207
/* DATA_FORMAT_R16G16B16_UINT */ {},
208
/* DATA_FORMAT_R16G16B16_SINT */ {},
209
/* DATA_FORMAT_R16G16B16_SFLOAT */ {},
210
/* DATA_FORMAT_R16G16B16A16_UNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM },
211
/* DATA_FORMAT_R16G16B16A16_SNORM */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SNORM },
212
/* DATA_FORMAT_R16G16B16A16_USCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },
213
/* DATA_FORMAT_R16G16B16A16_SSCALED */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },
214
/* DATA_FORMAT_R16G16B16A16_UINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UINT },
215
/* DATA_FORMAT_R16G16B16A16_SINT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_SINT },
216
/* DATA_FORMAT_R16G16B16A16_SFLOAT */ { DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_FLOAT },
217
/* DATA_FORMAT_R32_UINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_UINT },
218
/* DATA_FORMAT_R32_SINT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_SINT },
219
/* DATA_FORMAT_R32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT },
220
/* DATA_FORMAT_R32G32_UINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_UINT },
221
/* DATA_FORMAT_R32G32_SINT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_SINT },
222
/* DATA_FORMAT_R32G32_SFLOAT */ { DXGI_FORMAT_R32G32_TYPELESS, DXGI_FORMAT_R32G32_FLOAT },
223
/* DATA_FORMAT_R32G32B32_UINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_UINT },
224
/* DATA_FORMAT_R32G32B32_SINT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_SINT },
225
/* DATA_FORMAT_R32G32B32_SFLOAT */ { DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_FLOAT },
226
/* DATA_FORMAT_R32G32B32A32_UINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_UINT },
227
/* DATA_FORMAT_R32G32B32A32_SINT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_SINT },
228
/* DATA_FORMAT_R32G32B32A32_SFLOAT */ { DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_FLOAT },
229
/* DATA_FORMAT_R64_UINT */ {},
230
/* DATA_FORMAT_R64_SINT */ {},
231
/* DATA_FORMAT_R64_SFLOAT */ {},
232
/* DATA_FORMAT_R64G64_UINT */ {},
233
/* DATA_FORMAT_R64G64_SINT */ {},
234
/* DATA_FORMAT_R64G64_SFLOAT */ {},
235
/* DATA_FORMAT_R64G64B64_UINT */ {},
236
/* DATA_FORMAT_R64G64B64_SINT */ {},
237
/* DATA_FORMAT_R64G64B64_SFLOAT */ {},
238
/* DATA_FORMAT_R64G64B64A64_UINT */ {},
239
/* DATA_FORMAT_R64G64B64A64_SINT */ {},
240
/* DATA_FORMAT_R64G64B64A64_SFLOAT */ {},
241
/* DATA_FORMAT_B10G11R11_UFLOAT_PACK32 */ { DXGI_FORMAT_R11G11B10_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT },
242
/* DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32 */ { DXGI_FORMAT_R9G9B9E5_SHAREDEXP, DXGI_FORMAT_R9G9B9E5_SHAREDEXP },
243
/* DATA_FORMAT_D16_UNORM */ { DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_R16_UNORM, 0, DXGI_FORMAT_D16_UNORM },
244
/* DATA_FORMAT_X8_D24_UNORM_PACK32 */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },
245
/* DATA_FORMAT_D32_SFLOAT */ { DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_FLOAT, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT },
246
/* DATA_FORMAT_S8_UINT */ {},
247
/* DATA_FORMAT_D16_UNORM_S8_UINT */ {},
248
/* DATA_FORMAT_D24_UNORM_S8_UINT */ { DXGI_FORMAT_R24G8_TYPELESS, DXGI_FORMAT_UNKNOWN, 0, DXGI_FORMAT_D24_UNORM_S8_UINT },
249
/* DATA_FORMAT_D32_SFLOAT_S8_UINT */ { DXGI_FORMAT_R32G8X24_TYPELESS, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, DXGI_FORMAT_D32_FLOAT_S8X24_UINT },
250
/* DATA_FORMAT_BC1_RGB_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },
251
/* DATA_FORMAT_BC1_RGB_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB, D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(0, 1, 2, D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1) },
252
/* DATA_FORMAT_BC1_RGBA_UNORM_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM },
253
/* DATA_FORMAT_BC1_RGBA_SRGB_BLOCK */ { DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM_SRGB },
254
/* DATA_FORMAT_BC2_UNORM_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM },
255
/* DATA_FORMAT_BC2_SRGB_BLOCK */ { DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM_SRGB },
256
/* DATA_FORMAT_BC3_UNORM_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM },
257
/* DATA_FORMAT_BC3_SRGB_BLOCK */ { DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM_SRGB },
258
/* DATA_FORMAT_BC4_UNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM },
259
/* DATA_FORMAT_BC4_SNORM_BLOCK */ { DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_SNORM },
260
/* DATA_FORMAT_BC5_UNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM },
261
/* DATA_FORMAT_BC5_SNORM_BLOCK */ { DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_SNORM },
262
/* DATA_FORMAT_BC6H_UFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16 },
263
/* DATA_FORMAT_BC6H_SFLOAT_BLOCK */ { DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_SF16 },
264
/* DATA_FORMAT_BC7_UNORM_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM },
265
/* DATA_FORMAT_BC7_SRGB_BLOCK */ { DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM_SRGB },
266
/* DATA_FORMAT_ETC2_R8G8B8_UNORM_BLOCK */ {},
267
/* DATA_FORMAT_ETC2_R8G8B8_SRGB_BLOCK */ {},
268
/* DATA_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK */ {},
269
/* DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK */ {},
270
/* DATA_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK */ {},
271
/* DATA_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK */ {},
272
/* DATA_FORMAT_EAC_R11_UNORM_BLOCK */ {},
273
/* DATA_FORMAT_EAC_R11_SNORM_BLOCK */ {},
274
/* DATA_FORMAT_EAC_R11G11_UNORM_BLOCK */ {},
275
/* DATA_FORMAT_EAC_R11G11_SNORM_BLOCK */ {},
276
/* DATA_FORMAT_ASTC_4x4_UNORM_BLOCK */ {},
277
/* DATA_FORMAT_ASTC_4x4_SRGB_BLOCK */ {},
278
/* DATA_FORMAT_ASTC_5x4_UNORM_BLOCK */ {},
279
/* DATA_FORMAT_ASTC_5x4_SRGB_BLOCK */ {},
280
/* DATA_FORMAT_ASTC_5x5_UNORM_BLOCK */ {},
281
/* DATA_FORMAT_ASTC_5x5_SRGB_BLOCK */ {},
282
/* DATA_FORMAT_ASTC_6x5_UNORM_BLOCK */ {},
283
/* DATA_FORMAT_ASTC_6x5_SRGB_BLOCK */ {},
284
/* DATA_FORMAT_ASTC_6x6_UNORM_BLOCK */ {},
285
/* DATA_FORMAT_ASTC_6x6_SRGB_BLOCK */ {},
286
/* DATA_FORMAT_ASTC_8x5_UNORM_BLOCK */ {},
287
/* DATA_FORMAT_ASTC_8x5_SRGB_BLOCK */ {},
288
/* DATA_FORMAT_ASTC_8x6_UNORM_BLOCK */ {},
289
/* DATA_FORMAT_ASTC_8x6_SRGB_BLOCK */ {},
290
/* DATA_FORMAT_ASTC_8x8_UNORM_BLOCK */ {},
291
/* DATA_FORMAT_ASTC_8x8_SRGB_BLOCK */ {},
292
/* DATA_FORMAT_ASTC_10x5_UNORM_BLOCK */ {},
293
/* DATA_FORMAT_ASTC_10x5_SRGB_BLOCK */ {},
294
/* DATA_FORMAT_ASTC_10x6_UNORM_BLOCK */ {},
295
/* DATA_FORMAT_ASTC_10x6_SRGB_BLOCK */ {},
296
/* DATA_FORMAT_ASTC_10x8_UNORM_BLOCK */ {},
297
/* DATA_FORMAT_ASTC_10x8_SRGB_BLOCK */ {},
298
/* DATA_FORMAT_ASTC_10x10_UNORM_BLOCK */ {},
299
/* DATA_FORMAT_ASTC_10x10_SRGB_BLOCK */ {},
300
/* DATA_FORMAT_ASTC_12x10_UNORM_BLOCK */ {},
301
/* DATA_FORMAT_ASTC_12x10_SRGB_BLOCK */ {},
302
/* DATA_FORMAT_ASTC_12x12_UNORM_BLOCK */ {},
303
/* DATA_FORMAT_ASTC_12x12_SRGB_BLOCK */ {},
304
/* DATA_FORMAT_G8B8G8R8_422_UNORM */ {},
305
/* DATA_FORMAT_B8G8R8G8_422_UNORM */ {},
306
/* DATA_FORMAT_G8_B8_R8_3PLANE_420_UNORM */ {},
307
/* DATA_FORMAT_G8_B8R8_2PLANE_420_UNORM */ {},
308
/* DATA_FORMAT_G8_B8_R8_3PLANE_422_UNORM */ {},
309
/* DATA_FORMAT_G8_B8R8_2PLANE_422_UNORM */ {},
310
/* DATA_FORMAT_G8_B8_R8_3PLANE_444_UNORM */ {},
311
/* DATA_FORMAT_R10X6_UNORM_PACK16 */ {},
312
/* DATA_FORMAT_R10X6G10X6_UNORM_2PACK16 */ {},
313
/* DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 */ {},
314
/* DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 */ {},
315
/* DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 */ {},
316
/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 */ {},
317
/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 */ {},
318
/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 */ {},
319
/* DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 */ {},
320
/* DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 */ {},
321
/* DATA_FORMAT_R12X4_UNORM_PACK16 */ {},
322
/* DATA_FORMAT_R12X4G12X4_UNORM_2PACK16 */ {},
323
/* DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 */ {},
324
/* DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 */ {},
325
/* DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 */ {},
326
/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 */ {},
327
/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 */ {},
328
/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 */ {},
329
/* DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 */ {},
330
/* DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 */ {},
331
/* DATA_FORMAT_G16B16G16R16_422_UNORM */ {},
332
/* DATA_FORMAT_B16G16R16G16_422_UNORM */ {},
333
/* DATA_FORMAT_G16_B16_R16_3PLANE_420_UNORM */ {},
334
/* DATA_FORMAT_G16_B16R16_2PLANE_420_UNORM */ {},
335
/* DATA_FORMAT_G16_B16_R16_3PLANE_422_UNORM */ {},
336
/* DATA_FORMAT_G16_B16R16_2PLANE_422_UNORM */ {},
337
/* DATA_FORMAT_G16_B16_R16_3PLANE_444_UNORM */ {},
338
/* DATA_FORMAT_ASTC_4x4_SFLOAT_BLOCK */ {},
339
/* DATA_FORMAT_ASTC_5x4_SFLOAT_BLOCK */ {},
340
/* DATA_FORMAT_ASTC_5x5_SFLOAT_BLOCK */ {},
341
/* DATA_FORMAT_ASTC_6x5_SFLOAT_BLOCK */ {},
342
/* DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK */ {},
343
/* DATA_FORMAT_ASTC_8x5_SFLOAT_BLOCK */ {},
344
/* DATA_FORMAT_ASTC_8x6_SFLOAT_BLOCK */ {},
345
/* DATA_FORMAT_ASTC_8x8_SFLOAT_BLOCK */ {},
346
/* DATA_FORMAT_ASTC_10x5_SFLOAT_BLOCK*/ {},
347
/* DATA_FORMAT_ASTC_10x6_SFLOAT_BLOCK */ {},
348
/* DATA_FORMAT_ASTC_10x8_SFLOAT_BLOCK */ {},
349
/* DATA_FORMAT_ASTC_10x10_SFLOAT_BLOCK */ {},
350
/* DATA_FORMAT_ASTC_12x10_SFLOAT_BLOCK */ {},
351
/* DATA_FORMAT_ASTC_12x12_SFLOAT_BLOCK */ {},
352
};
353
354
static D3D12_CPU_DESCRIPTOR_HANDLE get_cpu_handle(D3D12_CPU_DESCRIPTOR_HANDLE p_handle, uint64_t p_index, uint32_t p_increment_size) {
355
p_handle.ptr += p_index * p_increment_size;
356
return p_handle;
357
}
358
359
static D3D12_GPU_DESCRIPTOR_HANDLE get_gpu_handle(D3D12_GPU_DESCRIPTOR_HANDLE p_handle, uint64_t p_index, uint32_t p_increment_size) {
360
p_handle.ptr += p_index * p_increment_size;
361
return p_handle;
362
}
363
364
Error RenderingDeviceDriverD3D12::DescriptorHeap::initialize(ID3D12Device *p_device, D3D12_DESCRIPTOR_HEAP_TYPE p_type, uint32_t p_num_descriptors, bool p_shader_visible) {
365
D3D12MA::VIRTUAL_BLOCK_DESC block_desc = {};
366
block_desc.Size = p_num_descriptors;
367
368
HRESULT hr = D3D12MA::CreateVirtualBlock(&block_desc, virtual_block.GetAddressOf());
369
ERR_FAIL_COND_V(FAILED(hr), ERR_CANT_CREATE);
370
371
D3D12_DESCRIPTOR_HEAP_DESC heap_desc = {};
372
heap_desc.Type = p_type;
373
heap_desc.NumDescriptors = p_num_descriptors;
374
heap_desc.Flags = p_shader_visible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
375
376
hr = p_device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(heap.GetAddressOf()));
377
ERR_FAIL_COND_V_MSG(FAILED(hr), ERR_CANT_CREATE, "CreateDescriptorHeap failed with error " + vformat("0x%08ux", (uint64_t)hr) + ".");
378
379
#if defined(_MSC_VER) || !defined(_WIN32)
380
cpu_handle = heap->GetCPUDescriptorHandleForHeapStart();
381
if (p_shader_visible) {
382
gpu_handle = heap->GetGPUDescriptorHandleForHeapStart();
383
}
384
#else
385
heap->GetCPUDescriptorHandleForHeapStart(&cpu_handle);
386
if (p_shader_visible) {
387
heap->GetGPUDescriptorHandleForHeapStart(&gpu_handle);
388
}
389
#endif
390
391
increment_size = p_device->GetDescriptorHandleIncrementSize(p_type);
392
393
return OK;
394
}
395
396
Error RenderingDeviceDriverD3D12::DescriptorHeap::allocate(uint32_t p_descriptor_count, Allocation &r_allocation) {
397
D3D12MA::VIRTUAL_ALLOCATION_DESC desc = {};
398
desc.Size = p_descriptor_count;
399
400
D3D12MA::VirtualAllocation virtual_alloc = {};
401
uint64_t offset = 0;
402
HRESULT hr = virtual_block->Allocate(&desc, &virtual_alloc, &offset);
403
404
// This error is expected, and needs to be handled by the caller.
405
if (hr == E_OUTOFMEMORY) {
406
return ERR_OUT_OF_MEMORY;
407
}
408
409
ERR_FAIL_COND_V_MSG(FAILED(hr), ERR_CANT_CREATE, "Allocate failed with error " + vformat("0x%08ux", (uint64_t)hr) + ".");
410
411
r_allocation.virtual_alloc_handle = virtual_alloc.AllocHandle;
412
r_allocation.cpu_handle = get_cpu_handle(cpu_handle, offset, increment_size);
413
r_allocation.gpu_handle = get_gpu_handle(gpu_handle, offset, increment_size);
414
415
return OK;
416
}
417
418
void RenderingDeviceDriverD3D12::DescriptorHeap::free(const Allocation &p_allocation) {
419
D3D12MA::VirtualAllocation virtual_alloc = {};
420
virtual_alloc.AllocHandle = p_allocation.virtual_alloc_handle;
421
422
virtual_block->FreeAllocation(virtual_alloc);
423
}
424
425
void RenderingDeviceDriverD3D12::CPUDescriptorHeapPool::initialize(ID3D12Device *p_device, D3D12_DESCRIPTOR_HEAP_TYPE p_type) {
426
type = p_type;
427
increment_size = p_device->GetDescriptorHandleIncrementSize(p_type);
428
}
429
430
Error RenderingDeviceDriverD3D12::CPUDescriptorHeapPool::allocate(uint32_t p_descriptor_count, ID3D12Device *p_device, Allocation &r_allocation) {
431
MutexLock lock(mutex);
432
433
bool allocated = false;
434
for (uint32_t i = 0; i < heaps.size(); i++) {
435
Error err = heaps[i].allocate(p_descriptor_count, r_allocation);
436
437
if (err == OK) {
438
r_allocation.heap_index = i;
439
allocated = true;
440
break;
441
}
442
443
// Only "out of memory" error is expected.
444
ERR_FAIL_COND_V(err != ERR_OUT_OF_MEMORY, err);
445
}
446
447
// Create new block.
448
if (!allocated) {
449
uint32_t heap_index = heaps.size();
450
451
DescriptorHeap heap;
452
Error err = heap.initialize(p_device, type, MAX(2048u, p_descriptor_count), false);
453
ERR_FAIL_COND_V(err != OK, err);
454
455
heaps.push_back(std::move(heap));
456
457
err = heaps[heap_index].allocate(p_descriptor_count, r_allocation);
458
ERR_FAIL_COND_V(err != OK, err);
459
460
r_allocation.heap_index = heap_index;
461
}
462
463
return OK;
464
}
465
466
void RenderingDeviceDriverD3D12::CPUDescriptorHeapPool::free(const Allocation &p_allocation) {
467
if (p_allocation.heap_index != UINT_MAX) {
468
MutexLock lock(mutex);
469
heaps[p_allocation.heap_index].free(p_allocation);
470
}
471
}
472
473
static const D3D12_COMPARISON_FUNC RD_TO_D3D12_COMPARE_OP[RD::COMPARE_OP_MAX] = {
474
D3D12_COMPARISON_FUNC_NEVER,
475
D3D12_COMPARISON_FUNC_LESS,
476
D3D12_COMPARISON_FUNC_EQUAL,
477
D3D12_COMPARISON_FUNC_LESS_EQUAL,
478
D3D12_COMPARISON_FUNC_GREATER,
479
D3D12_COMPARISON_FUNC_NOT_EQUAL,
480
D3D12_COMPARISON_FUNC_GREATER_EQUAL,
481
D3D12_COMPARISON_FUNC_ALWAYS,
482
};
483
484
uint32_t RenderingDeviceDriverD3D12::SubgroupCapabilities::supported_stages_flags_rd() const {
485
// If there's a way to check exactly which are supported, I have yet to find it.
486
return (
487
RenderingDevice::ShaderStage::SHADER_STAGE_FRAGMENT_BIT |
488
RenderingDevice::ShaderStage::SHADER_STAGE_COMPUTE_BIT);
489
}
490
491
uint32_t RenderingDeviceDriverD3D12::SubgroupCapabilities::supported_operations_flags_rd() const {
492
if (!wave_ops_supported) {
493
return 0;
494
} else {
495
return (
496
RenderingDevice::SubgroupOperations::SUBGROUP_BASIC_BIT |
497
RenderingDevice::SubgroupOperations::SUBGROUP_BALLOT_BIT |
498
RenderingDevice::SubgroupOperations::SUBGROUP_VOTE_BIT |
499
RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_BIT |
500
RenderingDevice::SubgroupOperations::SUBGROUP_SHUFFLE_RELATIVE_BIT |
501
RenderingDevice::SubgroupOperations::SUBGROUP_QUAD_BIT |
502
RenderingDevice::SubgroupOperations::SUBGROUP_ARITHMETIC_BIT |
503
RenderingDevice::SubgroupOperations::SUBGROUP_CLUSTERED_BIT);
504
}
505
}
506
507
void RenderingDeviceDriverD3D12::_debug_message_func(D3D12_MESSAGE_CATEGORY p_category, D3D12_MESSAGE_SEVERITY p_severity, D3D12_MESSAGE_ID p_id, LPCSTR p_description, void *p_context) {
508
String type_string;
509
switch (p_category) {
510
case D3D12_MESSAGE_CATEGORY_APPLICATION_DEFINED:
511
type_string = "APPLICATION_DEFINED";
512
break;
513
case D3D12_MESSAGE_CATEGORY_MISCELLANEOUS:
514
type_string = "MISCELLANEOUS";
515
break;
516
case D3D12_MESSAGE_CATEGORY_INITIALIZATION:
517
type_string = "INITIALIZATION";
518
break;
519
case D3D12_MESSAGE_CATEGORY_CLEANUP:
520
type_string = "CLEANUP";
521
break;
522
case D3D12_MESSAGE_CATEGORY_COMPILATION:
523
type_string = "COMPILATION";
524
break;
525
case D3D12_MESSAGE_CATEGORY_STATE_CREATION:
526
type_string = "STATE_CREATION";
527
break;
528
case D3D12_MESSAGE_CATEGORY_STATE_SETTING:
529
type_string = "STATE_SETTING";
530
break;
531
case D3D12_MESSAGE_CATEGORY_STATE_GETTING:
532
type_string = "STATE_GETTING";
533
break;
534
case D3D12_MESSAGE_CATEGORY_RESOURCE_MANIPULATION:
535
type_string = "RESOURCE_MANIPULATION";
536
break;
537
case D3D12_MESSAGE_CATEGORY_EXECUTION:
538
type_string = "EXECUTION";
539
break;
540
case D3D12_MESSAGE_CATEGORY_SHADER:
541
type_string = "SHADER";
542
break;
543
}
544
545
String error_message(type_string +
546
" - Message Id Number: " + String::num_int64(p_id) +
547
"\n\t" + p_description);
548
549
// Convert D3D12 severity to our own log macros.
550
switch (p_severity) {
551
case D3D12_MESSAGE_SEVERITY_MESSAGE:
552
print_verbose(error_message);
553
break;
554
case D3D12_MESSAGE_SEVERITY_INFO:
555
print_line(error_message);
556
break;
557
case D3D12_MESSAGE_SEVERITY_WARNING:
558
WARN_PRINT(error_message);
559
break;
560
case D3D12_MESSAGE_SEVERITY_ERROR:
561
case D3D12_MESSAGE_SEVERITY_CORRUPTION:
562
ERR_PRINT(error_message);
563
CRASH_COND_MSG(Engine::get_singleton()->is_abort_on_gpu_errors_enabled(),
564
"Crashing, because abort on GPU errors is enabled.");
565
break;
566
}
567
}
568
569
/******************/
570
/**** RESOURCE ****/
571
/******************/
572
573
static const D3D12_RESOURCE_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSION[RD::TEXTURE_TYPE_MAX] = {
574
D3D12_RESOURCE_DIMENSION_TEXTURE1D,
575
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
576
D3D12_RESOURCE_DIMENSION_TEXTURE3D,
577
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
578
D3D12_RESOURCE_DIMENSION_TEXTURE1D,
579
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
580
D3D12_RESOURCE_DIMENSION_TEXTURE2D,
581
};
582
583
void RenderingDeviceDriverD3D12::_resource_transition_batch(CommandBufferInfo *p_command_buffer, ResourceInfo *p_resource, uint32_t p_subresource, uint32_t p_num_planes, D3D12_RESOURCE_STATES p_new_state) {
584
DEV_ASSERT(p_subresource != UINT32_MAX); // We don't support an "all-resources" command here.
585
586
ResourceInfo::States *res_states = p_resource->states_ptr;
587
D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[p_subresource];
588
589
// Transitions can be considered redundant if the current state has all the bits of the new state.
590
// This check does not apply to the common state however, which must resort to checking if the state is the same (0).
591
bool any_state_is_common = *curr_state == D3D12_RESOURCE_STATE_COMMON || p_new_state == D3D12_RESOURCE_STATE_COMMON;
592
bool redundant_transition = any_state_is_common ? *curr_state == p_new_state : ((*curr_state) & p_new_state) == p_new_state;
593
if (redundant_transition) {
594
bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
595
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;
596
if (needs_uav_barrier) {
597
if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + 1) {
598
p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + 1);
599
}
600
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(p_resource->resource);
601
p_command_buffer->res_barriers_count++;
602
res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;
603
}
604
} else {
605
uint64_t subres_mask_piece = ((uint64_t)1 << (p_subresource & 0b111111));
606
uint8_t subres_qword = p_subresource >> 6;
607
608
if (p_command_buffer->res_barriers_requests.has(res_states)) {
609
BarrierRequest &br = p_command_buffer->res_barriers_requests.get(res_states);
610
DEV_ASSERT(br.dx_resource == p_resource->resource);
611
DEV_ASSERT(br.subres_mask_qwords == STEPIFY(res_states->subresource_states.size(), 64) / 64);
612
DEV_ASSERT(br.planes == p_num_planes);
613
614
// First, find if the subresource already has a barrier scheduled.
615
uint8_t curr_group_idx = 0;
616
bool same_transition_scheduled = false;
617
for (curr_group_idx = 0; curr_group_idx < br.groups_count; curr_group_idx++) {
618
if (unlikely(br.groups[curr_group_idx].states == BarrierRequest::DELETED_GROUP)) {
619
continue;
620
}
621
if ((br.groups[curr_group_idx].subres_mask[subres_qword] & subres_mask_piece)) {
622
uint32_t state_mask = br.groups[curr_group_idx].states;
623
same_transition_scheduled = (state_mask & (uint32_t)p_new_state) == (uint32_t)p_new_state;
624
break;
625
}
626
}
627
if (!same_transition_scheduled) {
628
bool subres_already_there = curr_group_idx != br.groups_count;
629
D3D12_RESOURCE_STATES final_states = {};
630
if (subres_already_there) {
631
final_states = br.groups[curr_group_idx].states;
632
final_states |= p_new_state;
633
bool subres_alone = true;
634
for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
635
if (i == subres_qword) {
636
if (br.groups[curr_group_idx].subres_mask[i] != subres_mask_piece) {
637
subres_alone = false;
638
break;
639
}
640
} else {
641
if (br.groups[curr_group_idx].subres_mask[i] != 0) {
642
subres_alone = false;
643
break;
644
}
645
}
646
}
647
bool relocated = false;
648
if (subres_alone) {
649
// Subresource is there by itself.
650
for (uint8_t i = 0; i < br.groups_count; i++) {
651
if (unlikely(i == curr_group_idx)) {
652
continue;
653
}
654
if (unlikely(br.groups[i].states == BarrierRequest::DELETED_GROUP)) {
655
continue;
656
}
657
// There's another group with the final states; relocate to it.
658
if (br.groups[i].states == final_states) {
659
br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;
660
relocated = true;
661
break;
662
}
663
}
664
if (relocated) {
665
// Let's delete the group where it used to be by itself.
666
if (curr_group_idx == br.groups_count - 1) {
667
br.groups_count--;
668
} else {
669
br.groups[curr_group_idx].states = BarrierRequest::DELETED_GROUP;
670
}
671
} else {
672
// Its current group, where it's alone, can extend its states.
673
br.groups[curr_group_idx].states = final_states;
674
}
675
} else {
676
// Already there, but not by itself and the state mask is different, so it now belongs to a different group.
677
br.groups[curr_group_idx].subres_mask[subres_qword] &= ~subres_mask_piece;
678
subres_already_there = false;
679
}
680
} else {
681
final_states = p_new_state;
682
}
683
if (!subres_already_there) {
684
// See if it fits exactly the states of some of the groups to fit it there.
685
for (uint8_t i = 0; i < br.groups_count; i++) {
686
if (unlikely(i == curr_group_idx)) {
687
continue;
688
}
689
if (unlikely(br.groups[i].states == BarrierRequest::DELETED_GROUP)) {
690
continue;
691
}
692
if (br.groups[i].states == final_states) {
693
br.groups[i].subres_mask[subres_qword] |= subres_mask_piece;
694
subres_already_there = true;
695
break;
696
}
697
}
698
if (!subres_already_there) {
699
// Add a new group to accommodate this subresource.
700
uint8_t group_to_fill = 0;
701
if (br.groups_count < BarrierRequest::MAX_GROUPS) {
702
// There are still free groups.
703
group_to_fill = br.groups_count;
704
br.groups_count++;
705
} else {
706
// Let's try to take over a deleted one.
707
for (; group_to_fill < br.groups_count; group_to_fill++) {
708
if (unlikely(br.groups[group_to_fill].states == BarrierRequest::DELETED_GROUP)) {
709
break;
710
}
711
}
712
CRASH_COND(group_to_fill == br.groups_count);
713
}
714
715
br.groups[group_to_fill].states = final_states;
716
for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
717
if (unlikely(i == subres_qword)) {
718
br.groups[group_to_fill].subres_mask[i] = subres_mask_piece;
719
} else {
720
br.groups[group_to_fill].subres_mask[i] = 0;
721
}
722
}
723
}
724
}
725
}
726
} else {
727
BarrierRequest &br = p_command_buffer->res_barriers_requests[res_states];
728
br.dx_resource = p_resource->resource;
729
br.subres_mask_qwords = STEPIFY(p_resource->states_ptr->subresource_states.size(), 64) / 64;
730
CRASH_COND(p_resource->states_ptr->subresource_states.size() > BarrierRequest::MAX_SUBRESOURCES);
731
br.planes = p_num_planes;
732
br.groups[0].states = p_new_state;
733
for (uint8_t i = 0; i < br.subres_mask_qwords; i++) {
734
if (unlikely(i == subres_qword)) {
735
br.groups[0].subres_mask[i] = subres_mask_piece;
736
} else {
737
br.groups[0].subres_mask[i] = 0;
738
}
739
}
740
br.groups_count = 1;
741
}
742
}
743
}
744
745
void RenderingDeviceDriverD3D12::_resource_transitions_flush(CommandBufferInfo *p_command_buffer) {
746
for (const KeyValue<ResourceInfo::States *, BarrierRequest> &E : p_command_buffer->res_barriers_requests) {
747
ResourceInfo::States *res_states = E.key;
748
const BarrierRequest &br = E.value;
749
750
uint32_t num_subresources = res_states->subresource_states.size();
751
752
// When there's not a lot of subresources, the empirical finding is that it's better
753
// to avoid attempting the single-barrier optimization.
754
static const uint32_t SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES = 48;
755
756
bool may_do_single_barrier = br.groups_count == 1 && num_subresources * br.planes >= SINGLE_BARRIER_ATTEMPT_MAX_NUM_SUBRESOURCES;
757
if (may_do_single_barrier) {
758
// A single group means we may be able to do a single all-subresources barrier.
759
760
{
761
// First requisite is that all subresources are involved.
762
763
uint8_t subres_mask_full_qwords = num_subresources / 64;
764
for (uint32_t i = 0; i < subres_mask_full_qwords; i++) {
765
if (br.groups[0].subres_mask[i] != UINT64_MAX) {
766
may_do_single_barrier = false;
767
break;
768
}
769
}
770
if (may_do_single_barrier) {
771
if (num_subresources % 64) {
772
DEV_ASSERT(br.subres_mask_qwords == subres_mask_full_qwords + 1);
773
uint64_t mask_tail_qword = 0;
774
for (uint8_t i = 0; i < num_subresources % 64; i++) {
775
mask_tail_qword |= ((uint64_t)1 << i);
776
}
777
if ((br.groups[0].subres_mask[subres_mask_full_qwords] & mask_tail_qword) != mask_tail_qword) {
778
may_do_single_barrier = false;
779
}
780
}
781
}
782
}
783
784
if (may_do_single_barrier) {
785
// Second requisite is that the source state is the same for all.
786
787
for (uint32_t i = 1; i < num_subresources; i++) {
788
if (res_states->subresource_states[i] != res_states->subresource_states[0]) {
789
may_do_single_barrier = false;
790
break;
791
}
792
}
793
794
if (may_do_single_barrier) {
795
// Hurray!, we can do a single barrier (plus maybe a UAV one, too).
796
797
bool just_written = res_states->subresource_states[0] == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
798
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;
799
800
uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + 1;
801
if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + needed_barriers) {
802
p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + needed_barriers);
803
}
804
805
if (needs_uav_barrier) {
806
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
807
p_command_buffer->res_barriers_count++;
808
res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;
809
}
810
811
if (res_states->subresource_states[0] != br.groups[0].states) {
812
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, res_states->subresource_states[0], br.groups[0].states, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES);
813
p_command_buffer->res_barriers_count++;
814
}
815
816
for (uint32_t i = 0; i < num_subresources; i++) {
817
res_states->subresource_states[i] = br.groups[0].states;
818
}
819
}
820
}
821
}
822
823
if (!may_do_single_barrier) {
824
for (uint8_t i = 0; i < br.groups_count; i++) {
825
const BarrierRequest::Group &g = E.value.groups[i];
826
827
if (unlikely(g.states == BarrierRequest::DELETED_GROUP)) {
828
continue;
829
}
830
831
uint32_t subresource = 0;
832
do {
833
uint64_t subres_mask_piece = ((uint64_t)1 << (subresource % 64));
834
uint8_t subres_qword = subresource / 64;
835
836
if (likely(g.subres_mask[subres_qword] == 0)) {
837
subresource += 64;
838
continue;
839
}
840
841
if (likely(!(g.subres_mask[subres_qword] & subres_mask_piece))) {
842
subresource++;
843
continue;
844
}
845
846
D3D12_RESOURCE_STATES *curr_state = &res_states->subresource_states[subresource];
847
848
bool just_written = *curr_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
849
bool needs_uav_barrier = just_written && res_states->last_batch_with_uav_barrier != p_command_buffer->res_barriers_batch;
850
851
uint32_t needed_barriers = (needs_uav_barrier ? 1 : 0) + br.planes;
852
if (p_command_buffer->res_barriers.size() < p_command_buffer->res_barriers_count + needed_barriers) {
853
p_command_buffer->res_barriers.resize(p_command_buffer->res_barriers_count + needed_barriers);
854
}
855
856
if (needs_uav_barrier) {
857
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::UAV(br.dx_resource);
858
p_command_buffer->res_barriers_count++;
859
res_states->last_batch_with_uav_barrier = p_command_buffer->res_barriers_batch;
860
}
861
862
if (*curr_state != g.states) {
863
for (uint8_t k = 0; k < br.planes; k++) {
864
p_command_buffer->res_barriers[p_command_buffer->res_barriers_count] = CD3DX12_RESOURCE_BARRIER::Transition(br.dx_resource, *curr_state, g.states, subresource + k * num_subresources);
865
p_command_buffer->res_barriers_count++;
866
}
867
}
868
869
*curr_state = g.states;
870
871
subresource++;
872
} while (subresource < num_subresources);
873
}
874
}
875
}
876
877
if (p_command_buffer->res_barriers_count) {
878
p_command_buffer->cmd_list->ResourceBarrier(p_command_buffer->res_barriers_count, p_command_buffer->res_barriers.ptr());
879
p_command_buffer->res_barriers_requests.clear();
880
}
881
882
p_command_buffer->res_barriers_count = 0;
883
p_command_buffer->res_barriers_batch++;
884
}
885
886
/*****************/
887
/**** BUFFERS ****/
888
/*****************/
889
890
RDD::BufferID RenderingDeviceDriverD3D12::buffer_create(uint64_t p_size, BitField<BufferUsageBits> p_usage, MemoryAllocationType p_allocation_type, uint64_t p_frames_drawn) {
891
uint32_t alignment = D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT; // 16 bytes is reasonable.
892
if (p_usage.has_flag(BUFFER_USAGE_UNIFORM_BIT)) {
893
// 256 bytes is absurd. Only use it when required.
894
alignment = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
895
}
896
897
// We don't have VMA like in Vulkan, that takes care of the details. We must align the size.
898
p_size = STEPIFY(p_size, alignment);
899
900
const size_t original_size = p_size;
901
if (p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT)) {
902
p_size = p_size * frames.size();
903
}
904
905
CD3DX12_RESOURCE_DESC1 resource_desc = CD3DX12_RESOURCE_DESC1::Buffer(p_size);
906
if (p_usage.has_flag(RDD::BUFFER_USAGE_STORAGE_BIT)) {
907
resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
908
} else {
909
resource_desc.Flags |= D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
910
}
911
912
D3D12MA::ALLOCATION_DESC allocation_desc = {};
913
allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
914
D3D12_RESOURCE_STATES initial_state = D3D12_RESOURCE_STATE_COMMON;
915
switch (p_allocation_type) {
916
case MEMORY_ALLOCATION_TYPE_CPU: {
917
bool is_src = p_usage.has_flag(BUFFER_USAGE_TRANSFER_FROM_BIT);
918
bool is_dst = p_usage.has_flag(BUFFER_USAGE_TRANSFER_TO_BIT);
919
if (is_src && !is_dst) {
920
// Looks like a staging buffer: CPU maps, writes sequentially, then GPU copies to VRAM.
921
allocation_desc.HeapType = D3D12_HEAP_TYPE_UPLOAD;
922
initial_state = D3D12_RESOURCE_STATE_GENERIC_READ;
923
}
924
if (is_dst && !is_src) {
925
// Looks like a readback buffer: GPU copies from VRAM, then CPU maps and reads.
926
allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK;
927
initial_state = D3D12_RESOURCE_STATE_COPY_DEST;
928
}
929
} break;
930
case MEMORY_ALLOCATION_TYPE_GPU: {
931
// Use default parameters.
932
if (p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT)) {
933
allocation_desc.HeapType = dynamic_persistent_upload_heap;
934
935
// D3D12_HEAP_TYPE_UPLOAD mandates D3D12_RESOURCE_STATE_GENERIC_READ.
936
if (dynamic_persistent_upload_heap == D3D12_HEAP_TYPE_UPLOAD) {
937
initial_state = D3D12_RESOURCE_STATE_GENERIC_READ;
938
}
939
940
// We can't use STORAGE for write access, just for read.
941
resource_desc.Flags = resource_desc.Flags & ~D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
942
}
943
} break;
944
}
945
946
ComPtr<ID3D12Resource> buffer;
947
ComPtr<D3D12MA::Allocation> allocation;
948
HRESULT res;
949
if (barrier_capabilities.enhanced_barriers_supported) {
950
res = allocator->CreateResource3(
951
&allocation_desc,
952
&resource_desc,
953
D3D12_BARRIER_LAYOUT_UNDEFINED,
954
nullptr,
955
0,
956
nullptr,
957
allocation.GetAddressOf(),
958
IID_PPV_ARGS(buffer.GetAddressOf()));
959
} else {
960
res = allocator->CreateResource(
961
&allocation_desc,
962
reinterpret_cast<const D3D12_RESOURCE_DESC *>(&resource_desc),
963
initial_state,
964
nullptr,
965
allocation.GetAddressOf(),
966
IID_PPV_ARGS(buffer.GetAddressOf()));
967
}
968
969
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), BufferID(), "Can't create buffer of size: " + itos(p_size) + ", error " + vformat("0x%08ux", (uint64_t)res) + ".");
970
971
// Bookkeep.
972
973
BufferInfo *buf_info;
974
if (p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT)) {
975
void *persistent_ptr = nullptr;
976
res = buffer->Map(0, &VOID_RANGE, &persistent_ptr);
977
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), BufferID(), "Map failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
978
979
BufferDynamicInfo *dyn_buffer = VersatileResource::allocate<BufferDynamicInfo>(resources_allocator);
980
buf_info = dyn_buffer;
981
#ifdef DEBUG_ENABLED
982
dyn_buffer->last_frame_mapped = p_frames_drawn - 1ul;
983
#endif
984
dyn_buffer->frame_idx = 0u;
985
dyn_buffer->persistent_ptr = (uint8_t *)persistent_ptr;
986
} else {
987
buf_info = VersatileResource::allocate<BufferInfo>(resources_allocator);
988
}
989
buf_info->resource = buffer.Get();
990
buf_info->owner_info.resource = buffer;
991
buf_info->owner_info.allocation = allocation;
992
buf_info->owner_info.states.subresource_states.push_back(initial_state);
993
buf_info->states_ptr = &buf_info->owner_info.states;
994
buf_info->gpu_virtual_address = buffer->GetGPUVirtualAddress();
995
buf_info->size = original_size;
996
buf_info->flags.is_dynamic = p_usage.has_flag(BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT);
997
998
return BufferID(buf_info);
999
}
1000
1001
bool RenderingDeviceDriverD3D12::buffer_set_texel_format(BufferID p_buffer, DataFormat p_format) {
1002
BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
1003
buf_info->texel_format = p_format;
1004
return true;
1005
}
1006
1007
void RenderingDeviceDriverD3D12::buffer_free(BufferID p_buffer) {
1008
BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
1009
if (buf_info->is_dynamic()) {
1010
buf_info->resource->Unmap(0, &VOID_RANGE);
1011
VersatileResource::free(resources_allocator, (BufferDynamicInfo *)buf_info);
1012
} else {
1013
VersatileResource::free(resources_allocator, buf_info);
1014
}
1015
}
1016
1017
uint64_t RenderingDeviceDriverD3D12::buffer_get_allocation_size(BufferID p_buffer) {
1018
const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
1019
return buf_info->owner_info.allocation ? buf_info->owner_info.allocation->GetSize() : 0;
1020
}
1021
1022
uint8_t *RenderingDeviceDriverD3D12::buffer_map(BufferID p_buffer) {
1023
const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
1024
void *data_ptr = nullptr;
1025
HRESULT res = buf_info->resource->Map(0, &VOID_RANGE, &data_ptr);
1026
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), nullptr, "Map failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
1027
return (uint8_t *)data_ptr;
1028
}
1029
1030
void RenderingDeviceDriverD3D12::buffer_unmap(BufferID p_buffer) {
1031
const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
1032
buf_info->resource->Unmap(0, &VOID_RANGE);
1033
}
1034
1035
uint8_t *RenderingDeviceDriverD3D12::buffer_persistent_map_advance(BufferID p_buffer, uint64_t p_frames_drawn) {
1036
BufferDynamicInfo *buf_info = (BufferDynamicInfo *)p_buffer.id;
1037
ERR_FAIL_COND_V_MSG(!buf_info->is_dynamic(), nullptr, "Buffer must have BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT. Use buffer_map() instead.");
1038
#ifdef DEBUG_ENABLED
1039
ERR_FAIL_COND_V_MSG(buf_info->last_frame_mapped == p_frames_drawn, nullptr, "Buffers with BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT must only be mapped once per frame. Otherwise there could be race conditions with the GPU. Amalgamate all data uploading into one map(), use an extra buffer or remove the bit.");
1040
buf_info->last_frame_mapped = p_frames_drawn;
1041
#endif
1042
buf_info->frame_idx = (buf_info->frame_idx + 1u) % frames.size();
1043
return buf_info->persistent_ptr + buf_info->frame_idx * buf_info->size;
1044
}
1045
1046
uint64_t RenderingDeviceDriverD3D12::buffer_get_dynamic_offsets(Span<BufferID> p_buffers) {
1047
uint64_t mask = 0u;
1048
uint64_t shift = 0u;
1049
1050
for (const BufferID &buf : p_buffers) {
1051
const BufferInfo *buf_info = (const BufferInfo *)buf.id;
1052
if (!buf_info->is_dynamic()) {
1053
continue;
1054
}
1055
const BufferDynamicInfo *dyn_buf = (const BufferDynamicInfo *)buf.id;
1056
mask |= dyn_buf->frame_idx << shift;
1057
// We can encode the frame index in 2 bits since frame_count won't be > 4.
1058
shift += 2UL;
1059
}
1060
1061
return mask;
1062
}
1063
1064
uint64_t RenderingDeviceDriverD3D12::buffer_get_device_address(BufferID p_buffer) {
1065
const BufferInfo *buf_info = (const BufferInfo *)p_buffer.id;
1066
return buf_info->gpu_virtual_address;
1067
}
1068
1069
/*****************/
1070
/**** TEXTURE ****/
1071
/*****************/
1072
1073
static const D3D12_SRV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[RD::TEXTURE_TYPE_MAX] = {
1074
D3D12_SRV_DIMENSION_TEXTURE1D,
1075
D3D12_SRV_DIMENSION_TEXTURE2D,
1076
D3D12_SRV_DIMENSION_TEXTURE3D,
1077
D3D12_SRV_DIMENSION_TEXTURECUBE,
1078
D3D12_SRV_DIMENSION_TEXTURE1DARRAY,
1079
D3D12_SRV_DIMENSION_TEXTURE2DARRAY,
1080
D3D12_SRV_DIMENSION_TEXTURECUBEARRAY,
1081
};
1082
1083
static const D3D12_SRV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[RD::TEXTURE_TYPE_MAX] = {
1084
D3D12_SRV_DIMENSION_UNKNOWN,
1085
D3D12_SRV_DIMENSION_TEXTURE2DMS,
1086
D3D12_SRV_DIMENSION_UNKNOWN,
1087
D3D12_SRV_DIMENSION_UNKNOWN,
1088
D3D12_SRV_DIMENSION_UNKNOWN,
1089
D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY,
1090
D3D12_SRV_DIMENSION_UNKNOWN,
1091
};
1092
1093
static const D3D12_UAV_DIMENSION RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[RD::TEXTURE_TYPE_MAX] = {
1094
D3D12_UAV_DIMENSION_TEXTURE1D,
1095
D3D12_UAV_DIMENSION_TEXTURE2D,
1096
D3D12_UAV_DIMENSION_TEXTURE3D,
1097
D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
1098
D3D12_UAV_DIMENSION_TEXTURE1DARRAY,
1099
D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
1100
D3D12_UAV_DIMENSION_TEXTURE2DARRAY,
1101
};
1102
1103
uint32_t RenderingDeviceDriverD3D12::_find_max_common_supported_sample_count(VectorView<DXGI_FORMAT> p_formats) {
1104
uint32_t common = UINT32_MAX;
1105
1106
MutexLock lock(format_sample_counts_mask_cache_mutex);
1107
for (uint32_t i = 0; i < p_formats.size(); i++) {
1108
if (format_sample_counts_mask_cache.has(p_formats[i])) {
1109
common &= format_sample_counts_mask_cache[p_formats[i]];
1110
} else {
1111
D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msql = {};
1112
msql.Format = p_formats[i];
1113
uint32_t mask = 0;
1114
for (int samples = 1 << (TEXTURE_SAMPLES_MAX - 1); samples >= 1; samples /= 2) {
1115
msql.SampleCount = (UINT)samples;
1116
HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, &msql, sizeof(msql));
1117
if (SUCCEEDED(res) && msql.NumQualityLevels) {
1118
int bit = get_shift_from_power_of_2((uint32_t)samples);
1119
ERR_FAIL_COND_V(bit == -1, 1);
1120
mask |= (uint32_t)(1 << bit);
1121
}
1122
}
1123
format_sample_counts_mask_cache.insert(p_formats[i], mask);
1124
common &= mask;
1125
}
1126
}
1127
if (common == UINT32_MAX) {
1128
return 1;
1129
} else {
1130
return ((uint32_t)1 << nearest_shift(common));
1131
}
1132
}
1133
1134
UINT RenderingDeviceDriverD3D12::_compute_component_mapping(const RDD::TextureView &p_view) {
1135
UINT base_swizzle = RD_TO_D3D12_FORMAT[p_view.format].swizzle;
1136
1137
D3D12_SHADER_COMPONENT_MAPPING component_swizzles[TEXTURE_SWIZZLE_MAX] = {
1138
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0, // Unused.
1139
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_0,
1140
D3D12_SHADER_COMPONENT_MAPPING_FORCE_VALUE_1,
1141
// These will be D3D12_SHADER_COMPONENT_MAPPING_FROM_MEMORY_COMPONENT_*.
1142
D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(0, base_swizzle),
1143
D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(1, base_swizzle),
1144
D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(2, base_swizzle),
1145
D3D12_DECODE_SHADER_4_COMPONENT_MAPPING(3, base_swizzle),
1146
};
1147
1148
return D3D12_ENCODE_SHADER_4_COMPONENT_MAPPING(
1149
p_view.swizzle_r == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_R] : component_swizzles[p_view.swizzle_r],
1150
p_view.swizzle_g == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_G] : component_swizzles[p_view.swizzle_g],
1151
p_view.swizzle_b == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_B] : component_swizzles[p_view.swizzle_b],
1152
p_view.swizzle_a == TEXTURE_SWIZZLE_IDENTITY ? component_swizzles[TEXTURE_SWIZZLE_A] : component_swizzles[p_view.swizzle_a]);
1153
}
1154
1155
UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, BitField<TextureAspectBits> p_aspect_bits) {
1156
TextureAspect aspect = TEXTURE_ASPECT_MAX;
1157
1158
if (p_aspect_bits.has_flag(TEXTURE_ASPECT_COLOR_BIT)) {
1159
DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);
1160
aspect = TEXTURE_ASPECT_COLOR;
1161
}
1162
if (p_aspect_bits.has_flag(TEXTURE_ASPECT_DEPTH_BIT)) {
1163
DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);
1164
aspect = TEXTURE_ASPECT_DEPTH;
1165
} else if (p_aspect_bits.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) {
1166
DEV_ASSERT(aspect == TEXTURE_ASPECT_MAX);
1167
aspect = TEXTURE_ASPECT_STENCIL;
1168
}
1169
1170
DEV_ASSERT(aspect != TEXTURE_ASPECT_MAX);
1171
1172
return _compute_plane_slice(p_format, aspect);
1173
}
1174
1175
UINT RenderingDeviceDriverD3D12::_compute_plane_slice(DataFormat p_format, TextureAspect p_aspect) {
1176
switch (p_aspect) {
1177
case TEXTURE_ASPECT_COLOR:
1178
// The plane must be 0 for the color aspect (assuming the format is a regular color one, which must be the case).
1179
return 0;
1180
case TEXTURE_ASPECT_DEPTH:
1181
// The plane must be 0 for the color or depth aspect
1182
return 0;
1183
case TEXTURE_ASPECT_STENCIL:
1184
// The plane may be 0 for the stencil aspect (if the format is stencil-only), or 1 (if the format is depth-stencil; other cases are ill).
1185
return format_get_plane_count(p_format) == 2 ? 1 : 0;
1186
default:
1187
DEV_ASSERT(false);
1188
return 0;
1189
}
1190
}
1191
1192
UINT RenderingDeviceDriverD3D12::_compute_subresource_from_layers(TextureInfo *p_texture, const TextureSubresourceLayers &p_layers, uint32_t p_layer_offset) {
1193
return D3D12CalcSubresource(p_layers.mipmap, p_layers.base_layer + p_layer_offset, _compute_plane_slice(p_texture->format, p_layers.aspect), p_texture->desc.MipLevels, p_texture->desc.ArraySize());
1194
}
1195
1196
void RenderingDeviceDriverD3D12::_discard_texture_subresources(const TextureInfo *p_tex_info, const CommandBufferInfo *p_cmd_buf_info) {
1197
uint32_t planes = 1;
1198
if ((p_tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
1199
planes = format_get_plane_count(p_tex_info->format);
1200
}
1201
D3D12_DISCARD_REGION dr = {};
1202
dr.NumRects = p_cmd_buf_info->render_pass_state.region_is_all ? 0 : 1;
1203
dr.pRects = p_cmd_buf_info->render_pass_state.region_is_all ? nullptr : &p_cmd_buf_info->render_pass_state.region_rect;
1204
dr.FirstSubresource = UINT_MAX;
1205
dr.NumSubresources = 0;
1206
for (uint32_t u = 0; u < planes; u++) {
1207
for (uint32_t v = 0; v < p_tex_info->layers; v++) {
1208
for (uint32_t w = 0; w < p_tex_info->mipmaps; w++) {
1209
UINT subresource = D3D12CalcSubresource(
1210
p_tex_info->base_mip + w,
1211
p_tex_info->base_layer + v,
1212
u,
1213
p_tex_info->desc.MipLevels,
1214
p_tex_info->desc.ArraySize());
1215
if (dr.NumSubresources == 0) {
1216
dr.FirstSubresource = subresource;
1217
dr.NumSubresources = 1;
1218
} else if (dr.FirstSubresource + dr.NumSubresources == subresource) {
1219
dr.NumSubresources++;
1220
} else {
1221
p_cmd_buf_info->cmd_list->DiscardResource(p_tex_info->resource, &dr);
1222
dr.FirstSubresource = subresource;
1223
dr.NumSubresources = 1;
1224
}
1225
}
1226
}
1227
}
1228
if (dr.NumSubresources) {
1229
p_cmd_buf_info->cmd_list->DiscardResource(p_tex_info->resource, &dr);
1230
}
1231
}
1232
1233
bool RenderingDeviceDriverD3D12::_unordered_access_supported_by_format(DataFormat p_format) {
1234
switch (p_format) {
1235
case DATA_FORMAT_R4G4_UNORM_PACK8:
1236
case DATA_FORMAT_R4G4B4A4_UNORM_PACK16:
1237
case DATA_FORMAT_B4G4R4A4_UNORM_PACK16:
1238
case DATA_FORMAT_R5G6B5_UNORM_PACK16:
1239
case DATA_FORMAT_B5G6R5_UNORM_PACK16:
1240
case DATA_FORMAT_R5G5B5A1_UNORM_PACK16:
1241
case DATA_FORMAT_B5G5R5A1_UNORM_PACK16:
1242
case DATA_FORMAT_A1R5G5B5_UNORM_PACK16:
1243
case DATA_FORMAT_A8B8G8R8_UNORM_PACK32:
1244
case DATA_FORMAT_A8B8G8R8_SNORM_PACK32:
1245
case DATA_FORMAT_A8B8G8R8_USCALED_PACK32:
1246
case DATA_FORMAT_A8B8G8R8_SSCALED_PACK32:
1247
case DATA_FORMAT_A8B8G8R8_UINT_PACK32:
1248
case DATA_FORMAT_A8B8G8R8_SINT_PACK32:
1249
case DATA_FORMAT_A8B8G8R8_SRGB_PACK32:
1250
case DATA_FORMAT_A2R10G10B10_UNORM_PACK32:
1251
case DATA_FORMAT_A2R10G10B10_SNORM_PACK32:
1252
case DATA_FORMAT_A2R10G10B10_USCALED_PACK32:
1253
case DATA_FORMAT_A2R10G10B10_SSCALED_PACK32:
1254
case DATA_FORMAT_A2R10G10B10_UINT_PACK32:
1255
case DATA_FORMAT_A2R10G10B10_SINT_PACK32:
1256
case DATA_FORMAT_A2B10G10R10_UNORM_PACK32:
1257
case DATA_FORMAT_A2B10G10R10_SNORM_PACK32:
1258
case DATA_FORMAT_A2B10G10R10_USCALED_PACK32:
1259
case DATA_FORMAT_A2B10G10R10_SSCALED_PACK32:
1260
case DATA_FORMAT_A2B10G10R10_UINT_PACK32:
1261
case DATA_FORMAT_A2B10G10R10_SINT_PACK32:
1262
case DATA_FORMAT_B10G11R11_UFLOAT_PACK32:
1263
case DATA_FORMAT_E5B9G9R9_UFLOAT_PACK32:
1264
case DATA_FORMAT_X8_D24_UNORM_PACK32:
1265
case DATA_FORMAT_R10X6_UNORM_PACK16:
1266
case DATA_FORMAT_R10X6G10X6_UNORM_2PACK16:
1267
case DATA_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
1268
case DATA_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
1269
case DATA_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
1270
case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
1271
case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
1272
case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
1273
case DATA_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
1274
case DATA_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
1275
case DATA_FORMAT_R12X4_UNORM_PACK16:
1276
case DATA_FORMAT_R12X4G12X4_UNORM_2PACK16:
1277
case DATA_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
1278
case DATA_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
1279
case DATA_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
1280
case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
1281
case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
1282
case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
1283
case DATA_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
1284
case DATA_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
1285
return false;
1286
default:
1287
return true;
1288
}
1289
}
1290
1291
RDD::TextureID RenderingDeviceDriverD3D12::texture_create(const TextureFormat &p_format, const TextureView &p_view) {
1292
// Using D3D12_RESOURCE_DESC1. Thanks to the layout, it's sliceable down to D3D12_RESOURCE_DESC if needed.
1293
CD3DX12_RESOURCE_DESC1 resource_desc = {};
1294
resource_desc.Dimension = RD_TEXTURE_TYPE_TO_D3D12_RESOURCE_DIMENSION[p_format.texture_type];
1295
resource_desc.Alignment = 0; // D3D12MA will override this to use a smaller alignment than the default if possible.
1296
1297
resource_desc.Width = p_format.width;
1298
resource_desc.Height = p_format.height;
1299
resource_desc.DepthOrArraySize = p_format.depth * p_format.array_layers;
1300
resource_desc.MipLevels = p_format.mipmaps;
1301
1302
// Format.
1303
bool cross_family_sharing = false;
1304
bool relaxed_casting_available = false;
1305
DXGI_FORMAT *relaxed_casting_formats = nullptr;
1306
uint32_t relaxed_casting_format_count = 0;
1307
{
1308
resource_desc.Format = RD_TO_D3D12_FORMAT[p_format.format].family;
1309
1310
// If views of different families are wanted, special setup is needed for proper sharing among them.
1311
// If the driver reports relaxed casting is, leverage its new extended resource creation API (via D3D12MA).
1312
if (p_format.shareable_formats.size() && format_capabilities.relaxed_casting_supported) {
1313
relaxed_casting_available = true;
1314
relaxed_casting_formats = ALLOCA_ARRAY(DXGI_FORMAT, p_format.shareable_formats.size() + 1);
1315
relaxed_casting_formats[0] = RD_TO_D3D12_FORMAT[p_format.format].general_format;
1316
relaxed_casting_format_count++;
1317
}
1318
1319
HashMap<DataFormat, D3D12_RESOURCE_FLAGS> aliases_forbidden_flags;
1320
for (int i = 0; i < p_format.shareable_formats.size(); i++) {
1321
DataFormat curr_format = p_format.shareable_formats[i];
1322
String format_text = "'" + String(FORMAT_NAMES[p_format.format]) + "'";
1323
1324
ERR_FAIL_COND_V_MSG(RD_TO_D3D12_FORMAT[curr_format].family == DXGI_FORMAT_UNKNOWN, TextureID(), "Format " + format_text + " is not supported.");
1325
1326
if (RD_TO_D3D12_FORMAT[curr_format].family != RD_TO_D3D12_FORMAT[p_format.format].family) {
1327
cross_family_sharing = true;
1328
}
1329
1330
if (relaxed_casting_available) {
1331
relaxed_casting_formats[relaxed_casting_format_count] = RD_TO_D3D12_FORMAT[curr_format].general_format;
1332
relaxed_casting_format_count++;
1333
}
1334
}
1335
1336
if (cross_family_sharing && !relaxed_casting_available) {
1337
// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_texture_layout.
1338
if (p_format.texture_type == TEXTURE_TYPE_1D) {
1339
ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a 1D texture.");
1340
}
1341
if (p_format.samples != TEXTURE_SAMPLES_1) {
1342
ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a multi-sample texture.");
1343
}
1344
if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
1345
ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for a depth-stencil texture.");
1346
}
1347
if (RD_TO_D3D12_FORMAT[p_format.format].family == DXGI_FORMAT_R32G32B32_TYPELESS) {
1348
ERR_FAIL_V_MSG(TextureID(), "This texture's views require aliasing, but that's not supported for an R32G32B32 texture.");
1349
}
1350
}
1351
}
1352
1353
// Usage.
1354
if ((p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
1355
resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
1356
} else {
1357
if ((p_format.usage_bits & TEXTURE_USAGE_CAN_COPY_TO_BIT) && _unordered_access_supported_by_format(p_format.format)) {
1358
resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; // For clearing via UAV.
1359
}
1360
}
1361
if ((p_format.usage_bits & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
1362
resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
1363
}
1364
if ((p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT)) {
1365
resource_desc.Flags |= D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
1366
}
1367
if ((p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT)) {
1368
ERR_FAIL_V_MSG(TextureID(), "CPU readable textures are unsupported on D3D12.");
1369
}
1370
if ((p_format.usage_bits & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) && (p_format.usage_bits & TEXTURE_USAGE_VRS_FRAGMENT_SHADING_RATE_BIT)) {
1371
// For VRS images we can't use the typeless format.
1372
resource_desc.Format = DXGI_FORMAT_R8_UINT;
1373
}
1374
1375
resource_desc.SampleDesc = {};
1376
DXGI_FORMAT format_to_test = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL) ? RD_TO_D3D12_FORMAT[p_format.format].dsv_format : RD_TO_D3D12_FORMAT[p_format.format].general_format;
1377
if (!(resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
1378
resource_desc.SampleDesc.Count = MIN(
1379
_find_max_common_supported_sample_count(format_to_test),
1380
TEXTURE_SAMPLES_COUNT[p_format.samples]);
1381
} else {
1382
// No MSAA in D3D12 if storage. May have become possible recently where supported, though.
1383
resource_desc.SampleDesc.Count = 1;
1384
}
1385
resource_desc.SampleDesc.Quality = resource_desc.SampleDesc.Count == 1 ? 0 : DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
1386
1387
// Create.
1388
1389
D3D12MA::ALLOCATION_DESC allocation_desc = {};
1390
allocation_desc.HeapType = D3D12_HEAP_TYPE_DEFAULT;
1391
if ((resource_desc.Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))) {
1392
allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
1393
} else {
1394
allocation_desc.ExtraHeapFlags = D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
1395
}
1396
if ((resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS)) {
1397
allocation_desc.ExtraHeapFlags |= D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS;
1398
}
1399
1400
D3D12_RESOURCE_STATES initial_state = {};
1401
ID3D12Resource *texture = nullptr;
1402
ComPtr<ID3D12Resource> main_texture;
1403
ComPtr<D3D12MA::Allocation> allocation;
1404
static const FLOAT black[4] = {};
1405
D3D12_CLEAR_VALUE clear_value = CD3DX12_CLEAR_VALUE(RD_TO_D3D12_FORMAT[p_format.format].general_format, black);
1406
D3D12_CLEAR_VALUE *clear_value_ptr = (resource_desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET) ? &clear_value : nullptr;
1407
{
1408
HRESULT res = E_FAIL;
1409
if (barrier_capabilities.enhanced_barriers_supported || (cross_family_sharing && relaxed_casting_available)) {
1410
// Create with undefined layout if enhanced barriers are supported. Leave as common otherwise for interop with legacy barriers.
1411
D3D12_BARRIER_LAYOUT initial_layout = barrier_capabilities.enhanced_barriers_supported ? D3D12_BARRIER_LAYOUT_UNDEFINED : D3D12_BARRIER_LAYOUT_COMMON;
1412
res = allocator->CreateResource3(
1413
&allocation_desc,
1414
&resource_desc,
1415
initial_layout,
1416
clear_value_ptr,
1417
relaxed_casting_format_count,
1418
relaxed_casting_formats,
1419
allocation.GetAddressOf(),
1420
IID_PPV_ARGS(main_texture.GetAddressOf()));
1421
initial_state = D3D12_RESOURCE_STATE_COMMON;
1422
} else {
1423
res = allocator->CreateResource(
1424
&allocation_desc,
1425
(D3D12_RESOURCE_DESC *)&resource_desc,
1426
D3D12_RESOURCE_STATE_COPY_DEST,
1427
clear_value_ptr,
1428
allocation.GetAddressOf(),
1429
IID_PPV_ARGS(main_texture.GetAddressOf()));
1430
initial_state = D3D12_RESOURCE_STATE_COPY_DEST;
1431
}
1432
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), TextureID(), "CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
1433
texture = main_texture.Get();
1434
}
1435
1436
// Describe views.
1437
1438
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
1439
{
1440
srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
1441
srv_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[p_format.texture_type] : RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[p_format.texture_type];
1442
srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view);
1443
1444
switch (srv_desc.ViewDimension) {
1445
case D3D12_SRV_DIMENSION_TEXTURE1D: {
1446
srv_desc.Texture1D.MipLevels = p_format.mipmaps;
1447
} break;
1448
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
1449
srv_desc.Texture1DArray.MipLevels = p_format.mipmaps;
1450
srv_desc.Texture1DArray.ArraySize = p_format.array_layers;
1451
} break;
1452
case D3D12_SRV_DIMENSION_TEXTURE2D: {
1453
srv_desc.Texture2D.MipLevels = p_format.mipmaps;
1454
} break;
1455
case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
1456
} break;
1457
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
1458
srv_desc.Texture2DArray.MipLevels = p_format.mipmaps;
1459
srv_desc.Texture2DArray.ArraySize = p_format.array_layers;
1460
} break;
1461
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
1462
srv_desc.Texture2DMSArray.ArraySize = p_format.array_layers;
1463
} break;
1464
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {
1465
srv_desc.TextureCubeArray.MipLevels = p_format.mipmaps;
1466
srv_desc.TextureCubeArray.NumCubes = p_format.array_layers / 6;
1467
} break;
1468
case D3D12_SRV_DIMENSION_TEXTURE3D: {
1469
srv_desc.Texture3D.MipLevels = p_format.mipmaps;
1470
} break;
1471
case D3D12_SRV_DIMENSION_TEXTURECUBE: {
1472
srv_desc.TextureCube.MipLevels = p_format.mipmaps;
1473
} break;
1474
default: {
1475
}
1476
}
1477
}
1478
1479
D3D12_UNORDERED_ACCESS_VIEW_DESC main_uav_desc = {};
1480
{
1481
main_uav_desc.Format = RD_TO_D3D12_FORMAT[p_format.format].general_format;
1482
main_uav_desc.ViewDimension = p_format.samples == TEXTURE_SAMPLES_1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[p_format.texture_type] : D3D12_UAV_DIMENSION_UNKNOWN;
1483
1484
switch (main_uav_desc.ViewDimension) {
1485
case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {
1486
main_uav_desc.Texture1DArray.ArraySize = p_format.array_layers;
1487
} break;
1488
case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {
1489
// Either for an actual 2D texture array, cubemap or cubemap array.
1490
main_uav_desc.Texture2DArray.ArraySize = p_format.array_layers;
1491
} break;
1492
case D3D12_UAV_DIMENSION_TEXTURE3D: {
1493
main_uav_desc.Texture3D.WSize = p_format.depth;
1494
} break;
1495
default: {
1496
}
1497
}
1498
}
1499
1500
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = main_uav_desc;
1501
uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
1502
1503
// Bookkeep.
1504
1505
TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
1506
tex_info->resource = texture;
1507
tex_info->owner_info.resource = main_texture;
1508
tex_info->owner_info.allocation = allocation;
1509
tex_info->owner_info.states.subresource_states.resize(p_format.mipmaps * p_format.array_layers);
1510
for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) {
1511
tex_info->owner_info.states.subresource_states[i] = initial_state;
1512
}
1513
tex_info->states_ptr = &tex_info->owner_info.states;
1514
tex_info->format = p_format.format;
1515
GODOT_GCC_WARNING_PUSH_AND_IGNORE("-Wstrict-aliasing")
1516
tex_info->desc = *(CD3DX12_RESOURCE_DESC *)&resource_desc;
1517
GODOT_GCC_WARNING_POP
1518
tex_info->base_layer = 0;
1519
tex_info->layers = resource_desc.ArraySize();
1520
tex_info->base_mip = 0;
1521
tex_info->mipmaps = resource_desc.MipLevels;
1522
tex_info->view_descs.srv = srv_desc;
1523
tex_info->view_descs.uav = uav_desc;
1524
1525
return TextureID(tex_info);
1526
}
1527
1528
RDD::TextureID RenderingDeviceDriverD3D12::texture_create_from_extension(uint64_t p_native_texture, TextureType p_type, DataFormat p_format, uint32_t p_array_layers, bool p_depth_stencil, uint32_t p_mipmaps) {
1529
ID3D12Resource *texture = (ID3D12Resource *)p_native_texture;
1530
1531
#if defined(_MSC_VER) || !defined(_WIN32)
1532
const D3D12_RESOURCE_DESC base_resource_desc = texture->GetDesc();
1533
#else
1534
D3D12_RESOURCE_DESC base_resource_desc;
1535
texture->GetDesc(&base_resource_desc);
1536
#endif
1537
CD3DX12_RESOURCE_DESC resource_desc(base_resource_desc);
1538
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
1539
{
1540
srv_desc.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
1541
srv_desc.ViewDimension = resource_desc.SampleDesc.Count == 1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV[p_type] : RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_SRV_MS[p_type];
1542
srv_desc.Shader4ComponentMapping = _compute_component_mapping(TextureView{ p_format });
1543
1544
switch (srv_desc.ViewDimension) {
1545
case D3D12_SRV_DIMENSION_TEXTURE1D: {
1546
srv_desc.Texture1D.MipLevels = resource_desc.MipLevels;
1547
} break;
1548
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
1549
srv_desc.Texture1DArray.MipLevels = resource_desc.MipLevels;
1550
srv_desc.Texture1DArray.ArraySize = p_array_layers;
1551
} break;
1552
case D3D12_SRV_DIMENSION_TEXTURE2D: {
1553
srv_desc.Texture2D.MipLevels = resource_desc.MipLevels;
1554
} break;
1555
case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
1556
} break;
1557
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
1558
srv_desc.Texture2DArray.MipLevels = resource_desc.MipLevels;
1559
srv_desc.Texture2DArray.ArraySize = p_array_layers;
1560
} break;
1561
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
1562
srv_desc.Texture2DMSArray.ArraySize = p_array_layers;
1563
} break;
1564
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {
1565
srv_desc.TextureCubeArray.MipLevels = resource_desc.MipLevels;
1566
srv_desc.TextureCubeArray.NumCubes = p_array_layers / 6;
1567
} break;
1568
case D3D12_SRV_DIMENSION_TEXTURE3D: {
1569
srv_desc.Texture3D.MipLevels = resource_desc.MipLevels;
1570
} break;
1571
case D3D12_SRV_DIMENSION_TEXTURECUBE: {
1572
srv_desc.TextureCube.MipLevels = resource_desc.MipLevels;
1573
} break;
1574
default: {
1575
}
1576
}
1577
}
1578
1579
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
1580
{
1581
uav_desc.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
1582
uav_desc.ViewDimension = resource_desc.SampleDesc.Count == 1 ? RD_TEXTURE_TYPE_TO_D3D12_VIEW_DIMENSION_FOR_UAV[p_type] : D3D12_UAV_DIMENSION_UNKNOWN;
1583
1584
switch (uav_desc.ViewDimension) {
1585
case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {
1586
uav_desc.Texture1DArray.ArraySize = p_array_layers;
1587
} break;
1588
case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {
1589
// Either for an actual 2D texture array, cubemap or cubemap array.
1590
uav_desc.Texture2DArray.ArraySize = p_array_layers;
1591
} break;
1592
case D3D12_UAV_DIMENSION_TEXTURE3D: {
1593
uav_desc.Texture3D.WSize = resource_desc.Depth();
1594
} break;
1595
default: {
1596
}
1597
}
1598
}
1599
1600
TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
1601
tex_info->resource = texture;
1602
tex_info->owner_info.resource = nullptr; // Not allocated by us.
1603
tex_info->owner_info.allocation = nullptr; // Not allocated by us.
1604
tex_info->owner_info.states.subresource_states.resize(resource_desc.MipLevels * p_array_layers);
1605
for (uint32_t i = 0; i < tex_info->owner_info.states.subresource_states.size(); i++) {
1606
tex_info->owner_info.states.subresource_states[i] = !p_depth_stencil ? D3D12_RESOURCE_STATE_RENDER_TARGET : D3D12_RESOURCE_STATE_DEPTH_WRITE;
1607
}
1608
tex_info->states_ptr = &tex_info->owner_info.states;
1609
tex_info->format = p_format;
1610
#if defined(__GNUC__) && !defined(__clang__)
1611
#pragma GCC diagnostic push
1612
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
1613
#endif
1614
tex_info->desc = *(CD3DX12_RESOURCE_DESC *)&resource_desc;
1615
#if defined(__GNUC__) && !defined(__clang__)
1616
#pragma GCC diagnostic pop
1617
#endif
1618
tex_info->base_layer = 0;
1619
tex_info->layers = p_array_layers;
1620
tex_info->base_mip = 0;
1621
tex_info->mipmaps = resource_desc.MipLevels;
1622
tex_info->view_descs.srv = srv_desc;
1623
tex_info->view_descs.uav = uav_desc;
1624
#ifdef DEBUG_ENABLED
1625
tex_info->created_from_extension = true;
1626
#endif
1627
return TextureID(tex_info);
1628
}
1629
1630
RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared(TextureID p_original_texture, const TextureView &p_view) {
1631
return _texture_create_shared_from_slice(p_original_texture, p_view, (TextureSliceType)-1, 0, 0, 0, 0);
1632
}
1633
1634
RDD::TextureID RenderingDeviceDriverD3D12::texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {
1635
return _texture_create_shared_from_slice(p_original_texture, p_view, p_slice_type, p_layer, p_layers, p_mipmap, p_mipmaps);
1636
}
1637
1638
RDD::TextureID RenderingDeviceDriverD3D12::_texture_create_shared_from_slice(TextureID p_original_texture, const TextureView &p_view, TextureSliceType p_slice_type, uint32_t p_layer, uint32_t p_layers, uint32_t p_mipmap, uint32_t p_mipmaps) {
1639
TextureInfo *owner_tex_info = (TextureInfo *)p_original_texture.id;
1640
#ifdef DEBUG_ENABLED
1641
ERR_FAIL_COND_V(!owner_tex_info->owner_info.allocation, TextureID());
1642
#endif
1643
1644
ComPtr<ID3D12Resource> new_texture;
1645
ComPtr<D3D12MA::Allocation> new_allocation;
1646
ID3D12Resource *resource = owner_tex_info->resource;
1647
CD3DX12_RESOURCE_DESC new_tex_resource_desc = owner_tex_info->desc;
1648
1649
// Describe views.
1650
1651
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = owner_tex_info->view_descs.srv;
1652
{
1653
srv_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
1654
srv_desc.Shader4ComponentMapping = _compute_component_mapping(p_view);
1655
}
1656
1657
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = owner_tex_info->view_descs.uav;
1658
{
1659
uav_desc.Format = RD_TO_D3D12_FORMAT[p_view.format].general_format;
1660
}
1661
1662
if (p_slice_type != (TextureSliceType)-1) {
1663
// Complete description with slicing.
1664
1665
switch (p_slice_type) {
1666
case TEXTURE_SLICE_2D: {
1667
if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer == 0) {
1668
srv_desc.Texture2D.MostDetailedMip = p_mipmap;
1669
srv_desc.Texture2D.MipLevels = p_mipmaps;
1670
1671
DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D);
1672
uav_desc.Texture1D.MipSlice = p_mipmap;
1673
} else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer == 0) {
1674
DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN);
1675
} else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D && p_layer)) || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY) {
1676
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DARRAY;
1677
srv_desc.Texture2DArray.MostDetailedMip = p_mipmap;
1678
srv_desc.Texture2DArray.MipLevels = p_mipmaps;
1679
srv_desc.Texture2DArray.FirstArraySlice = p_layer;
1680
srv_desc.Texture2DArray.ArraySize = 1;
1681
srv_desc.Texture2DArray.PlaneSlice = 0;
1682
srv_desc.Texture2DArray.ResourceMinLODClamp = 0.0f;
1683
1684
uav_desc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
1685
uav_desc.Texture2DArray.MipSlice = p_mipmap;
1686
uav_desc.Texture2DArray.FirstArraySlice = p_layer;
1687
uav_desc.Texture2DArray.ArraySize = 1;
1688
uav_desc.Texture2DArray.PlaneSlice = 0;
1689
} else if ((srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY || (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS && p_layer))) {
1690
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY;
1691
srv_desc.Texture2DMSArray.FirstArraySlice = p_layer;
1692
srv_desc.Texture2DMSArray.ArraySize = 1;
1693
1694
uav_desc.ViewDimension = D3D12_UAV_DIMENSION_UNKNOWN;
1695
} else {
1696
DEV_ASSERT(false);
1697
}
1698
} break;
1699
case TEXTURE_SLICE_CUBEMAP: {
1700
if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBE || p_layer == 0) {
1701
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBE;
1702
srv_desc.TextureCube.MostDetailedMip = p_mipmap;
1703
srv_desc.TextureCube.MipLevels = p_mipmaps;
1704
1705
DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
1706
uav_desc.Texture2DArray.MipSlice = p_mipmap;
1707
uav_desc.Texture2DArray.FirstArraySlice = p_layer;
1708
uav_desc.Texture2DArray.ArraySize = 6;
1709
uav_desc.Texture2DArray.PlaneSlice = 0;
1710
} else if (srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY || p_layer != 0) {
1711
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURECUBEARRAY;
1712
srv_desc.TextureCubeArray.MostDetailedMip = p_mipmap;
1713
srv_desc.TextureCubeArray.MipLevels = p_mipmaps;
1714
srv_desc.TextureCubeArray.First2DArrayFace = p_layer;
1715
srv_desc.TextureCubeArray.NumCubes = 1;
1716
srv_desc.TextureCubeArray.ResourceMinLODClamp = 0.0f;
1717
1718
DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
1719
uav_desc.Texture2DArray.MipSlice = p_mipmap;
1720
uav_desc.Texture2DArray.FirstArraySlice = p_layer;
1721
uav_desc.Texture2DArray.ArraySize = 6;
1722
uav_desc.Texture2DArray.PlaneSlice = 0;
1723
} else {
1724
DEV_ASSERT(false);
1725
}
1726
} break;
1727
case TEXTURE_SLICE_3D: {
1728
DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE3D);
1729
srv_desc.Texture3D.MostDetailedMip = p_mipmap;
1730
srv_desc.Texture3D.MipLevels = p_mipmaps;
1731
1732
DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE3D);
1733
uav_desc.Texture3D.MipSlice = p_mipmap;
1734
uav_desc.Texture3D.WSize = -1;
1735
} break;
1736
case TEXTURE_SLICE_2D_ARRAY: {
1737
DEV_ASSERT(srv_desc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY);
1738
srv_desc.Texture2DArray.MostDetailedMip = p_mipmap;
1739
srv_desc.Texture2DArray.MipLevels = p_mipmaps;
1740
srv_desc.Texture2DArray.FirstArraySlice = p_layer;
1741
srv_desc.Texture2DArray.ArraySize = p_layers;
1742
1743
DEV_ASSERT(uav_desc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY);
1744
uav_desc.Texture2DArray.MipSlice = p_mipmap;
1745
uav_desc.Texture2DArray.FirstArraySlice = p_layer;
1746
uav_desc.Texture2DArray.ArraySize = p_layers;
1747
} break;
1748
default:
1749
break;
1750
}
1751
}
1752
1753
// Bookkeep.
1754
1755
TextureInfo *tex_info = VersatileResource::allocate<TextureInfo>(resources_allocator);
1756
tex_info->resource = resource;
1757
tex_info->states_ptr = owner_tex_info->states_ptr;
1758
tex_info->format = p_view.format;
1759
tex_info->desc = new_tex_resource_desc;
1760
if (p_slice_type == (TextureSliceType)-1) {
1761
tex_info->base_layer = owner_tex_info->base_layer;
1762
tex_info->layers = owner_tex_info->layers;
1763
tex_info->base_mip = owner_tex_info->base_mip;
1764
tex_info->mipmaps = owner_tex_info->mipmaps;
1765
} else {
1766
tex_info->base_layer = p_layer;
1767
tex_info->layers = p_layers;
1768
tex_info->base_mip = p_mipmap;
1769
tex_info->mipmaps = p_mipmaps;
1770
}
1771
tex_info->view_descs.srv = srv_desc;
1772
tex_info->view_descs.uav = uav_desc;
1773
tex_info->main_texture = owner_tex_info;
1774
1775
return TextureID(tex_info);
1776
}
1777
1778
void RenderingDeviceDriverD3D12::texture_free(TextureID p_texture) {
1779
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
1780
VersatileResource::free(resources_allocator, tex_info);
1781
}
1782
1783
uint64_t RenderingDeviceDriverD3D12::texture_get_allocation_size(TextureID p_texture) {
1784
const TextureInfo *tex_info = (const TextureInfo *)p_texture.id;
1785
return tex_info->owner_info.allocation ? tex_info->owner_info.allocation->GetSize() : 0;
1786
}
1787
1788
void RenderingDeviceDriverD3D12::texture_get_copyable_layout(TextureID p_texture, const TextureSubresource &p_subresource, TextureCopyableLayout *r_layout) {
1789
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
1790
1791
UINT plane = _compute_plane_slice(tex_info->format, p_subresource.aspect);
1792
UINT subresource = tex_info->desc.CalcSubresource(p_subresource.mipmap, p_subresource.layer, plane);
1793
1794
D3D12_PLACED_SUBRESOURCE_FOOTPRINT footprint = {};
1795
UINT64 subresource_total_size = 0;
1796
device->GetCopyableFootprints(
1797
&tex_info->desc,
1798
subresource,
1799
1,
1800
0,
1801
&footprint,
1802
nullptr,
1803
nullptr,
1804
&subresource_total_size);
1805
1806
*r_layout = {};
1807
r_layout->size = subresource_total_size;
1808
r_layout->row_pitch = footprint.Footprint.RowPitch;
1809
}
1810
1811
Vector<uint8_t> RenderingDeviceDriverD3D12::texture_get_data(TextureID p_texture, uint32_t p_layer) {
1812
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Cannot get texture data. CPU readable textures are unsupported on D3D12.");
1813
}
1814
1815
BitField<RDD::TextureUsageBits> RenderingDeviceDriverD3D12::texture_get_usages_supported_by_format(DataFormat p_format, bool p_cpu_readable) {
1816
if (p_cpu_readable) {
1817
// CPU readable textures are unsupported on D3D12.
1818
return 0;
1819
}
1820
1821
D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};
1822
srv_rtv_support.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
1823
if (srv_rtv_support.Format != DXGI_FORMAT_UNKNOWN) { // Some implementations (i.e., vkd3d-proton) error out instead of returning empty.
1824
HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));
1825
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
1826
}
1827
1828
D3D12_FEATURE_DATA_FORMAT_SUPPORT &uav_support = srv_rtv_support; // Fine for now.
1829
1830
D3D12_FEATURE_DATA_FORMAT_SUPPORT dsv_support = {};
1831
dsv_support.Format = RD_TO_D3D12_FORMAT[p_format].dsv_format;
1832
if (dsv_support.Format != DXGI_FORMAT_UNKNOWN) { // See above.
1833
HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &dsv_support, sizeof(dsv_support));
1834
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
1835
}
1836
1837
// Everything supported by default makes an all-or-nothing check easier for the caller.
1838
BitField<RDD::TextureUsageBits> supported = INT64_MAX;
1839
1840
// Per https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_format_support1,
1841
// as long as the resource can be used as a texture, Sample() will work with point filter at least.
1842
// However, we've empirically found that checking for at least D3D12_FORMAT_SUPPORT1_SHADER_LOAD is needed.
1843
// That's almost good for integer formats. The problem is that theoretically there may be
1844
// float formats that support LOAD but not SAMPLE fully, so this check will not detect
1845
// such a flaw in the format. Linearly interpolated sampling would just not work on them.
1846
if (!(srv_rtv_support.Support1 & (D3D12_FORMAT_SUPPORT1_SHADER_LOAD | D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE)) ||
1847
RD_TO_D3D12_FORMAT[p_format].general_format == DXGI_FORMAT_UNKNOWN) {
1848
supported.clear_flag(TEXTURE_USAGE_SAMPLING_BIT);
1849
}
1850
1851
if (!(srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_RENDER_TARGET)) {
1852
supported.clear_flag(TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);
1853
}
1854
if (!(dsv_support.Support1 & D3D12_FORMAT_SUPPORT1_DEPTH_STENCIL)) {
1855
supported.clear_flag(TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
1856
}
1857
if (!(uav_support.Support1 & D3D12_FORMAT_SUPPORT1_TYPED_UNORDERED_ACCESS_VIEW)) { // Maybe check LOAD/STORE, too?
1858
supported.clear_flag(TEXTURE_USAGE_STORAGE_BIT);
1859
}
1860
if (!(uav_support.Support2 & D3D12_FORMAT_SUPPORT2_UAV_ATOMIC_ADD)) { // Check a basic atomic at least.
1861
supported.clear_flag(TEXTURE_USAGE_STORAGE_ATOMIC_BIT);
1862
}
1863
if (RD_TO_D3D12_FORMAT[p_format].general_format != DXGI_FORMAT_R8_UINT) {
1864
supported.clear_flag(TEXTURE_USAGE_VRS_ATTACHMENT_BIT);
1865
}
1866
1867
return supported;
1868
}
1869
1870
bool RenderingDeviceDriverD3D12::texture_can_make_shared_with_format(TextureID p_texture, DataFormat p_format, bool &r_raw_reinterpretation) {
1871
r_raw_reinterpretation = false;
1872
1873
if (format_capabilities.relaxed_casting_supported) {
1874
// Relaxed casting is supported, there should be no need to check for format family compatibility.
1875
return true;
1876
} else {
1877
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
1878
if (tex_info->format == DATA_FORMAT_R16_UINT && p_format == DATA_FORMAT_R4G4B4A4_UNORM_PACK16) {
1879
// Specific cases that require buffer reinterpretation.
1880
r_raw_reinterpretation = true;
1881
return false;
1882
} else if (RD_TO_D3D12_FORMAT[tex_info->format].family != RD_TO_D3D12_FORMAT[p_format].family) {
1883
// Format family is different but copying resources directly is possible.
1884
return false;
1885
} else {
1886
// Format family is the same and the view can just cast the format.
1887
return true;
1888
}
1889
}
1890
}
1891
1892
/*****************/
1893
/**** SAMPLER ****/
1894
/*****************/
1895
1896
static const D3D12_TEXTURE_ADDRESS_MODE RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[RDD::SAMPLER_REPEAT_MODE_MAX] = {
1897
D3D12_TEXTURE_ADDRESS_MODE_WRAP,
1898
D3D12_TEXTURE_ADDRESS_MODE_MIRROR,
1899
D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
1900
D3D12_TEXTURE_ADDRESS_MODE_BORDER,
1901
D3D12_TEXTURE_ADDRESS_MODE_MIRROR_ONCE,
1902
};
1903
1904
static const FLOAT RD_TO_D3D12_SAMPLER_BORDER_COLOR[RDD::SAMPLER_BORDER_COLOR_MAX][4] = {
1905
{ 0, 0, 0, 0 },
1906
{ 0, 0, 0, 0 },
1907
{ 0, 0, 0, 1 },
1908
{ 0, 0, 0, 1 },
1909
{ 1, 1, 1, 1 },
1910
{ 1, 1, 1, 1 },
1911
};
1912
1913
RDD::SamplerID RenderingDeviceDriverD3D12::sampler_create(const SamplerState &p_state) {
1914
uint32_t slot = UINT32_MAX;
1915
1916
if (samplers.is_empty()) {
1917
// Adding a seemigly busy slot 0 makes things easier elsewhere.
1918
samplers.push_back({});
1919
samplers.push_back({});
1920
slot = 1;
1921
} else {
1922
for (uint32_t i = 1; i < samplers.size(); i++) {
1923
if ((int)samplers[i].Filter == INT_MAX) {
1924
slot = i;
1925
break;
1926
}
1927
}
1928
if (slot == UINT32_MAX) {
1929
slot = samplers.size();
1930
samplers.push_back({});
1931
}
1932
}
1933
1934
D3D12_SAMPLER_DESC &sampler_desc = samplers[slot];
1935
1936
// D3D12 does not support anisotropic nearest filtering.
1937
bool use_anisotropy = p_state.use_anisotropy && p_state.min_filter == RDD::SAMPLER_FILTER_LINEAR && p_state.mag_filter == RDD::SAMPLER_FILTER_LINEAR;
1938
1939
// Nearest mipmap is a separate D3D12 capability.
1940
if (!sampler_capabilities.aniso_filter_with_point_mip_supported && p_state.mip_filter == RDD::SAMPLER_FILTER_NEAREST) {
1941
use_anisotropy = false;
1942
}
1943
1944
D3D12_FILTER_REDUCTION_TYPE reduction_type = p_state.enable_compare ? D3D12_FILTER_REDUCTION_TYPE_COMPARISON : D3D12_FILTER_REDUCTION_TYPE_STANDARD;
1945
1946
if (use_anisotropy) {
1947
if (p_state.mip_filter == RDD::SAMPLER_FILTER_NEAREST) {
1948
// This path is never going to be taken if the capability is unsupported.
1949
sampler_desc.Filter = D3D12_ENCODE_MIN_MAG_ANISOTROPIC_MIP_POINT_FILTER(reduction_type);
1950
} else {
1951
sampler_desc.Filter = D3D12_ENCODE_ANISOTROPIC_FILTER(reduction_type);
1952
}
1953
sampler_desc.MaxAnisotropy = p_state.anisotropy_max;
1954
} else {
1955
static const D3D12_FILTER_TYPE RD_FILTER_TYPE_TO_D3D12[] = {
1956
D3D12_FILTER_TYPE_POINT, // SAMPLER_FILTER_NEAREST.
1957
D3D12_FILTER_TYPE_LINEAR, // SAMPLER_FILTER_LINEAR.
1958
};
1959
sampler_desc.Filter = D3D12_ENCODE_BASIC_FILTER(
1960
RD_FILTER_TYPE_TO_D3D12[p_state.min_filter],
1961
RD_FILTER_TYPE_TO_D3D12[p_state.mag_filter],
1962
RD_FILTER_TYPE_TO_D3D12[p_state.mip_filter],
1963
reduction_type);
1964
}
1965
1966
sampler_desc.AddressU = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_u];
1967
sampler_desc.AddressV = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_v];
1968
sampler_desc.AddressW = RD_REPEAT_MODE_TO_D3D12_ADDRESS_MODE[p_state.repeat_w];
1969
1970
for (int i = 0; i < 4; i++) {
1971
sampler_desc.BorderColor[i] = RD_TO_D3D12_SAMPLER_BORDER_COLOR[p_state.border_color][i];
1972
}
1973
1974
sampler_desc.MinLOD = p_state.min_lod;
1975
sampler_desc.MaxLOD = p_state.max_lod;
1976
sampler_desc.MipLODBias = p_state.lod_bias;
1977
1978
sampler_desc.ComparisonFunc = p_state.enable_compare ? RD_TO_D3D12_COMPARE_OP[p_state.compare_op] : D3D12_COMPARISON_FUNC_NEVER;
1979
1980
// TODO: Emulate somehow?
1981
if (p_state.unnormalized_uvw) {
1982
WARN_PRINT("Creating a sampler with unnormalized UVW, which is not supported.");
1983
}
1984
1985
return SamplerID(slot);
1986
}
1987
1988
void RenderingDeviceDriverD3D12::sampler_free(SamplerID p_sampler) {
1989
samplers[p_sampler.id].Filter = (D3D12_FILTER)INT_MAX;
1990
}
1991
1992
bool RenderingDeviceDriverD3D12::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_filter) {
1993
D3D12_FEATURE_DATA_FORMAT_SUPPORT srv_rtv_support = {};
1994
srv_rtv_support.Format = RD_TO_D3D12_FORMAT[p_format].general_format;
1995
HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &srv_rtv_support, sizeof(srv_rtv_support));
1996
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
1997
return (srv_rtv_support.Support1 & D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE);
1998
}
1999
2000
/**********************/
2001
/**** VERTEX ARRAY ****/
2002
/**********************/
2003
2004
RDD::VertexFormatID RenderingDeviceDriverD3D12::vertex_format_create(Span<VertexAttribute> p_vertex_attribs, const VertexAttributeBindingsMap &p_vertex_bindings) {
2005
VertexFormatInfo *vf_info = VersatileResource::allocate<VertexFormatInfo>(resources_allocator);
2006
vf_info->input_elem_descs.resize(p_vertex_attribs.size());
2007
2008
uint32_t max_binding = 0;
2009
for (uint32_t i = 0; i < p_vertex_attribs.size(); i++) {
2010
D3D12_INPUT_ELEMENT_DESC &input_element_desc = vf_info->input_elem_descs[i];
2011
const VertexAttribute &vertex_attrib = p_vertex_attribs[i];
2012
const VertexAttributeBinding &vertex_binding = p_vertex_bindings[vertex_attrib.binding];
2013
2014
input_element_desc = {};
2015
input_element_desc.SemanticName = "TEXCOORD";
2016
input_element_desc.SemanticIndex = vertex_attrib.location;
2017
input_element_desc.Format = RD_TO_D3D12_FORMAT[vertex_attrib.format].general_format;
2018
input_element_desc.InputSlot = vertex_attrib.binding;
2019
input_element_desc.AlignedByteOffset = vertex_attrib.offset;
2020
if (vertex_binding.frequency == VERTEX_FREQUENCY_INSTANCE) {
2021
input_element_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA;
2022
input_element_desc.InstanceDataStepRate = 1;
2023
} else {
2024
input_element_desc.InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
2025
input_element_desc.InstanceDataStepRate = 0;
2026
}
2027
2028
max_binding = MAX(max_binding, vertex_attrib.binding + 1);
2029
}
2030
2031
vf_info->vertex_buffer_strides.resize(max_binding);
2032
for (const VertexAttributeBindingsMap::KV &vertex_binding_pair : p_vertex_bindings) {
2033
vf_info->vertex_buffer_strides[vertex_binding_pair.key] = vertex_binding_pair.value.stride;
2034
}
2035
2036
return VertexFormatID(vf_info);
2037
}
2038
2039
void RenderingDeviceDriverD3D12::vertex_format_free(VertexFormatID p_vertex_format) {
2040
VertexFormatInfo *vf_info = (VertexFormatInfo *)p_vertex_format.id;
2041
VersatileResource::free(resources_allocator, vf_info);
2042
}
2043
2044
/******************/
2045
/**** BARRIERS ****/
2046
/******************/
2047
2048
static D3D12_BARRIER_ACCESS _rd_texture_layout_access_mask(RDD::TextureLayout p_texture_layout) {
2049
switch (p_texture_layout) {
2050
case RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL:
2051
return D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
2052
case RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
2053
return D3D12_BARRIER_ACCESS_RENDER_TARGET;
2054
case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
2055
return D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ | D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE;
2056
case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
2057
return D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;
2058
case RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
2059
return D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
2060
case RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL:
2061
return D3D12_BARRIER_ACCESS_COPY_SOURCE;
2062
case RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL:
2063
return D3D12_BARRIER_ACCESS_COPY_DEST;
2064
case RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL:
2065
return D3D12_BARRIER_ACCESS_RESOLVE_SOURCE;
2066
case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL:
2067
return D3D12_BARRIER_ACCESS_RESOLVE_DEST;
2068
case RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL:
2069
return D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE;
2070
case RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL:
2071
DEV_ASSERT(false && "Fragment density maps are not supported in D3D12.");
2072
return D3D12_BARRIER_ACCESS_NO_ACCESS;
2073
default:
2074
return D3D12_BARRIER_ACCESS_NO_ACCESS;
2075
}
2076
}
2077
2078
static void _rd_access_to_d3d12_and_mask(BitField<RDD::BarrierAccessBits> p_access, RDD::TextureLayout p_texture_layout, D3D12_BARRIER_ACCESS &r_access, D3D12_BARRIER_SYNC &r_sync_mask) {
2079
r_access = D3D12_BARRIER_ACCESS_COMMON;
2080
r_sync_mask = D3D12_BARRIER_SYNC_ALL;
2081
2082
if (p_access.has_flag(RDD::BARRIER_ACCESS_INDIRECT_COMMAND_READ_BIT)) {
2083
r_access |= D3D12_BARRIER_ACCESS_INDIRECT_ARGUMENT;
2084
r_sync_mask |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT;
2085
}
2086
2087
if (p_access.has_flag(RDD::BARRIER_ACCESS_INDEX_READ_BIT)) {
2088
r_access |= D3D12_BARRIER_ACCESS_INDEX_BUFFER;
2089
r_sync_mask |= D3D12_BARRIER_SYNC_INDEX_INPUT | D3D12_BARRIER_SYNC_DRAW;
2090
}
2091
2092
if (p_access.has_flag(RDD::BARRIER_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) {
2093
r_access |= D3D12_BARRIER_ACCESS_VERTEX_BUFFER;
2094
r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING;
2095
}
2096
2097
if (p_access.has_flag(RDD::BARRIER_ACCESS_UNIFORM_READ_BIT)) {
2098
r_access |= D3D12_BARRIER_ACCESS_CONSTANT_BUFFER;
2099
r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING |
2100
D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING;
2101
}
2102
2103
if (p_access.has_flag(RDD::BARRIER_ACCESS_INPUT_ATTACHMENT_READ_BIT)) {
2104
r_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET;
2105
r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_RENDER_TARGET;
2106
}
2107
2108
if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_READ_BIT)) {
2109
r_access |= D3D12_BARRIER_ACCESS_COPY_SOURCE;
2110
r_sync_mask |= D3D12_BARRIER_SYNC_COPY;
2111
}
2112
2113
if (p_access.has_flag(RDD::BARRIER_ACCESS_COPY_WRITE_BIT)) {
2114
r_access |= D3D12_BARRIER_ACCESS_COPY_DEST;
2115
r_sync_mask |= D3D12_BARRIER_SYNC_COPY;
2116
}
2117
2118
if (p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_READ_BIT)) {
2119
r_access |= D3D12_BARRIER_ACCESS_RESOLVE_SOURCE;
2120
r_sync_mask |= D3D12_BARRIER_SYNC_RESOLVE;
2121
}
2122
2123
if (p_access.has_flag(RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT)) {
2124
r_access |= D3D12_BARRIER_ACCESS_RESOLVE_DEST;
2125
r_sync_mask |= D3D12_BARRIER_SYNC_RESOLVE;
2126
}
2127
2128
if (p_access.has_flag(RDD::BARRIER_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT)) {
2129
r_access |= D3D12_BARRIER_ACCESS_SHADING_RATE_SOURCE;
2130
r_sync_mask |= D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_ALL_SHADING;
2131
}
2132
2133
const D3D12_BARRIER_SYNC unordered_access_mask = D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING |
2134
D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING | D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW;
2135
2136
if (p_access.has_flag(RDD::BARRIER_ACCESS_STORAGE_CLEAR_BIT)) {
2137
r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
2138
r_sync_mask |= unordered_access_mask;
2139
}
2140
2141
// These access bits only have compatibility with certain layouts unlike in Vulkan where they imply specific operations in the same layout.
2142
if (p_access.has_flag(RDD::BARRIER_ACCESS_SHADER_WRITE_BIT)) {
2143
r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
2144
r_sync_mask |= unordered_access_mask;
2145
} else if (p_access.has_flag(RDD::BARRIER_ACCESS_SHADER_READ_BIT)) {
2146
if (p_texture_layout == RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL) {
2147
// Unordered access must be enforced if the texture is using the storage layout.
2148
r_access |= D3D12_BARRIER_ACCESS_UNORDERED_ACCESS;
2149
r_sync_mask |= unordered_access_mask;
2150
} else {
2151
r_access |= D3D12_BARRIER_ACCESS_SHADER_RESOURCE;
2152
r_sync_mask |= D3D12_BARRIER_SYNC_VERTEX_SHADING | D3D12_BARRIER_SYNC_PIXEL_SHADING | D3D12_BARRIER_SYNC_COMPUTE_SHADING | D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_ALL_SHADING;
2153
}
2154
}
2155
2156
if (p_access.has_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT) || p_access.has_flag(RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_READ_BIT)) {
2157
r_access |= D3D12_BARRIER_ACCESS_RENDER_TARGET;
2158
r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_RENDER_TARGET;
2159
}
2160
2161
if (p_access.has_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)) {
2162
r_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_WRITE;
2163
r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_DEPTH_STENCIL;
2164
} else if (p_access.has_flag(RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT)) {
2165
r_access |= D3D12_BARRIER_ACCESS_DEPTH_STENCIL_READ;
2166
r_sync_mask |= D3D12_BARRIER_SYNC_DRAW | D3D12_BARRIER_SYNC_DEPTH_STENCIL;
2167
}
2168
}
2169
2170
static void _rd_stages_to_d3d12(BitField<RDD::PipelineStageBits> p_stages, D3D12_BARRIER_SYNC &r_sync) {
2171
if (p_stages.has_flag(RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT)) {
2172
r_sync = D3D12_BARRIER_SYNC_ALL;
2173
} else {
2174
if (p_stages.has_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT)) {
2175
r_sync |= D3D12_BARRIER_SYNC_EXECUTE_INDIRECT;
2176
}
2177
2178
if (p_stages.has_flag(RDD::PIPELINE_STAGE_VERTEX_INPUT_BIT)) {
2179
r_sync |= D3D12_BARRIER_SYNC_INDEX_INPUT;
2180
}
2181
2182
if (p_stages.has_flag(RDD::PIPELINE_STAGE_VERTEX_SHADER_BIT)) {
2183
r_sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING;
2184
}
2185
2186
if (p_stages.has_flag(RDD::PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_GEOMETRY_SHADER_BIT)) {
2187
// There's no granularity for tessellation or geometry stages. The specification defines it as part of vertex shading.
2188
r_sync |= D3D12_BARRIER_SYNC_VERTEX_SHADING;
2189
}
2190
2191
if (p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT)) {
2192
r_sync |= D3D12_BARRIER_SYNC_PIXEL_SHADING;
2193
}
2194
2195
if (p_stages.has_flag(RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT) || p_stages.has_flag(RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT)) {
2196
// Covers both read and write operations for depth stencil.
2197
r_sync |= D3D12_BARRIER_SYNC_DEPTH_STENCIL;
2198
}
2199
2200
if (p_stages.has_flag(RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT)) {
2201
r_sync |= D3D12_BARRIER_SYNC_RENDER_TARGET;
2202
}
2203
2204
if (p_stages.has_flag(RDD::PIPELINE_STAGE_COMPUTE_SHADER_BIT)) {
2205
r_sync |= D3D12_BARRIER_SYNC_COMPUTE_SHADING;
2206
}
2207
2208
if (p_stages.has_flag(RDD::PIPELINE_STAGE_COPY_BIT)) {
2209
r_sync |= D3D12_BARRIER_SYNC_COPY;
2210
}
2211
2212
if (p_stages.has_flag(RDD::PIPELINE_STAGE_RESOLVE_BIT)) {
2213
r_sync |= D3D12_BARRIER_SYNC_RESOLVE;
2214
}
2215
2216
if (p_stages.has_flag(RDD::PIPELINE_STAGE_CLEAR_STORAGE_BIT)) {
2217
r_sync |= D3D12_BARRIER_SYNC_CLEAR_UNORDERED_ACCESS_VIEW;
2218
}
2219
2220
if (p_stages.has_flag(RDD::PIPELINE_STAGE_ALL_GRAPHICS_BIT)) {
2221
r_sync |= D3D12_BARRIER_SYNC_DRAW;
2222
}
2223
}
2224
}
2225
2226
static void _rd_stages_and_access_to_d3d12(BitField<RDD::PipelineStageBits> p_stages, RDD::TextureLayout p_texture_layout, BitField<RDD::BarrierAccessBits> p_access, D3D12_BARRIER_SYNC &r_sync, D3D12_BARRIER_ACCESS &r_access) {
2227
D3D12_BARRIER_SYNC sync_mask;
2228
r_sync = D3D12_BARRIER_SYNC_NONE;
2229
2230
if (p_texture_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) {
2231
// Undefined texture layouts are a special case where no access bits or synchronization scopes are allowed.
2232
r_access = D3D12_BARRIER_ACCESS_NO_ACCESS;
2233
return;
2234
}
2235
2236
// Convert access bits to the D3D12 barrier access bits.
2237
_rd_access_to_d3d12_and_mask(p_access, p_texture_layout, r_access, sync_mask);
2238
2239
if (p_texture_layout != RDD::TEXTURE_LAYOUT_MAX) {
2240
// Only allow the access bits compatible with the texture layout.
2241
r_access &= _rd_texture_layout_access_mask(p_texture_layout);
2242
}
2243
2244
// Convert stage bits to the D3D12 synchronization scope bits.
2245
_rd_stages_to_d3d12(p_stages, r_sync);
2246
2247
// Only enable synchronization stages compatible with the access bits that were used.
2248
r_sync &= sync_mask;
2249
2250
if (r_sync == D3D12_BARRIER_SYNC_NONE) {
2251
if (p_access.is_empty()) {
2252
// No valid synchronization scope was defined and no access in particular is required.
2253
r_access = D3D12_BARRIER_ACCESS_NO_ACCESS;
2254
} else {
2255
// Access is required but the synchronization scope wasn't compatible. We fall back to the global synchronization scope and access.
2256
r_sync = D3D12_BARRIER_SYNC_ALL;
2257
r_access = D3D12_BARRIER_ACCESS_COMMON;
2258
}
2259
}
2260
}
2261
2262
static D3D12_BARRIER_LAYOUT _rd_texture_layout_to_d3d12_barrier_layout(RDD::TextureLayout p_texture_layout) {
2263
switch (p_texture_layout) {
2264
case RDD::TEXTURE_LAYOUT_UNDEFINED:
2265
return D3D12_BARRIER_LAYOUT_UNDEFINED;
2266
case RDD::TEXTURE_LAYOUT_GENERAL:
2267
return D3D12_BARRIER_LAYOUT_COMMON;
2268
case RDD::TEXTURE_LAYOUT_STORAGE_OPTIMAL:
2269
return D3D12_BARRIER_LAYOUT_UNORDERED_ACCESS;
2270
case RDD::TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
2271
return D3D12_BARRIER_LAYOUT_RENDER_TARGET;
2272
case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
2273
return D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_WRITE;
2274
case RDD::TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
2275
return D3D12_BARRIER_LAYOUT_DEPTH_STENCIL_READ;
2276
case RDD::TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
2277
return D3D12_BARRIER_LAYOUT_SHADER_RESOURCE;
2278
case RDD::TEXTURE_LAYOUT_COPY_SRC_OPTIMAL:
2279
return D3D12_BARRIER_LAYOUT_COPY_SOURCE;
2280
case RDD::TEXTURE_LAYOUT_COPY_DST_OPTIMAL:
2281
return D3D12_BARRIER_LAYOUT_COPY_DEST;
2282
case RDD::TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL:
2283
return D3D12_BARRIER_LAYOUT_RESOLVE_SOURCE;
2284
case RDD::TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL:
2285
return D3D12_BARRIER_LAYOUT_RESOLVE_DEST;
2286
case RDD::TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL:
2287
return D3D12_BARRIER_LAYOUT_SHADING_RATE_SOURCE;
2288
case RDD::TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL:
2289
DEV_ASSERT(false && "Fragment density maps are not supported in D3D12.");
2290
return D3D12_BARRIER_LAYOUT_UNDEFINED;
2291
default:
2292
DEV_ASSERT(false && "Unknown texture layout.");
2293
return D3D12_BARRIER_LAYOUT_UNDEFINED;
2294
}
2295
}
2296
2297
void RenderingDeviceDriverD3D12::command_pipeline_barrier(CommandBufferID p_cmd_buffer,
2298
BitField<PipelineStageBits> p_src_stages,
2299
BitField<PipelineStageBits> p_dst_stages,
2300
VectorView<RDD::MemoryAccessBarrier> p_memory_barriers,
2301
VectorView<RDD::BufferBarrier> p_buffer_barriers,
2302
VectorView<RDD::TextureBarrier> p_texture_barriers,
2303
VectorView<AccelerationStructureBarrier> p_acceleration_structure_barriers) {
2304
if (!barrier_capabilities.enhanced_barriers_supported) {
2305
// Enhanced barriers are a requirement for this function.
2306
return;
2307
}
2308
2309
if (p_memory_barriers.size() == 0 && p_buffer_barriers.size() == 0 && p_texture_barriers.size() == 0) {
2310
// At least one barrier must be present in the arguments.
2311
return;
2312
}
2313
2314
// Convert the RDD barriers to D3D12 enhanced barriers.
2315
thread_local LocalVector<D3D12_GLOBAL_BARRIER> global_barriers;
2316
thread_local LocalVector<D3D12_BUFFER_BARRIER> buffer_barriers;
2317
thread_local LocalVector<D3D12_TEXTURE_BARRIER> texture_barriers;
2318
global_barriers.clear();
2319
buffer_barriers.clear();
2320
texture_barriers.clear();
2321
2322
D3D12_GLOBAL_BARRIER global_barrier = {};
2323
for (uint32_t i = 0; i < p_memory_barriers.size(); i++) {
2324
const MemoryAccessBarrier &memory_barrier = p_memory_barriers[i];
2325
_rd_stages_and_access_to_d3d12(p_src_stages, RDD::TEXTURE_LAYOUT_MAX, memory_barrier.src_access, global_barrier.SyncBefore, global_barrier.AccessBefore);
2326
_rd_stages_and_access_to_d3d12(p_dst_stages, RDD::TEXTURE_LAYOUT_MAX, memory_barrier.dst_access, global_barrier.SyncAfter, global_barrier.AccessAfter);
2327
global_barriers.push_back(global_barrier);
2328
}
2329
2330
D3D12_BUFFER_BARRIER buffer_barrier_d3d12 = {};
2331
buffer_barrier_d3d12.Offset = 0;
2332
buffer_barrier_d3d12.Size = UINT64_MAX; // The specification says this must be the size of the buffer barrier.
2333
for (uint32_t i = 0; i < p_buffer_barriers.size(); i++) {
2334
const BufferBarrier &buffer_barrier_rd = p_buffer_barriers[i];
2335
const BufferInfo *buffer_info = (const BufferInfo *)(buffer_barrier_rd.buffer.id);
2336
_rd_stages_and_access_to_d3d12(p_src_stages, RDD::TEXTURE_LAYOUT_MAX, buffer_barrier_rd.src_access, buffer_barrier_d3d12.SyncBefore, buffer_barrier_d3d12.AccessBefore);
2337
_rd_stages_and_access_to_d3d12(p_dst_stages, RDD::TEXTURE_LAYOUT_MAX, buffer_barrier_rd.dst_access, buffer_barrier_d3d12.SyncAfter, buffer_barrier_d3d12.AccessAfter);
2338
buffer_barrier_d3d12.pResource = buffer_info->resource;
2339
buffer_barriers.push_back(buffer_barrier_d3d12);
2340
}
2341
2342
D3D12_TEXTURE_BARRIER texture_barrier_d3d12 = {};
2343
for (uint32_t i = 0; i < p_texture_barriers.size(); i++) {
2344
const TextureBarrier &texture_barrier_rd = p_texture_barriers[i];
2345
const TextureInfo *texture_info = (const TextureInfo *)(texture_barrier_rd.texture.id);
2346
if (texture_info->main_texture) {
2347
texture_info = texture_info->main_texture;
2348
}
2349
// Textures created for simultaneous access do not need explicit transitions.
2350
if (texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS) {
2351
continue;
2352
}
2353
_rd_stages_and_access_to_d3d12(p_src_stages, texture_barrier_rd.prev_layout, texture_barrier_rd.src_access, texture_barrier_d3d12.SyncBefore, texture_barrier_d3d12.AccessBefore);
2354
_rd_stages_and_access_to_d3d12(p_dst_stages, texture_barrier_rd.next_layout, texture_barrier_rd.dst_access, texture_barrier_d3d12.SyncAfter, texture_barrier_d3d12.AccessAfter);
2355
texture_barrier_d3d12.LayoutBefore = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.prev_layout);
2356
texture_barrier_d3d12.LayoutAfter = _rd_texture_layout_to_d3d12_barrier_layout(texture_barrier_rd.next_layout);
2357
texture_barrier_d3d12.pResource = texture_info->resource;
2358
if (texture_barrier_rd.subresources.mipmap_count == texture_info->mipmaps && texture_barrier_rd.subresources.layer_count == texture_info->layers) {
2359
// So, all resources. Then, let's be explicit about it so D3D12 doesn't think
2360
// we are dealing with a subset of subresources.
2361
texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = 0xffffffff;
2362
texture_barrier_d3d12.Subresources.NumMipLevels = 0;
2363
// Because NumMipLevels == 0, all the other fields are ignored by D3D12.
2364
} else {
2365
texture_barrier_d3d12.Subresources.IndexOrFirstMipLevel = texture_barrier_rd.subresources.base_mipmap;
2366
texture_barrier_d3d12.Subresources.NumMipLevels = texture_barrier_rd.subresources.mipmap_count;
2367
texture_barrier_d3d12.Subresources.FirstArraySlice = texture_barrier_rd.subresources.base_layer;
2368
texture_barrier_d3d12.Subresources.NumArraySlices = texture_barrier_rd.subresources.layer_count;
2369
texture_barrier_d3d12.Subresources.FirstPlane = _compute_plane_slice(texture_info->format, texture_barrier_rd.subresources.aspect);
2370
texture_barrier_d3d12.Subresources.NumPlanes = format_get_plane_count(texture_info->format);
2371
}
2372
texture_barrier_d3d12.Flags = (texture_barrier_rd.prev_layout == RDD::TEXTURE_LAYOUT_UNDEFINED) ? D3D12_TEXTURE_BARRIER_FLAG_DISCARD : D3D12_TEXTURE_BARRIER_FLAG_NONE;
2373
texture_barriers.push_back(texture_barrier_d3d12);
2374
}
2375
2376
// Define the barrier groups and execute.
2377
2378
D3D12_BARRIER_GROUP barrier_groups[3] = {};
2379
uint32_t barrier_groups_count = 0;
2380
2381
if (!global_barriers.is_empty()) {
2382
D3D12_BARRIER_GROUP &barrier_group = barrier_groups[barrier_groups_count++];
2383
barrier_group.Type = D3D12_BARRIER_TYPE_GLOBAL;
2384
barrier_group.NumBarriers = global_barriers.size();
2385
barrier_group.pGlobalBarriers = global_barriers.ptr();
2386
}
2387
2388
if (!buffer_barriers.is_empty()) {
2389
D3D12_BARRIER_GROUP &barrier_group = barrier_groups[barrier_groups_count++];
2390
barrier_group.Type = D3D12_BARRIER_TYPE_BUFFER;
2391
barrier_group.NumBarriers = buffer_barriers.size();
2392
barrier_group.pBufferBarriers = buffer_barriers.ptr();
2393
}
2394
2395
if (!texture_barriers.is_empty()) {
2396
D3D12_BARRIER_GROUP &barrier_group = barrier_groups[barrier_groups_count++];
2397
barrier_group.Type = D3D12_BARRIER_TYPE_TEXTURE;
2398
barrier_group.NumBarriers = texture_barriers.size();
2399
barrier_group.pTextureBarriers = texture_barriers.ptr();
2400
}
2401
2402
if (barrier_groups_count) {
2403
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffer.id);
2404
cmd_buf_info->cmd_list_7->Barrier(barrier_groups_count, barrier_groups);
2405
}
2406
}
2407
2408
/****************/
2409
/**** FENCES ****/
2410
/****************/
2411
2412
RDD::FenceID RenderingDeviceDriverD3D12::fence_create() {
2413
ComPtr<ID3D12Fence> d3d_fence;
2414
HRESULT res = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(d3d_fence.GetAddressOf()));
2415
ERR_FAIL_COND_V(!SUCCEEDED(res), FenceID());
2416
2417
HANDLE event_handle = CreateEvent(nullptr, FALSE, FALSE, nullptr);
2418
ERR_FAIL_NULL_V(event_handle, FenceID());
2419
2420
FenceInfo *fence = memnew(FenceInfo);
2421
fence->d3d_fence = d3d_fence;
2422
fence->event_handle = event_handle;
2423
return FenceID(fence);
2424
}
2425
2426
Error RenderingDeviceDriverD3D12::fence_wait(FenceID p_fence) {
2427
FenceInfo *fence = (FenceInfo *)(p_fence.id);
2428
fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle);
2429
DWORD res = WaitForSingleObjectEx(fence->event_handle, INFINITE, FALSE);
2430
#ifdef PIX_ENABLED
2431
PIXNotifyWakeFromFenceSignal(fence->event_handle);
2432
#endif
2433
2434
return (res == WAIT_FAILED) ? FAILED : OK;
2435
}
2436
2437
void RenderingDeviceDriverD3D12::fence_free(FenceID p_fence) {
2438
FenceInfo *fence = (FenceInfo *)(p_fence.id);
2439
CloseHandle(fence->event_handle);
2440
memdelete(fence);
2441
}
2442
2443
/********************/
2444
/**** SEMAPHORES ****/
2445
/********************/
2446
2447
RDD::SemaphoreID RenderingDeviceDriverD3D12::semaphore_create() {
2448
ComPtr<ID3D12Fence> d3d_fence;
2449
HRESULT res = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(d3d_fence.GetAddressOf()));
2450
ERR_FAIL_COND_V(!SUCCEEDED(res), SemaphoreID());
2451
2452
SemaphoreInfo *semaphore = memnew(SemaphoreInfo);
2453
semaphore->d3d_fence = d3d_fence;
2454
return SemaphoreID(semaphore);
2455
}
2456
2457
void RenderingDeviceDriverD3D12::semaphore_free(SemaphoreID p_semaphore) {
2458
SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_semaphore.id);
2459
memdelete(semaphore);
2460
}
2461
2462
/******************/
2463
/**** COMMANDS ****/
2464
/******************/
2465
2466
// ----- QUEUE FAMILY -----
2467
2468
RDD::CommandQueueFamilyID RenderingDeviceDriverD3D12::command_queue_family_get(BitField<CommandQueueFamilyBits> p_cmd_queue_family_bits, RenderingContextDriver::SurfaceID p_surface) {
2469
// Return the command list type encoded plus one so zero is an invalid value.
2470
// The only ones that support presenting to a surface are direct queues.
2471
if (p_cmd_queue_family_bits.has_flag(COMMAND_QUEUE_FAMILY_GRAPHICS_BIT) || (p_surface != 0)) {
2472
return CommandQueueFamilyID(D3D12_COMMAND_LIST_TYPE_DIRECT + 1);
2473
} else if (p_cmd_queue_family_bits.has_flag(COMMAND_QUEUE_FAMILY_COMPUTE_BIT)) {
2474
return CommandQueueFamilyID(D3D12_COMMAND_LIST_TYPE_COMPUTE + 1);
2475
} else if (p_cmd_queue_family_bits.has_flag(COMMAND_QUEUE_FAMILY_TRANSFER_BIT)) {
2476
return CommandQueueFamilyID(D3D12_COMMAND_LIST_TYPE_COPY + 1);
2477
} else {
2478
return CommandQueueFamilyID();
2479
}
2480
}
2481
2482
// ----- QUEUE -----
2483
2484
RDD::CommandQueueID RenderingDeviceDriverD3D12::command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue) {
2485
ComPtr<ID3D12CommandQueue> d3d_queue;
2486
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
2487
queue_desc.Type = (D3D12_COMMAND_LIST_TYPE)(p_cmd_queue_family.id - 1);
2488
HRESULT res = device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(d3d_queue.GetAddressOf()));
2489
ERR_FAIL_COND_V(!SUCCEEDED(res), CommandQueueID());
2490
2491
if (p_identify_as_main_queue && D3D12Hooks::get_singleton() != nullptr) {
2492
D3D12Hooks::get_singleton()->set_command_queue(d3d_queue.Get());
2493
}
2494
2495
CommandQueueInfo *command_queue = memnew(CommandQueueInfo);
2496
command_queue->d3d_queue = d3d_queue;
2497
return CommandQueueID(command_queue);
2498
}
2499
2500
Error RenderingDeviceDriverD3D12::command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) {
2501
CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id);
2502
for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) {
2503
const SemaphoreInfo *semaphore = (const SemaphoreInfo *)(p_wait_semaphores[i].id);
2504
command_queue->d3d_queue->Wait(semaphore->d3d_fence.Get(), semaphore->fence_value);
2505
}
2506
2507
if (p_cmd_buffers.size() > 0) {
2508
thread_local LocalVector<ID3D12CommandList *> command_lists;
2509
command_lists.resize(p_cmd_buffers.size());
2510
for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) {
2511
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffers[i].id);
2512
command_lists[i] = cmd_buf_info->cmd_list.Get();
2513
}
2514
2515
command_queue->d3d_queue->ExecuteCommandLists(command_lists.size(), command_lists.ptr());
2516
2517
for (uint32_t i = 0; i < p_cmd_semaphores.size(); i++) {
2518
SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_cmd_semaphores[i].id);
2519
semaphore->fence_value++;
2520
command_queue->d3d_queue->Signal(semaphore->d3d_fence.Get(), semaphore->fence_value);
2521
}
2522
2523
if (p_cmd_fence) {
2524
FenceInfo *fence = (FenceInfo *)(p_cmd_fence.id);
2525
fence->fence_value++;
2526
command_queue->d3d_queue->Signal(fence->d3d_fence.Get(), fence->fence_value);
2527
}
2528
}
2529
2530
HRESULT res;
2531
bool any_present_failed = false;
2532
for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
2533
SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);
2534
res = swap_chain->d3d_swap_chain->Present(swap_chain->sync_interval, swap_chain->present_flags);
2535
if (!SUCCEEDED(res)) {
2536
print_verbose(vformat("D3D12: Presenting swapchain failed with error 0x%08ux.", (uint64_t)res));
2537
any_present_failed = true;
2538
}
2539
}
2540
2541
return any_present_failed ? FAILED : OK;
2542
}
2543
2544
void RenderingDeviceDriverD3D12::command_queue_free(CommandQueueID p_cmd_queue) {
2545
CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id);
2546
memdelete(command_queue);
2547
}
2548
2549
// ----- POOL -----
2550
2551
RDD::CommandPoolID RenderingDeviceDriverD3D12::command_pool_create(CommandQueueFamilyID p_cmd_queue_family, CommandBufferType p_cmd_buffer_type) {
2552
CommandPoolInfo *command_pool = memnew(CommandPoolInfo);
2553
command_pool->queue_family = p_cmd_queue_family;
2554
command_pool->buffer_type = p_cmd_buffer_type;
2555
return CommandPoolID(command_pool);
2556
}
2557
2558
bool RenderingDeviceDriverD3D12::command_pool_reset(CommandPoolID p_cmd_pool) {
2559
return true;
2560
}
2561
2562
void RenderingDeviceDriverD3D12::command_pool_free(CommandPoolID p_cmd_pool) {
2563
CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id);
2564
2565
// Destroy all command buffers associated with this command pool, mirroring Vulkan's behavior.
2566
SelfList<CommandBufferInfo> *cmd_buf_elem = command_pool->command_buffers.first();
2567
while (cmd_buf_elem != nullptr) {
2568
CommandBufferInfo *cmd_buf_info = cmd_buf_elem->self();
2569
cmd_buf_elem = cmd_buf_elem->next();
2570
2571
cmd_buf_info->cmd_list.Reset();
2572
cmd_buf_info->cmd_list_1.Reset();
2573
cmd_buf_info->cmd_list_5.Reset();
2574
cmd_buf_info->cmd_list_7.Reset();
2575
cmd_buf_info->cmd_allocator.Reset();
2576
2577
resource_descriptor_heap_pool.free(cmd_buf_info->uav_alloc);
2578
rtv_descriptor_heap_pool.free(cmd_buf_info->rtv_alloc);
2579
dsv_descriptor_heap_pool.free(cmd_buf_info->dsv_alloc);
2580
2581
VersatileResource::free(resources_allocator, cmd_buf_info);
2582
}
2583
2584
memdelete(command_pool);
2585
}
2586
2587
// ----- BUFFER -----
2588
2589
RDD::CommandBufferID RenderingDeviceDriverD3D12::command_buffer_create(CommandPoolID p_cmd_pool) {
2590
DEV_ASSERT(p_cmd_pool);
2591
2592
CommandPoolInfo *command_pool = (CommandPoolInfo *)(p_cmd_pool.id);
2593
D3D12_COMMAND_LIST_TYPE list_type;
2594
if (command_pool->buffer_type == COMMAND_BUFFER_TYPE_SECONDARY) {
2595
list_type = D3D12_COMMAND_LIST_TYPE_BUNDLE;
2596
} else {
2597
list_type = D3D12_COMMAND_LIST_TYPE(command_pool->queue_family.id - 1);
2598
}
2599
2600
ComPtr<ID3D12CommandAllocator> cmd_allocator;
2601
{
2602
HRESULT res = device->CreateCommandAllocator(list_type, IID_PPV_ARGS(cmd_allocator.GetAddressOf()));
2603
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), CommandBufferID(), "CreateCommandAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
2604
}
2605
2606
ComPtr<ID3D12GraphicsCommandList> cmd_list;
2607
{
2608
ComPtr<ID3D12Device4> device_4;
2609
device->QueryInterface(device_4.GetAddressOf());
2610
HRESULT res = E_FAIL;
2611
if (device_4) {
2612
res = device_4->CreateCommandList1(0, list_type, D3D12_COMMAND_LIST_FLAG_NONE, IID_PPV_ARGS(cmd_list.GetAddressOf()));
2613
} else {
2614
res = device->CreateCommandList(0, list_type, cmd_allocator.Get(), nullptr, IID_PPV_ARGS(cmd_list.GetAddressOf()));
2615
}
2616
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), CommandBufferID(), "CreateCommandList failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
2617
if (!device_4) {
2618
cmd_list->Close();
2619
}
2620
}
2621
2622
CPUDescriptorHeapPool::Allocation uav_alloc;
2623
CPUDescriptorHeapPool::Allocation rtv_alloc;
2624
CPUDescriptorHeapPool::Allocation dsv_alloc;
2625
2626
if (list_type != D3D12_COMMAND_LIST_TYPE_COPY) {
2627
Error err = resource_descriptor_heap_pool.allocate(1, device.Get(), uav_alloc);
2628
ERR_FAIL_COND_V(err != OK, CommandBufferID());
2629
2630
err = rtv_descriptor_heap_pool.allocate(1, device.Get(), rtv_alloc);
2631
if (unlikely(err != OK)) {
2632
resource_descriptor_heap_pool.free(uav_alloc);
2633
ERR_FAIL_V(CommandBufferID());
2634
}
2635
2636
err = dsv_descriptor_heap_pool.allocate(1, device.Get(), dsv_alloc);
2637
if (unlikely(err != OK)) {
2638
resource_descriptor_heap_pool.free(uav_alloc);
2639
rtv_descriptor_heap_pool.free(rtv_alloc);
2640
ERR_FAIL_V(CommandBufferID());
2641
}
2642
}
2643
2644
// Bookkeep
2645
2646
CommandBufferInfo *cmd_buf_info = VersatileResource::allocate<CommandBufferInfo>(resources_allocator);
2647
cmd_buf_info->cmd_allocator = cmd_allocator;
2648
cmd_buf_info->cmd_list = cmd_list;
2649
2650
cmd_list->QueryInterface(cmd_buf_info->cmd_list_1.GetAddressOf());
2651
cmd_list->QueryInterface(cmd_buf_info->cmd_list_5.GetAddressOf());
2652
cmd_list->QueryInterface(cmd_buf_info->cmd_list_7.GetAddressOf());
2653
2654
cmd_buf_info->uav_alloc = uav_alloc;
2655
cmd_buf_info->rtv_alloc = rtv_alloc;
2656
cmd_buf_info->dsv_alloc = dsv_alloc;
2657
2658
// Add this command buffer to the command pool's list of command buffers.
2659
command_pool->command_buffers.add(&cmd_buf_info->command_buffer_info_elem);
2660
2661
return CommandBufferID(cmd_buf_info);
2662
}
2663
2664
bool RenderingDeviceDriverD3D12::command_buffer_begin(CommandBufferID p_cmd_buffer) {
2665
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
2666
HRESULT res = cmd_buf_info->cmd_allocator->Reset();
2667
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
2668
res = cmd_buf_info->cmd_list->Reset(cmd_buf_info->cmd_allocator.Get(), nullptr);
2669
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
2670
return true;
2671
}
2672
2673
bool RenderingDeviceDriverD3D12::command_buffer_begin_secondary(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, uint32_t p_subpass, FramebufferID p_framebuffer) {
2674
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
2675
HRESULT res = cmd_buf_info->cmd_allocator->Reset();
2676
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
2677
res = cmd_buf_info->cmd_list->Reset(cmd_buf_info->cmd_allocator.Get(), nullptr);
2678
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), false, "Reset failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
2679
return true;
2680
}
2681
2682
void RenderingDeviceDriverD3D12::command_buffer_end(CommandBufferID p_cmd_buffer) {
2683
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
2684
HRESULT res = cmd_buf_info->cmd_list->Close();
2685
2686
ERR_FAIL_COND_MSG(!SUCCEEDED(res), "Close failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
2687
cmd_buf_info->graphics_pso = nullptr;
2688
cmd_buf_info->graphics_root_signature_crc = 0;
2689
cmd_buf_info->compute_pso = nullptr;
2690
cmd_buf_info->compute_root_signature_crc = 0;
2691
cmd_buf_info->pending_dyn_params = true;
2692
cmd_buf_info->descriptor_heaps_set = false;
2693
}
2694
2695
void RenderingDeviceDriverD3D12::command_buffer_execute_secondary(CommandBufferID p_cmd_buffer, VectorView<CommandBufferID> p_secondary_cmd_buffers) {
2696
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
2697
for (uint32_t i = 0; i < p_secondary_cmd_buffers.size(); i++) {
2698
const CommandBufferInfo *secondary_cb_info = (const CommandBufferInfo *)p_secondary_cmd_buffers[i].id;
2699
cmd_buf_info->cmd_list->ExecuteBundle(secondary_cb_info->cmd_list.Get());
2700
}
2701
}
2702
2703
/********************/
2704
/**** SWAP CHAIN ****/
2705
/********************/
2706
2707
void RenderingDeviceDriverD3D12::_swap_chain_release(SwapChain *p_swap_chain) {
2708
_swap_chain_release_buffers(p_swap_chain);
2709
2710
p_swap_chain->d3d_swap_chain.Reset();
2711
}
2712
2713
void RenderingDeviceDriverD3D12::_swap_chain_release_buffers(SwapChain *p_swap_chain) {
2714
for (ID3D12Resource *render_target : p_swap_chain->render_targets) {
2715
render_target->Release();
2716
}
2717
2718
p_swap_chain->render_targets.clear();
2719
p_swap_chain->render_targets_info.clear();
2720
2721
for (RDD::FramebufferID framebuffer : p_swap_chain->framebuffers) {
2722
framebuffer_free(framebuffer);
2723
}
2724
2725
p_swap_chain->framebuffers.clear();
2726
}
2727
2728
RDD::SwapChainID RenderingDeviceDriverD3D12::swap_chain_create(RenderingContextDriver::SurfaceID p_surface) {
2729
// Create the render pass that will be used to draw to the swap chain's framebuffers.
2730
RDD::Attachment attachment;
2731
attachment.format = DATA_FORMAT_R8G8B8A8_UNORM;
2732
attachment.samples = RDD::TEXTURE_SAMPLES_1;
2733
attachment.load_op = RDD::ATTACHMENT_LOAD_OP_CLEAR;
2734
attachment.store_op = RDD::ATTACHMENT_STORE_OP_STORE;
2735
2736
RDD::Subpass subpass;
2737
RDD::AttachmentReference color_ref;
2738
color_ref.attachment = 0;
2739
color_ref.aspect.set_flag(RDD::TEXTURE_ASPECT_COLOR_BIT);
2740
subpass.color_references.push_back(color_ref);
2741
2742
RenderPassID render_pass = render_pass_create(attachment, subpass, {}, 1, AttachmentReference());
2743
ERR_FAIL_COND_V(!render_pass, SwapChainID());
2744
2745
// Create the empty swap chain until it is resized.
2746
SwapChain *swap_chain = memnew(SwapChain);
2747
swap_chain->surface = p_surface;
2748
swap_chain->data_format = attachment.format;
2749
swap_chain->render_pass = render_pass;
2750
return SwapChainID(swap_chain);
2751
}
2752
2753
Error RenderingDeviceDriverD3D12::swap_chain_resize(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, uint32_t p_desired_framebuffer_count) {
2754
DEV_ASSERT(p_cmd_queue.id != 0);
2755
DEV_ASSERT(p_swap_chain.id != 0);
2756
2757
CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id);
2758
SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);
2759
RenderingContextDriverD3D12::Surface *surface = (RenderingContextDriverD3D12::Surface *)(swap_chain->surface);
2760
if (surface->width == 0 || surface->height == 0) {
2761
// Very likely the window is minimized, don't create a swap chain.
2762
return ERR_SKIP;
2763
}
2764
2765
HRESULT res;
2766
const bool is_tearing_supported = context_driver->get_tearing_supported();
2767
UINT sync_interval = 0;
2768
UINT present_flags = 0;
2769
UINT creation_flags = 0;
2770
switch (surface->vsync_mode) {
2771
case DisplayServer::VSYNC_MAILBOX: {
2772
sync_interval = 1;
2773
present_flags = DXGI_PRESENT_RESTART;
2774
} break;
2775
case DisplayServer::VSYNC_ENABLED: {
2776
sync_interval = 1;
2777
present_flags = 0;
2778
} break;
2779
case DisplayServer::VSYNC_DISABLED: {
2780
sync_interval = 0;
2781
present_flags = is_tearing_supported ? DXGI_PRESENT_ALLOW_TEARING : 0;
2782
creation_flags = is_tearing_supported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
2783
} break;
2784
case DisplayServer::VSYNC_ADAPTIVE: // Unsupported.
2785
default:
2786
sync_interval = 1;
2787
present_flags = 0;
2788
break;
2789
}
2790
2791
if (swap_chain->d3d_swap_chain != nullptr && creation_flags != swap_chain->creation_flags) {
2792
// The swap chain must be recreated if the creation flags are different.
2793
_swap_chain_release(swap_chain);
2794
}
2795
2796
#ifdef DCOMP_ENABLED
2797
bool create_for_composition = OS::get_singleton()->is_layered_allowed();
2798
#else
2799
if (OS::get_singleton()->is_layered_allowed()) {
2800
WARN_PRINT_ONCE("Window transparency is not supported without DirectComposition on D3D12.");
2801
}
2802
bool create_for_composition = false;
2803
#endif
2804
2805
DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {};
2806
if (swap_chain->d3d_swap_chain != nullptr) {
2807
_swap_chain_release_buffers(swap_chain);
2808
res = swap_chain->d3d_swap_chain->ResizeBuffers(p_desired_framebuffer_count, surface->width, surface->height, DXGI_FORMAT_UNKNOWN, creation_flags);
2809
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_UNAVAILABLE);
2810
} else {
2811
swap_chain_desc.BufferCount = p_desired_framebuffer_count;
2812
swap_chain_desc.Format = RD_TO_D3D12_FORMAT[swap_chain->data_format].general_format;
2813
swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
2814
swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
2815
swap_chain_desc.SampleDesc.Count = 1;
2816
swap_chain_desc.Flags = creation_flags;
2817
swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;
2818
if (create_for_composition) {
2819
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
2820
has_comp_alpha[(uint64_t)p_cmd_queue.id] = true;
2821
} else {
2822
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
2823
has_comp_alpha[(uint64_t)p_cmd_queue.id] = false;
2824
}
2825
swap_chain_desc.Width = surface->width;
2826
swap_chain_desc.Height = surface->height;
2827
2828
ComPtr<IDXGISwapChain1> swap_chain_1;
2829
if (create_for_composition) {
2830
res = context_driver->dxgi_factory_get()->CreateSwapChainForComposition(command_queue->d3d_queue.Get(), &swap_chain_desc, nullptr, swap_chain_1.GetAddressOf());
2831
if (!SUCCEEDED(res)) {
2832
WARN_PRINT_ONCE("Window transparency is not supported without DirectComposition on D3D12.");
2833
swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;
2834
has_comp_alpha[(uint64_t)p_cmd_queue.id] = false;
2835
create_for_composition = false;
2836
2837
res = context_driver->dxgi_factory_get()->CreateSwapChainForHwnd(command_queue->d3d_queue.Get(), surface->hwnd, &swap_chain_desc, nullptr, nullptr, swap_chain_1.GetAddressOf());
2838
}
2839
} else {
2840
res = context_driver->dxgi_factory_get()->CreateSwapChainForHwnd(command_queue->d3d_queue.Get(), surface->hwnd, &swap_chain_desc, nullptr, nullptr, swap_chain_1.GetAddressOf());
2841
}
2842
2843
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2844
2845
swap_chain_1.As(&swap_chain->d3d_swap_chain);
2846
ERR_FAIL_NULL_V(swap_chain->d3d_swap_chain, ERR_CANT_CREATE);
2847
2848
res = context_driver->dxgi_factory_get()->MakeWindowAssociation(surface->hwnd, DXGI_MWA_NO_ALT_ENTER | DXGI_MWA_NO_WINDOW_CHANGES);
2849
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2850
}
2851
2852
#ifdef DCOMP_ENABLED
2853
if (create_for_composition) {
2854
if (surface->composition_device.Get() == nullptr) {
2855
using PFN_DCompositionCreateDevice = HRESULT(WINAPI *)(IDXGIDevice *, REFIID, void **);
2856
PFN_DCompositionCreateDevice pfn_DCompositionCreateDevice = (PFN_DCompositionCreateDevice)(void *)GetProcAddress(context_driver->lib_dcomp, "DCompositionCreateDevice");
2857
ERR_FAIL_NULL_V(pfn_DCompositionCreateDevice, ERR_CANT_CREATE);
2858
2859
res = pfn_DCompositionCreateDevice(nullptr, IID_PPV_ARGS(surface->composition_device.GetAddressOf()));
2860
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2861
2862
res = surface->composition_device->CreateTargetForHwnd(surface->hwnd, TRUE, surface->composition_target.GetAddressOf());
2863
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2864
2865
res = surface->composition_device->CreateVisual(surface->composition_visual.GetAddressOf());
2866
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2867
2868
res = surface->composition_visual->SetContent(swap_chain->d3d_swap_chain.Get());
2869
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2870
2871
res = surface->composition_target->SetRoot(surface->composition_visual.Get());
2872
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2873
2874
res = surface->composition_device->Commit();
2875
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2876
} else {
2877
res = surface->composition_visual->SetContent(swap_chain->d3d_swap_chain.Get());
2878
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2879
2880
res = surface->composition_device->Commit();
2881
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2882
}
2883
}
2884
#endif
2885
2886
res = swap_chain->d3d_swap_chain->GetDesc1(&swap_chain_desc);
2887
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2888
ERR_FAIL_COND_V(swap_chain_desc.BufferCount == 0, ERR_CANT_CREATE);
2889
2890
surface->width = swap_chain_desc.Width;
2891
surface->height = swap_chain_desc.Height;
2892
2893
swap_chain->creation_flags = creation_flags;
2894
swap_chain->sync_interval = sync_interval;
2895
swap_chain->present_flags = present_flags;
2896
2897
// Retrieve the render targets associated to the swap chain and recreate the framebuffers. The following code
2898
// relies on the address of the elements remaining static when new elements are inserted, so the container must
2899
// follow this restriction when reserving the right amount of elements beforehand.
2900
swap_chain->render_targets.reserve(swap_chain_desc.BufferCount);
2901
swap_chain->render_targets_info.reserve(swap_chain_desc.BufferCount);
2902
swap_chain->framebuffers.reserve(swap_chain_desc.BufferCount);
2903
2904
for (uint32_t i = 0; i < swap_chain_desc.BufferCount; i++) {
2905
// Retrieve the resource corresponding to the swap chain's buffer.
2906
ID3D12Resource *render_target = nullptr;
2907
res = swap_chain->d3d_swap_chain->GetBuffer(i, IID_PPV_ARGS(&render_target));
2908
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
2909
swap_chain->render_targets.push_back(render_target);
2910
2911
// Create texture information for the framebuffer to reference the resource. Since the states pointer must
2912
// reference an address of the element itself, we must insert it first and then modify it.
2913
swap_chain->render_targets_info.push_back(TextureInfo());
2914
TextureInfo &texture_info = swap_chain->render_targets_info[i];
2915
texture_info.owner_info.states.subresource_states.push_back(D3D12_RESOURCE_STATE_PRESENT);
2916
texture_info.states_ptr = &texture_info.owner_info.states;
2917
texture_info.format = swap_chain->data_format;
2918
#if defined(_MSC_VER) || !defined(_WIN32)
2919
texture_info.desc = CD3DX12_RESOURCE_DESC(render_target->GetDesc());
2920
#else
2921
render_target->GetDesc(&texture_info.desc);
2922
#endif
2923
texture_info.layers = 1;
2924
texture_info.mipmaps = 1;
2925
texture_info.resource = render_target;
2926
texture_info.view_descs.srv.Format = texture_info.desc.Format;
2927
texture_info.view_descs.srv.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
2928
2929
// Create the framebuffer for this buffer.
2930
FramebufferID framebuffer = _framebuffer_create(swap_chain->render_pass, TextureID(&swap_chain->render_targets_info[i]), swap_chain_desc.Width, swap_chain_desc.Height, true);
2931
ERR_FAIL_COND_V(!framebuffer, ERR_CANT_CREATE);
2932
swap_chain->framebuffers.push_back(framebuffer);
2933
}
2934
2935
// Once everything's been created correctly, indicate the surface no longer needs to be resized.
2936
context_driver->surface_set_needs_resize(swap_chain->surface, false);
2937
2938
return OK;
2939
}
2940
2941
RDD::FramebufferID RenderingDeviceDriverD3D12::swap_chain_acquire_framebuffer(CommandQueueID p_cmd_queue, SwapChainID p_swap_chain, bool &r_resize_required) {
2942
DEV_ASSERT(p_swap_chain.id != 0);
2943
2944
const SwapChain *swap_chain = (const SwapChain *)(p_swap_chain.id);
2945
if (context_driver->surface_get_needs_resize(swap_chain->surface)) {
2946
r_resize_required = true;
2947
return FramebufferID();
2948
}
2949
2950
const uint32_t buffer_index = swap_chain->d3d_swap_chain->GetCurrentBackBufferIndex();
2951
DEV_ASSERT(buffer_index < swap_chain->framebuffers.size());
2952
return swap_chain->framebuffers[buffer_index];
2953
}
2954
2955
RDD::RenderPassID RenderingDeviceDriverD3D12::swap_chain_get_render_pass(SwapChainID p_swap_chain) {
2956
const SwapChain *swap_chain = (const SwapChain *)(p_swap_chain.id);
2957
return swap_chain->render_pass;
2958
}
2959
2960
RDD::DataFormat RenderingDeviceDriverD3D12::swap_chain_get_format(SwapChainID p_swap_chain) {
2961
const SwapChain *swap_chain = (const SwapChain *)(p_swap_chain.id);
2962
return swap_chain->data_format;
2963
}
2964
2965
void RenderingDeviceDriverD3D12::swap_chain_free(SwapChainID p_swap_chain) {
2966
SwapChain *swap_chain = (SwapChain *)(p_swap_chain.id);
2967
_swap_chain_release(swap_chain);
2968
render_pass_free(swap_chain->render_pass);
2969
memdelete(swap_chain);
2970
}
2971
2972
/*********************/
2973
/**** FRAMEBUFFER ****/
2974
/*********************/
2975
2976
D3D12_RENDER_TARGET_VIEW_DESC RenderingDeviceDriverD3D12::_make_rtv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) {
2977
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = {};
2978
rtv_desc.Format = p_texture_info->view_descs.srv.Format;
2979
2980
switch (p_texture_info->view_descs.srv.ViewDimension) {
2981
case D3D12_SRV_DIMENSION_TEXTURE1D: {
2982
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1D;
2983
rtv_desc.Texture1D.MipSlice = p_texture_info->base_mip + p_mipmap_offset;
2984
} break;
2985
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
2986
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE1DARRAY;
2987
rtv_desc.Texture1DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
2988
rtv_desc.Texture1DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
2989
rtv_desc.Texture1DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture1DArray.ArraySize : p_layers;
2990
} break;
2991
case D3D12_SRV_DIMENSION_TEXTURE2D: {
2992
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
2993
rtv_desc.Texture2D.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
2994
rtv_desc.Texture2D.PlaneSlice = p_texture_info->view_descs.srv.Texture2D.PlaneSlice;
2995
} break;
2996
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
2997
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
2998
rtv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
2999
rtv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3000
rtv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DArray.ArraySize : p_layers;
3001
rtv_desc.Texture2DArray.PlaneSlice = p_texture_info->view_descs.srv.Texture2DArray.PlaneSlice;
3002
} break;
3003
case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
3004
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMS;
3005
} break;
3006
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
3007
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY;
3008
rtv_desc.Texture2DMSArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3009
rtv_desc.Texture2DMSArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DMSArray.ArraySize : p_layers;
3010
} break;
3011
case D3D12_SRV_DIMENSION_TEXTURE3D: {
3012
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE3D;
3013
rtv_desc.Texture3D.MipSlice = p_texture_info->view_descs.srv.Texture3D.MostDetailedMip + p_mipmap_offset;
3014
rtv_desc.Texture3D.FirstWSlice = 0;
3015
rtv_desc.Texture3D.WSize = -1;
3016
} break;
3017
case D3D12_SRV_DIMENSION_TEXTURECUBE:
3018
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {
3019
rtv_desc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
3020
rtv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
3021
rtv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3022
rtv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->layers : p_layers;
3023
rtv_desc.Texture2DArray.PlaneSlice = 0;
3024
} break;
3025
default: {
3026
DEV_ASSERT(false);
3027
}
3028
}
3029
3030
return rtv_desc;
3031
}
3032
3033
D3D12_UNORDERED_ACCESS_VIEW_DESC RenderingDeviceDriverD3D12::_make_ranged_uav_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) {
3034
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = p_texture_info->view_descs.uav;
3035
3036
uint32_t mip = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
3037
switch (p_texture_info->view_descs.uav.ViewDimension) {
3038
case D3D12_UAV_DIMENSION_TEXTURE1D: {
3039
uav_desc.Texture1DArray.MipSlice = mip;
3040
} break;
3041
case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: {
3042
uav_desc.Texture1DArray.MipSlice = mip;
3043
uav_desc.Texture1DArray.FirstArraySlice = mip;
3044
uav_desc.Texture1DArray.ArraySize = p_layers;
3045
} break;
3046
case D3D12_UAV_DIMENSION_TEXTURE2D: {
3047
uav_desc.Texture2D.MipSlice = mip;
3048
} break;
3049
case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: {
3050
uav_desc.Texture2DArray.MipSlice = mip;
3051
uav_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3052
uav_desc.Texture2DArray.ArraySize = p_layers;
3053
} break;
3054
case D3D12_UAV_DIMENSION_TEXTURE3D: {
3055
uav_desc.Texture3D.MipSlice = mip;
3056
uav_desc.Texture3D.WSize = MAX(uav_desc.Texture3D.WSize >> p_mipmap_offset, 1U);
3057
} break;
3058
default:
3059
break;
3060
}
3061
3062
return uav_desc;
3063
}
3064
3065
D3D12_DEPTH_STENCIL_VIEW_DESC RenderingDeviceDriverD3D12::_make_dsv_for_texture(const TextureInfo *p_texture_info, uint32_t p_mipmap_offset, uint32_t p_layer_offset, uint32_t p_layers, bool p_add_bases) {
3066
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = {};
3067
dsv_desc.Format = RD_TO_D3D12_FORMAT[p_texture_info->format].dsv_format;
3068
dsv_desc.Flags = D3D12_DSV_FLAG_NONE;
3069
3070
switch (p_texture_info->view_descs.srv.ViewDimension) {
3071
case D3D12_SRV_DIMENSION_TEXTURE1D: {
3072
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1D;
3073
dsv_desc.Texture1D.MipSlice = p_texture_info->base_mip + p_mipmap_offset;
3074
} break;
3075
case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: {
3076
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE1DARRAY;
3077
dsv_desc.Texture1DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
3078
dsv_desc.Texture1DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3079
dsv_desc.Texture1DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture1DArray.ArraySize : p_layers;
3080
} break;
3081
case D3D12_SRV_DIMENSION_TEXTURE2D: {
3082
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
3083
dsv_desc.Texture2D.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
3084
} break;
3085
case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: {
3086
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
3087
dsv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
3088
dsv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3089
dsv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DArray.ArraySize : p_layers;
3090
} break;
3091
case D3D12_SRV_DIMENSION_TEXTURE2DMS: {
3092
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMS;
3093
dsv_desc.Texture2DMS.UnusedField_NothingToDefine = p_texture_info->view_descs.srv.Texture2DMS.UnusedField_NothingToDefine;
3094
} break;
3095
case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: {
3096
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY;
3097
dsv_desc.Texture2DMSArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3098
dsv_desc.Texture2DMSArray.ArraySize = p_layers == UINT32_MAX ? p_texture_info->view_descs.srv.Texture2DMSArray.ArraySize : p_layers;
3099
} break;
3100
case D3D12_SRV_DIMENSION_TEXTURECUBE: {
3101
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
3102
dsv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
3103
dsv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3104
dsv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? 6 : p_layers;
3105
} break;
3106
case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: {
3107
dsv_desc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2DARRAY;
3108
dsv_desc.Texture2DArray.MipSlice = (p_add_bases ? p_texture_info->base_mip : 0) + p_mipmap_offset;
3109
dsv_desc.Texture2DArray.FirstArraySlice = (p_add_bases ? p_texture_info->base_layer : 0) + p_layer_offset;
3110
dsv_desc.Texture2DArray.ArraySize = p_layers == UINT32_MAX ? (p_texture_info->view_descs.srv.TextureCubeArray.NumCubes * 6) : p_layers;
3111
} break;
3112
default: {
3113
DEV_ASSERT(false);
3114
}
3115
}
3116
3117
return dsv_desc;
3118
}
3119
3120
RDD::FramebufferID RenderingDeviceDriverD3D12::_framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height, bool p_is_screen) {
3121
const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
3122
3123
uint32_t num_color = 0;
3124
uint32_t num_depth_stencil = 0;
3125
for (uint32_t i = 0; i < p_attachments.size(); i++) {
3126
const TextureInfo *tex_info = (const TextureInfo *)p_attachments[i].id;
3127
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
3128
num_color++;
3129
} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
3130
num_depth_stencil++;
3131
}
3132
}
3133
3134
uint32_t vrs_index = UINT32_MAX;
3135
for (const Subpass &E : pass_info->subpasses) {
3136
if (E.fragment_shading_rate_reference.attachment != AttachmentReference::UNUSED) {
3137
vrs_index = E.fragment_shading_rate_reference.attachment;
3138
}
3139
}
3140
3141
CPUDescriptorHeapPool::Allocation rtv_alloc;
3142
if (num_color) {
3143
Error err = rtv_descriptor_heap_pool.allocate(num_color, device.Get(), rtv_alloc);
3144
ERR_FAIL_COND_V(err != OK, FramebufferID());
3145
}
3146
3147
CPUDescriptorHeapPool::Allocation dsv_alloc;
3148
if (num_depth_stencil) {
3149
Error err = dsv_descriptor_heap_pool.allocate(num_depth_stencil, device.Get(), dsv_alloc);
3150
if (unlikely(err != OK)) {
3151
rtv_descriptor_heap_pool.free(rtv_alloc);
3152
ERR_FAIL_V(FramebufferID());
3153
}
3154
}
3155
3156
// Bookkeep.
3157
FramebufferInfo *fb_info = VersatileResource::allocate<FramebufferInfo>(resources_allocator);
3158
fb_info->is_screen = p_is_screen;
3159
3160
fb_info->rtv_alloc = rtv_alloc;
3161
fb_info->dsv_alloc = dsv_alloc;
3162
3163
fb_info->attachments_handle_inds.resize(p_attachments.size());
3164
fb_info->attachments.reserve(num_color + num_depth_stencil);
3165
3166
uint32_t color_idx = 0;
3167
uint32_t depth_stencil_idx = 0;
3168
for (uint32_t i = 0; i < p_attachments.size(); i++) {
3169
const TextureInfo *tex_info = (const TextureInfo *)p_attachments[i].id;
3170
3171
if (fb_info->size.x == 0) {
3172
fb_info->size = Size2i(tex_info->desc.Width, tex_info->desc.Height);
3173
}
3174
3175
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
3176
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, 0, 0, UINT32_MAX);
3177
device->CreateRenderTargetView(tex_info->resource, &rtv_desc, get_cpu_handle(fb_info->rtv_alloc.cpu_handle, color_idx, rtv_descriptor_heap_pool.increment_size));
3178
3179
fb_info->attachments_handle_inds[i] = color_idx;
3180
fb_info->attachments.push_back(p_attachments[i]);
3181
color_idx++;
3182
} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
3183
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = _make_dsv_for_texture(tex_info, 0, 0, UINT32_MAX);
3184
device->CreateDepthStencilView(tex_info->resource, &dsv_desc, get_cpu_handle(fb_info->dsv_alloc.cpu_handle, depth_stencil_idx, dsv_descriptor_heap_pool.increment_size));
3185
3186
fb_info->attachments_handle_inds[i] = depth_stencil_idx;
3187
fb_info->attachments.push_back(p_attachments[i]);
3188
depth_stencil_idx++;
3189
} else if (i == vrs_index) {
3190
fb_info->vrs_attachment = p_attachments[i];
3191
} else {
3192
DEV_ASSERT(false);
3193
}
3194
}
3195
3196
DEV_ASSERT(fb_info->attachments.size() == color_idx + depth_stencil_idx);
3197
DEV_ASSERT((fb_info->vrs_attachment.id != 0) == (vrs_index != UINT32_MAX));
3198
3199
return FramebufferID(fb_info);
3200
}
3201
3202
RDD::FramebufferID RenderingDeviceDriverD3D12::framebuffer_create(RenderPassID p_render_pass, VectorView<TextureID> p_attachments, uint32_t p_width, uint32_t p_height) {
3203
return _framebuffer_create(p_render_pass, p_attachments, p_width, p_height, false);
3204
}
3205
3206
void RenderingDeviceDriverD3D12::framebuffer_free(FramebufferID p_framebuffer) {
3207
FramebufferInfo *fb_info = (FramebufferInfo *)p_framebuffer.id;
3208
3209
rtv_descriptor_heap_pool.free(fb_info->rtv_alloc);
3210
dsv_descriptor_heap_pool.free(fb_info->dsv_alloc);
3211
3212
VersatileResource::free(resources_allocator, fb_info);
3213
}
3214
3215
/****************/
3216
/**** SHADER ****/
3217
/****************/
3218
3219
bool RenderingDeviceDriverD3D12::_shader_apply_specialization_constants(
3220
const ShaderInfo *p_shader_info,
3221
VectorView<PipelineSpecializationConstant> p_specialization_constants,
3222
HashMap<ShaderStage, Vector<uint8_t>> &r_final_stages_bytecode) {
3223
// If something needs to be patched, COW will do the trick.
3224
r_final_stages_bytecode = p_shader_info->stages_bytecode;
3225
uint32_t stages_re_sign_mask = 0;
3226
for (uint32_t i = 0; i < p_specialization_constants.size(); i++) {
3227
const PipelineSpecializationConstant &psc = p_specialization_constants[i];
3228
if (!(p_shader_info->spirv_specialization_constants_ids_mask & (1 << psc.constant_id))) {
3229
// This SC wasn't even in the original SPIR-V shader.
3230
continue;
3231
}
3232
for (const ShaderInfo::SpecializationConstant &sc : p_shader_info->specialization_constants) {
3233
if (psc.constant_id == sc.constant_id) {
3234
if (psc.int_value != sc.int_value) {
3235
stages_re_sign_mask |= RenderingDXIL::patch_specialization_constant(psc.type, &psc.int_value, sc.stages_bit_offsets, r_final_stages_bytecode, false);
3236
}
3237
break;
3238
}
3239
}
3240
}
3241
// Re-sign patched stages.
3242
for (KeyValue<ShaderStage, Vector<uint8_t>> &E : r_final_stages_bytecode) {
3243
ShaderStage stage = E.key;
3244
if ((stages_re_sign_mask & (1 << stage))) {
3245
Vector<uint8_t> &bytecode = E.value;
3246
RenderingDXIL::sign_bytecode(stage, bytecode);
3247
}
3248
}
3249
3250
return true;
3251
}
3252
3253
RDD::ShaderID RenderingDeviceDriverD3D12::shader_create_from_container(const Ref<RenderingShaderContainer> &p_shader_container, const Vector<ImmutableSampler> &p_immutable_samplers) {
3254
ShaderReflection shader_refl = p_shader_container->get_shader_reflection();
3255
ShaderInfo shader_info_in;
3256
const RenderingShaderContainerD3D12 *shader_container_d3d12 = Object::cast_to<RenderingShaderContainerD3D12>(p_shader_container.ptr());
3257
ERR_FAIL_NULL_V_MSG(shader_container_d3d12, ShaderID(), "Shader container is not a recognized format.");
3258
3259
RenderingShaderContainerD3D12::ShaderReflectionD3D12 shader_refl_d3d12 = shader_container_d3d12->get_shader_reflection_d3d12();
3260
if (shader_refl_d3d12.dxil_push_constant_stages != 0) {
3261
shader_info_in.dxil_push_constant_size = shader_refl.push_constant_size;
3262
}
3263
3264
shader_info_in.spirv_specialization_constants_ids_mask = shader_refl_d3d12.spirv_specialization_constants_ids_mask;
3265
shader_info_in.nir_runtime_data_root_param_idx = shader_refl_d3d12.nir_runtime_data_root_param_idx;
3266
shader_info_in.pipeline_type = shader_refl.pipeline_type;
3267
3268
shader_info_in.sets.resize(shader_refl.uniform_sets.size());
3269
for (uint32_t i = 0; i < shader_info_in.sets.size(); i++) {
3270
const RenderingShaderContainerD3D12::ReflectionBindingSetDataD3D12 &set_d3d12 = shader_refl_d3d12.reflection_binding_sets_d3d12[i];
3271
3272
ShaderInfo::UniformSet &set = shader_info_in.sets[i];
3273
set.resource_root_param_idx = set_d3d12.resource_root_param_idx;
3274
set.resource_descriptor_count = set_d3d12.resource_descriptor_count;
3275
set.sampler_root_param_idx = set_d3d12.sampler_root_param_idx;
3276
set.sampler_descriptor_count = set_d3d12.sampler_descriptor_count;
3277
3278
set.bindings.resize(shader_refl.uniform_sets[i].size());
3279
for (uint32_t j = 0; j < set.bindings.size(); j++) {
3280
const ShaderUniform &uniform = shader_refl.uniform_sets[i][j];
3281
const RenderingShaderContainerD3D12::ReflectionBindingDataD3D12 &uniform_d3d12 = shader_refl_d3d12.reflection_binding_set_uniforms_d3d12[i][j];
3282
ShaderInfo::UniformBindingInfo &binding = set.bindings[j];
3283
binding.stages = uniform_d3d12.dxil_stages;
3284
binding.res_class = (ResourceClass)(uniform_d3d12.resource_class);
3285
binding.type = UniformType(uniform.type);
3286
binding.length = uniform.length;
3287
binding.writable = uniform.writable;
3288
binding.resource_descriptor_offset = uniform_d3d12.resource_descriptor_offset;
3289
binding.sampler_descriptor_offset = uniform_d3d12.sampler_descriptor_offset;
3290
binding.root_param_idx = uniform_d3d12.root_param_idx;
3291
}
3292
}
3293
3294
shader_info_in.specialization_constants.resize(shader_refl.specialization_constants.size());
3295
for (uint32_t i = 0; i < shader_info_in.specialization_constants.size(); i++) {
3296
ShaderInfo::SpecializationConstant &sc = shader_info_in.specialization_constants[i];
3297
const ShaderSpecializationConstant &src_sc = shader_refl.specialization_constants[i];
3298
const RenderingShaderContainerD3D12::ReflectionSpecializationDataD3D12 &src_sc_d3d12 = shader_refl_d3d12.reflection_specialization_data_d3d12[i];
3299
sc.constant_id = src_sc.constant_id;
3300
sc.int_value = src_sc.int_value;
3301
memcpy(sc.stages_bit_offsets, src_sc_d3d12.stages_bit_offsets, sizeof(sc.stages_bit_offsets));
3302
}
3303
3304
Vector<uint8_t> decompressed_code;
3305
for (uint32_t i = 0; i < shader_refl.stages_vector.size(); i++) {
3306
const RenderingShaderContainer::Shader &shader = p_shader_container->shaders[i];
3307
bool requires_decompression = (shader.code_decompressed_size > 0);
3308
if (requires_decompression) {
3309
decompressed_code.resize(shader.code_decompressed_size);
3310
bool decompressed = p_shader_container->decompress_code(shader.code_compressed_bytes.ptr(), shader.code_compressed_bytes.size(), shader.code_compression_flags, decompressed_code.ptrw(), decompressed_code.size());
3311
ERR_FAIL_COND_V_MSG(!decompressed, ShaderID(), vformat("Failed to decompress code on shader stage %s.", String(SHADER_STAGE_NAMES[shader_refl.stages_vector[i]])));
3312
}
3313
3314
if (requires_decompression) {
3315
shader_info_in.stages_bytecode[shader.shader_stage] = decompressed_code;
3316
} else {
3317
shader_info_in.stages_bytecode[shader.shader_stage] = shader.code_compressed_bytes;
3318
}
3319
}
3320
3321
PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER d3d_D3D12CreateRootSignatureDeserializer = (PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12CreateRootSignatureDeserializer");
3322
ERR_FAIL_NULL_V(d3d_D3D12CreateRootSignatureDeserializer, ShaderID());
3323
3324
HRESULT res = d3d_D3D12CreateRootSignatureDeserializer(shader_refl_d3d12.root_signature_bytes.ptr(), shader_refl_d3d12.root_signature_bytes.size(), IID_PPV_ARGS(shader_info_in.root_signature_deserializer.GetAddressOf()));
3325
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ShaderID(), "D3D12CreateRootSignatureDeserializer failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
3326
3327
ComPtr<ID3D12RootSignature> root_signature;
3328
res = device->CreateRootSignature(0, shader_refl_d3d12.root_signature_bytes.ptr(), shader_refl_d3d12.root_signature_bytes.size(), IID_PPV_ARGS(shader_info_in.root_signature.GetAddressOf()));
3329
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ShaderID(), "CreateRootSignature failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
3330
3331
shader_info_in.root_signature_desc = shader_info_in.root_signature_deserializer->GetRootSignatureDesc();
3332
shader_info_in.root_signature_crc = shader_refl_d3d12.root_signature_crc;
3333
3334
// Bookkeep.
3335
ShaderInfo *shader_info_ptr = VersatileResource::allocate<ShaderInfo>(resources_allocator);
3336
*shader_info_ptr = shader_info_in;
3337
return ShaderID(shader_info_ptr);
3338
}
3339
3340
uint32_t RenderingDeviceDriverD3D12::shader_get_layout_hash(ShaderID p_shader) {
3341
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
3342
return shader_info_in->root_signature_crc;
3343
}
3344
3345
void RenderingDeviceDriverD3D12::shader_free(ShaderID p_shader) {
3346
ShaderInfo *shader_info_in = (ShaderInfo *)p_shader.id;
3347
VersatileResource::free(resources_allocator, shader_info_in);
3348
}
3349
3350
void RenderingDeviceDriverD3D12::shader_destroy_modules(ShaderID p_shader) {
3351
ShaderInfo *shader_info_in = (ShaderInfo *)p_shader.id;
3352
shader_info_in->stages_bytecode.clear();
3353
}
3354
3355
/*********************/
3356
/**** UNIFORM SET ****/
3357
/*********************/
3358
3359
RDD::UniformSetID RenderingDeviceDriverD3D12::uniform_set_create(VectorView<BoundUniform> p_uniforms, ShaderID p_shader, uint32_t p_set_index, int p_linear_pool_index) {
3360
// Pre-bookkeep.
3361
UniformSetInfo *uniform_set_info = VersatileResource::allocate<UniformSetInfo>(resources_allocator);
3362
3363
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
3364
const ShaderInfo::UniformSet &uniform_set = shader_info_in->sets[p_set_index];
3365
3366
// We first gather dynamic arrays in a local array because TightLocalVector's
3367
// growth is not efficient when the number of elements is unknown.
3368
UniformSetInfo::DynamicBuffer dynamic_buffers[MAX_DYNAMIC_BUFFERS];
3369
uint32_t num_dynamic_buffers = 0u;
3370
3371
// Allocate range for resource descriptors.
3372
if (uniform_set.resource_descriptor_count > 0) {
3373
Error err = resource_descriptor_heap.allocate(uniform_set.resource_descriptor_count, uniform_set_info->resource_descriptor_heap_alloc);
3374
if (unlikely(err != OK)) {
3375
VersatileResource::free(resources_allocator, uniform_set_info);
3376
3377
ERR_FAIL_COND_V_MSG(err == ERR_OUT_OF_MEMORY, UniformSetID(), "Cannot create uniform set because there's not enough room in the RESOURCES descriptor heap.\n"
3378
"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors project setting.");
3379
3380
ERR_FAIL_V_MSG(UniformSetID(), "Failed to allocate resource descriptors.");
3381
}
3382
}
3383
3384
// Allocate range for sampler descriptors. Since we do not have much space for samplers, and many uniform sets use identical ones, it's very beneficial to cache and reuse them.
3385
bool create_samplers = false;
3386
if (uniform_set.sampler_descriptor_count > 0) {
3387
uint32_t sampler_key = HASH_MURMUR3_SEED;
3388
for (uint32_t i = 0; i < p_uniforms.size(); i++) {
3389
const BoundUniform &uniform = p_uniforms[i];
3390
3391
switch (uniform.type) {
3392
case UNIFORM_TYPE_SAMPLER: {
3393
for (uint32_t j = 0; j < uniform.ids.size(); j++) {
3394
sampler_key = hash_murmur3_one_64(uniform.ids[j].id, sampler_key);
3395
}
3396
} break;
3397
case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
3398
for (uint32_t j = 0; j < uniform.ids.size(); j += 2) {
3399
sampler_key = hash_murmur3_one_64(uniform.ids[j].id, sampler_key);
3400
}
3401
} break;
3402
default: {
3403
} break;
3404
}
3405
}
3406
sampler_key = hash_fmix32(sampler_key);
3407
3408
RBMap<uint32_t, SamplerDescriptorHeapAllocation>::Iterator find_result = sampler_descriptor_heap_allocations.find(sampler_key);
3409
if (find_result != sampler_descriptor_heap_allocations.end()) {
3410
uniform_set_info->sampler_descriptor_heap_alloc = &find_result->value;
3411
++uniform_set_info->sampler_descriptor_heap_alloc->use_count;
3412
} else {
3413
uniform_set_info->sampler_descriptor_heap_alloc = &sampler_descriptor_heap_allocations.insert(sampler_key, SamplerDescriptorHeapAllocation())->get();
3414
uniform_set_info->sampler_descriptor_heap_alloc->key = sampler_key;
3415
3416
Error err = sampler_descriptor_heap.allocate(uniform_set.sampler_descriptor_count, *uniform_set_info->sampler_descriptor_heap_alloc);
3417
if (unlikely(err != OK)) {
3418
resource_descriptor_heap.free(uniform_set_info->resource_descriptor_heap_alloc);
3419
VersatileResource::free(resources_allocator, uniform_set_info);
3420
3421
ERR_FAIL_COND_V_MSG(err == ERR_OUT_OF_MEMORY, UniformSetID(), "Cannot create uniform set because there's not enough room in the SAMPLERS descriptors heap.\n"
3422
"Please increase the value of the rendering/rendering_device/d3d12/max_sampler_descriptors project setting.");
3423
3424
ERR_FAIL_V_MSG(UniformSetID(), "Failed to allocate sampler descriptors.");
3425
}
3426
3427
create_samplers = true;
3428
}
3429
}
3430
3431
struct NeededState {
3432
bool is_buffer = false;
3433
uint64_t shader_uniform_idx_mask = 0;
3434
D3D12_RESOURCE_STATES states = {};
3435
};
3436
HashMap<ResourceInfo *, NeededState> resource_states;
3437
3438
for (uint32_t i = 0; i < p_uniforms.size(); i++) {
3439
const BoundUniform &uniform = p_uniforms[i];
3440
const ShaderInfo::UniformBindingInfo &binding = uniform_set.bindings[i];
3441
3442
switch (uniform.type) {
3443
case UNIFORM_TYPE_SAMPLER: {
3444
if (create_samplers) {
3445
for (uint32_t j = 0; j < uniform.ids.size(); j++) {
3446
const D3D12_SAMPLER_DESC &sampler_desc = samplers[uniform.ids[j].id];
3447
device->CreateSampler(&sampler_desc, get_cpu_handle(uniform_set_info->sampler_descriptor_heap_alloc->cpu_handle, binding.sampler_descriptor_offset + j, sampler_descriptor_heap.increment_size));
3448
}
3449
}
3450
} break;
3451
case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE: {
3452
for (uint32_t j = 0; j < uniform.ids.size(); j += 2) {
3453
if (create_samplers) {
3454
const D3D12_SAMPLER_DESC &sampler_desc = samplers[uniform.ids[j].id];
3455
device->CreateSampler(&sampler_desc, get_cpu_handle(uniform_set_info->sampler_descriptor_heap_alloc->cpu_handle, binding.sampler_descriptor_offset + (j / 2), sampler_descriptor_heap.increment_size));
3456
}
3457
3458
TextureInfo *texture_info = (TextureInfo *)uniform.ids[j + 1].id;
3459
device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + (j / 2), resource_descriptor_heap.increment_size));
3460
3461
NeededState &ns = resource_states[texture_info];
3462
ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
3463
ns.states |= D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
3464
}
3465
} break;
3466
case UNIFORM_TYPE_TEXTURE: {
3467
for (uint32_t j = 0; j < uniform.ids.size(); j++) {
3468
TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
3469
device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + j, resource_descriptor_heap.increment_size));
3470
3471
NeededState &ns = resource_states[texture_info];
3472
ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
3473
ns.states |= D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE;
3474
}
3475
} break;
3476
case UNIFORM_TYPE_IMAGE: {
3477
for (uint32_t j = 0; j < uniform.ids.size(); j++) {
3478
TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
3479
device->CreateUnorderedAccessView(texture_info->resource, nullptr, &texture_info->view_descs.uav, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + j, resource_descriptor_heap.increment_size));
3480
3481
NeededState &ns = resource_states[texture_info];
3482
ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
3483
ns.states |= D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
3484
}
3485
} break;
3486
case UNIFORM_TYPE_TEXTURE_BUFFER:
3487
case UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER: {
3488
CRASH_NOW_MSG("Unimplemented!");
3489
} break;
3490
case UNIFORM_TYPE_IMAGE_BUFFER: {
3491
CRASH_NOW_MSG("Unimplemented!");
3492
} break;
3493
case UNIFORM_TYPE_UNIFORM_BUFFER:
3494
case UNIFORM_TYPE_UNIFORM_BUFFER_DYNAMIC: {
3495
BufferInfo *buf_info = (BufferInfo *)uniform.ids[0].id;
3496
3497
if (uniform.type == UNIFORM_TYPE_UNIFORM_BUFFER) {
3498
ERR_FAIL_COND_V_MSG(buf_info->is_dynamic(), UniformSetID(),
3499
"Sent a buffer with BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_UNIFORM_BUFFER instead of UNIFORM_TYPE_UNIFORM_BUFFER_DYNAMIC.");
3500
3501
D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc = {};
3502
cbv_desc.BufferLocation = buf_info->gpu_virtual_address;
3503
cbv_desc.SizeInBytes = STEPIFY(buf_info->size, D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
3504
3505
device->CreateConstantBufferView(&cbv_desc, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset, resource_descriptor_heap.increment_size));
3506
} else {
3507
ERR_FAIL_COND_V_MSG(!buf_info->is_dynamic(), UniformSetID(),
3508
"Sent a buffer without BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_UNIFORM_BUFFER_DYNAMIC instead of UNIFORM_TYPE_UNIFORM_BUFFER.");
3509
ERR_FAIL_COND_V_MSG(num_dynamic_buffers >= MAX_DYNAMIC_BUFFERS, UniformSetID(),
3510
"Uniform set exceeded the limit of dynamic/persistent buffers. (" + itos(MAX_DYNAMIC_BUFFERS) + ").");
3511
3512
UniformSetInfo::DynamicBuffer &dynamic_buffer = dynamic_buffers[num_dynamic_buffers++];
3513
dynamic_buffer.info = (const BufferDynamicInfo *)buf_info;
3514
dynamic_buffer.binding = i;
3515
}
3516
3517
NeededState &ns = resource_states[buf_info];
3518
ns.is_buffer = true;
3519
ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
3520
ns.states |= D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
3521
} break;
3522
case UNIFORM_TYPE_STORAGE_BUFFER:
3523
case UNIFORM_TYPE_STORAGE_BUFFER_DYNAMIC: {
3524
BufferInfo *buf_info = (BufferInfo *)uniform.ids[0].id;
3525
3526
if (uniform.type == UNIFORM_TYPE_STORAGE_BUFFER) {
3527
ERR_FAIL_COND_V_MSG(buf_info->is_dynamic(), UniformSetID(),
3528
"Sent a buffer with BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_STORAGE_BUFFER instead of UNIFORM_TYPE_STORAGE_BUFFER_DYNAMIC.");
3529
3530
// Create UAV or SRV depending on whether the uniform is writable.
3531
if (binding.writable) {
3532
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
3533
uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
3534
uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
3535
uav_desc.Buffer.FirstElement = 0;
3536
uav_desc.Buffer.NumElements = (buf_info->size + 3u) / 4u;
3537
uav_desc.Buffer.StructureByteStride = 0;
3538
uav_desc.Buffer.CounterOffsetInBytes = 0;
3539
uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
3540
device->CreateUnorderedAccessView(buf_info->resource, nullptr, &uav_desc, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset, resource_descriptor_heap.increment_size));
3541
} else {
3542
D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc = {};
3543
srv_desc.Format = DXGI_FORMAT_R32_TYPELESS;
3544
srv_desc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
3545
srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
3546
srv_desc.Buffer.FirstElement = 0;
3547
srv_desc.Buffer.NumElements = (buf_info->size + 3u) / 4u;
3548
srv_desc.Buffer.StructureByteStride = 0;
3549
srv_desc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_RAW;
3550
device->CreateShaderResourceView(buf_info->resource, &srv_desc, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset, resource_descriptor_heap.increment_size));
3551
}
3552
3553
} else {
3554
ERR_FAIL_COND_V_MSG(!buf_info->is_dynamic(), UniformSetID(),
3555
"Sent a buffer without BUFFER_USAGE_DYNAMIC_PERSISTENT_BIT but binding (" + itos(uniform.binding) + "), set (" + itos(p_set_index) + ") is UNIFORM_TYPE_STORAGE_BUFFER_DYNAMIC instead of UNIFORM_TYPE_STORAGE_BUFFER.");
3556
ERR_FAIL_COND_V_MSG(num_dynamic_buffers >= MAX_DYNAMIC_BUFFERS, UniformSetID(),
3557
"Uniform set exceeded the limit of dynamic/persistent buffers. (" + itos(MAX_DYNAMIC_BUFFERS) + ").");
3558
3559
UniformSetInfo::DynamicBuffer &dynamic_buffer = dynamic_buffers[num_dynamic_buffers++];
3560
dynamic_buffer.info = (const BufferDynamicInfo *)buf_info;
3561
dynamic_buffer.binding = i;
3562
}
3563
3564
NeededState &ns = resource_states[buf_info];
3565
ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
3566
ns.is_buffer = true;
3567
ns.states |= (binding.writable ? D3D12_RESOURCE_STATE_UNORDERED_ACCESS : D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE);
3568
} break;
3569
case UNIFORM_TYPE_INPUT_ATTACHMENT: {
3570
for (uint32_t j = 0; j < uniform.ids.size(); j++) {
3571
TextureInfo *texture_info = (TextureInfo *)uniform.ids[j].id;
3572
3573
device->CreateShaderResourceView(texture_info->resource, &texture_info->view_descs.srv, get_cpu_handle(uniform_set_info->resource_descriptor_heap_alloc.cpu_handle, binding.resource_descriptor_offset + j, resource_descriptor_heap.increment_size));
3574
3575
NeededState &ns = resource_states[texture_info];
3576
ns.shader_uniform_idx_mask |= ((uint64_t)1 << i);
3577
ns.states |= D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
3578
}
3579
} break;
3580
default: {
3581
DEV_ASSERT(false);
3582
}
3583
}
3584
}
3585
3586
uniform_set_info->dynamic_buffers.resize(num_dynamic_buffers);
3587
for (size_t i = 0u; i < num_dynamic_buffers; ++i) {
3588
uniform_set_info->dynamic_buffers[i] = dynamic_buffers[i];
3589
}
3590
3591
{
3592
uniform_set_info->resource_states.reserve(resource_states.size());
3593
for (const KeyValue<ResourceInfo *, NeededState> &E : resource_states) {
3594
UniformSetInfo::StateRequirement sr;
3595
sr.resource = E.key;
3596
sr.is_buffer = E.value.is_buffer;
3597
sr.states = E.value.states;
3598
sr.shader_uniform_idx_mask = E.value.shader_uniform_idx_mask;
3599
uniform_set_info->resource_states.push_back(sr);
3600
}
3601
}
3602
3603
return UniformSetID(uniform_set_info);
3604
}
3605
3606
void RenderingDeviceDriverD3D12::uniform_set_free(UniformSetID p_uniform_set) {
3607
UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_set.id;
3608
3609
resource_descriptor_heap.free(uniform_set_info->resource_descriptor_heap_alloc);
3610
3611
if (uniform_set_info->sampler_descriptor_heap_alloc != nullptr) {
3612
if ((--uniform_set_info->sampler_descriptor_heap_alloc->use_count) == 0) {
3613
sampler_descriptor_heap.free(*uniform_set_info->sampler_descriptor_heap_alloc);
3614
sampler_descriptor_heap_allocations.erase(uniform_set_info->sampler_descriptor_heap_alloc->key);
3615
}
3616
}
3617
3618
VersatileResource::free(resources_allocator, uniform_set_info);
3619
}
3620
3621
uint32_t RenderingDeviceDriverD3D12::uniform_sets_get_dynamic_offsets(VectorView<UniformSetID> p_uniform_sets, ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count) const {
3622
uint32_t mask = 0u;
3623
uint32_t shift = 0u;
3624
#ifdef DEV_ENABLED
3625
uint32_t curr_dynamic_offset = 0u;
3626
#endif
3627
3628
for (uint32_t i = 0; i < p_set_count; i++) {
3629
const UniformSetInfo *usi = (const UniformSetInfo *)p_uniform_sets[i].id;
3630
// At this point this assert should already have been validated.
3631
DEV_ASSERT(curr_dynamic_offset + usi->dynamic_buffers.size() <= MAX_DYNAMIC_BUFFERS);
3632
3633
for (const UniformSetInfo::DynamicBuffer &dynamic_buffer : usi->dynamic_buffers) {
3634
DEV_ASSERT(dynamic_buffer.info->frame_idx < 16u);
3635
mask |= dynamic_buffer.info->frame_idx << shift;
3636
shift += 4u;
3637
}
3638
#ifdef DEV_ENABLED
3639
curr_dynamic_offset += usi->dynamic_buffers.size();
3640
#endif
3641
}
3642
3643
return mask;
3644
}
3645
3646
// ----- COMMANDS -----
3647
3648
void RenderingDeviceDriverD3D12::command_uniform_set_prepare_for_use(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
3649
if (barrier_capabilities.enhanced_barriers_supported) {
3650
return;
3651
}
3652
3653
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
3654
const UniformSetInfo *uniform_set_info = (const UniformSetInfo *)p_uniform_set.id;
3655
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
3656
const ShaderInfo::UniformSet &shader_set = shader_info_in->sets[p_set_index];
3657
3658
for (const UniformSetInfo::StateRequirement &sr : uniform_set_info->resource_states) {
3659
#ifdef DEV_ENABLED
3660
{
3661
uint32_t stages = 0;
3662
D3D12_RESOURCE_STATES wanted_state = {};
3663
bool writable = false;
3664
// Doing the full loop for debugging since the real one below may break early,
3665
// but we want an exhaustive check
3666
uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.
3667
for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {
3668
uint64_t bit_mask = ((uint64_t)1 << bit);
3669
if (likely((inv_uniforms_mask & bit_mask))) {
3670
continue;
3671
}
3672
inv_uniforms_mask |= bit_mask;
3673
3674
const ShaderInfo::UniformBindingInfo &binding = shader_set.bindings[bit];
3675
if (unlikely(!binding.stages)) {
3676
continue;
3677
}
3678
3679
if (stages) { // Second occurrence at least?
3680
CRASH_COND_MSG(binding.writable != writable, "A resource is used in the same uniform set both as R/O and R/W. That's not supported and shouldn't happen.");
3681
CRASH_COND_MSG(sr.states != wanted_state, "A resource is used in the same uniform set with different resource states. The code needs to be enhanced to support that.");
3682
} else {
3683
wanted_state = sr.states;
3684
stages |= binding.stages;
3685
writable = binding.writable;
3686
}
3687
3688
DEV_ASSERT((wanted_state == D3D12_RESOURCE_STATE_UNORDERED_ACCESS) == (bool)(wanted_state & D3D12_RESOURCE_STATE_UNORDERED_ACCESS));
3689
}
3690
}
3691
#endif
3692
3693
// We may have assumed D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE for a resource,
3694
// because at uniform set creation time we couldn't know for sure which stages
3695
// it would be used in (due to the fact that a set can be created against a different,
3696
// albeit compatible, shader, which may make a different usage in the end).
3697
// However, now we know and can exclude up to one unneeded states.
3698
3699
// TODO: If subresources involved already in the needed states, or scheduled for it,
3700
// maybe it's more optimal not to do anything here
3701
3702
uint32_t stages = 0;
3703
D3D12_RESOURCE_STATES wanted_state = {};
3704
uint64_t inv_uniforms_mask = ~sr.shader_uniform_idx_mask; // Inverting the mask saves operations.
3705
for (uint8_t bit = 0; inv_uniforms_mask != UINT64_MAX; bit++) {
3706
uint64_t bit_mask = ((uint64_t)1 << bit);
3707
if (likely((inv_uniforms_mask & bit_mask))) {
3708
continue;
3709
}
3710
inv_uniforms_mask |= bit_mask;
3711
3712
const ShaderInfo::UniformBindingInfo &binding = shader_set.bindings[bit];
3713
if (unlikely(!binding.stages)) {
3714
continue;
3715
}
3716
3717
if (!stages) {
3718
wanted_state = sr.states;
3719
3720
if (!(wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {
3721
// By now, we already know the resource is used, and with no PS/NON_PS disjuntive; no need to check further.
3722
break;
3723
}
3724
}
3725
3726
stages |= binding.stages;
3727
3728
if (stages == (SHADER_STAGE_VERTEX_BIT | SHADER_STAGE_FRAGMENT_BIT) || stages == SHADER_STAGE_COMPUTE_BIT) {
3729
// By now, we already know the resource is used, and as both PS/NON_PS; no need to check further.
3730
break;
3731
}
3732
}
3733
3734
if (likely(wanted_state)) {
3735
if ((wanted_state & D3D12_RESOURCE_STATE_ALL_SHADER_RESOURCE)) {
3736
if (stages == SHADER_STAGE_VERTEX_BIT || stages == SHADER_STAGE_COMPUTE_BIT) {
3737
D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
3738
wanted_state &= ~unneeded_states;
3739
} else if (stages == SHADER_STAGE_FRAGMENT_BIT) {
3740
D3D12_RESOURCE_STATES unneeded_states = D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
3741
wanted_state &= ~unneeded_states;
3742
}
3743
}
3744
3745
if (likely(wanted_state)) {
3746
if (sr.is_buffer) {
3747
_resource_transition_batch(cmd_buf_info, sr.resource, 0, 1, wanted_state);
3748
} else {
3749
TextureInfo *tex_info = (TextureInfo *)sr.resource;
3750
uint32_t planes = 1;
3751
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
3752
planes = format_get_plane_count(tex_info->format);
3753
}
3754
for (uint32_t i = 0; i < tex_info->layers; i++) {
3755
for (uint32_t j = 0; j < tex_info->mipmaps; j++) {
3756
uint32_t subresource = D3D12CalcSubresource(tex_info->base_mip + j, tex_info->base_layer + i, 0, tex_info->desc.MipLevels, tex_info->desc.ArraySize());
3757
_resource_transition_batch(cmd_buf_info, tex_info, subresource, planes, wanted_state);
3758
}
3759
}
3760
}
3761
}
3762
}
3763
}
3764
3765
if (p_set_index == shader_info_in->sets.size() - 1) {
3766
_resource_transitions_flush(cmd_buf_info);
3767
}
3768
}
3769
3770
void RenderingDeviceDriverD3D12::_command_check_descriptor_sets(CommandBufferID p_cmd_buffer) {
3771
DEV_ASSERT(segment_begun && "Unable to use commands that rely on descriptors because a segment was never begun.");
3772
3773
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
3774
if (!cmd_buf_info->descriptor_heaps_set) {
3775
// Set descriptor heaps for the command buffer if they haven't been set yet.
3776
ID3D12DescriptorHeap *heaps[] = {
3777
resource_descriptor_heap.heap.Get(),
3778
sampler_descriptor_heap.heap.Get(),
3779
};
3780
3781
cmd_buf_info->cmd_list->SetDescriptorHeaps(2, heaps);
3782
cmd_buf_info->descriptor_heaps_set = true;
3783
}
3784
}
3785
3786
/******************/
3787
/**** TRANSFER ****/
3788
/******************/
3789
3790
RenderingDeviceDriverD3D12::DescriptorHeap::Allocation RenderingDeviceDriverD3D12::_command_allocate_per_frame_descriptor() {
3791
FrameInfo &f = frames[frame_idx];
3792
if (f.descriptor_allocation_count < f.descriptor_allocations.size()) {
3793
uint32_t allocation_index = f.descriptor_allocation_count;
3794
++f.descriptor_allocation_count;
3795
return f.descriptor_allocations[allocation_index];
3796
} else {
3797
DescriptorHeap::Allocation descriptor_allocation = {};
3798
3799
Error err = resource_descriptor_heap.allocate(1, descriptor_allocation);
3800
ERR_FAIL_COND_V_MSG(err == ERR_OUT_OF_MEMORY, DescriptorHeap::Allocation(), "Cannot allocate per frame descriptor because there's not enough room in the RESOURCES descriptor heap.\n"
3801
"Please increase the value of the rendering/rendering_device/d3d12/max_resource_descriptors project setting.");
3802
3803
ERR_FAIL_COND_V_MSG(err != OK, DescriptorHeap::Allocation(), "Failed to allocate per frame descriptor.");
3804
3805
f.descriptor_allocations.push_back(descriptor_allocation);
3806
f.descriptor_allocation_count = f.descriptor_allocations.size();
3807
3808
return descriptor_allocation;
3809
}
3810
}
3811
3812
void RenderingDeviceDriverD3D12::command_clear_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, uint64_t p_offset, uint64_t p_size) {
3813
_command_check_descriptor_sets(p_cmd_buffer);
3814
3815
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
3816
BufferInfo *buf_info = (BufferInfo *)p_buffer.id;
3817
3818
if (!barrier_capabilities.enhanced_barriers_supported) {
3819
_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3820
_resource_transitions_flush(cmd_buf_info);
3821
}
3822
3823
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = {};
3824
uav_desc.Format = DXGI_FORMAT_R32_TYPELESS;
3825
uav_desc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
3826
uav_desc.Buffer.FirstElement = p_offset / 4;
3827
uav_desc.Buffer.NumElements = p_size / 4;
3828
uav_desc.Buffer.StructureByteStride = 0;
3829
uav_desc.Buffer.CounterOffsetInBytes = 0;
3830
uav_desc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
3831
device->CreateUnorderedAccessView(
3832
buf_info->resource,
3833
nullptr,
3834
&uav_desc,
3835
cmd_buf_info->uav_alloc.cpu_handle);
3836
3837
DescriptorHeap::Allocation shader_visible_descriptor_allocation = _command_allocate_per_frame_descriptor();
3838
ERR_FAIL_COND(shader_visible_descriptor_allocation.virtual_alloc_handle == 0);
3839
3840
device->CopyDescriptorsSimple(
3841
1,
3842
shader_visible_descriptor_allocation.cpu_handle,
3843
cmd_buf_info->uav_alloc.cpu_handle,
3844
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
3845
3846
static const UINT values[4] = {};
3847
cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint(
3848
shader_visible_descriptor_allocation.gpu_handle,
3849
cmd_buf_info->uav_alloc.cpu_handle,
3850
buf_info->resource,
3851
values,
3852
0,
3853
nullptr);
3854
}
3855
3856
void RenderingDeviceDriverD3D12::command_copy_buffer(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, BufferID p_buf_locfer, VectorView<BufferCopyRegion> p_regions) {
3857
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
3858
BufferInfo *src_buf_info = (BufferInfo *)p_src_buffer.id;
3859
BufferInfo *buf_loc_info = (BufferInfo *)p_buf_locfer.id;
3860
3861
if (!barrier_capabilities.enhanced_barriers_supported) {
3862
_resource_transition_batch(cmd_buf_info, src_buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
3863
_resource_transition_batch(cmd_buf_info, buf_loc_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
3864
_resource_transitions_flush(cmd_buf_info);
3865
}
3866
3867
for (uint32_t i = 0; i < p_regions.size(); i++) {
3868
cmd_buf_info->cmd_list->CopyBufferRegion(buf_loc_info->resource, p_regions[i].dst_offset, src_buf_info->resource, p_regions[i].src_offset, p_regions[i].size);
3869
}
3870
}
3871
3872
void RenderingDeviceDriverD3D12::command_copy_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<TextureCopyRegion> p_regions) {
3873
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
3874
TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;
3875
TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;
3876
3877
if (!barrier_capabilities.enhanced_barriers_supported) {
3878
// Batch all barrier transitions for the textures before performing the copies.
3879
for (uint32_t i = 0; i < p_regions.size(); i++) {
3880
uint32_t layer_count = MIN(p_regions[i].src_subresources.layer_count, p_regions[i].dst_subresources.layer_count);
3881
for (uint32_t j = 0; j < layer_count; j++) {
3882
UINT src_subresource = _compute_subresource_from_layers(src_tex_info, p_regions[i].src_subresources, j);
3883
UINT dst_subresource = _compute_subresource_from_layers(dst_tex_info, p_regions[i].dst_subresources, j);
3884
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
3885
_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);
3886
}
3887
}
3888
3889
_resource_transitions_flush(cmd_buf_info);
3890
}
3891
3892
CD3DX12_BOX src_box;
3893
for (uint32_t i = 0; i < p_regions.size(); i++) {
3894
uint32_t layer_count = MIN(p_regions[i].src_subresources.layer_count, p_regions[i].dst_subresources.layer_count);
3895
for (uint32_t j = 0; j < layer_count; j++) {
3896
UINT src_subresource = _compute_subresource_from_layers(src_tex_info, p_regions[i].src_subresources, j);
3897
UINT dst_subresource = _compute_subresource_from_layers(dst_tex_info, p_regions[i].dst_subresources, j);
3898
CD3DX12_TEXTURE_COPY_LOCATION src_location(src_tex_info->resource, src_subresource);
3899
CD3DX12_TEXTURE_COPY_LOCATION dst_location(dst_tex_info->resource, dst_subresource);
3900
src_box.left = p_regions[i].src_offset.x;
3901
src_box.top = p_regions[i].src_offset.y;
3902
src_box.front = p_regions[i].src_offset.z;
3903
src_box.right = p_regions[i].src_offset.x + p_regions[i].size.x;
3904
src_box.bottom = p_regions[i].src_offset.y + p_regions[i].size.y;
3905
src_box.back = p_regions[i].src_offset.z + p_regions[i].size.z;
3906
cmd_buf_info->cmd_list->CopyTextureRegion(&dst_location, p_regions[i].dst_offset.x, p_regions[i].dst_offset.y, p_regions[i].dst_offset.z, &src_location, &src_box);
3907
}
3908
}
3909
}
3910
3911
void RenderingDeviceDriverD3D12::command_resolve_texture(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, uint32_t p_src_layer, uint32_t p_src_mipmap, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, uint32_t p_dst_layer, uint32_t p_dst_mipmap) {
3912
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
3913
TextureInfo *src_tex_info = (TextureInfo *)p_src_texture.id;
3914
TextureInfo *dst_tex_info = (TextureInfo *)p_dst_texture.id;
3915
3916
UINT src_subresource = D3D12CalcSubresource(p_src_mipmap, p_src_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
3917
UINT dst_subresource = D3D12CalcSubresource(p_dst_mipmap, p_dst_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());
3918
if (!barrier_capabilities.enhanced_barriers_supported) {
3919
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
3920
_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
3921
_resource_transitions_flush(cmd_buf_info);
3922
}
3923
3924
cmd_buf_info->cmd_list->ResolveSubresource(dst_tex_info->resource, dst_subresource, src_tex_info->resource, src_subresource, RD_TO_D3D12_FORMAT[src_tex_info->format].general_format);
3925
}
3926
3927
void RenderingDeviceDriverD3D12::command_clear_color_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, const Color &p_color, const TextureSubresourceRange &p_subresources) {
3928
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
3929
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
3930
if (tex_info->main_texture) {
3931
tex_info = tex_info->main_texture;
3932
}
3933
3934
auto _transition_subresources = [&](D3D12_RESOURCE_STATES p_new_state) {
3935
for (uint32_t i = 0; i < p_subresources.layer_count; i++) {
3936
for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) {
3937
UINT subresource = D3D12CalcSubresource(
3938
p_subresources.base_mipmap + j,
3939
p_subresources.base_layer + i,
3940
0,
3941
tex_info->desc.MipLevels,
3942
tex_info->desc.ArraySize());
3943
_resource_transition_batch(cmd_buf_info, tex_info, subresource, 1, p_new_state);
3944
}
3945
}
3946
_resource_transitions_flush(cmd_buf_info);
3947
};
3948
3949
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
3950
if (!barrier_capabilities.enhanced_barriers_supported) {
3951
_transition_subresources(D3D12_RESOURCE_STATE_RENDER_TARGET);
3952
}
3953
3954
for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) {
3955
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc = _make_rtv_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false);
3956
rtv_desc.Format = tex_info->view_descs.uav.Format;
3957
device->CreateRenderTargetView(
3958
tex_info->resource,
3959
&rtv_desc,
3960
cmd_buf_info->rtv_alloc.cpu_handle);
3961
3962
cmd_buf_info->cmd_list->ClearRenderTargetView(
3963
cmd_buf_info->rtv_alloc.cpu_handle,
3964
p_color.components,
3965
0,
3966
nullptr);
3967
}
3968
} else if (tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS) {
3969
// Clear via UAV.
3970
_command_check_descriptor_sets(p_cmd_buffer);
3971
3972
if (!barrier_capabilities.enhanced_barriers_supported) {
3973
_transition_subresources(D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
3974
}
3975
3976
for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) {
3977
D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc = _make_ranged_uav_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false);
3978
device->CreateUnorderedAccessView(
3979
tex_info->resource,
3980
nullptr,
3981
&uav_desc,
3982
cmd_buf_info->uav_alloc.cpu_handle);
3983
3984
DescriptorHeap::Allocation shader_visible_descriptor_allocation = _command_allocate_per_frame_descriptor();
3985
ERR_FAIL_COND(shader_visible_descriptor_allocation.virtual_alloc_handle == 0);
3986
3987
device->CopyDescriptorsSimple(
3988
1,
3989
shader_visible_descriptor_allocation.cpu_handle,
3990
cmd_buf_info->uav_alloc.cpu_handle,
3991
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
3992
3993
UINT values[4] = {
3994
(UINT)p_color.get_r8(),
3995
(UINT)p_color.get_g8(),
3996
(UINT)p_color.get_b8(),
3997
(UINT)p_color.get_a8(),
3998
};
3999
4000
cmd_buf_info->cmd_list->ClearUnorderedAccessViewUint(
4001
shader_visible_descriptor_allocation.gpu_handle,
4002
cmd_buf_info->uav_alloc.cpu_handle,
4003
tex_info->resource,
4004
values,
4005
0,
4006
nullptr);
4007
}
4008
} else {
4009
ERR_FAIL_MSG("Cannot clear texture because its format does not support UAV writes. You'll need to update its contents through another method.");
4010
}
4011
}
4012
4013
void RenderingDeviceDriverD3D12::command_clear_depth_stencil_texture(CommandBufferID p_cmd_buffer, TextureID p_texture, TextureLayout p_texture_layout, float p_depth, uint8_t p_stencil, const TextureSubresourceRange &p_subresources) {
4014
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4015
TextureInfo *tex_info = (TextureInfo *)p_texture.id;
4016
if (tex_info->main_texture) {
4017
tex_info = tex_info->main_texture;
4018
}
4019
4020
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
4021
if (!barrier_capabilities.enhanced_barriers_supported) {
4022
uint32_t num_planes = format_get_plane_count(tex_info->format);
4023
4024
for (uint32_t i = 0; i < p_subresources.layer_count; i++) {
4025
for (uint32_t j = 0; j < p_subresources.mipmap_count; j++) {
4026
UINT subresource = D3D12CalcSubresource(
4027
p_subresources.base_mipmap + j,
4028
p_subresources.base_layer + i,
4029
0,
4030
tex_info->desc.MipLevels,
4031
tex_info->desc.ArraySize());
4032
_resource_transition_batch(cmd_buf_info, tex_info, subresource, num_planes, D3D12_RESOURCE_STATE_DEPTH_WRITE);
4033
}
4034
}
4035
_resource_transitions_flush(cmd_buf_info);
4036
}
4037
4038
D3D12_CLEAR_FLAGS clear_flags = {};
4039
if (p_subresources.aspect.has_flag(RDD::TEXTURE_ASPECT_DEPTH_BIT)) {
4040
clear_flags |= D3D12_CLEAR_FLAG_DEPTH;
4041
}
4042
if (p_subresources.aspect.has_flag(RDD::TEXTURE_ASPECT_STENCIL_BIT)) {
4043
clear_flags |= D3D12_CLEAR_FLAG_STENCIL;
4044
}
4045
4046
for (uint32_t i = 0; i < p_subresources.mipmap_count; i++) {
4047
D3D12_DEPTH_STENCIL_VIEW_DESC dsv_desc = _make_dsv_for_texture(tex_info, p_subresources.base_mipmap + i, p_subresources.base_layer, p_subresources.layer_count, false);
4048
device->CreateDepthStencilView(
4049
tex_info->resource,
4050
&dsv_desc,
4051
cmd_buf_info->dsv_alloc.cpu_handle);
4052
4053
cmd_buf_info->cmd_list->ClearDepthStencilView(
4054
cmd_buf_info->dsv_alloc.cpu_handle,
4055
clear_flags,
4056
p_depth,
4057
p_stencil,
4058
0,
4059
nullptr);
4060
}
4061
} else {
4062
ERR_FAIL_MSG("Cannot clear depth because the texture was not created with the depth attachment bit. You'll need to update its contents through another method.");
4063
}
4064
}
4065
4066
void RenderingDeviceDriverD3D12::command_copy_buffer_to_texture(CommandBufferID p_cmd_buffer, BufferID p_src_buffer, TextureID p_dst_texture, TextureLayout p_dst_texture_layout, VectorView<BufferTextureCopyRegion> p_regions) {
4067
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4068
BufferInfo *buf_info = (BufferInfo *)p_src_buffer.id;
4069
TextureInfo *tex_info = (TextureInfo *)p_dst_texture.id;
4070
4071
if (!barrier_capabilities.enhanced_barriers_supported) {
4072
_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
4073
}
4074
4075
uint32_t block_w = 0, block_h = 0;
4076
get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h);
4077
4078
for (uint32_t i = 0; i < p_regions.size(); i++) {
4079
DEV_ASSERT((p_regions[i].buffer_offset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1)) == 0 && "Buffer offset must be aligned to 512 bytes. See API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT.");
4080
DEV_ASSERT((p_regions[i].row_pitch & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) == 0 && "Row pitch must be aligned to 256 bytes. See API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP.");
4081
4082
D3D12_PLACED_SUBRESOURCE_FOOTPRINT src_footprint = {};
4083
src_footprint.Offset = p_regions[i].buffer_offset;
4084
src_footprint.Footprint = CD3DX12_SUBRESOURCE_FOOTPRINT(
4085
RD_TO_D3D12_FORMAT[tex_info->format].family,
4086
STEPIFY(p_regions[i].texture_region_size.x, block_w),
4087
STEPIFY(p_regions[i].texture_region_size.y, block_h),
4088
p_regions[i].texture_region_size.z,
4089
p_regions[i].row_pitch);
4090
4091
CD3DX12_TEXTURE_COPY_LOCATION copy_src(buf_info->resource, src_footprint);
4092
4093
UINT dst_subresource = D3D12CalcSubresource(
4094
p_regions[i].texture_subresource.mipmap,
4095
p_regions[i].texture_subresource.layer,
4096
_compute_plane_slice(tex_info->format, p_regions[i].texture_subresource.aspect),
4097
tex_info->desc.MipLevels,
4098
tex_info->desc.ArraySize());
4099
4100
if (!barrier_capabilities.enhanced_barriers_supported) {
4101
_resource_transition_batch(cmd_buf_info, tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_COPY_DEST);
4102
_resource_transitions_flush(cmd_buf_info);
4103
}
4104
4105
CD3DX12_TEXTURE_COPY_LOCATION copy_dst(tex_info->resource, dst_subresource);
4106
4107
cmd_buf_info->cmd_list->CopyTextureRegion(
4108
&copy_dst,
4109
p_regions[i].texture_offset.x,
4110
p_regions[i].texture_offset.y,
4111
p_regions[i].texture_offset.z,
4112
&copy_src,
4113
nullptr);
4114
}
4115
}
4116
4117
void RenderingDeviceDriverD3D12::command_copy_texture_to_buffer(CommandBufferID p_cmd_buffer, TextureID p_src_texture, TextureLayout p_src_texture_layout, BufferID p_buf_locfer, VectorView<BufferTextureCopyRegion> p_regions) {
4118
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4119
TextureInfo *tex_info = (TextureInfo *)p_src_texture.id;
4120
BufferInfo *buf_info = (BufferInfo *)p_buf_locfer.id;
4121
4122
if (!barrier_capabilities.enhanced_barriers_supported) {
4123
_resource_transition_batch(cmd_buf_info, buf_info, 0, 1, D3D12_RESOURCE_STATE_COPY_DEST);
4124
}
4125
4126
uint32_t block_w = 0, block_h = 0;
4127
get_compressed_image_format_block_dimensions(tex_info->format, block_w, block_h);
4128
4129
for (uint32_t i = 0; i < p_regions.size(); i++) {
4130
DEV_ASSERT((p_regions[i].buffer_offset & (D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT - 1)) == 0 && "Buffer offset must be aligned to 512 bytes. See API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT.");
4131
DEV_ASSERT((p_regions[i].row_pitch & (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) == 0 && "Row pitch must be aligned to 256 bytes. See API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP.");
4132
4133
UINT src_subresource = D3D12CalcSubresource(
4134
p_regions[i].texture_subresource.mipmap,
4135
p_regions[i].texture_subresource.layer,
4136
_compute_plane_slice(tex_info->format, p_regions[i].texture_subresource.aspect),
4137
tex_info->desc.MipLevels,
4138
tex_info->desc.ArraySize());
4139
4140
if (!barrier_capabilities.enhanced_barriers_supported) {
4141
_resource_transition_batch(cmd_buf_info, tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_COPY_SOURCE);
4142
_resource_transitions_flush(cmd_buf_info);
4143
}
4144
4145
CD3DX12_TEXTURE_COPY_LOCATION copy_src(tex_info->resource, src_subresource);
4146
4147
CD3DX12_BOX src_box(
4148
p_regions[i].texture_offset.x,
4149
p_regions[i].texture_offset.y,
4150
p_regions[i].texture_offset.z,
4151
p_regions[i].texture_offset.x + STEPIFY(p_regions[i].texture_region_size.x, block_w),
4152
p_regions[i].texture_offset.y + STEPIFY(p_regions[i].texture_region_size.y, block_h),
4153
p_regions[i].texture_offset.z + p_regions[i].texture_region_size.z);
4154
4155
bool full_box =
4156
src_box.left == 0 &&
4157
src_box.top == 0 &&
4158
src_box.front == 0 &&
4159
src_box.right == tex_info->desc.Width &&
4160
src_box.bottom == tex_info->desc.Height &&
4161
src_box.back == tex_info->desc.Depth();
4162
4163
D3D12_PLACED_SUBRESOURCE_FOOTPRINT dst_footprint = {};
4164
dst_footprint.Offset = p_regions[i].buffer_offset;
4165
dst_footprint.Footprint.Format = RD_TO_D3D12_FORMAT[tex_info->format].family;
4166
dst_footprint.Footprint.Width = STEPIFY(p_regions[i].texture_region_size.x, block_w);
4167
dst_footprint.Footprint.Height = STEPIFY(p_regions[i].texture_region_size.y, block_h);
4168
dst_footprint.Footprint.Depth = p_regions[i].texture_region_size.z;
4169
dst_footprint.Footprint.RowPitch = p_regions[i].row_pitch;
4170
4171
CD3DX12_TEXTURE_COPY_LOCATION copy_dst(buf_info->resource, dst_footprint);
4172
4173
cmd_buf_info->cmd_list->CopyTextureRegion(
4174
&copy_dst,
4175
0,
4176
0,
4177
0,
4178
&copy_src,
4179
full_box ? nullptr : &src_box);
4180
}
4181
}
4182
4183
/******************/
4184
/**** PIPELINE ****/
4185
/******************/
4186
4187
void RenderingDeviceDriverD3D12::pipeline_free(PipelineID p_pipeline) {
4188
PipelineInfo *pipeline_info = (PipelineInfo *)(p_pipeline.id);
4189
memdelete(pipeline_info);
4190
}
4191
4192
// ----- BINDING -----
4193
4194
void RenderingDeviceDriverD3D12::command_bind_push_constants(CommandBufferID p_cmd_buffer, ShaderID p_shader, uint32_t p_dst_first_index, VectorView<uint32_t> p_data) {
4195
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
4196
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
4197
if (!shader_info_in->dxil_push_constant_size) {
4198
return;
4199
}
4200
if (shader_info_in->pipeline_type == PIPELINE_TYPE_COMPUTE) {
4201
cmd_buf_info->cmd_list->SetComputeRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);
4202
} else if (shader_info_in->pipeline_type == PIPELINE_TYPE_RASTERIZATION) {
4203
cmd_buf_info->cmd_list->SetGraphicsRoot32BitConstants(0, p_data.size(), p_data.ptr(), p_dst_first_index);
4204
} else if (shader_info_in->pipeline_type == PIPELINE_TYPE_RAYTRACING) {
4205
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
4206
} else {
4207
ERR_FAIL_MSG("This pipeline type is not currently supported by the D3D12 driver.");
4208
}
4209
}
4210
4211
// ----- CACHE -----
4212
4213
bool RenderingDeviceDriverD3D12::pipeline_cache_create(const Vector<uint8_t> &p_data) {
4214
return false;
4215
}
4216
4217
void RenderingDeviceDriverD3D12::pipeline_cache_free() {
4218
ERR_FAIL_MSG("Not implemented.");
4219
}
4220
4221
size_t RenderingDeviceDriverD3D12::pipeline_cache_query_size() {
4222
ERR_FAIL_V_MSG(0, "Not implemented.");
4223
}
4224
4225
Vector<uint8_t> RenderingDeviceDriverD3D12::pipeline_cache_serialize() {
4226
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Not implemented.");
4227
}
4228
4229
/*******************/
4230
/**** RENDERING ****/
4231
/*******************/
4232
4233
// ----- SUBPASS -----
4234
4235
RDD::RenderPassID RenderingDeviceDriverD3D12::render_pass_create(VectorView<Attachment> p_attachments, VectorView<Subpass> p_subpasses, VectorView<SubpassDependency> p_subpass_dependencies, uint32_t p_view_count, AttachmentReference p_fragment_density_map_attachment) {
4236
ERR_FAIL_COND_V_MSG(p_fragment_density_map_attachment.attachment != AttachmentReference::UNUSED, RenderPassID(), "Fragment density maps are not supported in D3D12.");
4237
4238
// Pre-bookkeep.
4239
RenderPassInfo *pass_info = VersatileResource::allocate<RenderPassInfo>(resources_allocator);
4240
4241
pass_info->attachments.resize(p_attachments.size());
4242
for (uint32_t i = 0; i < p_attachments.size(); i++) {
4243
pass_info->attachments[i] = p_attachments[i];
4244
}
4245
4246
pass_info->subpasses.resize(p_subpasses.size());
4247
for (uint32_t i = 0; i < p_subpasses.size(); i++) {
4248
pass_info->subpasses[i] = p_subpasses[i];
4249
}
4250
4251
pass_info->view_count = p_view_count;
4252
4253
DXGI_FORMAT *formats = ALLOCA_ARRAY(DXGI_FORMAT, p_attachments.size());
4254
for (uint32_t i = 0; i < p_attachments.size(); i++) {
4255
const D3D12Format &format = RD_TO_D3D12_FORMAT[p_attachments[i].format];
4256
if (format.dsv_format != DXGI_FORMAT_UNKNOWN) {
4257
formats[i] = format.dsv_format;
4258
} else {
4259
formats[i] = format.general_format;
4260
}
4261
}
4262
pass_info->max_supported_sample_count = _find_max_common_supported_sample_count(VectorView(formats, p_attachments.size()));
4263
4264
return RenderPassID(pass_info);
4265
}
4266
4267
void RenderingDeviceDriverD3D12::render_pass_free(RenderPassID p_render_pass) {
4268
RenderPassInfo *pass_info = (RenderPassInfo *)p_render_pass.id;
4269
VersatileResource::free(resources_allocator, pass_info);
4270
}
4271
4272
// ----- COMMANDS -----
4273
4274
void RenderingDeviceDriverD3D12::command_begin_render_pass(CommandBufferID p_cmd_buffer, RenderPassID p_render_pass, FramebufferID p_framebuffer, CommandBufferType p_cmd_buffer_type, const Rect2i &p_rect, VectorView<RenderPassClearValue> p_attachment_clears) {
4275
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4276
const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
4277
const FramebufferInfo *fb_info = (const FramebufferInfo *)p_framebuffer.id;
4278
4279
DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass == UINT32_MAX);
4280
4281
auto _transition_subresources = [&](TextureInfo *p_texture_info, D3D12_RESOURCE_STATES p_states) {
4282
uint32_t planes = 1;
4283
if ((p_texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
4284
planes = format_get_plane_count(p_texture_info->format);
4285
}
4286
for (uint32_t i = 0; i < p_texture_info->layers; i++) {
4287
for (uint32_t j = 0; j < p_texture_info->mipmaps; j++) {
4288
uint32_t subresource = D3D12CalcSubresource(
4289
p_texture_info->base_mip + j,
4290
p_texture_info->base_layer + i,
4291
0,
4292
p_texture_info->desc.MipLevels,
4293
p_texture_info->desc.ArraySize());
4294
4295
_resource_transition_batch(cmd_buf_info, p_texture_info, subresource, planes, p_states);
4296
}
4297
}
4298
};
4299
4300
if (fb_info->is_screen || !barrier_capabilities.enhanced_barriers_supported) {
4301
// Screen framebuffers must perform this transition even if enhanced barriers are supported.
4302
for (uint32_t i = 0; i < fb_info->attachments.size(); i++) {
4303
TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;
4304
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
4305
_transition_subresources(tex_info, D3D12_RESOURCE_STATE_RENDER_TARGET);
4306
} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
4307
_transition_subresources(tex_info, D3D12_RESOURCE_STATE_DEPTH_WRITE);
4308
} else {
4309
DEV_ASSERT(false);
4310
}
4311
}
4312
if (fb_info->vrs_attachment) {
4313
TextureInfo *tex_info = (TextureInfo *)fb_info->vrs_attachment.id;
4314
_transition_subresources(tex_info, D3D12_RESOURCE_STATE_SHADING_RATE_SOURCE);
4315
}
4316
4317
_resource_transitions_flush(cmd_buf_info);
4318
}
4319
4320
cmd_buf_info->render_pass_state.region_rect = CD3DX12_RECT(
4321
p_rect.position.x,
4322
p_rect.position.y,
4323
p_rect.position.x + p_rect.size.x,
4324
p_rect.position.y + p_rect.size.y);
4325
cmd_buf_info->render_pass_state.region_is_all = (cmd_buf_info->render_pass_state.region_rect.left == 0 &&
4326
cmd_buf_info->render_pass_state.region_rect.top == 0 &&
4327
cmd_buf_info->render_pass_state.region_rect.right == fb_info->size.x &&
4328
cmd_buf_info->render_pass_state.region_rect.bottom == fb_info->size.y);
4329
4330
cmd_buf_info->render_pass_state.attachment_layouts.resize(pass_info->attachments.size());
4331
4332
for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
4333
const Attachment &attachment = pass_info->attachments[i];
4334
4335
for (RenderPassState::AttachmentLayout::AspectLayout &aspect_layout : cmd_buf_info->render_pass_state.attachment_layouts[i].aspect_layouts) {
4336
aspect_layout.cur_layout = attachment.initial_layout;
4337
aspect_layout.expected_layout = attachment.initial_layout;
4338
}
4339
4340
if (attachment.load_op == ATTACHMENT_LOAD_OP_DONT_CARE) {
4341
const TextureInfo *tex_info = (const TextureInfo *)fb_info->attachments[i].id;
4342
_discard_texture_subresources(tex_info, cmd_buf_info);
4343
}
4344
}
4345
4346
if (fb_info->vrs_attachment && fsr_capabilities.attachment_supported) {
4347
static const D3D12_SHADING_RATE_COMBINER COMBINERS[D3D12_RS_SET_SHADING_RATE_COMBINER_COUNT] = {
4348
D3D12_SHADING_RATE_COMBINER_PASSTHROUGH,
4349
D3D12_SHADING_RATE_COMBINER_OVERRIDE,
4350
};
4351
cmd_buf_info->cmd_list_5->RSSetShadingRate(D3D12_SHADING_RATE_1X1, COMBINERS);
4352
}
4353
4354
cmd_buf_info->render_pass_state.current_subpass = UINT32_MAX;
4355
cmd_buf_info->render_pass_state.fb_info = fb_info;
4356
cmd_buf_info->render_pass_state.pass_info = pass_info;
4357
command_next_render_subpass(p_cmd_buffer, p_cmd_buffer_type);
4358
4359
AttachmentClear *clears = ALLOCA_ARRAY(AttachmentClear, pass_info->attachments.size());
4360
uint32_t num_clears = 0;
4361
4362
for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
4363
TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;
4364
if (!tex_info) {
4365
continue;
4366
}
4367
4368
AttachmentClear clear;
4369
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
4370
if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) {
4371
clear.aspect.set_flag(TEXTURE_ASPECT_COLOR_BIT);
4372
clear.color_attachment = i;
4373
}
4374
} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
4375
if (pass_info->attachments[i].load_op == ATTACHMENT_LOAD_OP_CLEAR) {
4376
clear.aspect.set_flag(TEXTURE_ASPECT_DEPTH_BIT);
4377
}
4378
if (pass_info->attachments[i].stencil_load_op == ATTACHMENT_LOAD_OP_CLEAR) {
4379
clear.aspect.set_flag(TEXTURE_ASPECT_STENCIL_BIT);
4380
}
4381
}
4382
if (!clear.aspect.is_empty()) {
4383
clear.value = p_attachment_clears[i];
4384
clears[num_clears] = clear;
4385
num_clears++;
4386
}
4387
}
4388
4389
if (num_clears) {
4390
command_render_clear_attachments(p_cmd_buffer, VectorView(clears, num_clears), VectorView(p_rect));
4391
}
4392
}
4393
4394
// Subpass dependencies cannot be specified by the end user, and by default they are very aggressive.
4395
// We can be more lenient by just looking at the texture layout and specifying appropriate access and stage bits.
4396
4397
// We specify full barrier for layouts we don't expect to see as fallback.
4398
static const BitField<RDD::BarrierAccessBits> RD_RENDER_PASS_LAYOUT_TO_ACCESS_BITS[RDD::TEXTURE_LAYOUT_MAX] = {
4399
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_UNDEFINED
4400
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_GENERAL
4401
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_STORAGE_OPTIMAL
4402
RDD::BARRIER_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
4403
RDD::BARRIER_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
4404
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
4405
RDD::BARRIER_ACCESS_SHADER_READ_BIT, // TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
4406
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_COPY_SRC_OPTIMAL
4407
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_COPY_DST_OPTIMAL
4408
RDD::BARRIER_ACCESS_RESOLVE_READ_BIT, // TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL
4409
RDD::BARRIER_ACCESS_RESOLVE_WRITE_BIT, // TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL
4410
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT, // TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL
4411
RDD::BARRIER_ACCESS_MEMORY_READ_BIT | RDD::BARRIER_ACCESS_MEMORY_WRITE_BIT // TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL
4412
};
4413
4414
// We specify all commands for layouts we don't expect to see as fallback.
4415
static const BitField<RDD::PipelineStageBits> RD_RENDER_PASS_LAYOUT_TO_STAGE_BITS[RDD::TEXTURE_LAYOUT_MAX] = {
4416
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_UNDEFINED
4417
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_GENERAL
4418
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_STORAGE_OPTIMAL
4419
RDD::PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
4420
RDD::PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | RDD::PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
4421
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
4422
RDD::PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // TEXTURE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
4423
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_COPY_SRC_OPTIMAL
4424
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_COPY_DST_OPTIMAL
4425
RDD::PIPELINE_STAGE_RESOLVE_BIT, // TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL
4426
RDD::PIPELINE_STAGE_RESOLVE_BIT, // TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL
4427
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT, // TEXTURE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL
4428
RDD::PIPELINE_STAGE_ALL_COMMANDS_BIT // TEXTURE_LAYOUT_FRAGMENT_DENSITY_MAP_ATTACHMENT_OPTIMAL
4429
};
4430
4431
void RenderingDeviceDriverD3D12::_render_pass_enhanced_barriers_flush(CommandBufferID p_cmd_buffer) {
4432
if (!barrier_capabilities.enhanced_barriers_supported) {
4433
return;
4434
}
4435
4436
BitField<PipelineStageBits> src_stages = {};
4437
BitField<PipelineStageBits> dst_stages = {};
4438
4439
thread_local LocalVector<TextureBarrier> texture_barriers;
4440
texture_barriers.clear();
4441
4442
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4443
4444
for (uint32_t i = 0; i < cmd_buf_info->render_pass_state.attachment_layouts.size(); i++) {
4445
RenderPassState::AttachmentLayout &attachment_layout = cmd_buf_info->render_pass_state.attachment_layouts[i];
4446
TextureID tex = cmd_buf_info->render_pass_state.fb_info->attachments[i];
4447
TextureInfo *tex_info = (TextureInfo *)tex.id;
4448
4449
for (uint32_t j = 0; j < TEXTURE_ASPECT_MAX; j++) {
4450
RenderPassState::AttachmentLayout::AspectLayout &aspect_layout = attachment_layout.aspect_layouts[j];
4451
4452
if (aspect_layout.cur_layout != aspect_layout.expected_layout) {
4453
src_stages = src_stages | RD_RENDER_PASS_LAYOUT_TO_STAGE_BITS[aspect_layout.cur_layout];
4454
dst_stages = dst_stages | RD_RENDER_PASS_LAYOUT_TO_STAGE_BITS[aspect_layout.expected_layout];
4455
4456
TextureBarrier texture_barrier;
4457
texture_barrier.texture = tex;
4458
texture_barrier.src_access = RD_RENDER_PASS_LAYOUT_TO_ACCESS_BITS[aspect_layout.cur_layout];
4459
texture_barrier.dst_access = RD_RENDER_PASS_LAYOUT_TO_ACCESS_BITS[aspect_layout.expected_layout];
4460
texture_barrier.prev_layout = aspect_layout.cur_layout;
4461
texture_barrier.next_layout = aspect_layout.expected_layout;
4462
texture_barrier.subresources.aspect = (TextureAspectBits)(1 << j);
4463
texture_barrier.subresources.base_mipmap = tex_info->base_mip;
4464
texture_barrier.subresources.mipmap_count = tex_info->mipmaps;
4465
texture_barrier.subresources.base_layer = tex_info->base_layer;
4466
texture_barrier.subresources.layer_count = tex_info->layers;
4467
texture_barriers.push_back(texture_barrier);
4468
4469
aspect_layout.cur_layout = aspect_layout.expected_layout;
4470
}
4471
}
4472
}
4473
4474
if (!texture_barriers.is_empty()) {
4475
command_pipeline_barrier(p_cmd_buffer, src_stages, dst_stages, VectorView<MemoryAccessBarrier>(), VectorView<BufferBarrier>(), texture_barriers, VectorView<AccelerationStructureBarrier>());
4476
}
4477
}
4478
4479
void RenderingDeviceDriverD3D12::_end_render_pass(CommandBufferID p_cmd_buffer) {
4480
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4481
4482
DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
4483
4484
const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
4485
const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
4486
const Subpass &subpass = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass];
4487
4488
if (fb_info->is_screen) {
4489
// Screen framebuffers must transition back to present state when the render pass is finished.
4490
for (uint32_t i = 0; i < fb_info->attachments.size(); i++) {
4491
TextureInfo *src_tex_info = (TextureInfo *)(fb_info->attachments[i].id);
4492
uint32_t src_subresource = D3D12CalcSubresource(src_tex_info->base_mip, src_tex_info->base_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
4493
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_PRESENT);
4494
}
4495
}
4496
4497
struct Resolve {
4498
ID3D12Resource *src_res = nullptr;
4499
uint32_t src_subres = 0;
4500
ID3D12Resource *dst_res = nullptr;
4501
uint32_t dst_subres = 0;
4502
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
4503
};
4504
Resolve *resolves = ALLOCA_ARRAY(Resolve, subpass.resolve_references.size());
4505
uint32_t num_resolves = 0;
4506
4507
for (uint32_t i = 0; i < subpass.resolve_references.size(); i++) {
4508
uint32_t color_index = subpass.color_references[i].attachment;
4509
uint32_t resolve_index = subpass.resolve_references[i].attachment;
4510
DEV_ASSERT((color_index == AttachmentReference::UNUSED) == (resolve_index == AttachmentReference::UNUSED));
4511
if (color_index == AttachmentReference::UNUSED || !fb_info->attachments[color_index]) {
4512
continue;
4513
}
4514
4515
TextureInfo *src_tex_info = (TextureInfo *)fb_info->attachments[color_index].id;
4516
uint32_t src_subresource = D3D12CalcSubresource(src_tex_info->base_mip, src_tex_info->base_layer, 0, src_tex_info->desc.MipLevels, src_tex_info->desc.ArraySize());
4517
4518
if (barrier_capabilities.enhanced_barriers_supported) {
4519
cmd_buf_info->render_pass_state.attachment_layouts[color_index].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout = TEXTURE_LAYOUT_RESOLVE_SRC_OPTIMAL;
4520
} else {
4521
_resource_transition_batch(cmd_buf_info, src_tex_info, src_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
4522
}
4523
4524
TextureInfo *dst_tex_info = (TextureInfo *)fb_info->attachments[resolve_index].id;
4525
uint32_t dst_subresource = D3D12CalcSubresource(dst_tex_info->base_mip, dst_tex_info->base_layer, 0, dst_tex_info->desc.MipLevels, dst_tex_info->desc.ArraySize());
4526
4527
if (barrier_capabilities.enhanced_barriers_supported) {
4528
// This should have already been done when beginning the subpass.
4529
DEV_ASSERT(cmd_buf_info->render_pass_state.attachment_layouts[resolve_index].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout == TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL);
4530
} else {
4531
_resource_transition_batch(cmd_buf_info, dst_tex_info, dst_subresource, 1, D3D12_RESOURCE_STATE_RESOLVE_DEST);
4532
}
4533
4534
resolves[num_resolves].src_res = src_tex_info->resource;
4535
resolves[num_resolves].src_subres = src_subresource;
4536
resolves[num_resolves].dst_res = dst_tex_info->resource;
4537
resolves[num_resolves].dst_subres = dst_subresource;
4538
resolves[num_resolves].format = RD_TO_D3D12_FORMAT[src_tex_info->format].general_format;
4539
num_resolves++;
4540
}
4541
4542
_resource_transitions_flush(cmd_buf_info);
4543
4544
// There can be enhanced barriers to flush only when we need to resolve textures.
4545
if (num_resolves != 0) {
4546
_render_pass_enhanced_barriers_flush(p_cmd_buffer);
4547
}
4548
4549
for (uint32_t i = 0; i < num_resolves; i++) {
4550
cmd_buf_info->cmd_list->ResolveSubresource(resolves[i].dst_res, resolves[i].dst_subres, resolves[i].src_res, resolves[i].src_subres, resolves[i].format);
4551
}
4552
}
4553
4554
void RenderingDeviceDriverD3D12::command_end_render_pass(CommandBufferID p_cmd_buffer) {
4555
_end_render_pass(p_cmd_buffer);
4556
4557
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4558
DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
4559
4560
const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
4561
const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
4562
4563
if (fb_info->vrs_attachment && fsr_capabilities.attachment_supported) {
4564
cmd_buf_info->cmd_list_5->RSSetShadingRateImage(nullptr);
4565
}
4566
4567
auto _transition_subresources = [&](TextureInfo *p_texture_info, D3D12_RESOURCE_STATES p_states) {
4568
uint32_t planes = 1;
4569
if ((p_texture_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
4570
planes = format_get_plane_count(p_texture_info->format);
4571
}
4572
for (uint32_t i = 0; i < p_texture_info->layers; i++) {
4573
for (uint32_t j = 0; j < p_texture_info->mipmaps; j++) {
4574
uint32_t subresource = D3D12CalcSubresource(
4575
p_texture_info->base_mip + j,
4576
p_texture_info->base_layer + i,
4577
0,
4578
p_texture_info->desc.MipLevels,
4579
p_texture_info->desc.ArraySize());
4580
4581
_resource_transition_batch(cmd_buf_info, p_texture_info, subresource, planes, p_states);
4582
}
4583
}
4584
};
4585
4586
if (!barrier_capabilities.enhanced_barriers_supported) {
4587
for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
4588
if (pass_info->attachments[i].store_op == ATTACHMENT_STORE_OP_DONT_CARE) {
4589
TextureInfo *tex_info = (TextureInfo *)fb_info->attachments[i].id;
4590
if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET)) {
4591
_transition_subresources(tex_info, D3D12_RESOURCE_STATE_RENDER_TARGET);
4592
} else if ((tex_info->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) {
4593
_transition_subresources(tex_info, D3D12_RESOURCE_STATE_DEPTH_WRITE);
4594
} else {
4595
DEV_ASSERT(false);
4596
}
4597
}
4598
}
4599
4600
_resource_transitions_flush(cmd_buf_info);
4601
}
4602
4603
for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
4604
const Attachment &attachment = pass_info->attachments[i];
4605
4606
for (RenderPassState::AttachmentLayout::AspectLayout &aspect_layout : cmd_buf_info->render_pass_state.attachment_layouts[i].aspect_layouts) {
4607
aspect_layout.expected_layout = attachment.final_layout;
4608
}
4609
}
4610
4611
_render_pass_enhanced_barriers_flush(p_cmd_buffer);
4612
4613
for (uint32_t i = 0; i < pass_info->attachments.size(); i++) {
4614
if (pass_info->attachments[i].store_op == ATTACHMENT_STORE_OP_DONT_CARE) {
4615
const TextureInfo *tex_info = (const TextureInfo *)fb_info->attachments[i].id;
4616
_discard_texture_subresources(tex_info, cmd_buf_info);
4617
}
4618
}
4619
4620
cmd_buf_info->render_pass_state.current_subpass = UINT32_MAX;
4621
}
4622
4623
void RenderingDeviceDriverD3D12::command_next_render_subpass(CommandBufferID p_cmd_buffer, CommandBufferType p_cmd_buffer_type) {
4624
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4625
4626
if (cmd_buf_info->render_pass_state.current_subpass == UINT32_MAX) {
4627
cmd_buf_info->render_pass_state.current_subpass = 0;
4628
} else {
4629
_end_render_pass(p_cmd_buffer);
4630
cmd_buf_info->render_pass_state.current_subpass++;
4631
}
4632
4633
const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
4634
const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
4635
const Subpass &subpass = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass];
4636
4637
for (uint32_t i = 0; i < subpass.input_references.size(); i++) {
4638
const AttachmentReference &input_reference = subpass.input_references[i];
4639
uint32_t attachment = input_reference.attachment;
4640
4641
if (attachment != AttachmentReference::UNUSED) {
4642
RenderPassState::AttachmentLayout &attachment_layout = cmd_buf_info->render_pass_state.attachment_layouts[attachment];
4643
4644
// Vulkan cares about aspect bits only for input attachments.
4645
for (uint32_t j = 0; j < TEXTURE_ASPECT_MAX; j++) {
4646
if (input_reference.aspect & (1 << j)) {
4647
attachment_layout.aspect_layouts[j].expected_layout = input_reference.layout;
4648
}
4649
}
4650
}
4651
}
4652
4653
D3D12_CPU_DESCRIPTOR_HANDLE *rtv_handles = ALLOCA_ARRAY(D3D12_CPU_DESCRIPTOR_HANDLE, subpass.color_references.size());
4654
for (uint32_t i = 0; i < subpass.color_references.size(); i++) {
4655
const AttachmentReference &color_reference = subpass.color_references[i];
4656
uint32_t attachment = color_reference.attachment;
4657
if (attachment == AttachmentReference::UNUSED) {
4658
rtv_handles[i] = null_rtv_alloc.cpu_handle;
4659
} else {
4660
uint32_t rt_index = fb_info->attachments_handle_inds[attachment];
4661
rtv_handles[i] = get_cpu_handle(fb_info->rtv_alloc.cpu_handle, rt_index, rtv_descriptor_heap_pool.increment_size);
4662
4663
cmd_buf_info->render_pass_state.attachment_layouts[attachment].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout = color_reference.layout;
4664
}
4665
}
4666
4667
D3D12_CPU_DESCRIPTOR_HANDLE dsv_handle = {};
4668
{
4669
if (subpass.depth_stencil_reference.attachment != AttachmentReference::UNUSED) {
4670
uint32_t ds_index = fb_info->attachments_handle_inds[subpass.depth_stencil_reference.attachment];
4671
dsv_handle = get_cpu_handle(fb_info->dsv_alloc.cpu_handle, ds_index, dsv_descriptor_heap_pool.increment_size);
4672
4673
RenderPassState::AttachmentLayout &attachment_layout = cmd_buf_info->render_pass_state.attachment_layouts[subpass.depth_stencil_reference.attachment];
4674
attachment_layout.aspect_layouts[TEXTURE_ASPECT_DEPTH].expected_layout = subpass.depth_stencil_reference.layout;
4675
attachment_layout.aspect_layouts[TEXTURE_ASPECT_STENCIL].expected_layout = subpass.depth_stencil_reference.layout;
4676
}
4677
}
4678
4679
for (uint32_t i = 0; i < subpass.resolve_references.size(); i++) {
4680
const AttachmentReference &resolve_reference = subpass.resolve_references[i];
4681
uint32_t attachment = resolve_reference.attachment;
4682
4683
if (attachment != AttachmentReference::UNUSED) {
4684
// Vulkan expects the layout to be in color attachment layout, but D3D12 wants resolve destination.
4685
DEV_ASSERT(resolve_reference.layout == TEXTURE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
4686
cmd_buf_info->render_pass_state.attachment_layouts[attachment].aspect_layouts[TEXTURE_ASPECT_COLOR].expected_layout = TEXTURE_LAYOUT_RESOLVE_DST_OPTIMAL;
4687
}
4688
}
4689
4690
_render_pass_enhanced_barriers_flush(p_cmd_buffer);
4691
4692
cmd_buf_info->cmd_list->OMSetRenderTargets(subpass.color_references.size(), rtv_handles, false, dsv_handle.ptr ? &dsv_handle : nullptr);
4693
}
4694
4695
void RenderingDeviceDriverD3D12::command_render_set_viewport(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_viewports) {
4696
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
4697
4698
D3D12_VIEWPORT *d3d12_viewports = ALLOCA_ARRAY(D3D12_VIEWPORT, p_viewports.size());
4699
for (uint32_t i = 0; i < p_viewports.size(); i++) {
4700
d3d12_viewports[i] = CD3DX12_VIEWPORT(
4701
p_viewports[i].position.x,
4702
p_viewports[i].position.y,
4703
p_viewports[i].size.x,
4704
p_viewports[i].size.y);
4705
}
4706
4707
cmd_buf_info->cmd_list->RSSetViewports(p_viewports.size(), d3d12_viewports);
4708
}
4709
4710
void RenderingDeviceDriverD3D12::command_render_set_scissor(CommandBufferID p_cmd_buffer, VectorView<Rect2i> p_scissors) {
4711
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
4712
4713
D3D12_RECT *d3d12_scissors = ALLOCA_ARRAY(D3D12_RECT, p_scissors.size());
4714
for (uint32_t i = 0; i < p_scissors.size(); i++) {
4715
d3d12_scissors[i] = CD3DX12_RECT(
4716
p_scissors[i].position.x,
4717
p_scissors[i].position.y,
4718
p_scissors[i].position.x + p_scissors[i].size.x,
4719
p_scissors[i].position.y + p_scissors[i].size.y);
4720
}
4721
4722
cmd_buf_info->cmd_list->RSSetScissorRects(p_scissors.size(), d3d12_scissors);
4723
}
4724
4725
void RenderingDeviceDriverD3D12::command_render_clear_attachments(CommandBufferID p_cmd_buffer, VectorView<AttachmentClear> p_attachment_clears, VectorView<Rect2i> p_rects) {
4726
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
4727
4728
DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
4729
const FramebufferInfo *fb_info = cmd_buf_info->render_pass_state.fb_info;
4730
const RenderPassInfo *pass_info = cmd_buf_info->render_pass_state.pass_info;
4731
4732
for (uint32_t i = 0; i < p_attachment_clears.size(); i++) {
4733
uint32_t attachment = UINT32_MAX;
4734
bool is_render_target = false;
4735
if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_COLOR_BIT)) {
4736
attachment = p_attachment_clears[i].color_attachment;
4737
is_render_target = true;
4738
} else {
4739
attachment = pass_info->subpasses[cmd_buf_info->render_pass_state.current_subpass].depth_stencil_reference.attachment;
4740
}
4741
4742
for (uint32_t j = 0; j < p_rects.size(); j++) {
4743
D3D12_RECT rect = CD3DX12_RECT(
4744
p_rects[j].position.x,
4745
p_rects[j].position.y,
4746
p_rects[j].position.x + p_rects[j].size.x,
4747
p_rects[j].position.y + p_rects[j].size.y);
4748
const D3D12_RECT *rect_ptr = cmd_buf_info->render_pass_state.region_is_all ? nullptr : &rect;
4749
4750
if (is_render_target) {
4751
uint32_t color_idx = fb_info->attachments_handle_inds[attachment];
4752
cmd_buf_info->cmd_list->ClearRenderTargetView(
4753
get_cpu_handle(fb_info->rtv_alloc.cpu_handle, color_idx, rtv_descriptor_heap_pool.increment_size),
4754
p_attachment_clears[i].value.color.components,
4755
rect_ptr ? 1 : 0,
4756
rect_ptr);
4757
} else {
4758
uint32_t depth_stencil_idx = fb_info->attachments_handle_inds[attachment];
4759
D3D12_CLEAR_FLAGS flags = {};
4760
if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_DEPTH_BIT)) {
4761
flags |= D3D12_CLEAR_FLAG_DEPTH;
4762
}
4763
if (p_attachment_clears[i].aspect.has_flag(TEXTURE_ASPECT_STENCIL_BIT)) {
4764
flags |= D3D12_CLEAR_FLAG_STENCIL;
4765
}
4766
cmd_buf_info->cmd_list->ClearDepthStencilView(
4767
get_cpu_handle(fb_info->dsv_alloc.cpu_handle, depth_stencil_idx, dsv_descriptor_heap_pool.increment_size),
4768
flags,
4769
p_attachment_clears[i].value.depth,
4770
p_attachment_clears[i].value.stencil,
4771
rect_ptr ? 1 : 0,
4772
rect_ptr);
4773
}
4774
}
4775
}
4776
}
4777
4778
void RenderingDeviceDriverD3D12::command_bind_render_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
4779
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4780
4781
const PipelineInfo *pipeline_info = (const PipelineInfo *)p_pipeline.id;
4782
const ShaderInfo *shader_info_in = pipeline_info->shader_info;
4783
const RenderPipelineInfo &render_info = pipeline_info->render_info;
4784
4785
if (cmd_buf_info->graphics_pso != pipeline_info->pso.Get()) {
4786
cmd_buf_info->cmd_list->SetPipelineState(pipeline_info->pso.Get());
4787
4788
cmd_buf_info->graphics_pso = pipeline_info->pso.Get();
4789
cmd_buf_info->compute_pso = nullptr;
4790
}
4791
4792
if (cmd_buf_info->graphics_root_signature_crc != shader_info_in->root_signature_crc) {
4793
cmd_buf_info->cmd_list->SetGraphicsRootSignature(shader_info_in->root_signature.Get());
4794
cmd_buf_info->graphics_root_signature_crc = shader_info_in->root_signature_crc;
4795
}
4796
4797
if (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.primitive_topology != render_info.dyn_params.primitive_topology)) {
4798
cmd_buf_info->cmd_list->IASetPrimitiveTopology(render_info.dyn_params.primitive_topology);
4799
cmd_buf_info->dyn_params.primitive_topology = render_info.dyn_params.primitive_topology;
4800
}
4801
4802
if (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.blend_constant != render_info.dyn_params.blend_constant)) {
4803
cmd_buf_info->cmd_list->OMSetBlendFactor(render_info.dyn_params.blend_constant.components);
4804
cmd_buf_info->dyn_params.blend_constant = render_info.dyn_params.blend_constant;
4805
}
4806
4807
if (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.stencil_reference != render_info.dyn_params.stencil_reference)) {
4808
cmd_buf_info->cmd_list->OMSetStencilRef(render_info.dyn_params.stencil_reference);
4809
cmd_buf_info->dyn_params.stencil_reference = render_info.dyn_params.stencil_reference;
4810
}
4811
4812
if (misc_features_support.depth_bounds_supported && (cmd_buf_info->pending_dyn_params || (cmd_buf_info->dyn_params.depth_bounds_min != render_info.dyn_params.depth_bounds_min) || (cmd_buf_info->dyn_params.depth_bounds_max != render_info.dyn_params.depth_bounds_max))) {
4813
cmd_buf_info->cmd_list_1->OMSetDepthBounds(render_info.dyn_params.depth_bounds_min, render_info.dyn_params.depth_bounds_max);
4814
cmd_buf_info->dyn_params.depth_bounds_min = render_info.dyn_params.depth_bounds_min;
4815
cmd_buf_info->dyn_params.depth_bounds_max = render_info.dyn_params.depth_bounds_max;
4816
}
4817
4818
cmd_buf_info->pending_dyn_params = false;
4819
cmd_buf_info->render_pass_state.vf_info = render_info.vf_info;
4820
}
4821
4822
void RenderingDeviceDriverD3D12::command_bind_render_uniform_sets(CommandBufferID p_cmd_buffer, VectorView<UniformSetID> p_uniform_sets, ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets) {
4823
_command_check_descriptor_sets(p_cmd_buffer);
4824
4825
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
4826
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
4827
4828
for (uint32_t i = 0u; i < p_set_count; ++i) {
4829
UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_sets[i].id;
4830
const ShaderInfo::UniformSet &uniform_set_shader_info = shader_info_in->sets[p_first_set_index + i];
4831
4832
for (const UniformSetInfo::DynamicBuffer &dynamic_buffer : uniform_set_info->dynamic_buffers) {
4833
uint32_t frame_index = p_dynamic_offsets & 0xF;
4834
p_dynamic_offsets >>= 4;
4835
4836
const ShaderInfo::UniformBindingInfo &binding = uniform_set_shader_info.bindings[dynamic_buffer.binding];
4837
if (binding.root_param_idx != UINT_MAX) {
4838
D3D12_GPU_VIRTUAL_ADDRESS buffer_location = dynamic_buffer.info->gpu_virtual_address + (dynamic_buffer.info->size * frame_index);
4839
switch (binding.res_class) {
4840
case RES_CLASS_INVALID: {
4841
} break;
4842
case RES_CLASS_CBV: {
4843
cmd_buf_info->cmd_list->SetGraphicsRootConstantBufferView(binding.root_param_idx, buffer_location);
4844
} break;
4845
case RES_CLASS_SRV: {
4846
cmd_buf_info->cmd_list->SetGraphicsRootShaderResourceView(binding.root_param_idx, buffer_location);
4847
} break;
4848
case RES_CLASS_UAV: {
4849
cmd_buf_info->cmd_list->SetGraphicsRootUnorderedAccessView(binding.root_param_idx, buffer_location);
4850
} break;
4851
}
4852
}
4853
}
4854
4855
if (uniform_set_shader_info.resource_root_param_idx != UINT_MAX) {
4856
cmd_buf_info->cmd_list->SetGraphicsRootDescriptorTable(uniform_set_shader_info.resource_root_param_idx, uniform_set_info->resource_descriptor_heap_alloc.gpu_handle);
4857
}
4858
if (uniform_set_shader_info.sampler_root_param_idx != UINT_MAX) {
4859
cmd_buf_info->cmd_list->SetGraphicsRootDescriptorTable(uniform_set_shader_info.sampler_root_param_idx, uniform_set_info->sampler_descriptor_heap_alloc->gpu_handle);
4860
}
4861
}
4862
}
4863
4864
void RenderingDeviceDriverD3D12::command_render_draw(CommandBufferID p_cmd_buffer, uint32_t p_vertex_count, uint32_t p_instance_count, uint32_t p_base_vertex, uint32_t p_first_instance) {
4865
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4866
_bind_vertex_buffers(cmd_buf_info);
4867
cmd_buf_info->cmd_list->DrawInstanced(p_vertex_count, p_instance_count, p_base_vertex, p_first_instance);
4868
}
4869
4870
void RenderingDeviceDriverD3D12::command_render_draw_indexed(CommandBufferID p_cmd_buffer, uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index, int32_t p_vertex_offset, uint32_t p_first_instance) {
4871
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4872
_bind_vertex_buffers(cmd_buf_info);
4873
cmd_buf_info->cmd_list->DrawIndexedInstanced(p_index_count, p_instance_count, p_first_index, p_vertex_offset, p_first_instance);
4874
}
4875
4876
void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
4877
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4878
_bind_vertex_buffers(cmd_buf_info);
4879
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
4880
if (!barrier_capabilities.enhanced_barriers_supported) {
4881
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
4882
_resource_transitions_flush(cmd_buf_info);
4883
}
4884
4885
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);
4886
}
4887
4888
void RenderingDeviceDriverD3D12::command_render_draw_indexed_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {
4889
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4890
_bind_vertex_buffers(cmd_buf_info);
4891
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
4892
BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;
4893
if (!barrier_capabilities.enhanced_barriers_supported) {
4894
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
4895
_resource_transition_batch(cmd_buf_info, count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
4896
_resource_transitions_flush(cmd_buf_info);
4897
}
4898
4899
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw_indexed.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);
4900
}
4901
4902
void RenderingDeviceDriverD3D12::command_render_draw_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
4903
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4904
_bind_vertex_buffers(cmd_buf_info);
4905
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
4906
if (!barrier_capabilities.enhanced_barriers_supported) {
4907
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
4908
_resource_transitions_flush(cmd_buf_info);
4909
}
4910
4911
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_draw_count, indirect_buf_info->resource, p_offset, nullptr, 0);
4912
}
4913
4914
void RenderingDeviceDriverD3D12::command_render_draw_indirect_count(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset, BufferID p_count_buffer, uint64_t p_count_buffer_offset, uint32_t p_max_draw_count, uint32_t p_stride) {
4915
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4916
_bind_vertex_buffers(cmd_buf_info);
4917
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
4918
BufferInfo *count_buf_info = (BufferInfo *)p_count_buffer.id;
4919
if (!barrier_capabilities.enhanced_barriers_supported) {
4920
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
4921
_resource_transition_batch(cmd_buf_info, count_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
4922
_resource_transitions_flush(cmd_buf_info);
4923
}
4924
4925
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.draw.Get(), p_max_draw_count, indirect_buf_info->resource, p_offset, count_buf_info->resource, p_count_buffer_offset);
4926
}
4927
4928
void RenderingDeviceDriverD3D12::command_render_bind_vertex_buffers(CommandBufferID p_cmd_buffer, uint32_t p_binding_count, const BufferID *p_buffers, const uint64_t *p_offsets, uint64_t p_dynamic_offsets) {
4929
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4930
4931
DEV_ASSERT(cmd_buf_info->render_pass_state.current_subpass != UINT32_MAX);
4932
4933
// Vertex buffer views are set deferredly, to be sure we already know the strides by then,
4934
// which is only true once the pipeline has been bound. Otherwise, we'd need that the pipeline
4935
// is always bound first, which would be not kind of us. [[DEFERRED_VERTEX_BUFFERS]]
4936
DEV_ASSERT(p_binding_count <= ARRAY_SIZE(cmd_buf_info->render_pass_state.vertex_buffer_views));
4937
for (uint32_t i = 0; i < p_binding_count; i++) {
4938
BufferInfo *buffer_info = (BufferInfo *)p_buffers[i].id;
4939
4940
uint32_t dynamic_offset = 0;
4941
if (buffer_info->is_dynamic()) {
4942
uint64_t buffer_frame_idx = p_dynamic_offsets & 0x3; // Assuming max 4 frames.
4943
p_dynamic_offsets >>= 2;
4944
dynamic_offset = buffer_frame_idx * buffer_info->size;
4945
}
4946
4947
cmd_buf_info->render_pass_state.vertex_buffer_views[i] = {};
4948
cmd_buf_info->render_pass_state.vertex_buffer_views[i].BufferLocation = buffer_info->gpu_virtual_address + dynamic_offset + p_offsets[i];
4949
cmd_buf_info->render_pass_state.vertex_buffer_views[i].SizeInBytes = buffer_info->size - p_offsets[i];
4950
if (!barrier_capabilities.enhanced_barriers_supported) {
4951
_resource_transition_batch(cmd_buf_info, buffer_info, 0, 1, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);
4952
}
4953
}
4954
4955
if (!barrier_capabilities.enhanced_barriers_supported) {
4956
_resource_transitions_flush(cmd_buf_info);
4957
}
4958
4959
cmd_buf_info->render_pass_state.vertex_buffer_count = p_binding_count;
4960
}
4961
4962
void RenderingDeviceDriverD3D12::command_render_bind_index_buffer(CommandBufferID p_cmd_buffer, BufferID p_buffer, IndexBufferFormat p_format, uint64_t p_offset) {
4963
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
4964
BufferInfo *buffer_info = (BufferInfo *)p_buffer.id;
4965
4966
D3D12_INDEX_BUFFER_VIEW d3d12_ib_view = {};
4967
d3d12_ib_view.BufferLocation = buffer_info->gpu_virtual_address + p_offset;
4968
d3d12_ib_view.SizeInBytes = buffer_info->size - p_offset;
4969
d3d12_ib_view.Format = p_format == INDEX_BUFFER_FORMAT_UINT16 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT;
4970
4971
if (!barrier_capabilities.enhanced_barriers_supported) {
4972
_resource_transition_batch(cmd_buf_info, buffer_info, 0, 1, D3D12_RESOURCE_STATE_INDEX_BUFFER);
4973
_resource_transitions_flush(cmd_buf_info);
4974
}
4975
4976
cmd_buf_info->cmd_list->IASetIndexBuffer(&d3d12_ib_view);
4977
}
4978
4979
// [[DEFERRED_VERTEX_BUFFERS]]
4980
void RenderingDeviceDriverD3D12::_bind_vertex_buffers(CommandBufferInfo *p_cmd_buf_info) {
4981
RenderPassState &render_pass_state = p_cmd_buf_info->render_pass_state;
4982
if (render_pass_state.vertex_buffer_count && render_pass_state.vf_info) {
4983
for (uint32_t i = 0; i < render_pass_state.vertex_buffer_count; i++) {
4984
render_pass_state.vertex_buffer_views[i].StrideInBytes = render_pass_state.vf_info->vertex_buffer_strides[i];
4985
}
4986
p_cmd_buf_info->cmd_list->IASetVertexBuffers(0, render_pass_state.vertex_buffer_count, render_pass_state.vertex_buffer_views);
4987
render_pass_state.vertex_buffer_count = 0;
4988
}
4989
}
4990
4991
void RenderingDeviceDriverD3D12::command_render_set_blend_constants(CommandBufferID p_cmd_buffer, const Color &p_constants) {
4992
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
4993
cmd_buf_info->cmd_list->OMSetBlendFactor(p_constants.components);
4994
}
4995
4996
void RenderingDeviceDriverD3D12::command_render_set_line_width(CommandBufferID p_cmd_buffer, float p_width) {
4997
if (!Math::is_equal_approx(p_width, 1.0f)) {
4998
ERR_FAIL_MSG("Setting line widths other than 1.0 is not supported by the Direct3D 12 rendering driver.");
4999
}
5000
}
5001
5002
// ----- PIPELINE -----
5003
5004
static const D3D12_PRIMITIVE_TOPOLOGY_TYPE RD_PRIMITIVE_TO_D3D12_TOPOLOGY_TYPE[RDD::RENDER_PRIMITIVE_MAX] = {
5005
D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT,
5006
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
5007
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
5008
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
5009
D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE,
5010
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
5011
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
5012
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
5013
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
5014
D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE,
5015
D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH,
5016
};
5017
5018
static const D3D12_PRIMITIVE_TOPOLOGY RD_PRIMITIVE_TO_D3D12_TOPOLOGY[RDD::RENDER_PRIMITIVE_MAX] = {
5019
D3D_PRIMITIVE_TOPOLOGY_POINTLIST,
5020
D3D_PRIMITIVE_TOPOLOGY_LINELIST,
5021
D3D_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,
5022
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP,
5023
D3D_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,
5024
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
5025
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,
5026
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
5027
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
5028
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
5029
D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST,
5030
};
5031
5032
static const D3D12_CULL_MODE RD_POLYGON_CULL_TO_D3D12_CULL_MODE[RDD::POLYGON_CULL_MAX] = {
5033
D3D12_CULL_MODE_NONE,
5034
D3D12_CULL_MODE_FRONT,
5035
D3D12_CULL_MODE_BACK,
5036
};
5037
5038
static const D3D12_STENCIL_OP RD_TO_D3D12_STENCIL_OP[RDD::STENCIL_OP_MAX] = {
5039
D3D12_STENCIL_OP_KEEP,
5040
D3D12_STENCIL_OP_ZERO,
5041
D3D12_STENCIL_OP_REPLACE,
5042
D3D12_STENCIL_OP_INCR_SAT,
5043
D3D12_STENCIL_OP_DECR_SAT,
5044
D3D12_STENCIL_OP_INVERT,
5045
D3D12_STENCIL_OP_INCR,
5046
D3D12_STENCIL_OP_DECR,
5047
};
5048
5049
static const D3D12_LOGIC_OP RD_TO_D3D12_LOGIC_OP[RDD::LOGIC_OP_MAX] = {
5050
D3D12_LOGIC_OP_CLEAR,
5051
D3D12_LOGIC_OP_AND,
5052
D3D12_LOGIC_OP_AND_REVERSE,
5053
D3D12_LOGIC_OP_COPY,
5054
D3D12_LOGIC_OP_AND_INVERTED,
5055
D3D12_LOGIC_OP_NOOP,
5056
D3D12_LOGIC_OP_XOR,
5057
D3D12_LOGIC_OP_OR,
5058
D3D12_LOGIC_OP_NOR,
5059
D3D12_LOGIC_OP_EQUIV,
5060
D3D12_LOGIC_OP_INVERT,
5061
D3D12_LOGIC_OP_OR_REVERSE,
5062
D3D12_LOGIC_OP_COPY_INVERTED,
5063
D3D12_LOGIC_OP_OR_INVERTED,
5064
D3D12_LOGIC_OP_NAND,
5065
D3D12_LOGIC_OP_SET,
5066
};
5067
5068
static const D3D12_BLEND RD_TO_D3D12_BLEND_FACTOR[RDD::BLEND_FACTOR_MAX] = {
5069
D3D12_BLEND_ZERO,
5070
D3D12_BLEND_ONE,
5071
D3D12_BLEND_SRC_COLOR,
5072
D3D12_BLEND_INV_SRC_COLOR,
5073
D3D12_BLEND_DEST_COLOR,
5074
D3D12_BLEND_INV_DEST_COLOR,
5075
D3D12_BLEND_SRC_ALPHA,
5076
D3D12_BLEND_INV_SRC_ALPHA,
5077
D3D12_BLEND_DEST_ALPHA,
5078
D3D12_BLEND_INV_DEST_ALPHA,
5079
D3D12_BLEND_BLEND_FACTOR,
5080
D3D12_BLEND_INV_BLEND_FACTOR,
5081
D3D12_BLEND_BLEND_FACTOR,
5082
D3D12_BLEND_INV_BLEND_FACTOR,
5083
D3D12_BLEND_SRC_ALPHA_SAT,
5084
D3D12_BLEND_SRC1_COLOR,
5085
D3D12_BLEND_INV_SRC1_COLOR,
5086
D3D12_BLEND_SRC1_ALPHA,
5087
D3D12_BLEND_INV_SRC1_ALPHA,
5088
};
5089
5090
static const D3D12_BLEND_OP RD_TO_D3D12_BLEND_OP[RDD::BLEND_OP_MAX] = {
5091
D3D12_BLEND_OP_ADD,
5092
D3D12_BLEND_OP_SUBTRACT,
5093
D3D12_BLEND_OP_REV_SUBTRACT,
5094
D3D12_BLEND_OP_MIN,
5095
D3D12_BLEND_OP_MAX,
5096
};
5097
5098
RDD::PipelineID RenderingDeviceDriverD3D12::render_pipeline_create(
5099
ShaderID p_shader,
5100
VertexFormatID p_vertex_format,
5101
RenderPrimitive p_render_primitive,
5102
PipelineRasterizationState p_rasterization_state,
5103
PipelineMultisampleState p_multisample_state,
5104
PipelineDepthStencilState p_depth_stencil_state,
5105
PipelineColorBlendState p_blend_state,
5106
VectorView<int32_t> p_color_attachments,
5107
BitField<PipelineDynamicStateFlags> p_dynamic_state,
5108
RenderPassID p_render_pass,
5109
uint32_t p_render_subpass,
5110
VectorView<PipelineSpecializationConstant> p_specialization_constants) {
5111
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
5112
5113
CD3DX12_PIPELINE_STATE_STREAM1 pipeline_desc = {};
5114
5115
const RenderPassInfo *pass_info = (const RenderPassInfo *)p_render_pass.id;
5116
RenderPipelineInfo render_info;
5117
5118
// Attachments.
5119
LocalVector<uint32_t> color_attachments;
5120
{
5121
const Subpass &subpass = pass_info->subpasses[p_render_subpass];
5122
5123
for (uint32_t i = 0; i < ARRAY_SIZE((&pipeline_desc.RTVFormats)->RTFormats); i++) {
5124
(&pipeline_desc.RTVFormats)->RTFormats[i] = DXGI_FORMAT_UNKNOWN;
5125
}
5126
5127
for (uint32_t i = 0; i < subpass.color_references.size(); i++) {
5128
const AttachmentReference &ref = subpass.color_references[i];
5129
if (ref.attachment != AttachmentReference::UNUSED) {
5130
const Attachment &attachment = pass_info->attachments[ref.attachment];
5131
DEV_ASSERT((&pipeline_desc.RTVFormats)->RTFormats[i] == DXGI_FORMAT_UNKNOWN);
5132
(&pipeline_desc.RTVFormats)->RTFormats[i] = RD_TO_D3D12_FORMAT[attachment.format].general_format;
5133
}
5134
}
5135
(&pipeline_desc.RTVFormats)->NumRenderTargets = p_color_attachments.size();
5136
5137
if (subpass.depth_stencil_reference.attachment != AttachmentReference::UNUSED) {
5138
const Attachment &attachment = pass_info->attachments[subpass.depth_stencil_reference.attachment];
5139
pipeline_desc.DSVFormat = RD_TO_D3D12_FORMAT[attachment.format].dsv_format;
5140
} else {
5141
pipeline_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
5142
}
5143
}
5144
5145
// Vertex.
5146
if (p_vertex_format) {
5147
const VertexFormatInfo *vf_info = (const VertexFormatInfo *)p_vertex_format.id;
5148
(&pipeline_desc.InputLayout)->pInputElementDescs = vf_info->input_elem_descs.ptr();
5149
(&pipeline_desc.InputLayout)->NumElements = vf_info->input_elem_descs.size();
5150
render_info.vf_info = vf_info;
5151
}
5152
5153
// Input assembly & tessellation.
5154
5155
pipeline_desc.PrimitiveTopologyType = RD_PRIMITIVE_TO_D3D12_TOPOLOGY_TYPE[p_render_primitive];
5156
if (p_render_primitive == RENDER_PRIMITIVE_TESSELATION_PATCH) {
5157
// Is there any way to get the true point count limit?
5158
ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > 32, PipelineID());
5159
render_info.dyn_params.primitive_topology = (D3D12_PRIMITIVE_TOPOLOGY)((int)D3D_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST + p_rasterization_state.patch_control_points);
5160
} else {
5161
render_info.dyn_params.primitive_topology = RD_PRIMITIVE_TO_D3D12_TOPOLOGY[p_render_primitive];
5162
}
5163
if (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX) {
5164
// TODO: This is right for 16-bit indices; for 32-bit there's a different enum value to set, but we don't know at this point.
5165
pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_0xFFFF;
5166
} else {
5167
pipeline_desc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED;
5168
}
5169
5170
// Rasterization.
5171
(&pipeline_desc.RasterizerState)->DepthClipEnable = !p_rasterization_state.enable_depth_clamp;
5172
// In D3D12, discard can be supported with some extra effort (empty pixel shader + disable depth/stencil test); that said, unsupported by now.
5173
ERR_FAIL_COND_V(p_rasterization_state.discard_primitives, PipelineID());
5174
(&pipeline_desc.RasterizerState)->FillMode = p_rasterization_state.wireframe ? D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID;
5175
(&pipeline_desc.RasterizerState)->CullMode = RD_POLYGON_CULL_TO_D3D12_CULL_MODE[p_rasterization_state.cull_mode];
5176
(&pipeline_desc.RasterizerState)->FrontCounterClockwise = p_rasterization_state.front_face == POLYGON_FRONT_FACE_COUNTER_CLOCKWISE;
5177
// In D3D12, there's still a point in setting up depth bias with no depth buffer, but just zeroing (disabling) it all in such case is closer to Vulkan.
5178
if (p_rasterization_state.depth_bias_enabled && pipeline_desc.DSVFormat != DXGI_FORMAT_UNKNOWN) {
5179
(&pipeline_desc.RasterizerState)->DepthBias = p_rasterization_state.depth_bias_constant_factor;
5180
(&pipeline_desc.RasterizerState)->DepthBiasClamp = p_rasterization_state.depth_bias_clamp;
5181
(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = p_rasterization_state.depth_bias_slope_factor;
5182
(&pipeline_desc.RasterizerState)->DepthBias = 0;
5183
(&pipeline_desc.RasterizerState)->DepthBiasClamp = 0.0f;
5184
(&pipeline_desc.RasterizerState)->SlopeScaledDepthBias = 0.0f;
5185
}
5186
(&pipeline_desc.RasterizerState)->ForcedSampleCount = 0;
5187
(&pipeline_desc.RasterizerState)->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
5188
(&pipeline_desc.RasterizerState)->MultisampleEnable = TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count] != 1;
5189
(&pipeline_desc.RasterizerState)->AntialiasedLineEnable = true;
5190
5191
// In D3D12, there's no line width.
5192
ERR_FAIL_COND_V(!Math::is_equal_approx(p_rasterization_state.line_width, 1.0f), PipelineID());
5193
5194
// Multisample.
5195
ERR_FAIL_COND_V(p_multisample_state.enable_sample_shading, PipelineID()); // How one enables this in D3D12?
5196
if ((&pipeline_desc.RTVFormats)->NumRenderTargets || pipeline_desc.DSVFormat != DXGI_FORMAT_UNKNOWN) {
5197
uint32_t sample_count = MIN(
5198
pass_info->max_supported_sample_count,
5199
TEXTURE_SAMPLES_COUNT[p_multisample_state.sample_count]);
5200
(&pipeline_desc.SampleDesc)->Count = sample_count;
5201
} else {
5202
(&pipeline_desc.SampleDesc)->Count = 1;
5203
}
5204
if ((&pipeline_desc.SampleDesc)->Count > 1) {
5205
(&pipeline_desc.SampleDesc)->Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
5206
} else {
5207
(&pipeline_desc.SampleDesc)->Quality = 0;
5208
}
5209
if (p_multisample_state.sample_mask.size()) {
5210
for (int i = 1; i < p_multisample_state.sample_mask.size(); i++) {
5211
// In D3D12 there's a single sample mask for every pixel.
5212
ERR_FAIL_COND_V(p_multisample_state.sample_mask[i] != p_multisample_state.sample_mask[0], PipelineID());
5213
}
5214
pipeline_desc.SampleMask = p_multisample_state.sample_mask[0];
5215
} else {
5216
pipeline_desc.SampleMask = 0xffffffff;
5217
}
5218
5219
// Depth stencil.
5220
5221
if (pipeline_desc.DSVFormat == DXGI_FORMAT_UNKNOWN) {
5222
(&pipeline_desc.DepthStencilState)->DepthEnable = false;
5223
(&pipeline_desc.DepthStencilState)->StencilEnable = false;
5224
} else {
5225
(&pipeline_desc.DepthStencilState)->DepthEnable = p_depth_stencil_state.enable_depth_test;
5226
(&pipeline_desc.DepthStencilState)->DepthWriteMask = p_depth_stencil_state.enable_depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
5227
(&pipeline_desc.DepthStencilState)->DepthFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.depth_compare_operator];
5228
(&pipeline_desc.DepthStencilState)->DepthBoundsTestEnable = p_depth_stencil_state.enable_depth_range;
5229
(&pipeline_desc.DepthStencilState)->StencilEnable = p_depth_stencil_state.enable_stencil;
5230
5231
// In D3D12 some elements can't be different across front and back.
5232
ERR_FAIL_COND_V(p_depth_stencil_state.front_op.compare_mask != p_depth_stencil_state.back_op.compare_mask, PipelineID());
5233
ERR_FAIL_COND_V(p_depth_stencil_state.front_op.write_mask != p_depth_stencil_state.back_op.write_mask, PipelineID());
5234
ERR_FAIL_COND_V(p_depth_stencil_state.front_op.reference != p_depth_stencil_state.back_op.reference, PipelineID());
5235
(&pipeline_desc.DepthStencilState)->StencilReadMask = p_depth_stencil_state.front_op.compare_mask;
5236
(&pipeline_desc.DepthStencilState)->StencilWriteMask = p_depth_stencil_state.front_op.write_mask;
5237
5238
(&pipeline_desc.DepthStencilState)->FrontFace.StencilFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.fail];
5239
(&pipeline_desc.DepthStencilState)->FrontFace.StencilPassOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.pass];
5240
(&pipeline_desc.DepthStencilState)->FrontFace.StencilDepthFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.front_op.depth_fail];
5241
(&pipeline_desc.DepthStencilState)->FrontFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.front_op.compare];
5242
5243
(&pipeline_desc.DepthStencilState)->BackFace.StencilFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.fail];
5244
(&pipeline_desc.DepthStencilState)->BackFace.StencilPassOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.pass];
5245
(&pipeline_desc.DepthStencilState)->BackFace.StencilDepthFailOp = RD_TO_D3D12_STENCIL_OP[p_depth_stencil_state.back_op.depth_fail];
5246
(&pipeline_desc.DepthStencilState)->BackFace.StencilFunc = RD_TO_D3D12_COMPARE_OP[p_depth_stencil_state.back_op.compare];
5247
5248
if (misc_features_support.depth_bounds_supported) {
5249
render_info.dyn_params.depth_bounds_min = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_min : 0.0f;
5250
render_info.dyn_params.depth_bounds_max = p_depth_stencil_state.enable_depth_range ? p_depth_stencil_state.depth_range_max : 1.0f;
5251
} else {
5252
if (p_depth_stencil_state.enable_depth_range) {
5253
WARN_PRINT_ONCE("Depth bounds test is not supported by the GPU driver.");
5254
}
5255
}
5256
5257
render_info.dyn_params.stencil_reference = p_depth_stencil_state.front_op.reference;
5258
}
5259
5260
// Blend states.
5261
(&pipeline_desc.BlendState)->AlphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
5262
{
5263
bool all_attachments_same_blend = true;
5264
for (int i = 0; i < p_blend_state.attachments.size(); i++) {
5265
const PipelineColorBlendState::Attachment &bs = p_blend_state.attachments[i];
5266
D3D12_RENDER_TARGET_BLEND_DESC &bd = (&pipeline_desc.BlendState)->RenderTarget[i];
5267
5268
bd.BlendEnable = bs.enable_blend;
5269
bd.LogicOpEnable = p_blend_state.enable_logic_op;
5270
bd.LogicOp = RD_TO_D3D12_LOGIC_OP[p_blend_state.logic_op];
5271
5272
bd.SrcBlend = RD_TO_D3D12_BLEND_FACTOR[bs.src_color_blend_factor];
5273
bd.DestBlend = RD_TO_D3D12_BLEND_FACTOR[bs.dst_color_blend_factor];
5274
bd.BlendOp = RD_TO_D3D12_BLEND_OP[bs.color_blend_op];
5275
5276
bd.SrcBlendAlpha = RD_TO_D3D12_BLEND_FACTOR[bs.src_alpha_blend_factor];
5277
bd.DestBlendAlpha = RD_TO_D3D12_BLEND_FACTOR[bs.dst_alpha_blend_factor];
5278
bd.BlendOpAlpha = RD_TO_D3D12_BLEND_OP[bs.alpha_blend_op];
5279
5280
if (bs.write_r) {
5281
bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_RED;
5282
}
5283
if (bs.write_g) {
5284
bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_GREEN;
5285
}
5286
if (bs.write_b) {
5287
bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_BLUE;
5288
}
5289
if (bs.write_a) {
5290
bd.RenderTargetWriteMask |= D3D12_COLOR_WRITE_ENABLE_ALPHA;
5291
}
5292
5293
if (i > 0 && all_attachments_same_blend) {
5294
all_attachments_same_blend = &(&pipeline_desc.BlendState)->RenderTarget[i] == &(&pipeline_desc.BlendState)->RenderTarget[0];
5295
}
5296
}
5297
5298
// Per D3D12 docs, if logic op used, independent blending is not supported.
5299
ERR_FAIL_COND_V(p_blend_state.enable_logic_op && !all_attachments_same_blend, PipelineID());
5300
5301
(&pipeline_desc.BlendState)->IndependentBlendEnable = !all_attachments_same_blend;
5302
}
5303
5304
render_info.dyn_params.blend_constant = p_blend_state.blend_constant;
5305
5306
// Multiview
5307
// We are using render target slices for each view.
5308
const D3D12_VIEW_INSTANCE_LOCATION viewInstanceLocations[D3D12_MAX_VIEW_INSTANCE_COUNT] = { { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 } };
5309
if (pass_info->view_count > 1) {
5310
(&pipeline_desc.ViewInstancingDesc)->ViewInstanceCount = pass_info->view_count;
5311
(&pipeline_desc.ViewInstancingDesc)->Flags = D3D12_VIEW_INSTANCING_FLAG_NONE;
5312
(&pipeline_desc.ViewInstancingDesc)->pViewInstanceLocations = viewInstanceLocations;
5313
}
5314
5315
// Stages bytecodes + specialization constants.
5316
5317
pipeline_desc.pRootSignature = shader_info_in->root_signature.Get();
5318
5319
HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;
5320
bool ok = _shader_apply_specialization_constants(shader_info_in, p_specialization_constants, final_stages_bytecode);
5321
ERR_FAIL_COND_V(!ok, PipelineID());
5322
5323
pipeline_desc.VS = D3D12_SHADER_BYTECODE{
5324
final_stages_bytecode[SHADER_STAGE_VERTEX].ptr(),
5325
(SIZE_T)final_stages_bytecode[SHADER_STAGE_VERTEX].size()
5326
};
5327
pipeline_desc.PS = D3D12_SHADER_BYTECODE{
5328
final_stages_bytecode[SHADER_STAGE_FRAGMENT].ptr(),
5329
(SIZE_T)final_stages_bytecode[SHADER_STAGE_FRAGMENT].size()
5330
};
5331
5332
ComPtr<ID3D12Device2> device_2;
5333
device->QueryInterface(device_2.GetAddressOf());
5334
ComPtr<ID3D12PipelineState> pso;
5335
HRESULT res = E_FAIL;
5336
if (device_2) {
5337
D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};
5338
pssd.pPipelineStateSubobjectStream = &pipeline_desc;
5339
pssd.SizeInBytes = sizeof(pipeline_desc);
5340
res = device_2->CreatePipelineState(&pssd, IID_PPV_ARGS(pso.GetAddressOf()));
5341
} else {
5342
D3D12_GRAPHICS_PIPELINE_STATE_DESC desc = pipeline_desc.GraphicsDescV0();
5343
res = device->CreateGraphicsPipelineState(&desc, IID_PPV_ARGS(pso.GetAddressOf()));
5344
}
5345
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Graphics)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
5346
5347
PipelineInfo *pipeline_info = memnew(PipelineInfo);
5348
pipeline_info->pso = pso;
5349
pipeline_info->shader_info = shader_info_in;
5350
pipeline_info->render_info = render_info;
5351
5352
return PipelineID(pipeline_info);
5353
}
5354
5355
/*****************/
5356
/**** COMPUTE ****/
5357
/*****************/
5358
5359
// ----- COMMANDS -----
5360
5361
void RenderingDeviceDriverD3D12::command_bind_compute_pipeline(CommandBufferID p_cmd_buffer, PipelineID p_pipeline) {
5362
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
5363
5364
const PipelineInfo *pipeline_info = (const PipelineInfo *)p_pipeline.id;
5365
const ShaderInfo *shader_info_in = pipeline_info->shader_info;
5366
5367
if (cmd_buf_info->compute_pso != pipeline_info->pso.Get()) {
5368
cmd_buf_info->cmd_list->SetPipelineState(pipeline_info->pso.Get());
5369
5370
cmd_buf_info->compute_pso = pipeline_info->pso.Get();
5371
cmd_buf_info->graphics_pso = nullptr;
5372
}
5373
5374
if (cmd_buf_info->compute_root_signature_crc != shader_info_in->root_signature_crc) {
5375
cmd_buf_info->cmd_list->SetComputeRootSignature(shader_info_in->root_signature.Get());
5376
cmd_buf_info->compute_root_signature_crc = shader_info_in->root_signature_crc;
5377
}
5378
}
5379
5380
void RenderingDeviceDriverD3D12::command_bind_compute_uniform_sets(CommandBufferID p_cmd_buffer, VectorView<UniformSetID> p_uniform_sets, ShaderID p_shader, uint32_t p_first_set_index, uint32_t p_set_count, uint32_t p_dynamic_offsets) {
5381
_command_check_descriptor_sets(p_cmd_buffer);
5382
5383
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
5384
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
5385
5386
for (uint32_t i = 0u; i < p_set_count; ++i) {
5387
UniformSetInfo *uniform_set_info = (UniformSetInfo *)p_uniform_sets[i].id;
5388
const ShaderInfo::UniformSet &uniform_set_shader_info = shader_info_in->sets[p_first_set_index + i];
5389
5390
for (const UniformSetInfo::DynamicBuffer &dynamic_buffer : uniform_set_info->dynamic_buffers) {
5391
uint32_t frame_index = p_dynamic_offsets & 0xF;
5392
p_dynamic_offsets >>= 4;
5393
5394
const ShaderInfo::UniformBindingInfo &binding = uniform_set_shader_info.bindings[dynamic_buffer.binding];
5395
if (binding.root_param_idx != UINT_MAX) {
5396
D3D12_GPU_VIRTUAL_ADDRESS buffer_location = dynamic_buffer.info->gpu_virtual_address + (dynamic_buffer.info->size * frame_index);
5397
switch (binding.res_class) {
5398
case RES_CLASS_INVALID: {
5399
} break;
5400
case RES_CLASS_CBV: {
5401
cmd_buf_info->cmd_list->SetComputeRootConstantBufferView(binding.root_param_idx, buffer_location);
5402
} break;
5403
case RES_CLASS_SRV: {
5404
cmd_buf_info->cmd_list->SetComputeRootShaderResourceView(binding.root_param_idx, buffer_location);
5405
} break;
5406
case RES_CLASS_UAV: {
5407
cmd_buf_info->cmd_list->SetComputeRootUnorderedAccessView(binding.root_param_idx, buffer_location);
5408
} break;
5409
}
5410
}
5411
}
5412
5413
if (uniform_set_shader_info.resource_root_param_idx != UINT_MAX) {
5414
cmd_buf_info->cmd_list->SetComputeRootDescriptorTable(uniform_set_shader_info.resource_root_param_idx, uniform_set_info->resource_descriptor_heap_alloc.gpu_handle);
5415
}
5416
if (uniform_set_shader_info.sampler_root_param_idx != UINT_MAX) {
5417
cmd_buf_info->cmd_list->SetComputeRootDescriptorTable(uniform_set_shader_info.sampler_root_param_idx, uniform_set_info->sampler_descriptor_heap_alloc->gpu_handle);
5418
}
5419
}
5420
}
5421
5422
void RenderingDeviceDriverD3D12::command_compute_dispatch(CommandBufferID p_cmd_buffer, uint32_t p_x_groups, uint32_t p_y_groups, uint32_t p_z_groups) {
5423
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
5424
if (!barrier_capabilities.enhanced_barriers_supported) {
5425
_resource_transitions_flush(cmd_buf_info);
5426
}
5427
5428
cmd_buf_info->cmd_list->Dispatch(p_x_groups, p_y_groups, p_z_groups);
5429
}
5430
5431
void RenderingDeviceDriverD3D12::command_compute_dispatch_indirect(CommandBufferID p_cmd_buffer, BufferID p_indirect_buffer, uint64_t p_offset) {
5432
CommandBufferInfo *cmd_buf_info = (CommandBufferInfo *)p_cmd_buffer.id;
5433
BufferInfo *indirect_buf_info = (BufferInfo *)p_indirect_buffer.id;
5434
if (!barrier_capabilities.enhanced_barriers_supported) {
5435
_resource_transition_batch(cmd_buf_info, indirect_buf_info, 0, 1, D3D12_RESOURCE_STATE_INDIRECT_ARGUMENT);
5436
_resource_transitions_flush(cmd_buf_info);
5437
}
5438
5439
cmd_buf_info->cmd_list->ExecuteIndirect(indirect_cmd_signatures.dispatch.Get(), 1, indirect_buf_info->resource, p_offset, nullptr, 0);
5440
}
5441
5442
// ----- PIPELINE -----
5443
5444
RDD::PipelineID RenderingDeviceDriverD3D12::compute_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) {
5445
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_shader.id;
5446
5447
CD3DX12_PIPELINE_STATE_STREAM pipeline_desc = {};
5448
5449
// Stages bytecodes + specialization constants.
5450
5451
pipeline_desc.pRootSignature = shader_info_in->root_signature.Get();
5452
5453
HashMap<ShaderStage, Vector<uint8_t>> final_stages_bytecode;
5454
bool ok = _shader_apply_specialization_constants(shader_info_in, p_specialization_constants, final_stages_bytecode);
5455
ERR_FAIL_COND_V(!ok, PipelineID());
5456
5457
pipeline_desc.CS = D3D12_SHADER_BYTECODE{
5458
final_stages_bytecode[SHADER_STAGE_COMPUTE].ptr(),
5459
(SIZE_T)final_stages_bytecode[SHADER_STAGE_COMPUTE].size()
5460
};
5461
5462
ComPtr<ID3D12Device2> device_2;
5463
device->QueryInterface(device_2.GetAddressOf());
5464
ComPtr<ID3D12PipelineState> pso;
5465
HRESULT res = E_FAIL;
5466
if (device_2) {
5467
D3D12_PIPELINE_STATE_STREAM_DESC pssd = {};
5468
pssd.pPipelineStateSubobjectStream = &pipeline_desc;
5469
pssd.SizeInBytes = sizeof(pipeline_desc);
5470
res = device_2->CreatePipelineState(&pssd, IID_PPV_ARGS(pso.GetAddressOf()));
5471
} else {
5472
D3D12_COMPUTE_PIPELINE_STATE_DESC desc = pipeline_desc.ComputeDescV0();
5473
res = device->CreateComputePipelineState(&desc, IID_PPV_ARGS(pso.GetAddressOf()));
5474
}
5475
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), PipelineID(), "Create(Compute)PipelineState failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
5476
5477
PipelineInfo *pipeline_info = memnew(PipelineInfo);
5478
pipeline_info->pso = pso;
5479
pipeline_info->shader_info = shader_info_in;
5480
5481
return PipelineID(pipeline_info);
5482
}
5483
5484
/********************/
5485
/**** RAYTRACING ****/
5486
/********************/
5487
5488
// ---- ACCELERATION STRUCTURES ----
5489
5490
RDD::AccelerationStructureID RenderingDeviceDriverD3D12::blas_create(BufferID p_vertex_buffer, uint64_t p_vertex_offset, VertexFormatID p_vertex_format, uint32_t p_vertex_count, uint32_t p_position_attribute_location, BufferID p_index_buffer, IndexBufferFormat p_index_format, uint64_t p_index_offset, uint32_t p_index_count, BitField<AccelerationStructureGeometryBits> p_geometry_bits) {
5491
ERR_FAIL_V_MSG(AccelerationStructureID(), "Ray tracing is not currently supported by the D3D12 driver.");
5492
}
5493
5494
uint32_t RenderingDeviceDriverD3D12::tlas_instances_buffer_get_size_bytes(uint32_t p_instance_count) {
5495
ERR_FAIL_V_MSG(0, "Ray tracing is not currently supported by the D3D12 driver.");
5496
}
5497
5498
void RenderingDeviceDriverD3D12::tlas_instances_buffer_fill(BufferID p_instances_buffer, VectorView<AccelerationStructureID> p_blases, VectorView<Transform3D> p_transforms) {
5499
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
5500
}
5501
5502
RDD::AccelerationStructureID RenderingDeviceDriverD3D12::tlas_create(BufferID p_instance_buffer) {
5503
ERR_FAIL_V_MSG(AccelerationStructureID(), "Ray tracing is not currently supported by the D3D12 driver.");
5504
}
5505
5506
void RenderingDeviceDriverD3D12::acceleration_structure_free(AccelerationStructureID p_acceleration_structure) {
5507
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
5508
}
5509
5510
uint32_t RenderingDeviceDriverD3D12::acceleration_structure_get_scratch_size_bytes(AccelerationStructureID p_acceleration_structure) {
5511
ERR_FAIL_V_MSG(0, "Ray tracing is not currently supported by the D3D12 driver.");
5512
}
5513
5514
// ----- PIPELINE -----
5515
5516
RDD::RaytracingPipelineID RenderingDeviceDriverD3D12::raytracing_pipeline_create(ShaderID p_shader, VectorView<PipelineSpecializationConstant> p_specialization_constants) {
5517
ERR_FAIL_V_MSG(RaytracingPipelineID(), "Ray tracing is not currently supported by the D3D12 driver.");
5518
}
5519
5520
void RenderingDeviceDriverD3D12::raytracing_pipeline_free(RDD::RaytracingPipelineID p_pipeline) {
5521
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
5522
}
5523
5524
// ----- COMMANDS -----
5525
5526
void RenderingDeviceDriverD3D12::command_build_acceleration_structure(CommandBufferID p_cmd_buffer, AccelerationStructureID p_acceleration_structure, BufferID p_scratch_buffer) {
5527
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
5528
}
5529
5530
void RenderingDeviceDriverD3D12::command_bind_raytracing_pipeline(CommandBufferID p_cmd_buffer, RaytracingPipelineID p_pipeline) {
5531
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
5532
}
5533
5534
void RenderingDeviceDriverD3D12::command_bind_raytracing_uniform_set(CommandBufferID p_cmd_buffer, UniformSetID p_uniform_set, ShaderID p_shader, uint32_t p_set_index) {
5535
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
5536
}
5537
5538
void RenderingDeviceDriverD3D12::command_trace_rays(CommandBufferID p_cmd_buffer, uint32_t p_width, uint32_t p_height) {
5539
ERR_FAIL_MSG("Ray tracing is not currently supported by the D3D12 driver.");
5540
}
5541
5542
/*****************/
5543
/**** QUERIES ****/
5544
/*****************/
5545
5546
// ----- TIMESTAMP -----
5547
5548
RDD::QueryPoolID RenderingDeviceDriverD3D12::timestamp_query_pool_create(uint32_t p_query_count) {
5549
ComPtr<ID3D12QueryHeap> query_heap;
5550
{
5551
D3D12_QUERY_HEAP_DESC qh_desc = {};
5552
qh_desc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP;
5553
qh_desc.Count = p_query_count;
5554
qh_desc.NodeMask = 0;
5555
HRESULT res = device->CreateQueryHeap(&qh_desc, IID_PPV_ARGS(query_heap.GetAddressOf()));
5556
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), QueryPoolID(), "CreateQueryHeap failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
5557
}
5558
5559
ComPtr<D3D12MA::Allocation> results_buffer_allocation;
5560
{
5561
D3D12MA::ALLOCATION_DESC allocation_desc = {};
5562
allocation_desc.HeapType = D3D12_HEAP_TYPE_READBACK;
5563
5564
CD3DX12_RESOURCE_DESC resource_desc = CD3DX12_RESOURCE_DESC::Buffer(sizeof(uint64_t) * p_query_count);
5565
5566
ComPtr<ID3D12Resource> results_buffer;
5567
HRESULT res = allocator->CreateResource(
5568
&allocation_desc,
5569
&resource_desc,
5570
D3D12_RESOURCE_STATE_COPY_DEST,
5571
nullptr,
5572
results_buffer_allocation.GetAddressOf(),
5573
IID_PPV_ARGS(results_buffer.GetAddressOf()));
5574
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), QueryPoolID(), "D3D12MA::CreateResource failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
5575
}
5576
5577
// Bookkeep.
5578
5579
TimestampQueryPoolInfo *tqp_info = VersatileResource::allocate<TimestampQueryPoolInfo>(resources_allocator);
5580
tqp_info->query_heap = query_heap;
5581
tqp_info->query_count = p_query_count;
5582
tqp_info->results_buffer_allocation = results_buffer_allocation;
5583
5584
return RDD::QueryPoolID(tqp_info);
5585
}
5586
5587
void RenderingDeviceDriverD3D12::timestamp_query_pool_free(QueryPoolID p_pool_id) {
5588
TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;
5589
VersatileResource::free(resources_allocator, tqp_info);
5590
}
5591
5592
void RenderingDeviceDriverD3D12::timestamp_query_pool_get_results(QueryPoolID p_pool_id, uint32_t p_query_count, uint64_t *r_results) {
5593
TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;
5594
5595
ID3D12Resource *results_buffer = tqp_info->results_buffer_allocation->GetResource();
5596
5597
void *results_buffer_data = nullptr;
5598
results_buffer->Map(0, &VOID_RANGE, &results_buffer_data);
5599
memcpy(r_results, results_buffer_data, sizeof(uint64_t) * p_query_count);
5600
results_buffer->Unmap(0, &VOID_RANGE);
5601
}
5602
5603
uint64_t RenderingDeviceDriverD3D12::timestamp_query_result_to_time(uint64_t p_result) {
5604
return p_result / (double)device_limits.timestamp_frequency * 1000000000.0;
5605
}
5606
5607
void RenderingDeviceDriverD3D12::command_timestamp_query_pool_reset(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_query_count) {
5608
}
5609
5610
void RenderingDeviceDriverD3D12::command_timestamp_write(CommandBufferID p_cmd_buffer, QueryPoolID p_pool_id, uint32_t p_index) {
5611
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
5612
TimestampQueryPoolInfo *tqp_info = (TimestampQueryPoolInfo *)p_pool_id.id;
5613
ID3D12Resource *results_buffer = tqp_info->results_buffer_allocation->GetResource();
5614
cmd_buf_info->cmd_list->EndQuery(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index);
5615
cmd_buf_info->cmd_list->ResolveQueryData(tqp_info->query_heap.Get(), D3D12_QUERY_TYPE_TIMESTAMP, p_index, 1, results_buffer, p_index * sizeof(uint64_t));
5616
}
5617
5618
void RenderingDeviceDriverD3D12::command_begin_label(CommandBufferID p_cmd_buffer, const char *p_label_name, const Color &p_color) {
5619
#ifdef PIX_ENABLED
5620
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
5621
PIXBeginEvent(cmd_buf_info->cmd_list.Get(), p_color.to_argb32(), p_label_name);
5622
#endif
5623
}
5624
5625
void RenderingDeviceDriverD3D12::command_end_label(CommandBufferID p_cmd_buffer) {
5626
#ifdef PIX_ENABLED
5627
const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)p_cmd_buffer.id;
5628
PIXEndEvent(cmd_buf_info->cmd_list.Get());
5629
#endif
5630
}
5631
5632
void RenderingDeviceDriverD3D12::command_insert_breadcrumb(CommandBufferID p_cmd_buffer, uint32_t p_data) {
5633
// TODO: Implement via DRED.
5634
}
5635
5636
/********************/
5637
/**** SUBMISSION ****/
5638
/********************/
5639
5640
void RenderingDeviceDriverD3D12::begin_segment(uint32_t p_frame_index, uint32_t p_frames_drawn) {
5641
frame_idx = p_frame_index;
5642
frames[frame_idx].descriptor_allocation_count = 0;
5643
5644
frames_drawn = p_frames_drawn;
5645
allocator->SetCurrentFrameIndex(p_frames_drawn);
5646
5647
segment_begun = true;
5648
}
5649
5650
void RenderingDeviceDriverD3D12::end_segment() {
5651
FrameInfo &f = frames[frame_idx];
5652
5653
// Free leftover descriptors.
5654
for (uint32_t i = f.descriptor_allocation_count; i < f.descriptor_allocations.size(); i++) {
5655
resource_descriptor_heap.free(f.descriptor_allocations[i]);
5656
}
5657
f.descriptor_allocations.resize(f.descriptor_allocation_count);
5658
5659
segment_begun = false;
5660
}
5661
5662
/**************/
5663
/**** MISC ****/
5664
/**************/
5665
5666
void RenderingDeviceDriverD3D12::_set_object_name(ID3D12Object *p_object, String p_object_name) {
5667
ERR_FAIL_NULL(p_object);
5668
int name_len = p_object_name.size();
5669
WCHAR *name_w = (WCHAR *)alloca(sizeof(WCHAR) * (name_len + 1));
5670
MultiByteToWideChar(CP_UTF8, 0, p_object_name.utf8().get_data(), -1, name_w, name_len);
5671
p_object->SetName(name_w);
5672
}
5673
5674
void RenderingDeviceDriverD3D12::set_object_name(ObjectType p_type, ID p_driver_id, const String &p_name) {
5675
switch (p_type) {
5676
case OBJECT_TYPE_TEXTURE: {
5677
const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
5678
if (tex_info->owner_info.allocation) {
5679
_set_object_name(tex_info->resource, p_name);
5680
}
5681
} break;
5682
case OBJECT_TYPE_SAMPLER: {
5683
} break;
5684
case OBJECT_TYPE_BUFFER: {
5685
const BufferInfo *buf_info = (const BufferInfo *)p_driver_id.id;
5686
_set_object_name(buf_info->resource, p_name);
5687
} break;
5688
case OBJECT_TYPE_SHADER: {
5689
const ShaderInfo *shader_info_in = (const ShaderInfo *)p_driver_id.id;
5690
_set_object_name(shader_info_in->root_signature.Get(), p_name);
5691
} break;
5692
case OBJECT_TYPE_UNIFORM_SET: {
5693
// Descriptor heaps are suballocated from bigger heaps and can therefore not be given unique names.
5694
} break;
5695
case OBJECT_TYPE_PIPELINE: {
5696
const PipelineInfo *pipeline_info = (const PipelineInfo *)p_driver_id.id;
5697
_set_object_name(pipeline_info->pso.Get(), p_name);
5698
} break;
5699
default: {
5700
DEV_ASSERT(false);
5701
}
5702
}
5703
}
5704
5705
uint64_t RenderingDeviceDriverD3D12::get_resource_native_handle(DriverResource p_type, ID p_driver_id) {
5706
switch (p_type) {
5707
case DRIVER_RESOURCE_LOGICAL_DEVICE: {
5708
return (uint64_t)device.Get();
5709
}
5710
case DRIVER_RESOURCE_PHYSICAL_DEVICE: {
5711
return (uint64_t)adapter.Get();
5712
}
5713
case DRIVER_RESOURCE_TOPMOST_OBJECT: {
5714
return 0;
5715
}
5716
case DRIVER_RESOURCE_COMMAND_QUEUE: {
5717
const CommandQueueInfo *cmd_queue_info = (const CommandQueueInfo *)p_driver_id.id;
5718
return (uint64_t)cmd_queue_info->d3d_queue.Get();
5719
}
5720
case DRIVER_RESOURCE_QUEUE_FAMILY: {
5721
return 0;
5722
}
5723
case DRIVER_RESOURCE_TEXTURE: {
5724
const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
5725
if (tex_info->main_texture) {
5726
tex_info = tex_info->main_texture;
5727
}
5728
return (uint64_t)tex_info->resource;
5729
} break;
5730
case DRIVER_RESOURCE_TEXTURE_VIEW: {
5731
const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
5732
return (uint64_t)tex_info->resource;
5733
}
5734
case DRIVER_RESOURCE_TEXTURE_DATA_FORMAT: {
5735
const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
5736
return (uint64_t)tex_info->desc.Format;
5737
}
5738
case DRIVER_RESOURCE_SAMPLER:
5739
case DRIVER_RESOURCE_UNIFORM_SET:
5740
return 0;
5741
case DRIVER_RESOURCE_BUFFER: {
5742
const TextureInfo *tex_info = (const TextureInfo *)p_driver_id.id;
5743
return (uint64_t)tex_info->resource;
5744
} break;
5745
case DRIVER_RESOURCE_COMPUTE_PIPELINE:
5746
case DRIVER_RESOURCE_RENDER_PIPELINE: {
5747
return p_driver_id.id;
5748
}
5749
default: {
5750
return 0;
5751
}
5752
}
5753
}
5754
5755
uint64_t RenderingDeviceDriverD3D12::get_total_memory_used() {
5756
D3D12MA::TotalStatistics stats;
5757
allocator->CalculateStatistics(&stats);
5758
return stats.Total.Stats.BlockBytes;
5759
}
5760
5761
uint64_t RenderingDeviceDriverD3D12::get_lazily_memory_used() {
5762
return 0;
5763
}
5764
5765
uint64_t RenderingDeviceDriverD3D12::limit_get(Limit p_limit) {
5766
uint64_t safe_unbounded = ((uint64_t)1 << 30);
5767
switch (p_limit) {
5768
case LIMIT_MAX_BOUND_UNIFORM_SETS:
5769
return safe_unbounded;
5770
case LIMIT_MAX_TEXTURE_ARRAY_LAYERS:
5771
return D3D12_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION;
5772
case LIMIT_MAX_TEXTURE_SIZE_1D:
5773
return D3D12_REQ_TEXTURE1D_U_DIMENSION;
5774
case LIMIT_MAX_TEXTURE_SIZE_2D:
5775
return D3D12_REQ_TEXTURE2D_U_OR_V_DIMENSION;
5776
case LIMIT_MAX_TEXTURE_SIZE_3D:
5777
return D3D12_REQ_TEXTURE3D_U_V_OR_W_DIMENSION;
5778
case LIMIT_MAX_TEXTURE_SIZE_CUBE:
5779
return D3D12_REQ_TEXTURECUBE_DIMENSION;
5780
case LIMIT_MAX_TEXTURES_PER_SHADER_STAGE:
5781
return device_limits.max_srvs_per_shader_stage;
5782
case LIMIT_MAX_UNIFORM_BUFFER_SIZE:
5783
return 65536;
5784
case LIMIT_MAX_VIEWPORT_DIMENSIONS_X:
5785
case LIMIT_MAX_VIEWPORT_DIMENSIONS_Y:
5786
return 16384; // Based on max. texture size. Maybe not correct.
5787
case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_X:
5788
return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
5789
case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Y:
5790
return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
5791
case LIMIT_MAX_COMPUTE_WORKGROUP_COUNT_Z:
5792
return D3D12_CS_DISPATCH_MAX_THREAD_GROUPS_PER_DIMENSION;
5793
case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_X:
5794
return D3D12_CS_THREAD_GROUP_MAX_X;
5795
case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y:
5796
return D3D12_CS_THREAD_GROUP_MAX_Y;
5797
case LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z:
5798
return D3D12_CS_THREAD_GROUP_MAX_Z;
5799
case LIMIT_MAX_COMPUTE_SHARED_MEMORY_SIZE:
5800
return D3D12_CS_TGSM_REGISTER_COUNT * sizeof(float);
5801
case LIMIT_SUBGROUP_SIZE:
5802
// Note in min/max. Shader model 6.6 supports it (see https://microsoft.github.io/DirectX-Specs/d3d/HLSL_SM_6_6_WaveSize.html),
5803
// but at this time I don't know the implications on the transpilation to DXIL, etc.
5804
case LIMIT_SUBGROUP_MIN_SIZE:
5805
case LIMIT_SUBGROUP_MAX_SIZE:
5806
return subgroup_capabilities.size;
5807
case LIMIT_SUBGROUP_IN_SHADERS:
5808
return subgroup_capabilities.supported_stages_flags_rd();
5809
case LIMIT_SUBGROUP_OPERATIONS:
5810
return subgroup_capabilities.supported_operations_flags_rd();
5811
case LIMIT_MAX_SHADER_VARYINGS:
5812
return MIN(D3D12_VS_OUTPUT_REGISTER_COUNT, D3D12_PS_INPUT_REGISTER_COUNT);
5813
default: {
5814
#ifdef DEV_ENABLED
5815
WARN_PRINT("Returning maximum value for unknown limit " + itos(p_limit) + ".");
5816
#endif
5817
return safe_unbounded;
5818
}
5819
}
5820
}
5821
5822
uint64_t RenderingDeviceDriverD3D12::api_trait_get(ApiTrait p_trait) {
5823
switch (p_trait) {
5824
case API_TRAIT_HONORS_PIPELINE_BARRIERS:
5825
return barrier_capabilities.enhanced_barriers_supported;
5826
case API_TRAIT_SHADER_CHANGE_INVALIDATION:
5827
return (uint64_t)SHADER_CHANGE_INVALIDATION_ALL_OR_NONE_ACCORDING_TO_LAYOUT_HASH;
5828
case API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT:
5829
return D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT;
5830
case API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP:
5831
return D3D12_TEXTURE_DATA_PITCH_ALIGNMENT;
5832
case API_TRAIT_SECONDARY_VIEWPORT_SCISSOR:
5833
return false;
5834
case API_TRAIT_CLEARS_WITH_COPY_ENGINE:
5835
return false;
5836
case API_TRAIT_USE_GENERAL_IN_COPY_QUEUES:
5837
return true;
5838
case API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS:
5839
return !barrier_capabilities.enhanced_barriers_supported;
5840
case API_TRAIT_TEXTURE_OUTPUTS_REQUIRE_CLEARS:
5841
return true;
5842
default:
5843
return RenderingDeviceDriver::api_trait_get(p_trait);
5844
}
5845
}
5846
5847
bool RenderingDeviceDriverD3D12::has_feature(Features p_feature) {
5848
switch (p_feature) {
5849
case SUPPORTS_HALF_FLOAT:
5850
return shader_capabilities.native_16bit_ops;
5851
case SUPPORTS_FRAGMENT_SHADER_WITH_ONLY_SIDE_EFFECTS:
5852
return true;
5853
case SUPPORTS_BUFFER_DEVICE_ADDRESS:
5854
return true;
5855
case SUPPORTS_IMAGE_ATOMIC_32_BIT:
5856
return true;
5857
case SUPPORTS_VULKAN_MEMORY_MODEL:
5858
return false;
5859
case SUPPORTS_POINT_SIZE:
5860
return false;
5861
default:
5862
return false;
5863
}
5864
}
5865
5866
const RDD::MultiviewCapabilities &RenderingDeviceDriverD3D12::get_multiview_capabilities() {
5867
return multiview_capabilities;
5868
}
5869
5870
const RDD::FragmentShadingRateCapabilities &RenderingDeviceDriverD3D12::get_fragment_shading_rate_capabilities() {
5871
return fsr_capabilities;
5872
}
5873
5874
const RDD::FragmentDensityMapCapabilities &RenderingDeviceDriverD3D12::get_fragment_density_map_capabilities() {
5875
return fdm_capabilities;
5876
}
5877
5878
String RenderingDeviceDriverD3D12::get_api_name() const {
5879
return "D3D12";
5880
}
5881
5882
String RenderingDeviceDriverD3D12::get_api_version() const {
5883
return vformat("%d_%d", feature_level / 10, feature_level % 10);
5884
}
5885
5886
String RenderingDeviceDriverD3D12::get_pipeline_cache_uuid() const {
5887
return pipeline_cache_id;
5888
}
5889
5890
const RDD::Capabilities &RenderingDeviceDriverD3D12::get_capabilities() const {
5891
return device_capabilities;
5892
}
5893
5894
const RenderingShaderContainerFormat &RenderingDeviceDriverD3D12::get_shader_container_format() const {
5895
return shader_container_format;
5896
}
5897
5898
bool RenderingDeviceDriverD3D12::is_composite_alpha_supported(CommandQueueID p_queue) const {
5899
if (has_comp_alpha.has((uint64_t)p_queue.id)) {
5900
return has_comp_alpha[(uint64_t)p_queue.id];
5901
}
5902
return false;
5903
}
5904
5905
/******************/
5906
5907
RenderingDeviceDriverD3D12::RenderingDeviceDriverD3D12(RenderingContextDriverD3D12 *p_context_driver) {
5908
DEV_ASSERT(p_context_driver != nullptr);
5909
5910
this->context_driver = p_context_driver;
5911
}
5912
5913
RenderingDeviceDriverD3D12::~RenderingDeviceDriverD3D12() {
5914
rtv_descriptor_heap_pool.free(null_rtv_alloc);
5915
5916
for (FrameInfo &f : frames) {
5917
for (DescriptorHeap::Allocation &alloc : f.descriptor_allocations) {
5918
resource_descriptor_heap.free(alloc);
5919
}
5920
}
5921
5922
if (D3D12Hooks::get_singleton() != nullptr) {
5923
D3D12Hooks::get_singleton()->cleanup_device();
5924
}
5925
5926
glsl_type_singleton_decref();
5927
}
5928
5929
bool RenderingDeviceDriverD3D12::is_in_developer_mode() {
5930
HKEY hkey = nullptr;
5931
LSTATUS result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", 0, KEY_READ, &hkey);
5932
if (result != ERROR_SUCCESS) {
5933
return false;
5934
}
5935
5936
DWORD value = 0;
5937
DWORD dword_size = sizeof(DWORD);
5938
result = RegQueryValueExW(hkey, L"AllowDevelopmentWithoutDevLicense", nullptr, nullptr, (PBYTE)&value, &dword_size);
5939
RegCloseKey(hkey);
5940
5941
if (result != ERROR_SUCCESS) {
5942
return false;
5943
}
5944
5945
return (value != 0);
5946
}
5947
5948
Error RenderingDeviceDriverD3D12::_initialize_device() {
5949
HRESULT res;
5950
5951
if (is_in_developer_mode()) {
5952
typedef HRESULT(WINAPI * PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(_In_ UINT, _In_count_(NumFeatures) const IID *, _In_opt_count_(NumFeatures) void *, _In_opt_count_(NumFeatures) UINT *);
5953
PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES d3d_D3D12EnableExperimentalFeatures = (PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12EnableExperimentalFeatures");
5954
ERR_FAIL_NULL_V(d3d_D3D12EnableExperimentalFeatures, ERR_CANT_CREATE);
5955
5956
UUID experimental_features[] = { D3D12ExperimentalShaderModels };
5957
d3d_D3D12EnableExperimentalFeatures(1, experimental_features, nullptr, nullptr);
5958
}
5959
5960
D3D_FEATURE_LEVEL requested_feature_level = D3D_FEATURE_LEVEL_11_0;
5961
// Override the adapter and feature level if needed by the XR backend.
5962
if (D3D12Hooks::get_singleton() != nullptr) {
5963
const LUID adapter_luid = D3D12Hooks::get_singleton()->get_adapter_luid();
5964
requested_feature_level = D3D12Hooks::get_singleton()->get_feature_level();
5965
ComPtr<IDXGIAdapter1> desired_adapter;
5966
for (UINT adapter_index = 0;; adapter_index++) {
5967
// EnumAdapters1 will fail with DXGI_ERROR_NOT_FOUND when there are no more adapters to
5968
// enumerate.
5969
if (context_driver->dxgi_factory_get()->EnumAdapters1(adapter_index, desired_adapter.ReleaseAndGetAddressOf()) == DXGI_ERROR_NOT_FOUND) {
5970
break;
5971
}
5972
DXGI_ADAPTER_DESC1 desc;
5973
desired_adapter->GetDesc1(&desc);
5974
if (!memcmp(&desc.AdapterLuid, &adapter_luid, sizeof(LUID))) {
5975
break;
5976
}
5977
}
5978
ERR_FAIL_NULL_V(desired_adapter, ERR_CANT_CREATE);
5979
adapter = desired_adapter;
5980
}
5981
5982
ID3D12DeviceFactory *device_factory = context_driver->device_factory_get();
5983
if (device_factory != nullptr) {
5984
res = device_factory->CreateDevice(adapter.Get(), requested_feature_level, IID_PPV_ARGS(device.GetAddressOf()));
5985
} else {
5986
PFN_D3D12_CREATE_DEVICE d3d_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12CreateDevice");
5987
ERR_FAIL_NULL_V(d3d_D3D12CreateDevice, ERR_CANT_CREATE);
5988
5989
res = d3d_D3D12CreateDevice(adapter.Get(), requested_feature_level, IID_PPV_ARGS(device.GetAddressOf()));
5990
}
5991
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
5992
5993
if (D3D12Hooks::get_singleton() != nullptr) {
5994
D3D12Hooks::get_singleton()->set_device(device.Get());
5995
}
5996
5997
if (context_driver->use_validation_layers()) {
5998
ComPtr<ID3D12InfoQueue> info_queue;
5999
res = device.As(&info_queue);
6000
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6001
6002
#if CUSTOM_INFO_QUEUE_ENABLED
6003
ComPtr<ID3D12InfoQueue1> info_queue_1;
6004
device.As(&info_queue_1);
6005
if (info_queue_1) {
6006
// Custom printing supported (added in Windows 10 Release Preview build 20236). Even if the callback cookie is unused, it seems the
6007
// argument is not optional and the function will fail if it's not specified.
6008
DWORD callback_cookie;
6009
info_queue_1->SetMuteDebugOutput(TRUE);
6010
res = info_queue_1->RegisterMessageCallback(&_debug_message_func, D3D12_MESSAGE_CALLBACK_IGNORE_FILTERS, nullptr, &callback_cookie);
6011
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6012
} else
6013
#endif
6014
{
6015
// Rely on D3D12's own debug printing.
6016
if (Engine::get_singleton()->is_abort_on_gpu_errors_enabled()) {
6017
res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_WARNING, TRUE);
6018
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6019
res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, TRUE);
6020
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6021
res = info_queue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, TRUE);
6022
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6023
}
6024
}
6025
6026
D3D12_MESSAGE_SEVERITY severities_to_mute[] = {
6027
D3D12_MESSAGE_SEVERITY_INFO,
6028
};
6029
6030
D3D12_MESSAGE_ID messages_to_mute[] = {
6031
D3D12_MESSAGE_ID_CLEARRENDERTARGETVIEW_MISMATCHINGCLEARVALUE,
6032
D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
6033
// These happen due to how D3D12MA manages buffers; seems benign.
6034
D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_HAS_NO_RESOURCE,
6035
D3D12_MESSAGE_ID_HEAP_ADDRESS_RANGE_INTERSECTS_MULTIPLE_BUFFERS,
6036
// Seemingly a false positive.
6037
D3D12_MESSAGE_ID_DATA_STATIC_WHILE_SET_AT_EXECUTE_DESCRIPTOR_INVALID_DATA_CHANGE,
6038
};
6039
6040
D3D12_INFO_QUEUE_FILTER filter = {};
6041
filter.DenyList.NumSeverities = ARRAY_SIZE(severities_to_mute);
6042
filter.DenyList.pSeverityList = severities_to_mute;
6043
filter.DenyList.NumIDs = ARRAY_SIZE(messages_to_mute);
6044
filter.DenyList.pIDList = messages_to_mute;
6045
6046
res = info_queue->PushStorageFilter(&filter);
6047
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6048
}
6049
6050
return OK;
6051
}
6052
6053
Error RenderingDeviceDriverD3D12::_check_capabilities() {
6054
// Check feature levels.
6055
const D3D_FEATURE_LEVEL FEATURE_LEVELS[] = {
6056
D3D_FEATURE_LEVEL_11_0,
6057
D3D_FEATURE_LEVEL_11_1,
6058
D3D_FEATURE_LEVEL_12_0,
6059
D3D_FEATURE_LEVEL_12_1,
6060
D3D_FEATURE_LEVEL_12_2,
6061
};
6062
6063
D3D12_FEATURE_DATA_FEATURE_LEVELS feat_levels = {};
6064
feat_levels.NumFeatureLevels = ARRAY_SIZE(FEATURE_LEVELS);
6065
feat_levels.pFeatureLevelsRequested = FEATURE_LEVELS;
6066
6067
HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_FEATURE_LEVELS, &feat_levels, sizeof(feat_levels));
6068
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
6069
6070
// Example: D3D_FEATURE_LEVEL_12_1 = 0xc100.
6071
uint32_t feat_level_major = feat_levels.MaxSupportedFeatureLevel >> 12;
6072
uint32_t feat_level_minor = (feat_levels.MaxSupportedFeatureLevel >> 16) & 0xff;
6073
feature_level = feat_level_major * 10 + feat_level_minor;
6074
6075
// Fill device capabilities.
6076
device_capabilities.device_family = DEVICE_DIRECTX;
6077
device_capabilities.version_major = feature_level / 10;
6078
device_capabilities.version_minor = feature_level % 10;
6079
6080
// Assume not supported until proven otherwise.
6081
multiview_capabilities.is_supported = false;
6082
multiview_capabilities.geometry_shader_is_supported = false;
6083
multiview_capabilities.tessellation_shader_is_supported = false;
6084
multiview_capabilities.max_view_count = 0;
6085
multiview_capabilities.max_instance_count = 0;
6086
multiview_capabilities.is_supported = false;
6087
subgroup_capabilities.size = 0;
6088
subgroup_capabilities.wave_ops_supported = false;
6089
shader_capabilities.shader_model = (D3D_SHADER_MODEL)0;
6090
shader_capabilities.native_16bit_ops = false;
6091
format_capabilities.relaxed_casting_supported = false;
6092
6093
{
6094
static const D3D_SHADER_MODEL SMS_TO_CHECK[] = {
6095
D3D_SHADER_MODEL_6_6,
6096
D3D_SHADER_MODEL_6_5,
6097
D3D_SHADER_MODEL_6_4,
6098
D3D_SHADER_MODEL_6_3,
6099
D3D_SHADER_MODEL_6_2,
6100
D3D_SHADER_MODEL_6_1,
6101
D3D_SHADER_MODEL_6_0, // Determined by NIR (dxil_min_shader_model).
6102
};
6103
6104
D3D12_FEATURE_DATA_SHADER_MODEL shader_model = {};
6105
for (uint32_t i = 0; i < ARRAY_SIZE(SMS_TO_CHECK); i++) {
6106
shader_model.HighestShaderModel = SMS_TO_CHECK[i];
6107
res = device->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &shader_model, sizeof(shader_model));
6108
if (SUCCEEDED(res)) {
6109
shader_capabilities.shader_model = shader_model.HighestShaderModel;
6110
break;
6111
}
6112
if (res == E_INVALIDARG) {
6113
continue; // Must assume the device doesn't know about the SM just checked.
6114
}
6115
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
6116
}
6117
6118
#define D3D_SHADER_MODEL_TO_STRING(m_sm) vformat("%d.%d", (m_sm >> 4), (m_sm & 0xf))
6119
6120
ERR_FAIL_COND_V_MSG(shader_capabilities.shader_model < SMS_TO_CHECK[ARRAY_SIZE(SMS_TO_CHECK) - 1], ERR_UNAVAILABLE,
6121
vformat("No support for any of the suitable shader models (%s-%s) has been found.", D3D_SHADER_MODEL_TO_STRING(SMS_TO_CHECK[ARRAY_SIZE(SMS_TO_CHECK) - 1]), D3D_SHADER_MODEL_TO_STRING(SMS_TO_CHECK[0])));
6122
6123
print_verbose("- Shader:");
6124
print_verbose(" model: " + D3D_SHADER_MODEL_TO_STRING(shader_capabilities.shader_model));
6125
}
6126
6127
shader_container_format.set_lib_d3d12(context_driver->lib_d3d12);
6128
6129
D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
6130
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
6131
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
6132
ERR_FAIL_COND_V_MSG(!options.TypedUAVLoadAdditionalFormats, ERR_UNAVAILABLE, "No support for Typed UAV Load Additional Formats has been found.");
6133
6134
D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1 = {};
6135
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &options1, sizeof(options1));
6136
if (SUCCEEDED(res)) {
6137
subgroup_capabilities.size = options1.WaveLaneCountMin;
6138
subgroup_capabilities.wave_ops_supported = options1.WaveOps;
6139
}
6140
6141
D3D12_FEATURE_DATA_D3D12_OPTIONS2 options2 = {};
6142
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS2, &options2, sizeof(options2));
6143
if (SUCCEEDED(res)) {
6144
misc_features_support.depth_bounds_supported = options2.DepthBoundsTestSupported;
6145
}
6146
6147
D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
6148
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3));
6149
if (SUCCEEDED(res)) {
6150
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_view_instancing_tier
6151
// https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html#sv_viewid
6152
if (options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_1) {
6153
multiview_capabilities.is_supported = true;
6154
multiview_capabilities.geometry_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;
6155
multiview_capabilities.tessellation_shader_is_supported = options3.ViewInstancingTier >= D3D12_VIEW_INSTANCING_TIER_3;
6156
multiview_capabilities.max_view_count = D3D12_MAX_VIEW_INSTANCE_COUNT;
6157
multiview_capabilities.max_instance_count = UINT32_MAX;
6158
}
6159
}
6160
6161
D3D12_FEATURE_DATA_D3D12_OPTIONS4 options4 = {};
6162
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS4, &options4, sizeof(options4));
6163
if (SUCCEEDED(res)) {
6164
shader_capabilities.native_16bit_ops = options4.Native16BitShaderOpsSupported;
6165
}
6166
6167
D3D12_FEATURE_DATA_D3D12_OPTIONS6 options6 = {};
6168
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS6, &options6, sizeof(options6));
6169
if (SUCCEEDED(res)) {
6170
if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_1) {
6171
fsr_capabilities.pipeline_supported = true;
6172
if (options6.VariableShadingRateTier >= D3D12_VARIABLE_SHADING_RATE_TIER_2) {
6173
fsr_capabilities.primitive_supported = true;
6174
fsr_capabilities.attachment_supported = true;
6175
fsr_capabilities.min_texel_size = Size2i(options6.ShadingRateImageTileSize, options6.ShadingRateImageTileSize);
6176
fsr_capabilities.max_texel_size = Size2i(8, 8);
6177
}
6178
}
6179
}
6180
6181
D3D12_FEATURE_DATA_D3D12_OPTIONS12 options12 = {};
6182
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS12, &options12, sizeof(options12));
6183
if (SUCCEEDED(res)) {
6184
format_capabilities.relaxed_casting_supported = options12.RelaxedFormatCastingSupported;
6185
barrier_capabilities.enhanced_barriers_supported = options12.EnhancedBarriersSupported;
6186
}
6187
6188
D3D12_FEATURE_DATA_D3D12_OPTIONS19 options19 = {};
6189
res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS19, &options19, sizeof(options19));
6190
if (SUCCEEDED(res)) {
6191
sampler_capabilities.aniso_filter_with_point_mip_supported = options19.AnisoFilterWithPointMipSupported;
6192
}
6193
6194
if (fsr_capabilities.pipeline_supported || fsr_capabilities.primitive_supported || fsr_capabilities.attachment_supported) {
6195
print_verbose("- D3D12 Variable Rate Shading supported:");
6196
if (fsr_capabilities.pipeline_supported) {
6197
print_verbose(" Draw call");
6198
}
6199
if (fsr_capabilities.primitive_supported) {
6200
print_verbose(" Primitive");
6201
}
6202
if (fsr_capabilities.attachment_supported) {
6203
print_verbose(String(" Screen-space image (tile size: ") + itos(fsr_capabilities.min_texel_size.x) + ")");
6204
}
6205
} else {
6206
print_verbose("- D3D12 Variable Rate Shading not supported");
6207
}
6208
6209
if (multiview_capabilities.is_supported) {
6210
print_verbose("- D3D12 multiview supported:");
6211
print_verbose(" max view count: " + itos(multiview_capabilities.max_view_count));
6212
//print_verbose(" max instances: " + itos(multiview_capabilities.max_instance_count)); // Hardcoded; not very useful at the moment.
6213
} else {
6214
print_verbose("- D3D12 multiview not supported");
6215
}
6216
6217
if (format_capabilities.relaxed_casting_supported) {
6218
#if 0
6219
print_verbose("- Relaxed casting supported");
6220
#else
6221
// Certain configurations (Windows 11 with an updated NVIDIA driver) crash when using relaxed casting.
6222
// Therefore, we disable it temporarily until we can assure that it's reliable.
6223
// There are fallbacks in place that work in every case, if less efficient.
6224
format_capabilities.relaxed_casting_supported = false;
6225
print_verbose("- Relaxed casting supported (but disabled for now)");
6226
#endif
6227
} else {
6228
print_verbose("- Relaxed casting not supported");
6229
}
6230
6231
print_verbose(String("- D3D12 16-bit ops supported: ") + (shader_capabilities.native_16bit_ops ? "yes" : "no"));
6232
6233
if (misc_features_support.depth_bounds_supported) {
6234
print_verbose("- Depth bounds test supported");
6235
} else {
6236
print_verbose("- Depth bounds test not supported");
6237
}
6238
6239
return OK;
6240
}
6241
6242
Error RenderingDeviceDriverD3D12::_get_device_limits() {
6243
D3D12_FEATURE_DATA_D3D12_OPTIONS options = {};
6244
HRESULT res = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS, &options, sizeof(options));
6245
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_UNAVAILABLE, "CheckFeatureSupport failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
6246
6247
// https://docs.microsoft.com/en-us/windows/win32/direct3d12/hardware-support
6248
device_limits.max_srvs_per_shader_stage = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 128 : UINT64_MAX;
6249
device_limits.max_cbvs_per_shader_stage = options.ResourceBindingTier <= D3D12_RESOURCE_BINDING_TIER_2 ? 14 : UINT64_MAX;
6250
device_limits.max_samplers_across_all_stages = options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1 ? 16 : 2048;
6251
if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_1) {
6252
device_limits.max_uavs_across_all_stages = feature_level <= 110 ? 8 : 64;
6253
} else if (options.ResourceBindingTier == D3D12_RESOURCE_BINDING_TIER_2) {
6254
device_limits.max_uavs_across_all_stages = 64;
6255
} else {
6256
device_limits.max_uavs_across_all_stages = UINT64_MAX;
6257
}
6258
6259
// Retrieving the timestamp frequency requires creating a command queue that will be discarded immediately.
6260
ComPtr<ID3D12CommandQueue> unused_command_queue;
6261
D3D12_COMMAND_QUEUE_DESC queue_desc = {};
6262
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
6263
res = device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(unused_command_queue.GetAddressOf()));
6264
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6265
6266
res = unused_command_queue->GetTimestampFrequency(&device_limits.timestamp_frequency);
6267
if (!SUCCEEDED(res)) {
6268
print_verbose("D3D12: GetTimestampFrequency failed with error " + vformat("0x%08ux", (uint64_t)res) + ". Timestamps will be inaccurate.");
6269
}
6270
6271
return OK;
6272
}
6273
6274
Error RenderingDeviceDriverD3D12::_initialize_allocator() {
6275
D3D12MA::ALLOCATOR_DESC allocator_desc = {};
6276
allocator_desc.pDevice = device.Get();
6277
allocator_desc.pAdapter = adapter.Get();
6278
allocator_desc.Flags = D3D12MA::ALLOCATOR_FLAG_DEFAULT_POOLS_NOT_ZEROED | D3D12MA::ALLOCATOR_FLAG_DONT_PREFER_SMALL_BUFFERS_COMMITTED;
6279
6280
HRESULT res = D3D12MA::CreateAllocator(&allocator_desc, &allocator);
6281
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12MA::CreateAllocator failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
6282
6283
if (allocator->IsGPUUploadHeapSupported()) {
6284
dynamic_persistent_upload_heap = D3D12_HEAP_TYPE_GPU_UPLOAD;
6285
print_verbose("D3D12: Device supports GPU UPLOAD heap.");
6286
} else {
6287
dynamic_persistent_upload_heap = D3D12_HEAP_TYPE_UPLOAD;
6288
// Print it as a warning (instead of verbose) because in the rare chance this lesser-used code path
6289
// causes bugs, we get an inkling of what's going on (i.e. in order to repro bugs locally).
6290
print_verbose("D3D12: Device does NOT support GPU UPLOAD heap. ReBAR must be enabled for this feature. Regular UPLOAD heaps will be used as fallback.");
6291
}
6292
6293
return OK;
6294
}
6295
6296
static Error create_command_signature(ID3D12Device *device, D3D12_INDIRECT_ARGUMENT_TYPE p_type, uint32_t p_stride, ComPtr<ID3D12CommandSignature> *r_cmd_sig) {
6297
D3D12_INDIRECT_ARGUMENT_DESC iarg_desc = {};
6298
iarg_desc.Type = p_type;
6299
D3D12_COMMAND_SIGNATURE_DESC cs_desc = {};
6300
cs_desc.ByteStride = p_stride;
6301
cs_desc.NumArgumentDescs = 1;
6302
cs_desc.pArgumentDescs = &iarg_desc;
6303
cs_desc.NodeMask = 0;
6304
HRESULT res = device->CreateCommandSignature(&cs_desc, nullptr, IID_PPV_ARGS(r_cmd_sig->GetAddressOf()));
6305
ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "CreateCommandSignature failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
6306
return OK;
6307
}
6308
6309
Error RenderingDeviceDriverD3D12::_initialize_frames(uint32_t p_frame_count) {
6310
uint32_t num_resource_descriptors = GLOBAL_GET("rendering/rendering_device/d3d12/max_resource_descriptors");
6311
uint32_t num_sampler_descriptors = GLOBAL_GET("rendering/rendering_device/d3d12/max_sampler_descriptors");
6312
6313
Error err = resource_descriptor_heap.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, num_resource_descriptors, true);
6314
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6315
6316
err = sampler_descriptor_heap.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, num_sampler_descriptors, true);
6317
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6318
6319
resource_descriptor_heap_pool.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
6320
rtv_descriptor_heap_pool.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
6321
dsv_descriptor_heap_pool.initialize(device.Get(), D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
6322
6323
err = rtv_descriptor_heap_pool.allocate(1, device.Get(), null_rtv_alloc);
6324
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6325
6326
D3D12_RENDER_TARGET_VIEW_DESC rtv_desc_null = {};
6327
rtv_desc_null.Format = DXGI_FORMAT_R8_UINT;
6328
rtv_desc_null.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
6329
device->CreateRenderTargetView(nullptr, &rtv_desc_null, null_rtv_alloc.cpu_handle);
6330
6331
frames.resize(p_frame_count);
6332
6333
return OK;
6334
}
6335
6336
Error RenderingDeviceDriverD3D12::_initialize_command_signatures() {
6337
Error err = create_command_signature(device.Get(), D3D12_INDIRECT_ARGUMENT_TYPE_DRAW, sizeof(D3D12_DRAW_ARGUMENTS), &indirect_cmd_signatures.draw);
6338
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6339
6340
err = create_command_signature(device.Get(), D3D12_INDIRECT_ARGUMENT_TYPE_DRAW_INDEXED, sizeof(D3D12_DRAW_INDEXED_ARGUMENTS), &indirect_cmd_signatures.draw_indexed);
6341
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6342
6343
err = create_command_signature(device.Get(), D3D12_INDIRECT_ARGUMENT_TYPE_DISPATCH, sizeof(D3D12_DISPATCH_ARGUMENTS), &indirect_cmd_signatures.dispatch);
6344
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6345
6346
return OK;
6347
}
6348
6349
Error RenderingDeviceDriverD3D12::initialize(uint32_t p_device_index, uint32_t p_frame_count) {
6350
glsl_type_singleton_init_or_ref();
6351
6352
context_device = context_driver->device_get(p_device_index);
6353
adapter.Attach(context_driver->create_adapter(p_device_index));
6354
ERR_FAIL_NULL_V(adapter, ERR_CANT_CREATE);
6355
6356
DXGI_ADAPTER_DESC adapter_desc;
6357
HRESULT res = adapter->GetDesc(&adapter_desc);
6358
ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE);
6359
6360
// Set the pipeline cache ID based on the adapter information.
6361
pipeline_cache_id = String::hex_encode_buffer((uint8_t *)&adapter_desc.AdapterLuid, sizeof(LUID));
6362
pipeline_cache_id += "-driver-" + itos(adapter_desc.Revision);
6363
6364
Error err = _initialize_device();
6365
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6366
6367
err = _check_capabilities();
6368
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6369
6370
err = _get_device_limits();
6371
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6372
6373
err = _initialize_allocator();
6374
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6375
6376
err = _initialize_frames(p_frame_count);
6377
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6378
6379
err = _initialize_command_signatures();
6380
ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE);
6381
6382
return OK;
6383
}
6384
6385