1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES 3.1 Module
3 * -------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Integer built-in function tests.
22 *//*--------------------------------------------------------------------*/
24 #include "es31fShaderIntegerFunctionTests.hpp"
25 #include "glsShaderExecUtil.hpp"
26 #include "tcuTestLog.hpp"
27 #include "tcuFormatUtil.hpp"
28 #include "tcuFloat.hpp"
29 #include "deRandom.hpp"
44 using namespace gls::ShaderExecUtil;
61 HexFloat (const float value_) : value(value_) {}
64 std::ostream& operator<< (std::ostream& str, const HexFloat& v)
66 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
71 const glu::VarType& type;
74 VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
77 std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
79 DE_ASSERT(varValue.type.isBasicType());
81 const glu::DataType basicType = varValue.type.getBasicType();
82 const glu::DataType scalarType = glu::getDataTypeScalarType(basicType);
83 const int numComponents = glu::getDataTypeScalarSize(basicType);
85 if (numComponents > 1)
86 str << glu::getDataTypeName(basicType) << "(";
88 for (int compNdx = 0; compNdx < numComponents; compNdx++)
95 case glu::TYPE_FLOAT: str << HexFloat(((const float*)varValue.value)[compNdx]); break;
96 case glu::TYPE_INT: str << ((const deInt32*)varValue.value)[compNdx]; break;
97 case glu::TYPE_UINT: str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]); break;
98 case glu::TYPE_BOOL: str << (((const deUint32*)varValue.value)[compNdx] != 0 ? "true" : "false"); break;
105 if (numComponents > 1)
111 inline int getShaderUintBitCount (glu::ShaderType shaderType, glu::Precision precision)
113 // \todo [2013-10-31 pyry] Query from GL for vertex and fragment shaders.
114 DE_UNREF(shaderType);
115 const int bitCounts[] = { 9, 16, 32 };
116 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bitCounts) == glu::PRECISION_LAST);
117 return bitCounts[precision];
120 static inline deUint32 extendSignTo32 (deUint32 integer, deUint32 integerLength)
122 DE_ASSERT(integerLength > 0 && integerLength <= 32);
124 return deUint32(0 - deInt32((integer & (1 << (integerLength - 1))) << 1)) | integer;
127 static inline deUint32 getLowBitMask (int integerLength)
129 DE_ASSERT(integerLength >= 0 && integerLength <= 32);
131 // \note: shifting more or equal to 32 => undefined behavior. Avoid it by shifting in two parts (1 << (num-1) << 1)
132 if (integerLength == 0u)
134 return ((1u << ((deUint32)integerLength - 1u)) << 1u) - 1u;
137 static void generateRandomInputData (de::Random& rnd, glu::ShaderType shaderType, glu::DataType dataType, glu::Precision precision, deUint32* dst, int numValues)
139 const int scalarSize = glu::getDataTypeScalarSize(dataType);
140 const deUint32 integerLength = (deUint32)getShaderUintBitCount(shaderType, precision);
141 const deUint32 integerMask = getLowBitMask(integerLength);
142 const bool isUnsigned = glu::isDataTypeUintOrUVec(dataType);
146 for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
147 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
148 dst[valueNdx*scalarSize + compNdx] = rnd.getUint32() & integerMask;
152 for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
153 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
154 dst[valueNdx*scalarSize + compNdx] = extendSignTo32(rnd.getUint32() & integerMask, integerLength);
160 // IntegerFunctionCase
162 class IntegerFunctionCase : public TestCase
165 IntegerFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType);
166 ~IntegerFunctionCase (void);
170 IterateResult iterate (void);
173 IntegerFunctionCase (const IntegerFunctionCase& other);
174 IntegerFunctionCase& operator= (const IntegerFunctionCase& other);
176 virtual void getInputValues (int numValues, void* const* values) const = 0;
177 virtual bool compare (const void* const* inputs, const void* const* outputs) = 0;
179 glu::ShaderType m_shaderType;
183 std::ostringstream m_failMsg; //!< Comparison failure help message.
186 ShaderExecutor* m_executor;
189 IntegerFunctionCase::IntegerFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType)
190 : TestCase (context, name, description)
191 , m_shaderType (shaderType)
193 , m_executor (DE_NULL)
195 m_spec.version = glu::getContextTypeGLSLVersion(context.getRenderContext().getType());
198 IntegerFunctionCase::~IntegerFunctionCase (void)
200 IntegerFunctionCase::deinit();
203 void IntegerFunctionCase::init (void)
205 DE_ASSERT(!m_executor);
207 m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec);
208 m_testCtx.getLog() << m_executor;
210 if (!m_executor->isOk())
211 throw tcu::TestError("Compile failed");
214 void IntegerFunctionCase::deinit (void)
217 m_executor = DE_NULL;
220 static vector<int> getScalarSizes (const vector<Symbol>& symbols)
222 vector<int> sizes(symbols.size());
223 for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
224 sizes[ndx] = symbols[ndx].varType.getScalarSize();
228 static int computeTotalScalarSize (const vector<Symbol>& symbols)
231 for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
232 totalSize += sym->varType.getScalarSize();
236 static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
238 vector<void*> pointers (symbols.size());
239 int curScalarOffset = 0;
241 for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
243 const Symbol& var = symbols[varNdx];
244 const int scalarSize = var.varType.getScalarSize();
246 // Uses planar layout as input/output specs do not support strides.
247 pointers[varNdx] = &data[curScalarOffset];
248 curScalarOffset += scalarSize*numValues;
251 DE_ASSERT(curScalarOffset == (int)data.size());
256 IntegerFunctionCase::IterateResult IntegerFunctionCase::iterate (void)
258 const int numInputScalars = computeTotalScalarSize(m_spec.inputs);
259 const int numOutputScalars = computeTotalScalarSize(m_spec.outputs);
260 vector<deUint32> inputData (numInputScalars * m_numValues);
261 vector<deUint32> outputData (numOutputScalars * m_numValues);
262 const vector<void*> inputPointers = getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
263 const vector<void*> outputPointers = getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
265 // Initialize input data.
266 getInputValues(m_numValues, &inputPointers[0]);
269 m_executor->useProgram();
270 m_executor->execute(m_numValues, &inputPointers[0], &outputPointers[0]);
274 const vector<int> inScalarSizes = getScalarSizes(m_spec.inputs);
275 const vector<int> outScalarSizes = getScalarSizes(m_spec.outputs);
276 vector<void*> curInputPtr (inputPointers.size());
277 vector<void*> curOutputPtr (outputPointers.size());
280 for (int valNdx = 0; valNdx < m_numValues; valNdx++)
282 // Set up pointers for comparison.
283 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
284 curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
286 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
287 curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
289 if (!compare(&curInputPtr[0], &curOutputPtr[0]))
291 // \todo [2013-08-08 pyry] We probably want to log reference value as well?
293 m_testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n " << m_failMsg.str() << TestLog::EndMessage;
295 m_testCtx.getLog() << TestLog::Message << " inputs:" << TestLog::EndMessage;
296 for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
297 m_testCtx.getLog() << TestLog::Message << " " << m_spec.inputs[inNdx].name << " = "
298 << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
299 << TestLog::EndMessage;
301 m_testCtx.getLog() << TestLog::Message << " outputs:" << TestLog::EndMessage;
302 for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
303 m_testCtx.getLog() << TestLog::Message << " " << m_spec.outputs[outNdx].name << " = "
304 << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
305 << TestLog::EndMessage;
313 m_testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
315 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL,
316 numFailed == 0 ? "Pass" : "Result comparison failed");
322 static const char* getPrecisionPostfix (glu::Precision precision)
324 static const char* s_postfix[] =
330 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
331 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
332 return s_postfix[precision];
335 static const char* getShaderTypePostfix (glu::ShaderType shaderType)
337 static const char* s_postfix[] =
346 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
347 return s_postfix[shaderType];
350 static std::string getIntegerFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
352 return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
355 class UaddCarryCase : public IntegerFunctionCase
358 UaddCarryCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
359 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "uaddCarry", shaderType)
361 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
362 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
363 m_spec.outputs.push_back(Symbol("sum", glu::VarType(baseType, precision)));
364 m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
365 m_spec.source = "sum = uaddCarry(x, y, carry);";
368 void getInputValues (int numValues, void* const* values) const
370 de::Random rnd (deStringHash(getName()) ^ 0x235facu);
371 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
372 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
373 const int scalarSize = glu::getDataTypeScalarSize(type);
374 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
375 const deUint32 integerMask = getLowBitMask(integerLength);
376 const bool isSigned = glu::isDataTypeIntOrIVec(type);
377 deUint32* in0 = (deUint32*)values[0];
378 deUint32* in1 = (deUint32*)values[1];
386 { 0x00000000u, 0x00000000u },
387 { 0xfffffffeu, 0x00000001u },
388 { 0x00000001u, 0xfffffffeu },
389 { 0xffffffffu, 0x00000001u },
390 { 0x00000001u, 0xffffffffu },
391 { 0xfffffffeu, 0x00000002u },
392 { 0x00000002u, 0xfffffffeu },
393 { 0xffffffffu, 0xffffffffu }
396 // generate integers with proper bit count
397 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
399 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
401 in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
402 in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
409 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
411 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
413 in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
414 in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
419 generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
420 generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
423 bool compare (const void* const* inputs, const void* const* outputs)
425 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
426 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
427 const int scalarSize = glu::getDataTypeScalarSize(type);
428 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
429 const deUint32 mask0 = getLowBitMask(integerLength);
431 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
433 const deUint32 in0 = ((const deUint32*)inputs[0])[compNdx];
434 const deUint32 in1 = ((const deUint32*)inputs[1])[compNdx];
435 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx];
436 const deUint32 out1 = ((const deUint32*)outputs[1])[compNdx];
437 const deUint32 ref0 = in0+in1;
438 const deUint32 ref1 = (deUint64(in0)+deUint64(in1)) > 0xffffffffu ? 1u : 0u;
440 if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
442 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
451 class UsubBorrowCase : public IntegerFunctionCase
454 UsubBorrowCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
455 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "usubBorrow", shaderType)
457 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
458 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
459 m_spec.outputs.push_back(Symbol("diff", glu::VarType(baseType, precision)));
460 m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
461 m_spec.source = "diff = usubBorrow(x, y, carry);";
464 void getInputValues (int numValues, void* const* values) const
466 de::Random rnd (deStringHash(getName()) ^ 0x235facu);
467 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
468 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
469 const int scalarSize = glu::getDataTypeScalarSize(type);
470 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
471 const deUint32 integerMask = getLowBitMask(integerLength);
472 const bool isSigned = glu::isDataTypeIntOrIVec(type);
473 deUint32* in0 = (deUint32*)values[0];
474 deUint32* in1 = (deUint32*)values[1];
482 { 0x00000000u, 0x00000000u },
483 { 0x00000001u, 0x00000001u },
484 { 0x00000001u, 0x00000002u },
485 { 0x00000001u, 0xffffffffu },
486 { 0xfffffffeu, 0xffffffffu },
487 { 0xffffffffu, 0xffffffffu },
490 // generate integers with proper bit count
491 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
493 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
495 in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
496 in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
503 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
505 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
507 in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
508 in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
513 generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
514 generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
517 bool compare (const void* const* inputs, const void* const* outputs)
519 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
520 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
521 const int scalarSize = glu::getDataTypeScalarSize(type);
522 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
523 const deUint32 mask0 = getLowBitMask(integerLength);
525 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
527 const deUint32 in0 = ((const deUint32*)inputs[0])[compNdx];
528 const deUint32 in1 = ((const deUint32*)inputs[1])[compNdx];
529 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx];
530 const deUint32 out1 = ((const deUint32*)outputs[1])[compNdx];
531 const deUint32 ref0 = in0-in1;
532 const deUint32 ref1 = in0 >= in1 ? 0u : 1u;
534 if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
536 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
545 class UmulExtendedCase : public IntegerFunctionCase
548 UmulExtendedCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
549 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "umulExtended", shaderType)
551 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
552 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
553 m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
554 m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
555 m_spec.source = "umulExtended(x, y, msb, lsb);";
558 void getInputValues (int numValues, void* const* values) const
560 de::Random rnd (deStringHash(getName()) ^ 0x235facu);
561 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
562 // const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
563 const int scalarSize = glu::getDataTypeScalarSize(type);
564 deUint32* in0 = (deUint32*)values[0];
565 deUint32* in1 = (deUint32*)values[1];
574 { 0x00000000u, 0x00000000u },
575 { 0xffffffffu, 0x00000001u },
576 { 0xffffffffu, 0x00000002u },
577 { 0x00000001u, 0xffffffffu },
578 { 0x00000002u, 0xffffffffu },
579 { 0xffffffffu, 0xffffffffu },
582 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
584 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
586 in0[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x;
587 in1[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y;
593 while (valueNdx < numValues)
595 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
597 const deUint32 base0 = rnd.getUint32();
598 const deUint32 base1 = rnd.getUint32();
599 const int adj0 = rnd.getInt(0, 20);
600 const int adj1 = rnd.getInt(0, 20);
601 in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
602 in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
609 bool compare (const void* const* inputs, const void* const* outputs)
611 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
612 const int scalarSize = glu::getDataTypeScalarSize(type);
614 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
616 const deUint32 in0 = ((const deUint32*)inputs[0])[compNdx];
617 const deUint32 in1 = ((const deUint32*)inputs[1])[compNdx];
618 const deUint32 out0 = ((const deUint32*)outputs[0])[compNdx];
619 const deUint32 out1 = ((const deUint32*)outputs[1])[compNdx];
620 const deUint64 mul64 = deUint64(in0)*deUint64(in1);
621 const deUint32 ref0 = deUint32(mul64 >> 32);
622 const deUint32 ref1 = deUint32(mul64 & 0xffffffffu);
624 if (out0 != ref0 || out1 != ref1)
626 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
635 class ImulExtendedCase : public IntegerFunctionCase
638 ImulExtendedCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
639 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "imulExtended", shaderType)
641 m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
642 m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
643 m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
644 m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
645 m_spec.source = "imulExtended(x, y, msb, lsb);";
648 void getInputValues (int numValues, void* const* values) const
650 de::Random rnd (deStringHash(getName()) ^ 0x224fa1u);
651 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
652 // const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
653 const int scalarSize = glu::getDataTypeScalarSize(type);
654 deUint32* in0 = (deUint32*)values[0];
655 deUint32* in1 = (deUint32*)values[1];
664 { 0x00000000u, 0x00000000u },
665 { 0xffffffffu, 0x00000002u },
666 { 0x7fffffffu, 0x00000001u },
667 { 0x7fffffffu, 0x00000002u },
668 { 0x7fffffffu, 0x7fffffffu },
669 { 0xffffffffu, 0xffffffffu },
670 { 0x7fffffffu, 0xfffffffeu },
673 for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
675 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
677 in0[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].x;
678 in1[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].y;
684 while (valueNdx < numValues)
686 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
688 const deInt32 base0 = (deInt32)rnd.getUint32();
689 const deInt32 base1 = (deInt32)rnd.getUint32();
690 const int adj0 = rnd.getInt(0, 20);
691 const int adj1 = rnd.getInt(0, 20);
692 in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
693 in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
700 bool compare (const void* const* inputs, const void* const* outputs)
702 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
703 const int scalarSize = glu::getDataTypeScalarSize(type);
705 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
707 const deInt32 in0 = ((const deInt32*)inputs[0])[compNdx];
708 const deInt32 in1 = ((const deInt32*)inputs[1])[compNdx];
709 const deInt32 out0 = ((const deInt32*)outputs[0])[compNdx];
710 const deInt32 out1 = ((const deInt32*)outputs[1])[compNdx];
711 const deInt64 mul64 = deInt64(in0)*deInt64(in1);
712 const deInt32 ref0 = deInt32(mul64 >> 32);
713 const deInt32 ref1 = deInt32(mul64 & 0xffffffffu);
715 if (out0 != ref0 || out1 != ref1)
717 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
726 class BitfieldExtractCase : public IntegerFunctionCase
729 BitfieldExtractCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
730 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldExtract", shaderType)
732 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
733 m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
734 m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
735 m_spec.outputs.push_back(Symbol("extracted", glu::VarType(baseType, precision)));
736 m_spec.source = "extracted = bitfieldExtract(value, offset, bits);";
739 void getInputValues (int numValues, void* const* values) const
741 de::Random rnd (deStringHash(getName()) ^ 0xa113fca2u);
742 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
743 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
744 const bool ignoreSign = precision != glu::PRECISION_HIGHP && glu::isDataTypeIntOrIVec(type);
745 const int numBits = getShaderUintBitCount(m_shaderType, precision) - (ignoreSign ? 1 : 0);
746 deUint32* inValue = (deUint32*)values[0];
747 int* inOffset = (int*)values[1];
748 int* inBits = (int*)values[2];
750 for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
752 const int bits = rnd.getInt(0, numBits);
753 const int offset = rnd.getInt(0, numBits-bits);
755 inOffset[valueNdx] = offset;
756 inBits[valueNdx] = bits;
759 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
762 bool compare (const void* const* inputs, const void* const* outputs)
764 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
765 const bool isSigned = glu::isDataTypeIntOrIVec(type);
766 const int scalarSize = glu::getDataTypeScalarSize(type);
767 const int offset = *((const int*)inputs[1]);
768 const int bits = *((const int*)inputs[2]);
770 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
772 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
773 const deUint32 out = ((const deUint32*)outputs[0])[compNdx];
774 const deUint32 valMask = (bits == 32 ? ~0u : ((1u<<bits)-1u));
775 const deUint32 baseVal = (offset == 32) ? (0) : ((value >> offset) & valMask);
776 const deUint32 ref = baseVal | ((isSigned && (baseVal & (1<<(bits-1)))) ? ~valMask : 0u);
780 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
789 class BitfieldInsertCase : public IntegerFunctionCase
792 BitfieldInsertCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
793 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldInsert", shaderType)
795 m_spec.inputs.push_back(Symbol("base", glu::VarType(baseType, precision)));
796 m_spec.inputs.push_back(Symbol("insert", glu::VarType(baseType, precision)));
797 m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
798 m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
799 m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, precision)));
800 m_spec.source = "result = bitfieldInsert(base, insert, offset, bits);";
803 void getInputValues (int numValues, void* const* values) const
805 de::Random rnd (deStringHash(getName()) ^ 0x12c2acff);
806 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
807 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
808 const int numBits = getShaderUintBitCount(m_shaderType, precision);
809 deUint32* inBase = (deUint32*)values[0];
810 deUint32* inInsert = (deUint32*)values[1];
811 int* inOffset = (int*)values[2];
812 int* inBits = (int*)values[3];
814 for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
816 const int bits = rnd.getInt(0, numBits);
817 const int offset = rnd.getInt(0, numBits-bits);
819 inOffset[valueNdx] = offset;
820 inBits[valueNdx] = bits;
823 generateRandomInputData(rnd, m_shaderType, type, precision, inBase, numValues);
824 generateRandomInputData(rnd, m_shaderType, type, precision, inInsert, numValues);
827 bool compare (const void* const* inputs, const void* const* outputs)
829 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
830 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
831 const int scalarSize = glu::getDataTypeScalarSize(type);
832 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
833 const deUint32 cmpMask = getLowBitMask(integerLength);
834 const int offset = *((const int*)inputs[2]);
835 const int bits = *((const int*)inputs[3]);
837 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
839 const deUint32 base = ((const deUint32*)inputs[0])[compNdx];
840 const deUint32 insert = ((const deUint32*)inputs[1])[compNdx];
841 const deInt32 out = ((const deUint32*)outputs[0])[compNdx];
843 const deUint32 mask = bits == 32 ? ~0u : (1u<<bits)-1;
844 const deUint32 ref = (base & ~(mask<<offset)) | ((insert & mask)<<offset);
846 if ((out&cmpMask) != (ref&cmpMask))
848 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
857 static inline deUint32 reverseBits (deUint32 v)
859 v = (((v & 0xaaaaaaaa) >> 1) | ((v & 0x55555555) << 1));
860 v = (((v & 0xcccccccc) >> 2) | ((v & 0x33333333) << 2));
861 v = (((v & 0xf0f0f0f0) >> 4) | ((v & 0x0f0f0f0f) << 4));
862 v = (((v & 0xff00ff00) >> 8) | ((v & 0x00ff00ff) << 8));
863 return((v >> 16) | (v << 16));
866 class BitfieldReverseCase : public IntegerFunctionCase
869 BitfieldReverseCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
870 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldReverse", shaderType)
872 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
873 m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, glu::PRECISION_HIGHP)));
874 m_spec.source = "result = bitfieldReverse(value);";
877 void getInputValues (int numValues, void* const* values) const
879 de::Random rnd (deStringHash(getName()) ^ 0xff23a4);
880 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
881 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
882 deUint32* inValue = (deUint32*)values[0];
884 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
887 bool compare (const void* const* inputs, const void* const* outputs)
889 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
890 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
891 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
892 const int scalarSize = glu::getDataTypeScalarSize(type);
893 const deUint32 cmpMask = reverseBits(getLowBitMask(integerLength));
895 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
897 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
898 const deInt32 out = ((const deUint32*)outputs[0])[compNdx];
899 const deUint32 ref = reverseBits(value);
901 if ((out&cmpMask) != (ref&cmpMask))
903 m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
912 class BitCountCase : public IntegerFunctionCase
915 BitCountCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
916 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitCount", shaderType)
918 const int vecSize = glu::getDataTypeScalarSize(baseType);
919 const glu::DataType intType = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
921 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
922 m_spec.outputs.push_back(Symbol("count", glu::VarType(intType, glu::PRECISION_LOWP)));
923 m_spec.source = "count = bitCount(value);";
926 void getInputValues (int numValues, void* const* values) const
928 de::Random rnd (deStringHash(getName()) ^ 0xab2cca4);
929 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
930 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
931 deUint32* inValue = (deUint32*)values[0];
933 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
936 bool compare (const void* const* inputs, const void* const* outputs)
938 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
939 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
940 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
941 const int scalarSize = glu::getDataTypeScalarSize(type);
942 const deUint32 countMask = getLowBitMask(integerLength);
944 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
946 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
947 const int out = ((const int*)outputs[0])[compNdx];
948 const int minRef = dePop32(value&countMask);
949 const int maxRef = dePop32(value);
951 if (!de::inRange(out, minRef, maxRef))
953 m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
962 static int findLSB (deUint32 value)
964 for (int i = 0; i < 32; i++)
972 class FindLSBCase : public IntegerFunctionCase
975 FindLSBCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
976 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findLSB", shaderType)
978 const int vecSize = glu::getDataTypeScalarSize(baseType);
979 const glu::DataType intType = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
981 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
982 m_spec.outputs.push_back(Symbol("lsb", glu::VarType(intType, glu::PRECISION_LOWP)));
983 m_spec.source = "lsb = findLSB(value);";
986 void getInputValues (int numValues, void* const* values) const
988 de::Random rnd (deStringHash(getName()) ^ 0x9923c2af);
989 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
990 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
991 deUint32* inValue = (deUint32*)values[0];
993 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
996 bool compare (const void* const* inputs, const void* const* outputs)
998 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
999 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1000 const int scalarSize = glu::getDataTypeScalarSize(type);
1001 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
1002 const deUint32 mask = getLowBitMask(integerLength);
1004 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1006 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
1007 const int out = ((const int*)outputs[0])[compNdx];
1008 const int minRef = findLSB(value&mask);
1009 const int maxRef = findLSB(value);
1011 if (!de::inRange(out, minRef, maxRef))
1013 m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1022 static int findMSB (deInt32 value)
1025 return 31 - deClz32((deUint32)value);
1027 return 31 - deClz32(~(deUint32)value);
1032 static int findMSB (deUint32 value)
1035 return 31 - deClz32(value);
1040 static deUint32 toPrecision (deUint32 value, int numIntegerBits)
1042 return value & getLowBitMask(numIntegerBits);
1045 static deInt32 toPrecision (deInt32 value, int numIntegerBits)
1047 return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits);
1050 class FindMSBCase : public IntegerFunctionCase
1053 FindMSBCase (Context& context, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
1054 : IntegerFunctionCase(context, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findMSB", shaderType)
1056 const int vecSize = glu::getDataTypeScalarSize(baseType);
1057 const glu::DataType intType = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
1059 m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
1060 m_spec.outputs.push_back(Symbol("msb", glu::VarType(intType, glu::PRECISION_LOWP)));
1061 m_spec.source = "msb = findMSB(value);";
1064 void getInputValues (int numValues, void* const* values) const
1066 de::Random rnd (deStringHash(getName()) ^ 0x742ac4e);
1067 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1068 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1069 deUint32* inValue = (deUint32*)values[0];
1071 generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
1074 bool compare (const void* const* inputs, const void* const* outputs)
1076 const glu::DataType type = m_spec.inputs[0].varType.getBasicType();
1077 const glu::Precision precision = m_spec.inputs[0].varType.getPrecision();
1078 const bool isSigned = glu::isDataTypeIntOrIVec(type);
1079 const int scalarSize = glu::getDataTypeScalarSize(type);
1080 const int integerLength = getShaderUintBitCount(m_shaderType, precision);
1082 for (int compNdx = 0; compNdx < scalarSize; compNdx++)
1084 const deUint32 value = ((const deUint32*)inputs[0])[compNdx];
1085 const int out = ((const deInt32*)outputs[0])[compNdx];
1086 const int minRef = isSigned ? findMSB(toPrecision(deInt32(value), integerLength)) : findMSB(toPrecision(value, integerLength));
1087 const int maxRef = isSigned ? findMSB(deInt32(value)) : findMSB(value);
1089 if (!de::inRange(out, minRef, maxRef))
1091 m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
1100 ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (Context& context)
1101 : TestCaseGroup(context, "integer", "Integer function tests")
1105 ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
1109 template<class TestClass>
1110 static void addFunctionCases (TestCaseGroup* parent, const char* functionName, bool intTypes, bool uintTypes, bool allPrec, deUint32 shaderBits)
1112 tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
1113 parent->addChild(group);
1115 const glu::DataType scalarTypes[] =
1121 for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
1123 const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
1125 if ((!intTypes && scalarType == glu::TYPE_INT) || (!uintTypes && scalarType == glu::TYPE_UINT))
1128 for (int vecSize = 1; vecSize <= 4; vecSize++)
1130 for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
1132 if (prec != glu::PRECISION_HIGHP && !allPrec)
1135 for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
1137 if (shaderBits & (1<<shaderTypeNdx))
1138 group->addChild(new TestClass(parent->getContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
1145 void ShaderIntegerFunctionTests::init (void)
1149 VS = (1<<glu::SHADERTYPE_VERTEX),
1150 FS = (1<<glu::SHADERTYPE_FRAGMENT),
1151 CS = (1<<glu::SHADERTYPE_COMPUTE),
1152 GS = (1<<glu::SHADERTYPE_GEOMETRY),
1153 TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
1154 TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
1156 ALL_SHADERS = VS|TC|TE|GS|FS|CS
1159 // Int? Uint? AllPrec? Shaders
1160 addFunctionCases<UaddCarryCase> (this, "uaddcarry", false, true, true, ALL_SHADERS);
1161 addFunctionCases<UsubBorrowCase> (this, "usubborrow", false, true, true, ALL_SHADERS);
1162 addFunctionCases<UmulExtendedCase> (this, "umulextended", false, true, false, ALL_SHADERS);
1163 addFunctionCases<ImulExtendedCase> (this, "imulextended", true, false, false, ALL_SHADERS);
1164 addFunctionCases<BitfieldExtractCase> (this, "bitfieldextract", true, true, true, ALL_SHADERS);
1165 addFunctionCases<BitfieldInsertCase> (this, "bitfieldinsert", true, true, true, ALL_SHADERS);
1166 addFunctionCases<BitfieldReverseCase> (this, "bitfieldreverse", true, true, true, ALL_SHADERS);
1167 addFunctionCases<BitCountCase> (this, "bitcount", true, true, true, ALL_SHADERS);
1168 addFunctionCases<FindLSBCase> (this, "findlsb", true, true, true, ALL_SHADERS);
1169 addFunctionCases<FindMSBCase> (this, "findmsb", true, true, true, ALL_SHADERS);