HlslTestUtils.h 20 KB

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