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 Instanced rendering tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es3fInstancedRenderingTests.hpp" 25 #include "gluPixelTransfer.hpp" 26 #include "gluShaderProgram.hpp" 27 #include "gluShaderUtil.hpp" 28 #include "tcuTestLog.hpp" 29 #include "tcuSurface.hpp" 30 #include "tcuImageCompare.hpp" 31 #include "tcuVector.hpp" 32 #include "tcuRenderTarget.hpp" 33 #include "deRandom.hpp" 34 #include "deStringUtil.hpp" 35 #include "deString.h" 36 37 #include "glw.h" 38 39 using std::vector; 40 using std::string; 41 42 namespace deqp 43 { 44 namespace gles3 45 { 46 namespace Functional 47 { 48 49 static const int MAX_RENDER_WIDTH = 128; 50 static const int MAX_RENDER_HEIGHT = 128; 51 52 static const int QUAD_GRID_SIZE = 127; 53 54 // Attribute divisors for the attributes defining the color's RGB components. 55 static const int ATTRIB_DIVISOR_R = 3; 56 static const int ATTRIB_DIVISOR_G = 2; 57 static const int ATTRIB_DIVISOR_B = 1; 58 59 static const int OFFSET_COMPONENTS = 3; // \note Affects whether a float or a vecN is used in shader, but only first component is non-zero. 60 61 // Scale and bias values when converting float to integer, when attribute is of integer type. 62 static const float FLOAT_INT_SCALE = 100.0f; 63 static const float FLOAT_INT_BIAS = -50.0f; 64 static const float FLOAT_UINT_SCALE = 100.0f; 65 static const float FLOAT_UINT_BIAS = 0.0f; 66 67 // \note Non-anonymous namespace needed; VarComp is used as a template parameter. 68 namespace vcns 69 { 70 71 union VarComp 72 { 73 float f32; 74 deUint32 u32; 75 deInt32 i32; 76 77 VarComp(float v) : f32(v) {} 78 VarComp(deUint32 v) : u32(v) {} 79 VarComp(deInt32 v) : i32(v) {} 80 }; 81 DE_STATIC_ASSERT(sizeof(VarComp) == sizeof(deUint32)); 82 83 } // vcns 84 85 using namespace vcns; 86 87 class InstancedRenderingCase : public TestCase 88 { 89 public: 90 enum DrawFunction 91 { 92 FUNCTION_DRAW_ARRAYS_INSTANCED = 0, 93 FUNCTION_DRAW_ELEMENTS_INSTANCED, 94 95 FUNCTION_LAST 96 }; 97 98 enum InstancingType 99 { 100 TYPE_INSTANCE_ID = 0, 101 TYPE_ATTRIB_DIVISOR, 102 TYPE_MIXED, 103 104 TYPE_LAST 105 }; 106 107 InstancedRenderingCase (Context& context, const char* name, const char* description, DrawFunction function, InstancingType instancingType, glu::DataType rgbAttrType, int numInstances); 108 ~InstancedRenderingCase (void); 109 110 void init (void); 111 void deinit (void); 112 IterateResult iterate (void); 113 114 private: 115 InstancedRenderingCase (const InstancedRenderingCase& other); 116 InstancedRenderingCase& operator= (const InstancedRenderingCase& other); 117 118 void pushVarCompAttrib (vector<VarComp>& vec, float val); 119 120 void setupVarAttribPointer (const void* attrPtr, int startLocation, int divisor); 121 void setupAndRender (void); 122 void computeReference (tcu::Surface& dst); 123 124 DrawFunction m_function; 125 InstancingType m_instancingType; 126 glu::DataType m_rgbAttrType; // \note Instance attribute types, color components only. Position offset attribute is always float/vecN. 127 int m_numInstances; 128 129 vector<float> m_gridVertexPositions; // X and Y components per vertex. 130 vector<deUint16> m_gridIndices; // \note Only used if m_function is FUNCTION_DRAW_ELEMENTS_INSTANCED. 131 132 // \note Some or all of the following instance attribute parameters may be unused with TYPE_INSTANCE_ID or TYPE_MIXED. 133 vector<float> m_instanceOffsets; // Position offsets. OFFSET_COMPONENTS components per offset. 134 // Attribute data for float, int or uint (or respective vector types) color components. 135 vector<VarComp> m_instanceColorR; 136 vector<VarComp> m_instanceColorG; 137 vector<VarComp> m_instanceColorB; 138 139 glu::ShaderProgram* m_program; 140 }; 141 142 InstancedRenderingCase::InstancedRenderingCase (Context& context, const char* name, const char* description, DrawFunction function, InstancingType instancingType, glu::DataType rgbAttrType, int numInstances) 143 : TestCase (context, name, description) 144 , m_function (function) 145 , m_instancingType (instancingType) 146 , m_rgbAttrType (rgbAttrType) 147 , m_numInstances (numInstances) 148 , m_program (DE_NULL) 149 { 150 } 151 152 InstancedRenderingCase::~InstancedRenderingCase (void) 153 { 154 InstancedRenderingCase::deinit(); 155 } 156 157 // Helper function that does biasing and scaling when converting float to integer. 158 void InstancedRenderingCase::pushVarCompAttrib (vector<VarComp>& vec, float val) 159 { 160 bool isFloatCase = glu::isDataTypeFloatOrVec(m_rgbAttrType); 161 bool isIntCase = glu::isDataTypeIntOrIVec(m_rgbAttrType); 162 bool isUintCase = glu::isDataTypeUintOrUVec(m_rgbAttrType); 163 bool isMatCase = glu::isDataTypeMatrix(m_rgbAttrType); 164 165 if (isFloatCase || isMatCase) 166 vec.push_back(VarComp(val)); 167 else if (isIntCase) 168 vec.push_back(VarComp((deInt32)(val*FLOAT_INT_SCALE + FLOAT_INT_BIAS))); 169 else if (isUintCase) 170 vec.push_back(VarComp((deUint32)(val*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS))); 171 else 172 DE_ASSERT(DE_FALSE); 173 } 174 175 void InstancedRenderingCase::init (void) 176 { 177 bool isFloatCase = glu::isDataTypeFloatOrVec(m_rgbAttrType); 178 bool isIntCase = glu::isDataTypeIntOrIVec(m_rgbAttrType); 179 bool isUintCase = glu::isDataTypeUintOrUVec(m_rgbAttrType); 180 bool isMatCase = glu::isDataTypeMatrix(m_rgbAttrType); 181 int typeSize = glu::getDataTypeScalarSize(m_rgbAttrType); 182 bool isScalarCase = typeSize == 1; 183 string swizzleFirst = isScalarCase ? "" : ".x"; 184 string typeName = glu::getDataTypeName(m_rgbAttrType); 185 186 string floatIntScaleStr = "(" + de::floatToString(FLOAT_INT_SCALE, 3) + ")"; 187 string floatIntBiasStr = "(" + de::floatToString(FLOAT_INT_BIAS, 3) + ")"; 188 string floatUintScaleStr = "(" + de::floatToString(FLOAT_UINT_SCALE, 3) + ")"; 189 string floatUintBiasStr = "(" + de::floatToString(FLOAT_UINT_BIAS, 3) + ")"; 190 191 DE_ASSERT(isFloatCase || isIntCase || isUintCase || isMatCase); 192 193 // Generate shader. 194 // \note For case TYPE_MIXED, vertex position offset and color red component get their values from instance id, while green and blue get their values from instanced attributes. 195 196 string numInstancesStr = de::toString(m_numInstances) + ".0"; 197 198 string instanceAttribs; 199 string posExpression; 200 string colorRExpression; 201 string colorGExpression; 202 string colorBExpression; 203 204 if (m_instancingType == TYPE_INSTANCE_ID || m_instancingType == TYPE_MIXED) 205 { 206 posExpression = "a_position + vec4(float(gl_InstanceID) * 2.0 / " + numInstancesStr + ", 0.0, 0.0, 0.0)"; 207 colorRExpression = "float(gl_InstanceID)/" + numInstancesStr; 208 209 if (m_instancingType == TYPE_INSTANCE_ID) 210 { 211 colorGExpression = "float(gl_InstanceID)*2.0/" + numInstancesStr; 212 colorBExpression = "1.0 - float(gl_InstanceID)/" + numInstancesStr; 213 } 214 } 215 216 if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED) 217 { 218 if (m_instancingType == TYPE_ATTRIB_DIVISOR) 219 { 220 posExpression = "a_position + vec4(a_instanceOffset"; 221 222 DE_STATIC_ASSERT(OFFSET_COMPONENTS >= 1 && OFFSET_COMPONENTS <= 4); 223 224 for (int i = 0; i < 4-OFFSET_COMPONENTS; i++) 225 posExpression += ", 0.0"; 226 posExpression += ")"; 227 228 if (isFloatCase) 229 colorRExpression = "a_instanceR" + swizzleFirst; 230 else if (isIntCase) 231 colorRExpression = "(float(a_instanceR" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr; 232 else if (isUintCase) 233 colorRExpression = "(float(a_instanceR" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr; 234 else if (isMatCase) 235 colorRExpression = "a_instanceR[0][0]"; 236 else 237 DE_ASSERT(DE_FALSE); 238 239 instanceAttribs += "in highp " + (OFFSET_COMPONENTS == 1 ? string("float") : "vec" + de::toString(OFFSET_COMPONENTS)) + " a_instanceOffset;\n"; 240 instanceAttribs += "in mediump " + typeName + " a_instanceR;\n"; 241 } 242 243 if (isFloatCase) 244 { 245 colorGExpression = "a_instanceG" + swizzleFirst; 246 colorBExpression = "a_instanceB" + swizzleFirst; 247 } 248 else if (isIntCase) 249 { 250 colorGExpression = "(float(a_instanceG" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr; 251 colorBExpression = "(float(a_instanceB" + swizzleFirst + ") - " + floatIntBiasStr + ") / " + floatIntScaleStr; 252 } 253 else if (isUintCase) 254 { 255 colorGExpression = "(float(a_instanceG" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr; 256 colorBExpression = "(float(a_instanceB" + swizzleFirst + ") - " + floatUintBiasStr + ") / " + floatUintScaleStr; 257 } 258 else if (isMatCase) 259 { 260 colorGExpression = "a_instanceG[0][0]"; 261 colorBExpression = "a_instanceB[0][0]"; 262 } 263 else 264 DE_ASSERT(DE_FALSE); 265 266 instanceAttribs += "in mediump " + typeName + " a_instanceG;\n"; 267 instanceAttribs += "in mediump " + typeName + " a_instanceB;\n"; 268 } 269 270 DE_ASSERT(!posExpression.empty()); 271 DE_ASSERT(!colorRExpression.empty()); 272 DE_ASSERT(!colorGExpression.empty()); 273 DE_ASSERT(!colorBExpression.empty()); 274 275 std::string vertShaderSourceStr = 276 "#version 300 es\n" 277 "in highp vec4 a_position;\n" + 278 instanceAttribs + 279 "out mediump vec4 v_color;\n" 280 "\n" 281 "void main()\n" 282 "{\n" 283 " gl_Position = " + posExpression + ";\n" 284 " v_color.r = " + colorRExpression + ";\n" 285 " v_color.g = " + colorGExpression + ";\n" 286 " v_color.b = " + colorBExpression + ";\n" 287 " v_color.a = 1.0;\n" 288 "}\n"; 289 290 static const char* fragShaderSource = 291 "#version 300 es\n" 292 "layout(location = 0) out mediump vec4 o_color;\n" 293 "in mediump vec4 v_color;\n" 294 "\n" 295 "void main()\n" 296 "{\n" 297 " o_color = v_color;\n" 298 "}\n"; 299 300 // Create shader program and log it. 301 302 DE_ASSERT(!m_program); 303 m_program = new glu::ShaderProgram(m_context.getRenderContext(), glu::makeVtxFragSources(vertShaderSourceStr, fragShaderSource)); 304 305 tcu::TestLog& log = m_testCtx.getLog(); 306 307 log << *m_program; 308 309 if(!m_program->isOk()) 310 TCU_FAIL("Failed to compile shader"); 311 312 // Vertex shader attributes. 313 314 if (m_function == FUNCTION_DRAW_ELEMENTS_INSTANCED) 315 { 316 // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>. 317 318 for (int y = 0; y < QUAD_GRID_SIZE + 1; y++) 319 for (int x = 0; x < QUAD_GRID_SIZE + 1; x++) 320 { 321 float fx = -1.0f + (float)x / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances; 322 float fy = -1.0f + (float)y / (float)QUAD_GRID_SIZE * 2.0f; 323 324 m_gridVertexPositions.push_back(fx); 325 m_gridVertexPositions.push_back(fy); 326 } 327 328 // Indices. 329 330 for (int y = 0; y < QUAD_GRID_SIZE; y++) 331 for (int x = 0; x < QUAD_GRID_SIZE; x++) 332 { 333 int ndx00 = y*(QUAD_GRID_SIZE + 1) + x; 334 int ndx10 = y*(QUAD_GRID_SIZE + 1) + x + 1; 335 int ndx01 = (y + 1)*(QUAD_GRID_SIZE + 1) + x; 336 int ndx11 = (y + 1)*(QUAD_GRID_SIZE + 1) + x + 1; 337 338 // Lower-left triangle of a quad. 339 m_gridIndices.push_back(ndx00); 340 m_gridIndices.push_back(ndx10); 341 m_gridIndices.push_back(ndx01); 342 343 // Upper-right triangle of a quad. 344 m_gridIndices.push_back(ndx11); 345 m_gridIndices.push_back(ndx01); 346 m_gridIndices.push_back(ndx10); 347 } 348 } 349 else 350 { 351 DE_ASSERT(m_function == FUNCTION_DRAW_ARRAYS_INSTANCED); 352 353 // Vertex positions. Positions form a vertical bar of width <screen width>/<number of instances>. 354 355 for (int y = 0; y < QUAD_GRID_SIZE; y++) 356 for (int x = 0; x < QUAD_GRID_SIZE; x++) 357 { 358 float fx0 = -1.0f + (float)(x+0) / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances; 359 float fx1 = -1.0f + (float)(x+1) / (float)QUAD_GRID_SIZE * 2.0f / (float)m_numInstances; 360 float fy0 = -1.0f + (float)(y+0) / (float)QUAD_GRID_SIZE * 2.0f; 361 float fy1 = -1.0f + (float)(y+1) / (float)QUAD_GRID_SIZE * 2.0f; 362 363 // Vertices of a quad's lower-left triangle: (fx0, fy0), (fx1, fy0) and (fx0, fy1) 364 m_gridVertexPositions.push_back(fx0); 365 m_gridVertexPositions.push_back(fy0); 366 m_gridVertexPositions.push_back(fx1); 367 m_gridVertexPositions.push_back(fy0); 368 m_gridVertexPositions.push_back(fx0); 369 m_gridVertexPositions.push_back(fy1); 370 371 // Vertices of a quad's upper-right triangle: (fx1, fy1), (fx0, fy1) and (fx1, fy0) 372 m_gridVertexPositions.push_back(fx1); 373 m_gridVertexPositions.push_back(fy1); 374 m_gridVertexPositions.push_back(fx0); 375 m_gridVertexPositions.push_back(fy1); 376 m_gridVertexPositions.push_back(fx1); 377 m_gridVertexPositions.push_back(fy0); 378 } 379 } 380 381 // Instanced attributes: position offset and color RGB components. 382 383 if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED) 384 { 385 if (m_instancingType == TYPE_ATTRIB_DIVISOR) 386 { 387 // Offsets are such that the vertical bars are drawn next to each other. 388 for (int i = 0; i < m_numInstances; i++) 389 { 390 m_instanceOffsets.push_back((float)i * 2.0f / (float)m_numInstances); 391 392 DE_STATIC_ASSERT(OFFSET_COMPONENTS >= 1 && OFFSET_COMPONENTS <= 4); 393 394 for (int j = 0; j < OFFSET_COMPONENTS-1; j++) 395 m_instanceOffsets.push_back(0.0f); 396 } 397 398 int rInstances = m_numInstances / ATTRIB_DIVISOR_R + (m_numInstances % ATTRIB_DIVISOR_R == 0 ? 0 : 1); 399 for (int i = 0; i < rInstances; i++) 400 { 401 pushVarCompAttrib(m_instanceColorR, (float)i / (float)rInstances); 402 403 for (int j = 0; j < typeSize - 1; j++) 404 pushVarCompAttrib(m_instanceColorR, 0.0f); 405 } 406 } 407 408 int gInstances = m_numInstances / ATTRIB_DIVISOR_G + (m_numInstances % ATTRIB_DIVISOR_G == 0 ? 0 : 1); 409 for (int i = 0; i < gInstances; i++) 410 { 411 pushVarCompAttrib(m_instanceColorG, (float)i*2.0f / (float)gInstances); 412 413 for (int j = 0; j < typeSize - 1; j++) 414 pushVarCompAttrib(m_instanceColorG, 0.0f); 415 } 416 417 int bInstances = m_numInstances / ATTRIB_DIVISOR_B + (m_numInstances % ATTRIB_DIVISOR_B == 0 ? 0 : 1); 418 for (int i = 0; i < bInstances; i++) 419 { 420 pushVarCompAttrib(m_instanceColorB, 1.0f - (float)i / (float)bInstances); 421 422 for (int j = 0; j < typeSize - 1; j++) 423 pushVarCompAttrib(m_instanceColorB, 0.0f); 424 } 425 } 426 } 427 428 void InstancedRenderingCase::deinit (void) 429 { 430 delete m_program; 431 m_program = DE_NULL; 432 } 433 434 InstancedRenderingCase::IterateResult InstancedRenderingCase::iterate (void) 435 { 436 int width = deMin32(m_context.getRenderTarget().getWidth(), MAX_RENDER_WIDTH); 437 int height = deMin32(m_context.getRenderTarget().getHeight(), MAX_RENDER_HEIGHT); 438 439 int xOffsetMax = m_context.getRenderTarget().getWidth() - width; 440 int yOffsetMax = m_context.getRenderTarget().getHeight() - height; 441 442 de::Random rnd (deStringHash(getName())); 443 444 int xOffset = rnd.getInt(0, xOffsetMax); 445 int yOffset = rnd.getInt(0, yOffsetMax); 446 tcu::Surface referenceImg (width, height); 447 tcu::Surface resultImg (width, height); 448 449 // Draw result. 450 451 glViewport(xOffset, yOffset, width, height); 452 453 setupAndRender(); 454 455 glu::readPixels(m_context.getRenderContext(), xOffset, yOffset, resultImg.getAccess()); 456 457 // Compute reference. 458 459 computeReference(referenceImg); 460 461 // Compare. 462 463 bool testOk = tcu::fuzzyCompare(m_testCtx.getLog(), "ComparisonResult", "Image comparison result", referenceImg, resultImg, 0.05f, tcu::COMPARE_LOG_RESULT); 464 465 m_testCtx.setTestResult(testOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, 466 testOk ? "Pass" : "Fail"); 467 468 return STOP; 469 } 470 471 void InstancedRenderingCase::setupVarAttribPointer (const void* attrPtr, int location, int divisor) 472 { 473 bool isFloatCase = glu::isDataTypeFloatOrVec(m_rgbAttrType); 474 bool isIntCase = glu::isDataTypeIntOrIVec(m_rgbAttrType); 475 bool isUintCase = glu::isDataTypeUintOrUVec(m_rgbAttrType); 476 bool isMatCase = glu::isDataTypeMatrix(m_rgbAttrType); 477 int typeSize = glu::getDataTypeScalarSize(m_rgbAttrType); 478 int numSlots = isMatCase ? glu::getDataTypeMatrixNumColumns(m_rgbAttrType) : 1; // Matrix uses as many attribute slots as it has columns. 479 480 for (int slotNdx = 0; slotNdx < numSlots; slotNdx++) 481 { 482 int curLoc = location + slotNdx; 483 484 glEnableVertexAttribArray(curLoc); 485 glVertexAttribDivisor(curLoc, divisor); 486 487 if (isFloatCase) 488 glVertexAttribPointer(curLoc, typeSize, GL_FLOAT, GL_FALSE, 0, attrPtr); 489 else if (isIntCase) 490 glVertexAttribIPointer(curLoc, typeSize, GL_INT, 0, attrPtr); 491 else if (isUintCase) 492 glVertexAttribIPointer(curLoc, typeSize, GL_UNSIGNED_INT, 0, attrPtr); 493 else if (isMatCase) 494 { 495 int numRows = glu::getDataTypeMatrixNumRows(m_rgbAttrType); 496 int numCols = glu::getDataTypeMatrixNumColumns(m_rgbAttrType); 497 498 glVertexAttribPointer(curLoc, numRows, GL_FLOAT, GL_FALSE, numCols*numRows*sizeof(float), attrPtr); 499 } 500 else 501 DE_ASSERT(DE_FALSE); 502 } 503 } 504 505 void InstancedRenderingCase::setupAndRender (void) 506 { 507 deUint32 program = m_program->getProgram(); 508 509 glUseProgram(program); 510 511 { 512 // Setup attributes. 513 514 // Position attribute is non-instanced. 515 int positionLoc = glGetAttribLocation(program, "a_position"); 516 glEnableVertexAttribArray(positionLoc); 517 glVertexAttribPointer(positionLoc, 2, GL_FLOAT, GL_FALSE, 0, &m_gridVertexPositions[0]); 518 519 if (m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED) 520 { 521 if (m_instancingType == TYPE_ATTRIB_DIVISOR) 522 { 523 // Position offset attribute is instanced with separate offset for every instance. 524 int offsetLoc = glGetAttribLocation(program, "a_instanceOffset"); 525 glEnableVertexAttribArray(offsetLoc); 526 glVertexAttribDivisor(offsetLoc, 1); 527 glVertexAttribPointer(offsetLoc, OFFSET_COMPONENTS, GL_FLOAT, GL_FALSE, 0, &m_instanceOffsets[0]); 528 529 int rLoc = glGetAttribLocation(program, "a_instanceR"); 530 setupVarAttribPointer((void*)&m_instanceColorR[0].u32, rLoc, ATTRIB_DIVISOR_R); 531 } 532 533 int gLoc = glGetAttribLocation(program, "a_instanceG"); 534 setupVarAttribPointer((void*)&m_instanceColorG[0].u32, gLoc, ATTRIB_DIVISOR_G); 535 536 int bLoc = glGetAttribLocation(program, "a_instanceB"); 537 setupVarAttribPointer((void*)&m_instanceColorB[0].u32, bLoc, ATTRIB_DIVISOR_B); 538 } 539 } 540 541 // Draw using appropriate function. 542 543 if (m_function == FUNCTION_DRAW_ARRAYS_INSTANCED) 544 { 545 const int numPositionComponents = 2; 546 glDrawArraysInstanced(GL_TRIANGLES, 0, ((int)m_gridVertexPositions.size() / numPositionComponents), m_numInstances); 547 } 548 else 549 glDrawElementsInstanced(GL_TRIANGLES, (int)m_gridIndices.size(), GL_UNSIGNED_SHORT, &m_gridIndices[0], m_numInstances); 550 551 glUseProgram(0); 552 } 553 554 void InstancedRenderingCase::computeReference (tcu::Surface& dst) 555 { 556 int wid = dst.getWidth(); 557 int hei = dst.getHeight(); 558 559 // Draw a rectangle (vertical bar) for each instance. 560 561 for (int instanceNdx = 0; instanceNdx < m_numInstances; instanceNdx++) 562 { 563 int xStart = instanceNdx * wid / m_numInstances; 564 int xEnd = (instanceNdx + 1) * wid / m_numInstances; 565 566 // Emulate attribute divisors if that is the case. 567 568 int clrNdxR = m_instancingType == TYPE_ATTRIB_DIVISOR ? instanceNdx / ATTRIB_DIVISOR_R : instanceNdx; 569 int clrNdxG = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? instanceNdx / ATTRIB_DIVISOR_G : instanceNdx; 570 int clrNdxB = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? instanceNdx / ATTRIB_DIVISOR_B : instanceNdx; 571 572 int rInstances = m_instancingType == TYPE_ATTRIB_DIVISOR ? m_numInstances / ATTRIB_DIVISOR_R + (m_numInstances % ATTRIB_DIVISOR_R == 0 ? 0 : 1) : m_numInstances; 573 int gInstances = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? m_numInstances / ATTRIB_DIVISOR_G + (m_numInstances % ATTRIB_DIVISOR_G == 0 ? 0 : 1) : m_numInstances; 574 int bInstances = m_instancingType == TYPE_ATTRIB_DIVISOR || m_instancingType == TYPE_MIXED ? m_numInstances / ATTRIB_DIVISOR_B + (m_numInstances % ATTRIB_DIVISOR_B == 0 ? 0 : 1) : m_numInstances; 575 576 // Calculate colors. 577 578 float r = (float)clrNdxR / (float)rInstances; 579 float g = (float)clrNdxG * 2.0f / (float)gInstances; 580 float b = 1.0f - (float)clrNdxB / (float)bInstances; 581 582 // Convert to integer and back if shader inputs are integers. 583 584 if (glu::isDataTypeIntOrIVec(m_rgbAttrType)) 585 { 586 deInt32 intR = (deInt32)(r*FLOAT_INT_SCALE + FLOAT_INT_BIAS); 587 deInt32 intG = (deInt32)(g*FLOAT_INT_SCALE + FLOAT_INT_BIAS); 588 deInt32 intB = (deInt32)(b*FLOAT_INT_SCALE + FLOAT_INT_BIAS); 589 r = (float)(intR - FLOAT_INT_BIAS) / FLOAT_INT_SCALE; 590 g = (float)(intG - FLOAT_INT_BIAS) / FLOAT_INT_SCALE; 591 b = (float)(intB - FLOAT_INT_BIAS) / FLOAT_INT_SCALE; 592 } 593 else if(glu::isDataTypeUintOrUVec(m_rgbAttrType)) 594 { 595 deUint32 uintR = (deInt32)(r*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS); 596 deUint32 uintG = (deInt32)(g*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS); 597 deUint32 uintB = (deInt32)(b*FLOAT_UINT_SCALE + FLOAT_UINT_BIAS); 598 r = (float)(uintR - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE; 599 g = (float)(uintG - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE; 600 b = (float)(uintB - FLOAT_UINT_BIAS) / FLOAT_UINT_SCALE; 601 } 602 603 // Draw rectangle. 604 605 for (int y = 0; y < hei; y++) 606 for (int x = xStart; x < xEnd; x++) 607 dst.setPixel(x, y, tcu::RGBA(tcu::Vec4(r, g, b, 1.0f))); 608 } 609 } 610 611 InstancedRenderingTests::InstancedRenderingTests (Context& context) 612 : TestCaseGroup(context, "instanced", "Instanced rendering tests") 613 { 614 } 615 616 InstancedRenderingTests::~InstancedRenderingTests (void) 617 { 618 } 619 620 void InstancedRenderingTests::init (void) 621 { 622 // Cases testing function, instancing method and instance count. 623 624 static const int instanceCounts[] = { 1, 2, 4, 20 }; 625 626 for (int function = 0; function < (int)InstancedRenderingCase::FUNCTION_LAST; function++) 627 { 628 const char* functionName = function == (int)InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED ? "draw_arrays_instanced" 629 : function == (int)InstancedRenderingCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ? "draw_elements_instanced" 630 : DE_NULL; 631 632 const char* functionDesc = function == (int)InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED ? "Use glDrawArraysInstanced()" 633 : function == (int)InstancedRenderingCase::FUNCTION_DRAW_ELEMENTS_INSTANCED ? "Use glDrawElementsInstanced()" 634 : DE_NULL; 635 636 DE_ASSERT(functionName != DE_NULL); 637 DE_ASSERT(functionDesc != DE_NULL); 638 639 TestCaseGroup* functionGroup = new TestCaseGroup(m_context, functionName, functionDesc); 640 addChild(functionGroup); 641 642 for (int instancingType = 0; instancingType < (int)InstancedRenderingCase::TYPE_LAST; instancingType++) 643 { 644 const char* instancingTypeName = instancingType == (int)InstancedRenderingCase::TYPE_INSTANCE_ID ? "instance_id" 645 : instancingType == (int)InstancedRenderingCase::TYPE_ATTRIB_DIVISOR ? "attribute_divisor" 646 : instancingType == (int)InstancedRenderingCase::TYPE_MIXED ? "mixed" 647 : DE_NULL; 648 649 const char* instancingTypeDesc = instancingType == (int)InstancedRenderingCase::TYPE_INSTANCE_ID ? "Use gl_InstanceID for instancing" 650 : instancingType == (int)InstancedRenderingCase::TYPE_ATTRIB_DIVISOR ? "Use vertex attribute divisors for instancing" 651 : instancingType == (int)InstancedRenderingCase::TYPE_MIXED ? "Use both gl_InstanceID and vertex attribute divisors for instancing" 652 : DE_NULL; 653 654 DE_ASSERT(instancingTypeName != DE_NULL); 655 DE_ASSERT(instancingTypeDesc != DE_NULL); 656 657 TestCaseGroup* instancingTypeGroup = new TestCaseGroup(m_context, instancingTypeName, instancingTypeDesc); 658 functionGroup->addChild(instancingTypeGroup); 659 660 for (int countNdx = 0; countNdx < DE_LENGTH_OF_ARRAY(instanceCounts); countNdx++) 661 { 662 std::string countName = de::toString(instanceCounts[countNdx]) + "_instances"; 663 664 instancingTypeGroup->addChild(new InstancedRenderingCase(m_context, countName.c_str(), "", 665 (InstancedRenderingCase::DrawFunction)function, 666 (InstancedRenderingCase::InstancingType)instancingType, 667 glu::TYPE_FLOAT, 668 instanceCounts[countNdx])); 669 } 670 } 671 } 672 673 // Data type specific cases. 674 675 static const glu::DataType s_testTypes[] = 676 { 677 glu::TYPE_FLOAT, 678 glu::TYPE_FLOAT_VEC2, 679 glu::TYPE_FLOAT_VEC3, 680 glu::TYPE_FLOAT_VEC4, 681 glu::TYPE_FLOAT_MAT2, 682 glu::TYPE_FLOAT_MAT2X3, 683 glu::TYPE_FLOAT_MAT2X4, 684 glu::TYPE_FLOAT_MAT3X2, 685 glu::TYPE_FLOAT_MAT3, 686 glu::TYPE_FLOAT_MAT3X4, 687 glu::TYPE_FLOAT_MAT4X2, 688 glu::TYPE_FLOAT_MAT4X3, 689 glu::TYPE_FLOAT_MAT4, 690 691 glu::TYPE_INT, 692 glu::TYPE_INT_VEC2, 693 glu::TYPE_INT_VEC3, 694 glu::TYPE_INT_VEC4, 695 696 glu::TYPE_UINT, 697 glu::TYPE_UINT_VEC2, 698 glu::TYPE_UINT_VEC3, 699 glu::TYPE_UINT_VEC4 700 }; 701 702 const int typeTestNumInstances = 4; 703 704 TestCaseGroup* typesGroup = new TestCaseGroup(m_context, "types", "Tests for instanced attributes of particular data types"); 705 addChild(typesGroup); 706 707 for (int typeNdx = 0; typeNdx < DE_LENGTH_OF_ARRAY(s_testTypes); typeNdx++) 708 { 709 glu::DataType type = s_testTypes[typeNdx]; 710 711 typesGroup->addChild(new InstancedRenderingCase(m_context, glu::getDataTypeName(type), "", 712 InstancedRenderingCase::FUNCTION_DRAW_ARRAYS_INSTANCED, 713 InstancedRenderingCase::TYPE_ATTRIB_DIVISOR, 714 type, 715 typeTestNumInstances)); 716 } 717 } 718 719 } // Functional 720 } // gles3 721 } // deqp 722