You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1966 lines
70 KiB
1966 lines
70 KiB
/*-------------------------------------------------------------------------
|
|
* drawElements Quality Program OpenGL ES 3.0 Module
|
|
* -------------------------------------------------
|
|
*
|
|
* Copyright 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*//*!
|
|
* \file
|
|
* \brief Shader matrix arithmetic tests.
|
|
*
|
|
* Variables:
|
|
* + operation
|
|
* - mat OP mat
|
|
* - mat OP vec
|
|
* - vec OP mat
|
|
* - mat OP scalar
|
|
* - OP ( mat )
|
|
* - vec OP vec
|
|
* - OP mat
|
|
* + matrix source
|
|
* - constant (ctor)
|
|
* - uniform
|
|
* - vertex input
|
|
* - fragment input
|
|
* + other operand: always dynamic data?
|
|
* + how to reduce to vec3?
|
|
*//*--------------------------------------------------------------------*/
|
|
|
|
#include "es3fShaderMatrixTests.hpp"
|
|
#include "glsShaderRenderCase.hpp"
|
|
#include "gluShaderUtil.hpp"
|
|
#include "tcuVector.hpp"
|
|
#include "tcuMatrix.hpp"
|
|
#include "tcuMatrixUtil.hpp"
|
|
#include "deStringUtil.hpp"
|
|
|
|
#include "glwEnums.hpp"
|
|
#include "glwFunctions.hpp"
|
|
|
|
namespace deqp
|
|
{
|
|
namespace gles3
|
|
{
|
|
namespace Functional
|
|
{
|
|
|
|
using std::string;
|
|
using std::vector;
|
|
using namespace glu;
|
|
using namespace deqp::gls;
|
|
|
|
using tcu::Vec2;
|
|
using tcu::Vec3;
|
|
using tcu::Vec4;
|
|
using tcu::Mat2;
|
|
using tcu::Mat2x3;
|
|
using tcu::Mat2x4;
|
|
using tcu::Mat3x2;
|
|
using tcu::Mat3;
|
|
using tcu::Mat3x4;
|
|
using tcu::Mat4x2;
|
|
using tcu::Mat4x3;
|
|
using tcu::Mat4;
|
|
|
|
// Uniform / constant values for tests.
|
|
// \note Input1 should not contain 0 components as it is used as divisor in div cases.
|
|
// \todo [2012-02-14 pyry] Make these dynamic.
|
|
static const float s_constInFloat[2] = { 0.5f, -0.2f };
|
|
static const Vec2 s_constInVec2[2] = { Vec2(1.2f, 0.5f), Vec2(0.5f, 1.0f) };
|
|
static const Vec3 s_constInVec3[2] = { Vec3(1.1f, 0.1f, 0.5f), Vec3(-0.2f, 0.5f, 0.8f) };
|
|
static const Vec4 s_constInVec4[2] = { Vec4(1.4f, 0.2f, -0.5f, 0.7f), Vec4(0.2f, -1.0f, 0.5f, 0.8f) };
|
|
|
|
static const float s_constInMat2x2[2][4] =
|
|
{
|
|
{
|
|
-0.1f, 1.0f,
|
|
-0.2f, 0.0f,
|
|
},
|
|
{
|
|
0.8f, 0.1f,
|
|
0.5f, -0.9f,
|
|
},
|
|
};
|
|
static const float s_constInMat3x2[2][6] =
|
|
{
|
|
{
|
|
0.8f, -0.3f, 0.3f,
|
|
1.0f, 1.2f, -1.2f,
|
|
},
|
|
{
|
|
1.2f, -1.0f, 0.5f,
|
|
-0.8f, 1.1f, 0.3f,
|
|
},
|
|
};
|
|
static const float s_constInMat4x2[2][8] =
|
|
{
|
|
{
|
|
-0.2f, 0.5f, 0.0f, -1.0f,
|
|
1.2f, -0.5f, 0.3f, -0.9f,
|
|
},
|
|
{
|
|
1.0f, 0.1f, -1.1f, 0.6f,
|
|
0.8f, -1.2f, -1.1f, 0.7f,
|
|
},
|
|
};
|
|
static const float s_constInMat2x3[2][6] =
|
|
{
|
|
{
|
|
-0.6f, -0.1f,
|
|
-0.7f, -1.2f,
|
|
-0.2f, 0.0f,
|
|
},
|
|
{
|
|
1.1f, 0.6f,
|
|
0.8f, 1.0f,
|
|
0.7f, 0.1f,
|
|
},
|
|
};
|
|
static const float s_constInMat3x3[2][9] =
|
|
{
|
|
{
|
|
-0.2f, 1.1f, 1.2f,
|
|
-1.0f, 1.2f, 0.5f,
|
|
0.7f, -0.2f, 1.0f,
|
|
},
|
|
{
|
|
-0.1f, -0.1f, 0.1f,
|
|
-0.1f, -0.2f, 1.0f,
|
|
-0.5f, 0.1f, -0.4f,
|
|
},
|
|
};
|
|
static const float s_constInMat4x3[2][12] =
|
|
{
|
|
{
|
|
-0.9f, 0.0f, 0.6f, 0.2f,
|
|
0.9f, -0.1f, -0.3f, -0.7f,
|
|
-0.1f, 0.1f, 1.0f, 0.0f,
|
|
},
|
|
{
|
|
0.5f, 0.7f, 0.7f, 1.2f,
|
|
1.1f, 0.1f, 1.0f, -1.0f,
|
|
-0.2f, -0.2f, -0.3f, -0.5f,
|
|
},
|
|
};
|
|
static const float s_constInMat2x4[2][8] =
|
|
{
|
|
{
|
|
-0.6f, -1.1f,
|
|
-0.6f, -0.6f,
|
|
-0.2f, -0.6f,
|
|
-0.1f, -0.1f,
|
|
},
|
|
{
|
|
-1.2f, -1.0f,
|
|
0.7f, -1.0f,
|
|
0.7f, 0.7f,
|
|
-0.4f, -0.3f,
|
|
},
|
|
};
|
|
static const float s_constInMat3x4[2][12] =
|
|
{
|
|
{
|
|
0.6f, -0.4f, 1.2f,
|
|
0.9f, 0.8f, 0.4f,
|
|
1.1f, 0.3f, 0.5f,
|
|
-0.2f, 0.0f, 1.1f,
|
|
},
|
|
{
|
|
-0.8f, 1.2f, -0.2f,
|
|
-1.1f, -0.9f, -0.5f,
|
|
-1.2f, 1.0f, 1.2f,
|
|
0.1f, -0.7f, -0.5f,
|
|
},
|
|
};
|
|
static const float s_constInMat4x4[2][16] =
|
|
{
|
|
{
|
|
0.3f, 0.9f, -0.2f, 1.0f,
|
|
-0.4f, -0.6f, 0.6f, -1.0f,
|
|
-0.9f, -0.1f, 0.3f, -0.2f,
|
|
-0.3f, -0.9f, 1.0f, 0.1f,
|
|
},
|
|
{
|
|
0.4f, -0.7f, -0.8f, 0.7f,
|
|
-0.4f, -0.8f, 0.6f, -0.3f,
|
|
0.7f, -1.0f, 0.1f, -0.3f,
|
|
0.2f, 0.6f, 0.4f, -1.0f,
|
|
},
|
|
};
|
|
|
|
namespace MatrixCaseUtils
|
|
{
|
|
|
|
enum InputType
|
|
{
|
|
INPUTTYPE_CONST = 0,
|
|
INPUTTYPE_UNIFORM,
|
|
INPUTTYPE_DYNAMIC,
|
|
|
|
INPUTTYPE_LAST
|
|
};
|
|
|
|
struct ShaderInput
|
|
{
|
|
ShaderInput (InputType inputType_, DataType dataType_, Precision precision_)
|
|
: inputType (inputType_)
|
|
, dataType (dataType_)
|
|
, precision (precision_)
|
|
{
|
|
}
|
|
|
|
InputType inputType;
|
|
DataType dataType;
|
|
Precision precision;
|
|
};
|
|
|
|
enum MatrixOp
|
|
{
|
|
OP_ADD = 0,
|
|
OP_SUB,
|
|
OP_MUL,
|
|
OP_DIV,
|
|
OP_COMP_MUL,
|
|
OP_OUTER_PRODUCT,
|
|
OP_TRANSPOSE,
|
|
OP_INVERSE,
|
|
OP_DETERMINANT,
|
|
OP_UNARY_PLUS,
|
|
OP_NEGATION,
|
|
OP_PRE_INCREMENT,
|
|
OP_PRE_DECREMENT,
|
|
OP_POST_INCREMENT,
|
|
OP_POST_DECREMENT,
|
|
OP_ADD_INTO,
|
|
OP_SUBTRACT_FROM,
|
|
OP_MULTIPLY_INTO,
|
|
OP_DIVIDE_INTO,
|
|
OP_LAST
|
|
};
|
|
|
|
// Type traits.
|
|
|
|
template <int DataT>
|
|
struct TypeTraits;
|
|
|
|
#define DECLARE_TYPE_TRAIT(DATATYPE, TYPE) \
|
|
template<> \
|
|
struct TypeTraits<DATATYPE> { \
|
|
typedef TYPE Type; \
|
|
}
|
|
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT, float);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC2, tcu::Vec2);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC3, tcu::Vec3);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_VEC4, tcu::Vec4);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2, tcu::Mat2);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X3, tcu::Mat2x3);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT2X4, tcu::Mat2x4);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X2, tcu::Mat3x2);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3, tcu::Mat3);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT3X4, tcu::Mat3x4);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X2, tcu::Mat4x2);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4X3, tcu::Mat4x3);
|
|
DECLARE_TYPE_TRAIT(TYPE_FLOAT_MAT4, tcu::Mat4);
|
|
|
|
// Operation info
|
|
|
|
enum OperationType
|
|
{
|
|
OPERATIONTYPE_BINARY_OPERATOR = 0,
|
|
OPERATIONTYPE_BINARY_FUNCTION,
|
|
OPERATIONTYPE_UNARY_PREFIX_OPERATOR,
|
|
OPERATIONTYPE_UNARY_POSTFIX_OPERATOR,
|
|
OPERATIONTYPE_UNARY_FUNCTION,
|
|
OPERATIONTYPE_ASSIGNMENT,
|
|
|
|
OPERATIONTYPE_LAST
|
|
};
|
|
|
|
static const char* getOperationName (MatrixOp op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case OP_ADD: return "+";
|
|
case OP_SUB: return "-";
|
|
case OP_MUL: return "*";
|
|
case OP_DIV: return "/";
|
|
case OP_COMP_MUL: return "matrixCompMult";
|
|
case OP_OUTER_PRODUCT: return "outerProduct";
|
|
case OP_TRANSPOSE: return "transpose";
|
|
case OP_INVERSE: return "inverse";
|
|
case OP_DETERMINANT: return "determinant";
|
|
case OP_UNARY_PLUS: return "+";
|
|
case OP_NEGATION: return "-";
|
|
case OP_PRE_INCREMENT: return "++";
|
|
case OP_PRE_DECREMENT: return "--";
|
|
case OP_POST_INCREMENT: return "++";
|
|
case OP_POST_DECREMENT: return "--";
|
|
case OP_ADD_INTO: return "+=";
|
|
case OP_SUBTRACT_FROM: return "-=";
|
|
case OP_MULTIPLY_INTO: return "*=";
|
|
case OP_DIVIDE_INTO: return "/=";
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return "";
|
|
}
|
|
}
|
|
|
|
static OperationType getOperationType (MatrixOp op)
|
|
{
|
|
switch (op)
|
|
{
|
|
case OP_ADD: return OPERATIONTYPE_BINARY_OPERATOR;
|
|
case OP_SUB: return OPERATIONTYPE_BINARY_OPERATOR;
|
|
case OP_MUL: return OPERATIONTYPE_BINARY_OPERATOR;
|
|
case OP_DIV: return OPERATIONTYPE_BINARY_OPERATOR;
|
|
case OP_COMP_MUL: return OPERATIONTYPE_BINARY_FUNCTION;
|
|
case OP_OUTER_PRODUCT: return OPERATIONTYPE_BINARY_FUNCTION;
|
|
case OP_TRANSPOSE: return OPERATIONTYPE_UNARY_FUNCTION;
|
|
case OP_INVERSE: return OPERATIONTYPE_UNARY_FUNCTION;
|
|
case OP_DETERMINANT: return OPERATIONTYPE_UNARY_FUNCTION;
|
|
case OP_UNARY_PLUS: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
|
|
case OP_NEGATION: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
|
|
case OP_PRE_INCREMENT: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
|
|
case OP_PRE_DECREMENT: return OPERATIONTYPE_UNARY_PREFIX_OPERATOR;
|
|
case OP_POST_INCREMENT: return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
|
|
case OP_POST_DECREMENT: return OPERATIONTYPE_UNARY_POSTFIX_OPERATOR;
|
|
case OP_ADD_INTO: return OPERATIONTYPE_ASSIGNMENT;
|
|
case OP_SUBTRACT_FROM: return OPERATIONTYPE_ASSIGNMENT;
|
|
case OP_MULTIPLY_INTO: return OPERATIONTYPE_ASSIGNMENT;
|
|
case OP_DIVIDE_INTO: return OPERATIONTYPE_ASSIGNMENT;
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return OPERATIONTYPE_LAST;
|
|
}
|
|
}
|
|
|
|
enum TestMatrixType
|
|
{
|
|
TESTMATRIXTYPE_DEFAULT = 0,
|
|
TESTMATRIXTYPE_NEGATED,
|
|
TESTMATRIXTYPE_INCREMENTED,
|
|
TESTMATRIXTYPE_DECREMENTED,
|
|
TESTMATRIXTYPE_NEGATED_INCREMENTED,
|
|
TESTMATRIXTYPE_INCREMENTED_LESS,
|
|
|
|
TESTMATRIXTYPE_LAST
|
|
};
|
|
|
|
static TestMatrixType getOperationTestMatrixType (MatrixOp op)
|
|
{
|
|
switch(op)
|
|
{
|
|
case OP_ADD: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_SUB: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_MUL: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_DIV: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_COMP_MUL: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_OUTER_PRODUCT: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_TRANSPOSE: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_INVERSE: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_DETERMINANT: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_UNARY_PLUS: return TESTMATRIXTYPE_DECREMENTED;
|
|
case OP_NEGATION: return TESTMATRIXTYPE_NEGATED_INCREMENTED;
|
|
case OP_PRE_INCREMENT: return TESTMATRIXTYPE_NEGATED;
|
|
case OP_PRE_DECREMENT: return TESTMATRIXTYPE_INCREMENTED;
|
|
case OP_POST_INCREMENT: return TESTMATRIXTYPE_NEGATED;
|
|
case OP_POST_DECREMENT: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_ADD_INTO: return TESTMATRIXTYPE_DEFAULT;
|
|
case OP_SUBTRACT_FROM: return TESTMATRIXTYPE_INCREMENTED_LESS;
|
|
case OP_MULTIPLY_INTO: return TESTMATRIXTYPE_NEGATED;
|
|
case OP_DIVIDE_INTO: return TESTMATRIXTYPE_DECREMENTED;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return TESTMATRIXTYPE_LAST;
|
|
}
|
|
}
|
|
|
|
static bool isOperationBinary (MatrixOp op)
|
|
{
|
|
return getOperationType(op) == OPERATIONTYPE_BINARY_OPERATOR ||
|
|
getOperationType(op) == OPERATIONTYPE_BINARY_FUNCTION ||
|
|
getOperationType(op) == OPERATIONTYPE_ASSIGNMENT;
|
|
}
|
|
|
|
static bool isOperationMatrixScalar (MatrixOp op)
|
|
{
|
|
return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV;
|
|
}
|
|
|
|
static bool isOperationMatrixVector (MatrixOp op)
|
|
{
|
|
return op == OP_MUL;
|
|
}
|
|
|
|
static bool isOperationArithmeticMatrixMatrix (MatrixOp op)
|
|
{
|
|
return op == OP_MUL;
|
|
}
|
|
|
|
static bool isOperationComponentwiseMatrixMatrix (MatrixOp op)
|
|
{
|
|
return op == OP_ADD || op == OP_SUB || op == OP_MUL || op == OP_DIV || op == OP_COMP_MUL;
|
|
}
|
|
|
|
static bool isOperationVectorVector (MatrixOp op)
|
|
{
|
|
return op == OP_OUTER_PRODUCT;
|
|
}
|
|
|
|
static bool isOperationUnaryAnyMatrix (MatrixOp op)
|
|
{
|
|
return op == OP_TRANSPOSE ||
|
|
op == OP_UNARY_PLUS ||
|
|
op == OP_NEGATION ||
|
|
op == OP_PRE_INCREMENT ||
|
|
op == OP_PRE_DECREMENT ||
|
|
op == OP_POST_INCREMENT ||
|
|
op == OP_POST_DECREMENT;
|
|
}
|
|
|
|
static bool isOperationUnarySymmetricMatrix (MatrixOp op)
|
|
{
|
|
return op == OP_INVERSE || op == OP_DETERMINANT;
|
|
}
|
|
|
|
static bool isOperationValueModifying (MatrixOp op)
|
|
{
|
|
return op == OP_PRE_INCREMENT ||
|
|
op == OP_PRE_DECREMENT ||
|
|
op == OP_POST_INCREMENT ||
|
|
op == OP_POST_DECREMENT;
|
|
}
|
|
|
|
static bool isOperationAssignment (MatrixOp op)
|
|
{
|
|
return op == OP_ADD_INTO ||
|
|
op == OP_SUBTRACT_FROM ||
|
|
op == OP_MULTIPLY_INTO ||
|
|
op == OP_DIVIDE_INTO;
|
|
}
|
|
|
|
static bool isOperationAssignmentAnyMatrix (MatrixOp op)
|
|
{
|
|
return op == OP_ADD_INTO ||
|
|
op == OP_SUBTRACT_FROM ||
|
|
op == OP_DIVIDE_INTO;
|
|
}
|
|
|
|
static bool isOperationAssignmentSymmetricMatrix (MatrixOp op)
|
|
{
|
|
return op == OP_MULTIPLY_INTO;
|
|
}
|
|
|
|
// Operation nature
|
|
|
|
enum OperationNature
|
|
{
|
|
OPERATIONNATURE_PURE = 0,
|
|
OPERATIONNATURE_MUTATING,
|
|
OPERATIONNATURE_ASSIGNMENT,
|
|
|
|
OPERATIONNATURE_LAST
|
|
};
|
|
|
|
static OperationNature getOperationNature (MatrixOp op)
|
|
{
|
|
if (isOperationAssignment(op))
|
|
return OPERATIONNATURE_ASSIGNMENT;
|
|
|
|
if (isOperationValueModifying(op))
|
|
return OPERATIONNATURE_MUTATING;
|
|
|
|
return OPERATIONNATURE_PURE;
|
|
}
|
|
|
|
// Input value loader.
|
|
|
|
template <int InputT, int DataT>
|
|
typename TypeTraits<DataT>::Type getInputValue (const ShaderEvalContext& evalCtx, int inputNdx);
|
|
|
|
template <> inline float getInputValue<INPUTTYPE_CONST, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInFloat[inputNdx]; }
|
|
template <> inline tcu::Vec2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec2[inputNdx]; }
|
|
template <> inline tcu::Vec3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec3[inputNdx]; }
|
|
template <> inline tcu::Vec4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_VEC4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return s_constInVec4[inputNdx]; }
|
|
|
|
template <> inline tcu::Mat2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2(s_constInMat2x2[inputNdx]); }
|
|
template <> inline tcu::Mat2x3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2X3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2x3(s_constInMat2x3[inputNdx]); }
|
|
template <> inline tcu::Mat2x4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT2X4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat2x4(s_constInMat2x4[inputNdx]); }
|
|
template <> inline tcu::Mat3x2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3X2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3x2(s_constInMat3x2[inputNdx]); }
|
|
template <> inline tcu::Mat3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3(s_constInMat3x3[inputNdx]); }
|
|
template <> inline tcu::Mat3x4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT3X4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat3x4(s_constInMat3x4[inputNdx]); }
|
|
template <> inline tcu::Mat4x2 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4X2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4x2(s_constInMat4x2[inputNdx]); }
|
|
template <> inline tcu::Mat4x3 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4X3> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4x3(s_constInMat4x3[inputNdx]); }
|
|
template <> inline tcu::Mat4 getInputValue<INPUTTYPE_CONST, TYPE_FLOAT_MAT4> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(evalCtx); return tcu::Mat4(s_constInMat4x4[inputNdx]); }
|
|
|
|
template <> inline float getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.x(); }
|
|
template <> inline tcu::Vec2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_VEC2> (const ShaderEvalContext& evalCtx, int inputNdx) { DE_UNREF(inputNdx); return evalCtx.coords.swizzle(0, 1); }
|
|
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); }
|
|
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); }
|
|
|
|
template <> inline tcu::Mat2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat2 m;
|
|
m.setColumn(0, evalCtx.in[0].swizzle(0,1));
|
|
m.setColumn(1, evalCtx.in[1].swizzle(0,1));
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat2x3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2X3> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat2x3 m;
|
|
m.setColumn(0, evalCtx.in[0].swizzle(0,1,2));
|
|
m.setColumn(1, evalCtx.in[1].swizzle(0,1,2));
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat2x4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT2X4> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat2x4 m;
|
|
m.setColumn(0, evalCtx.in[0]);
|
|
m.setColumn(1, evalCtx.in[1]);
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat3x2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3X2> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat3x2 m;
|
|
m.setColumn(0, evalCtx.in[0].swizzle(0,1));
|
|
m.setColumn(1, evalCtx.in[1].swizzle(0,1));
|
|
m.setColumn(2, evalCtx.in[2].swizzle(0,1));
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat3 m;
|
|
m.setColumn(0, evalCtx.in[0].swizzle(0,1,2));
|
|
m.setColumn(1, evalCtx.in[1].swizzle(0,1,2));
|
|
m.setColumn(2, evalCtx.in[2].swizzle(0,1,2));
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat3x4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT3X4> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat3x4 m;
|
|
m.setColumn(0, evalCtx.in[0]);
|
|
m.setColumn(1, evalCtx.in[1]);
|
|
m.setColumn(2, evalCtx.in[2]);
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat4x2 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4X2> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat4x2 m;
|
|
m.setColumn(0, evalCtx.in[0].swizzle(0,1));
|
|
m.setColumn(1, evalCtx.in[1].swizzle(0,1));
|
|
m.setColumn(2, evalCtx.in[2].swizzle(0,1));
|
|
m.setColumn(3, evalCtx.in[3].swizzle(0,1));
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat4x3 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4X3> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat4x3 m;
|
|
m.setColumn(0, evalCtx.in[0].swizzle(0,1,2));
|
|
m.setColumn(1, evalCtx.in[1].swizzle(0,1,2));
|
|
m.setColumn(2, evalCtx.in[2].swizzle(0,1,2));
|
|
m.setColumn(3, evalCtx.in[3].swizzle(0,1,2));
|
|
return m;
|
|
}
|
|
|
|
template <> inline tcu::Mat4 getInputValue<INPUTTYPE_DYNAMIC, TYPE_FLOAT_MAT4> (const ShaderEvalContext& evalCtx, int inputNdx)
|
|
{
|
|
DE_UNREF(inputNdx); // Not used.
|
|
tcu::Mat4 m;
|
|
m.setColumn(0, evalCtx.in[0]);
|
|
m.setColumn(1, evalCtx.in[1]);
|
|
m.setColumn(2, evalCtx.in[2]);
|
|
m.setColumn(3, evalCtx.in[3]);
|
|
return m;
|
|
}
|
|
|
|
// Reduction from expression result to vec3.
|
|
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Vec2& value) { return value.swizzle(0,1,0); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Vec3& value) { return value; }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Vec4& value) { return tcu::Vec3(value.x(), value.y(), value.z()+value.w()); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat2& value) { return tcu::Vec3(value(0, 0), value(0, 1), value(1, 0)+value(1, 1)); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat2x3& value) { return value.getColumn(0) + value.getColumn(1); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat2x4& value) { return value.getColumn(0).swizzle(0,1,2) + value.getColumn(1).swizzle(1,2,3); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat3x2& value) { return tcu::Vec3(value(0,0)+value(1,0), value(0,1)+value(1,1), value(0,2)+value(1,2)); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat3x4& value) { return value.getColumn(0).swizzle(0,1,2) + value.getColumn(1).swizzle(1,2,3) + value.getColumn(2).swizzle(2,3,0); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat4x2& value) { return tcu::Vec3(value(0,0)+value(1,0)+value(0,3), value(0,1)+value(1,1)+value(1,3), value(0,2)+value(1,2)); }
|
|
inline tcu::Vec3 reduceToVec3 (const tcu::Mat4x3& value) { return value.getColumn(0) + value.getColumn(1) + value.getColumn(2) + value.getColumn(3); }
|
|
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); }
|
|
|
|
// matrixCompMult
|
|
|
|
template <typename T, int Rows, int Cols>
|
|
tcu::Matrix<T, Rows, Cols> matrixCompMult (const tcu::Matrix<T, Rows, Cols>& a, const tcu::Matrix<T, Rows, Cols>& b)
|
|
{
|
|
tcu::Matrix<T, Rows, Cols> retVal;
|
|
|
|
for (int r = 0; r < Rows; ++r)
|
|
for (int c = 0; c < Cols; ++c)
|
|
retVal(r,c) = a(r,c) * b(r, c);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// outerProduct
|
|
|
|
template <typename T, int Rows, int Cols>
|
|
tcu::Matrix<T, Cols, Rows> outerProduct (const tcu::Vector<T, Cols>& a, const tcu::Vector<T, Rows>& b)
|
|
{
|
|
tcu::Matrix<T, Rows, Cols> retVal;
|
|
|
|
for (int r = 0; r < Rows; ++r)
|
|
for (int c = 0; c < Cols; ++c)
|
|
retVal(r,c) = a[c] * b[r];
|
|
|
|
return transpose(retVal); // to gl-form (column-major)
|
|
}
|
|
|
|
// Determinant
|
|
|
|
template <int Size>
|
|
float determinant (const tcu::Matrix<float, Size, Size>& mat);
|
|
|
|
template <>
|
|
float determinant<2> (const tcu::Matrix<float, 2, 2>& mat)
|
|
{
|
|
return mat(0,0) * mat(1,1) - mat(1,0) * mat(0,1);
|
|
}
|
|
|
|
template <>
|
|
float determinant<3> (const tcu::Matrix<float, 3, 3>& mat)
|
|
{
|
|
return + mat(0,0) * mat(1,1) * mat(2,2)
|
|
+ mat(0,1) * mat(1,2) * mat(2,0)
|
|
+ mat(0,2) * mat(1,0) * mat(2,1)
|
|
- mat(0,0) * mat(1,2) * mat(2,1)
|
|
- mat(0,1) * mat(1,0) * mat(2,2)
|
|
- mat(0,2) * mat(1,1) * mat(2,0);
|
|
}
|
|
|
|
template <>
|
|
float determinant<4> (const tcu::Matrix<float, 4, 4>& mat)
|
|
{
|
|
const float minorMatrices[4][3*3] =
|
|
{
|
|
{
|
|
mat(1,1), mat(2,1), mat(3,1),
|
|
mat(1,2), mat(2,2), mat(3,2),
|
|
mat(1,3), mat(2,3), mat(3,3),
|
|
},
|
|
{
|
|
mat(1,0), mat(2,0), mat(3,0),
|
|
mat(1,2), mat(2,2), mat(3,2),
|
|
mat(1,3), mat(2,3), mat(3,3),
|
|
},
|
|
{
|
|
mat(1,0), mat(2,0), mat(3,0),
|
|
mat(1,1), mat(2,1), mat(3,1),
|
|
mat(1,3), mat(2,3), mat(3,3),
|
|
},
|
|
{
|
|
mat(1,0), mat(2,0), mat(3,0),
|
|
mat(1,1), mat(2,1), mat(3,1),
|
|
mat(1,2), mat(2,2), mat(3,2),
|
|
}
|
|
};
|
|
|
|
return + mat(0,0) * determinant(tcu::Mat3(minorMatrices[0]))
|
|
- mat(0,1) * determinant(tcu::Mat3(minorMatrices[1]))
|
|
+ mat(0,2) * determinant(tcu::Mat3(minorMatrices[2]))
|
|
- mat(0,3) * determinant(tcu::Mat3(minorMatrices[3]));
|
|
}
|
|
|
|
// Inverse
|
|
|
|
template <int Size>
|
|
tcu::Matrix<float, Size, Size> inverse (const tcu::Matrix<float, Size, Size>& mat);
|
|
|
|
template <>
|
|
tcu::Matrix<float, 2, 2> inverse<2> (const tcu::Matrix<float, 2, 2>& mat)
|
|
{
|
|
const float det = determinant(mat);
|
|
tcu::Matrix<float, 2, 2> retVal;
|
|
|
|
DE_ASSERT(det != 0.0f);
|
|
|
|
retVal(0, 0) = mat(1, 1) / det;
|
|
retVal(0, 1) = -mat(0, 1) / det;
|
|
retVal(1, 0) = -mat(1, 0) / det;
|
|
retVal(1, 1) = mat(0, 0) / det;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
template <>
|
|
tcu::Matrix<float, 3, 3> inverse<3> (const tcu::Matrix<float, 3, 3>& mat)
|
|
{
|
|
// Blockwise inversion
|
|
|
|
DE_ASSERT(determinant(mat) != 0.0f);
|
|
|
|
const float areaA[2*2] =
|
|
{
|
|
mat(0,0), mat(0,1),
|
|
mat(1,0), mat(1,1)
|
|
};
|
|
const float areaB[2] =
|
|
{
|
|
mat(0,2),
|
|
mat(1,2),
|
|
};
|
|
const float areaC[2] =
|
|
{
|
|
mat(2,0), mat(2,1),
|
|
};
|
|
const float areaD[1] =
|
|
{
|
|
mat(2,2)
|
|
};
|
|
const float nullField[4] = { 0.0f };
|
|
|
|
const tcu::Matrix<float, 2, 2> invA = inverse(tcu::Matrix<float, 2, 2>(areaA));
|
|
const tcu::Matrix<float, 2, 1> matB = tcu::Matrix<float, 2, 1>(areaB);
|
|
const tcu::Matrix<float, 1, 2> matC = tcu::Matrix<float, 1, 2>(areaC);
|
|
const tcu::Matrix<float, 1, 1> matD = tcu::Matrix<float, 1, 1>(areaD);
|
|
|
|
const float schurComplement = 1.0f / (matD - matC*invA*matB)(0,0);
|
|
const tcu::Matrix<float, 2, 2> zeroMat = Mat2(nullField);
|
|
|
|
const tcu::Matrix<float, 2, 2> blockA = invA + invA*matB*schurComplement*matC*invA;
|
|
const tcu::Matrix<float, 2, 1> blockB = (zeroMat-invA)*matB*schurComplement;
|
|
const tcu::Matrix<float, 1, 2> blockC = matC*invA*(-schurComplement);
|
|
const float blockD = schurComplement;
|
|
|
|
const float result[3*3] =
|
|
{
|
|
blockA(0,0), blockA(0,1), blockB(0,0),
|
|
blockA(1,0), blockA(1,1), blockB(1,0),
|
|
blockC(0,0), blockC(0,1), blockD,
|
|
};
|
|
|
|
return Mat3(result);
|
|
}
|
|
|
|
template <>
|
|
tcu::Matrix<float, 4, 4> inverse<4> (const tcu::Matrix<float, 4, 4>& mat)
|
|
{
|
|
// Blockwise inversion
|
|
|
|
DE_ASSERT(determinant(mat) != 0.0f);
|
|
|
|
const float areaA[2*2] =
|
|
{
|
|
mat(0,0), mat(0,1),
|
|
mat(1,0), mat(1,1)
|
|
};
|
|
const float areaB[2*2] =
|
|
{
|
|
mat(0,2), mat(0,3),
|
|
mat(1,2), mat(1,3)
|
|
};
|
|
const float areaC[2*2] =
|
|
{
|
|
mat(2,0), mat(2,1),
|
|
mat(3,0), mat(3,1)
|
|
};
|
|
const float areaD[2*2] =
|
|
{
|
|
mat(2,2), mat(2,3),
|
|
mat(3,2), mat(3,3)
|
|
};
|
|
const float nullField[4] = { 0.0f };
|
|
|
|
const tcu::Matrix<float, 2, 2> invA = inverse(Mat2(areaA));
|
|
const tcu::Matrix<float, 2, 2> matB = Mat2(areaB);
|
|
const tcu::Matrix<float, 2, 2> matC = Mat2(areaC);
|
|
const tcu::Matrix<float, 2, 2> matD = Mat2(areaD);
|
|
|
|
const tcu::Matrix<float, 2, 2> schurComplement = inverse(matD - matC*invA*matB);
|
|
const tcu::Matrix<float, 2, 2> zeroMat = Mat2(nullField);
|
|
|
|
const tcu::Matrix<float, 2, 2> blockA = invA + invA*matB*schurComplement*matC*invA;
|
|
const tcu::Matrix<float, 2, 2> blockB = (zeroMat-invA)*matB*schurComplement;
|
|
const tcu::Matrix<float, 2, 2> blockC = (zeroMat-schurComplement)*matC*invA;
|
|
const tcu::Matrix<float, 2, 2> blockD = schurComplement;
|
|
|
|
const float result[4*4] =
|
|
{
|
|
blockA(0,0), blockA(0,1), blockB(0,0), blockB(0,1),
|
|
blockA(1,0), blockA(1,1), blockB(1,0), blockB(1,1),
|
|
blockC(0,0), blockC(0,1), blockD(0,0), blockD(0,1),
|
|
blockC(1,0), blockC(1,1), blockD(1,0), blockD(1,1),
|
|
};
|
|
|
|
return Mat4(result);
|
|
}
|
|
|
|
// negate
|
|
|
|
template <typename T, int Rows, int Cols>
|
|
tcu::Matrix<T, Rows, Cols> negate (const tcu::Matrix<T, Rows, Cols>& mat)
|
|
{
|
|
tcu::Matrix<T, Rows, Cols> retVal;
|
|
|
|
for (int r = 0; r < Rows; ++r)
|
|
for (int c = 0; c < Cols; ++c)
|
|
retVal(r,c) = -mat(r, c);
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// increment/decrement
|
|
|
|
template <typename T, int Rows, int Cols>
|
|
tcu::Matrix<T, Rows, Cols> increment (const tcu::Matrix<T, Rows, Cols>& mat)
|
|
{
|
|
tcu::Matrix<T, Rows, Cols> retVal;
|
|
|
|
for (int r = 0; r < Rows; ++r)
|
|
for (int c = 0; c < Cols; ++c)
|
|
retVal(r,c) = mat(r, c) + 1.0f;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
template <typename T, int Rows, int Cols>
|
|
tcu::Matrix<T, Rows, Cols> decrement (const tcu::Matrix<T, Rows, Cols>& mat)
|
|
{
|
|
tcu::Matrix<T, Rows, Cols> retVal;
|
|
|
|
for (int r = 0; r < Rows; ++r)
|
|
for (int c = 0; c < Cols; ++c)
|
|
retVal(r,c) = mat(r, c) - 1.0f;
|
|
|
|
return retVal;
|
|
}
|
|
|
|
// Evaluator template.
|
|
|
|
typedef void (*MatrixShaderEvalFunc) (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type);
|
|
|
|
template <int Op, int In0DataType, int In1DataType>
|
|
struct Evaluator;
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_ADD, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 + in1);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_SUB, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 - in1);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_MUL, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 * in1);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_DIV, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 / in1);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_COMP_MUL, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(matrixCompMult(in0, in1));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_OUTER_PRODUCT, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(outerProduct(in0, in1));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_TRANSPOSE, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
evalCtx.color.xyz() = reduceToVec3(transpose(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_INVERSE, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
evalCtx.color.xyz() = reduceToVec3(inverse(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_DETERMINANT, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
evalCtx.color.xyz() = Vec3(determinant(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_UNARY_PLUS, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
evalCtx.color.xyz() = reduceToVec3(in0);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_NEGATION, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
evalCtx.color.xyz() = reduceToVec3(negate(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_PRE_INCREMENT, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
|
|
// modifying reduction: sum modified value too
|
|
evalCtx.color.xyz() = reduceToVec3(increment(in0)) + reduceToVec3(increment(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_PRE_DECREMENT, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
|
|
// modifying reduction: sum modified value too
|
|
evalCtx.color.xyz() = reduceToVec3(decrement(in0)) + reduceToVec3(decrement(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_POST_INCREMENT, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
|
|
// modifying reduction: sum modified value too
|
|
evalCtx.color.xyz() = reduceToVec3(in0) + reduceToVec3(increment(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_POST_DECREMENT, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
DE_UNREF(in1Type);
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
|
|
// modifying reduction: sum modified value too
|
|
evalCtx.color.xyz() = reduceToVec3(in0) + reduceToVec3(decrement(in0));
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_ADD_INTO, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 + in1);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_SUBTRACT_FROM, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 - in1);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_MULTIPLY_INTO, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 * in1);
|
|
}
|
|
};
|
|
|
|
template <int In0DataType, int In1DataType>
|
|
struct Evaluator<OP_DIVIDE_INTO, In0DataType, In1DataType>
|
|
{
|
|
static void evaluate (ShaderEvalContext& evalCtx, InputType in0Type, InputType in1Type)
|
|
{
|
|
typename TypeTraits<In0DataType>::Type in0 = (in0Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In0DataType>(evalCtx, 0)
|
|
: getInputValue<INPUTTYPE_CONST, In0DataType>(evalCtx, 0);
|
|
typename TypeTraits<In1DataType>::Type in1 = (in1Type == INPUTTYPE_DYNAMIC) ? getInputValue<INPUTTYPE_DYNAMIC, In1DataType>(evalCtx, 1)
|
|
: getInputValue<INPUTTYPE_CONST, In1DataType>(evalCtx, 1);
|
|
evalCtx.color.xyz() = reduceToVec3(in0 / in1);
|
|
}
|
|
};
|
|
|
|
MatrixShaderEvalFunc getEvalFunc (const ShaderInput& in0, const ShaderInput& in1, MatrixOp op)
|
|
{
|
|
// Evaluator is selected based on op and input data types.
|
|
// For efficient lookup the types and op enums are packed together to form a 19-bit key:
|
|
// [18..14 OP] [13..7 TYPE0] [6..0 TYPE1]
|
|
|
|
DE_STATIC_ASSERT(TYPE_LAST <= (1<<7));
|
|
DE_STATIC_ASSERT(OP_LAST <= (1<<5));
|
|
|
|
#define PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE) (((OP) << 14) | ((IN0DATATYPE) << 7) | (IN1DATATYPE))
|
|
|
|
#define MAKE_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE) \
|
|
case PACK_EVAL_CASE(OP, IN0DATATYPE, IN1DATATYPE): \
|
|
return Evaluator<OP, IN0DATATYPE, IN1DATATYPE>::evaluate
|
|
|
|
#define MAKE_SCALAR_OPS(IN0DATATYPE, IN1DATATYPE) \
|
|
MAKE_EVAL_CASE(OP_ADD, IN0DATATYPE, IN1DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_SUB, IN0DATATYPE, IN1DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_DIV, IN0DATATYPE, IN1DATATYPE)
|
|
|
|
#define MAKE_CWISE_OPS(IN0DATATYPE, IN1DATATYPE) \
|
|
MAKE_EVAL_CASE(OP_ADD, IN0DATATYPE, IN1DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_SUB, IN0DATATYPE, IN1DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_DIV, IN0DATATYPE, IN1DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_COMP_MUL, IN0DATATYPE, IN1DATATYPE)
|
|
|
|
#define MAKE_MUL_OP(IN0DATATYPE, IN1DATATYPE) \
|
|
MAKE_EVAL_CASE(OP_MUL, IN0DATATYPE, IN1DATATYPE)
|
|
|
|
#define MAKE_VECVEC_OP(IN0DATATYPE, IN1DATATYPE) \
|
|
MAKE_EVAL_CASE(OP_OUTER_PRODUCT, IN0DATATYPE, IN1DATATYPE)
|
|
|
|
#define MAKE_UNARY_OP(IN0DATATYPE) \
|
|
MAKE_EVAL_CASE(OP_TRANSPOSE, IN0DATATYPE, TYPE_LAST); \
|
|
MAKE_EVAL_CASE(OP_UNARY_PLUS, IN0DATATYPE, TYPE_LAST); \
|
|
MAKE_EVAL_CASE(OP_NEGATION, IN0DATATYPE, TYPE_LAST); \
|
|
MAKE_EVAL_CASE(OP_PRE_INCREMENT, IN0DATATYPE, TYPE_LAST); \
|
|
MAKE_EVAL_CASE(OP_PRE_DECREMENT, IN0DATATYPE, TYPE_LAST); \
|
|
MAKE_EVAL_CASE(OP_POST_INCREMENT, IN0DATATYPE, TYPE_LAST); \
|
|
MAKE_EVAL_CASE(OP_POST_DECREMENT, IN0DATATYPE, TYPE_LAST)
|
|
|
|
#define MAKE_UNARY_SYMMETRIC_OP(IN0DATATYPE) \
|
|
MAKE_UNARY_OP(IN0DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_DETERMINANT, IN0DATATYPE, TYPE_LAST); \
|
|
MAKE_EVAL_CASE(OP_INVERSE, IN0DATATYPE, TYPE_LAST)
|
|
|
|
#define MAKE_ASSIGNMENT_OP(IN0DATATYPE) \
|
|
MAKE_EVAL_CASE(OP_ADD_INTO, IN0DATATYPE, IN0DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_SUBTRACT_FROM, IN0DATATYPE, IN0DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_DIVIDE_INTO, IN0DATATYPE, IN0DATATYPE)
|
|
|
|
#define MAKE_ASSIGNMENT_SYMMETRIC_OP(IN0DATATYPE) \
|
|
MAKE_ASSIGNMENT_OP(IN0DATATYPE); \
|
|
MAKE_EVAL_CASE(OP_MULTIPLY_INTO, IN0DATATYPE, IN0DATATYPE)
|
|
|
|
switch (PACK_EVAL_CASE(op, in0.dataType, in1.dataType))
|
|
{
|
|
// Matrix-scalar.
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X3, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT2X4, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X2, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT3X4, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X2, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4X3, TYPE_FLOAT);
|
|
MAKE_SCALAR_OPS(TYPE_FLOAT_MAT4, TYPE_FLOAT);
|
|
|
|
// Matrix-vector.
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_VEC2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_VEC2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_VEC2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_VEC3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_VEC3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_VEC3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_VEC4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_VEC4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_VEC4);
|
|
|
|
// Vector-matrix.
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT2X3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT2X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT3X2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT3X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_MAT4X2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_MAT4X3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_MAT4);
|
|
|
|
// Matrix-matrix.
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT3X2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2, TYPE_FLOAT_MAT4X2);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2X3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT3X2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X3, TYPE_FLOAT_MAT4X2);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT2X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT3X2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT2X4, TYPE_FLOAT_MAT4X2);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3X2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT2X3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X2, TYPE_FLOAT_MAT4X3);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT2X3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3, TYPE_FLOAT_MAT4X3);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT3X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT2X3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT3X4, TYPE_FLOAT_MAT4X3);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4X2);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT2X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT3X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X2, TYPE_FLOAT_MAT4);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4X3);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT2X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT3X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4X3, TYPE_FLOAT_MAT4);
|
|
|
|
MAKE_CWISE_OPS(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT2X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT3X4);
|
|
MAKE_MUL_OP(TYPE_FLOAT_MAT4, TYPE_FLOAT_MAT4);
|
|
|
|
// Vector-vector.
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC2);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC3);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC2, TYPE_FLOAT_VEC4);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC2);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC3);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC3, TYPE_FLOAT_VEC4);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC2);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC3);
|
|
MAKE_VECVEC_OP(TYPE_FLOAT_VEC4, TYPE_FLOAT_VEC4);
|
|
|
|
// Unary Matrix.
|
|
MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
|
|
MAKE_UNARY_OP(TYPE_FLOAT_MAT2X3);
|
|
MAKE_UNARY_OP(TYPE_FLOAT_MAT2X4);
|
|
MAKE_UNARY_OP(TYPE_FLOAT_MAT3X2);
|
|
MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
|
|
MAKE_UNARY_OP(TYPE_FLOAT_MAT3X4);
|
|
MAKE_UNARY_OP(TYPE_FLOAT_MAT4X2);
|
|
MAKE_UNARY_OP(TYPE_FLOAT_MAT4X3);
|
|
MAKE_UNARY_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
|
|
|
|
// Assignments
|
|
MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT2);
|
|
MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X3);
|
|
MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT2X4);
|
|
MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X2);
|
|
MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT3);
|
|
MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT3X4);
|
|
MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X2);
|
|
MAKE_ASSIGNMENT_OP(TYPE_FLOAT_MAT4X3);
|
|
MAKE_ASSIGNMENT_SYMMETRIC_OP(TYPE_FLOAT_MAT4);
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
return DE_NULL;
|
|
}
|
|
|
|
#undef PACK_EVAL_CASE
|
|
#undef MAKE_EVAL_CASE
|
|
#undef MUL_OP
|
|
#undef ALL_OPS
|
|
#undef MAKE_MAT_SCALAR_VEC_CASES
|
|
#undef MAKE_MAT_MAT_CASES
|
|
}
|
|
|
|
// Shader source format utilities.
|
|
|
|
template <int Size>
|
|
void writeVectorConstructor (std::ostream& str, const tcu::Vector<float, Size>& v)
|
|
{
|
|
str << "vec" << Size << "(";
|
|
for (int ndx = 0; ndx < Size; ndx++)
|
|
{
|
|
if (ndx != 0)
|
|
str << ", ";
|
|
str << de::floatToString(v[ndx], 1);
|
|
}
|
|
str << ")";
|
|
}
|
|
|
|
template <int Cols, int Rows>
|
|
void writeMatrixConstructor (std::ostream& str, const tcu::Matrix<float, Rows, Cols>& m)
|
|
{
|
|
if (Rows == Cols)
|
|
str << "mat" << Cols;
|
|
else
|
|
str << "mat" << Cols << "x" << Rows;
|
|
|
|
str << "(";
|
|
for (int colNdx = 0; colNdx < Cols; colNdx++)
|
|
{
|
|
for (int rowNdx = 0; rowNdx < Rows; rowNdx++)
|
|
{
|
|
if (rowNdx > 0 || colNdx > 0)
|
|
str << ", ";
|
|
str << de::floatToString(m(rowNdx, colNdx), 1);
|
|
}
|
|
}
|
|
str << ")";
|
|
}
|
|
|
|
} // MatrixCaseUtils
|
|
|
|
using namespace MatrixCaseUtils;
|
|
|
|
class MatrixShaderEvaluator : public ShaderEvaluator
|
|
{
|
|
public:
|
|
MatrixShaderEvaluator (MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1);
|
|
|
|
virtual void evaluate (ShaderEvalContext& evalCtx);
|
|
|
|
private:
|
|
MatrixShaderEvalFunc m_matEvalFunc;
|
|
InputType m_inType0;
|
|
InputType m_inType1;
|
|
};
|
|
|
|
MatrixShaderEvaluator::MatrixShaderEvaluator (MatrixShaderEvalFunc evalFunc, InputType inType0, InputType inType1)
|
|
: m_matEvalFunc (evalFunc)
|
|
, m_inType0 (inType0)
|
|
, m_inType1 (inType1)
|
|
{
|
|
}
|
|
|
|
void MatrixShaderEvaluator::evaluate (ShaderEvalContext& evalCtx)
|
|
{
|
|
m_matEvalFunc(evalCtx, m_inType0, m_inType1);
|
|
}
|
|
|
|
class ShaderMatrixCase : public ShaderRenderCase
|
|
{
|
|
public:
|
|
ShaderMatrixCase (Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase);
|
|
~ShaderMatrixCase (void);
|
|
|
|
void init (void);
|
|
|
|
protected:
|
|
std::string genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName);
|
|
void setupUniforms (int programID, const tcu::Vec4& constCoords);
|
|
|
|
private:
|
|
ShaderInput m_in0;
|
|
ShaderInput m_in1;
|
|
MatrixOp m_op;
|
|
MatrixShaderEvaluator m_matEvaluator;
|
|
};
|
|
|
|
ShaderMatrixCase::ShaderMatrixCase (Context& context, const char* name, const char* desc, const ShaderInput& in0, const ShaderInput& in1, MatrixOp op, bool isVertexCase)
|
|
: ShaderRenderCase (context.getTestContext(), context.getRenderContext(), context.getContextInfo(), name, desc, isVertexCase, m_matEvaluator)
|
|
, m_in0 (in0)
|
|
, m_in1 (in1)
|
|
, m_op (op)
|
|
, m_matEvaluator (getEvalFunc(in0, in1, op), in0.inputType, in1.inputType)
|
|
{
|
|
}
|
|
|
|
ShaderMatrixCase::~ShaderMatrixCase (void)
|
|
{
|
|
}
|
|
|
|
void ShaderMatrixCase::init (void)
|
|
{
|
|
std::ostringstream vtx;
|
|
std::ostringstream frag;
|
|
std::ostringstream& op = m_isVertexCase ? vtx : frag;
|
|
|
|
bool isInDynMat0 = isDataTypeMatrix(m_in0.dataType) && m_in0.inputType == INPUTTYPE_DYNAMIC;
|
|
bool isInDynMat1 = isDataTypeMatrix(m_in1.dataType) && m_in1.inputType == INPUTTYPE_DYNAMIC;
|
|
string inValue0;
|
|
string inValue1;
|
|
DataType resultType = TYPE_LAST;
|
|
Precision resultPrec = m_in0.precision;
|
|
vector<string> passVars;
|
|
int numInputs = (isOperationBinary(m_op)) ? (2) : (1);
|
|
|
|
std::string operationValue0;
|
|
std::string operationValue1;
|
|
|
|
DE_ASSERT(!isInDynMat0 || !isInDynMat1); // Only single dynamic matrix input is allowed.
|
|
DE_UNREF(isInDynMat0 && isInDynMat1);
|
|
|
|
// Compute result type.
|
|
if (m_op == OP_MUL && isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
|
|
{
|
|
resultType = getDataTypeMatrix(getDataTypeMatrixNumColumns(m_in1.dataType), getDataTypeMatrixNumRows(m_in0.dataType));
|
|
}
|
|
else if (m_op == OP_OUTER_PRODUCT)
|
|
{
|
|
resultType = getDataTypeMatrix(getDataTypeScalarSize(m_in1.dataType), getDataTypeScalarSize(m_in0.dataType));
|
|
}
|
|
else if (m_op == OP_TRANSPOSE)
|
|
{
|
|
resultType = getDataTypeMatrix(getDataTypeMatrixNumRows(m_in0.dataType), getDataTypeMatrixNumColumns(m_in0.dataType));
|
|
}
|
|
else if (m_op == OP_INVERSE)
|
|
{
|
|
resultType = m_in0.dataType;
|
|
}
|
|
else if (m_op == OP_DETERMINANT)
|
|
{
|
|
resultType = TYPE_FLOAT;
|
|
}
|
|
else if (getOperationType(m_op) == OPERATIONTYPE_UNARY_PREFIX_OPERATOR ||
|
|
getOperationType(m_op) == OPERATIONTYPE_UNARY_POSTFIX_OPERATOR)
|
|
{
|
|
resultType = m_in0.dataType;
|
|
}
|
|
else if (isDataTypeMatrix(m_in0.dataType) && isDataTypeMatrix(m_in1.dataType))
|
|
{
|
|
DE_ASSERT(m_in0.dataType == m_in1.dataType);
|
|
resultType = m_in0.dataType;
|
|
}
|
|
else if (isDataTypeMatrix(m_in0.dataType) || isDataTypeMatrix(m_in1.dataType))
|
|
{
|
|
int matNdx = isDataTypeMatrix(m_in0.dataType) ? 0 : 1;
|
|
DataType matrixType = matNdx == 0 ? m_in0.dataType : m_in1.dataType;
|
|
DataType otherType = matNdx == 0 ? m_in1.dataType : m_in0.dataType;
|
|
|
|
if (otherType == TYPE_FLOAT)
|
|
resultType = matrixType;
|
|
else
|
|
{
|
|
DE_ASSERT(isDataTypeVector(otherType));
|
|
resultType = getDataTypeFloatVec(matNdx == 0 ? getDataTypeMatrixNumRows(matrixType) : getDataTypeMatrixNumColumns(matrixType));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
vtx << "#version 300 es\n";
|
|
frag << "#version 300 es\n";
|
|
|
|
vtx << "in highp vec4 a_position;\n";
|
|
frag << "layout(location = 0) out mediump vec4 dEQP_FragColor;\n";
|
|
if (m_isVertexCase)
|
|
{
|
|
vtx << "out mediump vec4 v_color;\n";
|
|
frag << "in mediump vec4 v_color;\n";
|
|
}
|
|
|
|
// Input declarations.
|
|
for (int inNdx = 0; inNdx < numInputs; inNdx++)
|
|
{
|
|
const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0;
|
|
const char* precName = getPrecisionName(in.precision);
|
|
const char* typeName = getDataTypeName(in.dataType);
|
|
string& inValue = inNdx > 0 ? inValue1 : inValue0;
|
|
|
|
if (in.inputType == INPUTTYPE_DYNAMIC)
|
|
{
|
|
vtx << "in " << precName << " " << typeName << " a_";
|
|
|
|
if (isDataTypeMatrix(in.dataType))
|
|
{
|
|
// a_matN, v_matN
|
|
vtx << typeName << ";\n";
|
|
if (!m_isVertexCase)
|
|
{
|
|
vtx << "out " << precName << " " << typeName << " v_" << typeName << ";\n";
|
|
frag << "in " << precName << " " << typeName << " v_" << typeName << ";\n";
|
|
passVars.push_back(typeName);
|
|
}
|
|
|
|
inValue = string(m_isVertexCase ? "a_" : "v_") + getDataTypeName(in.dataType);
|
|
}
|
|
else
|
|
{
|
|
// a_coords, v_coords
|
|
vtx << "coords;\n";
|
|
if (!m_isVertexCase)
|
|
{
|
|
vtx << "out " << precName << " " << typeName << " v_coords;\n";
|
|
frag << "in " << precName << " " << typeName << " v_coords;\n";
|
|
passVars.push_back("coords");
|
|
}
|
|
|
|
inValue = m_isVertexCase ? "a_coords" : "v_coords";
|
|
}
|
|
}
|
|
else if (in.inputType == INPUTTYPE_UNIFORM)
|
|
{
|
|
op << "uniform " << precName << " " << typeName << " u_in" << inNdx << ";\n";
|
|
inValue = string("u_in") + de::toString(inNdx);
|
|
}
|
|
else if (in.inputType == INPUTTYPE_CONST)
|
|
{
|
|
op << "const " << precName << " " << typeName << " in" << inNdx << " = ";
|
|
|
|
// Generate declaration.
|
|
switch (in.dataType)
|
|
{
|
|
case TYPE_FLOAT: op << de::floatToString(s_constInFloat[inNdx], 1); break;
|
|
case TYPE_FLOAT_VEC2: writeVectorConstructor<2>(op, s_constInVec2[inNdx]); break;
|
|
case TYPE_FLOAT_VEC3: writeVectorConstructor<3>(op, s_constInVec3[inNdx]); break;
|
|
case TYPE_FLOAT_VEC4: writeVectorConstructor<4>(op, s_constInVec4[inNdx]); break;
|
|
case TYPE_FLOAT_MAT2: writeMatrixConstructor<2, 2>(op, Mat2(s_constInMat2x2[inNdx])); break;
|
|
case TYPE_FLOAT_MAT2X3: writeMatrixConstructor<2, 3>(op, Mat2x3(s_constInMat2x3[inNdx])); break;
|
|
case TYPE_FLOAT_MAT2X4: writeMatrixConstructor<2, 4>(op, Mat2x4(s_constInMat2x4[inNdx])); break;
|
|
case TYPE_FLOAT_MAT3X2: writeMatrixConstructor<3, 2>(op, Mat3x2(s_constInMat3x2[inNdx])); break;
|
|
case TYPE_FLOAT_MAT3: writeMatrixConstructor<3, 3>(op, Mat3(s_constInMat3x3[inNdx])); break;
|
|
case TYPE_FLOAT_MAT3X4: writeMatrixConstructor<3, 4>(op, Mat3x4(s_constInMat3x4[inNdx])); break;
|
|
case TYPE_FLOAT_MAT4X2: writeMatrixConstructor<4, 2>(op, Mat4x2(s_constInMat4x2[inNdx])); break;
|
|
case TYPE_FLOAT_MAT4X3: writeMatrixConstructor<4, 3>(op, Mat4x3(s_constInMat4x3[inNdx])); break;
|
|
case TYPE_FLOAT_MAT4: writeMatrixConstructor<4, 4>(op, Mat4(s_constInMat4x4[inNdx])); break;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
op << ";\n";
|
|
|
|
inValue = string("in") + de::toString(inNdx);
|
|
}
|
|
}
|
|
|
|
vtx << "\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n"
|
|
<< " gl_Position = a_position;\n";
|
|
frag << "\n"
|
|
<< "void main (void)\n"
|
|
<< "{\n";
|
|
|
|
if (m_isVertexCase)
|
|
frag << " dEQP_FragColor = v_color;\n";
|
|
else
|
|
{
|
|
for (vector<string>::const_iterator copyIter = passVars.begin(); copyIter != passVars.end(); copyIter++)
|
|
vtx << " v_" << *copyIter << " = " << "a_" << *copyIter << ";\n";
|
|
}
|
|
|
|
// Operation.
|
|
|
|
switch (getOperationNature(m_op))
|
|
{
|
|
case OPERATIONNATURE_PURE:
|
|
DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
|
|
|
|
operationValue0 = inValue0;
|
|
operationValue1 = inValue1;
|
|
break;
|
|
|
|
case OPERATIONNATURE_MUTATING:
|
|
DE_ASSERT(getOperationType(m_op) != OPERATIONTYPE_ASSIGNMENT);
|
|
|
|
op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " tmpValue = " << inValue0 << ";\n";
|
|
|
|
operationValue0 = "tmpValue";
|
|
operationValue1 = inValue1;
|
|
break;
|
|
|
|
case OPERATIONNATURE_ASSIGNMENT:
|
|
DE_ASSERT(getOperationType(m_op) == OPERATIONTYPE_ASSIGNMENT);
|
|
|
|
operationValue0 = inValue0;
|
|
operationValue1 = inValue1;
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
switch (getOperationType(m_op))
|
|
{
|
|
case OPERATIONTYPE_BINARY_OPERATOR:
|
|
op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << " " << getOperationName(m_op) << " " << operationValue1 << ";\n";
|
|
break;
|
|
|
|
case OPERATIONTYPE_UNARY_PREFIX_OPERATOR:
|
|
op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << operationValue0 << ";\n";
|
|
break;
|
|
|
|
case OPERATIONTYPE_UNARY_POSTFIX_OPERATOR:
|
|
op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << getOperationName(m_op) << ";\n";
|
|
break;
|
|
|
|
case OPERATIONTYPE_BINARY_FUNCTION:
|
|
op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ", " << operationValue1 << ");\n";
|
|
break;
|
|
|
|
case OPERATIONTYPE_UNARY_FUNCTION:
|
|
op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << getOperationName(m_op) << "(" << operationValue0 << ");\n";
|
|
break;
|
|
|
|
case OPERATIONTYPE_ASSIGNMENT:
|
|
op << " " << getPrecisionName(resultPrec) << " " << getDataTypeName(resultType) << " res = " << operationValue0 << ";\n";
|
|
op << " res " << getOperationName(m_op) << " " << operationValue1 << ";\n";
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
// Reduction to vec3 (rgb). Check the used value too if it was modified
|
|
op << " " << (m_isVertexCase ? "v_color" : "dEQP_FragColor") << " = ";
|
|
|
|
if (isOperationValueModifying(m_op))
|
|
op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0) + vec4(" << genGLSLMatToVec3Reduction(resultType, "tmpValue") << ", 0.0);\n";
|
|
else
|
|
op << "vec4(" << genGLSLMatToVec3Reduction(resultType, "res") << ", 1.0);\n";
|
|
|
|
vtx << "}\n";
|
|
frag << "}\n";
|
|
|
|
m_vertShaderSource = vtx.str();
|
|
m_fragShaderSource = frag.str();
|
|
|
|
// \todo [2012-02-14 pyry] Compute better values for matrix tests.
|
|
m_userAttribTransforms.resize(4);
|
|
for (int attribNdx = 0; attribNdx < 4; attribNdx++)
|
|
{
|
|
m_userAttribTransforms[attribNdx] = Mat4(0.0f);
|
|
m_userAttribTransforms[attribNdx]( 0, 3) = 0.1f + 0.15f * float(attribNdx); // !< prevent matrix*vec from going into zero (assuming vec.w != 0)
|
|
m_userAttribTransforms[attribNdx]( 1, 3) = 0.2f + 0.15f * float(attribNdx); // !<
|
|
m_userAttribTransforms[attribNdx]( 2, 3) = 0.3f + 0.15f * float(attribNdx); // !<
|
|
m_userAttribTransforms[attribNdx]( 3, 3) = 0.4f + 0.15f * float(attribNdx); // !<
|
|
m_userAttribTransforms[attribNdx]((0 + attribNdx) % 4, 0) = 1.0f;
|
|
m_userAttribTransforms[attribNdx]((1 + attribNdx) % 4, 1) = 1.0f;
|
|
m_userAttribTransforms[attribNdx]((2 + attribNdx) % 4, 2) = 1.0f;
|
|
m_userAttribTransforms[attribNdx]((3 + attribNdx) % 4, 3) = 1.0f;
|
|
}
|
|
|
|
// prevent bad reference cases such as black result images by fine-tuning used matrices
|
|
if (getOperationTestMatrixType(m_op) != TESTMATRIXTYPE_DEFAULT)
|
|
{
|
|
for (int attribNdx = 0; attribNdx < 4; attribNdx++)
|
|
{
|
|
for (int row = 0; row < 4; row++)
|
|
for (int col = 0; col < 4; col++)
|
|
{
|
|
switch (getOperationTestMatrixType(m_op))
|
|
{
|
|
case TESTMATRIXTYPE_NEGATED:
|
|
m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col);
|
|
break;
|
|
case TESTMATRIXTYPE_INCREMENTED:
|
|
m_userAttribTransforms[attribNdx](row, col) += 0.3f;
|
|
break;
|
|
case TESTMATRIXTYPE_DECREMENTED:
|
|
m_userAttribTransforms[attribNdx](row, col) -= 0.3f;
|
|
break;
|
|
case TESTMATRIXTYPE_NEGATED_INCREMENTED:
|
|
m_userAttribTransforms[attribNdx](row, col) = -m_userAttribTransforms[attribNdx](row, col) + 0.3f;
|
|
break;
|
|
case TESTMATRIXTYPE_INCREMENTED_LESS:
|
|
m_userAttribTransforms[attribNdx](row, col) -= 0.1f;
|
|
break;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ShaderRenderCase::init();
|
|
}
|
|
|
|
std::string ShaderMatrixCase::genGLSLMatToVec3Reduction (const glu::DataType& matType, const char* varName)
|
|
{
|
|
std::ostringstream op;
|
|
|
|
switch (matType)
|
|
{
|
|
case TYPE_FLOAT: op << varName << ", " << varName << ", " << varName << ""; break;
|
|
case TYPE_FLOAT_VEC2: op << varName << ".x, " << varName << ".y, " << varName << ".x"; break;
|
|
case TYPE_FLOAT_VEC3: op << varName << ""; break;
|
|
case TYPE_FLOAT_VEC4: op << varName << ".x, " << varName << ".y, " << varName << ".z+" << varName << ".w"; break;
|
|
case TYPE_FLOAT_MAT2: op << varName << "[0][0], " << varName << "[1][0], " << varName << "[0][1]+" << varName << "[1][1]"; break;
|
|
case TYPE_FLOAT_MAT2X3: op << varName << "[0] + " << varName << "[1]"; break;
|
|
case TYPE_FLOAT_MAT2X4: op << varName << "[0].xyz + " << varName << "[1].yzw"; break;
|
|
case TYPE_FLOAT_MAT3X2: op << varName << "[0][0]+" << varName << "[0][1], " << varName << "[1][0]+" << varName << "[1][1], " << varName << "[2][0]+" << varName << "[2][1]"; break;
|
|
case TYPE_FLOAT_MAT3: op << varName << "[0] + " << varName << "[1] + " << varName << "[2]"; break;
|
|
case TYPE_FLOAT_MAT3X4: op << varName << "[0].xyz + " << varName << "[1].yzw + " << varName << "[2].zwx"; break;
|
|
case TYPE_FLOAT_MAT4X2: op << varName << "[0][0]+" << varName << "[0][1]+" << varName << "[3][0], " << varName << "[1][0]+" << varName << "[1][1]+" << varName << "[3][1], " << varName << "[2][0]+" << varName << "[2][1]"; break;
|
|
case TYPE_FLOAT_MAT4X3: op << varName << "[0] + " << varName << "[1] + " << varName << "[2] + " << varName << "[3]"; break;
|
|
case TYPE_FLOAT_MAT4: op << varName << "[0].xyz+" << varName << "[1].yzw+" << varName << "[2].zwx+" << varName << "[3].wxy"; break;
|
|
|
|
default:
|
|
DE_ASSERT(DE_FALSE);
|
|
}
|
|
|
|
return op.str();
|
|
}
|
|
|
|
void ShaderMatrixCase::setupUniforms (int programID, const tcu::Vec4& constCoords)
|
|
{
|
|
const glw::Functions& gl = m_renderCtx.getFunctions();
|
|
|
|
DE_UNREF(constCoords);
|
|
|
|
for (int inNdx = 0; inNdx < 2; inNdx++)
|
|
{
|
|
const ShaderInput& in = inNdx > 0 ? m_in1 : m_in0;
|
|
|
|
if (in.inputType == INPUTTYPE_UNIFORM)
|
|
{
|
|
int loc = gl.getUniformLocation(programID, (string("u_in") + de::toString(inNdx)).c_str());
|
|
|
|
if (loc < 0)
|
|
continue;
|
|
|
|
switch (in.dataType)
|
|
{
|
|
case TYPE_FLOAT: gl.uniform1f(loc, s_constInFloat[inNdx]); break;
|
|
case TYPE_FLOAT_VEC2: gl.uniform2fv(loc, 1, s_constInVec2[inNdx].getPtr()); break;
|
|
case TYPE_FLOAT_VEC3: gl.uniform3fv(loc, 1, s_constInVec3[inNdx].getPtr()); break;
|
|
case TYPE_FLOAT_VEC4: gl.uniform4fv(loc, 1, s_constInVec4[inNdx].getPtr()); break;
|
|
// \note GLES3 supports transpose in matrix upload.
|
|
case TYPE_FLOAT_MAT2: gl.uniformMatrix2fv (loc, 1, GL_TRUE, s_constInMat2x2[inNdx]); break;
|
|
case TYPE_FLOAT_MAT2X3: gl.uniformMatrix2x3fv(loc, 1, GL_TRUE, s_constInMat2x3[inNdx]); break;
|
|
case TYPE_FLOAT_MAT2X4: gl.uniformMatrix2x4fv(loc, 1, GL_TRUE, s_constInMat2x4[inNdx]); break;
|
|
case TYPE_FLOAT_MAT3X2: gl.uniformMatrix3x2fv(loc, 1, GL_TRUE, s_constInMat3x2[inNdx]); break;
|
|
case TYPE_FLOAT_MAT3: gl.uniformMatrix3fv (loc, 1, GL_TRUE, s_constInMat3x3[inNdx]); break;
|
|
case TYPE_FLOAT_MAT3X4: gl.uniformMatrix3x4fv(loc, 1, GL_TRUE, s_constInMat3x4[inNdx]); break;
|
|
case TYPE_FLOAT_MAT4X2: gl.uniformMatrix4x2fv(loc, 1, GL_TRUE, s_constInMat4x2[inNdx]); break;
|
|
case TYPE_FLOAT_MAT4X3: gl.uniformMatrix4x3fv(loc, 1, GL_TRUE, s_constInMat4x3[inNdx]); break;
|
|
case TYPE_FLOAT_MAT4: gl.uniformMatrix4fv (loc, 1, GL_TRUE, s_constInMat4x4[inNdx]); break;
|
|
default:
|
|
DE_ASSERT(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ShaderMatrixTests::ShaderMatrixTests (Context& context)
|
|
: TestCaseGroup(context, "matrix", "Matrix Tests")
|
|
{
|
|
}
|
|
|
|
ShaderMatrixTests::~ShaderMatrixTests (void)
|
|
{
|
|
}
|
|
|
|
void ShaderMatrixTests::init (void)
|
|
{
|
|
static const struct
|
|
{
|
|
const char* name;
|
|
const char* desc;
|
|
MatrixOp op;
|
|
bool extendedInputTypeCases; // !< test with const and uniform types too
|
|
bool createInputTypeGroup; // !< create group for input types
|
|
} ops[] =
|
|
{
|
|
{ "add", "Matrix addition tests", OP_ADD, true, true },
|
|
{ "sub", "Matrix subtraction tests", OP_SUB, true, true },
|
|
{ "mul", "Matrix multiplication tests", OP_MUL, true, true },
|
|
{ "div", "Matrix division tests", OP_DIV, true, true },
|
|
{ "matrixcompmult", "Matrix component-wise multiplication tests", OP_COMP_MUL, false, true },
|
|
{ "outerproduct", "Matrix outerProduct() tests", OP_OUTER_PRODUCT, false, true },
|
|
{ "transpose", "Matrix transpose() tests", OP_TRANSPOSE, false, true },
|
|
{ "determinant", "Matrix determinant() tests", OP_DETERMINANT, false, true },
|
|
{ "inverse", "Matrix inverse() tests", OP_INVERSE, false, true },
|
|
{ "unary_addition", "Matrix unary addition tests", OP_UNARY_PLUS, false, false },
|
|
{ "negation", "Matrix negation tests", OP_NEGATION, false, false },
|
|
{ "pre_increment", "Matrix prefix increment tests", OP_PRE_INCREMENT, false, false },
|
|
{ "pre_decrement", "Matrix prefix decrement tests", OP_PRE_DECREMENT, false, false },
|
|
{ "post_increment", "Matrix postfix increment tests", OP_POST_INCREMENT, false, false },
|
|
{ "post_decrement", "Matrix postfix decrement tests", OP_POST_DECREMENT, false, false },
|
|
{ "add_assign", "Matrix add into tests", OP_ADD_INTO, false, false },
|
|
{ "sub_assign", "Matrix subtract from tests", OP_SUBTRACT_FROM, false, false },
|
|
{ "mul_assign", "Matrix multiply into tests", OP_MULTIPLY_INTO, false, false },
|
|
{ "div_assign", "Matrix divide into tests", OP_DIVIDE_INTO, false, false },
|
|
};
|
|
|
|
struct InputTypeSpec
|
|
{
|
|
const char* name;
|
|
const char* desc;
|
|
InputType type;
|
|
};
|
|
static const InputTypeSpec extendedInputTypes[] =
|
|
{
|
|
{ "const", "Constant matrix input", INPUTTYPE_CONST },
|
|
{ "uniform", "Uniform matrix input", INPUTTYPE_UNIFORM },
|
|
{ "dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC }
|
|
};
|
|
static const InputTypeSpec reducedInputTypes[] =
|
|
{
|
|
{ "dynamic", "Dynamic matrix input", INPUTTYPE_DYNAMIC }
|
|
};
|
|
|
|
static const DataType matrixTypes[] =
|
|
{
|
|
TYPE_FLOAT_MAT2,
|
|
TYPE_FLOAT_MAT2X3,
|
|
TYPE_FLOAT_MAT2X4,
|
|
TYPE_FLOAT_MAT3X2,
|
|
TYPE_FLOAT_MAT3,
|
|
TYPE_FLOAT_MAT3X4,
|
|
TYPE_FLOAT_MAT4X2,
|
|
TYPE_FLOAT_MAT4X3,
|
|
TYPE_FLOAT_MAT4
|
|
};
|
|
|
|
static const Precision precisions[] =
|
|
{
|
|
PRECISION_LOWP,
|
|
PRECISION_MEDIUMP,
|
|
PRECISION_HIGHP
|
|
};
|
|
|
|
for (int opNdx = 0; opNdx < DE_LENGTH_OF_ARRAY(ops); opNdx++)
|
|
{
|
|
const InputTypeSpec* inTypeList = (ops[opNdx].extendedInputTypeCases) ? (extendedInputTypes) : (reducedInputTypes);
|
|
const int inTypeListSize = (ops[opNdx].extendedInputTypeCases) ? (DE_LENGTH_OF_ARRAY(extendedInputTypes)) : (DE_LENGTH_OF_ARRAY(reducedInputTypes));
|
|
const MatrixOp op = ops[opNdx].op;
|
|
tcu::TestCaseGroup* opGroup = new tcu::TestCaseGroup(m_testCtx, ops[opNdx].name, ops[opNdx].desc);
|
|
|
|
addChild(opGroup);
|
|
|
|
for (int inTypeNdx = 0; inTypeNdx < inTypeListSize; inTypeNdx++)
|
|
{
|
|
const InputType inputType = inTypeList[inTypeNdx].type;
|
|
tcu::TestCaseGroup* inGroup;
|
|
|
|
if (ops[opNdx].createInputTypeGroup)
|
|
{
|
|
inGroup = new tcu::TestCaseGroup(m_testCtx, inTypeList[inTypeNdx].name, inTypeList[inTypeNdx].desc);
|
|
opGroup->addChild(inGroup);
|
|
}
|
|
else
|
|
inGroup = opGroup;
|
|
|
|
for (int matTypeNdx = 0; matTypeNdx < DE_LENGTH_OF_ARRAY(matrixTypes); matTypeNdx++)
|
|
{
|
|
DataType matType = matrixTypes[matTypeNdx];
|
|
int numCols = getDataTypeMatrixNumColumns(matType);
|
|
int numRows = getDataTypeMatrixNumRows(matType);
|
|
const char* matTypeName = getDataTypeName(matType);
|
|
|
|
for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++)
|
|
{
|
|
Precision precision = precisions[precNdx];
|
|
const char* precName = getPrecisionName(precision);
|
|
string baseName = string(precName) + "_" + matTypeName + "_";
|
|
ShaderInput matIn (inputType, matType, precision);
|
|
|
|
if (isOperationMatrixScalar(op))
|
|
{
|
|
// Matrix-scalar \note For div cases we use uniform input.
|
|
ShaderInput scalarIn(op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, TYPE_FLOAT, precision);
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(), "Matrix-scalar case", matIn, scalarIn, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(), "Matrix-scalar case", matIn, scalarIn, op, false));
|
|
}
|
|
|
|
if (isOperationMatrixVector(op))
|
|
{
|
|
// Matrix-vector.
|
|
DataType colVecType = getDataTypeFloatVec(numCols);
|
|
ShaderInput colVecIn (op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, colVecType, precision);
|
|
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(colVecType) + "_vertex").c_str(), "Matrix-vector case", matIn, colVecIn, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(colVecType) + "_fragment").c_str(), "Matrix-vector case", matIn, colVecIn, op, false));
|
|
|
|
// Vector-matrix.
|
|
DataType rowVecType = getDataTypeFloatVec(numRows);
|
|
ShaderInput rowVecIn (op == OP_DIV ? INPUTTYPE_UNIFORM : INPUTTYPE_DYNAMIC, rowVecType, precision);
|
|
string vecMatName = string(precName) + "_" + getDataTypeName(rowVecType) + "_" + matTypeName;
|
|
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_vertex").c_str(), "Vector-matrix case", rowVecIn, matIn, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (vecMatName + "_fragment").c_str(), "Vector-matrix case", rowVecIn, matIn, op, false));
|
|
}
|
|
|
|
if (isOperationArithmeticMatrixMatrix(op))
|
|
{
|
|
// Arithmetic matrix-matrix multiplication.
|
|
for (int otherCols = 2; otherCols <= 4; otherCols++)
|
|
{
|
|
ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, getDataTypeMatrix(otherCols, numCols /* rows */), precision);
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(otherMatIn.dataType) + "_vertex").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + getDataTypeName(otherMatIn.dataType) + "_fragment").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, false));
|
|
}
|
|
}
|
|
else if (isOperationComponentwiseMatrixMatrix(op))
|
|
{
|
|
// Component-wise.
|
|
ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_vertex").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + matTypeName + "_fragment").c_str(), "Matrix-matrix case", matIn, otherMatIn, op, false));
|
|
}
|
|
|
|
if (isOperationVectorVector(op))
|
|
{
|
|
ShaderInput vec1In(inputType, getDataTypeFloatVec(numRows), precision);
|
|
ShaderInput vec2In((inputType == INPUTTYPE_DYNAMIC) ? (INPUTTYPE_UNIFORM) : (inputType), getDataTypeFloatVec(numCols), precision);
|
|
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(), "Vector-vector case", vec1In, vec2In, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(), "Vector-vector case", vec1In, vec2In, op, false));
|
|
}
|
|
|
|
if ((isOperationUnaryAnyMatrix(op)) ||
|
|
(isOperationUnarySymmetricMatrix(op) && numCols == numRows))
|
|
{
|
|
ShaderInput voidInput(INPUTTYPE_LAST, TYPE_LAST, PRECISION_LAST);
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(), "Matrix case", matIn, voidInput, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(), "Matrix case", matIn, voidInput, op, false));
|
|
}
|
|
|
|
if ((isOperationAssignmentAnyMatrix(op)) ||
|
|
(isOperationAssignmentSymmetricMatrix(op) && numCols == numRows))
|
|
{
|
|
ShaderInput otherMatIn(inputType == INPUTTYPE_DYNAMIC ? INPUTTYPE_UNIFORM : inputType, matType, precision);
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_vertex").c_str(), "Matrix assignment case", matIn, otherMatIn, op, true));
|
|
inGroup->addChild(new ShaderMatrixCase(m_context, (baseName + "float_fragment").c_str(), "Matrix assignment case", matIn, otherMatIn, op, false));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // Functional
|
|
} // gles3
|
|
} // deqp
|
|
|
|
#if defined(_MSC_VER) && _MSC_FULL_VER == 191125507
|
|
// Work around crbug.com/759402 which is a code-gen bug in VC++ 2017, version
|
|
// 15.3.2.
|
|
#pragma optimize("", off)
|
|
#endif
|