|
1 | | -#include <DirectXPackedVector.h> |
2 | | -#include <cmath> |
3 | 1 | #ifndef NOMINMAX |
4 | 2 | #define NOMINMAX 1 |
5 | 3 | #endif |
@@ -105,6 +103,21 @@ static constexpr Operation Operations[] = { |
105 | 103 | #include "LongVectorOps.def" |
106 | 104 | }; |
107 | 105 |
|
| 106 | +#define OP_WITH_OUT_PARAM(OPERATION, TYPE, IMPL) \ |
| 107 | + template <> struct ExpectedBuilder<OpType::OPERATION, TYPE> { \ |
| 108 | + static std::vector<TYPE> buildExpected(Op<OpType::OPERATION, TYPE, 1>, \ |
| 109 | + const InputSets<TYPE> &Inputs) { \ |
| 110 | + DXASSERT_NOMSG(Inputs.size() == 1); \ |
| 111 | + size_t VectorSize = Inputs[0].size(); \ |
| 112 | + std::vector<TYPE> Expected; \ |
| 113 | + Expected.resize(VectorSize * 2); \ |
| 114 | + for (size_t I = 0; I < VectorSize; ++I) { \ |
| 115 | + IMPL \ |
| 116 | + } \ |
| 117 | + return Expected; \ |
| 118 | + } \ |
| 119 | + }; |
| 120 | + |
108 | 121 | constexpr const Operation &getOperation(OpType Op) { |
109 | 122 | if (Op < OpType::NumOpTypes) |
110 | 123 | return Operations[unsigned(Op)]; |
@@ -1017,41 +1030,21 @@ DEFAULT_OP_1(OpType::Log2, (std::log2(A))); |
1017 | 1030 | // with special logic. Frexp is only supported for fp32 values. |
1018 | 1031 | template <> struct Op<OpType::Frexp, float, 1> : DefaultValidation<float> {}; |
1019 | 1032 |
|
1020 | | -template <> struct ExpectedBuilder<OpType::Frexp, float> { |
1021 | | - static std::vector<float> buildExpected(Op<OpType::Frexp, float, 1> &, |
1022 | | - const InputSets<float> &Inputs) { |
1023 | | - DXASSERT_NOMSG(Inputs.size() == 1); |
1024 | | - |
1025 | | - // Expected values size is doubled. In the first half we store the |
1026 | | - // Mantissas and in the second half we store the Exponents. This way we |
1027 | | - // can leverage the existing logic which verify expected values in a |
1028 | | - // single vector. We just need to make sure that we organize the output in |
1029 | | - // the same way in the shader and when we read it back. |
1030 | | - |
1031 | | - size_t VectorSize = Inputs[0].size(); |
1032 | | - |
1033 | | - std::vector<float> Expected; |
1034 | | - Expected.resize(VectorSize * 2); |
1035 | | - |
1036 | | - for (size_t I = 0; I < VectorSize; ++I) { |
1037 | | - int Exp = 0; |
1038 | | - float Man = std::frexp(Inputs[0][I], &Exp); |
| 1033 | +OP_WITH_OUT_PARAM(Frexp, float, { |
| 1034 | + int Exp = 0; |
| 1035 | + float Man = std::frexp(Inputs[0][I], &Exp); |
1039 | 1036 |
|
1040 | | - // std::frexp returns a signed mantissa. But the HLSL implmentation |
1041 | | - // returns an unsigned mantissa. |
1042 | | - Man = std::abs(Man); |
| 1037 | + // std::frexp returns a signed mantissa. But the HLSL implmentation |
| 1038 | + // returns an unsigned mantissa. |
| 1039 | + Man = std::abs(Man); |
1043 | 1040 |
|
1044 | | - Expected[I] = Man; |
| 1041 | + Expected[I] = Man; |
1045 | 1042 |
|
1046 | | - // std::frexp returns the exponent as an int, but HLSL stores it as a |
1047 | | - // float. However, the HLSL exponents fractional component is always 0. |
1048 | | - // So it can conversion between float and int is safe. |
1049 | | - Expected[I + VectorSize] = static_cast<float>(Exp); |
1050 | | - } |
1051 | | - |
1052 | | - return Expected; |
1053 | | - } |
1054 | | -}; |
| 1043 | + // std::frexp returns the exponent as an int, but HLSL stores it as a |
| 1044 | + // float. However, the HLSL exponents fractional component is always 0. |
| 1045 | + // So it can conversion between float and int is safe. |
| 1046 | + Expected[I + VectorSize] = static_cast<float>(Exp); |
| 1047 | +}); |
1055 | 1048 |
|
1056 | 1049 | // |
1057 | 1050 | // Binary Comparison |
@@ -1240,43 +1233,20 @@ FLOAT_SPECIAL_OP(OpType::IsNan, (std::isnan(A))); |
1240 | 1233 |
|
1241 | 1234 | template <typename T> struct Op<OpType::ModF, T, 1> : DefaultValidation<T> {}; |
1242 | 1235 |
|
1243 | | -template <> struct ExpectedBuilder<OpType::ModF, float> { |
1244 | | - static std::vector<float> buildExpected(Op<OpType::ModF, float, 1>, |
1245 | | - const InputSets<float> &Inputs) { |
1246 | | - DXASSERT_NOMSG(Inputs.size() == 1); |
1247 | | - size_t VectorSize = Inputs[0].size(); |
1248 | | - std::vector<float> Expected; |
1249 | | - Expected.resize(VectorSize * 2); |
1250 | | - for (size_t I = 0; I < VectorSize; ++I) { |
1251 | | - float Exp = 0; |
1252 | | - float Man = std::modf(Inputs[0][I], &Exp); |
1253 | | - Expected[I] = Man; |
1254 | | - Expected[I + VectorSize] = static_cast<float>(Exp); |
1255 | | - } |
1256 | | - |
1257 | | - return Expected; |
1258 | | - } |
1259 | | -}; |
1260 | | - |
1261 | | -template <> struct ExpectedBuilder<OpType::ModF, HLSLHalf_t> { |
1262 | | - static std::vector<HLSLHalf_t> buildExpected(Op<OpType::ModF, HLSLHalf_t, 1>, |
1263 | | - const InputSets<HLSLHalf_t> &Inputs) { |
1264 | | - DXASSERT_NOMSG(Inputs.size() == 1); |
1265 | | - size_t VectorSize = Inputs[0].size(); |
1266 | | - std::vector<HLSLHalf_t> Expected; |
1267 | | - Expected.resize(VectorSize * 2); |
1268 | | - for (size_t I = 0; I < VectorSize; ++I) { |
1269 | | - float Exp = 0.0f; |
1270 | | - float Inp = float(Inputs[0][I]); |
1271 | | - float Man = std::modf(Inp, &Exp); |
1272 | | - Expected[I] = HLSLHalf_t(Man); |
1273 | | - Expected[I + VectorSize] = HLSLHalf_t(Exp); |
1274 | | - } |
1275 | | - |
1276 | | - return Expected; |
1277 | | - } |
1278 | | -}; |
1279 | | - |
| 1236 | +OP_WITH_OUT_PARAM(ModF, float, { |
| 1237 | + float Exp = 0.0f; |
| 1238 | + float Man = std::modf(Inputs[0][I], &Exp); |
| 1239 | + Expected[I] = Man; |
| 1240 | + Expected[I + VectorSize] = Exp; |
| 1241 | +}); |
| 1242 | + |
| 1243 | +OP_WITH_OUT_PARAM(ModF, HLSLHalf_t, { |
| 1244 | + float Exp = 0.0f; |
| 1245 | + float Inp = float(Inputs[0][I]); |
| 1246 | + float Man = std::modf(Inp, &Exp); |
| 1247 | + Expected[I] = HLSLHalf_t(Man); |
| 1248 | + Expected[I + VectorSize] = HLSLHalf_t(Exp); |
| 1249 | +}); |
1280 | 1250 |
|
1281 | 1251 | // |
1282 | 1252 | // dispatchTest |
|
0 commit comments