| /////////////////////////////////////////////////////////////////////////////// |
| // // |
| // HlslTestUtils.h // |
| // Copyright (C) Microsoft Corporation. All rights reserved. // |
| // This file is distributed under the University of Illinois Open Source // |
| // License. See LICENSE.TXT for details. // |
| // // |
| // Provides utility functions for HLSL tests. // |
| // // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // *** THIS FILE CANNOT TAKE ANY LLVM DEPENDENCIES *** // |
| |
| #include <algorithm> |
| #include <atomic> |
| #include <cmath> |
| #include <fstream> |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| #ifdef _WIN32 |
| |
| // Disable -Wignored-qualifiers for WexTestClass.h. |
| // For const size_t GetSize() const; in TestData.h. |
| #ifdef __clang__ |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wignored-qualifiers" |
| #endif |
| #include "WexTestClass.h" |
| #ifdef __clang__ |
| #pragma clang diagnostic pop |
| #endif |
| |
| #include <dxgiformat.h> |
| #else |
| #include "WEXAdapter.h" |
| #include "dxc/Support/Global.h" // DXASSERT_LOCALVAR |
| #endif |
| #include "dxc/DXIL/DxilConstants.h" // DenormMode |
| |
| #ifdef _HLK_CONF |
| #define DEFAULT_TEST_DIR L"" |
| #define DEFAULT_EXEC_TEST_DIR DEFAULT_TEST_DIR |
| #else |
| #include "dxc/Test/TestConfig.h" |
| #endif |
| |
| using namespace std; |
| |
| #ifndef HLSLDATAFILEPARAM |
| #define HLSLDATAFILEPARAM L"HlslDataDir" |
| #endif |
| |
| #ifndef FILECHECKDUMPDIRPARAM |
| #define FILECHECKDUMPDIRPARAM L"FileCheckDumpDir" |
| #endif |
| |
| // If TAEF verify macros are available, use them to alias other legacy |
| // comparison macros that don't have a direct translation. |
| // |
| // Other common replacements are as follows. |
| // |
| // EXPECT_EQ -> VERIFY_ARE_EQUAL |
| // ASSERT_EQ -> VERIFY_ARE_EQUAL |
| // |
| // Note that whether verification throws or continues depends on |
| // preprocessor settings. |
| |
| #ifdef VERIFY_ARE_EQUAL |
| #ifndef EXPECT_STREQ |
| #define EXPECT_STREQ(a, b) VERIFY_ARE_EQUAL(0, strcmp(a, b)) |
| #endif |
| #define EXPECT_STREQW(a, b) VERIFY_ARE_EQUAL(0, wcscmp(a, b)) |
| #define VERIFY_ARE_EQUAL_CMP(a, b, ...) VERIFY_IS_TRUE(a == b, __VA_ARGS__) |
| #define VERIFY_ARE_EQUAL_STR(a, b) \ |
| { \ |
| const char *pTmpA = (a); \ |
| const char *pTmpB = (b); \ |
| if (0 != strcmp(pTmpA, pTmpB)) { \ |
| CA2W conv(pTmpB, CP_UTF8); \ |
| WEX::Logging::Log::Comment(conv); \ |
| const char *pA = pTmpA; \ |
| const char *pB = pTmpB; \ |
| while (*pA == *pB) { \ |
| pA++; \ |
| pB++; \ |
| } \ |
| wchar_t diffMsg[32]; \ |
| swprintf_s(diffMsg, _countof(diffMsg), L"diff at %u", \ |
| (unsigned)(pA - pTmpA)); \ |
| WEX::Logging::Log::Comment(diffMsg); \ |
| } \ |
| VERIFY_ARE_EQUAL(0, strcmp(pTmpA, pTmpB)); \ |
| } |
| #define VERIFY_ARE_EQUAL_WSTR(a, b) \ |
| { \ |
| if (0 != wcscmp(a, b)) { \ |
| WEX::Logging::Log::Comment(b); \ |
| } \ |
| VERIFY_ARE_EQUAL(0, wcscmp(a, b)); \ |
| } |
| #ifndef ASSERT_EQ |
| #define ASSERT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual) |
| #endif |
| #ifndef ASSERT_NE |
| #define ASSERT_NE(expected, actual) VERIFY_ARE_NOT_EQUAL(expected, actual) |
| #endif |
| #ifndef TEST_F |
| #define TEST_F(typeName, functionName) void typeName::functionName() |
| #endif |
| #define ASSERT_HRESULT_SUCCEEDED VERIFY_SUCCEEDED |
| #ifndef EXPECT_EQ |
| #define EXPECT_EQ(expected, actual) VERIFY_ARE_EQUAL(expected, actual) |
| #endif |
| #endif // VERIFY_ARE_EQUAL |
| |
| static constexpr char whitespaceChars[] = " \t\r\n"; |
| static constexpr wchar_t wideWhitespaceChars[] = L" \t\r\n"; |
| |
| inline std::string strltrim(const std::string &value) { |
| size_t first = value.find_first_not_of(whitespaceChars); |
| return first == string::npos ? value : value.substr(first); |
| } |
| |
| inline std::string strrtrim(const std::string &value) { |
| size_t last = value.find_last_not_of(whitespaceChars); |
| return last == string::npos ? value : value.substr(0, last + 1); |
| } |
| |
| inline std::string strtrim(const std::string &value) { |
| return strltrim(strrtrim(value)); |
| } |
| |
| inline bool strstartswith(const std::string &value, const char *pattern) { |
| for (size_t i = 0;; ++i) { |
| if (pattern[i] == '\0') |
| return true; |
| if (i == value.size() || value[i] != pattern[i]) |
| return false; |
| } |
| } |
| |
| inline std::vector<std::string> |
| strtok(const std::string &value, const char *delimiters = whitespaceChars) { |
| size_t searchOffset = 0; |
| std::vector<std::string> tokens; |
| while (searchOffset != value.size()) { |
| size_t tokenStartIndex = value.find_first_not_of(delimiters, searchOffset); |
| if (tokenStartIndex == std::string::npos) |
| break; |
| size_t tokenEndIndex = value.find_first_of(delimiters, tokenStartIndex); |
| if (tokenEndIndex == std::string::npos) |
| tokenEndIndex = value.size(); |
| tokens.emplace_back( |
| value.substr(tokenStartIndex, tokenEndIndex - tokenStartIndex)); |
| searchOffset = tokenEndIndex; |
| } |
| return tokens; |
| } |
| |
| inline std::vector<std::wstring> |
| strtok(const std::wstring &value, |
| const wchar_t *delimiters = wideWhitespaceChars) { |
| size_t searchOffset = 0; |
| std::vector<std::wstring> tokens; |
| while (searchOffset != value.size()) { |
| size_t tokenStartIndex = value.find_first_not_of(delimiters, searchOffset); |
| if (tokenStartIndex == std::string::npos) |
| break; |
| size_t tokenEndIndex = value.find_first_of(delimiters, tokenStartIndex); |
| if (tokenEndIndex == std::string::npos) |
| tokenEndIndex = value.size(); |
| tokens.emplace_back( |
| value.substr(tokenStartIndex, tokenEndIndex - tokenStartIndex)); |
| searchOffset = tokenEndIndex; |
| } |
| return tokens; |
| } |
| |
| // strreplace will replace all instances of lookFors with replacements at the |
| // same index. Will log an error if the string is not found, unless the first |
| // character is ? marking it optional. |
| inline void strreplace(const std::vector<std::string> &lookFors, |
| const std::vector<std::string> &replacements, |
| std::string &str) { |
| for (unsigned i = 0; i < lookFors.size(); ++i) { |
| bool bOptional = false; |
| bool found = false; |
| size_t pos = 0; |
| LPCSTR pLookFor = lookFors[i].data(); |
| size_t lookForLen = lookFors[i].size(); |
| if (pLookFor[0] == '?') { |
| bOptional = true; |
| pLookFor++; |
| lookForLen--; |
| } |
| if (!pLookFor || !*pLookFor) { |
| continue; |
| } |
| for (;;) { |
| pos = str.find(pLookFor, pos); |
| if (pos == std::string::npos) |
| break; |
| found = true; // at least once |
| str.replace(pos, lookForLen, replacements[i]); |
| pos += replacements[i].size(); |
| } |
| if (!bOptional) { |
| if (!found) { |
| WEX::Logging::Log::Comment(WEX::Common::String().Format( |
| L"String not found: '%S' in text:\r\n%.*S", pLookFor, |
| (unsigned)str.size(), str.data())); |
| } |
| VERIFY_IS_TRUE(found); |
| } |
| } |
| } |
| |
| namespace hlsl_test { |
| |
| inline std::wstring vFormatToWString(const wchar_t *fmt, va_list argptr) { |
| std::wstring result; |
| #ifdef _WIN32 |
| int len = _vscwprintf(fmt, argptr); |
| result.resize(len + 1); |
| vswprintf_s((wchar_t *)result.data(), len + 1, fmt, argptr); |
| #else |
| wchar_t fmtOut[1000]; |
| int len = vswprintf(fmtOut, 1000, fmt, argptr); |
| DXASSERT_LOCALVAR(len, len >= 0, |
| "Too long formatted string in vFormatToWstring"); |
| result = fmtOut; |
| #endif |
| return result; |
| } |
| |
| inline std::wstring FormatToWString(const wchar_t *fmt, ...) { |
| va_list args; |
| va_start(args, fmt); |
| std::wstring result(vFormatToWString(fmt, args)); |
| va_end(args); |
| return result; |
| } |
| |
| inline void LogCommentFmt(const wchar_t *fmt, ...) { |
| va_list args; |
| va_start(args, fmt); |
| std::wstring buf(vFormatToWString(fmt, args)); |
| va_end(args); |
| WEX::Logging::Log::Comment(buf.data()); |
| } |
| |
| inline void LogErrorFmt(const wchar_t *fmt, ...) { |
| va_list args; |
| va_start(args, fmt); |
| std::wstring buf(vFormatToWString(fmt, args)); |
| va_end(args); |
| WEX::Logging::Log::Error(buf.data()); |
| } |
| |
| inline std::wstring |
| GetPathToHlslDataFile(const wchar_t *relative, |
| LPCWSTR paramName = HLSLDATAFILEPARAM, |
| LPCWSTR defaultDataDir = DEFAULT_TEST_DIR) { |
| WEX::TestExecution::SetVerifyOutput verifySettings( |
| WEX::TestExecution::VerifyOutputSettings::LogOnlyFailures); |
| WEX::Common::String HlslDataDirValue; |
| if (std::wstring(paramName).compare(HLSLDATAFILEPARAM) != 0) { |
| // Not fatal, for instance, FILECHECKDUMPDIRPARAM will dump files before |
| // running FileCheck, so they can be compared run to run |
| if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue( |
| paramName, HlslDataDirValue))) |
| return std::wstring(); |
| } else { |
| if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue( |
| HLSLDATAFILEPARAM, HlslDataDirValue))) |
| HlslDataDirValue = defaultDataDir; |
| } |
| |
| wchar_t envPath[MAX_PATH]; |
| wchar_t expanded[MAX_PATH]; |
| swprintf_s(envPath, _countof(envPath), L"%ls\\%ls", |
| reinterpret_cast<const wchar_t *>(HlslDataDirValue.GetBuffer()), |
| relative); |
| VERIFY_WIN32_BOOL_SUCCEEDED( |
| ExpandEnvironmentStringsW(envPath, expanded, _countof(expanded))); |
| return std::wstring(expanded); |
| } |
| |
| inline bool PathLooksAbsolute(LPCWSTR name) { |
| // Very simplified, only for the cases we care about in the test suite. |
| #ifdef _WIN32 |
| return name && *name && ((*name == L'\\') || (name[1] == L':')); |
| #else |
| return name && *name && (*name == L'/'); |
| #endif |
| } |
| |
| static bool HasRunLine(std::string &line) { |
| const char *delimiters = " ;/"; |
| auto lineelems = strtok(line, delimiters); |
| return !lineelems.empty() && lineelems.front().compare("RUN:") == 0; |
| } |
| |
| inline std::vector<std::string> GetRunLines(const LPCWSTR name) { |
| const std::wstring path = PathLooksAbsolute(name) |
| ? std::wstring(name) |
| : hlsl_test::GetPathToHlslDataFile(name); |
| #ifdef _WIN32 |
| std::ifstream infile(path); |
| #else |
| std::ifstream infile((CW2A(path.c_str()))); |
| #endif |
| if (infile.fail() || infile.bad()) { |
| std::wstring errMsg(L"Unable to read file "); |
| errMsg += path; |
| WEX::Logging::Log::Error(errMsg.c_str()); |
| VERIFY_FAIL(); |
| } |
| |
| std::vector<std::string> runlines; |
| std::string line; |
| constexpr size_t runlinesize = 300; |
| while (std::getline(infile, line)) { |
| if (!HasRunLine(line)) |
| continue; |
| char runline[runlinesize]; |
| memset(runline, 0, runlinesize); |
| memcpy(runline, line.c_str(), min(runlinesize, line.size())); |
| runlines.emplace_back(runline); |
| } |
| return runlines; |
| } |
| |
| inline std::string GetFirstLine(LPCWSTR name) { |
| char firstLine[300]; |
| memset(firstLine, 0, sizeof(firstLine)); |
| |
| const std::wstring path = PathLooksAbsolute(name) |
| ? std::wstring(name) |
| : hlsl_test::GetPathToHlslDataFile(name); |
| #ifdef _WIN32 |
| std::ifstream infile(path); |
| #else |
| std::ifstream infile((CW2A(path.c_str()))); |
| #endif |
| if (infile.bad()) { |
| std::wstring errMsg(L"Unable to read file "); |
| errMsg += path; |
| WEX::Logging::Log::Error(errMsg.c_str()); |
| VERIFY_FAIL(); |
| } |
| |
| infile.getline(firstLine, _countof(firstLine)); |
| return firstLine; |
| } |
| |
| inline HANDLE CreateFileForReading(LPCWSTR path) { |
| HANDLE sourceHandle = |
| CreateFileW(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0); |
| if (sourceHandle == INVALID_HANDLE_VALUE) { |
| DWORD err = GetLastError(); |
| std::wstring errorMessage( |
| FormatToWString(L"Unable to open file '%s', err=%u", path, err) |
| .c_str()); |
| VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str()); |
| } |
| return sourceHandle; |
| } |
| |
| inline HANDLE CreateNewFileForReadWrite(LPCWSTR path) { |
| HANDLE sourceHandle = CreateFileW(path, GENERIC_READ | GENERIC_WRITE, 0, 0, |
| CREATE_ALWAYS, 0, 0); |
| if (sourceHandle == INVALID_HANDLE_VALUE) { |
| DWORD err = GetLastError(); |
| std::wstring errorMessage( |
| FormatToWString(L"Unable to create file '%s', err=%u", path, err) |
| .c_str()); |
| VERIFY_SUCCEEDED(HRESULT_FROM_WIN32(err), errorMessage.c_str()); |
| } |
| return sourceHandle; |
| } |
| |
| // Copy of Unicode::IsStarMatchT/IsStarMatchWide is included here to avoid the |
| // dependency on DXC support libraries. |
| template <typename TChar> |
| inline static bool IsStarMatchT(const TChar *pMask, size_t maskLen, |
| const TChar *pName, size_t nameLen, |
| TChar star) { |
| if (maskLen == 0 && nameLen == 0) { |
| return true; |
| } |
| if (maskLen == 0 || nameLen == 0) { |
| return false; |
| } |
| |
| if (pMask[maskLen - 1] == star) { |
| // Prefix match. |
| if (maskLen == 1) { // For just '*', everything is a match. |
| return true; |
| } |
| --maskLen; |
| if (maskLen > nameLen) { // Mask is longer than name, can't be a match. |
| return false; |
| } |
| return 0 == memcmp(pMask, pName, sizeof(TChar) * maskLen); |
| } else { |
| // Exact match. |
| if (nameLen != maskLen) { |
| return false; |
| } |
| return 0 == memcmp(pMask, pName, sizeof(TChar) * nameLen); |
| } |
| } |
| |
| inline bool IsStarMatchWide(const wchar_t *pMask, size_t maskLen, |
| const wchar_t *pName, size_t nameLen) { |
| return IsStarMatchT<wchar_t>(pMask, maskLen, pName, nameLen, L'*'); |
| } |
| |
| inline bool GetTestParamBool(LPCWSTR name) { |
| WEX::Common::String ParamValue; |
| WEX::Common::String NameValue; |
| if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue(name, |
| ParamValue))) { |
| return false; |
| } |
| if (ParamValue.IsEmpty()) { |
| return false; |
| } |
| if (0 == wcscmp(ParamValue, L"*")) { |
| return true; |
| } |
| VERIFY_SUCCEEDED(WEX::TestExecution::RuntimeParameters::TryGetValue( |
| L"TestName", NameValue)); |
| if (NameValue.IsEmpty()) { |
| return false; |
| } |
| |
| return hlsl_test::IsStarMatchWide(ParamValue, ParamValue.GetLength(), |
| NameValue, NameValue.GetLength()); |
| } |
| |
| inline bool GetTestParamUseWARP(bool defaultVal) { |
| WEX::Common::String AdapterValue; |
| if (FAILED(WEX::TestExecution::RuntimeParameters::TryGetValue( |
| L"Adapter", AdapterValue))) { |
| return defaultVal; |
| } |
| if ((defaultVal && AdapterValue.IsEmpty()) || |
| AdapterValue.CompareNoCase(L"WARP") == 0 || |
| AdapterValue.CompareNoCase(L"Microsoft Basic Render Driver") == 0) { |
| return true; |
| } |
| return false; |
| } |
| |
| } // namespace hlsl_test |
| |
| #ifdef FP_SUBNORMAL |
| |
| inline bool isdenorm(float f) { return FP_SUBNORMAL == std::fpclassify(f); } |
| |
| #else |
| |
| inline bool isdenorm(float f) { |
| return (std::numeric_limits<float>::denorm_min() <= f && |
| f < std::numeric_limits<float>::min()) || |
| (-std::numeric_limits<float>::min() < f && |
| f <= -std::numeric_limits<float>::denorm_min()); |
| } |
| |
| #endif // FP_SUBNORMAL |
| |
| inline float ifdenorm_flushf(float a) { |
| return isdenorm(a) ? copysign(0.0f, a) : a; |
| } |
| |
| inline bool ifdenorm_flushf_eq(float a, float b) { |
| return ifdenorm_flushf(a) == ifdenorm_flushf(b); |
| } |
| |
| static const uint16_t Float16NaN = 0xff80; |
| static const uint16_t Float16PosInf = 0x7c00; |
| static const uint16_t Float16NegInf = 0xfc00; |
| static const uint16_t Float16PosDenorm = 0x0008; |
| static const uint16_t Float16NegDenorm = 0x8008; |
| static const uint16_t Float16PosZero = 0x0000; |
| static const uint16_t Float16NegZero = 0x8000; |
| |
| inline bool GetSign(float x) { return std::signbit(x); } |
| |
| inline int GetMantissa(float x) { |
| int bits = reinterpret_cast<int &>(x); |
| return bits & 0x7fffff; |
| } |
| |
| inline int GetExponent(float x) { |
| int bits = reinterpret_cast<int &>(x); |
| return (bits >> 23) & 0xff; |
| } |
| |
| #define FLOAT16_BIT_SIGN 0x8000 |
| #define FLOAT16_BIT_EXP 0x7c00 |
| #define FLOAT16_BIT_MANTISSA 0x03ff |
| #define FLOAT16_BIGGEST_DENORM FLOAT16_BIT_MANTISSA |
| #define FLOAT16_BIGGEST_NORMAL 0x7bff |
| |
| inline bool isnanFloat16(uint16_t val) { |
| return (val & FLOAT16_BIT_EXP) == FLOAT16_BIT_EXP && |
| (val & FLOAT16_BIT_MANTISSA) != 0; |
| } |
| |
| // These are defined in ShaderOpTest.cpp using DirectXPackedVector functions. |
| uint16_t ConvertFloat32ToFloat16(float val) throw(); |
| float ConvertFloat16ToFloat32(uint16_t val) throw(); |
| |
| inline bool CompareFloatULP( |
| const float &fsrc, const float &fref, int ULPTolerance, |
| hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) { |
| if (fsrc == fref) { |
| return true; |
| } |
| if (std::isnan(fsrc)) { |
| return std::isnan(fref); |
| } |
| if (mode == hlsl::DXIL::Float32DenormMode::Any) { |
| // If denorm expected, output can be sign preserved zero. Otherwise output |
| // should pass the regular ulp testing. |
| if (isdenorm(fref) && fsrc == 0 && std::signbit(fsrc) == std::signbit(fref)) |
| return true; |
| } |
| // For FTZ or Preserve mode, we should get the expected number within |
| // ULPTolerance for any operations. |
| int diff = *((const DWORD *)&fsrc) - *((const DWORD *)&fref); |
| unsigned int uDiff = diff < 0 ? -diff : diff; |
| return uDiff <= (unsigned int)ULPTolerance; |
| } |
| |
| inline bool CompareFloatEpsilon( |
| const float &fsrc, const float &fref, float epsilon, |
| hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) { |
| if (fsrc == fref) { |
| return true; |
| } |
| if (std::isnan(fsrc)) { |
| return std::isnan(fref); |
| } |
| if (mode == hlsl::DXIL::Float32DenormMode::Any) { |
| // If denorm expected, output can be sign preserved zero. Otherwise output |
| // should pass the regular epsilon testing. |
| if (isdenorm(fref) && fsrc == 0 && std::signbit(fsrc) == std::signbit(fref)) |
| return true; |
| } |
| // For FTZ or Preserve mode, we should get the expected number within |
| // epsilon for any operations. |
| return fabsf(fsrc - fref) < epsilon; |
| } |
| |
| // Compare using relative error (relative error < 2^{nRelativeExp}) |
| inline bool CompareFloatRelativeEpsilon( |
| const float &fsrc, const float &fref, int nRelativeExp, |
| hlsl::DXIL::Float32DenormMode mode = hlsl::DXIL::Float32DenormMode::Any) { |
| return CompareFloatULP(fsrc, fref, 23 - nRelativeExp, mode); |
| } |
| |
| inline bool CompareHalfULP(const uint16_t &fsrc, const uint16_t &fref, |
| float ULPTolerance) { |
| if (fsrc == fref) |
| return true; |
| if (isnanFloat16(fsrc)) |
| return isnanFloat16(fref); |
| // 16-bit floating point numbers must preserve denorms |
| int diff = fsrc - fref; |
| unsigned int uDiff = diff < 0 ? -diff : diff; |
| return uDiff <= (unsigned int)ULPTolerance; |
| } |
| |
| inline bool CompareHalfEpsilon(const uint16_t &fsrc, const uint16_t &fref, |
| float epsilon) { |
| if (fsrc == fref) |
| return true; |
| if (isnanFloat16(fsrc)) |
| return isnanFloat16(fref); |
| float src_f32 = ConvertFloat16ToFloat32(fsrc); |
| float ref_f32 = ConvertFloat16ToFloat32(fref); |
| return std::abs(src_f32 - ref_f32) < epsilon; |
| } |
| |
| inline bool CompareHalfRelativeEpsilon(const uint16_t &fsrc, |
| const uint16_t &fref, int nRelativeExp) { |
| return CompareHalfULP(fsrc, fref, (float)(10 - nRelativeExp)); |
| } |
| |
| #ifdef _WIN32 |
| // returns the number of bytes per pixel for a given dxgi format |
| // add more cases if different format needed to copy back resources |
| inline UINT GetByteSizeForFormat(DXGI_FORMAT value) { |
| switch (value) { |
| case DXGI_FORMAT_R32G32B32A32_TYPELESS: |
| return 16; |
| case DXGI_FORMAT_R32G32B32A32_FLOAT: |
| return 16; |
| case DXGI_FORMAT_R32G32B32A32_UINT: |
| return 16; |
| case DXGI_FORMAT_R32G32B32A32_SINT: |
| return 16; |
| case DXGI_FORMAT_R32G32B32_TYPELESS: |
| return 12; |
| case DXGI_FORMAT_R32G32B32_FLOAT: |
| return 12; |
| case DXGI_FORMAT_R32G32B32_UINT: |
| return 12; |
| case DXGI_FORMAT_R32G32B32_SINT: |
| return 12; |
| case DXGI_FORMAT_R16G16B16A16_TYPELESS: |
| return 8; |
| case DXGI_FORMAT_R16G16B16A16_FLOAT: |
| return 8; |
| case DXGI_FORMAT_R16G16B16A16_UNORM: |
| return 8; |
| case DXGI_FORMAT_R16G16B16A16_UINT: |
| return 8; |
| case DXGI_FORMAT_R16G16B16A16_SNORM: |
| return 8; |
| case DXGI_FORMAT_R16G16B16A16_SINT: |
| return 8; |
| case DXGI_FORMAT_R32G32_TYPELESS: |
| return 8; |
| case DXGI_FORMAT_R32G32_FLOAT: |
| return 8; |
| case DXGI_FORMAT_R32G32_UINT: |
| return 8; |
| case DXGI_FORMAT_R32G32_SINT: |
| return 8; |
| case DXGI_FORMAT_R32G8X24_TYPELESS: |
| return 8; |
| case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: |
| return 4; |
| case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: |
| return 4; |
| case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: |
| return 4; |
| case DXGI_FORMAT_R10G10B10A2_TYPELESS: |
| return 4; |
| case DXGI_FORMAT_R10G10B10A2_UNORM: |
| return 4; |
| case DXGI_FORMAT_R10G10B10A2_UINT: |
| return 4; |
| case DXGI_FORMAT_R11G11B10_FLOAT: |
| return 4; |
| case DXGI_FORMAT_R8G8B8A8_TYPELESS: |
| return 4; |
| case DXGI_FORMAT_R8G8B8A8_UNORM: |
| return 4; |
| case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: |
| return 4; |
| case DXGI_FORMAT_R8G8B8A8_UINT: |
| return 4; |
| case DXGI_FORMAT_R8G8B8A8_SNORM: |
| return 4; |
| case DXGI_FORMAT_R8G8B8A8_SINT: |
| return 4; |
| case DXGI_FORMAT_R16G16_TYPELESS: |
| return 4; |
| case DXGI_FORMAT_R16G16_FLOAT: |
| return 4; |
| case DXGI_FORMAT_R16G16_UNORM: |
| return 4; |
| case DXGI_FORMAT_R16G16_UINT: |
| return 4; |
| case DXGI_FORMAT_R16G16_SNORM: |
| return 4; |
| case DXGI_FORMAT_R16G16_SINT: |
| return 4; |
| case DXGI_FORMAT_R32_TYPELESS: |
| return 4; |
| case DXGI_FORMAT_D32_FLOAT: |
| return 4; |
| case DXGI_FORMAT_R32_FLOAT: |
| return 4; |
| case DXGI_FORMAT_R32_UINT: |
| return 4; |
| case DXGI_FORMAT_R32_SINT: |
| return 4; |
| case DXGI_FORMAT_R24G8_TYPELESS: |
| return 4; |
| case DXGI_FORMAT_D24_UNORM_S8_UINT: |
| return 4; |
| case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: |
| return 4; |
| case DXGI_FORMAT_X24_TYPELESS_G8_UINT: |
| return 4; |
| case DXGI_FORMAT_R8G8_TYPELESS: |
| return 2; |
| case DXGI_FORMAT_R8G8_UNORM: |
| return 2; |
| case DXGI_FORMAT_R8G8_UINT: |
| return 2; |
| case DXGI_FORMAT_R8G8_SNORM: |
| return 2; |
| case DXGI_FORMAT_R8G8_SINT: |
| return 2; |
| case DXGI_FORMAT_R16_TYPELESS: |
| return 2; |
| case DXGI_FORMAT_R16_FLOAT: |
| return 2; |
| case DXGI_FORMAT_D16_UNORM: |
| return 2; |
| case DXGI_FORMAT_R16_UNORM: |
| return 2; |
| case DXGI_FORMAT_R16_UINT: |
| return 2; |
| case DXGI_FORMAT_R16_SNORM: |
| return 2; |
| case DXGI_FORMAT_R16_SINT: |
| return 2; |
| case DXGI_FORMAT_R8_TYPELESS: |
| return 1; |
| case DXGI_FORMAT_R8_UNORM: |
| return 1; |
| case DXGI_FORMAT_R8_UINT: |
| return 1; |
| case DXGI_FORMAT_R8_SNORM: |
| return 1; |
| case DXGI_FORMAT_R8_SINT: |
| return 1; |
| case DXGI_FORMAT_A8_UNORM: |
| return 1; |
| case DXGI_FORMAT_R1_UNORM: |
| return 1; |
| default: |
| VERIFY_FAILED(E_INVALIDARG); |
| return 0; |
| } |
| } |
| #endif |