-
Notifications
You must be signed in to change notification settings - Fork 0
/
d3dUtil.h
344 lines (291 loc) · 11 KB
/
d3dUtil.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
//***************************************************************************************
// d3dUtil.h by Frank Luna (C) 2015 All Rights Reserved.
//
// General helper code.
//***************************************************************************************
#pragma once
#include <windows.h>
#include <wrl.h>
#include <dxgi1_4.h>
#include <d3d12.h>
#include <D3Dcompiler.h>
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <DirectXColors.h>
#include <DirectXCollision.h>
#include <string>
#include <memory>
#include <algorithm>
#include <vector>
#include <array>
#include <unordered_map>
#include <cstdint>
#include <fstream>
#include <sstream>
#include <cassert>
#include "d3dx12.h"
#include "DDSTextureLoader.h"
#include "MathHelper.h"
extern const int gNumFrameResources;
inline void d3dSetDebugName(IDXGIObject* obj, const char* name)
{
if(obj)
{
obj->SetPrivateData(WKPDID_D3DDebugObjectName, lstrlenA(name), name);
}
}
inline void d3dSetDebugName(ID3D12Device* obj, const char* name)
{
if(obj)
{
obj->SetPrivateData(WKPDID_D3DDebugObjectName, lstrlenA(name), name);
}
}
inline void d3dSetDebugName(ID3D12DeviceChild* obj, const char* name)
{
if(obj)
{
obj->SetPrivateData(WKPDID_D3DDebugObjectName, lstrlenA(name), name);
}
}
inline std::wstring AnsiToWString(const std::string& str)
{
WCHAR buffer[512];
MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, buffer, 512);
return std::wstring(buffer);
}
/*
#if defined(_DEBUG)
#ifndef Assert
#define Assert(x, description) \
{ \
static bool ignoreAssert = false; \
if(!ignoreAssert && !(x)) \
{ \
Debug::AssertResult result = Debug::ShowAssertDialog( \
(L#x), description, AnsiToWString(__FILE__), __LINE__); \
if(result == Debug::AssertIgnore) \
{ \
ignoreAssert = true; \
} \
else if(result == Debug::AssertBreak) \
{ \
__debugbreak(); \
} \
} \
}
#endif
#else
#ifndef Assert
#define Assert(x, description)
#endif
#endif
*/
class d3dUtil
{
public:
static bool IsKeyDown(int vkeyCode);
static std::string ToString(HRESULT hr);
static UINT CalcConstantBufferByteSize(UINT byteSize)
{
// Constant buffers must be a multiple of the minimum hardware
// allocation size (usually 256 bytes). So round up to nearest
// multiple of 256. We do this by adding 255 and then masking off
// the lower 2 bytes which store all bits < 256.
// Example: Suppose byteSize = 300.
// (300 + 255) & ~255
// 555 & ~255
// 0x022B & ~0x00ff
// 0x022B & 0xff00
// 0x0200
// 512
return (byteSize + 255) & ~255;
}
static Microsoft::WRL::ComPtr<ID3DBlob> LoadBinary(const std::wstring& filename);
static Microsoft::WRL::ComPtr<ID3D12Resource> CreateDefaultBuffer(
ID3D12Device* device,
ID3D12GraphicsCommandList* cmdList,
const void* initData,
UINT64 byteSize,
Microsoft::WRL::ComPtr<ID3D12Resource>& uploadBuffer);
static Microsoft::WRL::ComPtr<ID3DBlob> CompileShader(
const std::wstring& filename,
const D3D_SHADER_MACRO* defines,
const std::string& entrypoint,
const std::string& target);
};
class DxException
{
public:
DxException() = default;
DxException(HRESULT hr, const std::wstring& functionName, const std::wstring& filename, int lineNumber);
std::wstring ToString()const;
HRESULT ErrorCode = S_OK;
std::wstring FunctionName;
std::wstring Filename;
int LineNumber = -1;
};
// Defines a subrange of geometry in a MeshGeometry. This is for when multiple
// geometries are stored in one vertex and index buffer. It provides the offsets
// and data needed to draw a subset of geometry stores in the vertex and index
// buffers so that we can implement the technique described by Figure 6.3.
struct SubmeshGeometry
{
UINT IndexCount = 0;
UINT StartIndexLocation = 0;
INT BaseVertexLocation = 0;
// Bounding box of the geometry defined by this submesh.
// This is used in later chapters of the book.
DirectX::BoundingBox Bounds;
};
struct MeshGeometry
{
// Give it a name so we can look it up by name.
std::string Name;
// System memory copies. Use Blobs because the vertex/index format can be generic.
// It is up to the client to cast appropriately.
Microsoft::WRL::ComPtr<ID3DBlob> VertexBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> NormalBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> UvBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> IndexBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> MaterialBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> MeshBufferCPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> NormalBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> UvBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> MaterialBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> MeshBufferGPU = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> VertexBufferUploader = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> NormalBufferUploader = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> UvBufferUploader = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> IndexBufferUploader = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> MaterialBufferUploader = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> MeshBufferUploader = nullptr;
// Data about the buffers.
UINT VertexByteStride = 0;
UINT VertexBufferByteSize = 0;
UINT NormalByteStride = 0;
UINT NormalBufferByteSize = 0;
UINT UvByteStride = 0;
UINT UvBufferByteSize = 0;
UINT MaterialByteStride = 0;
UINT MaterialBufferByteSize = 0;
UINT MeshByteStride = 0;
UINT MeshBufferByteSize = 0;
DXGI_FORMAT IndexFormat = DXGI_FORMAT_R16_UINT;
UINT IndexBufferByteSize = 0;
// A MeshGeometry may store multiple geometries in one vertex/index buffer.
// Use this container to define the Submesh geometries so we can draw
// the Submeshes individually.
std::unordered_map<std::string, SubmeshGeometry> DrawArgs;
D3D12_VERTEX_BUFFER_VIEW VertexBufferView()const
{
D3D12_VERTEX_BUFFER_VIEW vbv{};
vbv.BufferLocation = VertexBufferGPU->GetGPUVirtualAddress();
vbv.StrideInBytes = VertexByteStride;
vbv.SizeInBytes = VertexBufferByteSize;
return vbv;
}
D3D12_VERTEX_BUFFER_VIEW NormalBufferView()const
{
D3D12_VERTEX_BUFFER_VIEW vbv{};
vbv.BufferLocation = NormalBufferGPU->GetGPUVirtualAddress();
vbv.StrideInBytes = NormalByteStride;
vbv.SizeInBytes = NormalBufferByteSize;
return vbv;
}
D3D12_VERTEX_BUFFER_VIEW UvBufferView()const
{
D3D12_VERTEX_BUFFER_VIEW vbv{};
vbv.BufferLocation = UvBufferGPU->GetGPUVirtualAddress();
vbv.StrideInBytes = UvByteStride;
vbv.SizeInBytes = UvBufferByteSize;
return vbv;
}
D3D12_INDEX_BUFFER_VIEW IndexBufferView()const
{
D3D12_INDEX_BUFFER_VIEW ibv{};
ibv.BufferLocation = IndexBufferGPU->GetGPUVirtualAddress();
ibv.Format = IndexFormat;
ibv.SizeInBytes = IndexBufferByteSize;
return ibv;
}
D3D12_INDEX_BUFFER_VIEW MaterialBufferView()const
{
D3D12_INDEX_BUFFER_VIEW ibv{};
ibv.BufferLocation = MaterialBufferGPU->GetGPUVirtualAddress();
ibv.Format = IndexFormat;
ibv.SizeInBytes = IndexBufferByteSize;
return ibv;
}
// We can free this memory after we finish upload to the GPU.
void DisposeUploaders()
{
VertexBufferUploader = nullptr;
NormalBufferUploader = nullptr;
UvBufferUploader = nullptr;
IndexBufferUploader = nullptr;
MaterialBufferUploader = nullptr;
}
};
struct Light
{
DirectX::XMFLOAT3 Strength = { 0.5f, 0.5f, 0.5f };
float FalloffStart = 1.0f; // point/spot light only
DirectX::XMFLOAT3 Direction = { 0.0f, -1.0f, 0.0f };// directional/spot light only
float FalloffEnd = 10.0f; // point/spot light only
DirectX::XMFLOAT3 Position = { 0.0f, 0.0f, 0.0f }; // point/spot light only
float SpotPower = 64.0f; // spot light only
};
#define MaxLights 16
struct MaterialConstants
{
DirectX::XMFLOAT4 DiffuseAlbedo = { 1.0f, 1.0f, 1.0f, 1.0f };
DirectX::XMFLOAT3 FresnelR0 = { 0.01f, 0.01f, 0.01f };
float Roughness = 0.25f;
// Used in texture mapping.
DirectX::XMFLOAT4X4 MatTransform = MathHelper::Identity4x4();
};
// Simple struct to represent a material for our demos. A production 3D engine
// would likely create a class hierarchy of Materials.
struct Material
{
// Unique material name for lookup.
std::string Name;
// Index into constant buffer corresponding to this material.
int MatCBIndex = -1;
// Index into SRV heap for diffuse texture.
int DiffuseSrvHeapIndex = -1;
// Index into SRV heap for normal texture.
int NormalSrvHeapIndex = -1;
// Dirty flag indicating the material has changed and we need to update the constant buffer.
// Because we have a material constant buffer for each FrameResource, we have to apply the
// update to each FrameResource. Thus, when we modify a material we should set
// NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
int NumFramesDirty = gNumFrameResources;
// Material constant buffer data used for shading.
DirectX::XMFLOAT4 DiffuseAlbedo = { 1.0f, 1.0f, 1.0f, 1.0f };
DirectX::XMFLOAT3 FresnelR0 = { 0.01f, 0.01f, 0.01f };
float Roughness = .25f;
DirectX::XMFLOAT4X4 MatTransform = MathHelper::Identity4x4();
};
struct Texture
{
// Unique material name for lookup.
std::string Name;
std::wstring Filename;
Microsoft::WRL::ComPtr<ID3D12Resource> Resource = nullptr;
Microsoft::WRL::ComPtr<ID3D12Resource> UploadHeap = nullptr;
};
#ifndef ThrowIfFailed
#define ThrowIfFailed(x) \
{ \
HRESULT hr__ = (x); \
std::wstring wfn = AnsiToWString(__FILE__); \
if(FAILED(hr__)) { throw DxException(hr__, L#x, wfn, __LINE__); } \
}
#endif
#ifndef ReleaseCom
#define ReleaseCom(x) { if(x){ x->Release(); x = 0; } }
#endif