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 Fragment shader output tests. 22 * 23 * \todo [2012-04-10 pyry] Missing: 24 * + non-contiguous attachments in framebuffer 25 *//*--------------------------------------------------------------------*/ 26 27 #include "es3fFragmentOutputTests.hpp" 28 #include "gluShaderUtil.hpp" 29 #include "gluShaderProgram.hpp" 30 #include "gluTextureUtil.hpp" 31 #include "gluStrUtil.hpp" 32 #include "tcuTestLog.hpp" 33 #include "tcuTexture.hpp" 34 #include "tcuTextureUtil.hpp" 35 #include "tcuVector.hpp" 36 #include "tcuVectorUtil.hpp" 37 #include "tcuImageCompare.hpp" 38 #include "deRandom.hpp" 39 #include "deStringUtil.hpp" 40 #include "deMath.h" 41 42 // For getFormatName() \todo [pyry] Move to glu? 43 #include "es3fFboTestUtil.hpp" 44 45 #include "glwEnums.hpp" 46 #include "glwFunctions.hpp" 47 48 namespace deqp 49 { 50 namespace gles3 51 { 52 namespace Functional 53 { 54 55 using std::vector; 56 using std::string; 57 using tcu::IVec2; 58 using tcu::IVec4; 59 using tcu::UVec2; 60 using tcu::UVec4; 61 using tcu::Vec2; 62 using tcu::Vec3; 63 using tcu::Vec4; 64 using tcu::BVec4; 65 using tcu::TestLog; 66 using FboTestUtil::getFormatName; 67 using FboTestUtil::getFramebufferReadFormat; 68 69 struct BufferSpec 70 { 71 BufferSpec (void) 72 : format (GL_NONE) 73 , width (0) 74 , height (0) 75 , samples (0) 76 { 77 } 78 79 BufferSpec (deUint32 format_, int width_, int height_, int samples_) 80 : format (format_) 81 , width (width_) 82 , height (height_) 83 , samples (samples_) 84 { 85 } 86 87 deUint32 format; 88 int width; 89 int height; 90 int samples; 91 }; 92 93 struct FragmentOutput 94 { 95 FragmentOutput (void) 96 : type (glu::TYPE_LAST) 97 , precision (glu::PRECISION_LAST) 98 , location (0) 99 , arrayLength (0) 100 { 101 } 102 103 FragmentOutput (glu::DataType type_, glu::Precision precision_, int location_, int arrayLength_ = 0) 104 : type (type_) 105 , precision (precision_) 106 , location (location_) 107 , arrayLength (arrayLength_) 108 { 109 } 110 111 glu::DataType type; 112 glu::Precision precision; 113 int location; 114 int arrayLength; //!< 0 if not an array. 115 }; 116 117 struct OutputVec 118 { 119 vector<FragmentOutput> outputs; 120 121 OutputVec& operator<< (const FragmentOutput& output) 122 { 123 outputs.push_back(output); 124 return *this; 125 } 126 127 vector<FragmentOutput> toVec (void) const 128 { 129 return outputs; 130 } 131 }; 132 133 class FragmentOutputCase : public TestCase 134 { 135 public: 136 FragmentOutputCase (Context& context, const char* name, const char* desc, const vector<BufferSpec>& fboSpec, const vector<FragmentOutput>& outputs); 137 ~FragmentOutputCase (void); 138 139 void init (void); 140 void deinit (void); 141 IterateResult iterate (void); 142 143 private: 144 FragmentOutputCase (const FragmentOutputCase& other); 145 FragmentOutputCase& operator= (const FragmentOutputCase& other); 146 147 vector<BufferSpec> m_fboSpec; 148 vector<FragmentOutput> m_outputs; 149 150 glu::ShaderProgram* m_program; 151 deUint32 m_framebuffer; 152 vector<deUint32> m_renderbuffers; 153 }; 154 155 FragmentOutputCase::FragmentOutputCase (Context& context, const char* name, const char* desc, const vector<BufferSpec>& fboSpec, const vector<FragmentOutput>& outputs) 156 : TestCase (context, name, desc) 157 , m_fboSpec (fboSpec) 158 , m_outputs (outputs) 159 , m_program (DE_NULL) 160 , m_framebuffer (0) 161 { 162 } 163 164 FragmentOutputCase::~FragmentOutputCase (void) 165 { 166 deinit(); 167 } 168 169 static glu::ShaderProgram* createProgram (const glu::RenderContext& context, const vector<FragmentOutput>& outputs) 170 { 171 std::ostringstream vtx; 172 std::ostringstream frag; 173 174 vtx << "#version 300 es\n" 175 << "in highp vec4 a_position;\n"; 176 frag << "#version 300 es\n"; 177 178 // Input-output declarations. 179 for (int outNdx = 0; outNdx < (int)outputs.size(); outNdx++) 180 { 181 const FragmentOutput& output = outputs[outNdx]; 182 bool isArray = output.arrayLength > 0; 183 const char* typeName = glu::getDataTypeName(output.type); 184 const char* outputPrec = glu::getPrecisionName(output.precision); 185 bool isFloat = glu::isDataTypeFloatOrVec(output.type); 186 const char* interp = isFloat ? "smooth" : "flat"; 187 const char* interpPrec = isFloat ? "highp" : outputPrec; 188 189 if (isArray) 190 { 191 for (int elemNdx = 0; elemNdx < output.arrayLength; elemNdx++) 192 { 193 vtx << "in " << interpPrec << " " << typeName << " in" << outNdx << "_" << elemNdx << ";\n" 194 << interp << " out " << interpPrec << " " << typeName << " var" << outNdx << "_" << elemNdx << ";\n"; 195 frag << interp << " in " << interpPrec << " " << typeName << " var" << outNdx << "_" << elemNdx << ";\n"; 196 } 197 frag << "layout(location = " << output.location << ") out " << outputPrec << " " << typeName << " out" << outNdx << "[" << output.arrayLength << "];\n"; 198 } 199 else 200 { 201 vtx << "in " << interpPrec << " " << typeName << " in" << outNdx << ";\n" 202 << interp << " out " << interpPrec << " " << typeName << " var" << outNdx << ";\n"; 203 frag << interp << " in " << interpPrec << " " << typeName << " var" << outNdx << ";\n" 204 << "layout(location = " << output.location << ") out " << outputPrec << " " << typeName << " out" << outNdx << ";\n"; 205 } 206 } 207 208 vtx << "\nvoid main()\n{\n"; 209 frag << "\nvoid main()\n{\n"; 210 211 vtx << " gl_Position = a_position;\n"; 212 213 // Copy body 214 for (int outNdx = 0; outNdx < (int)outputs.size(); outNdx++) 215 { 216 const FragmentOutput& output = outputs[outNdx]; 217 bool isArray = output.arrayLength > 0; 218 219 if (isArray) 220 { 221 for (int elemNdx = 0; elemNdx < output.arrayLength; elemNdx++) 222 { 223 vtx << "\tvar" << outNdx << "_" << elemNdx << " = in" << outNdx << "_" << elemNdx << ";\n"; 224 frag << "\tout" << outNdx << "[" << elemNdx << "] = var" << outNdx << "_" << elemNdx << ";\n"; 225 } 226 } 227 else 228 { 229 vtx << "\tvar" << outNdx << " = in" << outNdx << ";\n"; 230 frag << "\tout" << outNdx << " = var" << outNdx << ";\n"; 231 } 232 } 233 234 vtx << "}\n"; 235 frag << "}\n"; 236 237 return new glu::ShaderProgram(context, glu::makeVtxFragSources(vtx.str(), frag.str())); 238 } 239 240 void FragmentOutputCase::init (void) 241 { 242 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 243 TestLog& log = m_testCtx.getLog(); 244 245 // Check that all attachments are supported 246 for (std::vector<BufferSpec>::const_iterator bufIter = m_fboSpec.begin(); bufIter != m_fboSpec.end(); ++bufIter) 247 { 248 if (!glu::isSizedFormatColorRenderable(m_context.getRenderContext(), m_context.getContextInfo(), bufIter->format)) 249 throw tcu::NotSupportedError("Unsupported attachment format"); 250 } 251 252 DE_ASSERT(!m_program); 253 m_program = createProgram(m_context.getRenderContext(), m_outputs); 254 255 log << *m_program; 256 if (!m_program->isOk()) 257 TCU_FAIL("Compile failed"); 258 259 // Print render target info to log. 260 log << TestLog::Section("Framebuffer", "Framebuffer configuration"); 261 262 for (int ndx = 0; ndx < (int)m_fboSpec.size(); ndx++) 263 log << TestLog::Message << "COLOR_ATTACHMENT" << ndx << ": " 264 << glu::getTextureFormatStr(m_fboSpec[ndx].format) << ", " 265 << m_fboSpec[ndx].width << "x" << m_fboSpec[ndx].height << ", " 266 << m_fboSpec[ndx].samples << " samples" 267 << TestLog::EndMessage; 268 269 log << TestLog::EndSection; 270 271 // Create framebuffer. 272 m_renderbuffers.resize(m_fboSpec.size(), 0); 273 gl.genFramebuffers(1, &m_framebuffer); 274 gl.genRenderbuffers((int)m_renderbuffers.size(), &m_renderbuffers[0]); 275 276 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); 277 278 for (int bufNdx = 0; bufNdx < (int)m_renderbuffers.size(); bufNdx++) 279 { 280 deUint32 rbo = m_renderbuffers[bufNdx]; 281 const BufferSpec& bufSpec = m_fboSpec[bufNdx]; 282 deUint32 attachment = GL_COLOR_ATTACHMENT0+bufNdx; 283 284 gl.bindRenderbuffer(GL_RENDERBUFFER, rbo); 285 gl.renderbufferStorageMultisample(GL_RENDERBUFFER, bufSpec.samples, bufSpec.format, bufSpec.width, bufSpec.height); 286 gl.framebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rbo); 287 } 288 GLU_EXPECT_NO_ERROR(gl.getError(), "After framebuffer setup"); 289 290 deUint32 fboStatus = gl.checkFramebufferStatus(GL_FRAMEBUFFER); 291 if (fboStatus == GL_FRAMEBUFFER_UNSUPPORTED) 292 throw tcu::NotSupportedError("Framebuffer not supported", "", __FILE__, __LINE__); 293 else if (fboStatus != GL_FRAMEBUFFER_COMPLETE) 294 throw tcu::TestError((string("Incomplete framebuffer: ") + glu::getFramebufferStatusStr(fboStatus).toString()).c_str(), "", __FILE__, __LINE__); 295 296 gl.bindFramebuffer(GL_FRAMEBUFFER, 0); 297 GLU_EXPECT_NO_ERROR(gl.getError(), "After init"); 298 } 299 300 void FragmentOutputCase::deinit (void) 301 { 302 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 303 304 if (m_framebuffer) 305 { 306 gl.deleteFramebuffers(1, &m_framebuffer); 307 m_framebuffer = 0; 308 } 309 310 if (!m_renderbuffers.empty()) 311 { 312 gl.deleteRenderbuffers((int)m_renderbuffers.size(), &m_renderbuffers[0]); 313 m_renderbuffers.clear(); 314 } 315 316 delete m_program; 317 m_program = DE_NULL; 318 } 319 320 static IVec2 getMinSize (const vector<BufferSpec>& fboSpec) 321 { 322 IVec2 minSize(0x7fffffff, 0x7fffffff); 323 for (vector<BufferSpec>::const_iterator i = fboSpec.begin(); i != fboSpec.end(); i++) 324 { 325 minSize.x() = de::min(minSize.x(), i->width); 326 minSize.y() = de::min(minSize.y(), i->height); 327 } 328 return minSize; 329 } 330 331 static int getNumInputVectors (const vector<FragmentOutput>& outputs) 332 { 333 int numVecs = 0; 334 for (vector<FragmentOutput>::const_iterator i = outputs.begin(); i != outputs.end(); i++) 335 numVecs += (i->arrayLength > 0 ? i->arrayLength : 1); 336 return numVecs; 337 } 338 339 static Vec2 getFloatRange (glu::Precision precision) 340 { 341 // \todo [2012-04-09 pyry] Not quite the full ranges. 342 static const Vec2 ranges[] = 343 { 344 Vec2(-2.0f, 2.0f), 345 Vec2(-16000.0f, 16000.0f), 346 Vec2(-1e35f, 1e35f) 347 }; 348 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST); 349 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges))); 350 return ranges[precision]; 351 } 352 353 static IVec2 getIntRange (glu::Precision precision) 354 { 355 static const IVec2 ranges[] = 356 { 357 IVec2(-(1<< 7), (1<< 7)-1), 358 IVec2(-(1<<15), (1<<15)-1), 359 IVec2(0x80000000, 0x7fffffff) 360 }; 361 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST); 362 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges))); 363 return ranges[precision]; 364 } 365 366 static UVec2 getUintRange (glu::Precision precision) 367 { 368 static const UVec2 ranges[] = 369 { 370 UVec2(0, (1<< 8)-1), 371 UVec2(0, (1<<16)-1), 372 UVec2(0, 0xffffffffu) 373 }; 374 DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(ranges) == glu::PRECISION_LAST); 375 DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(ranges))); 376 return ranges[precision]; 377 } 378 379 static inline Vec4 readVec4 (const float* ptr, int numComponents) 380 { 381 DE_ASSERT(numComponents >= 1); 382 return Vec4(ptr[0], 383 numComponents >= 2 ? ptr[1] : 0.0f, 384 numComponents >= 3 ? ptr[2] : 0.0f, 385 numComponents >= 4 ? ptr[3] : 0.0f); 386 } 387 388 static inline IVec4 readIVec4 (const int* ptr, int numComponents) 389 { 390 DE_ASSERT(numComponents >= 1); 391 return IVec4(ptr[0], 392 numComponents >= 2 ? ptr[1] : 0, 393 numComponents >= 3 ? ptr[2] : 0, 394 numComponents >= 4 ? ptr[3] : 0); 395 } 396 397 static void renderFloatReference (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight, int numComponents, const float* vertices) 398 { 399 const bool isSRGB = tcu::isSRGB(dst.getFormat()); 400 const float cellW = (float)dst.getWidth() / (float)(gridWidth-1); 401 const float cellH = (float)dst.getHeight() / (float)(gridHeight-1); 402 403 for (int y = 0; y < dst.getHeight(); y++) 404 { 405 for (int x = 0; x < dst.getWidth(); x++) 406 { 407 const int cellX = de::clamp(deFloorFloatToInt32((float)x / cellW), 0, gridWidth-2); 408 const int cellY = de::clamp(deFloorFloatToInt32((float)y / cellH), 0, gridHeight-2); 409 const float xf = ((float)x - (float)cellX*cellW + 0.5f) / cellW; 410 const float yf = ((float)y - (float)cellY*cellH + 0.5f) / cellH; 411 const Vec4 v00 = readVec4(vertices + ((cellY+0)*gridWidth + cellX+0)*numComponents, numComponents); 412 const Vec4 v01 = readVec4(vertices + ((cellY+1)*gridWidth + cellX+0)*numComponents, numComponents); 413 const Vec4 v10 = readVec4(vertices + ((cellY+0)*gridWidth + cellX+1)*numComponents, numComponents); 414 const Vec4 v11 = readVec4(vertices + ((cellY+1)*gridWidth + cellX+1)*numComponents, numComponents); 415 const bool tri = xf + yf >= 1.0f; 416 const Vec4& v0 = tri ? v11 : v00; 417 const Vec4& v1 = tri ? v01 : v10; 418 const Vec4& v2 = tri ? v10 : v01; 419 const float s = tri ? 1.0f-xf : xf; 420 const float t = tri ? 1.0f-yf : yf; 421 const Vec4 color = v0 + (v1-v0)*s + (v2-v0)*t; 422 423 dst.setPixel(isSRGB ? tcu::linearToSRGB(color) : color, x, y); 424 } 425 } 426 } 427 428 static void renderIntReference (const tcu::PixelBufferAccess& dst, int gridWidth, int gridHeight, int numComponents, const int* vertices) 429 { 430 float cellW = (float)dst.getWidth() / (float)(gridWidth-1); 431 float cellH = (float)dst.getHeight() / (float)(gridHeight-1); 432 433 for (int y = 0; y < dst.getHeight(); y++) 434 { 435 for (int x = 0; x < dst.getWidth(); x++) 436 { 437 int cellX = de::clamp(deFloorFloatToInt32((float)x / cellW), 0, gridWidth-2); 438 int cellY = de::clamp(deFloorFloatToInt32((float)y / cellH), 0, gridHeight-2); 439 IVec4 c = readIVec4(vertices + (cellY*gridWidth + cellX+1)*numComponents, numComponents); 440 441 dst.setPixel(c, x, y); 442 } 443 } 444 } 445 446 static const IVec4 s_swizzles[] = 447 { 448 IVec4(0,1,2,3), 449 IVec4(1,2,3,0), 450 IVec4(2,3,0,1), 451 IVec4(3,0,1,2), 452 IVec4(3,2,1,0), 453 IVec4(2,1,0,3), 454 IVec4(1,0,3,2), 455 IVec4(0,3,2,1) 456 }; 457 458 template <typename T> 459 inline tcu::Vector<T, 4> swizzleVec (const tcu::Vector<T, 4>& vec, int swzNdx) 460 { 461 const IVec4& swz = s_swizzles[swzNdx % DE_LENGTH_OF_ARRAY(s_swizzles)]; 462 return vec.swizzle(swz[0], swz[1], swz[2], swz[3]); 463 } 464 465 namespace 466 { 467 468 struct AttachmentData 469 { 470 tcu::TextureFormat format; //!< Actual format of attachment. 471 tcu::TextureFormat referenceFormat; //!< Used for reference rendering. 472 tcu::TextureFormat readFormat; 473 int numWrittenChannels; 474 glu::Precision outPrecision; 475 vector<deUint8> renderedData; 476 vector<deUint8> referenceData; 477 }; 478 479 template<typename Type> 480 string valueRangeToString (int numValidChannels, const tcu::Vector<Type, 4>& minValue, const tcu::Vector<Type, 4>& maxValue) 481 { 482 std::ostringstream stream; 483 484 stream << "("; 485 486 for (int i = 0; i < 4; i++) 487 { 488 if (i != 0) 489 stream << ", "; 490 491 if (i < numValidChannels) 492 stream << minValue[i] << " -> " << maxValue[i]; 493 else 494 stream << "Undef"; 495 } 496 497 stream << ")"; 498 499 return stream.str(); 500 } 501 502 void clearUndefined (const tcu::PixelBufferAccess& access, int numValidChannels) 503 { 504 for (int y = 0; y < access.getHeight(); y++) 505 for (int x = 0; x < access.getWidth(); x++) 506 { 507 switch (tcu::getTextureChannelClass(access.getFormat().type)) 508 { 509 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 510 { 511 const Vec4 srcPixel = access.getPixel(x, y); 512 Vec4 dstPixel (0.0f, 0.0f, 0.0f, 1.0f); 513 514 for (int channelNdx = 0; channelNdx < numValidChannels; channelNdx++) 515 dstPixel[channelNdx] = srcPixel[channelNdx]; 516 517 access.setPixel(dstPixel, x, y); 518 break; 519 } 520 521 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 522 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 523 case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: 524 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 525 { 526 const IVec4 bitDepth = tcu::getTextureFormatBitDepth(access.getFormat()); 527 const IVec4 srcPixel = access.getPixelInt(x, y); 528 IVec4 dstPixel (0, 0, 0, (0x1u << (deUint64)bitDepth.w()) - 1); 529 530 for (int channelNdx = 0; channelNdx < numValidChannels; channelNdx++) 531 dstPixel[channelNdx] = srcPixel[channelNdx]; 532 533 access.setPixel(dstPixel, x, y); 534 break; 535 } 536 537 default: 538 DE_ASSERT(false); 539 } 540 } 541 } 542 543 } // anonymous 544 545 FragmentOutputCase::IterateResult FragmentOutputCase::iterate (void) 546 { 547 TestLog& log = m_testCtx.getLog(); 548 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 549 550 // Compute grid size & index list. 551 const int minCellSize = 8; 552 const IVec2 minBufSize = getMinSize(m_fboSpec); 553 const int gridWidth = de::clamp(minBufSize.x()/minCellSize, 1, 255)+1; 554 const int gridHeight = de::clamp(minBufSize.y()/minCellSize, 1, 255)+1; 555 const int numVertices = gridWidth*gridHeight; 556 const int numQuads = (gridWidth-1)*(gridHeight-1); 557 const int numIndices = numQuads*6; 558 559 const int numInputVecs = getNumInputVectors(m_outputs); 560 vector<vector<deUint32> > inputs (numInputVecs); 561 vector<float> positions (numVertices*4); 562 vector<deUint16> indices (numIndices); 563 564 const int readAlignment = 4; 565 const int viewportW = minBufSize.x(); 566 const int viewportH = minBufSize.y(); 567 const int numAttachments = (int)m_fboSpec.size(); 568 569 vector<deUint32> drawBuffers (numAttachments); 570 vector<AttachmentData> attachments (numAttachments); 571 572 // Initialize attachment data. 573 for (int ndx = 0; ndx < numAttachments; ndx++) 574 { 575 const tcu::TextureFormat texFmt = glu::mapGLInternalFormat(m_fboSpec[ndx].format); 576 const tcu::TextureChannelClass chnClass = tcu::getTextureChannelClass(texFmt.type); 577 const bool isFixedPoint = chnClass == tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT || 578 chnClass == tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT; 579 580 // \note Fixed-point formats use float reference to enable more accurate result verification. 581 const tcu::TextureFormat refFmt = isFixedPoint ? tcu::TextureFormat(texFmt.order, tcu::TextureFormat::FLOAT) : texFmt; 582 const tcu::TextureFormat readFmt = getFramebufferReadFormat(texFmt); 583 const int attachmentW = m_fboSpec[ndx].width; 584 const int attachmentH = m_fboSpec[ndx].height; 585 586 drawBuffers[ndx] = GL_COLOR_ATTACHMENT0+ndx; 587 attachments[ndx].format = texFmt; 588 attachments[ndx].readFormat = readFmt; 589 attachments[ndx].referenceFormat = refFmt; 590 attachments[ndx].renderedData.resize(readFmt.getPixelSize()*attachmentW*attachmentH); 591 attachments[ndx].referenceData.resize(refFmt.getPixelSize()*attachmentW*attachmentH); 592 } 593 594 // Initialize indices. 595 for (int quadNdx = 0; quadNdx < numQuads; quadNdx++) 596 { 597 int quadY = quadNdx / (gridWidth-1); 598 int quadX = quadNdx - quadY*(gridWidth-1); 599 600 indices[quadNdx*6+0] = deUint16(quadX + quadY*gridWidth); 601 indices[quadNdx*6+1] = deUint16(quadX + (quadY+1)*gridWidth); 602 indices[quadNdx*6+2] = deUint16(quadX + quadY*gridWidth + 1); 603 indices[quadNdx*6+3] = indices[quadNdx*6+1]; 604 indices[quadNdx*6+4] = deUint16(quadX + (quadY+1)*gridWidth + 1); 605 indices[quadNdx*6+5] = indices[quadNdx*6+2]; 606 } 607 608 for (int y = 0; y < gridHeight; y++) 609 { 610 for (int x = 0; x < gridWidth; x++) 611 { 612 float xf = (float)x / (float)(gridWidth-1); 613 float yf = (float)y / (float)(gridHeight-1); 614 615 positions[(y*gridWidth + x)*4 + 0] = 2.0f*xf - 1.0f; 616 positions[(y*gridWidth + x)*4 + 1] = 2.0f*yf - 1.0f; 617 positions[(y*gridWidth + x)*4 + 2] = 0.0f; 618 positions[(y*gridWidth + x)*4 + 3] = 1.0f; 619 } 620 } 621 622 // Initialize input vectors. 623 { 624 int curInVec = 0; 625 for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++) 626 { 627 const FragmentOutput& output = m_outputs[outputNdx]; 628 bool isFloat = glu::isDataTypeFloatOrVec(output.type); 629 bool isInt = glu::isDataTypeIntOrIVec(output.type); 630 bool isUint = glu::isDataTypeUintOrUVec(output.type); 631 int numVecs = output.arrayLength > 0 ? output.arrayLength : 1; 632 int numScalars = glu::getDataTypeScalarSize(output.type); 633 634 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 635 { 636 inputs[curInVec].resize(numVertices*numScalars); 637 638 // Record how many outputs are written in attachment. 639 DE_ASSERT(output.location+vecNdx < (int)attachments.size()); 640 attachments[output.location+vecNdx].numWrittenChannels = numScalars; 641 attachments[output.location+vecNdx].outPrecision = output.precision; 642 643 if (isFloat) 644 { 645 Vec2 range = getFloatRange(output.precision); 646 Vec4 minVal (range.x()); 647 Vec4 maxVal (range.y()); 648 float* dst = (float*)&inputs[curInVec][0]; 649 650 if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size())) 651 { 652 // \note Floating-point precision conversion is not well-defined. For that reason we must 653 // limit value range to intersection of both data type and render target value ranges. 654 const tcu::TextureFormatInfo fmtInfo = tcu::getTextureFormatInfo(attachments[output.location+vecNdx].format); 655 minVal = tcu::max(minVal, fmtInfo.valueMin); 656 maxVal = tcu::min(maxVal, fmtInfo.valueMax); 657 } 658 659 m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << valueRangeToString(numScalars, minVal, maxVal) << TestLog::EndMessage; 660 661 for (int y = 0; y < gridHeight; y++) 662 { 663 for (int x = 0; x < gridWidth; x++) 664 { 665 float xf = (float)x / (float)(gridWidth-1); 666 float yf = (float)y / (float)(gridHeight-1); 667 668 float f0 = (xf + yf) * 0.5f; 669 float f1 = 0.5f + (xf - yf) * 0.5f; 670 Vec4 f = swizzleVec(Vec4(f0, f1, 1.0f-f0, 1.0f-f1), curInVec); 671 Vec4 c = minVal + (maxVal-minVal)*f; 672 float* v = dst + (y*gridWidth + x)*numScalars; 673 674 for (int ndx = 0; ndx < numScalars; ndx++) 675 v[ndx] = c[ndx]; 676 } 677 } 678 } 679 else if (isInt) 680 { 681 const IVec2 range = getIntRange(output.precision); 682 IVec4 minVal (range.x()); 683 IVec4 maxVal (range.y()); 684 685 if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size())) 686 { 687 // Limit to range of output format as conversion mode is not specified. 688 const IVec4 fmtBits = tcu::getTextureFormatBitDepth(attachments[output.location+vecNdx].format); 689 const BVec4 isZero = lessThanEqual(fmtBits, IVec4(0)); 690 const IVec4 fmtMinVal = (-(tcu::Vector<deInt64, 4>(1) << (fmtBits-1).cast<deInt64>())).asInt(); 691 const IVec4 fmtMaxVal = ((tcu::Vector<deInt64, 4>(1) << (fmtBits-1).cast<deInt64>())-deInt64(1)).asInt(); 692 693 minVal = select(minVal, tcu::max(minVal, fmtMinVal), isZero); 694 maxVal = select(maxVal, tcu::min(maxVal, fmtMaxVal), isZero); 695 } 696 697 m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << valueRangeToString(numScalars, minVal, maxVal) << TestLog::EndMessage; 698 699 const IVec4 rangeDiv = swizzleVec((IVec4(gridWidth, gridHeight, gridWidth, gridHeight)-1), curInVec); 700 const IVec4 step = ((maxVal.cast<deInt64>() - minVal.cast<deInt64>()) / (rangeDiv.cast<deInt64>())).asInt(); 701 deInt32* dst = (deInt32*)&inputs[curInVec][0]; 702 703 for (int y = 0; y < gridHeight; y++) 704 { 705 for (int x = 0; x < gridWidth; x++) 706 { 707 int ix = gridWidth - x - 1; 708 int iy = gridHeight - y - 1; 709 IVec4 c = minVal + step*swizzleVec(IVec4(x, y, ix, iy), curInVec); 710 deInt32* v = dst + (y*gridWidth + x)*numScalars; 711 712 DE_ASSERT(boolAll(logicalAnd(greaterThanEqual(c, minVal), lessThanEqual(c, maxVal)))); 713 714 for (int ndx = 0; ndx < numScalars; ndx++) 715 v[ndx] = c[ndx]; 716 } 717 } 718 } 719 else if (isUint) 720 { 721 const UVec2 range = getUintRange(output.precision); 722 UVec4 maxVal (range.y()); 723 724 if (de::inBounds(output.location+vecNdx, 0, (int)attachments.size())) 725 { 726 // Limit to range of output format as conversion mode is not specified. 727 const IVec4 fmtBits = tcu::getTextureFormatBitDepth(attachments[output.location+vecNdx].format); 728 const UVec4 fmtMaxVal = ((tcu::Vector<deUint64, 4>(1) << fmtBits.cast<deUint64>())-deUint64(1)).asUint(); 729 730 maxVal = tcu::min(maxVal, fmtMaxVal); 731 } 732 733 m_testCtx.getLog() << TestLog::Message << "out" << curInVec << " value range: " << valueRangeToString(numScalars, UVec4(0), maxVal) << TestLog::EndMessage; 734 735 const IVec4 rangeDiv = swizzleVec((IVec4(gridWidth, gridHeight, gridWidth, gridHeight)-1), curInVec); 736 const UVec4 step = maxVal / rangeDiv.asUint(); 737 deUint32* dst = &inputs[curInVec][0]; 738 739 DE_ASSERT(range.x() == 0); 740 741 for (int y = 0; y < gridHeight; y++) 742 { 743 for (int x = 0; x < gridWidth; x++) 744 { 745 int ix = gridWidth - x - 1; 746 int iy = gridHeight - y - 1; 747 UVec4 c = step*swizzleVec(IVec4(x, y, ix, iy).asUint(), curInVec); 748 deUint32* v = dst + (y*gridWidth + x)*numScalars; 749 750 DE_ASSERT(boolAll(lessThanEqual(c, maxVal))); 751 752 for (int ndx = 0; ndx < numScalars; ndx++) 753 v[ndx] = c[ndx]; 754 } 755 } 756 } 757 else 758 DE_ASSERT(false); 759 760 curInVec += 1; 761 } 762 } 763 } 764 765 // Render using gl. 766 gl.useProgram(m_program->getProgram()); 767 gl.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); 768 gl.viewport(0, 0, viewportW, viewportH); 769 gl.drawBuffers((int)drawBuffers.size(), &drawBuffers[0]); 770 gl.disable(GL_DITHER); // Dithering causes issues with unorm formats. Those issues could be worked around in threshold, but it makes validation less accurate. 771 GLU_EXPECT_NO_ERROR(gl.getError(), "After program setup"); 772 773 { 774 int curInVec = 0; 775 for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++) 776 { 777 const FragmentOutput& output = m_outputs[outputNdx]; 778 bool isArray = output.arrayLength > 0; 779 bool isFloat = glu::isDataTypeFloatOrVec(output.type); 780 bool isInt = glu::isDataTypeIntOrIVec(output.type); 781 bool isUint = glu::isDataTypeUintOrUVec(output.type); 782 int scalarSize = glu::getDataTypeScalarSize(output.type); 783 deUint32 glScalarType = isFloat ? GL_FLOAT : 784 isInt ? GL_INT : 785 isUint ? GL_UNSIGNED_INT : GL_NONE; 786 int numVecs = isArray ? output.arrayLength : 1; 787 788 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 789 { 790 string name = string("in") + de::toString(outputNdx) + (isArray ? string("_") + de::toString(vecNdx) : string()); 791 int loc = gl.getAttribLocation(m_program->getProgram(), name.c_str()); 792 793 if (loc >= 0) 794 { 795 gl.enableVertexAttribArray(loc); 796 if (isFloat) 797 gl.vertexAttribPointer(loc, scalarSize, glScalarType, GL_FALSE, 0, &inputs[curInVec][0]); 798 else 799 gl.vertexAttribIPointer(loc, scalarSize, glScalarType, 0, &inputs[curInVec][0]); 800 } 801 else 802 log << TestLog::Message << "Warning: No location for attribute '" << name << "' found." << TestLog::EndMessage; 803 804 curInVec += 1; 805 } 806 } 807 } 808 { 809 int posLoc = gl.getAttribLocation(m_program->getProgram(), "a_position"); 810 TCU_CHECK(posLoc >= 0); 811 gl.enableVertexAttribArray(posLoc); 812 gl.vertexAttribPointer(posLoc, 4, GL_FLOAT, GL_FALSE, 0, &positions[0]); 813 } 814 GLU_EXPECT_NO_ERROR(gl.getError(), "After attribute setup"); 815 816 gl.drawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, &indices[0]); 817 GLU_EXPECT_NO_ERROR(gl.getError(), "glDrawElements"); 818 819 // Read all attachment points. 820 for (int ndx = 0; ndx < numAttachments; ndx++) 821 { 822 const glu::TransferFormat transferFmt = glu::getTransferFormat(attachments[ndx].readFormat); 823 void* dst = &attachments[ndx].renderedData[0]; 824 const int attachmentW = m_fboSpec[ndx].width; 825 const int attachmentH = m_fboSpec[ndx].height; 826 const int numValidChannels = attachments[ndx].numWrittenChannels; 827 const tcu::PixelBufferAccess rendered (attachments[ndx].readFormat, attachmentW, attachmentH, 1, deAlign32(attachments[ndx].readFormat.getPixelSize()*attachmentW, readAlignment), 0, &attachments[ndx].renderedData[0]); 828 829 gl.readBuffer(GL_COLOR_ATTACHMENT0+ndx); 830 gl.readPixels(0, 0, minBufSize.x(), minBufSize.y(), transferFmt.format, transferFmt.dataType, dst); 831 832 clearUndefined(rendered, numValidChannels); 833 } 834 835 // Render reference images. 836 { 837 int curInNdx = 0; 838 for (int outputNdx = 0; outputNdx < (int)m_outputs.size(); outputNdx++) 839 { 840 const FragmentOutput& output = m_outputs[outputNdx]; 841 const bool isArray = output.arrayLength > 0; 842 const bool isFloat = glu::isDataTypeFloatOrVec(output.type); 843 const bool isInt = glu::isDataTypeIntOrIVec(output.type); 844 const bool isUint = glu::isDataTypeUintOrUVec(output.type); 845 const int scalarSize = glu::getDataTypeScalarSize(output.type); 846 const int numVecs = isArray ? output.arrayLength : 1; 847 848 for (int vecNdx = 0; vecNdx < numVecs; vecNdx++) 849 { 850 const int location = output.location+vecNdx; 851 const void* inputData = &inputs[curInNdx][0]; 852 853 DE_ASSERT(de::inBounds(location, 0, (int)m_fboSpec.size())); 854 855 const int bufW = m_fboSpec[location].width; 856 const int bufH = m_fboSpec[location].height; 857 const tcu::PixelBufferAccess buf (attachments[location].referenceFormat, bufW, bufH, 1, &attachments[location].referenceData[0]); 858 const tcu::PixelBufferAccess viewportBuf = getSubregion(buf, 0, 0, 0, viewportW, viewportH, 1); 859 860 if (isInt || isUint) 861 renderIntReference(viewportBuf, gridWidth, gridHeight, scalarSize, (const int*)inputData); 862 else if (isFloat) 863 renderFloatReference(viewportBuf, gridWidth, gridHeight, scalarSize, (const float*)inputData); 864 else 865 DE_ASSERT(false); 866 867 curInNdx += 1; 868 } 869 } 870 } 871 872 // Compare all images. 873 bool allLevelsOk = true; 874 for (int attachNdx = 0; attachNdx < numAttachments; attachNdx++) 875 { 876 const int attachmentW = m_fboSpec[attachNdx].width; 877 const int attachmentH = m_fboSpec[attachNdx].height; 878 const int numValidChannels = attachments[attachNdx].numWrittenChannels; 879 const tcu::BVec4 cmpMask (numValidChannels >= 1, numValidChannels >= 2, numValidChannels >= 3, numValidChannels >= 4); 880 const glu::Precision outPrecision = attachments[attachNdx].outPrecision; 881 const tcu::TextureFormat& format = attachments[attachNdx].format; 882 tcu::ConstPixelBufferAccess rendered (attachments[attachNdx].readFormat, attachmentW, attachmentH, 1, deAlign32(attachments[attachNdx].readFormat.getPixelSize()*attachmentW, readAlignment), 0, &attachments[attachNdx].renderedData[0]); 883 tcu::ConstPixelBufferAccess reference (attachments[attachNdx].referenceFormat, attachmentW, attachmentH, 1, &attachments[attachNdx].referenceData[0]); 884 tcu::TextureChannelClass texClass = tcu::getTextureChannelClass(format.type); 885 bool isOk = true; 886 const string name = string("Attachment") + de::toString(attachNdx); 887 const string desc = string("Color attachment ") + de::toString(attachNdx); 888 889 log << TestLog::Message << "Attachment " << attachNdx << ": " << numValidChannels << " channels have defined values and used for comparison" << TestLog::EndMessage; 890 891 switch (texClass) 892 { 893 case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: 894 { 895 const deUint32 interpThreshold = 4; //!< 4 ULP interpolation threshold (interpolation always in highp) 896 deUint32 outTypeThreshold = 0; //!< Threshold based on output type 897 UVec4 formatThreshold; //!< Threshold computed based on format. 898 UVec4 finalThreshold; 899 900 // 1 ULP rounding error is allowed for smaller floating-point formats 901 switch (format.type) 902 { 903 case tcu::TextureFormat::FLOAT: formatThreshold = UVec4(0); break; 904 case tcu::TextureFormat::HALF_FLOAT: formatThreshold = UVec4((1<<(23-10))); break; 905 case tcu::TextureFormat::UNSIGNED_INT_11F_11F_10F_REV: formatThreshold = UVec4((1<<(23-6)), (1<<(23-6)), (1<<(23-5)), 0); break; 906 default: 907 DE_ASSERT(false); 908 break; 909 } 910 911 // 1 ULP rounding error for highp -> output precision cast 912 switch (outPrecision) 913 { 914 case glu::PRECISION_LOWP: outTypeThreshold = (1<<(23-8)); break; 915 case glu::PRECISION_MEDIUMP: outTypeThreshold = (1<<(23-10)); break; 916 case glu::PRECISION_HIGHP: outTypeThreshold = 0; break; 917 default: 918 DE_ASSERT(false); 919 } 920 921 finalThreshold = select(max(formatThreshold, UVec4(deMax32(interpThreshold, outTypeThreshold))), UVec4(~0u), cmpMask); 922 923 isOk = tcu::floatUlpThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, finalThreshold, tcu::COMPARE_LOG_RESULT); 924 break; 925 } 926 927 case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: 928 { 929 // \note glReadPixels() allows only 8 bits to be read. This means that RGB10_A2 will loose some 930 // bits in the process and it must be taken into account when computing threshold. 931 const IVec4 bits = min(IVec4(8), tcu::getTextureFormatBitDepth(format)); 932 const Vec4 baseThreshold = 1.0f / ((IVec4(1) << bits)-1).asFloat(); 933 const Vec4 threshold = select(baseThreshold, Vec4(2.0f), cmpMask); 934 935 isOk = tcu::floatThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT); 936 break; 937 } 938 939 case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: 940 case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: 941 { 942 const tcu::UVec4 threshold = select(UVec4(0u), UVec4(~0u), cmpMask); 943 isOk = tcu::intThresholdCompare(log, name.c_str(), desc.c_str(), reference, rendered, threshold, tcu::COMPARE_LOG_RESULT); 944 break; 945 } 946 947 default: 948 TCU_FAIL("Unsupported comparison"); 949 break; 950 } 951 952 if (!isOk) 953 allLevelsOk = false; 954 } 955 956 m_testCtx.setTestResult(allLevelsOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 957 allLevelsOk ? "Pass" : "Image comparison failed"); 958 return STOP; 959 } 960 961 FragmentOutputTests::FragmentOutputTests (Context& context) 962 : TestCaseGroup(context, "fragment_out", "Fragment output tests") 963 { 964 } 965 966 FragmentOutputTests::~FragmentOutputTests (void) 967 { 968 } 969 970 static FragmentOutputCase* createRandomCase (Context& context, int minRenderTargets, int maxRenderTargets, deUint32 seed) 971 { 972 static const glu::DataType outputTypes[] = 973 { 974 glu::TYPE_FLOAT, 975 glu::TYPE_FLOAT_VEC2, 976 glu::TYPE_FLOAT_VEC3, 977 glu::TYPE_FLOAT_VEC4, 978 glu::TYPE_INT, 979 glu::TYPE_INT_VEC2, 980 glu::TYPE_INT_VEC3, 981 glu::TYPE_INT_VEC4, 982 glu::TYPE_UINT, 983 glu::TYPE_UINT_VEC2, 984 glu::TYPE_UINT_VEC3, 985 glu::TYPE_UINT_VEC4 986 }; 987 static const glu::Precision precisions[] = 988 { 989 glu::PRECISION_LOWP, 990 glu::PRECISION_MEDIUMP, 991 glu::PRECISION_HIGHP 992 }; 993 static const deUint32 floatFormats[] = 994 { 995 GL_RGBA32F, 996 GL_RGBA16F, 997 GL_R11F_G11F_B10F, 998 GL_RG32F, 999 GL_RG16F, 1000 GL_R32F, 1001 GL_R16F, 1002 GL_RGBA8, 1003 GL_SRGB8_ALPHA8, 1004 GL_RGB10_A2, 1005 GL_RGBA4, 1006 GL_RGB5_A1, 1007 GL_RGB8, 1008 GL_RGB565, 1009 GL_RG8, 1010 GL_R8 1011 }; 1012 static const deUint32 intFormats[] = 1013 { 1014 GL_RGBA32I, 1015 GL_RGBA16I, 1016 GL_RGBA8I, 1017 GL_RG32I, 1018 GL_RG16I, 1019 GL_RG8I, 1020 GL_R32I, 1021 GL_R16I, 1022 GL_R8I 1023 }; 1024 static const deUint32 uintFormats[] = 1025 { 1026 GL_RGBA32UI, 1027 GL_RGBA16UI, 1028 GL_RGBA8UI, 1029 GL_RGB10_A2UI, 1030 GL_RG32UI, 1031 GL_RG16UI, 1032 GL_RG8UI, 1033 GL_R32UI, 1034 GL_R16UI, 1035 GL_R8UI 1036 }; 1037 1038 de::Random rnd (seed); 1039 vector<FragmentOutput> outputs; 1040 vector<BufferSpec> targets; 1041 vector<glu::DataType> outTypes; 1042 1043 int numTargets = rnd.getInt(minRenderTargets, maxRenderTargets); 1044 const int width = 128; // \todo [2012-04-10 pyry] Separate randomized sizes per target? 1045 const int height = 64; 1046 const int samples = 0; 1047 1048 // Compute outputs. 1049 int curLoc = 0; 1050 while (curLoc < numTargets) 1051 { 1052 bool useArray = rnd.getFloat() < 0.3f; 1053 int maxArrayLen = numTargets-curLoc; 1054 int arrayLen = useArray ? rnd.getInt(1, maxArrayLen) : 0; 1055 glu::DataType basicType = rnd.choose<glu::DataType>(&outputTypes[0], &outputTypes[0] + DE_LENGTH_OF_ARRAY(outputTypes)); 1056 glu::Precision precision = rnd.choose<glu::Precision>(&precisions[0], &precisions[0] + DE_LENGTH_OF_ARRAY(precisions)); 1057 int numLocations = useArray ? arrayLen : 1; 1058 1059 outputs.push_back(FragmentOutput(basicType, precision, curLoc, arrayLen)); 1060 1061 for (int ndx = 0; ndx < numLocations; ndx++) 1062 outTypes.push_back(basicType); 1063 1064 curLoc += numLocations; 1065 } 1066 DE_ASSERT(curLoc == numTargets); 1067 DE_ASSERT((int)outTypes.size() == numTargets); 1068 1069 // Compute buffers. 1070 while ((int)targets.size() < numTargets) 1071 { 1072 glu::DataType outType = outTypes[targets.size()]; 1073 bool isFloat = glu::isDataTypeFloatOrVec(outType); 1074 bool isInt = glu::isDataTypeIntOrIVec(outType); 1075 bool isUint = glu::isDataTypeUintOrUVec(outType); 1076 deUint32 format = 0; 1077 1078 if (isFloat) 1079 format = rnd.choose<deUint32>(&floatFormats[0], &floatFormats[0] + DE_LENGTH_OF_ARRAY(floatFormats)); 1080 else if (isInt) 1081 format = rnd.choose<deUint32>(&intFormats[0], &intFormats[0] + DE_LENGTH_OF_ARRAY(intFormats)); 1082 else if (isUint) 1083 format = rnd.choose<deUint32>(&uintFormats[0], &uintFormats[0] + DE_LENGTH_OF_ARRAY(uintFormats)); 1084 else 1085 DE_ASSERT(false); 1086 1087 targets.push_back(BufferSpec(format, width, height, samples)); 1088 } 1089 1090 return new FragmentOutputCase(context, de::toString(seed).c_str(), "", targets, outputs); 1091 } 1092 1093 void FragmentOutputTests::init (void) 1094 { 1095 static const deUint32 requiredFloatFormats[] = 1096 { 1097 GL_RGBA32F, 1098 GL_RGBA16F, 1099 GL_R11F_G11F_B10F, 1100 GL_RG32F, 1101 GL_RG16F, 1102 GL_R32F, 1103 GL_R16F 1104 }; 1105 static const deUint32 requiredFixedFormats[] = 1106 { 1107 GL_RGBA8, 1108 GL_SRGB8_ALPHA8, 1109 GL_RGB10_A2, 1110 GL_RGBA4, 1111 GL_RGB5_A1, 1112 GL_RGB8, 1113 GL_RGB565, 1114 GL_RG8, 1115 GL_R8 1116 }; 1117 static const deUint32 requiredIntFormats[] = 1118 { 1119 GL_RGBA32I, 1120 GL_RGBA16I, 1121 GL_RGBA8I, 1122 GL_RG32I, 1123 GL_RG16I, 1124 GL_RG8I, 1125 GL_R32I, 1126 GL_R16I, 1127 GL_R8I 1128 }; 1129 static const deUint32 requiredUintFormats[] = 1130 { 1131 GL_RGBA32UI, 1132 GL_RGBA16UI, 1133 GL_RGBA8UI, 1134 GL_RGB10_A2UI, 1135 GL_RG32UI, 1136 GL_RG16UI, 1137 GL_RG8UI, 1138 GL_R32UI, 1139 GL_R16UI, 1140 GL_R8UI 1141 }; 1142 1143 static const glu::Precision precisions[] = 1144 { 1145 glu::PRECISION_LOWP, 1146 glu::PRECISION_MEDIUMP, 1147 glu::PRECISION_HIGHP 1148 }; 1149 1150 // .basic. 1151 { 1152 tcu::TestCaseGroup* basicGroup = new tcu::TestCaseGroup(m_testCtx, "basic", "Basic fragment output tests"); 1153 addChild(basicGroup); 1154 1155 const int width = 64; 1156 const int height = 64; 1157 const int samples = 0; 1158 1159 // .float 1160 tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point output tests"); 1161 basicGroup->addChild(floatGroup); 1162 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFloatFormats); fmtNdx++) 1163 { 1164 deUint32 format = requiredFloatFormats[fmtNdx]; 1165 string fmtName = getFormatName(format); 1166 vector<BufferSpec> fboSpec; 1167 1168 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1169 1170 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1171 { 1172 glu::Precision prec = precisions[precNdx]; 1173 string precName = glu::getPrecisionName(prec); 1174 1175 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0)).toVec())); 1176 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0)).toVec())); 1177 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0)).toVec())); 1178 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0)).toVec())); 1179 } 1180 } 1181 1182 // .fixed 1183 tcu::TestCaseGroup* fixedGroup = new tcu::TestCaseGroup(m_testCtx, "fixed", "Fixed-point output tests"); 1184 basicGroup->addChild(fixedGroup); 1185 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFixedFormats); fmtNdx++) 1186 { 1187 deUint32 format = requiredFixedFormats[fmtNdx]; 1188 string fmtName = getFormatName(format); 1189 vector<BufferSpec> fboSpec; 1190 1191 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1192 1193 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1194 { 1195 glu::Precision prec = precisions[precNdx]; 1196 string precName = glu::getPrecisionName(prec); 1197 1198 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0)).toVec())); 1199 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0)).toVec())); 1200 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0)).toVec())); 1201 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0)).toVec())); 1202 } 1203 } 1204 1205 // .int 1206 tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer output tests"); 1207 basicGroup->addChild(intGroup); 1208 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredIntFormats); fmtNdx++) 1209 { 1210 deUint32 format = requiredIntFormats[fmtNdx]; 1211 string fmtName = getFormatName(format); 1212 vector<BufferSpec> fboSpec; 1213 1214 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1215 1216 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1217 { 1218 glu::Precision prec = precisions[precNdx]; 1219 string precName = glu::getPrecisionName(prec); 1220 1221 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_int").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT, prec, 0)).toVec())); 1222 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC2, prec, 0)).toVec())); 1223 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC3, prec, 0)).toVec())); 1224 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC4, prec, 0)).toVec())); 1225 } 1226 } 1227 1228 // .uint 1229 tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Usigned integer output tests"); 1230 basicGroup->addChild(uintGroup); 1231 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredUintFormats); fmtNdx++) 1232 { 1233 deUint32 format = requiredUintFormats[fmtNdx]; 1234 string fmtName = getFormatName(format); 1235 vector<BufferSpec> fboSpec; 1236 1237 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1238 1239 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1240 { 1241 glu::Precision prec = precisions[precNdx]; 1242 string precName = glu::getPrecisionName(prec); 1243 1244 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uint").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT, prec, 0)).toVec())); 1245 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC2, prec, 0)).toVec())); 1246 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC3, prec, 0)).toVec())); 1247 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC4, prec, 0)).toVec())); 1248 } 1249 } 1250 } 1251 1252 // .array 1253 { 1254 tcu::TestCaseGroup* arrayGroup = new tcu::TestCaseGroup(m_testCtx, "array", "Array outputs"); 1255 addChild(arrayGroup); 1256 1257 const int width = 64; 1258 const int height = 64; 1259 const int samples = 0; 1260 const int numTargets = 3; 1261 1262 // .float 1263 tcu::TestCaseGroup* floatGroup = new tcu::TestCaseGroup(m_testCtx, "float", "Floating-point output tests"); 1264 arrayGroup->addChild(floatGroup); 1265 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFloatFormats); fmtNdx++) 1266 { 1267 deUint32 format = requiredFloatFormats[fmtNdx]; 1268 string fmtName = getFormatName(format); 1269 vector<BufferSpec> fboSpec; 1270 1271 for (int ndx = 0; ndx < numTargets; ndx++) 1272 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1273 1274 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1275 { 1276 glu::Precision prec = precisions[precNdx]; 1277 string precName = glu::getPrecisionName(prec); 1278 1279 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0, numTargets)).toVec())); 1280 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0, numTargets)).toVec())); 1281 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0, numTargets)).toVec())); 1282 floatGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0, numTargets)).toVec())); 1283 } 1284 } 1285 1286 // .fixed 1287 tcu::TestCaseGroup* fixedGroup = new tcu::TestCaseGroup(m_testCtx, "fixed", "Fixed-point output tests"); 1288 arrayGroup->addChild(fixedGroup); 1289 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredFixedFormats); fmtNdx++) 1290 { 1291 deUint32 format = requiredFixedFormats[fmtNdx]; 1292 string fmtName = getFormatName(format); 1293 vector<BufferSpec> fboSpec; 1294 1295 for (int ndx = 0; ndx < numTargets; ndx++) 1296 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1297 1298 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1299 { 1300 glu::Precision prec = precisions[precNdx]; 1301 string precName = glu::getPrecisionName(prec); 1302 1303 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_float").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT, prec, 0, numTargets)).toVec())); 1304 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC2, prec, 0, numTargets)).toVec())); 1305 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC3, prec, 0, numTargets)).toVec())); 1306 fixedGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_vec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_FLOAT_VEC4, prec, 0, numTargets)).toVec())); 1307 } 1308 } 1309 1310 // .int 1311 tcu::TestCaseGroup* intGroup = new tcu::TestCaseGroup(m_testCtx, "int", "Integer output tests"); 1312 arrayGroup->addChild(intGroup); 1313 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredIntFormats); fmtNdx++) 1314 { 1315 deUint32 format = requiredIntFormats[fmtNdx]; 1316 string fmtName = getFormatName(format); 1317 vector<BufferSpec> fboSpec; 1318 1319 for (int ndx = 0; ndx < numTargets; ndx++) 1320 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1321 1322 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1323 { 1324 glu::Precision prec = precisions[precNdx]; 1325 string precName = glu::getPrecisionName(prec); 1326 1327 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_int").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT, prec, 0, numTargets)).toVec())); 1328 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC2, prec, 0, numTargets)).toVec())); 1329 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC3, prec, 0, numTargets)).toVec())); 1330 intGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_ivec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_INT_VEC4, prec, 0, numTargets)).toVec())); 1331 } 1332 } 1333 1334 // .uint 1335 tcu::TestCaseGroup* uintGroup = new tcu::TestCaseGroup(m_testCtx, "uint", "Usigned integer output tests"); 1336 arrayGroup->addChild(uintGroup); 1337 for (int fmtNdx = 0; fmtNdx < DE_LENGTH_OF_ARRAY(requiredUintFormats); fmtNdx++) 1338 { 1339 deUint32 format = requiredUintFormats[fmtNdx]; 1340 string fmtName = getFormatName(format); 1341 vector<BufferSpec> fboSpec; 1342 1343 for (int ndx = 0; ndx < numTargets; ndx++) 1344 fboSpec.push_back(BufferSpec(format, width, height, samples)); 1345 1346 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1347 { 1348 glu::Precision prec = precisions[precNdx]; 1349 string precName = glu::getPrecisionName(prec); 1350 1351 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uint").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT, prec, 0, numTargets)).toVec())); 1352 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec2").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC2, prec, 0, numTargets)).toVec())); 1353 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec3").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC3, prec, 0, numTargets)).toVec())); 1354 uintGroup->addChild(new FragmentOutputCase(m_context, (fmtName + "_" + precName + "_uvec4").c_str(), "", fboSpec, (OutputVec() << FragmentOutput(glu::TYPE_UINT_VEC4, prec, 0, numTargets)).toVec())); 1355 } 1356 } 1357 } 1358 1359 // .random 1360 { 1361 tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Random fragment output cases"); 1362 addChild(randomGroup); 1363 1364 for (deUint32 seed = 0; seed < 100; seed++) 1365 randomGroup->addChild(createRandomCase(m_context, 2, 4, seed)); 1366 } 1367 } 1368 1369 } // Functional 1370 } // gles3 1371 } // deqp 1372