-
Notifications
You must be signed in to change notification settings - Fork 2k
/
DXSampleHelper.h
253 lines (218 loc) · 6.74 KB
/
DXSampleHelper.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
//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
#pragma once
#include <stdexcept>
// Note that while ComPtr is used to manage the lifetime of resources on the CPU,
// it has no understanding of the lifetime of resources on the GPU. Apps must account
// for the GPU lifetime of resources to avoid destroying objects that may still be
// referenced by the GPU.
using Microsoft::WRL::ComPtr;
inline std::string HrToString(HRESULT hr)
{
char s_str[64] = {};
sprintf_s(s_str, "HRESULT of 0x%08X", static_cast<UINT>(hr));
return std::string(s_str);
}
class HrException : public std::runtime_error
{
public:
HrException(HRESULT hr) : std::runtime_error(HrToString(hr)), m_hr(hr) {}
HRESULT Error() const { return m_hr; }
private:
const HRESULT m_hr;
};
#define SAFE_RELEASE(p) if (p) (p)->Release()
inline void ThrowIfFailed(HRESULT hr)
{
if (FAILED(hr))
{
throw HrException(hr);
}
}
inline void GetAssetsPath(_Out_writes_(pathSize) WCHAR* path, UINT pathSize)
{
if (path == nullptr)
{
throw std::exception();
}
DWORD size = GetModuleFileName(nullptr, path, pathSize);
if (size == 0 || size == pathSize)
{
// Method failed or path was truncated.
throw std::exception();
}
WCHAR* lastSlash = wcsrchr(path, L'\\');
if (lastSlash)
{
*(lastSlash + 1) = L'\0';
}
}
inline HRESULT ReadDataFromFile(LPCWSTR filename, byte** data, UINT* size)
{
using namespace Microsoft::WRL;
#if WINVER >= _WIN32_WINNT_WIN8
CREATEFILE2_EXTENDED_PARAMETERS extendedParams = {};
extendedParams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
extendedParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
extendedParams.dwFileFlags = FILE_FLAG_SEQUENTIAL_SCAN;
extendedParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
extendedParams.lpSecurityAttributes = nullptr;
extendedParams.hTemplateFile = nullptr;
Wrappers::FileHandle file(CreateFile2(filename, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &extendedParams));
#else
Wrappers::FileHandle file(CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, nullptr));
#endif
if (file.Get() == INVALID_HANDLE_VALUE)
{
throw std::exception();
}
FILE_STANDARD_INFO fileInfo = {};
if (!GetFileInformationByHandleEx(file.Get(), FileStandardInfo, &fileInfo, sizeof(fileInfo)))
{
throw std::exception();
}
if (fileInfo.EndOfFile.HighPart != 0)
{
throw std::exception();
}
*data = reinterpret_cast<byte*>(malloc(fileInfo.EndOfFile.LowPart));
*size = fileInfo.EndOfFile.LowPart;
if (!ReadFile(file.Get(), *data, fileInfo.EndOfFile.LowPart, nullptr, nullptr))
{
throw std::exception();
}
return S_OK;
}
inline HRESULT ReadDataFromDDSFile(LPCWSTR filename, byte** data, UINT* offset, UINT* size)
{
if (FAILED(ReadDataFromFile(filename, data, size)))
{
return E_FAIL;
}
// DDS files always start with the same magic number.
static const UINT DDS_MAGIC = 0x20534444;
UINT magicNumber = *reinterpret_cast<const UINT*>(*data);
if (magicNumber != DDS_MAGIC)
{
return E_FAIL;
}
struct DDS_PIXELFORMAT
{
UINT size;
UINT flags;
UINT fourCC;
UINT rgbBitCount;
UINT rBitMask;
UINT gBitMask;
UINT bBitMask;
UINT aBitMask;
};
struct DDS_HEADER
{
UINT size;
UINT flags;
UINT height;
UINT width;
UINT pitchOrLinearSize;
UINT depth;
UINT mipMapCount;
UINT reserved1[11];
DDS_PIXELFORMAT ddsPixelFormat;
UINT caps;
UINT caps2;
UINT caps3;
UINT caps4;
UINT reserved2;
};
auto ddsHeader = reinterpret_cast<const DDS_HEADER*>(*data + sizeof(UINT));
if (ddsHeader->size != sizeof(DDS_HEADER) || ddsHeader->ddsPixelFormat.size != sizeof(DDS_PIXELFORMAT))
{
return E_FAIL;
}
const ptrdiff_t ddsDataOffset = sizeof(UINT) + sizeof(DDS_HEADER);
*offset = ddsDataOffset;
*size = *size - ddsDataOffset;
return S_OK;
}
// Assign a name to the object to aid with debugging.
#if defined(_DEBUG) || defined(DBG)
inline void SetName(ID3D12Object* pObject, LPCWSTR name)
{
pObject->SetName(name);
}
inline void SetNameIndexed(ID3D12Object* pObject, LPCWSTR name, UINT index)
{
WCHAR fullName[50];
if (swprintf_s(fullName, L"%s[%u]", name, index) > 0)
{
pObject->SetName(fullName);
}
}
#else
inline void SetName(ID3D12Object*, LPCWSTR)
{
}
inline void SetNameIndexed(ID3D12Object*, LPCWSTR, UINT)
{
}
#endif
// Naming helper for ComPtr<T>.
// Assigns the name of the variable as the name of the object.
// The indexed variant will include the index in the name of the object.
#define NAME_D3D12_OBJECT(x) SetName((x).Get(), L#x)
#define NAME_D3D12_OBJECT_INDEXED(x, n) SetNameIndexed((x)[n].Get(), L#x, n)
inline UINT CalculateConstantBufferByteSize(UINT byteSize)
{
// Constant buffer size is required to be aligned.
return (byteSize + (D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1)) & ~(D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT - 1);
}
#ifdef D3D_COMPILE_STANDARD_FILE_INCLUDE
inline Microsoft::WRL::ComPtr<ID3DBlob> CompileShader(
const std::wstring& filename,
const D3D_SHADER_MACRO* defines,
const std::string& entrypoint,
const std::string& target)
{
UINT compileFlags = 0;
#if defined(_DEBUG) || defined(DBG)
compileFlags = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION;
#endif
HRESULT hr;
Microsoft::WRL::ComPtr<ID3DBlob> byteCode = nullptr;
Microsoft::WRL::ComPtr<ID3DBlob> errors;
hr = D3DCompileFromFile(filename.c_str(), defines, D3D_COMPILE_STANDARD_FILE_INCLUDE,
entrypoint.c_str(), target.c_str(), compileFlags, 0, &byteCode, &errors);
if (errors != nullptr)
{
OutputDebugStringA((char*)errors->GetBufferPointer());
}
ThrowIfFailed(hr);
return byteCode;
}
#endif
// Resets all elements in a ComPtr array.
template<class T>
void ResetComPtrArray(T* comPtrArray)
{
for (auto &i : *comPtrArray)
{
i.Reset();
}
}
// Resets all elements in a unique_ptr array.
template<class T>
void ResetUniquePtrArray(T* uniquePtrArray)
{
for (auto &i : *uniquePtrArray)
{
i.reset();
}
}