1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.1 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Floating-point packing and unpacking function tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es31fShaderPackingFunctionTests.hpp" 25#include "glsShaderExecUtil.hpp" 26#include "tcuTestLog.hpp" 27#include "tcuFormatUtil.hpp" 28#include "tcuFloat.hpp" 29#include "deRandom.hpp" 30#include "deMath.h" 31#include "deString.h" 32 33namespace deqp 34{ 35namespace gles31 36{ 37namespace Functional 38{ 39 40using std::string; 41using tcu::TestLog; 42using namespace gls::ShaderExecUtil; 43 44namespace 45{ 46 47inline deUint32 getUlpDiff (float a, float b) 48{ 49 const deUint32 aBits = tcu::Float32(a).bits(); 50 const deUint32 bBits = tcu::Float32(b).bits(); 51 return aBits > bBits ? aBits - bBits : bBits - aBits; 52} 53 54struct HexFloat 55{ 56 const float value; 57 HexFloat (const float value_) : value(value_) {} 58}; 59 60std::ostream& operator<< (std::ostream& str, const HexFloat& v) 61{ 62 return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits()); 63} 64 65} // anonymous 66 67// ShaderPackingFunctionCase 68 69class ShaderPackingFunctionCase : public TestCase 70{ 71public: 72 ShaderPackingFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType); 73 ~ShaderPackingFunctionCase (void); 74 75 void init (void); 76 void deinit (void); 77 78protected: 79 glu::ShaderType m_shaderType; 80 ShaderSpec m_spec; 81 ShaderExecutor* m_executor; 82 83private: 84 ShaderPackingFunctionCase (const ShaderPackingFunctionCase& other); 85 ShaderPackingFunctionCase& operator= (const ShaderPackingFunctionCase& other); 86}; 87 88ShaderPackingFunctionCase::ShaderPackingFunctionCase (Context& context, const char* name, const char* description, glu::ShaderType shaderType) 89 : TestCase (context, name, description) 90 , m_shaderType (shaderType) 91 , m_executor (DE_NULL) 92{ 93 m_spec.version = glu::getContextTypeGLSLVersion(context.getRenderContext().getType()); 94} 95 96ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void) 97{ 98 ShaderPackingFunctionCase::deinit(); 99} 100 101void ShaderPackingFunctionCase::init (void) 102{ 103 DE_ASSERT(!m_executor); 104 105 m_executor = createExecutor(m_context.getRenderContext(), m_shaderType, m_spec); 106 m_testCtx.getLog() << m_executor; 107 108 if (!m_executor->isOk()) 109 throw tcu::TestError("Compile failed"); 110} 111 112void ShaderPackingFunctionCase::deinit (void) 113{ 114 delete m_executor; 115 m_executor = DE_NULL; 116} 117 118// Test cases 119 120static const char* getPrecisionPostfix (glu::Precision precision) 121{ 122 static const char* s_postfix[] = 123 { 124 "_lowp", 125 "_mediump", 126 "_highp" 127 }; 128 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST); 129 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix))); 130 return s_postfix[precision]; 131} 132 133static const char* getShaderTypePostfix (glu::ShaderType shaderType) 134{ 135 static const char* s_postfix[] = 136 { 137 "_vertex", 138 "_fragment", 139 "_geometry", 140 "_tess_control", 141 "_tess_eval", 142 "_compute" 143 }; 144 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix))); 145 return s_postfix[shaderType]; 146} 147 148class PackSnorm2x16Case : public ShaderPackingFunctionCase 149{ 150public: 151 PackSnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision) 152 : ShaderPackingFunctionCase (context, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType) 153 , m_precision (precision) 154 { 155 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision))); 156 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 157 158 m_spec.source = "out0 = packSnorm2x16(in0);"; 159 } 160 161 IterateResult iterate (void) 162 { 163 de::Random rnd (deStringHash(getName()) ^ 0x776002); 164 std::vector<tcu::Vec2> inputs; 165 std::vector<deUint32> outputs; 166 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only. 167 m_precision == glu::PRECISION_MEDIUMP ? 33 : // (2^-10) * (2^15) + 1 168 m_precision == glu::PRECISION_LOWP ? 129 : 0; // (2^-8) * (2^15) + 1 169 170 // Special values to check. 171 inputs.push_back(tcu::Vec2(0.0f, 0.0f)); 172 inputs.push_back(tcu::Vec2(-1.0f, 1.0f)); 173 inputs.push_back(tcu::Vec2(0.5f, -0.5f)); 174 inputs.push_back(tcu::Vec2(-1.5f, 1.5f)); 175 inputs.push_back(tcu::Vec2(0.25f, -0.75f)); 176 177 // Random values, mostly in range. 178 for (int ndx = 0; ndx < 15; ndx++) 179 { 180 const float x = rnd.getFloat()*2.5f - 1.25f; 181 const float y = rnd.getFloat()*2.5f - 1.25f; 182 inputs.push_back(tcu::Vec2(x, y)); 183 } 184 185 // Large random values. 186 for (int ndx = 0; ndx < 80; ndx++) 187 { 188 const float x = rnd.getFloat()*1e6f - 0.5e6f; 189 const float y = rnd.getFloat()*1e6f - 0.5e6f; 190 inputs.push_back(tcu::Vec2(x, y)); 191 } 192 193 outputs.resize(inputs.size()); 194 195 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 196 197 { 198 const void* in = &inputs[0]; 199 void* out = &outputs[0]; 200 201 m_executor->useProgram(); 202 m_executor->execute((int)inputs.size(), &in, &out); 203 } 204 205 // Verify 206 { 207 const int numValues = (int)inputs.size(); 208 const int maxPrints = 10; 209 int numFailed = 0; 210 211 for (int valNdx = 0; valNdx < numValues; valNdx++) 212 { 213 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1); 214 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1); 215 const deUint32 ref = (ref1 << 16) | ref0; 216 const deUint32 res = outputs[valNdx]; 217 const deUint16 res0 = (deUint16)(res & 0xffff); 218 const deUint16 res1 = (deUint16)(res >> 16); 219 const int diff0 = de::abs((int)ref0 - (int)res0); 220 const int diff1 = de::abs((int)ref1 - (int)res1); 221 222 if (diff0 > maxDiff || diff1 > maxDiff) 223 { 224 if (numFailed < maxPrints) 225 { 226 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 227 << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 228 << ", got " << tcu::toHex(res) 229 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 230 << TestLog::EndMessage; 231 } 232 else if (numFailed == maxPrints) 233 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 234 235 numFailed += 1; 236 } 237 } 238 239 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 240 241 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 242 numFailed == 0 ? "Pass" : "Result comparison failed"); 243 } 244 245 return STOP; 246 } 247 248private: 249 glu::Precision m_precision; 250}; 251 252class UnpackSnorm2x16Case : public ShaderPackingFunctionCase 253{ 254public: 255 UnpackSnorm2x16Case (Context& context, glu::ShaderType shaderType) 256 : ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType) 257 { 258 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 259 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP))); 260 261 m_spec.source = "out0 = unpackSnorm2x16(in0);"; 262 } 263 264 IterateResult iterate (void) 265 { 266 const deUint32 maxDiff = 1; // Rounding error. 267 de::Random rnd (deStringHash(getName()) ^ 0x776002); 268 std::vector<deUint32> inputs; 269 std::vector<tcu::Vec2> outputs; 270 271 inputs.push_back(0x00000000u); 272 inputs.push_back(0x7fff8000u); 273 inputs.push_back(0x80007fffu); 274 inputs.push_back(0xffffffffu); 275 inputs.push_back(0x0001fffeu); 276 277 // Random values. 278 for (int ndx = 0; ndx < 95; ndx++) 279 inputs.push_back(rnd.getUint32()); 280 281 outputs.resize(inputs.size()); 282 283 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 284 285 { 286 const void* in = &inputs[0]; 287 void* out = &outputs[0]; 288 289 m_executor->useProgram(); 290 m_executor->execute((int)inputs.size(), &in, &out); 291 } 292 293 // Verify 294 { 295 const int numValues = (int)inputs.size(); 296 const int maxPrints = 10; 297 int numFailed = 0; 298 299 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 300 { 301 const deInt16 in0 = (deInt16)(deUint16)(inputs[valNdx] & 0xffff); 302 const deInt16 in1 = (deInt16)(deUint16)(inputs[valNdx] >> 16); 303 const float ref0 = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f); 304 const float ref1 = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f); 305 const float res0 = outputs[valNdx].x(); 306 const float res1 = outputs[valNdx].y(); 307 308 const deUint32 diff0 = getUlpDiff(ref0, res0); 309 const deUint32 diff1 = getUlpDiff(ref1, res1); 310 311 if (diff0 > maxDiff || diff1 > maxDiff) 312 { 313 if (numFailed < maxPrints) 314 { 315 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 316 << " expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = " 317 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")" 318 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")" 319 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 320 << TestLog::EndMessage; 321 } 322 else if (numFailed == maxPrints) 323 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 324 325 numFailed += 1; 326 } 327 } 328 329 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 330 331 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 332 numFailed == 0 ? "Pass" : "Result comparison failed"); 333 } 334 335 return STOP; 336 } 337}; 338 339class PackUnorm2x16Case : public ShaderPackingFunctionCase 340{ 341public: 342 PackUnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision) 343 : ShaderPackingFunctionCase (context, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType) 344 , m_precision (precision) 345 { 346 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision))); 347 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 348 349 m_spec.source = "out0 = packUnorm2x16(in0);"; 350 } 351 352 IterateResult iterate (void) 353 { 354 de::Random rnd (deStringHash(getName()) ^ 0x776002); 355 std::vector<tcu::Vec2> inputs; 356 std::vector<deUint32> outputs; 357 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only. 358 m_precision == glu::PRECISION_MEDIUMP ? 65 : // (2^-10) * (2^16) + 1 359 m_precision == glu::PRECISION_LOWP ? 257 : 0; // (2^-8) * (2^16) + 1 360 361 // Special values to check. 362 inputs.push_back(tcu::Vec2(0.0f, 0.0f)); 363 inputs.push_back(tcu::Vec2(0.5f, 1.0f)); 364 inputs.push_back(tcu::Vec2(1.0f, 0.5f)); 365 inputs.push_back(tcu::Vec2(-0.5f, 1.5f)); 366 inputs.push_back(tcu::Vec2(0.25f, 0.75f)); 367 368 // Random values, mostly in range. 369 for (int ndx = 0; ndx < 15; ndx++) 370 { 371 const float x = rnd.getFloat()*1.25f; 372 const float y = rnd.getFloat()*1.25f; 373 inputs.push_back(tcu::Vec2(x, y)); 374 } 375 376 // Large random values. 377 for (int ndx = 0; ndx < 80; ndx++) 378 { 379 const float x = rnd.getFloat()*1e6f - 1e5f; 380 const float y = rnd.getFloat()*1e6f - 1e5f; 381 inputs.push_back(tcu::Vec2(x, y)); 382 } 383 384 outputs.resize(inputs.size()); 385 386 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 387 388 { 389 const void* in = &inputs[0]; 390 void* out = &outputs[0]; 391 392 m_executor->useProgram(); 393 m_executor->execute((int)inputs.size(), &in, &out); 394 } 395 396 // Verify 397 { 398 const int numValues = (int)inputs.size(); 399 const int maxPrints = 10; 400 int numFailed = 0; 401 402 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 403 { 404 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1); 405 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1); 406 const deUint32 ref = (ref1 << 16) | ref0; 407 const deUint32 res = outputs[valNdx]; 408 const deUint16 res0 = (deUint16)(res & 0xffff); 409 const deUint16 res1 = (deUint16)(res >> 16); 410 const int diff0 = de::abs((int)ref0 - (int)res0); 411 const int diff1 = de::abs((int)ref1 - (int)res1); 412 413 if (diff0 > maxDiff || diff1 > maxDiff) 414 { 415 if (numFailed < maxPrints) 416 { 417 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 418 << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 419 << ", got " << tcu::toHex(res) 420 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 421 << TestLog::EndMessage; 422 } 423 else if (numFailed == maxPrints) 424 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 425 426 numFailed += 1; 427 } 428 } 429 430 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 431 432 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 433 numFailed == 0 ? "Pass" : "Result comparison failed"); 434 } 435 436 return STOP; 437 } 438 439private: 440 glu::Precision m_precision; 441}; 442 443class UnpackUnorm2x16Case : public ShaderPackingFunctionCase 444{ 445public: 446 UnpackUnorm2x16Case (Context& context, glu::ShaderType shaderType) 447 : ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType) 448 { 449 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 450 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP))); 451 452 m_spec.source = "out0 = unpackUnorm2x16(in0);"; 453 } 454 455 IterateResult iterate (void) 456 { 457 const deUint32 maxDiff = 1; // Rounding error. 458 de::Random rnd (deStringHash(getName()) ^ 0x776002); 459 std::vector<deUint32> inputs; 460 std::vector<tcu::Vec2> outputs; 461 462 inputs.push_back(0x00000000u); 463 inputs.push_back(0x7fff8000u); 464 inputs.push_back(0x80007fffu); 465 inputs.push_back(0xffffffffu); 466 inputs.push_back(0x0001fffeu); 467 468 // Random values. 469 for (int ndx = 0; ndx < 95; ndx++) 470 inputs.push_back(rnd.getUint32()); 471 472 outputs.resize(inputs.size()); 473 474 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 475 476 { 477 const void* in = &inputs[0]; 478 void* out = &outputs[0]; 479 480 m_executor->useProgram(); 481 m_executor->execute((int)inputs.size(), &in, &out); 482 } 483 484 // Verify 485 { 486 const int numValues = (int)inputs.size(); 487 const int maxPrints = 10; 488 int numFailed = 0; 489 490 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 491 { 492 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff); 493 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16); 494 const float ref0 = float(in0) / 65535.0f; 495 const float ref1 = float(in1) / 65535.0f; 496 const float res0 = outputs[valNdx].x(); 497 const float res1 = outputs[valNdx].y(); 498 499 const deUint32 diff0 = getUlpDiff(ref0, res0); 500 const deUint32 diff1 = getUlpDiff(ref1, res1); 501 502 if (diff0 > maxDiff || diff1 > maxDiff) 503 { 504 if (numFailed < maxPrints) 505 { 506 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 507 << " expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = " 508 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")" 509 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")" 510 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 511 << TestLog::EndMessage; 512 } 513 else if (numFailed == maxPrints) 514 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 515 516 numFailed += 1; 517 } 518 } 519 520 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 521 522 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 523 numFailed == 0 ? "Pass" : "Result comparison failed"); 524 } 525 526 return STOP; 527 } 528}; 529 530class PackHalf2x16Case : public ShaderPackingFunctionCase 531{ 532public: 533 PackHalf2x16Case (Context& context, glu::ShaderType shaderType) 534 : ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType) 535 { 536 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP))); 537 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 538 539 m_spec.source = "out0 = packHalf2x16(in0);"; 540 } 541 542 IterateResult iterate (void) 543 { 544 const int maxDiff = 0; // Values can be represented exactly in mediump. 545 de::Random rnd (deStringHash(getName()) ^ 0x776002); 546 std::vector<tcu::Vec2> inputs; 547 std::vector<deUint32> outputs; 548 549 // Special values to check. 550 inputs.push_back(tcu::Vec2(0.0f, 0.0f)); 551 inputs.push_back(tcu::Vec2(0.5f, 1.0f)); 552 inputs.push_back(tcu::Vec2(1.0f, 0.5f)); 553 inputs.push_back(tcu::Vec2(-0.5f, 1.5f)); 554 inputs.push_back(tcu::Vec2(0.25f, 0.75f)); 555 556 // Random values. 557 { 558 const int minExp = -14; 559 const int maxExp = 15; 560 561 for (int ndx = 0; ndx < 95; ndx++) 562 { 563 tcu::Vec2 v; 564 for (int c = 0; c < 2; c++) 565 { 566 const int s = rnd.getBool() ? 1 : -1; 567 const int exp = rnd.getInt(minExp, maxExp); 568 const deUint32 mantissa = rnd.getUint32() & ((1<<23)-1); 569 570 v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat(); 571 } 572 inputs.push_back(v); 573 } 574 } 575 576 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump. 577 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal) 578 *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat()); 579 580 outputs.resize(inputs.size()); 581 582 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 583 584 { 585 const void* in = &inputs[0]; 586 void* out = &outputs[0]; 587 588 m_executor->useProgram(); 589 m_executor->execute((int)inputs.size(), &in, &out); 590 } 591 592 // Verify 593 { 594 const int numValues = (int)inputs.size(); 595 const int maxPrints = 10; 596 int numFailed = 0; 597 598 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 599 { 600 const deUint16 ref0 = (deUint16)tcu::Float16(inputs[valNdx].x()).bits(); 601 const deUint16 ref1 = (deUint16)tcu::Float16(inputs[valNdx].y()).bits(); 602 const deUint32 ref = (ref1 << 16) | ref0; 603 const deUint32 res = outputs[valNdx]; 604 const deUint16 res0 = (deUint16)(res & 0xffff); 605 const deUint16 res1 = (deUint16)(res >> 16); 606 const int diff0 = de::abs((int)ref0 - (int)res0); 607 const int diff1 = de::abs((int)ref1 - (int)res1); 608 609 if (diff0 > maxDiff || diff1 > maxDiff) 610 { 611 if (numFailed < maxPrints) 612 { 613 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 614 << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 615 << ", got " << tcu::toHex(res) 616 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 617 << TestLog::EndMessage; 618 } 619 else if (numFailed == maxPrints) 620 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 621 622 numFailed += 1; 623 } 624 } 625 626 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 627 628 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 629 numFailed == 0 ? "Pass" : "Result comparison failed"); 630 } 631 632 return STOP; 633 } 634}; 635 636class UnpackHalf2x16Case : public ShaderPackingFunctionCase 637{ 638public: 639 UnpackHalf2x16Case (Context& context, glu::ShaderType shaderType) 640 : ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType) 641 { 642 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 643 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP))); 644 645 m_spec.source = "out0 = unpackHalf2x16(in0);"; 646 } 647 648 IterateResult iterate (void) 649 { 650 const int maxDiff = 0; // All bits must be accurate. 651 de::Random rnd (deStringHash(getName()) ^ 0x776002); 652 std::vector<deUint32> inputs; 653 std::vector<tcu::Vec2> outputs; 654 655 // Special values. 656 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits()); 657 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits()); 658 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits()); 659 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits()); 660 661 // Construct random values. 662 { 663 const int minExp = -14; 664 const int maxExp = 15; 665 const int mantBits = 10; 666 667 for (int ndx = 0; ndx < 96; ndx++) 668 { 669 deUint32 inVal = 0; 670 for (int c = 0; c < 2; c++) 671 { 672 const int s = rnd.getBool() ? 1 : -1; 673 const int exp = rnd.getInt(minExp, maxExp); 674 const deUint32 mantissa = rnd.getUint32() & ((1<<mantBits)-1); 675 const deUint16 value = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits(); 676 677 inVal |= value << (16*c); 678 } 679 inputs.push_back(inVal); 680 } 681 } 682 683 outputs.resize(inputs.size()); 684 685 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 686 687 { 688 const void* in = &inputs[0]; 689 void* out = &outputs[0]; 690 691 m_executor->useProgram(); 692 m_executor->execute((int)inputs.size(), &in, &out); 693 } 694 695 // Verify 696 { 697 const int numValues = (int)inputs.size(); 698 const int maxPrints = 10; 699 int numFailed = 0; 700 701 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 702 { 703 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff); 704 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16); 705 const float ref0 = tcu::Float16(in0).asFloat(); 706 const float ref1 = tcu::Float16(in1).asFloat(); 707 const float res0 = outputs[valNdx].x(); 708 const float res1 = outputs[valNdx].y(); 709 710 const deUint32 refBits0 = tcu::Float32(ref0).bits(); 711 const deUint32 refBits1 = tcu::Float32(ref1).bits(); 712 const deUint32 resBits0 = tcu::Float32(res0).bits(); 713 const deUint32 resBits1 = tcu::Float32(res1).bits(); 714 715 const int diff0 = de::abs((int)refBits0 - (int)resBits0); 716 const int diff1 = de::abs((int)refBits1 - (int)resBits1); 717 718 if (diff0 > maxDiff || diff1 > maxDiff) 719 { 720 if (numFailed < maxPrints) 721 { 722 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 723 << " expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = " 724 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")" 725 << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")" 726 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 727 << TestLog::EndMessage; 728 } 729 else if (numFailed == maxPrints) 730 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 731 732 numFailed += 1; 733 } 734 } 735 736 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 737 738 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 739 numFailed == 0 ? "Pass" : "Result comparison failed"); 740 } 741 742 return STOP; 743 } 744}; 745 746class PackSnorm4x8Case : public ShaderPackingFunctionCase 747{ 748public: 749 PackSnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision) 750 : ShaderPackingFunctionCase (context, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType) 751 , m_precision (precision) 752 { 753 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision))); 754 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 755 756 m_spec.source = "out0 = packSnorm4x8(in0);"; 757 } 758 759 IterateResult iterate (void) 760 { 761 de::Random rnd (deStringHash(getName()) ^ 0x42f2c0); 762 std::vector<tcu::Vec4> inputs; 763 std::vector<deUint32> outputs; 764 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only. 765 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^7) + 1 766 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^7) + 1 767 768 // Special values to check. 769 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f)); 770 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f)); 771 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f)); 772 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f)); 773 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f)); 774 775 // Random values, mostly in range. 776 for (int ndx = 0; ndx < 15; ndx++) 777 { 778 const float x = rnd.getFloat()*2.5f - 1.25f; 779 const float y = rnd.getFloat()*2.5f - 1.25f; 780 const float z = rnd.getFloat()*2.5f - 1.25f; 781 const float w = rnd.getFloat()*2.5f - 1.25f; 782 inputs.push_back(tcu::Vec4(x, y, z, w)); 783 } 784 785 // Large random values. 786 for (int ndx = 0; ndx < 80; ndx++) 787 { 788 const float x = rnd.getFloat()*1e6f - 0.5e6f; 789 const float y = rnd.getFloat()*1e6f - 0.5e6f; 790 const float z = rnd.getFloat()*1e6f - 0.5e6f; 791 const float w = rnd.getFloat()*1e6f - 0.5e6f; 792 inputs.push_back(tcu::Vec4(x, y, z, w)); 793 } 794 795 outputs.resize(inputs.size()); 796 797 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 798 799 { 800 const void* in = &inputs[0]; 801 void* out = &outputs[0]; 802 803 m_executor->useProgram(); 804 m_executor->execute((int)inputs.size(), &in, &out); 805 } 806 807 // Verify 808 { 809 const int numValues = (int)inputs.size(); 810 const int maxPrints = 10; 811 int numFailed = 0; 812 813 for (int valNdx = 0; valNdx < numValues; valNdx++) 814 { 815 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1); 816 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1); 817 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1); 818 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1); 819 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0); 820 const deUint32 res = outputs[valNdx]; 821 const deUint16 res0 = (deUint8)(res & 0xff); 822 const deUint16 res1 = (deUint8)((res >> 8) & 0xff); 823 const deUint16 res2 = (deUint8)((res >> 16) & 0xff); 824 const deUint16 res3 = (deUint8)((res >> 24) & 0xff); 825 const int diff0 = de::abs((int)ref0 - (int)res0); 826 const int diff1 = de::abs((int)ref1 - (int)res1); 827 const int diff2 = de::abs((int)ref2 - (int)res2); 828 const int diff3 = de::abs((int)ref3 - (int)res3); 829 830 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff) 831 { 832 if (numFailed < maxPrints) 833 { 834 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 835 << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 836 << ", got " << tcu::toHex(res) 837 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff 838 << TestLog::EndMessage; 839 } 840 else if (numFailed == maxPrints) 841 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 842 843 numFailed += 1; 844 } 845 } 846 847 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 848 849 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 850 numFailed == 0 ? "Pass" : "Result comparison failed"); 851 } 852 853 return STOP; 854 } 855 856private: 857 glu::Precision m_precision; 858}; 859 860class UnpackSnorm4x8Case : public ShaderPackingFunctionCase 861{ 862public: 863 UnpackSnorm4x8Case (Context& context, glu::ShaderType shaderType) 864 : ShaderPackingFunctionCase(context, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType) 865 { 866 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 867 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 868 869 m_spec.source = "out0 = unpackSnorm4x8(in0);"; 870 } 871 872 IterateResult iterate (void) 873 { 874 const deUint32 maxDiff = 1; // Rounding error. 875 de::Random rnd (deStringHash(getName()) ^ 0x776002); 876 std::vector<deUint32> inputs; 877 std::vector<tcu::Vec4> outputs; 878 879 inputs.push_back(0x00000000u); 880 inputs.push_back(0x7fff8000u); 881 inputs.push_back(0x80007fffu); 882 inputs.push_back(0xffffffffu); 883 inputs.push_back(0x0001fffeu); 884 885 // Random values. 886 for (int ndx = 0; ndx < 95; ndx++) 887 inputs.push_back(rnd.getUint32()); 888 889 outputs.resize(inputs.size()); 890 891 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 892 893 { 894 const void* in = &inputs[0]; 895 void* out = &outputs[0]; 896 897 m_executor->useProgram(); 898 m_executor->execute((int)inputs.size(), &in, &out); 899 } 900 901 // Verify 902 { 903 const int numValues = (int)inputs.size(); 904 const int maxPrints = 10; 905 int numFailed = 0; 906 907 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 908 { 909 const deInt8 in0 = (deInt8)(deUint8)(inputs[valNdx] & 0xff); 910 const deInt8 in1 = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff); 911 const deInt8 in2 = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff); 912 const deInt8 in3 = (deInt8)(deUint8)(inputs[valNdx] >> 24); 913 const float ref0 = de::clamp(float(in0) / 127.f, -1.0f, 1.0f); 914 const float ref1 = de::clamp(float(in1) / 127.f, -1.0f, 1.0f); 915 const float ref2 = de::clamp(float(in2) / 127.f, -1.0f, 1.0f); 916 const float ref3 = de::clamp(float(in3) / 127.f, -1.0f, 1.0f); 917 const float res0 = outputs[valNdx].x(); 918 const float res1 = outputs[valNdx].y(); 919 const float res2 = outputs[valNdx].z(); 920 const float res3 = outputs[valNdx].w(); 921 922 const deUint32 diff0 = getUlpDiff(ref0, res0); 923 const deUint32 diff1 = getUlpDiff(ref1, res1); 924 const deUint32 diff2 = getUlpDiff(ref2, res2); 925 const deUint32 diff3 = getUlpDiff(ref3, res3); 926 927 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff) 928 { 929 if (numFailed < maxPrints) 930 { 931 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 932 << " expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = " 933 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")" 934 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")" 935 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff 936 << TestLog::EndMessage; 937 } 938 else if (numFailed == maxPrints) 939 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 940 941 numFailed += 1; 942 } 943 } 944 945 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 946 947 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 948 numFailed == 0 ? "Pass" : "Result comparison failed"); 949 } 950 951 return STOP; 952 } 953}; 954 955class PackUnorm4x8Case : public ShaderPackingFunctionCase 956{ 957public: 958 PackUnorm4x8Case (Context& context, glu::ShaderType shaderType, glu::Precision precision) 959 : ShaderPackingFunctionCase (context, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType) 960 , m_precision (precision) 961 { 962 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision))); 963 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 964 965 m_spec.source = "out0 = packUnorm4x8(in0);"; 966 } 967 968 IterateResult iterate (void) 969 { 970 de::Random rnd (deStringHash(getName()) ^ 0x776002); 971 std::vector<tcu::Vec4> inputs; 972 std::vector<deUint32> outputs; 973 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only. 974 m_precision == glu::PRECISION_MEDIUMP ? 1 : // (2^-10) * (2^8) + 1 975 m_precision == glu::PRECISION_LOWP ? 2 : 0; // (2^-8) * (2^8) + 1 976 977 // Special values to check. 978 inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f)); 979 inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f)); 980 inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f)); 981 inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f)); 982 inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f)); 983 984 // Random values, mostly in range. 985 for (int ndx = 0; ndx < 15; ndx++) 986 { 987 const float x = rnd.getFloat()*1.25f - 0.125f; 988 const float y = rnd.getFloat()*1.25f - 0.125f; 989 const float z = rnd.getFloat()*1.25f - 0.125f; 990 const float w = rnd.getFloat()*1.25f - 0.125f; 991 inputs.push_back(tcu::Vec4(x, y, z, w)); 992 } 993 994 // Large random values. 995 for (int ndx = 0; ndx < 80; ndx++) 996 { 997 const float x = rnd.getFloat()*1e6f - 1e5f; 998 const float y = rnd.getFloat()*1e6f - 1e5f; 999 const float z = rnd.getFloat()*1e6f - 1e5f; 1000 const float w = rnd.getFloat()*1e6f - 1e5f; 1001 inputs.push_back(tcu::Vec4(x, y, z, w)); 1002 } 1003 1004 outputs.resize(inputs.size()); 1005 1006 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 1007 1008 { 1009 const void* in = &inputs[0]; 1010 void* out = &outputs[0]; 1011 1012 m_executor->useProgram(); 1013 m_executor->execute((int)inputs.size(), &in, &out); 1014 } 1015 1016 // Verify 1017 { 1018 const int numValues = (int)inputs.size(); 1019 const int maxPrints = 10; 1020 int numFailed = 0; 1021 1022 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 1023 { 1024 const deUint16 ref0 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1); 1025 const deUint16 ref1 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1); 1026 const deUint16 ref2 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1); 1027 const deUint16 ref3 = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1); 1028 const deUint32 ref = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0); 1029 const deUint32 res = outputs[valNdx]; 1030 const deUint16 res0 = (deUint8)(res & 0xff); 1031 const deUint16 res1 = (deUint8)((res >> 8) & 0xff); 1032 const deUint16 res2 = (deUint8)((res >> 16) & 0xff); 1033 const deUint16 res3 = (deUint8)((res >> 24) & 0xff); 1034 const int diff0 = de::abs((int)ref0 - (int)res0); 1035 const int diff1 = de::abs((int)ref1 - (int)res1); 1036 const int diff2 = de::abs((int)ref2 - (int)res2); 1037 const int diff3 = de::abs((int)ref3 - (int)res3); 1038 1039 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff) 1040 { 1041 if (numFailed < maxPrints) 1042 { 1043 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 1044 << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 1045 << ", got " << tcu::toHex(res) 1046 << "\n diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff 1047 << TestLog::EndMessage; 1048 } 1049 else if (numFailed == maxPrints) 1050 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 1051 1052 numFailed += 1; 1053 } 1054 } 1055 1056 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 1057 1058 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1059 numFailed == 0 ? "Pass" : "Result comparison failed"); 1060 } 1061 1062 return STOP; 1063 } 1064 1065private: 1066 glu::Precision m_precision; 1067}; 1068 1069class UnpackUnorm4x8Case : public ShaderPackingFunctionCase 1070{ 1071public: 1072 UnpackUnorm4x8Case (Context& context, glu::ShaderType shaderType) 1073 : ShaderPackingFunctionCase(context, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType) 1074 { 1075 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 1076 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP))); 1077 1078 m_spec.source = "out0 = unpackUnorm4x8(in0);"; 1079 } 1080 1081 IterateResult iterate (void) 1082 { 1083 const deUint32 maxDiff = 1; // Rounding error. 1084 de::Random rnd (deStringHash(getName()) ^ 0x776002); 1085 std::vector<deUint32> inputs; 1086 std::vector<tcu::Vec4> outputs; 1087 1088 inputs.push_back(0x00000000u); 1089 inputs.push_back(0x7fff8000u); 1090 inputs.push_back(0x80007fffu); 1091 inputs.push_back(0xffffffffu); 1092 inputs.push_back(0x0001fffeu); 1093 1094 // Random values. 1095 for (int ndx = 0; ndx < 95; ndx++) 1096 inputs.push_back(rnd.getUint32()); 1097 1098 outputs.resize(inputs.size()); 1099 1100 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 1101 1102 { 1103 const void* in = &inputs[0]; 1104 void* out = &outputs[0]; 1105 1106 m_executor->useProgram(); 1107 m_executor->execute((int)inputs.size(), &in, &out); 1108 } 1109 1110 // Verify 1111 { 1112 const int numValues = (int)inputs.size(); 1113 const int maxPrints = 10; 1114 int numFailed = 0; 1115 1116 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 1117 { 1118 const deUint8 in0 = (deUint8)(inputs[valNdx] & 0xff); 1119 const deUint8 in1 = (deUint8)((inputs[valNdx] >> 8) & 0xff); 1120 const deUint8 in2 = (deUint8)((inputs[valNdx] >> 16) & 0xff); 1121 const deUint8 in3 = (deUint8)(inputs[valNdx] >> 24); 1122 const float ref0 = de::clamp(float(in0) / 255.f, 0.0f, 1.0f); 1123 const float ref1 = de::clamp(float(in1) / 255.f, 0.0f, 1.0f); 1124 const float ref2 = de::clamp(float(in2) / 255.f, 0.0f, 1.0f); 1125 const float ref3 = de::clamp(float(in3) / 255.f, 0.0f, 1.0f); 1126 const float res0 = outputs[valNdx].x(); 1127 const float res1 = outputs[valNdx].y(); 1128 const float res2 = outputs[valNdx].z(); 1129 const float res3 = outputs[valNdx].w(); 1130 1131 const deUint32 diff0 = getUlpDiff(ref0, res0); 1132 const deUint32 diff1 = getUlpDiff(ref1, res1); 1133 const deUint32 diff2 = getUlpDiff(ref2, res2); 1134 const deUint32 diff3 = getUlpDiff(ref3, res3); 1135 1136 if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff) 1137 { 1138 if (numFailed < maxPrints) 1139 { 1140 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 1141 << " expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = " 1142 << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")" 1143 << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")" 1144 << "\n ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff 1145 << TestLog::EndMessage; 1146 } 1147 else if (numFailed == maxPrints) 1148 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 1149 1150 numFailed += 1; 1151 } 1152 } 1153 1154 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 1155 1156 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 1157 numFailed == 0 ? "Pass" : "Result comparison failed"); 1158 } 1159 1160 return STOP; 1161 } 1162}; 1163 1164ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context) 1165 : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests") 1166{ 1167} 1168 1169ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void) 1170{ 1171} 1172 1173void ShaderPackingFunctionTests::init (void) 1174{ 1175 // New built-in functions in GLES 3.1 1176 { 1177 const glu::ShaderType allShaderTypes[] = 1178 { 1179 glu::SHADERTYPE_VERTEX, 1180 glu::SHADERTYPE_TESSELLATION_CONTROL, 1181 glu::SHADERTYPE_TESSELLATION_EVALUATION, 1182 glu::SHADERTYPE_GEOMETRY, 1183 glu::SHADERTYPE_FRAGMENT, 1184 glu::SHADERTYPE_COMPUTE 1185 }; 1186 1187 // packSnorm4x8 1188 for (int prec = 0; prec < glu::PRECISION_LAST; prec++) 1189 { 1190 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++) 1191 addChild(new PackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec))); 1192 } 1193 1194 // unpackSnorm4x8 1195 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++) 1196 addChild(new UnpackSnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx])); 1197 1198 // packUnorm4x8 1199 for (int prec = 0; prec < glu::PRECISION_LAST; prec++) 1200 { 1201 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++) 1202 addChild(new PackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx], glu::Precision(prec))); 1203 } 1204 1205 // unpackUnorm4x8 1206 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++) 1207 addChild(new UnpackUnorm4x8Case(m_context, allShaderTypes[shaderTypeNdx])); 1208 } 1209 1210 // GLES 3 functions in new shader types. 1211 { 1212 const glu::ShaderType newShaderTypes[] = 1213 { 1214 glu::SHADERTYPE_GEOMETRY, 1215 glu::SHADERTYPE_COMPUTE 1216 }; 1217 1218 // packSnorm2x16 1219 for (int prec = 0; prec < glu::PRECISION_LAST; prec++) 1220 { 1221 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++) 1222 addChild(new PackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec))); 1223 } 1224 1225 // unpackSnorm2x16 1226 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++) 1227 addChild(new UnpackSnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx])); 1228 1229 // packUnorm2x16 1230 for (int prec = 0; prec < glu::PRECISION_LAST; prec++) 1231 { 1232 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++) 1233 addChild(new PackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx], glu::Precision(prec))); 1234 } 1235 1236 // unpackUnorm2x16 1237 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++) 1238 addChild(new UnpackUnorm2x16Case(m_context, newShaderTypes[shaderTypeNdx])); 1239 1240 // packHalf2x16 1241 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++) 1242 addChild(new PackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx])); 1243 1244 // unpackHalf2x16 1245 for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++) 1246 addChild(new UnpackHalf2x16Case(m_context, newShaderTypes[shaderTypeNdx])); 1247 } 1248} 1249 1250} // Functional 1251} // gles31 1252} // deqp 1253