1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Shader matrix arithmetic tests. 22 * 23 * Variables: 24 * + operation 25 * - mat OP mat 26 * - mat OP vec 27 * - vec OP mat 28 * - mat OP scalar 29 * - OP mat 30 * + matrix source 31 * - constant (ctor) 32 * - uniform 33 * - vertex input 34 * - fragment input 35 * + other operand: always dynamic data? 36 * + how to reduce to vec3? 37 *//*--------------------------------------------------------------------*/ 38 39 #include "es2fShaderMatrixTests.hpp" 40 #include "glsShaderRenderCase.hpp" 41 #include "gluShaderUtil.hpp" 42 #include "tcuVector.hpp" 43 #include "tcuMatrix.hpp" 44 #include "tcuMatrixUtil.hpp" 45 #include "deStringUtil.hpp" 46 47 #include "glwEnums.hpp" 48 #include "glwFunctions.hpp" 49 50 namespace deqp 51 { 52 namespace gles2 53 { 54 namespace Functional 55 { 56 57 using std::string; 58 using std::vector; 59 using namespace glu; 60 using namespace deqp::gls; 61 62 using tcu::Vec2; 63 using tcu::Vec3; 64 using tcu::Vec4; 65 using tcu::Mat2; 66 using tcu::Mat3; 67 using tcu::Mat4; 68 69 // Uniform / constant values for tests. 70 // \note Input1 should not contain 0 components as it is used as divisor in div cases. 71 // \todo [2012-02-14 pyry] Make these dynamic. 72 static const float s_constInFloat[2] = { 0.5f, -0.2f }; 73 static const Vec2 s_constInVec2[2] = { Vec2(1.2f, 0.5f), Vec2(0.5f, 1.0f) }; 74 static const Vec3 s_constInVec3[2] = { Vec3(1.1f, 0.1f, 0.5f), Vec3(-0.2f, 0.5f, 0.8f) }; 75 static const Vec4 s_constInVec4[2] = { Vec4(1.4f, 0.2f, -0.5f, 0.7f), Vec4(0.2f, -1.0f, 0.5f, 0.8f) }; 76 77 static const float s_constInMat20[] = { 0.6f, -1.0f, 0.7f, 0.4f }; 78 static const float s_constInMat21[] = { -0.5f, -0.4f, 0.7f, -0.8f }; 79 80 static const float s_constInMat31[] = 81 { 82 1.2f, 0.1f, -0.1f, 83 0.1f, 0.9f, 0.2f, 84 0.2f, -0.1f, 0.7f 85 }; 86 static const float s_constInMat41[] = 87 { 88 1.2f, -0.2f, 0.4f, 0.1f, 89 0.1f, 0.8f, -0.1f, -0.2f, 90 -0.2f, 0.1f, -1.1f, 0.3f, 91 0.1f, 0.2f, 0.3f, 0.9f 92 }; 93 94 static const Mat2 s_constInMat2[2] = { tcu::Mat2(s_constInMat20), tcu::Mat2(s_constInMat21) }; 95 static const Mat3 s_constInMat3[2] = { tcu::translationMatrix(tcu::Vec2(0.2f, -0.3f)), tcu::Mat3(s_constInMat31) }; 96 static const Mat4 s_constInMat4[2] = { tcu::translationMatrix(tcu::Vec3(0.2f, -0.3f, 0.15f)), tcu::Mat4(s_constInMat41) }; 97 98 namespace MatrixCaseUtils 99 { 100 101 enum InputType 102 { 103 INPUTTYPE_CONST = 0, 104 INPUTTYPE_UNIFORM, 105 INPUTTYPE_DYNAMIC, 106 107 INPUTTYPE_LAST 108 }; 109 110 struct ShaderInput 111 { 112 ShaderInput (InputType inputType_, DataType dataType_, Precision precision_) 113 : inputType (inputType_) 114 , dataType (dataType_) 115 , precision (precision_) 116 { 117 } 118 119 InputType inputType; 120 DataType dataType; 121 Precision precision; 122 }; 123 124 enum MatrixOp 125 { 126 OP_ADD = 0, 127 OP_SUB, 128 OP_MUL, 129 OP_DIV, 130 OP_COMP_MUL, 131 OP_UNARY_PLUS, 132 OP_NEGATION, 133 OP_PRE_INCREMENT, 134 OP_PRE_DECREMENT, 135 OP_POST_INCREMENT, 136 OP_POST_DECREMENT, 137 OP_ADD_INTO, 138 OP_SUBTRACT_FROM, 139 OP_MULTIPLY_INTO, 140 OP_DIVIDE_INTO, 141 142 OP_LAST 143 }; 144 145 // Type traits. 146 147 template <int DataT> 148 struct TypeTraits; 149 150 #define DECLARE_TYPE_TRAIT(DATATYPE, TYPE) \ 151 template<> \ 152 struct TypeTraits<DATATYPE> { \ 153 typedef TYPE Type; \ 154 } 155 156 DECLARE_TYPE_TRAIT(TYPE_FLOAT, float); 157 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC2, tcu::Vec2); 158 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC3, tcu::Vec3); 159 DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC4, tcu::Vec4); 160 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2, tcu::Mat2); 161 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3, tcu::Mat3); 162 DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4, tcu::Mat4); 163 164 // Operation info 165 166 enum OperationType 167 { 168 OPERATIONTYPE_BINARY_OPERATOR = 0, 169 OPERATIONTYPE_BINARY_FUNCTION, 170 OPERATIONTYPE_UNARY_PREFIX_OPERATOR, 171 OPERATIONTYPE_UNARY_POSTFIX_OPERATOR, 172 OPERATIONTYPE_ASSIGNMENT, 173 174 OPERATIONTYPE_LAST 175 }; 176 177 static const char* getOperationName (MatrixOp op) 178 { 179 switch (op) 180 { 181 case OP_ADD: return "+"; 182 case OP_SUB: return "-"; 183 case OP_MUL: return "*"; 184 case OP_DIV: return "/"; 185 case OP_COMP_MUL: return "matrixCompMult"; 186 case OP_UNARY_PLUS: return "+"; 187 case OP_NEGATION: return "-"; 188 case OP_PRE_INCREMENT: return "++"; 189 case OP_PRE_DECREMENT: return "--"; 190 case OP_POST_INCREMENT: return "++"; 191 case OP_POST_DECREMENT: return "--"; 192 case OP_ADD_INTO: return "+="; 193 case OP_SUBTRACT_FROM: return "-="; 194 case OP_MULTIPLY_INTO: return "*="; 195 case OP_DIVIDE_INTO: return "/="; 196 default: 197 DE_ASSERT(DE_FALSE); 198 return ""; 199 } 200 } 201 202 static OperationType getOperationType (MatrixOp op) 203 { 204 switch (op) 205 { 206 case OP_ADD: return OPERATIONTYPE_BINARY_OPERATOR; 207 case OP_SUB: return OPERATIONTYPE_BINARY_OPERATOR; 208 case OP_MUL: return OPERATIONTYPE_BINARY_OPERATOR; 209 case OP_DIV: return OPERATIONTYPE_BINARY_OPERATOR; 210 case OP_COMP_MUL: return OPERATIONTYPE_BINARY_FUNCTION; 211 case OP_UNARY_PLUS: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR; 212 case OP_NEGATION: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR; 213 case OP_PRE_INCREMENT: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR; 214 case OP_PRE_DECREMENT: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR; 215 case OP_POST_INCREMENT: return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR; 216 case OP_POST_DECREMENT: return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR; 217 case OP_ADD_INTO: return OPERATIONTYPE_ASSIGNMENT; 218 case OP_SUBTRACT_FROM: return OPERATIONTYPE_ASSIGNMENT; 219 case OP_MULTIPLY_INTO: return OPERATIONTYPE_ASSIGNMENT; 220 case OP_DIVIDE_INTO: return OPERATIONTYPE_ASSIGNMENT; 221 default: 222 DE_ASSERT(DE_FALSE); 223 return OPERATIONTYPE_LAST; 224 } 225 } 226 227 enum TestMatrixType 228 { 229 TESTMATRIXTYPE_DEFAULT = 0, 230 TESTMATRIXTYPE_NEGATED, 231 TESTMATRIXTYPE_INCREMENTED, 232 TESTMATRIXTYPE_DECREMENTED, 233 234 TESTMATRIXTYPE_LAST 235 }; 236 237 static TestMatrixType getOperationTestMatrixType (MatrixOp op) 238 { 239 switch(op) 240 { 241 case OP_ADD: return TESTMATRIXTYPE_DEFAULT; 242 case OP_SUB: return TESTMATRIXTYPE_DEFAULT; 243 case OP_MUL: return TESTMATRIXTYPE_DEFAULT; 244 case OP_DIV: return TESTMATRIXTYPE_DEFAULT; 245 case OP_COMP_MUL: return TESTMATRIXTYPE_DEFAULT; 246 case OP_UNARY_PLUS: return TESTMATRIXTYPE_DEFAULT; 247 case OP_NEGATION: return TESTMATRIXTYPE_NEGATED; 248 case OP_PRE_INCREMENT: return TESTMATRIXTYPE_NEGATED; 249 case OP_PRE_DECREMENT: return TESTMATRIXTYPE_INCREMENTED; 250 case OP_POST_INCREMENT: return TESTMATRIXTYPE_NEGATED; 251 case OP_POST_DECREMENT: return TESTMATRIXTYPE_DEFAULT; 252 case OP_ADD_INTO: return TESTMATRIXTYPE_DECREMENTED; 253 case OP_SUBTRACT_FROM: return TESTMATRIXTYPE_DEFAULT; 254 case OP_MULTIPLY_INTO: return TESTMATRIXTYPE_DEFAULT; 255 case OP_DIVIDE_INTO: return TESTMATRIXTYPE_DEFAULT; 256 257 default: 258 DE_ASSERT(DE_FALSE); 259 return TESTMATRIXTYPE_LAST; 260 } 261 } 262 263 static bool isOperationBinary (MatrixOp op) 264 { 265 return getOperationType(op) == OPERATIONTYPE_BINARY_OPERATOR || 266 getOperationType(op) == OPERATIONTYPE_BINARY_FUNCTION || 267 getOperationType(op) == OPERATIONTYPE_ASSIGNMENT; 268 } 269 270 static bool isOperationMatrixScalar (MatrixOp op) 271 { 272 return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV; 273 } 274 275 static bool isOperationMatrixVector (MatrixOp op) 276 { 277 return op == OP_MUL; 278 } 279 280 static bool isOperationMatrixMatrix (MatrixOp op) 281 { 282 return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_COMP_MUL; 283 } 284 285 static bool isOperationUnary (MatrixOp op) 286 { 287 return op == OP_UNARY_PLUS || 288 op == OP_NEGATION || 289 op == OP_PRE_INCREMENT || 290 op == OP_PRE_DECREMENT || 291 op == OP_POST_INCREMENT || 292 op == OP_POST_DECREMENT; 293 } 294 295 static bool isOperationValueModifying (MatrixOp op) 296 { 297 return op == OP_PRE_INCREMENT || 298 op == OP_PRE_DECREMENT || 299 op == OP_POST_INCREMENT || 300 op == OP_POST_DECREMENT; 301 } 302 303 static bool isOperationAssignment (MatrixOp op) 304 { 305 return op == OP_ADD_INTO || 306 op == OP_SUBTRACT_FROM || 307 op == OP_MULTIPLY_INTO || 308 op == OP_DIVIDE_INTO; 309 } 310 311 // Operation nature 312 313 enum OperationNature 314 { 315 OPERATIONNATURE_PURE = 0, 316 OPERATIONNATURE_MUTATING, 317 OPERATIONNATURE_ASSIGNMENT, 318 319 OPERATIONNATURE_LAST 320 }; 321 322 static OperationNature getOperationNature (MatrixOp op) 323 { 324 if (isOperationAssignment(op)) 325 return OPERATIONNATURE_ASSIGNMENT; 326 327 if (isOperationValueModifying(op)) 328 return OPERATIONNATURE_MUTATING; 329 330 return OPERATIONNATURE_PURE; 331 } 332 333 // Input value loader. 334 335 template <int InputT, int DataT> 336 typename TypeTraits<DataT>::Type getInputValue (const ShaderEvalContext& evalCtx, int inputNdx); 337 338 template <> inline float getInputValue<INPUTTYPE_CONST, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInFloat[inputNdx]; } 339 template <> inline tcu::Vec2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec2[inputNdx]; } 340 template <> inline tcu::Vec3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec3[inputNdx]; } 341 template <> inline tcu::Vec4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec4[inputNdx]; } 342 template <> inline tcu::Mat2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat2[inputNdx]; } 343 template <> inline tcu::Mat3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat3[inputNdx]; } 344 template <> inline tcu::Mat4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInMat4[inputNdx]; } 345 346 template <> inline float getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.x(); } 347 template <> inline tcu::Vec2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1); } 348 template <> inline tcu::Vec3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1, 2); } 349 template <> inline tcu::Vec4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1, 2, 3); } 350 351 template <> inline tcu::Mat2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx) 352 { 353 DE_UNREF(inputNdx); // Not used. 354 tcu::Mat2 m; 355 m.setColumn(0, evalCtx.in[0].swizzle(0,1)); 356 m.setColumn(1, evalCtx.in[1].swizzle(0,1)); 357 return m; 358 } 359 360 template <> inline tcu::Mat3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx) 361 { 362 DE_UNREF(inputNdx); // Not used. 363 tcu::Mat3 m; 364 m.setColumn(0, evalCtx.in[0].swizzle(0,1,2)); 365 m.setColumn(1, evalCtx.in[1].swizzle(0,1,2)); 366 m.setColumn(2, evalCtx.in[2].swizzle(0,1,2)); 367 return m; 368 } 369 370 template <> inline tcu::Mat4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4> (const ShaderEvalContext& evalCtx, int inputNdx) 371 { 372 DE_UNREF(inputNdx); // Not used. 373 tcu::Mat4 m; 374 m.setColumn(0, evalCtx.in[0]); 375 m.setColumn(1, evalCtx.in[1]); 376 m.setColumn(2, evalCtx.in[2]); 377 m.setColumn(3, evalCtx.in[3]); 378 return m; 379 } 380 381 // Reduction from expression result to vec3. 382 383 inline tcu::Vec3 reduceToVec3 (const tcu::Vec2& value) { return value.swizzle(0,1,0); } 384 inline tcu::Vec3 reduceToVec3 (const tcu::Vec3& value) { return value; } 385 inline tcu::Vec3 reduceToVec3 (const tcu::Vec4& value) { return tcu::Vec3(value.x(), value.y(), value.z()+value.w()); } 386 inline tcu::Vec3 reduceToVec3 (const tcu::Mat2& value) { return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0)+value(1, 1)); } 387 inline tcu::Vec3 reduceToVec3 (const tcu::Mat3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2); } 388 inline tcu::Vec3 reduceToVec3 (const tcu::Mat4& value) { return value.getColumn(0).swizzle(0,1,2) + value.getColumn(1).swizzle(1,2,3) + value.getColumn(2).swizzle(2,3,0) + value.getColumn(3).swizzle(3,0,1); } 389 390 // matrixCompMult 391 392 template <typename T, int Rows, int Cols> 393 tcu::Matrix<T, Rows, Cols> matrixCompMult (const tcu::Matrix<T, Rows, Cols>& a, const tcu::Matrix<T, Rows, Cols>& b) 394 { 395 tcu::Matrix<T, Rows, Cols> retVal; 396 397 for (int r = 0; r < Rows; ++r) 398 for (int c = 0; c < Cols; ++c) 399 retVal(r,c) = a(r,c) * b(r, c); 400 401 return retVal; 402 } 403 404 // negate 405 406 template <typename T, int Rows, int Cols> 407 tcu::Matrix<T, Rows, Cols> negate (const tcu::Matrix<T, Rows, Cols>& mat) 408 { 409 tcu::Matrix<T, Rows, Cols> retVal; 410 411 for (int r = 0; r < Rows; ++r) 412 for (int c = 0; c < Cols; ++c) 413 retVal(r,c) = -mat(r, c); 414 415 return retVal; 416 } 417 418 // increment/decrement 419 420 template <typename T, int Rows, int Cols> 421 tcu::Matrix<T, Rows, Cols> increment (const tcu::Matrix<T, Rows, Cols>& mat) 422 { 423 tcu::Matrix<T, Rows, Cols> retVal; 424 425 for (int r = 0; r < Rows; ++r) 426 for (int c = 0; c < Cols; ++c) 427 retVal(r,c) = mat(r, c) + 1.0f; 428 429 return retVal; 430 } 431 432 template <typename T, int Rows, int Cols> 433 tcu::Matrix<T, Rows, Cols> decrement (const tcu::Matrix<T, Rows, Cols>& mat) 434 { 435 tcu::Matrix<T, Rows, Cols> retVal; 436 437 for (int r = 0; r < Rows; ++r) 438 for (int c = 0; c < Cols; ++c) 439 retVal(r,c) = mat(r, c) - 1.0f; 440 441 return retVal; 442 } 443 444 // Evaluator template. 445 446 template <int Op, int In0Type, int In0DataType, int In1Type, int In1DataType> 447 struct Evaluator; 448 449 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 450 struct Evaluator<OP_ADD, In0Type, In0DataType, In1Type, In1DataType> 451 { 452 static void evaluate (ShaderEvalContext& evalCtx) 453 { 454 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) + getInputValue<In1Type, In1DataType>(evalCtx, 1)); 455 } 456 }; 457 458 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 459 struct Evaluator<OP_SUB, In0Type, In0DataType, In1Type, In1DataType> 460 { 461 static void evaluate (ShaderEvalContext& evalCtx) 462 { 463 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) - getInputValue<In1Type, In1DataType>(evalCtx, 1)); 464 } 465 }; 466 467 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 468 struct Evaluator<OP_MUL, In0Type, In0DataType, In1Type, In1DataType> 469 { 470 static void evaluate (ShaderEvalContext& evalCtx) 471 { 472 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) * getInputValue<In1Type, In1DataType>(evalCtx, 1)); 473 } 474 }; 475 476 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 477 struct Evaluator<OP_DIV, In0Type, In0DataType, In1Type, In1DataType> 478 { 479 static void evaluate (ShaderEvalContext& evalCtx) 480 { 481 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) / getInputValue<In1Type, In1DataType>(evalCtx, 1)); 482 } 483 }; 484 485 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 486 struct Evaluator<OP_COMP_MUL, In0Type, In0DataType, In1Type, In1DataType> 487 { 488 static void evaluate (ShaderEvalContext& evalCtx) 489 { 490 evalCtx.color.xyz() = reduceToVec3(matrixCompMult(getInputValue<In0Type, In0DataType>(evalCtx, 0), getInputValue<In1Type, In1DataType>(evalCtx, 1))); 491 } 492 }; 493 494 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 495 struct Evaluator<OP_UNARY_PLUS, In0Type, In0DataType, In1Type, In1DataType> 496 { 497 static void evaluate (ShaderEvalContext& evalCtx) 498 { 499 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0)); 500 } 501 }; 502 503 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 504 struct Evaluator<OP_NEGATION, In0Type, In0DataType, In1Type, In1DataType> 505 { 506 static void evaluate (ShaderEvalContext& evalCtx) 507 { 508 evalCtx.color.xyz() = reduceToVec3(negate(getInputValue<In0Type, In0DataType>(evalCtx, 0))); 509 } 510 }; 511 512 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 513 struct Evaluator<OP_PRE_INCREMENT, In0Type, In0DataType, In1Type, In1DataType> 514 { 515 static void evaluate (ShaderEvalContext& evalCtx) 516 { 517 // modifying reduction: sum modified value too 518 evalCtx.color.xyz() = reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0))) + reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0))); 519 } 520 }; 521 522 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 523 struct Evaluator<OP_PRE_DECREMENT, In0Type, In0DataType, In1Type, In1DataType> 524 { 525 static void evaluate (ShaderEvalContext& evalCtx) 526 { 527 // modifying reduction: sum modified value too 528 evalCtx.color.xyz() = reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0))) + reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0))); 529 } 530 }; 531 532 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 533 struct Evaluator<OP_POST_INCREMENT, In0Type, In0DataType, In1Type, In1DataType> 534 { 535 static void evaluate (ShaderEvalContext& evalCtx) 536 { 537 // modifying reduction: sum modified value too 538 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0)) + reduceToVec3(increment(getInputValue<In0Type, In0DataType>(evalCtx, 0))); 539 } 540 }; 541 542 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 543 struct Evaluator<OP_POST_DECREMENT, In0Type, In0DataType, In1Type, In1DataType> 544 { 545 static void evaluate (ShaderEvalContext& evalCtx) 546 { 547 // modifying reduction: sum modified value too 548 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0)) + reduceToVec3(decrement(getInputValue<In0Type, In0DataType>(evalCtx, 0))); 549 } 550 }; 551 552 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 553 struct Evaluator<OP_ADD_INTO, In0Type, In0DataType, In1Type, In1DataType> 554 { 555 static void evaluate (ShaderEvalContext& evalCtx) 556 { 557 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) + getInputValue<In1Type, In1DataType>(evalCtx, 1)); 558 } 559 }; 560 561 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 562 struct Evaluator<OP_SUBTRACT_FROM, In0Type, In0DataType, In1Type, In1DataType> 563 { 564 static void evaluate (ShaderEvalContext& evalCtx) 565 { 566 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) - getInputValue<In1Type, In1DataType>(evalCtx, 1)); 567 } 568 }; 569 570 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 571 struct Evaluator<OP_MULTIPLY_INTO, In0Type, In0DataType, In1Type, In1DataType> 572 { 573 static void evaluate (ShaderEvalContext& evalCtx) 574 { 575 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) * getInputValue<In1Type, In1DataType>(evalCtx, 1)); 576 } 577 }; 578 579 template <int In0Type, int In0DataType, int In1Type, int In1DataType> 580 struct Evaluator<OP_DIVIDE_INTO, In0Type, In0DataType, In1Type, In1DataType> 581 { 582 static void evaluate (ShaderEvalContext& evalCtx) 583 { 584 evalCtx.color.xyz() = reduceToVec3(getInputValue<In0Type, In0DataType>(evalCtx, 0) / getInputValue<In1Type, In1DataType>(evalCtx, 1)); 585 } 586 }; 587 588 ShaderEvalFunc getEvalFunc (const ShaderInput& in0, const ShaderInput& in1, MatrixOp op) 589 { 590 DE_STATIC_ASSERT(TYPE_LAST <= (1<<7)); 591 DE_STATIC_ASSERT(OP_LAST <= (1<<4)); 592 DE_STATIC_ASSERT(INPUTTYPE_LAST <= (1<<2)); 593 594 #define PACK_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) (((OP) << 18) | ((IN0TYPE) << 16) | ((IN0DATATYPE) << 9) | ((IN1TYPE) << 7) | (IN1DATATYPE)) 595 596 #define MAKE_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) \ 597 case PACK_EVAL_CASE(OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE): \ 598 return Evaluator<OP, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE>::evaluate 599 600 #define SCALAR_OPS(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) \ 601 MAKE_EVAL_CASE(OP_ADD, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 602 MAKE_EVAL_CASE(OP_SUB, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 603 MAKE_EVAL_CASE(OP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 604 MAKE_EVAL_CASE(OP_DIV, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) 605 606 #define ALL_OPS(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) \ 607 MAKE_EVAL_CASE(OP_ADD, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 608 MAKE_EVAL_CASE(OP_SUB, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 609 MAKE_EVAL_CASE(OP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 610 MAKE_EVAL_CASE(OP_DIV, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 611 MAKE_EVAL_CASE(OP_COMP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); 612 613 #define MUL_OP(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) \ 614 MAKE_EVAL_CASE(OP_MUL, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) 615 616 #define MAKE_MAT_SCALAR_VEC_CASES(OP, TYPE0, TYPE1) \ 617 OP(INPUTTYPE_CONST, TYPE0, INPUTTYPE_CONST, TYPE1); \ 618 OP(INPUTTYPE_DYNAMIC, TYPE0, INPUTTYPE_CONST, TYPE1); \ 619 OP(INPUTTYPE_CONST, TYPE0, INPUTTYPE_DYNAMIC, TYPE1); \ 620 OP(INPUTTYPE_DYNAMIC, TYPE0, INPUTTYPE_DYNAMIC, TYPE1) 621 622 #define MAKE_MAT_MAT_CASES(OP, MATTYPE) \ 623 OP(INPUTTYPE_CONST, MATTYPE, INPUTTYPE_CONST, MATTYPE); \ 624 OP(INPUTTYPE_DYNAMIC, MATTYPE, INPUTTYPE_CONST, MATTYPE) 625 626 #define UNARY_OP(IN0TYPE, IN0DATATYPE) \ 627 MAKE_EVAL_CASE(OP_UNARY_PLUS, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST); \ 628 MAKE_EVAL_CASE(OP_NEGATION, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST); \ 629 MAKE_EVAL_CASE(OP_PRE_INCREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST); \ 630 MAKE_EVAL_CASE(OP_PRE_DECREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST); \ 631 MAKE_EVAL_CASE(OP_POST_INCREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST); \ 632 MAKE_EVAL_CASE(OP_POST_DECREMENT, IN0TYPE, IN0DATATYPE, INPUTTYPE_CONST, TYPE_LAST) 633 634 #define MAKE_UNARY_CASES(OP, MATTYPE) \ 635 OP(INPUTTYPE_CONST, MATTYPE); \ 636 OP(INPUTTYPE_DYNAMIC, MATTYPE) 637 638 #define ASSIGN_OP(IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) \ 639 MAKE_EVAL_CASE(OP_ADD_INTO, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 640 MAKE_EVAL_CASE(OP_SUBTRACT_FROM, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 641 MAKE_EVAL_CASE(OP_MULTIPLY_INTO, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE); \ 642 MAKE_EVAL_CASE(OP_DIVIDE_INTO, IN0TYPE, IN0DATATYPE, IN1TYPE, IN1DATATYPE) 643 644 #define MAKE_ASSIGNMENT_CASES(OP, MATTYPE) \ 645 OP(INPUTTYPE_CONST, MATTYPE, INPUTTYPE_CONST, MATTYPE); \ 646 OP(INPUTTYPE_DYNAMIC, MATTYPE, INPUTTYPE_CONST, MATTYPE); \ 647 OP(INPUTTYPE_CONST, MATTYPE, INPUTTYPE_DYNAMIC, MATTYPE); \ 648 OP(INPUTTYPE_DYNAMIC, MATTYPE, INPUTTYPE_DYNAMIC, MATTYPE) 649 650 // \note At the moment there is no difference between uniform and const inputs. This saves binary size. 651 InputType in0Type = in0.inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_DYNAMIC : INPUTTYPE_CONST; 652 InputType in1Type = in1.inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_DYNAMIC : INPUTTYPE_CONST; 653 654 switch (PACK_EVAL_CASE(op, in0Type, in0.dataType, in1Type, in1.dataType)) 655 { 656 // Matrix-scalar. 657 MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS, TYPE_FLOAT_MAT2, TYPE_FLOAT); 658 MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS, TYPE_FLOAT_MAT3, TYPE_FLOAT); 659 MAKE_MAT_SCALAR_VEC_CASES(SCALAR_OPS, TYPE_FLOAT_MAT4, TYPE_FLOAT); 660 661 // Matrix-vector. 662 MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_MAT2, TYPE_FLOAT_VEC2); 663 MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_MAT3, TYPE_FLOAT_VEC3); 664 MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_MAT4, TYPE_FLOAT_VEC4); 665 666 // Vector-matrix. 667 MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT2); 668 MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT3); 669 MAKE_MAT_SCALAR_VEC_CASES(MUL_OP, TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT4); 670 671 // Matrix-matrix. 672 MAKE_MAT_MAT_CASES(ALL_OPS, TYPE_FLOAT_MAT2); 673 MAKE_MAT_MAT_CASES(ALL_OPS, TYPE_FLOAT_MAT3); 674 MAKE_MAT_MAT_CASES(ALL_OPS, TYPE_FLOAT_MAT4); 675 676 // Unary matrix 677 MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT2); 678 MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT3); 679 MAKE_UNARY_CASES(UNARY_OP, TYPE_FLOAT_MAT4); 680 681 // Assignment matrix 682 MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT2); 683 MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT3); 684 MAKE_ASSIGNMENT_CASES(ASSIGN_OP, TYPE_FLOAT_MAT4); 685 686 default: 687 DE_ASSERT(DE_FALSE); 688 return DE_NULL; 689 } 690 691 #undef PACK_EVAL_CASE 692 #undef MAKE_EVAL_CASE 693 #undef MUL_OP 694 #undef ALL_OPS 695 #undef MAKE_MAT_SCALAR_VEC_CASES 696 #undef MAKE_MAT_MAT_CASES 697 } 698 699 // Shader source format utilities. 700 701 template <int Size> 702 void writeVectorConstructor (std::ostream& str, const tcu::Vector<float, Size>& v) 703 { 704 str << "vec" << Size << "("; 705 for (int ndx = 0; ndx < Size; ndx++) 706 { 707 if (ndx != 0) 708 str << ", "; 709 str << de::floatToString(v[ndx], 1); 710 } 711 str << ")"; 712 } 713 714 template <int Cols, int Rows> 715 void writeMatrixConstructor (std::ostream& str, const tcu::Matrix<float, Rows, Cols>& m) 716 { 717 if (Rows == Cols) 718 str << "mat" << Cols; 719 else 720 str << "mat" << Cols << "x" << Rows; 721 722 str << "("; 723 for (int colNdx = 0; colNdx < Cols; colNdx++) 724 { 725 for (int rowNdx = 0; rowNdx < Rows; rowNdx++) 726 { 727 if (rowNdx > 0 || colNdx > 0) 728 str << ", "; 729 str << de::floatToString(m(rowNdx, colNdx), 1); 730 } 731 } 732 str << ")"; 733 } 734 735 } // MatrixCaseUtils 736 737 using namespace MatrixCaseUtils; 738 739 class ShaderMatrixCase : public ShaderRenderCase 740 { 741 public: 742 ShaderMatrixCase (Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase); 743 ~ShaderMatrixCase (void); 744 745 void init (void); 746 747 protected: 748 std::string genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName); 749 void setupUniforms (int programID, const tcu::Vec4& constCoords); 750 751 private: 752 ShaderInput m_in0; 753 ShaderInput m_in1; 754 MatrixOp m_op; 755 }; 756 757 ShaderMatrixCase::ShaderMatrixCase (Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase) 758 : ShaderRenderCase (context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, getEvalFunc(in0, in1, op)) 759 , m_in0 (in0) 760 , m_in1 (in1) 761 , m_op (op) 762 { 763 } 764 765 ShaderMatrixCase::~ShaderMatrixCase (void) 766 { 767 } 768 769 void ShaderMatrixCase::init (void) 770 { 771 std::ostringstream vtx; 772 std::ostringstream frag; 773 std::ostringstream& op = m_isVertexCase ? vtx : frag; 774 775 bool isInDynMat0 = isDataTypeMatrix(m_in0.dataType) && m_in0.inputType == INPUTTYPE_DYNAMIC; 776 bool isInDynMat1 = isDataTypeMatrix(m_in1.dataType) && m_in1.inputType == INPUTTYPE_DYNAMIC; 777 string inValue0; 778 string inValue1; 779 DataType resultType = TYPE_LAST; 780 Precision resultPrec = m_in0.precision; 781 vector<string> passVars; 782 int numInputs = (isOperationBinary(m_op)) ? (2) : (1); 783 784 std::string operationValue0; 785 std::string operationValue1; 786 787 DE_ASSERT(!isInDynMat0 || !isInDynMat1); // Only single dynamic matrix input is allowed. 788 DE_UNREF(isInDynMat0 && isInDynMat1); 789 790 // Compute result type. 791 if (isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType)) 792 { 793 DE_ASSERT(m_in0.dataType == m_in1.dataType); 794 resultType = m_in0.dataType; 795 } 796 else if (getOperationType(m_op) == OPERATIONTYPE_UNARY_PREFIX_OPERATOR || 797 getOperationType(m_op) == OPERATIONTYPE_UNARY_POSTFIX_OPERATOR) 798 { 799 resultType = m_in0.dataType; 800 } 801 else 802 { 803 int matNdx = isDataTypeMatrix(m_in0.dataType) ? 0 : 1; 804 DataType matrixType = matNdx == 0 ? m_in0.dataType : m_in1.dataType; 805 DataType otherType = matNdx == 0 ? m_in1.dataType : m_in0.dataType; 806 807 if (otherType == TYPE_FLOAT) 808 resultType = matrixType; 809 else 810 { 811 DE_ASSERT(isDataTypeVector(otherType)); 812 resultType = otherType; 813 } 814 } 815 816 vtx << "attribute highp vec4 a_position;\n"; 817 if (m_isVertexCase) 818 { 819 vtx << "varying mediump vec4 v_color;\n"; 820 frag << "varying mediump vec4 v_color;\n"; 821 } 822 823 // Input declarations. 824 for (int inNdx = 0; inNdx < numInputs; inNdx++) 825 { 826 const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0; 827 const char* precName = getPrecisionName(in.precision); 828 const char* typeName = getDataTypeName(in.dataType); 829 string& inValue = inNdx > 0 ? inValue1 : inValue0; 830 831 if (in.inputType == INPUTTYPE_DYNAMIC) 832 { 833 vtx << "attribute " << precName << " " << typeName << " a_"; 834 835 if (isDataTypeMatrix(in.dataType)) 836 { 837 // a_matN, v_matN 838 vtx << typeName << ";\n"; 839 if (!m_isVertexCase) 840 { 841 vtx << "varying " << precName << " " << typeName << " v_" << typeName << ";\n"; 842 frag << "varying " << precName << " " << typeName << " v_" << typeName << ";\n"; 843 passVars.push_back(typeName); 844 } 845 846 inValue = string(m_isVertexCase ? "a_" : "v_") + getDataTypeName(in.dataType); 847 } 848 else 849 { 850 // a_coords, v_coords 851 vtx << "coords;\n"; 852 if (!m_isVertexCase) 853 { 854 vtx << "varying " << precName << " " << typeName << " v_coords;\n"; 855 frag << "varying " << precName << " " << typeName << " v_coords;\n"; 856 passVars.push_back("coords"); 857 } 858 859 inValue = m_isVertexCase ? "a_coords" : "v_coords"; 860 } 861 } 862 else if (in.inputType == INPUTTYPE_UNIFORM) 863 { 864 op << "uniform " << precName << " " << typeName << " u_in" << inNdx << ";\n"; 865 inValue = string("u_in") + de::toString(inNdx); 866 } 867 else if (in.inputType == INPUTTYPE_CONST) 868 { 869 op << "const " << precName << " " << typeName << " in" << inNdx << " = "; 870 871 // Generate declaration. 872 switch (in.dataType) 873 { 874 case TYPE_FLOAT: op << de::floatToString(s_constInFloat[inNdx], 1); break; 875 case TYPE_FLOAT_VEC2: writeVectorConstructor<2>(op, s_constInVec2[inNdx]); break; 876 case TYPE_FLOAT_VEC3: writeVectorConstructor<3>(op, s_constInVec3[inNdx]); break; 877 case TYPE_FLOAT_VEC4: writeVectorConstructor<4>(op, s_constInVec4[inNdx]); break; 878 case TYPE_FLOAT_MAT2: writeMatrixConstructor<2, 2>(op, Mat2(s_constInMat2[inNdx])); break; 879 case TYPE_FLOAT_MAT3: writeMatrixConstructor<3, 3>(op, Mat3(s_constInMat3[inNdx])); break; 880 case TYPE_FLOAT_MAT4: writeMatrixConstructor<4, 4>(op, Mat4(s_constInMat4[inNdx])); break; 881 882 default: 883 DE_ASSERT(DE_FALSE); 884 } 885 886 op << ";\n"; 887 888 inValue = string("in") + de::toString(inNdx); 889 } 890 } 891 892 vtx << "\n" 893 << "void main (void)\n" 894 << "{\n" 895 << " gl_Position = a_position;\n"; 896 frag << "\n" 897 << "void main (void)\n" 898 << "{\n"; 899 900 if (m_isVertexCase) 901 { 902 frag << " gl_FragColor = v_color;\n"; 903 } 904 else 905 { 906 for (vector<string>::const_iterator copyIter = passVars.begin(); copyIter != passVars.end(); copyIter++) 907 vtx << " v_" << *copyIter << " = " << "a_" << *copyIter << ";\n"; 908 } 909 910 // Operation. 911 912 switch (getOperationNature(m_op)) 913 { 914 case OPERATIONNATURE_PURE: 915 DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT); 916 917 operationValue0 = inValue0; 918 operationValue1 = inValue1; 919 break; 920 921 case OPERATIONNATURE_MUTATING: 922 DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT); 923 924 op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " tmpValue = " << inValue0 << ";\n"; 925 926 operationValue0 = "tmpValue"; 927 operationValue1 = inValue1; 928 break; 929 930 case OPERATIONNATURE_ASSIGNMENT: 931 DE_ASSERT(getOperationType(m_op) == OPERATIONTYPE_ASSIGNMENT); 932 933 operationValue0 = inValue0; 934 operationValue1 = inValue1; 935 break; 936 937 default: 938 DE_ASSERT(DE_FALSE); 939 } 940 941 switch (getOperationType(m_op)) 942 { 943 case OPERATIONTYPE_BINARY_OPERATOR: 944 op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << " " << getOperationName(m_op) << " " << operationValue1 << ";\n"; 945 break; 946 947 case OPERATIONTYPE_UNARY_PREFIX_OPERATOR: 948 op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << operationValue0 << ";\n"; 949 break; 950 951 case OPERATIONTYPE_UNARY_POSTFIX_OPERATOR: 952 op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << getOperationName(m_op) << ";\n"; 953 break; 954 955 case OPERATIONTYPE_BINARY_FUNCTION: 956 op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ", " << operationValue1 << ");\n"; 957 break; 958 959 case OPERATIONTYPE_ASSIGNMENT: 960 op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << ";\n"; 961 op << " res " << getOperationName(m_op) << " " << operationValue1 << ";\n"; 962 break; 963 964 default: 965 DE_ASSERT(DE_FALSE); 966 } 967 968 // Reduction to vec3 (rgb). Check the used value too if it was modified. 969 op << " " << (m_isVertexCase ? "v_color" : "gl_FragColor") << " = "; 970 971 if (isOperationValueModifying(m_op)) 972 op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0) + vec4(" << genGLSLMatToVec3Reduction(resultType, "tmpValue") << ", 0.0);\n"; 973 else 974 op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0);\n"; 975 976 vtx << "}\n"; 977 frag << "}\n"; 978 979 m_vertShaderSource = vtx.str(); 980 m_fragShaderSource = frag.str(); 981 982 // \todo [2012-02-14 pyry] Compute better values for matrix tests. 983 m_userAttribTransforms.resize(4); 984 for (int attribNdx = 0; attribNdx < 4; attribNdx++) 985 { 986 m_userAttribTransforms[attribNdx] = Mat4(0.0f); 987 m_userAttribTransforms[attribNdx]((0 + attribNdx) % 4, 0) = 1.0f; 988 m_userAttribTransforms[attribNdx]((1 + attribNdx) % 4, 1) = 1.0f; 989 m_userAttribTransforms[attribNdx]((2 + attribNdx) % 4, 2) = 1.0f; 990 m_userAttribTransforms[attribNdx]((3 + attribNdx) % 4, 3) = 1.0f; 991 } 992 993 // prevent bad reference cases such as black result images by fine-tuning used matrices 994 if (getOperationTestMatrixType(m_op) != TESTMATRIXTYPE_DEFAULT) 995 { 996 for (int attribNdx = 0; attribNdx < 4; attribNdx++) 997 { 998 for (int row = 0; row < 4; row++) 999 for (int col = 0; col < 4; col++) 1000 { 1001 switch (getOperationTestMatrixType(m_op)) 1002 { 1003 case TESTMATRIXTYPE_NEGATED: 1004 m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col); 1005 break; 1006 case TESTMATRIXTYPE_INCREMENTED: 1007 m_userAttribTransforms[attribNdx](row, col) += 0.3f; 1008 break; 1009 case TESTMATRIXTYPE_DECREMENTED: 1010 m_userAttribTransforms[attribNdx](row, col) -= 0.1f; 1011 break; 1012 1013 default: 1014 DE_ASSERT(DE_FALSE); 1015 break; 1016 } 1017 } 1018 } 1019 } 1020 1021 ShaderRenderCase::init(); 1022 } 1023 1024 std::string ShaderMatrixCase::genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName) 1025 { 1026 std::ostringstream op; 1027 1028 switch (matType) 1029 { 1030 case TYPE_FLOAT: op << varName << ", " << varName << ", " << varName << ""; break; 1031 case TYPE_FLOAT_VEC2: op << varName << ".x, " << varName << ".y, " << varName << ".x"; break; 1032 case TYPE_FLOAT_VEC3: op << varName << ""; break; 1033 case TYPE_FLOAT_VEC4: op << varName << ".x, " << varName << ".y, " << varName << ".z+" << varName << ".w"; break; 1034 case TYPE_FLOAT_MAT2: op << varName << "[0][0], " << varName << "[1][0], " << varName << "[0][1]+" << varName << "[1][1]"; break; 1035 case TYPE_FLOAT_MAT3: op << varName << "[0]+" << varName << "[1]+" << varName << "[2]"; break; 1036 case TYPE_FLOAT_MAT4: op << varName << "[0].xyz+" << varName << "[1].yzw+" << varName << "[2].zwx+" << varName << "[3].wxy"; break; 1037 1038 default: 1039 DE_ASSERT(DE_FALSE); 1040 } 1041 1042 return op.str(); 1043 } 1044 1045 void ShaderMatrixCase::setupUniforms (int programID, const tcu::Vec4& constCoords) 1046 { 1047 const glw::Functions& gl = m_renderCtx.getFunctions(); 1048 1049 DE_UNREF(constCoords); 1050 1051 for (int inNdx = 0; inNdx < 2; inNdx++) 1052 { 1053 const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0; 1054 1055 if (in.inputType == INPUTTYPE_UNIFORM) 1056 { 1057 int loc = gl.getUniformLocation(programID, (string("u_in") + de::toString(inNdx)).c_str()); 1058 1059 if (loc < 0) 1060 continue; 1061 1062 switch (in.dataType) 1063 { 1064 case TYPE_FLOAT: gl.uniform1f(loc, s_constInFloat[inNdx]); break; 1065 case TYPE_FLOAT_VEC2: gl.uniform2fv(loc, 1, s_constInVec2[inNdx].getPtr()); break; 1066 case TYPE_FLOAT_VEC3: gl.uniform3fv(loc, 1, s_constInVec3[inNdx].getPtr()); break; 1067 case TYPE_FLOAT_VEC4: gl.uniform4fv(loc, 1, s_constInVec4[inNdx].getPtr()); break; 1068 case TYPE_FLOAT_MAT2: gl.uniformMatrix2fv(loc, 1, GL_FALSE, s_constInMat2[inNdx].getColumnMajorData().getPtr()); break; 1069 case TYPE_FLOAT_MAT3: gl.uniformMatrix3fv(loc, 1, GL_FALSE, s_constInMat3[inNdx].getColumnMajorData().getPtr()); break; 1070 case TYPE_FLOAT_MAT4: gl.uniformMatrix4fv(loc, 1, GL_FALSE, s_constInMat4[inNdx].getColumnMajorData().getPtr()); break; 1071 default: 1072 DE_ASSERT(false); 1073 } 1074 } 1075 } 1076 } 1077 1078 ShaderMatrixTests::ShaderMatrixTests (Context& context) 1079 : TestCaseGroup(context, "matrix", "Matrix Tests") 1080 { 1081 } 1082 1083 ShaderMatrixTests::~ShaderMatrixTests (void) 1084 { 1085 } 1086 1087 void ShaderMatrixTests::init (void) 1088 { 1089 static const struct 1090 { 1091 const char* name; 1092 const char* desc; 1093 MatrixOp op; 1094 bool extendedInputTypeCases; // !< test with const and uniform types too 1095 } ops[] = 1096 { 1097 { "add", "Matrix addition tests", OP_ADD, true }, 1098 { "sub", "Matrix subtraction tests", OP_SUB, true }, 1099 { "mul", "Matrix multiplication tests", OP_MUL, true }, 1100 { "div", "Matrix division tests", OP_DIV, true }, 1101 { "matrixcompmult", "Matrix component-wise multiplication tests", OP_COMP_MUL, false }, 1102 { "unary_addition", "Matrix unary addition tests", OP_UNARY_PLUS, false }, 1103 { "negation", "Matrix negation tests", OP_NEGATION, false }, 1104 { "pre_increment", "Matrix prefix increment tests", OP_PRE_INCREMENT, false }, 1105 { "pre_decrement", "Matrix prefix decrement tests", OP_PRE_DECREMENT, false }, 1106 { "post_increment", "Matrix postfix increment tests", OP_POST_INCREMENT, false }, 1107 { "post_decrement", "Matrix postfix decrement tests", OP_POST_DECREMENT, false }, 1108 { "add_assign", "Matrix add into tests", OP_ADD_INTO, false }, 1109 { "sub_assign", "Matrix subtract from tests", OP_SUBTRACT_FROM, false }, 1110 { "mul_assign", "Matrix multiply into tests", OP_MULTIPLY_INTO, false }, 1111 { "div_assign", "Matrix divide into tests", OP_DIVIDE_INTO, false }, 1112 }; 1113 1114 struct InputTypeSpec 1115 { 1116 const char* name; 1117 const char* desc; 1118 InputType type; 1119 }; 1120 static const InputTypeSpec extendedInputTypes[] = 1121 { 1122 { "const", "Constant matrix input", INPUTTYPE_CONST }, 1123 { "uniform", "Uniform matrix input", INPUTTYPE_UNIFORM }, 1124 { "dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC } 1125 }; 1126 static const InputTypeSpec reducedInputTypes[] = 1127 { 1128 { "dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC } 1129 }; 1130 1131 static const DataType matrixTypes[] = 1132 { 1133 TYPE_FLOAT_MAT2, 1134 TYPE_FLOAT_MAT3, 1135 TYPE_FLOAT_MAT4 1136 }; 1137 1138 static const Precision precisions[] = 1139 { 1140 PRECISION_LOWP, 1141 PRECISION_MEDIUMP, 1142 PRECISION_HIGHP 1143 }; 1144 1145 for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++) 1146 { 1147 const InputTypeSpec* inTypeList = (ops[opNdx].extendedInputTypeCases) ? (extendedInputTypes) : (reducedInputTypes); 1148 const int inTypeListSize = (ops[opNdx].extendedInputTypeCases) ? (DE_LENGTH_OF_ARRAY(extendedInputTypes)) : (DE_LENGTH_OF_ARRAY(reducedInputTypes)); 1149 const MatrixOp op = ops[opNdx].op; 1150 tcu::TestCaseGroup* opGroup = new tcu::TestCaseGroup(m_testCtx, ops[opNdx].name, ops[opNdx].desc); 1151 1152 addChild(opGroup); 1153 1154 for (int inTypeNdx = 0; inTypeNdx < inTypeListSize; inTypeNdx++) 1155 { 1156 const InputType inputType = inTypeList[inTypeNdx].type; 1157 1158 for (int matTypeNdx = 0; matTypeNdx < DE_LENGTH_OF_ARRAY(matrixTypes); matTypeNdx++) 1159 { 1160 DataType matType = matrixTypes[matTypeNdx]; 1161 const char* matTypeName = getDataTypeName(matType); 1162 1163 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1164 { 1165 Precision precision = precisions[precNdx]; 1166 const char* precName = getPrecisionName(precision); 1167 string baseName = string(inTypeList[inTypeNdx].name) + "_" + precName + "_" + matTypeName + "_"; 1168 ShaderInput matIn (inputType, matType, precision); 1169 1170 if (isOperationMatrixScalar(op)) 1171 { 1172 // Matrix-scalar \note For div cases we use uniform input. 1173 ShaderInput scalarIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, TYPE_FLOAT, precision); 1174 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(), "Matrix-scalar case", matIn, scalarIn, op, true)); 1175 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(), "Matrix-scalar case", matIn, scalarIn, op, false)); 1176 } 1177 1178 if (isOperationMatrixVector(op)) 1179 { 1180 // Matrix-vector. 1181 DataType vecType = getDataTypeFloatVec(getDataTypeMatrixNumColumns(matType)); 1182 ShaderInput vecIn (op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, vecType, precision); 1183 1184 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(vecType) + "_vertex").c_str(), "Matrix-vector case", matIn, vecIn, op, true)); 1185 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(vecType) + "_fragment").c_str(), "Matrix-vector case", matIn, vecIn, op, false)); 1186 1187 // Vector-matrix. 1188 string vecMatName = string(inTypeList[inTypeNdx].name) + "_" + precName + "_" + getDataTypeName(vecType) + "_" + matTypeName; 1189 opGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_vertex").c_str(), "Vector-matrix case", vecIn, matIn, op, true)); 1190 opGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_fragment").c_str(), "Vector-matrix case", vecIn, matIn, op, false)); 1191 } 1192 1193 if (isOperationMatrixMatrix(op)) 1194 { 1195 // Matrix-matrix. 1196 ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision); 1197 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_vertex").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, true)); 1198 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_fragment").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, false)); 1199 } 1200 1201 if (isOperationUnary(op)) 1202 { 1203 // op matrix 1204 ShaderInput voidInput(INPUTTYPE_LAST, TYPE_LAST, PRECISION_LAST); 1205 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "vertex").c_str(), "Matrix case", matIn, voidInput, op, true)); 1206 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "fragment").c_str(), "Matrix case", matIn, voidInput, op, false)); 1207 } 1208 1209 if (isOperationAssignment(op)) 1210 { 1211 ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision); 1212 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "vertex").c_str(), "Matrix assignment case", matIn, otherMatIn, op, true)); 1213 opGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "fragment").c_str(), "Matrix assignment case", matIn, otherMatIn, op, false)); 1214 } 1215 } 1216 } 1217 } 1218 } 1219 } 1220 1221 } // Functional 1222 } // gles2 1223 } // deqp 1224