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