HlslTestUtils.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // HlslTestUtils.h //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides utility functions for HLSL tests. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include <string>
  12. #include <sstream>
  13. #include <fstream>
  14. #include <atomic>
  15. #include <cmath>
  16. #include <vector>
  17. #include <algorithm>
  18. #ifdef _WIN32
  19. #include <dxgiformat.h>
  20. #include "WexTestClass.h"
  21. #else
  22. #include "dxc/Support/Global.h" // DXASSERT_LOCALVAR
  23. #include "WEXAdapter.h"
  24. #endif
  25. #include "dxc/Support/Unicode.h"
  26. #include "dxc/DXIL/DxilConstants.h" // DenormMode
  27. using namespace std;
  28. #ifndef HLSLDATAFILEPARAM
  29. #define HLSLDATAFILEPARAM L"HlslDataDir"
  30. #endif
  31. #ifndef FILECHECKDUMPDIRPARAM
  32. #define FILECHECKDUMPDIRPARAM L"FileCheckDumpDir"
  33. #endif
  34. // If TAEF verify macros are available, use them to alias other legacy
  35. // comparison macros that don't have a direct translation.
  36. //
  37. // Other common replacements are as follows.
  38. //
  39. // EXPECT_EQ -> VERIFY_ARE_EQUAL
  40. // ASSERT_EQ -> VERIFY_ARE_EQUAL
  41. //
  42. // Note that whether verification throws or continues depends on
  43. // preprocessor settings.
  44. #ifdef VERIFY_ARE_EQUAL
  45. #ifndef EXPECT_STREQ
  46. #define EXPECT_STREQ(a, b) VERIFY_ARE_EQUAL(0, strcmp(a, b))
  47. #endif
  48. #define EXPECT_STREQW(a, b) VERIFY_ARE_EQUAL(0, wcscmp(a, b))
  49. #define VERIFY_ARE_EQUAL_CMP(a, b, ...) VERIFY_IS_TRUE(a == b, __VA_ARGS__)
  50. #define VERIFY_ARE_EQUAL_STR(a, b) { \
  51. const char *pTmpA = (a);\
  52. const char *pTmpB = (b);\
  53. if (0 != strcmp(pTmpA, pTmpB)) {\
  54. CA2W conv(pTmpB, CP_UTF8); WEX::Logging::Log::Comment(conv);\
  55. const char *pA = pTmpA; const char *pB = pTmpB; \
  56. while(*pA == *pB) { pA++; pB++; } \
  57. wchar_t diffMsg[32]; swprintf_s(diffMsg, _countof(diffMsg), L"diff at %u", (unsigned)(pA-pTmpA)); \
  58. WEX::Logging::Log::Comment(diffMsg); \
  59. } \
  60. VERIFY_ARE_EQUAL(0, strcmp(pTmpA, pTmpB)); \
  61. }
  62. #define VERIFY_ARE_EQUAL_WSTR(a, b) { \
  63. if (0 != wcscmp(a, b)) { WEX::Logging::Log::Comment(b);} \
  64. VERIFY_ARE_EQUAL(0, wcscmp(a, b)); \
  65. }
  66. #ifndef ASSERT_EQ
  67. #define ASSERT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual)
  68. #endif
  69. #ifndef ASSERT_NE
  70. #define ASSERT_NE(expected, actual) VERIFY_ARE_NOT_EQUAL(expected, actual)
  71. #endif
  72. #ifndef TEST_F
  73. #define TEST_F(typeName, functionName) void typeName::functionName()
  74. #endif
  75. #define ASSERT_HRESULT_SUCCEEDED VERIFY_SUCCEEDED
  76. #ifndef EXPECT_EQ
  77. #define EXPECT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual)
  78. #endif
  79. #endif // VERIFY_ARE_EQUAL
  80. static constexpr char whitespaceChars[] = " \t\r\n";
  81. inline std::string strltrim(const std::string &value) {
  82. size_t first = value.find_first_not_of(whitespaceChars);
  83. return first == string::npos ? value : value.substr(first);
  84. }
  85. inline std::string strrtrim(const std::string &value) {
  86. size_t last = value.find_last_not_of(whitespaceChars);
  87. return last == string::npos ? value : value.substr(0, last + 1);
  88. }
  89. inline std::string strtrim(const std::string &value) {
  90. return strltrim(strrtrim(value));
  91. }
  92. inline bool strstartswith(const std::string& value, const char* pattern) {
  93. for (size_t i = 0; ; ++i) {
  94. if (pattern[i] == '\0') return true;
  95. if (i == value.size() || value[i] != pattern[i]) return false;
  96. }
  97. }
  98. inline std::vector<std::string> strtok(const std::string &value, const char *delimiters = whitespaceChars) {
  99. size_t searchOffset = 0;
  100. std::vector<std::string> tokens;
  101. while (searchOffset != value.size()) {
  102. size_t tokenStartIndex = value.find_first_not_of(delimiters, searchOffset);
  103. if (tokenStartIndex == std::string::npos) break;
  104. size_t tokenEndIndex = value.find_first_of(delimiters, tokenStartIndex);
  105. if (tokenEndIndex == std::string::npos) tokenEndIndex = value.size();
  106. tokens.emplace_back(value.substr(tokenStartIndex, tokenEndIndex - tokenStartIndex));
  107. searchOffset = tokenEndIndex;
  108. }
  109. return tokens;
  110. }
  111. namespace hlsl_test {
  112. inline std::wstring
  113. vFormatToWString(_In_z_ _Printf_format_string_ const wchar_t *fmt, va_list argptr) {
  114. std::wstring result;
  115. #ifdef _WIN32
  116. int len = _vscwprintf(fmt, argptr);
  117. result.resize(len + 1);
  118. vswprintf_s((wchar_t *)result.data(), len + 1, fmt, argptr);
  119. #else
  120. wchar_t fmtOut[1000];
  121. int len = vswprintf(fmtOut, 1000, fmt, argptr);
  122. DXASSERT_LOCALVAR(len, len >= 0,
  123. "Too long formatted string in vFormatToWstring");
  124. result = fmtOut;
  125. #endif
  126. return result;
  127. }
  128. inline std::wstring
  129. FormatToWString(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
  130. va_list args;
  131. va_start(args, fmt);
  132. std::wstring result(vFormatToWString(fmt, args));
  133. va_end(args);
  134. return result;
  135. }
  136. inline void LogCommentFmt(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
  137. va_list args;
  138. va_start(args, fmt);
  139. std::wstring buf(vFormatToWString(fmt, args));
  140. va_end(args);
  141. WEX::Logging::Log::Comment(buf.data());
  142. }
  143. inline void LogErrorFmt(_In_z_ _Printf_format_string_ const wchar_t *fmt, ...) {
  144. va_list args;
  145. va_start(args, fmt);
  146. std::wstring buf(vFormatToWString(fmt, args));
  147. va_end(args);
  148. WEX::Logging::Log::Error(buf.data());
  149. }
  150. inline std::wstring GetPathToHlslDataFile(const wchar_t* relative, LPCWSTR paramName = HLSLDATAFILEPARAM) {
  151. WEX::TestExecution::SetVerifyOutput verifySettings(WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures);
  152. WEX::Common::String HlslDataDirValue;
  153. if (std::wstring(paramName).compare(HLSLDATAFILEPARAM) != 0) {
  154. // Not fatal, for instance, FILECHECKDUMPDIRPARAM will dump files before running FileCheck, so they can be compared run to run
  155. if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(paramName, HlslDataDirValue)))
  156. return std::wstring();
  157. } else {
  158. ASSERT_HRESULT_SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(HLSLDATAFILEPARAM, HlslDataDirValue));
  159. }
  160. wchar_t envPath[MAX_PATH];
  161. wchar_t expanded[MAX_PATH];
  162. swprintf_s(envPath, _countof(envPath), L"%ls\\%ls", reinterpret_cast<const wchar_t*>(HlslDataDirValue.GetBuffer()), relative);
  163. VERIFY_WIN32_BOOL_SUCCEEDED(ExpandEnvironmentStringsW(envPath, expanded, _countof(expanded)));
  164. return std::wstring(expanded);
  165. }
  166. inline bool PathLooksAbsolute(LPCWSTR name) {
  167. // Very simplified, only for the cases we care about in the test suite.
  168. #ifdef _WIN32
  169. return name && *name && ((*name == L'\\') || (name[1] == L':'));
  170. #else
  171. return name && *name && (*name == L'/');
  172. #endif
  173. }
  174. static bool HasRunLine(std::string &line) {
  175. const char *delimiters = " ;/";
  176. auto lineelems = strtok(line, delimiters);
  177. return !lineelems.empty() &&
  178. lineelems.front().compare("RUN:") == 0;
  179. }
  180. inline std::vector<std::string> GetRunLines(const LPCWSTR name) {
  181. const std::wstring path = PathLooksAbsolute(name)
  182. ? std::wstring(name)
  183. : hlsl_test::GetPathToHlslDataFile(name);
  184. #ifdef _WIN32
  185. std::ifstream infile(path);
  186. #else
  187. std::ifstream infile((CW2A(path.c_str())));
  188. #endif
  189. if (infile.bad()) {
  190. std::wstring errMsg(L"Unable to read file ");
  191. errMsg += path;
  192. WEX::Logging::Log::Error(errMsg.c_str());
  193. VERIFY_FAIL();
  194. }
  195. std::vector<std::string> runlines;
  196. std::string line;
  197. constexpr size_t runlinesize = 300;
  198. while (std::getline(infile, line)) {
  199. if (!HasRunLine(line))
  200. continue;
  201. char runline[runlinesize];
  202. memset(runline, 0, runlinesize);
  203. memcpy(runline, line.c_str(), min(runlinesize, line.size()));
  204. runlines.emplace_back(runline);
  205. }
  206. return runlines;
  207. }
  208. inline std::string GetFirstLine(LPCWSTR name) {
  209. char firstLine[300];
  210. memset(firstLine, 0, sizeof(firstLine));
  211. const std::wstring path = PathLooksAbsolute(name)
  212. ? std::wstring(name)
  213. : hlsl_test::GetPathToHlslDataFile(name);
  214. #ifdef _WIN32
  215. std::ifstream infile(path);
  216. #else
  217. std::ifstream infile((CW2A(path.c_str())));
  218. #endif
  219. if (infile.bad()) {
  220. std::wstring errMsg(L"Unable to read file ");
  221. errMsg += path;
  222. WEX::Logging::Log::Error(errMsg.c_str());
  223. VERIFY_FAIL();
  224. }
  225. infile.getline(firstLine, _countof(firstLine));
  226. return firstLine;
  227. }
  228. inline HANDLE CreateFileForReading(LPCWSTR path) {
  229. HANDLE sourceHandle = CreateFileW(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
  230. if (sourceHandle == INVALID_HANDLE_VALUE) {
  231. DWORD err = GetLastError();
  232. std::wstring errorMessage(FormatToWString(L"Unable to open file '%s', err=%u", path, err).c_str());
  233. VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str());
  234. }
  235. return sourceHandle;
  236. }
  237. inline HANDLE CreateNewFileForReadWrite(LPCWSTR path) {
  238. HANDLE sourceHandle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
  239. if (sourceHandle == INVALID_HANDLE_VALUE) {
  240. DWORD err = GetLastError();
  241. std::wstring errorMessage(FormatToWString(L"Unable to create file '%s', err=%u", path, err).c_str());
  242. VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str());
  243. }
  244. return sourceHandle;
  245. }
  246. inline bool GetTestParamBool(LPCWSTR name) {
  247. WEX::Common::String ParamValue;
  248. WEX::Common::String NameValue;
  249. if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(name,
  250. ParamValue))) {
  251. return false;
  252. }
  253. if (ParamValue.IsEmpty()) {
  254. return false;
  255. }
  256. if (0 == wcscmp(ParamValue, L"*")) {
  257. return true;
  258. }
  259. VERIFY_SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue(
  260. L"TestName", NameValue));
  261. if (NameValue.IsEmpty()) {
  262. return false;
  263. }
  264. return Unicode::IsStarMatchUTF16(ParamValue, ParamValue.GetLength(),
  265. NameValue, NameValue.GetLength());
  266. }
  267. inline bool GetTestParamUseWARP(bool defaultVal) {
  268. WEX::Common::String AdapterValue;
  269. if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(
  270. L"Adapter", AdapterValue))) {
  271. return defaultVal;
  272. }
  273. if ((defaultVal && AdapterValue.IsEmpty()) ||
  274. AdapterValue.CompareNoCase(L"WARP") == 0) {
  275. return true;
  276. }
  277. return false;
  278. }
  279. }
  280. #ifdef FP_SUBNORMAL
  281. inline bool isdenorm(float f) {
  282. return FP_SUBNORMAL == std::fpclassify(f);
  283. }
  284. #else
  285. inline bool isdenorm(float f) {
  286. return (std::numeric_limits<float>::denorm_min() <= f && f < std::numeric_limits<float>::min()) ||
  287. (-std::numeric_limits<float>::min() < f && f <= -std::numeric_limits<float>::denorm_min());
  288. }
  289. #endif // FP_SUBNORMAL
  290. inline float ifdenorm_flushf(float a) {
  291. return isdenorm(a) ? copysign(0.0f, a) : a;
  292. }
  293. inline bool ifdenorm_flushf_eq(float a, float b) {
  294. return ifdenorm_flushf(a) == ifdenorm_flushf(b);
  295. }
  296. static const uint16_t Float16NaN = 0xff80;
  297. static const uint16_t Float16PosInf = 0x7c00;
  298. static const uint16_t Float16NegInf = 0xfc00;
  299. static const uint16_t Float16PosDenorm = 0x0008;
  300. static const uint16_t Float16NegDenorm = 0x8008;
  301. static const uint16_t Float16PosZero = 0x0000;
  302. static const uint16_t Float16NegZero = 0x8000;
  303. inline bool GetSign(float x) {
  304. return std::signbit(x);
  305. }
  306. inline int GetMantissa(float x) {
  307. int bits = reinterpret_cast<int &>(x);
  308. return bits & 0x7fffff;
  309. }
  310. inline int GetExponent(float x) {
  311. int bits = reinterpret_cast<int &>(x);
  312. return (bits >> 23) & 0xff;
  313. }
  314. #define FLOAT16_BIT_SIGN 0x8000
  315. #define FLOAT16_BIT_EXP 0x7c00
  316. #define FLOAT16_BIT_MANTISSA 0x03ff
  317. #define FLOAT16_BIGGEST_DENORM FLOAT16_BIT_MANTISSA
  318. #define FLOAT16_BIGGEST_NORMAL 0x7bff
  319. inline bool isnanFloat16(uint16_t val) {
  320. return (val & FLOAT16_BIT_EXP) == FLOAT16_BIT_EXP &&
  321. (val & FLOAT16_BIT_MANTISSA) != 0;
  322. }
  323. inline uint16_t ConvertFloat32ToFloat16(float val) {
  324. union Bits {
  325. uint32_t u_bits;
  326. float f_bits;
  327. };
  328. static const uint32_t SignMask = 0x8000;
  329. // Minimum f32 value representable in f16 format without denormalizing
  330. static const uint32_t Min16in32 = 0x38800000;
  331. // Maximum f32 value (next to infinity)
  332. static const uint32_t Max32 = 0x7f7FFFFF;
  333. // Mask for f32 mantissa
  334. static const uint32_t Fraction32Mask = 0x007FFFFF;
  335. // pow(2,24)
  336. static const uint32_t DenormalRatio = 0x4B800000;
  337. static const uint32_t NormalDelta = 0x38000000;
  338. Bits bits;
  339. bits.f_bits = val;
  340. uint32_t sign = bits.u_bits & (SignMask << 16);
  341. Bits Abs;
  342. Abs.u_bits = bits.u_bits ^ sign;
  343. bool isLessThanNormal = Abs.f_bits < *(const float*)&Min16in32;
  344. bool isInfOrNaN = Abs.u_bits > Max32;
  345. if (isLessThanNormal) {
  346. // Compute Denormal result
  347. return (uint16_t)(Abs.f_bits * *(const float*)(&DenormalRatio)) | (uint16_t)(sign >> 16);
  348. }
  349. else if (isInfOrNaN) {
  350. // Compute Inf or Nan result
  351. uint32_t Fraction = Abs.u_bits & Fraction32Mask;
  352. uint16_t IsNaN = Fraction == 0 ? 0 : 0xffff;
  353. return (IsNaN & FLOAT16_BIT_MANTISSA) | FLOAT16_BIT_EXP | (uint16_t)(sign >> 16);
  354. }
  355. else {
  356. // Compute Normal result
  357. return (uint16_t)((Abs.u_bits - NormalDelta) >> 13) | (uint16_t)(sign >> 16);
  358. }
  359. }
  360. inline float ConvertFloat16ToFloat32(uint16_t x) {
  361. union Bits {
  362. float f_bits;
  363. uint32_t u_bits;
  364. };
  365. uint32_t Sign = (x & FLOAT16_BIT_SIGN) << 16;
  366. // nan -> exponent all set and mantisa is non zero
  367. // +/-inf -> exponent all set and mantissa is zero
  368. // denorm -> exponent zero and significand nonzero
  369. uint32_t Abs = (x & 0x7fff);
  370. uint32_t IsNormal = Abs > FLOAT16_BIGGEST_DENORM;
  371. uint32_t IsInfOrNaN = Abs > FLOAT16_BIGGEST_NORMAL;
  372. // Signless Result for normals
  373. uint32_t DenormRatio = 0x33800000;
  374. float DenormResult = Abs * (*(float*)&DenormRatio);
  375. uint32_t AbsShifted = Abs << 13;
  376. // Signless Result for normals
  377. uint32_t NormalResult = AbsShifted + 0x38000000;
  378. // Signless Result for int & nans
  379. uint32_t InfResult = AbsShifted + 0x70000000;
  380. Bits bits;
  381. bits.u_bits = 0;
  382. if (IsInfOrNaN)
  383. bits.u_bits |= InfResult;
  384. else if (IsNormal)
  385. bits.u_bits |= NormalResult;
  386. else
  387. bits.f_bits = DenormResult;
  388. bits.u_bits |= Sign;
  389. return bits.f_bits;
  390. }
  391. uint16_t ConvertFloat32ToFloat16(float val);
  392. float ConvertFloat16ToFloat32(uint16_t val);
  393. inline bool CompareFloatULP(const float &fsrc, const float &fref, int ULPTolerance,
  394. hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) {
  395. if (fsrc == fref) {
  396. return true;
  397. }
  398. if (std::isnan(fsrc)) {
  399. return std::isnan(fref);
  400. }
  401. if (mode == hlsl::DXIL::Float32DenormMode::Any) {
  402. // If denorm expected, output can be sign preserved zero. Otherwise output
  403. // should pass the regular ulp testing.
  404. if (isdenorm(fref) && fsrc == 0 && std::signbit(fsrc) == std::signbit(fref))
  405. return true;
  406. }
  407. // For FTZ or Preserve mode, we should get the expected number within
  408. // ULPTolerance for any operations.
  409. int diff = *((const DWORD *)&fsrc) - *((const DWORD *)&fref);
  410. unsigned int uDiff = diff < 0 ? -diff : diff;
  411. return uDiff <= (unsigned int)ULPTolerance;
  412. }
  413. inline bool CompareFloatEpsilon(const float &fsrc, const float &fref, float epsilon,
  414. hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) {
  415. if (fsrc == fref) {
  416. return true;
  417. }
  418. if (std::isnan(fsrc)) {
  419. return std::isnan(fref);
  420. }
  421. if (mode == hlsl::DXIL::Float32DenormMode::Any) {
  422. // If denorm expected, output can be sign preserved zero. Otherwise output
  423. // should pass the regular epsilon testing.
  424. if (isdenorm(fref) && fsrc == 0 && std::signbit(fsrc) == std::signbit(fref))
  425. return true;
  426. }
  427. // For FTZ or Preserve mode, we should get the expected number within
  428. // epsilon for any operations.
  429. return fabsf(fsrc - fref) < epsilon;
  430. }
  431. // Compare using relative error (relative error < 2^{nRelativeExp})
  432. inline bool CompareFloatRelativeEpsilon(const float &fsrc, const float &fref, int nRelativeExp,
  433. hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) {
  434. return CompareFloatULP(fsrc, fref, 23 - nRelativeExp, mode);
  435. }
  436. inline bool CompareHalfULP(const uint16_t &fsrc, const uint16_t &fref, float ULPTolerance) {
  437. if (fsrc == fref)
  438. return true;
  439. if (isnanFloat16(fsrc))
  440. return isnanFloat16(fref);
  441. // 16-bit floating point numbers must preserve denorms
  442. int diff = fsrc - fref;
  443. unsigned int uDiff = diff < 0 ? -diff : diff;
  444. return uDiff <= (unsigned int)ULPTolerance;
  445. }
  446. inline bool CompareHalfEpsilon(const uint16_t &fsrc, const uint16_t &fref, float epsilon) {
  447. if (fsrc == fref)
  448. return true;
  449. if (isnanFloat16(fsrc))
  450. return isnanFloat16(fref);
  451. float src_f32 = ConvertFloat16ToFloat32(fsrc);
  452. float ref_f32 = ConvertFloat16ToFloat32(fref);
  453. return std::abs(src_f32-ref_f32) < epsilon;
  454. }
  455. inline bool CompareHalfRelativeEpsilon(const uint16_t &fsrc, const uint16_t &fref, int nRelativeExp) {
  456. return CompareHalfULP(fsrc, fref, (float)(10 - nRelativeExp));
  457. }
  458. #ifdef _WIN32
  459. // returns the number of bytes per pixel for a given dxgi format
  460. // add more cases if different format needed to copy back resources
  461. inline UINT GetByteSizeForFormat(DXGI_FORMAT value) {
  462. switch (value) {
  463. case DXGI_FORMAT_R32G32B32A32_TYPELESS: return 16;
  464. case DXGI_FORMAT_R32G32B32A32_FLOAT: return 16;
  465. case DXGI_FORMAT_R32G32B32A32_UINT: return 16;
  466. case DXGI_FORMAT_R32G32B32A32_SINT: return 16;
  467. case DXGI_FORMAT_R32G32B32_TYPELESS: return 12;
  468. case DXGI_FORMAT_R32G32B32_FLOAT: return 12;
  469. case DXGI_FORMAT_R32G32B32_UINT: return 12;
  470. case DXGI_FORMAT_R32G32B32_SINT: return 12;
  471. case DXGI_FORMAT_R16G16B16A16_TYPELESS: return 8;
  472. case DXGI_FORMAT_R16G16B16A16_FLOAT: return 8;
  473. case DXGI_FORMAT_R16G16B16A16_UNORM: return 8;
  474. case DXGI_FORMAT_R16G16B16A16_UINT: return 8;
  475. case DXGI_FORMAT_R16G16B16A16_SNORM: return 8;
  476. case DXGI_FORMAT_R16G16B16A16_SINT: return 8;
  477. case DXGI_FORMAT_R32G32_TYPELESS: return 8;
  478. case DXGI_FORMAT_R32G32_FLOAT: return 8;
  479. case DXGI_FORMAT_R32G32_UINT: return 8;
  480. case DXGI_FORMAT_R32G32_SINT: return 8;
  481. case DXGI_FORMAT_R32G8X24_TYPELESS: return 8;
  482. case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return 4;
  483. case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: return 4;
  484. case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: return 4;
  485. case DXGI_FORMAT_R10G10B10A2_TYPELESS: return 4;
  486. case DXGI_FORMAT_R10G10B10A2_UNORM: return 4;
  487. case DXGI_FORMAT_R10G10B10A2_UINT: return 4;
  488. case DXGI_FORMAT_R11G11B10_FLOAT: return 4;
  489. case DXGI_FORMAT_R8G8B8A8_TYPELESS: return 4;
  490. case DXGI_FORMAT_R8G8B8A8_UNORM: return 4;
  491. case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return 4;
  492. case DXGI_FORMAT_R8G8B8A8_UINT: return 4;
  493. case DXGI_FORMAT_R8G8B8A8_SNORM: return 4;
  494. case DXGI_FORMAT_R8G8B8A8_SINT: return 4;
  495. case DXGI_FORMAT_R16G16_TYPELESS: return 4;
  496. case DXGI_FORMAT_R16G16_FLOAT: return 4;
  497. case DXGI_FORMAT_R16G16_UNORM: return 4;
  498. case DXGI_FORMAT_R16G16_UINT: return 4;
  499. case DXGI_FORMAT_R16G16_SNORM: return 4;
  500. case DXGI_FORMAT_R16G16_SINT: return 4;
  501. case DXGI_FORMAT_R32_TYPELESS: return 4;
  502. case DXGI_FORMAT_D32_FLOAT: return 4;
  503. case DXGI_FORMAT_R32_FLOAT: return 4;
  504. case DXGI_FORMAT_R32_UINT: return 4;
  505. case DXGI_FORMAT_R32_SINT: return 4;
  506. case DXGI_FORMAT_R24G8_TYPELESS: return 4;
  507. case DXGI_FORMAT_D24_UNORM_S8_UINT: return 4;
  508. case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: return 4;
  509. case DXGI_FORMAT_X24_TYPELESS_G8_UINT: return 4;
  510. case DXGI_FORMAT_R8G8_TYPELESS: return 2;
  511. case DXGI_FORMAT_R8G8_UNORM: return 2;
  512. case DXGI_FORMAT_R8G8_UINT: return 2;
  513. case DXGI_FORMAT_R8G8_SNORM: return 2;
  514. case DXGI_FORMAT_R8G8_SINT: return 2;
  515. case DXGI_FORMAT_R16_TYPELESS: return 2;
  516. case DXGI_FORMAT_R16_FLOAT: return 2;
  517. case DXGI_FORMAT_D16_UNORM: return 2;
  518. case DXGI_FORMAT_R16_UNORM: return 2;
  519. case DXGI_FORMAT_R16_UINT: return 2;
  520. case DXGI_FORMAT_R16_SNORM: return 2;
  521. case DXGI_FORMAT_R16_SINT: return 2;
  522. case DXGI_FORMAT_R8_TYPELESS: return 1;
  523. case DXGI_FORMAT_R8_UNORM: return 1;
  524. case DXGI_FORMAT_R8_UINT: return 1;
  525. case DXGI_FORMAT_R8_SNORM: return 1;
  526. case DXGI_FORMAT_R8_SINT: return 1;
  527. case DXGI_FORMAT_A8_UNORM: return 1;
  528. case DXGI_FORMAT_R1_UNORM: return 1;
  529. default:
  530. VERIFY_FAILED(E_INVALIDARG);
  531. return 0;
  532. }
  533. }
  534. #endif