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 Transform feedback tests. 22 *//*--------------------------------------------------------------------*/ 23 24#include "es3fTransformFeedbackTests.hpp" 25#include "tcuTestLog.hpp" 26#include "tcuSurface.hpp" 27#include "tcuImageCompare.hpp" 28#include "tcuVector.hpp" 29#include "tcuFormatUtil.hpp" 30#include "tcuRenderTarget.hpp" 31#include "gluShaderUtil.hpp" 32#include "gluVarType.hpp" 33#include "gluVarTypeUtil.hpp" 34#include "gluPixelTransfer.hpp" 35#include "gluRenderContext.hpp" 36#include "gluShaderProgram.hpp" 37#include "gluObjectWrapper.hpp" 38#include "glwFunctions.hpp" 39#include "glwEnums.hpp" 40#include "deRandom.hpp" 41#include "deStringUtil.hpp" 42#include "deMemory.h" 43#include "deString.h" 44 45#include <set> 46#include <map> 47#include <algorithm> 48 49using std::string; 50using std::vector; 51using std::set; 52 53using std::map; 54using std::set; 55 56using tcu::TestLog; 57 58namespace deqp 59{ 60namespace gles3 61{ 62namespace Functional 63{ 64namespace TransformFeedback 65{ 66 67enum 68{ 69 VIEWPORT_WIDTH = 128, 70 VIEWPORT_HEIGHT = 128, 71 BUFFER_GUARD_MULTIPLIER = 2 //!< stride*BUFFER_GUARD_MULTIPLIER bytes are added to the end of tf buffer and used to check for overruns. 72}; 73 74enum Interpolation 75{ 76 INTERPOLATION_SMOOTH = 0, 77 INTERPOLATION_FLAT, 78 INTERPOLATION_CENTROID, 79 80 INTERPOLATION_LAST 81}; 82 83static const char* getInterpolationName (Interpolation interp) 84{ 85 switch (interp) 86 { 87 case INTERPOLATION_SMOOTH: return "smooth"; 88 case INTERPOLATION_FLAT: return "flat"; 89 case INTERPOLATION_CENTROID: return "centroid"; 90 default: 91 DE_ASSERT(false); 92 return DE_NULL; 93 } 94} 95 96struct Varying 97{ 98 Varying (const char* name_, const glu::VarType& type_, Interpolation interp_) 99 : name (name_) 100 , type (type_) 101 , interpolation (interp_) 102 { 103 } 104 105 std::string name; //!< Variable name. 106 glu::VarType type; //!< Variable type. 107 Interpolation interpolation; //!< Interpolation mode (smooth, flat, centroid). 108}; 109 110struct VaryingNameEquals 111{ 112 VaryingNameEquals (const std::string& name_) : name(name_) {} 113 bool operator() (const Varying& var) const { return var.name == name; } 114 115 std::string name; 116}; 117 118struct Attribute 119{ 120 Attribute (const std::string& name_, const glu::VarType& type_, int offset_) 121 : name (name_) 122 , type (type_) 123 , offset (offset_) 124 { 125 } 126 127 std::string name; 128 glu::VarType type; 129 int offset; 130}; 131 132struct AttributeNameEquals 133{ 134 AttributeNameEquals (const std::string& name_) : name(name_) {} 135 bool operator() (const Attribute& attr) const { return attr.name == name; } 136 137 std::string name; 138}; 139 140struct Output 141{ 142 Output (void) 143 : bufferNdx (0) 144 , offset (0) 145 { 146 } 147 148 std::string name; 149 glu::VarType type; 150 int bufferNdx; 151 int offset; 152 vector<const Attribute*> inputs; 153}; 154 155struct DrawCall 156{ 157 DrawCall (int numElements_, bool tfEnabled_) 158 : numElements (numElements_) 159 , transformFeedbackEnabled (tfEnabled_) 160 { 161 } 162 163 DrawCall (void) 164 : numElements (0) 165 , transformFeedbackEnabled (false) 166 { 167 } 168 169 int numElements; 170 bool transformFeedbackEnabled; 171}; 172 173std::ostream& operator<< (std::ostream& str, const DrawCall& call) 174{ 175 return str << "(" << call.numElements << ", " << (call.transformFeedbackEnabled ? "resumed" : "paused") << ")"; 176} 177 178class ProgramSpec 179{ 180public: 181 ProgramSpec (void); 182 ~ProgramSpec (void); 183 184 glu::StructType* createStruct (const char* name); 185 void addVarying (const char* name, const glu::VarType& type, Interpolation interp); 186 void addTransformFeedbackVarying (const char* name); 187 188 const vector<glu::StructType*>& getStructs (void) const { return m_structs; } 189 const vector<Varying>& getVaryings (void) const { return m_varyings; } 190 const vector<string>& getTransformFeedbackVaryings (void) const { return m_transformFeedbackVaryings; } 191 bool isPointSizeUsed (void) const; 192 193private: 194 ProgramSpec (const ProgramSpec& other); 195 ProgramSpec& operator= (const ProgramSpec& other); 196 197 vector<glu::StructType*> m_structs; 198 vector<Varying> m_varyings; 199 vector<string> m_transformFeedbackVaryings; 200}; 201 202// ProgramSpec 203 204ProgramSpec::ProgramSpec (void) 205{ 206} 207 208ProgramSpec::~ProgramSpec (void) 209{ 210 for (vector<glu::StructType*>::iterator i = m_structs.begin(); i != m_structs.end(); i++) 211 delete *i; 212} 213 214glu::StructType* ProgramSpec::createStruct (const char* name) 215{ 216 m_structs.reserve(m_structs.size()+1); 217 m_structs.push_back(new glu::StructType(name)); 218 return m_structs.back(); 219} 220 221void ProgramSpec::addVarying (const char* name, const glu::VarType& type, Interpolation interp) 222{ 223 m_varyings.push_back(Varying(name, type, interp)); 224} 225 226void ProgramSpec::addTransformFeedbackVarying (const char* name) 227{ 228 m_transformFeedbackVaryings.push_back(name); 229} 230 231bool ProgramSpec::isPointSizeUsed (void) const 232{ 233 return std::find(m_transformFeedbackVaryings.begin(), m_transformFeedbackVaryings.end(), "gl_PointSize") != m_transformFeedbackVaryings.end(); 234} 235 236static bool isProgramSupported (const glw::Functions& gl, const ProgramSpec& spec, deUint32 tfMode) 237{ 238 int maxVertexAttribs = 0; 239 int maxTfInterleavedComponents = 0; 240 int maxTfSeparateAttribs = 0; 241 int maxTfSeparateComponents = 0; 242 243 gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); 244 gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS, &maxTfInterleavedComponents); 245 gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxTfSeparateAttribs); 246 gl.getIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS, &maxTfSeparateComponents); 247 248 // Check vertex attribs. 249 int totalVertexAttribs = 1 /* a_position */ + (spec.isPointSizeUsed() ? 1 : 0); 250 for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++) 251 { 252 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&var->type); vecIter != glu::VectorTypeIterator::end(&var->type); vecIter++) 253 totalVertexAttribs += 1; 254 } 255 256 if (totalVertexAttribs > maxVertexAttribs) 257 return false; // Vertex attribute count exceeded. 258 259 // Check varyings. 260 int totalTfComponents = 0; 261 int totalTfAttribs = 0; 262 for (vector<string>::const_iterator iter = spec.getTransformFeedbackVaryings().begin(); iter != spec.getTransformFeedbackVaryings().end(); iter++) 263 { 264 const string& name = *iter; 265 int numComponents = 0; 266 267 if (name == "gl_Position") 268 numComponents = 4; 269 else if (name == "gl_PointSize") 270 numComponents = 1; 271 else 272 { 273 string varName = glu::parseVariableName(name.c_str()); 274 const Varying& varying = *std::find_if(spec.getVaryings().begin(), spec.getVaryings().end(), VaryingNameEquals(varName)); 275 glu::TypeComponentVector varPath; 276 277 glu::parseTypePath(name.c_str(), varying.type, varPath); 278 numComponents = glu::getVarType(varying.type, varPath).getScalarSize(); 279 } 280 281 if (tfMode == GL_SEPARATE_ATTRIBS && numComponents > maxTfSeparateComponents) 282 return false; // Per-attribute component count exceeded. 283 284 totalTfComponents += numComponents; 285 totalTfAttribs += 1; 286 } 287 288 if (tfMode == GL_SEPARATE_ATTRIBS && totalTfAttribs > maxTfSeparateAttribs) 289 return false; 290 291 if (tfMode == GL_INTERLEAVED_ATTRIBS && totalTfComponents > maxTfInterleavedComponents) 292 return false; 293 294 return true; 295} 296 297// Program 298 299static std::string getAttributeName (const char* varyingName, const glu::TypeComponentVector& path) 300{ 301 std::ostringstream str; 302 303 str << "a_" << (deStringBeginsWith(varyingName, "v_") ? varyingName+2 : varyingName); 304 305 for (glu::TypeComponentVector::const_iterator iter = path.begin(); iter != path.end(); iter++) 306 { 307 const char* prefix = DE_NULL; 308 309 switch (iter->type) 310 { 311 case glu::VarTypeComponent::STRUCT_MEMBER: prefix = "_m"; break; 312 case glu::VarTypeComponent::ARRAY_ELEMENT: prefix = "_e"; break; 313 case glu::VarTypeComponent::MATRIX_COLUMN: prefix = "_c"; break; 314 case glu::VarTypeComponent::VECTOR_COMPONENT: prefix = "_s"; break; 315 default: 316 DE_ASSERT(false); 317 } 318 319 str << prefix << iter->index; 320 } 321 322 return str.str(); 323} 324 325static void genShaderSources (const ProgramSpec& spec, std::string& vertSource, std::string& fragSource, bool pointSizeRequired) 326{ 327 std::ostringstream vtx; 328 std::ostringstream frag; 329 bool addPointSize = spec.isPointSizeUsed(); 330 331 vtx << "#version 300 es\n" 332 << "in highp vec4 a_position;\n"; 333 frag << "#version 300 es\n" 334 << "layout(location = 0) out mediump vec4 o_color;\n" 335 << "uniform highp vec4 u_scale;\n" 336 << "uniform highp vec4 u_bias;\n"; 337 338 if (addPointSize) 339 vtx << "in highp float a_pointSize;\n"; 340 341 // Declare attributes. 342 for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++) 343 { 344 const char* name = var->name.c_str(); 345 const glu::VarType& type = var->type; 346 347 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&type); vecIter != glu::VectorTypeIterator::end(&type); vecIter++) 348 { 349 glu::VarType attribType = glu::getVarType(type, vecIter.getPath()); 350 string attribName = getAttributeName(name, vecIter.getPath()); 351 352 vtx << "in " << glu::declare(attribType, attribName.c_str()) << ";\n"; 353 } 354 } 355 356 // Declare vayrings. 357 for (int ndx = 0; ndx < 2; ndx++) 358 { 359 const char* inout = ndx ? "in" : "out"; 360 std::ostringstream& str = ndx ? frag : vtx; 361 362 // Declare structs that have type name. 363 for (vector<glu::StructType*>::const_iterator structIter = spec.getStructs().begin(); structIter != spec.getStructs().end(); structIter++) 364 { 365 const glu::StructType* structPtr = *structIter; 366 if (structPtr->hasTypeName()) 367 str << glu::declare(structPtr) << ";\n"; 368 } 369 370 for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++) 371 str << getInterpolationName(var->interpolation) << " " << inout << " " << glu::declare(var->type, var->name.c_str()) << ";\n"; 372 } 373 374 vtx << "\nvoid main (void)\n{\n" 375 << "\tgl_Position = a_position;\n"; 376 frag << "\nvoid main (void)\n{\n" 377 << "\thighp vec4 res = vec4(0.0);\n"; 378 379 if (addPointSize) 380 vtx << "\tgl_PointSize = a_pointSize;\n"; 381 else if (pointSizeRequired) 382 vtx << "\tgl_PointSize = 1.0;\n"; 383 384 // Generate assignments / usage. 385 for (vector<Varying>::const_iterator var = spec.getVaryings().begin(); var != spec.getVaryings().end(); var++) 386 { 387 const char* name = var->name.c_str(); 388 const glu::VarType& type = var->type; 389 390 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&type); vecIter != glu::VectorTypeIterator::end(&type); vecIter++) 391 { 392 glu::VarType subType = glu::getVarType(type, vecIter.getPath()); 393 string attribName = getAttributeName(name, vecIter.getPath()); 394 395 DE_ASSERT(subType.isBasicType() && glu::isDataTypeScalarOrVector(subType.getBasicType())); 396 397 // Vertex: assign from attribute. 398 vtx << "\t" << name << vecIter << " = " << attribName << ";\n"; 399 400 // Fragment: add to res variable. 401 int scalarSize = glu::getDataTypeScalarSize(subType.getBasicType()); 402 403 frag << "\tres += "; 404 if (scalarSize == 1) frag << "vec4(" << name << vecIter << ")"; 405 else if (scalarSize == 2) frag << "vec2(" << name << vecIter << ").xxyy"; 406 else if (scalarSize == 3) frag << "vec3(" << name << vecIter << ").xyzx"; 407 else if (scalarSize == 4) frag << "vec4(" << name << vecIter << ")"; 408 409 frag << ";\n"; 410 } 411 } 412 413 frag << "\to_color = res * u_scale + u_bias;\n"; 414 415 vtx << "}\n"; 416 frag << "}\n"; 417 418 vertSource = vtx.str(); 419 fragSource = frag.str(); 420} 421 422static glu::ShaderProgram* createVertexCaptureProgram (const glu::RenderContext& context, const ProgramSpec& spec, deUint32 bufferMode, deUint32 primitiveType) 423{ 424 std::string vertSource, fragSource; 425 426 genShaderSources(spec, vertSource, fragSource, primitiveType == GL_POINTS /* Is point size required? */); 427 428 return new glu::ShaderProgram(context, glu::ProgramSources() 429 << glu::VertexSource(vertSource) 430 << glu::FragmentSource(fragSource) 431 << glu::TransformFeedbackVaryings<vector<string>::const_iterator>(spec.getTransformFeedbackVaryings().begin(), spec.getTransformFeedbackVaryings().end()) 432 << glu::TransformFeedbackMode(bufferMode)); 433} 434 435// Helpers. 436 437static void computeInputLayout (vector<Attribute>& attributes, int& inputStride, const vector<Varying>& varyings, bool usePointSize) 438{ 439 inputStride = 0; 440 441 // Add position. 442 attributes.push_back(Attribute("a_position", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP), inputStride)); 443 inputStride += 4*sizeof(deUint32); 444 445 if (usePointSize) 446 { 447 attributes.push_back(Attribute("a_pointSize", glu::VarType(glu::TYPE_FLOAT, glu::PRECISION_HIGHP), inputStride)); 448 inputStride += 1*sizeof(deUint32); 449 } 450 451 // Compute attribute vector. 452 for (vector<Varying>::const_iterator var = varyings.begin(); var != varyings.end(); var++) 453 { 454 for (glu::VectorTypeIterator vecIter = glu::VectorTypeIterator::begin(&var->type); vecIter != glu::VectorTypeIterator::end(&var->type); vecIter++) 455 { 456 glu::VarType type = vecIter.getType(); 457 string name = getAttributeName(var->name.c_str(), vecIter.getPath()); 458 459 attributes.push_back(Attribute(name, type, inputStride)); 460 inputStride += glu::getDataTypeScalarSize(type.getBasicType())*sizeof(deUint32); 461 } 462 } 463} 464 465static void computeTransformFeedbackOutputs (vector<Output>& transformFeedbackOutputs, const vector<Attribute>& attributes, const vector<Varying>& varyings, const vector<string>& transformFeedbackVaryings, deUint32 bufferMode) 466{ 467 int accumulatedSize = 0; 468 469 transformFeedbackOutputs.resize(transformFeedbackVaryings.size()); 470 for (int varNdx = 0; varNdx < (int)transformFeedbackVaryings.size(); varNdx++) 471 { 472 const string& name = transformFeedbackVaryings[varNdx]; 473 int bufNdx = (bufferMode == GL_SEPARATE_ATTRIBS ? varNdx : 0); 474 int offset = (bufferMode == GL_SEPARATE_ATTRIBS ? 0 : accumulatedSize); 475 Output& output = transformFeedbackOutputs[varNdx]; 476 477 output.name = name; 478 output.bufferNdx = bufNdx; 479 output.offset = offset; 480 481 if (name == "gl_Position") 482 { 483 const Attribute* posIn = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_position"))); 484 output.type = posIn->type; 485 output.inputs.push_back(posIn); 486 } 487 else if (name == "gl_PointSize") 488 { 489 const Attribute* sizeIn = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_pointSize"))); 490 output.type = sizeIn->type; 491 output.inputs.push_back(sizeIn); 492 } 493 else 494 { 495 string varName = glu::parseVariableName(name.c_str()); 496 const Varying& varying = *std::find_if(varyings.begin(), varyings.end(), VaryingNameEquals(varName)); 497 glu::TypeComponentVector varPath; 498 499 glu::parseTypePath(name.c_str(), varying.type, varPath); 500 501 output.type = glu::getVarType(varying.type, varPath); 502 503 // Add all vectorized attributes as inputs. 504 for (glu::VectorTypeIterator iter = glu::VectorTypeIterator::begin(&output.type); iter != glu::VectorTypeIterator::end(&output.type); iter++) 505 { 506 // Full path. 507 glu::TypeComponentVector fullPath(varPath.size() + iter.getPath().size()); 508 509 std::copy(varPath.begin(), varPath.end(), fullPath.begin()); 510 std::copy(iter.getPath().begin(), iter.getPath().end(), fullPath.begin()+varPath.size()); 511 512 string attribName = getAttributeName(varName.c_str(), fullPath); 513 const Attribute* attrib = &(*std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals(attribName))); 514 515 output.inputs.push_back(attrib); 516 } 517 } 518 519 accumulatedSize += output.type.getScalarSize()*sizeof(deUint32); 520 } 521} 522 523static void genAttributeData (const Attribute& attrib, deUint8* basePtr, int stride, int numElements, de::Random& rnd) 524{ 525 const int elementSize = (int)sizeof(deUint32); 526 bool isFloat = glu::isDataTypeFloatOrVec(attrib.type.getBasicType()); 527 bool isInt = glu::isDataTypeIntOrIVec(attrib.type.getBasicType()); 528 bool isUint = glu::isDataTypeIntOrIVec(attrib.type.getBasicType()); 529 glu::Precision precision = attrib.type.getPrecision(); 530 int numComps = glu::getDataTypeScalarSize(attrib.type.getBasicType()); 531 532 for (int elemNdx = 0; elemNdx < numElements; elemNdx++) 533 { 534 for (int compNdx = 0; compNdx < numComps; compNdx++) 535 { 536 int offset = attrib.offset+elemNdx*stride+compNdx*elementSize; 537 if (isFloat) 538 { 539 float* comp = (float*)(basePtr+offset); 540 switch (precision) 541 { 542 case glu::PRECISION_LOWP: *comp = 0.0f + 0.25f*(float)rnd.getInt(0, 4); break; 543 case glu::PRECISION_MEDIUMP: *comp = rnd.getFloat(-1e3f, 1e3f); break; 544 case glu::PRECISION_HIGHP: *comp = rnd.getFloat(-1e5f, 1e5f); break; 545 default: 546 DE_ASSERT(false); 547 } 548 } 549 else if (isInt) 550 { 551 int* comp = (int*)(basePtr+offset); 552 switch (precision) 553 { 554 case glu::PRECISION_LOWP: *comp = (int)(rnd.getUint32()&0xff) << 24 >> 24; break; 555 case glu::PRECISION_MEDIUMP: *comp = (int)(rnd.getUint32()&0xffff) << 16 >> 16; break; 556 case glu::PRECISION_HIGHP: *comp = (int)rnd.getUint32(); break; 557 default: 558 DE_ASSERT(false); 559 } 560 } 561 else if (isUint) 562 { 563 deUint32* comp = (deUint32*)(basePtr+offset); 564 switch (precision) 565 { 566 case glu::PRECISION_LOWP: *comp = rnd.getUint32()&0xff; break; 567 case glu::PRECISION_MEDIUMP: *comp = rnd.getUint32()&0xffff; break; 568 case glu::PRECISION_HIGHP: *comp = rnd.getUint32(); break; 569 default: 570 DE_ASSERT(false); 571 } 572 } 573 } 574 } 575} 576 577static void genInputData (const vector<Attribute>& attributes, int numInputs, int inputStride, deUint8* inputBasePtr, de::Random& rnd) 578{ 579 // Random positions. 580 const Attribute& position = *std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_position")); 581 582 for (int ndx = 0; ndx < numInputs; ndx++) 583 { 584 deUint8* ptr = inputBasePtr + position.offset + inputStride*ndx; 585 *((float*)(ptr+ 0)) = rnd.getFloat(-1.2f, 1.2f); 586 *((float*)(ptr+ 4)) = rnd.getFloat(-1.2f, 1.2f); 587 *((float*)(ptr+ 8)) = rnd.getFloat(-1.2f, 1.2f); 588 *((float*)(ptr+12)) = rnd.getFloat(0.1f, 2.0f); 589 } 590 591 // Point size. 592 vector<Attribute>::const_iterator pointSizePos = std::find_if(attributes.begin(), attributes.end(), AttributeNameEquals("a_pointSize")); 593 if (pointSizePos != attributes.end()) 594 { 595 for (int ndx = 0; ndx < numInputs; ndx++) 596 { 597 deUint8* ptr = inputBasePtr + pointSizePos->offset + inputStride*ndx; 598 *((float*)ptr) = rnd.getFloat(1.0f, 8.0f); 599 } 600 } 601 602 // Random data for rest of components. 603 for (vector<Attribute>::const_iterator attrib = attributes.begin(); attrib != attributes.end(); attrib++) 604 { 605 if (attrib->name == "a_position" || attrib->name == "a_pointSize") 606 continue; 607 608 genAttributeData(*attrib, inputBasePtr, inputStride, numInputs, rnd); 609 } 610} 611 612static deUint32 getTransformFeedbackOutputCount (deUint32 primitiveType, int numElements) 613{ 614 switch (primitiveType) 615 { 616 case GL_TRIANGLES: return numElements - numElements%3; 617 case GL_TRIANGLE_STRIP: return de::max(0, numElements-2)*3; 618 case GL_TRIANGLE_FAN: return de::max(0, numElements-2)*3; 619 case GL_LINES: return numElements - numElements%2; 620 case GL_LINE_STRIP: return de::max(0, numElements-1)*2; 621 case GL_LINE_LOOP: return numElements > 1 ? numElements*2 : 0; 622 case GL_POINTS: return numElements; 623 624 default: 625 DE_ASSERT(false); 626 return 0; 627 } 628} 629 630static deUint32 getTransformFeedbackPrimitiveCount (deUint32 primitiveType, int numElements) 631{ 632 switch (primitiveType) 633 { 634 case GL_TRIANGLES: return numElements/3; 635 case GL_TRIANGLE_STRIP: return de::max(0, numElements-2); 636 case GL_TRIANGLE_FAN: return de::max(0, numElements-2); 637 case GL_LINES: return numElements/2; 638 case GL_LINE_STRIP: return de::max(0, numElements-1); 639 case GL_LINE_LOOP: return numElements > 1 ? numElements : 0; 640 case GL_POINTS: return numElements; 641 642 default: 643 DE_ASSERT(false); 644 return 0; 645 } 646} 647 648static deUint32 getTransformFeedbackPrimitiveMode (deUint32 primitiveType) 649{ 650 switch (primitiveType) 651 { 652 case GL_TRIANGLES: 653 case GL_TRIANGLE_STRIP: 654 case GL_TRIANGLE_FAN: 655 return GL_TRIANGLES; 656 657 case GL_LINES: 658 case GL_LINE_LOOP: 659 case GL_LINE_STRIP: 660 return GL_LINES; 661 662 case GL_POINTS: 663 return GL_POINTS; 664 665 default: 666 DE_ASSERT(false); 667 return 0; 668 } 669} 670 671static int getAttributeIndex (deUint32 primitiveType, int numInputs, int outNdx) 672{ 673 switch (primitiveType) 674 { 675 case GL_TRIANGLES: return outNdx; 676 case GL_LINES: return outNdx; 677 case GL_POINTS: return outNdx; 678 679 case GL_TRIANGLE_STRIP: 680 { 681 int triNdx = outNdx/3; 682 int vtxNdx = outNdx%3; 683 return (triNdx%2 != 0 && vtxNdx < 2) ? (triNdx+1-vtxNdx) : (triNdx+vtxNdx); 684 } 685 686 case GL_TRIANGLE_FAN: 687 return (outNdx%3 != 0) ? (outNdx/3 + outNdx%3) : 0; 688 689 case GL_LINE_STRIP: 690 return outNdx/2 + outNdx%2; 691 692 case GL_LINE_LOOP: 693 { 694 int inNdx = outNdx/2 + outNdx%2; 695 return inNdx < numInputs ? inNdx : 0; 696 } 697 698 default: 699 DE_ASSERT(false); 700 return 0; 701 } 702} 703 704static bool compareTransformFeedbackOutput (tcu::TestLog& log, deUint32 primitiveType, const Output& output, int numInputs, const deUint8* inBasePtr, int inStride, const deUint8* outBasePtr, int outStride) 705{ 706 bool isOk = true; 707 int outOffset = output.offset; 708 709 for (int attrNdx = 0; attrNdx < (int)output.inputs.size(); attrNdx++) 710 { 711 const Attribute& attribute = *output.inputs[attrNdx]; 712 glu::DataType type = attribute.type.getBasicType(); 713 int numComponents = glu::getDataTypeScalarSize(type); 714 glu::Precision precision = attribute.type.getPrecision(); 715 glu::DataType scalarType = glu::getDataTypeScalarType(type); 716 int numOutputs = getTransformFeedbackOutputCount(primitiveType, numInputs); 717 718 for (int outNdx = 0; outNdx < numOutputs; outNdx++) 719 { 720 int inNdx = getAttributeIndex(primitiveType, numInputs, outNdx); 721 722 for (int compNdx = 0; compNdx < numComponents; compNdx++) 723 { 724 const deUint8* inPtr = inBasePtr + inStride*inNdx + attribute.offset + compNdx*sizeof(deUint32); 725 const deUint8* outPtr = outBasePtr + outStride*outNdx + outOffset + compNdx*sizeof(deUint32); 726 deUint32 inVal = *(const deUint32*)inPtr; 727 deUint32 outVal = *(const deUint32*)outPtr; 728 bool isEqual = false; 729 730 if (scalarType == glu::TYPE_FLOAT) 731 { 732 // ULP comparison is used for highp and mediump. Lowp uses threshold-comparison. 733 switch (precision) 734 { 735 case glu::PRECISION_HIGHP: isEqual = de::abs((int)inVal - (int)outVal) < 2; break; 736 case glu::PRECISION_MEDIUMP: isEqual = de::abs((int)inVal - (int)outVal) < 2+(1<<13); break; 737 case glu::PRECISION_LOWP: 738 { 739 float inF = *(const float*)inPtr; 740 float outF = *(const float*)outPtr; 741 isEqual = de::abs(inF - outF) < 0.1f; 742 break; 743 } 744 default: 745 DE_ASSERT(false); 746 } 747 } 748 else 749 isEqual = (inVal == outVal); // Bit-exact match required for integer types. 750 751 if (!isEqual) 752 { 753 log << TestLog::Message << "Mismatch in " << output.name << " (" << attribute.name << "), output = " << outNdx << ", input = " << inNdx << ", component = " << compNdx << TestLog::EndMessage; 754 isOk = false; 755 break; 756 } 757 } 758 759 if (!isOk) 760 break; 761 } 762 763 if (!isOk) 764 break; 765 766 outOffset += numComponents*sizeof(deUint32); 767 } 768 769 return isOk; 770} 771 772static int computeTransformFeedbackPrimitiveCount (deUint32 primitiveType, const DrawCall* first, const DrawCall* end) 773{ 774 int primCount = 0; 775 776 for (const DrawCall* call = first; call != end; ++call) 777 { 778 if (call->transformFeedbackEnabled) 779 primCount += getTransformFeedbackPrimitiveCount(primitiveType, call->numElements); 780 } 781 782 return primCount; 783} 784 785static void writeBufferGuard (const glw::Functions& gl, deUint32 target, int bufferSize, int guardSize) 786{ 787 deUint8* ptr = (deUint8*)gl.mapBufferRange(target, bufferSize, guardSize, GL_MAP_WRITE_BIT); 788 if (ptr) 789 deMemset(ptr, 0xcd, guardSize); 790 gl.unmapBuffer(target); 791 GLU_EXPECT_NO_ERROR(gl.getError(), "guardband write"); 792} 793 794static bool verifyGuard (const deUint8* ptr, int guardSize) 795{ 796 for (int ndx = 0; ndx < guardSize; ndx++) 797 { 798 if (ptr[ndx] != 0xcd) 799 return false; 800 } 801 return true; 802} 803 804static void logTransformFeedbackVaryings (TestLog& log, const glw::Functions& gl, deUint32 program) 805{ 806 int numTfVaryings = 0; 807 int maxNameLen = 0; 808 809 gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &numTfVaryings); 810 gl.getProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &maxNameLen); 811 GLU_EXPECT_NO_ERROR(gl.getError(), "Query TF varyings"); 812 813 log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_VARYINGS = " << numTfVaryings << TestLog::EndMessage; 814 815 vector<char> nameBuf(maxNameLen+1); 816 817 for (int ndx = 0; ndx < numTfVaryings; ndx++) 818 { 819 glw::GLsizei size = 0; 820 glw::GLenum type = 0; 821 822 gl.getTransformFeedbackVarying(program, ndx, (glw::GLsizei)nameBuf.size(), DE_NULL, &size, &type, &nameBuf[0]); 823 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetTransformFeedbackVarying()"); 824 825 const glu::DataType dataType = glu::getDataTypeFromGLType(type); 826 const std::string typeName = dataType != glu::TYPE_LAST ? std::string(glu::getDataTypeName(dataType)) 827 : (std::string("unknown(") + tcu::toHex(type).toString() + ")"); 828 829 log << TestLog::Message << (const char*)&nameBuf[0] << ": " << typeName << "[" << size << "]" << TestLog::EndMessage; 830 } 831} 832 833class TransformFeedbackCase : public TestCase 834{ 835public: 836 TransformFeedbackCase (Context& context, const char* name, const char* desc, deUint32 bufferMode, deUint32 primitiveType); 837 ~TransformFeedbackCase (void); 838 839 void init (void); 840 void deinit (void); 841 IterateResult iterate (void); 842 843protected: 844 ProgramSpec m_progSpec; 845 deUint32 m_bufferMode; 846 deUint32 m_primitiveType; 847 848private: 849 TransformFeedbackCase (const TransformFeedbackCase& other); 850 TransformFeedbackCase& operator= (const TransformFeedbackCase& other); 851 852 bool runTest (const DrawCall* first, const DrawCall* end, deUint32 seed); 853 854 // Derived from ProgramSpec in init() 855 int m_inputStride; 856 vector<Attribute> m_attributes; 857 vector<Output> m_transformFeedbackOutputs; 858 vector<int> m_bufferStrides; 859 860 // GL state. 861 glu::ShaderProgram* m_program; 862 glu::TransformFeedback* m_transformFeedback; 863 vector<deUint32> m_outputBuffers; 864 865 int m_iterNdx; 866}; 867 868TransformFeedbackCase::TransformFeedbackCase (Context& context, const char* name, const char* desc, deUint32 bufferMode, deUint32 primitiveType) 869 : TestCase (context, name, desc) 870 , m_bufferMode (bufferMode) 871 , m_primitiveType (primitiveType) 872 , m_inputStride (0) 873 , m_program (DE_NULL) 874 , m_transformFeedback (DE_NULL) 875 , m_iterNdx (0) 876{ 877} 878 879TransformFeedbackCase::~TransformFeedbackCase (void) 880{ 881 TransformFeedbackCase::deinit(); 882} 883 884static bool hasArraysInTFVaryings (const ProgramSpec& spec) 885{ 886 for (vector<string>::const_iterator tfVar = spec.getTransformFeedbackVaryings().begin(); tfVar != spec.getTransformFeedbackVaryings().end(); ++tfVar) 887 { 888 string varName = glu::parseVariableName(tfVar->c_str()); 889 vector<Varying>::const_iterator varIter = std::find_if(spec.getVaryings().begin(), spec.getVaryings().end(), VaryingNameEquals(varName)); 890 891 if (varName == "gl_Position" || varName == "gl_PointSize") 892 continue; 893 894 DE_ASSERT(varIter != spec.getVaryings().end()); 895 896 if (varIter->type.isArrayType()) 897 return true; 898 } 899 900 return false; 901} 902 903void TransformFeedbackCase::init (void) 904{ 905 TestLog& log = m_testCtx.getLog(); 906 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 907 908 DE_ASSERT(!m_program); 909 m_program = createVertexCaptureProgram(m_context.getRenderContext(), m_progSpec, m_bufferMode, m_primitiveType); 910 911 log << *m_program; 912 if (!m_program->isOk()) 913 { 914 const bool linkFail = m_program->getShaderInfo(glu::SHADERTYPE_VERTEX).compileOk && 915 m_program->getShaderInfo(glu::SHADERTYPE_FRAGMENT).compileOk && 916 !m_program->getProgramInfo().linkOk; 917 918 if (linkFail) 919 { 920 if (!isProgramSupported(gl, m_progSpec, m_bufferMode)) 921 throw tcu::NotSupportedError("Implementation limits execeeded", "", __FILE__, __LINE__); 922 else if (hasArraysInTFVaryings(m_progSpec)) 923 throw tcu::NotSupportedError("Capturing arrays is not supported (undefined in specification)", "", __FILE__, __LINE__); 924 else 925 throw tcu::TestError("Link failed", "", __FILE__, __LINE__); 926 } 927 else 928 throw tcu::TestError("Compile failed", "", __FILE__, __LINE__); 929 } 930 931 log << TestLog::Message << "Transform feedback varyings: " << tcu::formatArray(m_progSpec.getTransformFeedbackVaryings().begin(), m_progSpec.getTransformFeedbackVaryings().end()) << TestLog::EndMessage; 932 933 // Print out transform feedback points reported by GL. 934 log << TestLog::Message << "Transform feedback varyings reported by compiler:" << TestLog::EndMessage; 935 logTransformFeedbackVaryings(log, gl, m_program->getProgram()); 936 937 // Compute input specification. 938 computeInputLayout(m_attributes, m_inputStride, m_progSpec.getVaryings(), m_progSpec.isPointSizeUsed()); 939 940 // Build list of varyings used in transform feedback. 941 computeTransformFeedbackOutputs(m_transformFeedbackOutputs, m_attributes, m_progSpec.getVaryings(), m_progSpec.getTransformFeedbackVaryings(), m_bufferMode); 942 DE_ASSERT(!m_transformFeedbackOutputs.empty()); 943 944 // Buffer strides. 945 DE_ASSERT(m_bufferStrides.empty()); 946 if (m_bufferMode == GL_SEPARATE_ATTRIBS) 947 { 948 for (vector<Output>::const_iterator outIter = m_transformFeedbackOutputs.begin(); outIter != m_transformFeedbackOutputs.end(); outIter++) 949 m_bufferStrides.push_back(outIter->type.getScalarSize()*sizeof(deUint32)); 950 } 951 else 952 { 953 int totalSize = 0; 954 for (vector<Output>::const_iterator outIter = m_transformFeedbackOutputs.begin(); outIter != m_transformFeedbackOutputs.end(); outIter++) 955 totalSize += outIter->type.getScalarSize()*sizeof(deUint32); 956 957 m_bufferStrides.push_back(totalSize); 958 } 959 960 // \note Actual storage is allocated in iterate(). 961 m_outputBuffers.resize(m_bufferStrides.size()); 962 gl.genBuffers((glw::GLsizei)m_outputBuffers.size(), &m_outputBuffers[0]); 963 964 DE_ASSERT(!m_transformFeedback); 965 m_transformFeedback = new glu::TransformFeedback(m_context.getRenderContext()); 966 967 GLU_EXPECT_NO_ERROR(gl.getError(), "init"); 968 969 m_iterNdx = 0; 970 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 971} 972 973void TransformFeedbackCase::deinit (void) 974{ 975 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 976 977 if (!m_outputBuffers.empty()) 978 { 979 gl.deleteBuffers((glw::GLsizei)m_outputBuffers.size(), &m_outputBuffers[0]); 980 m_outputBuffers.clear(); 981 } 982 983 delete m_transformFeedback; 984 m_transformFeedback = DE_NULL; 985 986 delete m_program; 987 m_program = DE_NULL; 988 989 // Clean up state. 990 m_attributes.clear(); 991 m_transformFeedbackOutputs.clear(); 992 m_bufferStrides.clear(); 993 m_inputStride = 0; 994} 995 996TransformFeedbackCase::IterateResult TransformFeedbackCase::iterate (void) 997{ 998 // Test cases. 999 static const DrawCall s_elemCount1[] = { DrawCall(1, true) }; 1000 static const DrawCall s_elemCount2[] = { DrawCall(2, true) }; 1001 static const DrawCall s_elemCount3[] = { DrawCall(3, true) }; 1002 static const DrawCall s_elemCount4[] = { DrawCall(4, true) }; 1003 static const DrawCall s_elemCount123[] = { DrawCall(123, true) }; 1004 static const DrawCall s_basicPause1[] = { DrawCall(64, true), DrawCall(64, false), DrawCall(64, true) }; 1005 static const DrawCall s_basicPause2[] = { DrawCall(13, true), DrawCall(5, true), DrawCall(17, false), DrawCall(3, true), DrawCall(7, false) }; 1006 static const DrawCall s_startPaused[] = { DrawCall(123, false), DrawCall(123, true) }; 1007 static const DrawCall s_random1[] = { DrawCall(65, true), DrawCall(135, false), DrawCall(74, true), DrawCall(16, false), DrawCall(226, false), DrawCall(9, true), DrawCall(174, false) }; 1008 static const DrawCall s_random2[] = { DrawCall(217, true), DrawCall(171, true), DrawCall(147, true), DrawCall(152, false), DrawCall(55, true) }; 1009 1010 static const struct 1011 { 1012 const DrawCall* calls; 1013 int numCalls; 1014 } s_iterations[] = 1015 { 1016#define ITER(ARR) { ARR, DE_LENGTH_OF_ARRAY(ARR) } 1017 ITER(s_elemCount1), 1018 ITER(s_elemCount2), 1019 ITER(s_elemCount3), 1020 ITER(s_elemCount4), 1021 ITER(s_elemCount123), 1022 ITER(s_basicPause1), 1023 ITER(s_basicPause2), 1024 ITER(s_startPaused), 1025 ITER(s_random1), 1026 ITER(s_random2) 1027#undef ITER 1028 }; 1029 1030 TestLog& log = m_testCtx.getLog(); 1031 bool isOk = true; 1032 deUint32 seed = deStringHash(getName()) ^ deInt32Hash(m_iterNdx); 1033 int numIterations = DE_LENGTH_OF_ARRAY(s_iterations); 1034 const DrawCall* first = s_iterations[m_iterNdx].calls; 1035 const DrawCall* end = s_iterations[m_iterNdx].calls + s_iterations[m_iterNdx].numCalls; 1036 1037 std::string sectionName = std::string("Iteration") + de::toString(m_iterNdx+1); 1038 std::string sectionDesc = std::string("Iteration ") + de::toString(m_iterNdx+1) + " / " + de::toString(numIterations); 1039 tcu::ScopedLogSection section (log, sectionName, sectionDesc); 1040 1041 log << TestLog::Message << "Testing " << s_iterations[m_iterNdx].numCalls << " draw calls, (element count, TF state): " << tcu::formatArray(first, end) << TestLog::EndMessage; 1042 1043 isOk = runTest(first, end, seed); 1044 1045 if (!isOk) 1046 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Result comparison failed"); 1047 1048 m_iterNdx += 1; 1049 return (isOk && m_iterNdx < numIterations) ? CONTINUE : STOP; 1050} 1051 1052bool TransformFeedbackCase::runTest (const DrawCall* first, const DrawCall* end, deUint32 seed) 1053{ 1054 TestLog& log = m_testCtx.getLog(); 1055 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1056 de::Random rnd (seed); 1057 int numInputs = 0; //!< Sum of element counts in calls. 1058 int numOutputs = 0; //!< Sum of output counts for calls that have transform feedback enabled. 1059 int width = m_context.getRenderContext().getRenderTarget().getWidth(); 1060 int height = m_context.getRenderContext().getRenderTarget().getHeight(); 1061 int viewportW = de::min((int)VIEWPORT_WIDTH, width); 1062 int viewportH = de::min((int)VIEWPORT_HEIGHT, height); 1063 int viewportX = rnd.getInt(0, width-viewportW); 1064 int viewportY = rnd.getInt(0, height-viewportH); 1065 tcu::Surface frameWithTf (viewportW, viewportH); 1066 tcu::Surface frameWithoutTf (viewportW, viewportH); 1067 glu::Query primitiveQuery (m_context.getRenderContext()); 1068 bool outputsOk = true; 1069 bool imagesOk = true; 1070 bool queryOk = true; 1071 1072 // Compute totals. 1073 for (const DrawCall* call = first; call != end; call++) 1074 { 1075 numInputs += call->numElements; 1076 numOutputs += call->transformFeedbackEnabled ? getTransformFeedbackOutputCount(m_primitiveType, call->numElements) : 0; 1077 } 1078 1079 // Input data. 1080 vector<deUint8> inputData(m_inputStride*numInputs); 1081 genInputData(m_attributes, numInputs, m_inputStride, &inputData[0], rnd); 1082 1083 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, m_transformFeedback->get()); 1084 GLU_EXPECT_NO_ERROR(gl.getError(), "glBindTransformFeedback()"); 1085 1086 // Allocate storage for transform feedback output buffers and bind to targets. 1087 for (int bufNdx = 0; bufNdx < (int)m_outputBuffers.size(); bufNdx++) 1088 { 1089 deUint32 buffer = m_outputBuffers[bufNdx]; 1090 int stride = m_bufferStrides[bufNdx]; 1091 int target = bufNdx; 1092 int size = stride*numOutputs; 1093 int guardSize = stride*BUFFER_GUARD_MULTIPLIER; 1094 const deUint32 usage = GL_DYNAMIC_READ; 1095 1096 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer); 1097 gl.bufferData(GL_TRANSFORM_FEEDBACK_BUFFER, size+guardSize, DE_NULL, usage); 1098 writeBufferGuard(gl, GL_TRANSFORM_FEEDBACK_BUFFER, size, guardSize); 1099 1100 // \todo [2012-07-30 pyry] glBindBufferRange()? 1101 gl.bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, target, buffer); 1102 1103 GLU_EXPECT_NO_ERROR(gl.getError(), "transform feedback buffer setup"); 1104 } 1105 1106 // Setup attributes. 1107 for (vector<Attribute>::const_iterator attrib = m_attributes.begin(); attrib != m_attributes.end(); attrib++) 1108 { 1109 int loc = gl.getAttribLocation(m_program->getProgram(), attrib->name.c_str()); 1110 glu::DataType scalarType = glu::getDataTypeScalarType(attrib->type.getBasicType()); 1111 int numComponents = glu::getDataTypeScalarSize(attrib->type.getBasicType()); 1112 const void* ptr = &inputData[0] + attrib->offset; 1113 1114 if (loc >= 0) 1115 { 1116 gl.enableVertexAttribArray(loc); 1117 1118 if (scalarType == glu::TYPE_FLOAT) gl.vertexAttribPointer (loc, numComponents, GL_FLOAT, GL_FALSE, m_inputStride, ptr); 1119 else if (scalarType == glu::TYPE_INT) gl.vertexAttribIPointer (loc, numComponents, GL_INT, m_inputStride, ptr); 1120 else if (scalarType == glu::TYPE_UINT) gl.vertexAttribIPointer (loc, numComponents, GL_UNSIGNED_INT, m_inputStride, ptr); 1121 } 1122 } 1123 1124 // Setup viewport. 1125 gl.viewport(viewportX, viewportY, viewportW, viewportH); 1126 1127 // Setup program. 1128 gl.useProgram(m_program->getProgram()); 1129 1130 gl.uniform4fv(gl.getUniformLocation(m_program->getProgram(), "u_scale"), 1, tcu::Vec4(0.01f).getPtr()); 1131 gl.uniform4fv(gl.getUniformLocation(m_program->getProgram(), "u_bias"), 1, tcu::Vec4(0.5f).getPtr()); 1132 1133 // Enable query. 1134 gl.beginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, *primitiveQuery); 1135 GLU_EXPECT_NO_ERROR(gl.getError(), "glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)"); 1136 1137 // Draw. 1138 { 1139 int offset = 0; 1140 bool tfEnabled = true; 1141 1142 gl.clear(GL_COLOR_BUFFER_BIT); 1143 1144 gl.beginTransformFeedback(getTransformFeedbackPrimitiveMode(m_primitiveType)); 1145 1146 for (const DrawCall* call = first; call != end; call++) 1147 { 1148 // Pause or resume transform feedback if necessary. 1149 if (call->transformFeedbackEnabled != tfEnabled) 1150 { 1151 if (call->transformFeedbackEnabled) 1152 gl.resumeTransformFeedback(); 1153 else 1154 gl.pauseTransformFeedback(); 1155 tfEnabled = call->transformFeedbackEnabled; 1156 } 1157 1158 gl.drawArrays(m_primitiveType, offset, call->numElements); 1159 offset += call->numElements; 1160 } 1161 1162 // Resume feedback before finishing it. 1163 if (!tfEnabled) 1164 gl.resumeTransformFeedback(); 1165 1166 gl.endTransformFeedback(); 1167 GLU_EXPECT_NO_ERROR(gl.getError(), "render"); 1168 } 1169 1170 gl.endQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); 1171 GLU_EXPECT_NO_ERROR(gl.getError(), "glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN)"); 1172 1173 // Check and log query status right after submit 1174 { 1175 deUint32 available = GL_FALSE; 1176 gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT_AVAILABLE, &available); 1177 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv()"); 1178 1179 log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN status after submit: " << (available != GL_FALSE ? "GL_TRUE" : "GL_FALSE") << TestLog::EndMessage; 1180 } 1181 1182 // Compare result buffers. 1183 for (int bufferNdx = 0; bufferNdx < (int)m_outputBuffers.size(); bufferNdx++) 1184 { 1185 deUint32 buffer = m_outputBuffers[bufferNdx]; 1186 int stride = m_bufferStrides[bufferNdx]; 1187 int size = stride*numOutputs; 1188 int guardSize = stride*BUFFER_GUARD_MULTIPLIER; 1189 const void* bufPtr = DE_NULL; 1190 1191 // Bind buffer for reading. 1192 gl.bindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, buffer); 1193 bufPtr = gl.mapBufferRange(GL_TRANSFORM_FEEDBACK_BUFFER, 0, size+guardSize, GL_MAP_READ_BIT); 1194 GLU_EXPECT_NO_ERROR(gl.getError(), "mapping buffer"); 1195 1196 // Verify all output variables that are written to this buffer. 1197 for (vector<Output>::const_iterator out = m_transformFeedbackOutputs.begin(); out != m_transformFeedbackOutputs.end(); out++) 1198 { 1199 if (out->bufferNdx != bufferNdx) 1200 continue; 1201 1202 int inputOffset = 0; 1203 int outputOffset = 0; 1204 1205 // Process all draw calls and check ones with transform feedback enabled. 1206 for (const DrawCall* call = first; call != end; call++) 1207 { 1208 if (call->transformFeedbackEnabled) 1209 { 1210 const deUint8* inputPtr = &inputData[0] + inputOffset*m_inputStride; 1211 const deUint8* outputPtr = (const deUint8*)bufPtr + outputOffset*stride; 1212 1213 if (!compareTransformFeedbackOutput(log, m_primitiveType, *out, call->numElements, inputPtr, m_inputStride, outputPtr, stride)) 1214 { 1215 outputsOk = false; 1216 break; 1217 } 1218 } 1219 1220 inputOffset += call->numElements; 1221 outputOffset += call->transformFeedbackEnabled ? getTransformFeedbackOutputCount(m_primitiveType, call->numElements) : 0; 1222 } 1223 } 1224 1225 // Verify guardband. 1226 if (!verifyGuard((const deUint8*)bufPtr + size, guardSize)) 1227 { 1228 log << TestLog::Message << "Error: Transform feedback buffer overrun detected" << TestLog::EndMessage; 1229 outputsOk = false; 1230 } 1231 1232 gl.unmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER); 1233 } 1234 1235 // Check status after mapping buffers. 1236 { 1237 const bool mustBeReady = !m_outputBuffers.empty(); // Mapping buffer forces synchronization. 1238 const int expectedCount = computeTransformFeedbackPrimitiveCount(m_primitiveType, first, end); 1239 deUint32 available = GL_FALSE; 1240 deUint32 numPrimitives = 0; 1241 1242 gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT_AVAILABLE, &available); 1243 gl.getQueryObjectuiv(*primitiveQuery, GL_QUERY_RESULT, &numPrimitives); 1244 GLU_EXPECT_NO_ERROR(gl.getError(), "glGetQueryObjectuiv()"); 1245 1246 if (!mustBeReady && available == GL_FALSE) 1247 { 1248 log << TestLog::Message << "ERROR: GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN result not available after mapping buffers!" << TestLog::EndMessage; 1249 queryOk = false; 1250 } 1251 1252 log << TestLog::Message << "GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN = " << numPrimitives << TestLog::EndMessage; 1253 1254 if ((int)numPrimitives != expectedCount) 1255 { 1256 log << TestLog::Message << "ERROR: Expected " << expectedCount << " primitives!" << TestLog::EndMessage; 1257 queryOk = false; 1258 } 1259 } 1260 1261 // Clear transform feedback state. 1262 gl.bindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0); 1263 for (int bufNdx = 0; bufNdx < (int)m_outputBuffers.size(); bufNdx++) 1264 { 1265 gl.bindBuffer (GL_TRANSFORM_FEEDBACK_BUFFER, 0); 1266 gl.bindBufferBase (GL_TRANSFORM_FEEDBACK_BUFFER, bufNdx, 0); 1267 } 1268 1269 // Read back rendered image. 1270 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, frameWithTf.getAccess()); 1271 1272 // Render without transform feedback. 1273 { 1274 int offset = 0; 1275 1276 gl.clear(GL_COLOR_BUFFER_BIT); 1277 1278 for (const DrawCall* call = first; call != end; call++) 1279 { 1280 gl.drawArrays(m_primitiveType, offset, call->numElements); 1281 offset += call->numElements; 1282 } 1283 1284 GLU_EXPECT_NO_ERROR(gl.getError(), "render"); 1285 glu::readPixels(m_context.getRenderContext(), viewportX, viewportY, frameWithoutTf.getAccess()); 1286 } 1287 1288 // Compare images with and without transform feedback. 1289 imagesOk = tcu::pixelThresholdCompare(log, "Result", "Image comparison result", frameWithoutTf, frameWithTf, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_ON_ERROR); 1290 1291 if (imagesOk) 1292 m_testCtx.getLog() << TestLog::Message << "Rendering result comparison between TF enabled and TF disabled passed." << TestLog::EndMessage; 1293 else 1294 m_testCtx.getLog() << TestLog::Message << "ERROR: Rendering result comparison between TF enabled and TF disabled failed!" << TestLog::EndMessage; 1295 1296 return outputsOk && imagesOk && queryOk; 1297} 1298 1299// Test cases. 1300 1301class PositionCase : public TransformFeedbackCase 1302{ 1303public: 1304 PositionCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType) 1305 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType) 1306 { 1307 m_progSpec.addTransformFeedbackVarying("gl_Position"); 1308 } 1309}; 1310 1311class PointSizeCase : public TransformFeedbackCase 1312{ 1313public: 1314 PointSizeCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType) 1315 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType) 1316 { 1317 m_progSpec.addTransformFeedbackVarying("gl_PointSize"); 1318 } 1319}; 1320 1321class BasicTypeCase : public TransformFeedbackCase 1322{ 1323public: 1324 BasicTypeCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation) 1325 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType) 1326 { 1327 m_progSpec.addVarying("v_varA", glu::VarType(type, precision), interpolation); 1328 m_progSpec.addVarying("v_varB", glu::VarType(type, precision), interpolation); 1329 1330 m_progSpec.addTransformFeedbackVarying("v_varA"); 1331 m_progSpec.addTransformFeedbackVarying("v_varB"); 1332 } 1333}; 1334 1335class BasicArrayCase : public TransformFeedbackCase 1336{ 1337public: 1338 BasicArrayCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation) 1339 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType) 1340 { 1341 if (glu::isDataTypeMatrix(type) || m_bufferMode == GL_SEPARATE_ATTRIBS) 1342 { 1343 // \note For matrix types we need to use reduced array sizes or otherwise we will exceed maximum attribute (16) 1344 // or transform feedback component count (64). 1345 // On separate attribs mode maximum component count per varying is 4. 1346 m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 1), interpolation); 1347 m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 2), interpolation); 1348 } 1349 else 1350 { 1351 m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 3), interpolation); 1352 m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 4), interpolation); 1353 } 1354 1355 m_progSpec.addTransformFeedbackVarying("v_varA"); 1356 m_progSpec.addTransformFeedbackVarying("v_varB"); 1357 } 1358}; 1359 1360class ArrayElementCase : public TransformFeedbackCase 1361{ 1362public: 1363 ArrayElementCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, glu::DataType type, glu::Precision precision, Interpolation interpolation) 1364 : TransformFeedbackCase(context, name, desc, bufferType, primitiveType) 1365 { 1366 m_progSpec.addVarying("v_varA", glu::VarType(glu::VarType(type, precision), 3), interpolation); 1367 m_progSpec.addVarying("v_varB", glu::VarType(glu::VarType(type, precision), 4), interpolation); 1368 1369 m_progSpec.addTransformFeedbackVarying("v_varA[1]"); 1370 m_progSpec.addTransformFeedbackVarying("v_varB[0]"); 1371 m_progSpec.addTransformFeedbackVarying("v_varB[3]"); 1372 } 1373}; 1374 1375class RandomCase : public TransformFeedbackCase 1376{ 1377public: 1378 RandomCase (Context& context, const char* name, const char* desc, deUint32 bufferType, deUint32 primitiveType, deUint32 seed) 1379 : TransformFeedbackCase (context, name, desc, bufferType, primitiveType) 1380 , m_seed (seed) 1381 { 1382 } 1383 1384 void init (void) 1385 { 1386 // \note Hard-coded indices and hackery are used when indexing this, beware. 1387 static const glu::DataType typeCandidates[] = 1388 { 1389 glu::TYPE_FLOAT, 1390 glu::TYPE_FLOAT_VEC2, 1391 glu::TYPE_FLOAT_VEC3, 1392 glu::TYPE_FLOAT_VEC4, 1393 glu::TYPE_INT, 1394 glu::TYPE_INT_VEC2, 1395 glu::TYPE_INT_VEC3, 1396 glu::TYPE_INT_VEC4, 1397 glu::TYPE_UINT, 1398 glu::TYPE_UINT_VEC2, 1399 glu::TYPE_UINT_VEC3, 1400 glu::TYPE_UINT_VEC4, 1401 1402 glu::TYPE_FLOAT_MAT2, 1403 glu::TYPE_FLOAT_MAT2X3, 1404 glu::TYPE_FLOAT_MAT2X4, 1405 1406 glu::TYPE_FLOAT_MAT3X2, 1407 glu::TYPE_FLOAT_MAT3, 1408 glu::TYPE_FLOAT_MAT3X4, 1409 1410 glu::TYPE_FLOAT_MAT4X2, 1411 glu::TYPE_FLOAT_MAT4X3, 1412 glu::TYPE_FLOAT_MAT4 1413 }; 1414 1415 static const glu::Precision precisions[] = 1416 { 1417 glu::PRECISION_LOWP, 1418 glu::PRECISION_MEDIUMP, 1419 glu::PRECISION_HIGHP 1420 }; 1421 1422 static const Interpolation interpModes[] = 1423 { 1424 INTERPOLATION_FLAT, 1425 INTERPOLATION_SMOOTH, 1426 INTERPOLATION_CENTROID 1427 }; 1428 1429 const int maxAttributeVectors = 16; 1430// const int maxTransformFeedbackComponents = 64; // \note It is enough to limit attribute set size. 1431 bool isSeparateMode = m_bufferMode == GL_SEPARATE_ATTRIBS; 1432 int maxTransformFeedbackVars = isSeparateMode ? 4 : maxAttributeVectors; 1433 const float arrayWeight = 0.3f; 1434 const float positionWeight = 0.7f; 1435 const float pointSizeWeight = 0.1f; 1436 const float captureFullArrayWeight = 0.5f; 1437 1438 de::Random rnd (m_seed); 1439 bool usePosition = rnd.getFloat() < positionWeight; 1440 bool usePointSize = rnd.getFloat() < pointSizeWeight; 1441 int numAttribVectorsToUse = rnd.getInt(1, maxAttributeVectors - 1/*position*/ - (usePointSize ? 1 : 0)); 1442 1443 int numAttributeVectors = 0; 1444 int varNdx = 0; 1445 1446 // Generate varyings. 1447 while (numAttributeVectors < numAttribVectorsToUse) 1448 { 1449 int maxVecs = isSeparateMode ? de::min(2 /*at most 2*mat2*/, numAttribVectorsToUse-numAttributeVectors) : numAttribVectorsToUse-numAttributeVectors; 1450 const glu::DataType* begin = &typeCandidates[0]; 1451 const glu::DataType* end = begin + (maxVecs >= 4 ? 21 : 1452 maxVecs >= 3 ? 18 : 1453 maxVecs >= 2 ? (isSeparateMode ? 13 : 15) : 12); 1454 1455 glu::DataType type = rnd.choose<glu::DataType>(begin, end); 1456 glu::Precision precision = rnd.choose<glu::Precision>(&precisions[0], &precisions[0]+DE_LENGTH_OF_ARRAY(precisions)); 1457 Interpolation interp = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT 1458 ? rnd.choose<Interpolation>(&interpModes[0], &interpModes[0]+DE_LENGTH_OF_ARRAY(interpModes)) 1459 : INTERPOLATION_FLAT; 1460 int numVecs = glu::isDataTypeMatrix(type) ? glu::getDataTypeMatrixNumColumns(type) : 1; 1461 int numComps = glu::getDataTypeScalarSize(type); 1462 int maxArrayLen = de::max(1, isSeparateMode ? 4/numComps : maxVecs/numVecs); 1463 bool useArray = rnd.getFloat() < arrayWeight; 1464 int arrayLen = useArray ? rnd.getInt(1, maxArrayLen) : 1; 1465 std::string name = "v_var" + de::toString(varNdx); 1466 1467 if (useArray) 1468 m_progSpec.addVarying(name.c_str(), glu::VarType(glu::VarType(type, precision), arrayLen), interp); 1469 else 1470 m_progSpec.addVarying(name.c_str(), glu::VarType(type, precision), interp); 1471 1472 numAttributeVectors += arrayLen*numVecs; 1473 varNdx += 1; 1474 } 1475 1476 // Generate transform feedback candidate set. 1477 vector<string> tfCandidates; 1478 1479 if (usePosition) tfCandidates.push_back("gl_Position"); 1480 if (usePointSize) tfCandidates.push_back("gl_PointSize"); 1481 1482 for (int ndx = 0; ndx < varNdx /* num varyings */; ndx++) 1483 { 1484 const Varying& var = m_progSpec.getVaryings()[ndx]; 1485 1486 if (var.type.isArrayType()) 1487 { 1488 const bool captureFull = rnd.getFloat() < captureFullArrayWeight; 1489 1490 if (captureFull) 1491 tfCandidates.push_back(var.name); 1492 else 1493 { 1494 const int numElem = var.type.getArraySize(); 1495 for (int elemNdx = 0; elemNdx < numElem; elemNdx++) 1496 tfCandidates.push_back(var.name + "[" + de::toString(elemNdx) + "]"); 1497 } 1498 } 1499 else 1500 tfCandidates.push_back(var.name); 1501 } 1502 1503 // Pick random selection. 1504 vector<string> tfVaryings(de::min((int)tfCandidates.size(), maxTransformFeedbackVars)); 1505 rnd.choose(tfCandidates.begin(), tfCandidates.end(), tfVaryings.begin(), (int)tfVaryings.size()); 1506 rnd.shuffle(tfVaryings.begin(), tfVaryings.end()); 1507 1508 for (vector<string>::const_iterator var = tfVaryings.begin(); var != tfVaryings.end(); var++) 1509 m_progSpec.addTransformFeedbackVarying(var->c_str()); 1510 1511 TransformFeedbackCase::init(); 1512 } 1513 1514private: 1515 deUint32 m_seed; 1516}; 1517 1518} // TransformFeedback 1519 1520using namespace TransformFeedback; 1521 1522TransformFeedbackTests::TransformFeedbackTests (Context& context) 1523 : TestCaseGroup(context, "transform_feedback", "Transform feedback tests") 1524{ 1525} 1526 1527TransformFeedbackTests::~TransformFeedbackTests (void) 1528{ 1529} 1530 1531void TransformFeedbackTests::init (void) 1532{ 1533 static const struct 1534 { 1535 const char* name; 1536 deUint32 mode; 1537 } bufferModes[] = 1538 { 1539 { "separate", GL_SEPARATE_ATTRIBS }, 1540 { "interleaved", GL_INTERLEAVED_ATTRIBS } 1541 }; 1542 1543 static const struct 1544 { 1545 const char* name; 1546 deUint32 type; 1547 } primitiveTypes[] = 1548 { 1549 { "points", GL_POINTS }, 1550 { "lines", GL_LINES }, 1551 { "triangles", GL_TRIANGLES } 1552 1553 // Not supported by GLES3. 1554// { "line_strip", GL_LINE_STRIP }, 1555// { "line_loop", GL_LINE_LOOP }, 1556// { "triangle_fan", GL_TRIANGLE_FAN }, 1557// { "triangle_strip", GL_TRIANGLE_STRIP } 1558 }; 1559 1560 static const glu::DataType basicTypes[] = 1561 { 1562 glu::TYPE_FLOAT, 1563 glu::TYPE_FLOAT_VEC2, 1564 glu::TYPE_FLOAT_VEC3, 1565 glu::TYPE_FLOAT_VEC4, 1566 glu::TYPE_FLOAT_MAT2, 1567 glu::TYPE_FLOAT_MAT2X3, 1568 glu::TYPE_FLOAT_MAT2X4, 1569 glu::TYPE_FLOAT_MAT3X2, 1570 glu::TYPE_FLOAT_MAT3, 1571 glu::TYPE_FLOAT_MAT3X4, 1572 glu::TYPE_FLOAT_MAT4X2, 1573 glu::TYPE_FLOAT_MAT4X3, 1574 glu::TYPE_FLOAT_MAT4, 1575 glu::TYPE_INT, 1576 glu::TYPE_INT_VEC2, 1577 glu::TYPE_INT_VEC3, 1578 glu::TYPE_INT_VEC4, 1579 glu::TYPE_UINT, 1580 glu::TYPE_UINT_VEC2, 1581 glu::TYPE_UINT_VEC3, 1582 glu::TYPE_UINT_VEC4 1583 }; 1584 1585 static const glu::Precision precisions[] = 1586 { 1587 glu::PRECISION_LOWP, 1588 glu::PRECISION_MEDIUMP, 1589 glu::PRECISION_HIGHP 1590 }; 1591 1592 static const struct 1593 { 1594 const char* name; 1595 Interpolation interp; 1596 } interpModes[] = 1597 { 1598 { "smooth", INTERPOLATION_SMOOTH }, 1599 { "flat", INTERPOLATION_FLAT }, 1600 { "centroid", INTERPOLATION_CENTROID } 1601 }; 1602 1603 // .position 1604 { 1605 tcu::TestCaseGroup* positionGroup = new tcu::TestCaseGroup(m_testCtx, "position", "gl_Position capture using transform feedback"); 1606 addChild(positionGroup); 1607 1608 for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++) 1609 { 1610 for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++) 1611 { 1612 string name = string(primitiveTypes[primitiveType].name) + "_" + bufferModes[bufferMode].name; 1613 positionGroup->addChild(new PositionCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type)); 1614 } 1615 } 1616 } 1617 1618 // .point_size 1619 { 1620 tcu::TestCaseGroup* pointSizeGroup = new tcu::TestCaseGroup(m_testCtx, "point_size", "gl_PointSize capture using transform feedback"); 1621 addChild(pointSizeGroup); 1622 1623 for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++) 1624 { 1625 for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++) 1626 { 1627 string name = string(primitiveTypes[primitiveType].name) + "_" + bufferModes[bufferMode].name; 1628 pointSizeGroup->addChild(new PointSizeCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type)); 1629 } 1630 } 1631 } 1632 1633 // .basic_type 1634 { 1635 tcu::TestCaseGroup* basicTypeGroup = new tcu::TestCaseGroup(m_testCtx, "basic_types", "Basic types in transform feedback"); 1636 addChild(basicTypeGroup); 1637 1638 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++) 1639 { 1640 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, ""); 1641 deUint32 bufferMode = bufferModes[bufferModeNdx].mode; 1642 basicTypeGroup->addChild(modeGroup); 1643 1644 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++) 1645 { 1646 tcu::TestCaseGroup* primitiveGroup = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, ""); 1647 deUint32 primitiveType = primitiveTypes[primitiveTypeNdx].type; 1648 modeGroup->addChild(primitiveGroup); 1649 1650 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++) 1651 { 1652 glu::DataType type = basicTypes[typeNdx]; 1653 bool isFloat = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT; 1654 1655 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1656 { 1657 glu::Precision precision = precisions[precNdx]; 1658 1659 string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type); 1660 primitiveGroup->addChild(new BasicTypeCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT)); 1661 } 1662 } 1663 } 1664 } 1665 } 1666 1667 // .array 1668 { 1669 tcu::TestCaseGroup* arrayGroup = new tcu::TestCaseGroup(m_testCtx, "array", "Capturing whole array in TF"); 1670 addChild(arrayGroup); 1671 1672 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++) 1673 { 1674 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, ""); 1675 deUint32 bufferMode = bufferModes[bufferModeNdx].mode; 1676 arrayGroup->addChild(modeGroup); 1677 1678 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++) 1679 { 1680 tcu::TestCaseGroup* primitiveGroup = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, ""); 1681 deUint32 primitiveType = primitiveTypes[primitiveTypeNdx].type; 1682 modeGroup->addChild(primitiveGroup); 1683 1684 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++) 1685 { 1686 glu::DataType type = basicTypes[typeNdx]; 1687 bool isFloat = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT; 1688 1689 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1690 { 1691 glu::Precision precision = precisions[precNdx]; 1692 1693 string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type); 1694 primitiveGroup->addChild(new BasicArrayCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT)); 1695 } 1696 } 1697 } 1698 } 1699 } 1700 1701 // .array_element 1702 { 1703 tcu::TestCaseGroup* arrayElemGroup = new tcu::TestCaseGroup(m_testCtx, "array_element", "Capturing single array element in TF"); 1704 addChild(arrayElemGroup); 1705 1706 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++) 1707 { 1708 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, ""); 1709 deUint32 bufferMode = bufferModes[bufferModeNdx].mode; 1710 arrayElemGroup->addChild(modeGroup); 1711 1712 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++) 1713 { 1714 tcu::TestCaseGroup* primitiveGroup = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, ""); 1715 deUint32 primitiveType = primitiveTypes[primitiveTypeNdx].type; 1716 modeGroup->addChild(primitiveGroup); 1717 1718 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(basicTypes); typeNdx++) 1719 { 1720 glu::DataType type = basicTypes[typeNdx]; 1721 bool isFloat = glu::getDataTypeScalarType(type) == glu::TYPE_FLOAT; 1722 1723 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1724 { 1725 glu::Precision precision = precisions[precNdx]; 1726 1727 string name = string(glu::getPrecisionName(precision)) + "_" + glu::getDataTypeName(type); 1728 primitiveGroup->addChild(new ArrayElementCase(m_context, name.c_str(), "", bufferMode, primitiveType, type, precision, isFloat ? INTERPOLATION_SMOOTH : INTERPOLATION_FLAT)); 1729 } 1730 } 1731 } 1732 } 1733 } 1734 1735 // .interpolation 1736 { 1737 tcu::TestCaseGroup* interpolationGroup = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Different interpolation modes in transform feedback varyings"); 1738 addChild(interpolationGroup); 1739 1740 for (int modeNdx = 0; modeNdx < DE_LENGTH_OF_ARRAY(interpModes); modeNdx++) 1741 { 1742 Interpolation interp = interpModes[modeNdx].interp; 1743 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, interpModes[modeNdx].name, ""); 1744 1745 interpolationGroup->addChild(modeGroup); 1746 1747 for (int precNdx = 0; precNdx < DE_LENGTH_OF_ARRAY(precisions); precNdx++) 1748 { 1749 glu::Precision precision = precisions[precNdx]; 1750 1751 for (int primitiveType = 0; primitiveType < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveType++) 1752 { 1753 for (int bufferMode = 0; bufferMode < DE_LENGTH_OF_ARRAY(bufferModes); bufferMode++) 1754 { 1755 string name = string(glu::getPrecisionName(precision)) + "_vec4_" + primitiveTypes[primitiveType].name + "_" + bufferModes[bufferMode].name; 1756 modeGroup->addChild(new BasicTypeCase(m_context, name.c_str(), "", bufferModes[bufferMode].mode, primitiveTypes[primitiveType].type, glu::TYPE_FLOAT_VEC4, precision, interp)); 1757 } 1758 } 1759 } 1760 } 1761 } 1762 1763 // .random 1764 { 1765 tcu::TestCaseGroup* randomGroup = new tcu::TestCaseGroup(m_testCtx, "random", "Randomized transform feedback cases"); 1766 addChild(randomGroup); 1767 1768 for (int bufferModeNdx = 0; bufferModeNdx < DE_LENGTH_OF_ARRAY(bufferModes); bufferModeNdx++) 1769 { 1770 tcu::TestCaseGroup* modeGroup = new tcu::TestCaseGroup(m_testCtx, bufferModes[bufferModeNdx].name, ""); 1771 deUint32 bufferMode = bufferModes[bufferModeNdx].mode; 1772 randomGroup->addChild(modeGroup); 1773 1774 for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeNdx++) 1775 { 1776 tcu::TestCaseGroup* primitiveGroup = new tcu::TestCaseGroup(m_testCtx, primitiveTypes[primitiveTypeNdx].name, ""); 1777 deUint32 primitiveType = primitiveTypes[primitiveTypeNdx].type; 1778 modeGroup->addChild(primitiveGroup); 1779 1780 for (int ndx = 0; ndx < 10; ndx++) 1781 { 1782 deUint32 seed = deInt32Hash(bufferMode) ^ deInt32Hash(primitiveType) ^ deInt32Hash(ndx); 1783 primitiveGroup->addChild(new RandomCase(m_context, de::toString(ndx+1).c_str(), "", bufferMode, primitiveType, seed)); 1784 } 1785 } 1786 } 1787 } 1788} 1789 1790} // Functional 1791} // gles3 1792} // deqp 1793