1/*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 3.0 Module 3 * ------------------------------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Floating-point packing and unpacking function tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es3fShaderPackingFunctionTests.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 gles3 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::GLSL_VERSION_300_ES; 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 }; 140 DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix))); 141 return s_postfix[shaderType]; 142} 143 144class PackSnorm2x16Case : public ShaderPackingFunctionCase 145{ 146public: 147 PackSnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision) 148 : ShaderPackingFunctionCase (context, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType) 149 , m_precision (precision) 150 { 151 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision))); 152 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 153 154 m_spec.source = "out0 = packSnorm2x16(in0);"; 155 } 156 157 IterateResult iterate (void) 158 { 159 de::Random rnd (deStringHash(getName()) ^ 0x776002); 160 std::vector<tcu::Vec2> inputs; 161 std::vector<deUint32> outputs; 162 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only. 163 m_precision == glu::PRECISION_MEDIUMP ? 33 : // (2^-10) * (2^15) + 1 164 m_precision == glu::PRECISION_LOWP ? 129 : 0; // (2^-8) * (2^15) + 1 165 166 // Special values to check. 167 inputs.push_back(tcu::Vec2(0.0f, 0.0f)); 168 inputs.push_back(tcu::Vec2(-1.0f, 1.0f)); 169 inputs.push_back(tcu::Vec2(0.5f, -0.5f)); 170 inputs.push_back(tcu::Vec2(-1.5f, 1.5f)); 171 inputs.push_back(tcu::Vec2(0.25f, -0.75f)); 172 173 // Random values, mostly in range. 174 for (int ndx = 0; ndx < 15; ndx++) 175 { 176 const float x = rnd.getFloat()*2.5f - 1.25f; 177 const float y = rnd.getFloat()*2.5f - 1.25f; 178 inputs.push_back(tcu::Vec2(x, y)); 179 } 180 181 // Large random values. 182 for (int ndx = 0; ndx < 80; ndx++) 183 { 184 const float x = rnd.getFloat()*1e6f - 0.5e6f; 185 const float y = rnd.getFloat()*1e6f - 0.5e6f; 186 inputs.push_back(tcu::Vec2(x, y)); 187 } 188 189 outputs.resize(inputs.size()); 190 191 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 192 193 { 194 const void* in = &inputs[0]; 195 void* out = &outputs[0]; 196 197 m_executor->useProgram(); 198 m_executor->execute((int)inputs.size(), &in, &out); 199 } 200 201 // Verify 202 { 203 const int numValues = (int)inputs.size(); 204 const int maxPrints = 10; 205 int numFailed = 0; 206 207 for (int valNdx = 0; valNdx < numValues; valNdx++) 208 { 209 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1); 210 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1); 211 const deUint32 ref = (ref1 << 16) | ref0; 212 const deUint32 res = outputs[valNdx]; 213 const deUint16 res0 = (deUint16)(res & 0xffff); 214 const deUint16 res1 = (deUint16)(res >> 16); 215 const int diff0 = de::abs((int)ref0 - (int)res0); 216 const int diff1 = de::abs((int)ref1 - (int)res1); 217 218 if (diff0 > maxDiff || diff1 > maxDiff) 219 { 220 if (numFailed < maxPrints) 221 { 222 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 223 << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 224 << ", got " << tcu::toHex(res) 225 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 226 << TestLog::EndMessage; 227 } 228 else if (numFailed == maxPrints) 229 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 230 231 numFailed += 1; 232 } 233 } 234 235 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 236 237 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 238 numFailed == 0 ? "Pass" : "Result comparison failed"); 239 } 240 241 return STOP; 242 } 243 244private: 245 glu::Precision m_precision; 246}; 247 248class UnpackSnorm2x16Case : public ShaderPackingFunctionCase 249{ 250public: 251 UnpackSnorm2x16Case (Context& context, glu::ShaderType shaderType) 252 : ShaderPackingFunctionCase(context, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType) 253 { 254 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 255 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP))); 256 257 m_spec.source = "out0 = unpackSnorm2x16(in0);"; 258 } 259 260 IterateResult iterate (void) 261 { 262 const deUint32 maxDiff = 1; // Rounding error. 263 de::Random rnd (deStringHash(getName()) ^ 0x776002); 264 std::vector<deUint32> inputs; 265 std::vector<tcu::Vec2> outputs; 266 267 inputs.push_back(0x00000000u); 268 inputs.push_back(0x7fff8000u); 269 inputs.push_back(0x80007fffu); 270 inputs.push_back(0xffffffffu); 271 inputs.push_back(0x0001fffeu); 272 273 // Random values. 274 for (int ndx = 0; ndx < 95; ndx++) 275 inputs.push_back(rnd.getUint32()); 276 277 outputs.resize(inputs.size()); 278 279 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 280 281 { 282 const void* in = &inputs[0]; 283 void* out = &outputs[0]; 284 285 m_executor->useProgram(); 286 m_executor->execute((int)inputs.size(), &in, &out); 287 } 288 289 // Verify 290 { 291 const int numValues = (int)inputs.size(); 292 const int maxPrints = 10; 293 int numFailed = 0; 294 295 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 296 { 297 const deInt16 in0 = (deInt16)(deUint16)(inputs[valNdx] & 0xffff); 298 const deInt16 in1 = (deInt16)(deUint16)(inputs[valNdx] >> 16); 299 const float ref0 = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f); 300 const float ref1 = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f); 301 const float res0 = outputs[valNdx].x(); 302 const float res1 = outputs[valNdx].y(); 303 304 const deUint32 diff0 = getUlpDiff(ref0, res0); 305 const deUint32 diff1 = getUlpDiff(ref1, res1); 306 307 if (diff0 > maxDiff || diff1 > maxDiff) 308 { 309 if (numFailed < maxPrints) 310 { 311 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 312 << " expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = " 313 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")" 314 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")" 315 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 316 << TestLog::EndMessage; 317 } 318 else if (numFailed == maxPrints) 319 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 320 321 numFailed += 1; 322 } 323 } 324 325 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 326 327 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 328 numFailed == 0 ? "Pass" : "Result comparison failed"); 329 } 330 331 return STOP; 332 } 333}; 334 335class PackUnorm2x16Case : public ShaderPackingFunctionCase 336{ 337public: 338 PackUnorm2x16Case (Context& context, glu::ShaderType shaderType, glu::Precision precision) 339 : ShaderPackingFunctionCase (context, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType) 340 , m_precision (precision) 341 { 342 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision))); 343 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 344 345 m_spec.source = "out0 = packUnorm2x16(in0);"; 346 } 347 348 IterateResult iterate (void) 349 { 350 de::Random rnd (deStringHash(getName()) ^ 0x776002); 351 std::vector<tcu::Vec2> inputs; 352 std::vector<deUint32> outputs; 353 const int maxDiff = m_precision == glu::PRECISION_HIGHP ? 1 : // Rounding only. 354 m_precision == glu::PRECISION_MEDIUMP ? 65 : // (2^-10) * (2^16) + 1 355 m_precision == glu::PRECISION_LOWP ? 257 : 0; // (2^-8) * (2^16) + 1 356 357 // Special values to check. 358 inputs.push_back(tcu::Vec2(0.0f, 0.0f)); 359 inputs.push_back(tcu::Vec2(0.5f, 1.0f)); 360 inputs.push_back(tcu::Vec2(1.0f, 0.5f)); 361 inputs.push_back(tcu::Vec2(-0.5f, 1.5f)); 362 inputs.push_back(tcu::Vec2(0.25f, 0.75f)); 363 364 // Random values, mostly in range. 365 for (int ndx = 0; ndx < 15; ndx++) 366 { 367 const float x = rnd.getFloat()*1.25f; 368 const float y = rnd.getFloat()*1.25f; 369 inputs.push_back(tcu::Vec2(x, y)); 370 } 371 372 // Large random values. 373 for (int ndx = 0; ndx < 80; ndx++) 374 { 375 const float x = rnd.getFloat()*1e6f - 1e5f; 376 const float y = rnd.getFloat()*1e6f - 1e5f; 377 inputs.push_back(tcu::Vec2(x, y)); 378 } 379 380 outputs.resize(inputs.size()); 381 382 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 383 384 { 385 const void* in = &inputs[0]; 386 void* out = &outputs[0]; 387 388 m_executor->useProgram(); 389 m_executor->execute((int)inputs.size(), &in, &out); 390 } 391 392 // Verify 393 { 394 const int numValues = (int)inputs.size(); 395 const int maxPrints = 10; 396 int numFailed = 0; 397 398 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 399 { 400 const deUint16 ref0 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1); 401 const deUint16 ref1 = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1); 402 const deUint32 ref = (ref1 << 16) | ref0; 403 const deUint32 res = outputs[valNdx]; 404 const deUint16 res0 = (deUint16)(res & 0xffff); 405 const deUint16 res1 = (deUint16)(res >> 16); 406 const int diff0 = de::abs((int)ref0 - (int)res0); 407 const int diff1 = de::abs((int)ref1 - (int)res1); 408 409 if (diff0 > maxDiff || diff1 > maxDiff) 410 { 411 if (numFailed < maxPrints) 412 { 413 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 414 << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 415 << ", got " << tcu::toHex(res) 416 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 417 << TestLog::EndMessage; 418 } 419 else if (numFailed == maxPrints) 420 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 421 422 numFailed += 1; 423 } 424 } 425 426 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 427 428 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 429 numFailed == 0 ? "Pass" : "Result comparison failed"); 430 } 431 432 return STOP; 433 } 434 435private: 436 glu::Precision m_precision; 437}; 438 439class UnpackUnorm2x16Case : public ShaderPackingFunctionCase 440{ 441public: 442 UnpackUnorm2x16Case (Context& context, glu::ShaderType shaderType) 443 : ShaderPackingFunctionCase(context, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType) 444 { 445 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 446 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP))); 447 448 m_spec.source = "out0 = unpackUnorm2x16(in0);"; 449 } 450 451 IterateResult iterate (void) 452 { 453 const deUint32 maxDiff = 1; // Rounding error. 454 de::Random rnd (deStringHash(getName()) ^ 0x776002); 455 std::vector<deUint32> inputs; 456 std::vector<tcu::Vec2> outputs; 457 458 inputs.push_back(0x00000000u); 459 inputs.push_back(0x7fff8000u); 460 inputs.push_back(0x80007fffu); 461 inputs.push_back(0xffffffffu); 462 inputs.push_back(0x0001fffeu); 463 464 // Random values. 465 for (int ndx = 0; ndx < 95; ndx++) 466 inputs.push_back(rnd.getUint32()); 467 468 outputs.resize(inputs.size()); 469 470 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 471 472 { 473 const void* in = &inputs[0]; 474 void* out = &outputs[0]; 475 476 m_executor->useProgram(); 477 m_executor->execute((int)inputs.size(), &in, &out); 478 } 479 480 // Verify 481 { 482 const int numValues = (int)inputs.size(); 483 const int maxPrints = 10; 484 int numFailed = 0; 485 486 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 487 { 488 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff); 489 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16); 490 const float ref0 = float(in0) / 65535.0f; 491 const float ref1 = float(in1) / 65535.0f; 492 const float res0 = outputs[valNdx].x(); 493 const float res1 = outputs[valNdx].y(); 494 495 const deUint32 diff0 = getUlpDiff(ref0, res0); 496 const deUint32 diff1 = getUlpDiff(ref1, res1); 497 498 if (diff0 > maxDiff || diff1 > maxDiff) 499 { 500 if (numFailed < maxPrints) 501 { 502 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 503 << " expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = " 504 << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")" 505 << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")" 506 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 507 << TestLog::EndMessage; 508 } 509 else if (numFailed == maxPrints) 510 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 511 512 numFailed += 1; 513 } 514 } 515 516 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 517 518 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 519 numFailed == 0 ? "Pass" : "Result comparison failed"); 520 } 521 522 return STOP; 523 } 524}; 525 526class PackHalf2x16Case : public ShaderPackingFunctionCase 527{ 528public: 529 PackHalf2x16Case (Context& context, glu::ShaderType shaderType) 530 : ShaderPackingFunctionCase(context, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType) 531 { 532 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP))); 533 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 534 535 m_spec.source = "out0 = packHalf2x16(in0);"; 536 } 537 538 IterateResult iterate (void) 539 { 540 const int maxDiff = 0; // Values can be represented exactly in mediump. 541 de::Random rnd (deStringHash(getName()) ^ 0x776002); 542 std::vector<tcu::Vec2> inputs; 543 std::vector<deUint32> outputs; 544 545 // Special values to check. 546 inputs.push_back(tcu::Vec2(0.0f, 0.0f)); 547 inputs.push_back(tcu::Vec2(0.5f, 1.0f)); 548 inputs.push_back(tcu::Vec2(1.0f, 0.5f)); 549 inputs.push_back(tcu::Vec2(-0.5f, 1.5f)); 550 inputs.push_back(tcu::Vec2(0.25f, 0.75f)); 551 552 // Random values. 553 { 554 const int minExp = -14; 555 const int maxExp = 15; 556 557 for (int ndx = 0; ndx < 95; ndx++) 558 { 559 tcu::Vec2 v; 560 for (int c = 0; c < 2; c++) 561 { 562 const int s = rnd.getBool() ? 1 : -1; 563 const int exp = rnd.getInt(minExp, maxExp); 564 const deUint32 mantissa = rnd.getUint32() & ((1<<23)-1); 565 566 v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat(); 567 } 568 inputs.push_back(v); 569 } 570 } 571 572 // Convert input values to fp16 and back to make sure they can be represented exactly in mediump. 573 for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal) 574 *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat()); 575 576 outputs.resize(inputs.size()); 577 578 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 579 580 { 581 const void* in = &inputs[0]; 582 void* out = &outputs[0]; 583 584 m_executor->useProgram(); 585 m_executor->execute((int)inputs.size(), &in, &out); 586 } 587 588 // Verify 589 { 590 const int numValues = (int)inputs.size(); 591 const int maxPrints = 10; 592 int numFailed = 0; 593 594 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 595 { 596 const deUint16 ref0 = (deUint16)tcu::Float16(inputs[valNdx].x()).bits(); 597 const deUint16 ref1 = (deUint16)tcu::Float16(inputs[valNdx].y()).bits(); 598 const deUint32 ref = (ref1 << 16) | ref0; 599 const deUint32 res = outputs[valNdx]; 600 const deUint16 res0 = (deUint16)(res & 0xffff); 601 const deUint16 res1 = (deUint16)(res >> 16); 602 const int diff0 = de::abs((int)ref0 - (int)res0); 603 const int diff1 = de::abs((int)ref1 - (int)res1); 604 605 if (diff0 > maxDiff || diff1 > maxDiff) 606 { 607 if (numFailed < maxPrints) 608 { 609 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx 610 << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref) 611 << ", got " << tcu::toHex(res) 612 << "\n diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 613 << TestLog::EndMessage; 614 } 615 else if (numFailed == maxPrints) 616 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 617 618 numFailed += 1; 619 } 620 } 621 622 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 623 624 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 625 numFailed == 0 ? "Pass" : "Result comparison failed"); 626 } 627 628 return STOP; 629 } 630}; 631 632class UnpackHalf2x16Case : public ShaderPackingFunctionCase 633{ 634public: 635 UnpackHalf2x16Case (Context& context, glu::ShaderType shaderType) 636 : ShaderPackingFunctionCase(context, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType) 637 { 638 m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP))); 639 m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP))); 640 641 m_spec.source = "out0 = unpackHalf2x16(in0);"; 642 } 643 644 IterateResult iterate (void) 645 { 646 const int maxDiff = 0; // All bits must be accurate. 647 de::Random rnd (deStringHash(getName()) ^ 0x776002); 648 std::vector<deUint32> inputs; 649 std::vector<tcu::Vec2> outputs; 650 651 // Special values. 652 inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits()); 653 inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits()); 654 inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits()); 655 inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits()); 656 657 // Construct random values. 658 { 659 const int minExp = -14; 660 const int maxExp = 15; 661 const int mantBits = 10; 662 663 for (int ndx = 0; ndx < 96; ndx++) 664 { 665 deUint32 inVal = 0; 666 for (int c = 0; c < 2; c++) 667 { 668 const int s = rnd.getBool() ? 1 : -1; 669 const int exp = rnd.getInt(minExp, maxExp); 670 const deUint32 mantissa = rnd.getUint32() & ((1<<mantBits)-1); 671 const deUint16 value = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits(); 672 673 inVal |= value << (16*c); 674 } 675 inputs.push_back(inVal); 676 } 677 } 678 679 outputs.resize(inputs.size()); 680 681 m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage; 682 683 { 684 const void* in = &inputs[0]; 685 void* out = &outputs[0]; 686 687 m_executor->useProgram(); 688 m_executor->execute((int)inputs.size(), &in, &out); 689 } 690 691 // Verify 692 { 693 const int numValues = (int)inputs.size(); 694 const int maxPrints = 10; 695 int numFailed = 0; 696 697 for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++) 698 { 699 const deUint16 in0 = (deUint16)(inputs[valNdx] & 0xffff); 700 const deUint16 in1 = (deUint16)(inputs[valNdx] >> 16); 701 const float ref0 = tcu::Float16(in0).asFloat(); 702 const float ref1 = tcu::Float16(in1).asFloat(); 703 const float res0 = outputs[valNdx].x(); 704 const float res1 = outputs[valNdx].y(); 705 706 const deUint32 refBits0 = tcu::Float32(ref0).bits(); 707 const deUint32 refBits1 = tcu::Float32(ref1).bits(); 708 const deUint32 resBits0 = tcu::Float32(res0).bits(); 709 const deUint32 resBits1 = tcu::Float32(res1).bits(); 710 711 const int diff0 = de::abs((int)refBits0 - (int)resBits0); 712 const int diff1 = de::abs((int)refBits1 - (int)resBits1); 713 714 if (diff0 > maxDiff || diff1 > maxDiff) 715 { 716 if (numFailed < maxPrints) 717 { 718 m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n" 719 << " expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = " 720 << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")" 721 << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")" 722 << "\n ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff 723 << TestLog::EndMessage; 724 } 725 else if (numFailed == maxPrints) 726 m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage; 727 728 numFailed += 1; 729 } 730 } 731 732 m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage; 733 734 m_testCtx.setTestResult(numFailed == 0 ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 735 numFailed == 0 ? "Pass" : "Result comparison failed"); 736 } 737 738 return STOP; 739 } 740}; 741 742ShaderPackingFunctionTests::ShaderPackingFunctionTests (Context& context) 743 : TestCaseGroup(context, "pack_unpack", "Floating-point pack and unpack function tests") 744{ 745} 746 747ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void) 748{ 749} 750 751void ShaderPackingFunctionTests::init (void) 752{ 753 addChild(new PackSnorm2x16Case (m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_LOWP)); 754 addChild(new PackSnorm2x16Case (m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_LOWP)); 755 addChild(new PackSnorm2x16Case (m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_MEDIUMP)); 756 addChild(new PackSnorm2x16Case (m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_MEDIUMP)); 757 addChild(new PackSnorm2x16Case (m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_HIGHP)); 758 addChild(new PackSnorm2x16Case (m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_HIGHP)); 759 760 addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX)); 761 addChild(new UnpackSnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT)); 762 763 addChild(new PackUnorm2x16Case (m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_LOWP)); 764 addChild(new PackUnorm2x16Case (m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_LOWP)); 765 addChild(new PackUnorm2x16Case (m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_MEDIUMP)); 766 addChild(new PackUnorm2x16Case (m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_MEDIUMP)); 767 addChild(new PackUnorm2x16Case (m_context, glu::SHADERTYPE_VERTEX, glu::PRECISION_HIGHP)); 768 addChild(new PackUnorm2x16Case (m_context, glu::SHADERTYPE_FRAGMENT, glu::PRECISION_HIGHP)); 769 770 addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_VERTEX)); 771 addChild(new UnpackUnorm2x16Case(m_context, glu::SHADERTYPE_FRAGMENT)); 772 773 addChild(new PackHalf2x16Case (m_context, glu::SHADERTYPE_VERTEX)); 774 addChild(new PackHalf2x16Case (m_context, glu::SHADERTYPE_FRAGMENT)); 775 776 addChild(new UnpackHalf2x16Case (m_context, glu::SHADERTYPE_VERTEX)); 777 addChild(new UnpackHalf2x16Case (m_context, glu::SHADERTYPE_FRAGMENT)); 778} 779 780} // Functional 781} // gles3 782} // deqp 783