1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program OpenGL ES 2.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 Functional rasterization tests. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "es2fRasterizationTests.hpp" 25 #include "tcuRasterizationVerifier.hpp" 26 #include "tcuSurface.hpp" 27 #include "tcuRenderTarget.hpp" 28 #include "tcuVectorUtil.hpp" 29 #include "tcuStringTemplate.hpp" 30 #include "tcuResultCollector.hpp" 31 #include "gluShaderProgram.hpp" 32 #include "gluRenderContext.hpp" 33 #include "gluPixelTransfer.hpp" 34 #include "gluStrUtil.hpp" 35 #include "deStringUtil.hpp" 36 #include "deRandom.hpp" 37 #include "glwFunctions.hpp" 38 #include "glwEnums.hpp" 39 40 #include <vector> 41 42 namespace deqp 43 { 44 namespace gles2 45 { 46 namespace Functional 47 { 48 namespace 49 { 50 51 using tcu::RasterizationArguments; 52 using tcu::TriangleSceneSpec; 53 using tcu::PointSceneSpec; 54 using tcu::LineSceneSpec; 55 using tcu::LineInterpolationMethod; 56 57 static const char* const s_shaderVertexTemplate = "attribute highp vec4 a_position;\n" 58 "attribute highp vec4 a_color;\n" 59 "varying highp vec4 v_color;\n" 60 "uniform highp float u_pointSize;\n" 61 "void main ()\n" 62 "{\n" 63 " gl_Position = a_position;\n" 64 " gl_PointSize = u_pointSize;\n" 65 " v_color = a_color;\n" 66 "}\n"; 67 static const char* const s_shaderFragmentTemplate = "varying mediump vec4 v_color;\n" 68 "void main ()\n" 69 "{\n" 70 " gl_FragColor = v_color;\n" 71 "}\n"; 72 enum InterpolationCaseFlags 73 { 74 INTERPOLATIONFLAGS_NONE = 0, 75 INTERPOLATIONFLAGS_PROJECTED = (1 << 1), 76 }; 77 78 enum PrimitiveWideness 79 { 80 PRIMITIVEWIDENESS_NARROW = 0, 81 PRIMITIVEWIDENESS_WIDE, 82 83 PRIMITIVEWIDENESS_LAST 84 }; 85 86 class BaseRenderingCase : public TestCase 87 { 88 public: 89 BaseRenderingCase (Context& context, const char* name, const char* desc, int renderSize = 256); 90 ~BaseRenderingCase (void); 91 virtual void init (void); 92 void deinit (void); 93 94 protected: 95 void drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, glw::GLenum primitiveType); 96 void drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, const std::vector<tcu::Vec4>& coloDrata, glw::GLenum primitiveType); 97 98 const int m_renderSize; 99 int m_numSamples; 100 int m_subpixelBits; 101 float m_pointSize; 102 float m_lineWidth; 103 104 private: 105 glu::ShaderProgram* m_shader; 106 }; 107 108 BaseRenderingCase::BaseRenderingCase (Context& context, const char* name, const char* desc, int renderSize) 109 : TestCase (context, name, desc) 110 , m_renderSize (renderSize) 111 , m_numSamples (-1) 112 , m_subpixelBits (-1) 113 , m_pointSize (1.0f) 114 , m_lineWidth (1.0f) 115 , m_shader (DE_NULL) 116 { 117 } 118 119 BaseRenderingCase::~BaseRenderingCase (void) 120 { 121 deinit(); 122 } 123 124 void BaseRenderingCase::init (void) 125 { 126 const int width = m_context.getRenderTarget().getWidth(); 127 const int height = m_context.getRenderTarget().getHeight(); 128 129 // Requirements 130 131 if (width < m_renderSize || height < m_renderSize) 132 throw tcu::NotSupportedError(std::string("Render target size must be at least ") + de::toString(m_renderSize) + "x" + de::toString(m_renderSize)); 133 134 if (m_lineWidth != 1.0f) 135 { 136 float range[2] = { 0.0f, 0.0f }; 137 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range); 138 139 if (m_lineWidth < range[0] || m_lineWidth > range[1]) 140 throw tcu::NotSupportedError(std::string("Support for line width ") + de::toString(m_lineWidth) + " is required."); 141 142 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage; 143 } 144 145 if (m_pointSize != 1.0f) 146 { 147 float range[2] = { 0.0f, 0.0f }; 148 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range); 149 150 if (m_pointSize < range[0] || m_pointSize > range[1]) 151 throw tcu::NotSupportedError(std::string("Support for point size ") + de::toString(m_pointSize) + " is required."); 152 153 m_testCtx.getLog() << tcu::TestLog::Message << "ALIASED_POINT_SIZE_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage; 154 } 155 156 // Query info 157 158 m_numSamples = m_context.getRenderTarget().getNumSamples(); 159 m_context.getRenderContext().getFunctions().getIntegerv(GL_SUBPIXEL_BITS, &m_subpixelBits); 160 161 m_testCtx.getLog() << tcu::TestLog::Message << "Sample count = " << m_numSamples << tcu::TestLog::EndMessage; 162 m_testCtx.getLog() << tcu::TestLog::Message << "SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage; 163 164 // Gen shader 165 166 { 167 tcu::StringTemplate vertexSource (s_shaderVertexTemplate); 168 tcu::StringTemplate fragmentSource (s_shaderFragmentTemplate); 169 std::map<std::string, std::string> params; 170 171 m_shader = new glu::ShaderProgram(m_context.getRenderContext(), glu::ProgramSources() << glu::VertexSource(vertexSource.specialize(params)) << glu::FragmentSource(fragmentSource.specialize(params))); 172 if (!m_shader->isOk()) 173 throw tcu::TestError("could not create shader"); 174 } 175 } 176 177 void BaseRenderingCase::deinit (void) 178 { 179 if (m_shader) 180 { 181 delete m_shader; 182 m_shader = DE_NULL; 183 } 184 } 185 186 void BaseRenderingCase::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, glw::GLenum primitiveType) 187 { 188 // default to color white 189 const std::vector<tcu::Vec4> colorData(vertexData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f)); 190 191 drawPrimitives(result, vertexData, colorData, primitiveType); 192 } 193 194 void BaseRenderingCase::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, const std::vector<tcu::Vec4>& colorData, glw::GLenum primitiveType) 195 { 196 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 197 const glw::GLint positionLoc = gl.getAttribLocation(m_shader->getProgram(), "a_position"); 198 const glw::GLint colorLoc = gl.getAttribLocation(m_shader->getProgram(), "a_color"); 199 const glw::GLint pointSizeLoc = gl.getUniformLocation(m_shader->getProgram(), "u_pointSize"); 200 201 gl.clearColor (0, 0, 0, 1); 202 gl.clear (GL_COLOR_BUFFER_BIT); 203 gl.viewport (0, 0, m_renderSize, m_renderSize); 204 gl.useProgram (m_shader->getProgram()); 205 gl.enableVertexAttribArray (positionLoc); 206 gl.vertexAttribPointer (positionLoc, 4, GL_FLOAT, GL_FALSE, 0, &vertexData[0]); 207 gl.enableVertexAttribArray (colorLoc); 208 gl.vertexAttribPointer (colorLoc, 4, GL_FLOAT, GL_FALSE, 0, &colorData[0]); 209 gl.uniform1f (pointSizeLoc, m_pointSize); 210 gl.lineWidth (m_lineWidth); 211 gl.drawArrays (primitiveType, 0, (glw::GLsizei)vertexData.size()); 212 gl.disableVertexAttribArray (colorLoc); 213 gl.disableVertexAttribArray (positionLoc); 214 gl.useProgram (0); 215 gl.finish (); 216 GLU_EXPECT_NO_ERROR (gl.getError(), "draw primitives"); 217 218 glu::readPixels(m_context.getRenderContext(), 0, 0, result.getAccess()); 219 } 220 221 class BaseTriangleCase : public BaseRenderingCase 222 { 223 public: 224 BaseTriangleCase (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType); 225 ~BaseTriangleCase (void); 226 IterateResult iterate (void); 227 228 private: 229 virtual void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) = DE_NULL; 230 231 int m_iteration; 232 const int m_iterationCount; 233 const glw::GLenum m_primitiveDrawType; 234 bool m_allIterationsPassed; 235 }; 236 237 BaseTriangleCase::BaseTriangleCase (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType) 238 : BaseRenderingCase (context, name, desc) 239 , m_iteration (0) 240 , m_iterationCount (3) 241 , m_primitiveDrawType (primitiveDrawType) 242 , m_allIterationsPassed (true) 243 { 244 } 245 246 BaseTriangleCase::~BaseTriangleCase (void) 247 { 248 } 249 250 BaseTriangleCase::IterateResult BaseTriangleCase::iterate (void) 251 { 252 const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); 253 const tcu::ScopedLogSection section (m_testCtx.getLog(), iterationDescription, iterationDescription); 254 tcu::Surface resultImage (m_renderSize, m_renderSize); 255 std::vector<tcu::Vec4> drawBuffer; 256 std::vector<TriangleSceneSpec::SceneTriangle> triangles; 257 258 generateTriangles(m_iteration, drawBuffer, triangles); 259 260 // draw image 261 drawPrimitives(resultImage, drawBuffer, m_primitiveDrawType); 262 263 // compare 264 { 265 bool compareOk; 266 RasterizationArguments args; 267 TriangleSceneSpec scene; 268 269 args.numSamples = m_numSamples; 270 args.subpixelBits = m_subpixelBits; 271 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits; 272 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits; 273 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits; 274 275 scene.triangles.swap(triangles); 276 277 compareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog()); 278 279 if (!compareOk) 280 m_allIterationsPassed = false; 281 } 282 283 // result 284 if (++m_iteration == m_iterationCount) 285 { 286 if (m_allIterationsPassed) 287 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 288 else 289 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization"); 290 291 return STOP; 292 } 293 else 294 return CONTINUE; 295 } 296 297 class BaseLineCase : public BaseRenderingCase 298 { 299 public: 300 BaseLineCase (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType, PrimitiveWideness wideness); 301 ~BaseLineCase (void); 302 IterateResult iterate (void); 303 304 private: 305 virtual void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) = DE_NULL; 306 307 int m_iteration; 308 const int m_iterationCount; 309 const glw::GLenum m_primitiveDrawType; 310 const PrimitiveWideness m_primitiveWideness; 311 bool m_allIterationsPassed; 312 bool m_multisampleRelaxationRequired; 313 314 static const float s_wideSize; 315 }; 316 317 const float BaseLineCase::s_wideSize = 5.0f; 318 319 BaseLineCase::BaseLineCase (Context& context, const char* name, const char* desc, glw::GLenum primitiveDrawType, PrimitiveWideness wideness) 320 : BaseRenderingCase (context, name, desc) 321 , m_iteration (0) 322 , m_iterationCount (3) 323 , m_primitiveDrawType (primitiveDrawType) 324 , m_primitiveWideness (wideness) 325 , m_allIterationsPassed (true) 326 , m_multisampleRelaxationRequired (false) 327 { 328 DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST); 329 m_lineWidth = (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) ? (s_wideSize) : (1.0f); 330 } 331 332 BaseLineCase::~BaseLineCase (void) 333 { 334 } 335 336 BaseLineCase::IterateResult BaseLineCase::iterate (void) 337 { 338 const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); 339 const tcu::ScopedLogSection section (m_testCtx.getLog(), iterationDescription, iterationDescription); 340 tcu::Surface resultImage (m_renderSize, m_renderSize); 341 std::vector<tcu::Vec4> drawBuffer; 342 std::vector<LineSceneSpec::SceneLine> lines; 343 344 // last iteration, max out size 345 if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE && 346 m_iteration+1 == m_iterationCount) 347 { 348 float range[2] = { 0.0f, 0.0f }; 349 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_LINE_WIDTH_RANGE, range); 350 351 m_lineWidth = range[1]; 352 } 353 354 // gen data 355 generateLines(m_iteration, drawBuffer, lines); 356 357 // draw image 358 drawPrimitives(resultImage, drawBuffer, m_primitiveDrawType); 359 360 // compare 361 { 362 bool compareOk; 363 RasterizationArguments args; 364 LineSceneSpec scene; 365 366 args.numSamples = m_numSamples; 367 args.subpixelBits = m_subpixelBits; 368 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits; 369 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits; 370 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits; 371 372 scene.lines.swap(lines); 373 scene.lineWidth = m_lineWidth; 374 375 compareOk = verifyLineGroupRasterization(resultImage, scene, args, m_testCtx.getLog()); 376 377 // multisampled wide lines might not be supported 378 if (scene.lineWidth != 1.0f && m_numSamples > 1 && !compareOk) 379 { 380 m_multisampleRelaxationRequired = true; 381 compareOk = true; 382 } 383 384 if (!compareOk) 385 m_allIterationsPassed = false; 386 } 387 388 // result 389 if (++m_iteration == m_iterationCount) 390 { 391 if (m_allIterationsPassed && m_multisampleRelaxationRequired) 392 m_testCtx.setTestResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Rasterization of multisampled wide lines failed"); 393 else if (m_allIterationsPassed) 394 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 395 else 396 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization"); 397 398 return STOP; 399 } 400 else 401 return CONTINUE; 402 } 403 404 class PointCase : public BaseRenderingCase 405 { 406 public: 407 PointCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness); 408 ~PointCase (void); 409 IterateResult iterate (void); 410 411 private: 412 void generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints); 413 414 int m_iteration; 415 const int m_iterationCount; 416 const PrimitiveWideness m_primitiveWideness; 417 bool m_allIterationsPassed; 418 419 static const float s_wideSize; 420 }; 421 422 const float PointCase::s_wideSize = 10.0f; 423 424 PointCase::PointCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness) 425 : BaseRenderingCase (context, name, desc) 426 , m_iteration (0) 427 , m_iterationCount (3) 428 , m_primitiveWideness (wideness) 429 , m_allIterationsPassed (true) 430 { 431 m_pointSize = (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE) ? (s_wideSize) : (1.0f); 432 } 433 434 PointCase::~PointCase (void) 435 { 436 } 437 438 PointCase::IterateResult PointCase::iterate (void) 439 { 440 const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); 441 const tcu::ScopedLogSection section (m_testCtx.getLog(), iterationDescription, iterationDescription); 442 tcu::Surface resultImage (m_renderSize, m_renderSize); 443 std::vector<tcu::Vec4> drawBuffer; 444 std::vector<PointSceneSpec::ScenePoint> points; 445 446 // last iteration, max out size 447 if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE && 448 m_iteration+1 == m_iterationCount) 449 { 450 float range[2] = { 0.0f, 0.0f }; 451 m_context.getRenderContext().getFunctions().getFloatv(GL_ALIASED_POINT_SIZE_RANGE, range); 452 453 m_pointSize = range[1]; 454 } 455 456 // gen data 457 generatePoints(m_iteration, drawBuffer, points); 458 459 // draw image 460 drawPrimitives(resultImage, drawBuffer, GL_POINTS); 461 462 // compare 463 { 464 bool compareOk; 465 RasterizationArguments args; 466 PointSceneSpec scene; 467 468 args.numSamples = m_numSamples; 469 args.subpixelBits = m_subpixelBits; 470 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits; 471 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits; 472 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits; 473 474 scene.points.swap(points); 475 476 compareOk = verifyPointGroupRasterization(resultImage, scene, args, m_testCtx.getLog()); 477 478 if (!compareOk) 479 m_allIterationsPassed = false; 480 } 481 482 // result 483 if (++m_iteration == m_iterationCount) 484 { 485 if (m_allIterationsPassed) 486 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 487 else 488 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rasterization"); 489 490 return STOP; 491 } 492 else 493 return CONTINUE; 494 } 495 496 void PointCase::generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints) 497 { 498 outData.resize(6); 499 500 switch (iteration) 501 { 502 case 0: 503 // \note: these values are chosen arbitrarily 504 outData[0] = tcu::Vec4( 0.2f, 0.8f, 0.0f, 1.0f); 505 outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); 506 outData[2] = tcu::Vec4( 0.5f, 0.3f, 0.0f, 1.0f); 507 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); 508 outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f); 509 outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f); 510 break; 511 512 case 1: 513 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); 514 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); 515 outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); 516 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 517 outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); 518 outData[5] = tcu::Vec4( 0.4f, 1.2f, 0.0f, 1.0f); 519 break; 520 521 case 2: 522 outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); 523 outData[1] = tcu::Vec4( 0.3f, -0.9f, 0.0f, 1.0f); 524 outData[2] = tcu::Vec4( -0.4f, -0.1f, 0.0f, 1.0f); 525 outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f); 526 outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); 527 outData[5] = tcu::Vec4( -0.4f, 0.4f, 0.0f, 1.0f); 528 break; 529 } 530 531 outPoints.resize(outData.size()); 532 for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx) 533 { 534 outPoints[pointNdx].position = outData[pointNdx]; 535 outPoints[pointNdx].pointSize = m_pointSize; 536 } 537 538 // log 539 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size() << " point(s): (point size = " << m_pointSize << ")" << tcu::TestLog::EndMessage; 540 for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx) 541 m_testCtx.getLog() << tcu::TestLog::Message << "Point " << (pointNdx+1) << ":\t" << outPoints[pointNdx].position << tcu::TestLog::EndMessage; 542 } 543 544 class TrianglesCase : public BaseTriangleCase 545 { 546 public: 547 TrianglesCase (Context& context, const char* name, const char* desc); 548 ~TrianglesCase (void); 549 550 void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles); 551 }; 552 553 TrianglesCase::TrianglesCase (Context& context, const char* name, const char* desc) 554 : BaseTriangleCase(context, name, desc, GL_TRIANGLES) 555 { 556 } 557 558 TrianglesCase::~TrianglesCase (void) 559 { 560 561 } 562 563 void TrianglesCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) 564 { 565 outData.resize(6); 566 567 switch (iteration) 568 { 569 case 0: 570 // \note: these values are chosen arbitrarily 571 outData[0] = tcu::Vec4( 0.2f, 0.8f, 0.0f, 1.0f); 572 outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); 573 outData[2] = tcu::Vec4( 0.5f, 0.3f, 0.0f, 1.0f); 574 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); 575 outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f); 576 outData[5] = tcu::Vec4(-0.4f, 0.2f, 0.0f, 1.0f); 577 break; 578 579 case 1: 580 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); 581 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); 582 outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); 583 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 584 outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); 585 outData[5] = tcu::Vec4( 0.4f, 1.2f, 0.0f, 1.0f); 586 break; 587 588 case 2: 589 outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); 590 outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); 591 outData[2] = tcu::Vec4( -1.1f, -0.1f, 0.0f, 1.0f); 592 outData[3] = tcu::Vec4(-0.11f, 0.2f, 0.0f, 1.0f); 593 outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); 594 outData[5] = tcu::Vec4( -0.4f, 0.4f, 0.0f, 1.0f); 595 break; 596 } 597 598 outTriangles.resize(2); 599 outTriangles[0].positions[0] = outData[0]; outTriangles[0].sharedEdge[0] = false; 600 outTriangles[0].positions[1] = outData[1]; outTriangles[0].sharedEdge[1] = false; 601 outTriangles[0].positions[2] = outData[2]; outTriangles[0].sharedEdge[2] = false; 602 603 outTriangles[1].positions[0] = outData[3]; outTriangles[1].sharedEdge[0] = false; 604 outTriangles[1].positions[1] = outData[4]; outTriangles[1].sharedEdge[1] = false; 605 outTriangles[1].positions[2] = outData[5]; outTriangles[1].sharedEdge[2] = false; 606 607 // log 608 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage; 609 for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx) 610 { 611 m_testCtx.getLog() 612 << tcu::TestLog::Message 613 << "Triangle " << (triangleNdx+1) << ":" 614 << "\n\t" << outTriangles[triangleNdx].positions[0] 615 << "\n\t" << outTriangles[triangleNdx].positions[1] 616 << "\n\t" << outTriangles[triangleNdx].positions[2] 617 << tcu::TestLog::EndMessage; 618 } 619 } 620 621 class TriangleStripCase : public BaseTriangleCase 622 { 623 public: 624 TriangleStripCase (Context& context, const char* name, const char* desc); 625 626 void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles); 627 }; 628 629 TriangleStripCase::TriangleStripCase (Context& context, const char* name, const char* desc) 630 : BaseTriangleCase(context, name, desc, GL_TRIANGLE_STRIP) 631 { 632 } 633 634 void TriangleStripCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) 635 { 636 outData.resize(5); 637 638 switch (iteration) 639 { 640 case 0: 641 // \note: these values are chosen arbitrarily 642 outData[0] = tcu::Vec4(-0.504f, 0.8f, 0.0f, 1.0f); 643 outData[1] = tcu::Vec4(-0.2f, -0.2f, 0.0f, 1.0f); 644 outData[2] = tcu::Vec4(-0.2f, 0.199f, 0.0f, 1.0f); 645 outData[3] = tcu::Vec4( 0.5f, 0.201f, 0.0f, 1.0f); 646 outData[4] = tcu::Vec4( 1.5f, 0.4f, 0.0f, 1.0f); 647 break; 648 649 case 1: 650 outData[0] = tcu::Vec4(-0.499f, 0.129f, 0.0f, 1.0f); 651 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); 652 outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); 653 outData[3] = tcu::Vec4( 0.11f, -0.31f, 0.0f, 1.0f); 654 outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); 655 break; 656 657 case 2: 658 outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); 659 outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); 660 outData[2] = tcu::Vec4(-0.87f, -0.1f, 0.0f, 1.0f); 661 outData[3] = tcu::Vec4(-0.11f, 0.19f, 0.0f, 1.0f); 662 outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); 663 break; 664 } 665 666 outTriangles.resize(3); 667 outTriangles[0].positions[0] = outData[0]; outTriangles[0].sharedEdge[0] = false; 668 outTriangles[0].positions[1] = outData[1]; outTriangles[0].sharedEdge[1] = true; 669 outTriangles[0].positions[2] = outData[2]; outTriangles[0].sharedEdge[2] = false; 670 671 outTriangles[1].positions[0] = outData[2]; outTriangles[1].sharedEdge[0] = true; 672 outTriangles[1].positions[1] = outData[1]; outTriangles[1].sharedEdge[1] = false; 673 outTriangles[1].positions[2] = outData[3]; outTriangles[1].sharedEdge[2] = true; 674 675 outTriangles[2].positions[0] = outData[2]; outTriangles[2].sharedEdge[0] = true; 676 outTriangles[2].positions[1] = outData[3]; outTriangles[2].sharedEdge[1] = false; 677 outTriangles[2].positions[2] = outData[4]; outTriangles[2].sharedEdge[2] = false; 678 679 // log 680 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size() << " vertices." << tcu::TestLog::EndMessage; 681 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) 682 { 683 m_testCtx.getLog() 684 << tcu::TestLog::Message 685 << "\t" << outData[vtxNdx] 686 << tcu::TestLog::EndMessage; 687 } 688 } 689 690 class TriangleFanCase : public BaseTriangleCase 691 { 692 public: 693 TriangleFanCase (Context& context, const char* name, const char* desc); 694 695 void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles); 696 }; 697 698 TriangleFanCase::TriangleFanCase (Context& context, const char* name, const char* desc) 699 : BaseTriangleCase(context, name, desc, GL_TRIANGLE_FAN) 700 { 701 } 702 703 void TriangleFanCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) 704 { 705 outData.resize(5); 706 707 switch (iteration) 708 { 709 case 0: 710 // \note: these values are chosen arbitrarily 711 outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f); 712 outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); 713 outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f); 714 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); 715 outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f); 716 break; 717 718 case 1: 719 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); 720 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); 721 outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); 722 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 723 outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); 724 break; 725 726 case 2: 727 outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); 728 outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); 729 outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f); 730 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 731 outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); 732 break; 733 } 734 735 outTriangles.resize(3); 736 outTriangles[0].positions[0] = outData[0]; outTriangles[0].sharedEdge[0] = false; 737 outTriangles[0].positions[1] = outData[1]; outTriangles[0].sharedEdge[1] = false; 738 outTriangles[0].positions[2] = outData[2]; outTriangles[0].sharedEdge[2] = true; 739 740 outTriangles[1].positions[0] = outData[0]; outTriangles[1].sharedEdge[0] = true; 741 outTriangles[1].positions[1] = outData[2]; outTriangles[1].sharedEdge[1] = false; 742 outTriangles[1].positions[2] = outData[3]; outTriangles[1].sharedEdge[2] = true; 743 744 outTriangles[2].positions[0] = outData[0]; outTriangles[2].sharedEdge[0] = true; 745 outTriangles[2].positions[1] = outData[3]; outTriangles[2].sharedEdge[1] = false; 746 outTriangles[2].positions[2] = outData[4]; outTriangles[2].sharedEdge[2] = false; 747 748 // log 749 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size() << " vertices." << tcu::TestLog::EndMessage; 750 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) 751 { 752 m_testCtx.getLog() 753 << tcu::TestLog::Message 754 << "\t" << outData[vtxNdx] 755 << tcu::TestLog::EndMessage; 756 } 757 } 758 759 class LinesCase : public BaseLineCase 760 { 761 public: 762 LinesCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness); 763 764 void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines); 765 }; 766 767 LinesCase::LinesCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness) 768 : BaseLineCase(context, name, desc, GL_LINES, wideness) 769 { 770 } 771 772 void LinesCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) 773 { 774 outData.resize(6); 775 776 switch (iteration) 777 { 778 case 0: 779 // \note: these values are chosen arbitrarily 780 outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f); 781 outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); 782 outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f); 783 outData[3] = tcu::Vec4(-0.3f, 0.2f, 0.0f, 1.0f); 784 outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f); 785 outData[5] = tcu::Vec4( 0.1f, 0.5f, 0.0f, 1.0f); 786 break; 787 788 case 1: 789 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); 790 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); 791 outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); 792 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 793 outData[4] = tcu::Vec4( 0.88f, 0.9f, 0.0f, 1.0f); 794 outData[5] = tcu::Vec4( 0.18f, -0.2f, 0.0f, 1.0f); 795 break; 796 797 case 2: 798 outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); 799 outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); 800 outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f); 801 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 802 outData[4] = tcu::Vec4( 0.88f, 0.7f, 0.0f, 1.0f); 803 outData[5] = tcu::Vec4( 0.8f, -0.7f, 0.0f, 1.0f); 804 break; 805 } 806 807 outLines.resize(3); 808 outLines[0].positions[0] = outData[0]; 809 outLines[0].positions[1] = outData[1]; 810 outLines[1].positions[0] = outData[2]; 811 outLines[1].positions[1] = outData[3]; 812 outLines[2].positions[0] = outData[4]; 813 outLines[2].positions[1] = outData[5]; 814 815 // log 816 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering " << outLines.size() << " lines(s): (width = " << m_lineWidth << ")" << tcu::TestLog::EndMessage; 817 for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx) 818 { 819 m_testCtx.getLog() 820 << tcu::TestLog::Message 821 << "Line " << (lineNdx+1) << ":" 822 << "\n\t" << outLines[lineNdx].positions[0] 823 << "\n\t" << outLines[lineNdx].positions[1] 824 << tcu::TestLog::EndMessage; 825 } 826 } 827 828 class LineStripCase : public BaseLineCase 829 { 830 public: 831 LineStripCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness); 832 833 void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines); 834 }; 835 836 LineStripCase::LineStripCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness) 837 : BaseLineCase(context, name, desc, GL_LINE_STRIP, wideness) 838 { 839 } 840 841 void LineStripCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) 842 { 843 outData.resize(4); 844 845 switch (iteration) 846 { 847 case 0: 848 // \note: these values are chosen arbitrarily 849 outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f); 850 outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); 851 outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f); 852 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); 853 break; 854 855 case 1: 856 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); 857 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); 858 outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); 859 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 860 break; 861 862 case 2: 863 outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); 864 outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); 865 outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f); 866 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 867 break; 868 } 869 870 outLines.resize(3); 871 outLines[0].positions[0] = outData[0]; 872 outLines[0].positions[1] = outData[1]; 873 outLines[1].positions[0] = outData[1]; 874 outLines[1].positions[1] = outData[2]; 875 outLines[2].positions[0] = outData[2]; 876 outLines[2].positions[1] = outData[3]; 877 878 // log 879 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << m_lineWidth << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage; 880 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) 881 { 882 m_testCtx.getLog() 883 << tcu::TestLog::Message 884 << "\t" << outData[vtxNdx] 885 << tcu::TestLog::EndMessage; 886 } 887 } 888 889 class LineLoopCase : public BaseLineCase 890 { 891 public: 892 LineLoopCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness); 893 894 void generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines); 895 }; 896 897 LineLoopCase::LineLoopCase (Context& context, const char* name, const char* desc, PrimitiveWideness wideness) 898 : BaseLineCase(context, name, desc, GL_LINE_LOOP, wideness) 899 { 900 } 901 902 void LineLoopCase::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) 903 { 904 outData.resize(4); 905 906 switch (iteration) 907 { 908 case 0: 909 // \note: these values are chosen arbitrarily 910 outData[0] = tcu::Vec4( 0.01f, 0.0f, 0.0f, 1.0f); 911 outData[1] = tcu::Vec4( 0.5f, 0.2f, 0.0f, 1.0f); 912 outData[2] = tcu::Vec4( 0.46f, 0.3f, 0.0f, 1.0f); 913 outData[3] = tcu::Vec4(-0.5f, 0.2f, 0.0f, 1.0f); 914 break; 915 916 case 1: 917 outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f); 918 outData[1] = tcu::Vec4(-0.501f, -0.3f, 0.0f, 1.0f); 919 outData[2] = tcu::Vec4( 0.11f, -0.2f, 0.0f, 1.0f); 920 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 921 break; 922 923 case 2: 924 outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f); 925 outData[1] = tcu::Vec4( 1.1f, -0.9f, 0.0f, 1.0f); 926 outData[2] = tcu::Vec4( 0.7f, -0.1f, 0.0f, 1.0f); 927 outData[3] = tcu::Vec4( 0.11f, 0.2f, 0.0f, 1.0f); 928 break; 929 } 930 931 outLines.resize(4); 932 outLines[0].positions[0] = outData[0]; 933 outLines[0].positions[1] = outData[1]; 934 outLines[1].positions[0] = outData[1]; 935 outLines[1].positions[1] = outData[2]; 936 outLines[2].positions[0] = outData[2]; 937 outLines[2].positions[1] = outData[3]; 938 outLines[3].positions[0] = outData[3]; 939 outLines[3].positions[1] = outData[0]; 940 941 // log 942 m_testCtx.getLog() << tcu::TestLog::Message << "Rendering line loop, width = " << m_lineWidth << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage; 943 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) 944 { 945 m_testCtx.getLog() 946 << tcu::TestLog::Message 947 << "\t" << outData[vtxNdx] 948 << tcu::TestLog::EndMessage; 949 } 950 } 951 952 class FillRuleCase : public BaseRenderingCase 953 { 954 public: 955 enum FillRuleCaseType 956 { 957 FILLRULECASE_BASIC = 0, 958 FILLRULECASE_REVERSED, 959 FILLRULECASE_CLIPPED_FULL, 960 FILLRULECASE_CLIPPED_PARTIAL, 961 FILLRULECASE_PROJECTED, 962 963 FILLRULECASE_LAST 964 }; 965 966 FillRuleCase (Context& ctx, const char* name, const char* desc, FillRuleCaseType type); 967 ~FillRuleCase (void); 968 IterateResult iterate (void); 969 970 private: 971 int getRenderSize (FillRuleCase::FillRuleCaseType type) const; 972 int getNumIterations (FillRuleCase::FillRuleCaseType type) const; 973 void generateTriangles (int iteration, std::vector<tcu::Vec4>& outData) const; 974 975 const FillRuleCaseType m_caseType; 976 int m_iteration; 977 const int m_iterationCount; 978 bool m_allIterationsPassed; 979 980 }; 981 982 FillRuleCase::FillRuleCase (Context& ctx, const char* name, const char* desc, FillRuleCaseType type) 983 : BaseRenderingCase (ctx, name, desc, getRenderSize(type)) 984 , m_caseType (type) 985 , m_iteration (0) 986 , m_iterationCount (getNumIterations(type)) 987 , m_allIterationsPassed (true) 988 { 989 DE_ASSERT(type < FILLRULECASE_LAST); 990 } 991 992 FillRuleCase::~FillRuleCase (void) 993 { 994 deinit(); 995 } 996 997 FillRuleCase::IterateResult FillRuleCase::iterate (void) 998 { 999 const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); 1000 const tcu::ScopedLogSection section (m_testCtx.getLog(), iterationDescription, iterationDescription); 1001 const int thresholdRed = 1 << (8 - m_context.getRenderTarget().getPixelFormat().redBits); 1002 const int thresholdGreen = 1 << (8 - m_context.getRenderTarget().getPixelFormat().greenBits); 1003 const int thresholdBlue = 1 << (8 - m_context.getRenderTarget().getPixelFormat().blueBits); 1004 tcu::Surface resultImage (m_renderSize, m_renderSize); 1005 std::vector<tcu::Vec4> drawBuffer; 1006 bool imageShown = false; 1007 1008 generateTriangles(m_iteration, drawBuffer); 1009 1010 // draw image 1011 { 1012 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1013 const std::vector<tcu::Vec4> colorBuffer (drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f)); 1014 1015 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments." << tcu::TestLog::EndMessage; 1016 1017 gl.enable(GL_BLEND); 1018 gl.blendEquation(GL_FUNC_ADD); 1019 gl.blendFunc(GL_ONE, GL_ONE); 1020 drawPrimitives(resultImage, drawBuffer, colorBuffer, GL_TRIANGLES); 1021 } 1022 1023 // verify no overdraw 1024 { 1025 const tcu::RGBA triangleColor = tcu::RGBA(127, 127, 127, 255); 1026 bool overdraw = false; 1027 1028 m_testCtx.getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage; 1029 1030 for (int y = 0; y < resultImage.getHeight(); ++y) 1031 for (int x = 0; x < resultImage.getWidth(); ++x) 1032 { 1033 const tcu::RGBA color = resultImage.getPixel(x, y); 1034 1035 // color values are greater than triangle color? Allow lower values for multisampled edges and background. 1036 if ((color.getRed() - triangleColor.getRed()) > thresholdRed || 1037 (color.getGreen() - triangleColor.getGreen()) > thresholdGreen || 1038 (color.getBlue() - triangleColor.getBlue()) > thresholdBlue) 1039 overdraw = true; 1040 } 1041 1042 // results 1043 if (!overdraw) 1044 m_testCtx.getLog() << tcu::TestLog::Message << "No overlapping fragments detected." << tcu::TestLog::EndMessage; 1045 else 1046 { 1047 m_testCtx.getLog() << tcu::TestLog::Message << "Overlapping fragments detected, image is not valid." << tcu::TestLog::EndMessage; 1048 m_testCtx.getLog() << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering") 1049 << tcu::TestLog::Image("Result", "Result", resultImage) 1050 << tcu::TestLog::EndImageSet; 1051 1052 imageShown = true; 1053 m_allIterationsPassed = false; 1054 } 1055 } 1056 1057 // verify no missing fragments in the full viewport case 1058 if (m_caseType == FILLRULECASE_CLIPPED_FULL) 1059 { 1060 bool missingFragments = false; 1061 1062 m_testCtx.getLog() << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage; 1063 1064 for (int y = 0; y < resultImage.getHeight(); ++y) 1065 for (int x = 0; x < resultImage.getWidth(); ++x) 1066 { 1067 const tcu::RGBA color = resultImage.getPixel(x, y); 1068 1069 // black? (background) 1070 if (color.getRed() <= thresholdRed || 1071 color.getGreen() <= thresholdGreen || 1072 color.getBlue() <= thresholdBlue) 1073 missingFragments = true; 1074 } 1075 1076 // results 1077 if (!missingFragments) 1078 m_testCtx.getLog() << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage; 1079 else 1080 { 1081 m_testCtx.getLog() << tcu::TestLog::Message << "Missing fragments detected, image is not valid." << tcu::TestLog::EndMessage; 1082 1083 if (!imageShown) 1084 { 1085 m_testCtx.getLog() << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering") 1086 << tcu::TestLog::Image("Result", "Result", resultImage) 1087 << tcu::TestLog::EndImageSet; 1088 } 1089 1090 m_allIterationsPassed = false; 1091 } 1092 } 1093 1094 // result 1095 if (++m_iteration == m_iterationCount) 1096 { 1097 if (m_allIterationsPassed) 1098 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1099 else 1100 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixels"); 1101 1102 return STOP; 1103 } 1104 else 1105 return CONTINUE; 1106 } 1107 1108 int FillRuleCase::getRenderSize (FillRuleCase::FillRuleCaseType type) const 1109 { 1110 if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL) 1111 return 64; 1112 else 1113 return 256; 1114 } 1115 1116 int FillRuleCase::getNumIterations (FillRuleCase::FillRuleCaseType type) const 1117 { 1118 if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL) 1119 return 15; 1120 else 1121 return 2; 1122 } 1123 1124 void FillRuleCase::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData) const 1125 { 1126 switch (m_caseType) 1127 { 1128 case FILLRULECASE_BASIC: 1129 case FILLRULECASE_REVERSED: 1130 case FILLRULECASE_PROJECTED: 1131 { 1132 const int numRows = 4; 1133 const int numColumns = 4; 1134 const float quadSide = 0.15f; 1135 de::Random rnd (0xabcd); 1136 1137 outData.resize(6 * numRows * numColumns); 1138 1139 for (int col = 0; col < numColumns; ++col) 1140 for (int row = 0; row < numRows; ++row) 1141 { 1142 const tcu::Vec2 center = tcu::Vec2(((float)row + 0.5f) / (float)numRows * 2.0f - 1.0f, ((float)col + 0.5f) / (float)numColumns * 2.0f - 1.0f); 1143 const float rotation = float(iteration * numColumns * numRows + col * numRows + row) / (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f; 1144 const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation)); 1145 const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x()); 1146 const tcu::Vec2 quad[4] = 1147 { 1148 center + sideH + sideV, 1149 center + sideH - sideV, 1150 center - sideH - sideV, 1151 center - sideH + sideV, 1152 }; 1153 1154 if (m_caseType == FILLRULECASE_BASIC) 1155 { 1156 outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); 1157 outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f); 1158 outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); 1159 outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); 1160 outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); 1161 outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f); 1162 } 1163 else if (m_caseType == FILLRULECASE_REVERSED) 1164 { 1165 outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); 1166 outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f); 1167 outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); 1168 outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); 1169 outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); 1170 outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f); 1171 } 1172 else if (m_caseType == FILLRULECASE_PROJECTED) 1173 { 1174 const float w0 = rnd.getFloat(0.1f, 4.0f); 1175 const float w1 = rnd.getFloat(0.1f, 4.0f); 1176 const float w2 = rnd.getFloat(0.1f, 4.0f); 1177 const float w3 = rnd.getFloat(0.1f, 4.0f); 1178 1179 outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0); 1180 outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1); 1181 outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2); 1182 outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2); 1183 outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0); 1184 outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3); 1185 } 1186 else 1187 DE_ASSERT(DE_FALSE); 1188 } 1189 1190 break; 1191 } 1192 1193 case FILLRULECASE_CLIPPED_PARTIAL: 1194 case FILLRULECASE_CLIPPED_FULL: 1195 { 1196 const float quadSide = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f); 1197 const tcu::Vec2 center = (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f)); 1198 const float rotation = (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f; 1199 const tcu::Vec2 sideH = quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation)); 1200 const tcu::Vec2 sideV = tcu::Vec2(sideH.y(), -sideH.x()); 1201 const tcu::Vec2 quad[4] = 1202 { 1203 center + sideH + sideV, 1204 center + sideH - sideV, 1205 center - sideH - sideV, 1206 center - sideH + sideV, 1207 }; 1208 1209 outData.resize(6); 1210 outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); 1211 outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f); 1212 outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); 1213 outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f); 1214 outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f); 1215 outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f); 1216 break; 1217 } 1218 1219 default: 1220 DE_ASSERT(DE_FALSE); 1221 } 1222 } 1223 1224 class CullingTest : public BaseRenderingCase 1225 { 1226 public: 1227 CullingTest (Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder); 1228 ~CullingTest (void); 1229 IterateResult iterate (void); 1230 1231 private: 1232 void generateVertices (std::vector<tcu::Vec4>& outData) const; 1233 void extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const; 1234 bool triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const; 1235 1236 const glw::GLenum m_cullMode; 1237 const glw::GLenum m_primitive; 1238 const glw::GLenum m_faceOrder; 1239 }; 1240 1241 CullingTest::CullingTest (Context& ctx, const char* name, const char* desc, glw::GLenum cullMode, glw::GLenum primitive, glw::GLenum faceOrder) 1242 : BaseRenderingCase (ctx, name, desc) 1243 , m_cullMode (cullMode) 1244 , m_primitive (primitive) 1245 , m_faceOrder (faceOrder) 1246 { 1247 } 1248 1249 CullingTest::~CullingTest (void) 1250 { 1251 } 1252 1253 CullingTest::IterateResult CullingTest::iterate (void) 1254 { 1255 tcu::Surface resultImage(m_renderSize, m_renderSize); 1256 std::vector<tcu::Vec4> drawBuffer; 1257 std::vector<TriangleSceneSpec::SceneTriangle> triangles; 1258 1259 // generate scene 1260 generateVertices(drawBuffer); 1261 extractTriangles(triangles, drawBuffer); 1262 1263 // draw image 1264 { 1265 const glw::Functions& gl = m_context.getRenderContext().getFunctions(); 1266 1267 gl.enable(GL_CULL_FACE); 1268 gl.cullFace(m_cullMode); 1269 gl.frontFace(m_faceOrder); 1270 1271 m_testCtx.getLog() << tcu::TestLog::Message << "Setting front face to " << glu::getWindingName(m_faceOrder) << tcu::TestLog::EndMessage; 1272 m_testCtx.getLog() << tcu::TestLog::Message << "Setting cull face to " << glu::getFaceName(m_cullMode) << tcu::TestLog::EndMessage; 1273 m_testCtx.getLog() << tcu::TestLog::Message << "Drawing test pattern (" << glu::getPrimitiveTypeName(m_primitive) << ")" << tcu::TestLog::EndMessage; 1274 1275 drawPrimitives(resultImage, drawBuffer, m_primitive); 1276 } 1277 1278 // compare 1279 { 1280 RasterizationArguments args; 1281 TriangleSceneSpec scene; 1282 1283 args.numSamples = m_numSamples; 1284 args.subpixelBits = m_subpixelBits; 1285 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits; 1286 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits; 1287 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits; 1288 1289 scene.triangles.swap(triangles); 1290 1291 if (verifyTriangleGroupRasterization(resultImage, scene, args, m_testCtx.getLog(), tcu::VERIFICATIONMODE_WEAK)) 1292 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1293 else 1294 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Incorrect rendering"); 1295 } 1296 1297 return STOP; 1298 } 1299 1300 void CullingTest::generateVertices (std::vector<tcu::Vec4>& outData) const 1301 { 1302 de::Random rnd(543210); 1303 1304 outData.resize(6); 1305 for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx) 1306 { 1307 outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f); 1308 outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f); 1309 outData[vtxNdx].z() = 0.0f; 1310 outData[vtxNdx].w() = 1.0f; 1311 } 1312 } 1313 1314 void CullingTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const 1315 { 1316 const bool cullDirection = (m_cullMode == GL_FRONT) ^ (m_faceOrder == GL_CCW); 1317 1318 // No triangles 1319 if (m_cullMode == GL_FRONT_AND_BACK) 1320 return; 1321 1322 switch (m_primitive) 1323 { 1324 case GL_TRIANGLES: 1325 { 1326 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3) 1327 { 1328 const tcu::Vec4& v0 = vertices[vtxNdx + 0]; 1329 const tcu::Vec4& v1 = vertices[vtxNdx + 1]; 1330 const tcu::Vec4& v2 = vertices[vtxNdx + 2]; 1331 1332 if (triangleOrder(v0, v1, v2) != cullDirection) 1333 { 1334 TriangleSceneSpec::SceneTriangle tri; 1335 tri.positions[0] = v0; tri.sharedEdge[0] = false; 1336 tri.positions[1] = v1; tri.sharedEdge[1] = false; 1337 tri.positions[2] = v2; tri.sharedEdge[2] = false; 1338 1339 outTriangles.push_back(tri); 1340 } 1341 } 1342 break; 1343 } 1344 1345 case GL_TRIANGLE_STRIP: 1346 { 1347 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx) 1348 { 1349 const tcu::Vec4& v0 = vertices[vtxNdx + 0]; 1350 const tcu::Vec4& v1 = vertices[vtxNdx + 1]; 1351 const tcu::Vec4& v2 = vertices[vtxNdx + 2]; 1352 1353 if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0))) 1354 { 1355 TriangleSceneSpec::SceneTriangle tri; 1356 tri.positions[0] = v0; tri.sharedEdge[0] = false; 1357 tri.positions[1] = v1; tri.sharedEdge[1] = false; 1358 tri.positions[2] = v2; tri.sharedEdge[2] = false; 1359 1360 outTriangles.push_back(tri); 1361 } 1362 } 1363 break; 1364 } 1365 1366 case GL_TRIANGLE_FAN: 1367 { 1368 for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx) 1369 { 1370 const tcu::Vec4& v0 = vertices[0]; 1371 const tcu::Vec4& v1 = vertices[vtxNdx + 0]; 1372 const tcu::Vec4& v2 = vertices[vtxNdx + 1]; 1373 1374 if (triangleOrder(v0, v1, v2) != cullDirection) 1375 { 1376 TriangleSceneSpec::SceneTriangle tri; 1377 tri.positions[0] = v0; tri.sharedEdge[0] = false; 1378 tri.positions[1] = v1; tri.sharedEdge[1] = false; 1379 tri.positions[2] = v2; tri.sharedEdge[2] = false; 1380 1381 outTriangles.push_back(tri); 1382 } 1383 } 1384 break; 1385 } 1386 1387 default: 1388 DE_ASSERT(false); 1389 } 1390 } 1391 1392 bool CullingTest::triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const 1393 { 1394 const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w(); 1395 const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w(); 1396 const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w(); 1397 1398 // cross 1399 return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) < 0; 1400 } 1401 1402 class TriangleInterpolationTest : public BaseRenderingCase 1403 { 1404 public: 1405 TriangleInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags); 1406 ~TriangleInterpolationTest (void); 1407 IterateResult iterate (void); 1408 1409 private: 1410 void generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const; 1411 void extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const; 1412 1413 const glw::GLenum m_primitive; 1414 const bool m_projective; 1415 const int m_iterationCount; 1416 1417 int m_iteration; 1418 bool m_allIterationsPassed; 1419 }; 1420 1421 TriangleInterpolationTest::TriangleInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags) 1422 : BaseRenderingCase (ctx, name, desc) 1423 , m_primitive (primitive) 1424 , m_projective ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0) 1425 , m_iterationCount (3) 1426 , m_iteration (0) 1427 , m_allIterationsPassed (true) 1428 { 1429 } 1430 1431 TriangleInterpolationTest::~TriangleInterpolationTest (void) 1432 { 1433 deinit(); 1434 } 1435 1436 TriangleInterpolationTest::IterateResult TriangleInterpolationTest::iterate (void) 1437 { 1438 const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); 1439 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription); 1440 tcu::Surface resultImage (m_renderSize, m_renderSize); 1441 std::vector<tcu::Vec4> drawBuffer; 1442 std::vector<tcu::Vec4> colorBuffer; 1443 std::vector<TriangleSceneSpec::SceneTriangle> triangles; 1444 1445 // generate scene 1446 generateVertices(m_iteration, drawBuffer, colorBuffer); 1447 extractTriangles(triangles, drawBuffer, colorBuffer); 1448 1449 // log 1450 { 1451 m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage; 1452 for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx) 1453 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage; 1454 } 1455 1456 // draw image 1457 drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive); 1458 1459 // compare 1460 { 1461 RasterizationArguments args; 1462 TriangleSceneSpec scene; 1463 1464 args.numSamples = m_numSamples; 1465 args.subpixelBits = m_subpixelBits; 1466 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits; 1467 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits; 1468 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits; 1469 1470 scene.triangles.swap(triangles); 1471 1472 if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_testCtx.getLog())) 1473 m_allIterationsPassed = false; 1474 } 1475 1476 // result 1477 if (++m_iteration == m_iterationCount) 1478 { 1479 if (m_allIterationsPassed) 1480 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 1481 else 1482 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values"); 1483 1484 return STOP; 1485 } 1486 else 1487 return CONTINUE; 1488 } 1489 1490 void TriangleInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const 1491 { 1492 // use only red, green and blue 1493 const tcu::Vec4 colors[] = 1494 { 1495 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), 1496 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), 1497 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), 1498 }; 1499 1500 de::Random rnd(123 + iteration * 1000 + (int)m_primitive); 1501 1502 outVertices.resize(6); 1503 outColors.resize(6); 1504 1505 for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx) 1506 { 1507 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f); 1508 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f); 1509 outVertices[vtxNdx].z() = 0.0f; 1510 1511 if (!m_projective) 1512 outVertices[vtxNdx].w() = 1.0f; 1513 else 1514 { 1515 const float w = rnd.getFloat(0.2f, 4.0f); 1516 1517 outVertices[vtxNdx].x() *= w; 1518 outVertices[vtxNdx].y() *= w; 1519 outVertices[vtxNdx].z() *= w; 1520 outVertices[vtxNdx].w() = w; 1521 } 1522 1523 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)]; 1524 } 1525 } 1526 1527 void TriangleInterpolationTest::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const 1528 { 1529 switch (m_primitive) 1530 { 1531 case GL_TRIANGLES: 1532 { 1533 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3) 1534 { 1535 TriangleSceneSpec::SceneTriangle tri; 1536 tri.positions[0] = vertices[vtxNdx + 0]; 1537 tri.positions[1] = vertices[vtxNdx + 1]; 1538 tri.positions[2] = vertices[vtxNdx + 2]; 1539 tri.sharedEdge[0] = false; 1540 tri.sharedEdge[1] = false; 1541 tri.sharedEdge[2] = false; 1542 1543 tri.colors[0] = colors[vtxNdx + 0]; 1544 tri.colors[1] = colors[vtxNdx + 1]; 1545 tri.colors[2] = colors[vtxNdx + 2]; 1546 1547 outTriangles.push_back(tri); 1548 } 1549 break; 1550 } 1551 1552 case GL_TRIANGLE_STRIP: 1553 { 1554 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx) 1555 { 1556 TriangleSceneSpec::SceneTriangle tri; 1557 tri.positions[0] = vertices[vtxNdx + 0]; 1558 tri.positions[1] = vertices[vtxNdx + 1]; 1559 tri.positions[2] = vertices[vtxNdx + 2]; 1560 tri.sharedEdge[0] = false; 1561 tri.sharedEdge[1] = false; 1562 tri.sharedEdge[2] = false; 1563 1564 tri.colors[0] = colors[vtxNdx + 0]; 1565 tri.colors[1] = colors[vtxNdx + 1]; 1566 tri.colors[2] = colors[vtxNdx + 2]; 1567 1568 outTriangles.push_back(tri); 1569 } 1570 break; 1571 } 1572 1573 case GL_TRIANGLE_FAN: 1574 { 1575 for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx) 1576 { 1577 TriangleSceneSpec::SceneTriangle tri; 1578 tri.positions[0] = vertices[0]; 1579 tri.positions[1] = vertices[vtxNdx + 0]; 1580 tri.positions[2] = vertices[vtxNdx + 1]; 1581 tri.sharedEdge[0] = false; 1582 tri.sharedEdge[1] = false; 1583 tri.sharedEdge[2] = false; 1584 1585 tri.colors[0] = colors[0]; 1586 tri.colors[1] = colors[vtxNdx + 0]; 1587 tri.colors[2] = colors[vtxNdx + 1]; 1588 1589 outTriangles.push_back(tri); 1590 } 1591 break; 1592 } 1593 1594 default: 1595 DE_ASSERT(false); 1596 } 1597 } 1598 1599 class LineInterpolationTest : public BaseRenderingCase 1600 { 1601 public: 1602 LineInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, float lineWidth); 1603 ~LineInterpolationTest (void); 1604 IterateResult iterate (void); 1605 1606 private: 1607 void generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const; 1608 void extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const; 1609 1610 const glw::GLenum m_primitive; 1611 const bool m_projective; 1612 const int m_iterationCount; 1613 1614 int m_iteration; 1615 tcu::ResultCollector m_result; 1616 }; 1617 1618 LineInterpolationTest::LineInterpolationTest (Context& ctx, const char* name, const char* desc, glw::GLenum primitive, int flags, float lineWidth) 1619 : BaseRenderingCase (ctx, name, desc) 1620 , m_primitive (primitive) 1621 , m_projective ((flags & INTERPOLATIONFLAGS_PROJECTED) != 0) 1622 , m_iterationCount (3) 1623 , m_iteration (0) 1624 { 1625 m_lineWidth = lineWidth; 1626 } 1627 1628 LineInterpolationTest::~LineInterpolationTest (void) 1629 { 1630 deinit(); 1631 } 1632 1633 LineInterpolationTest::IterateResult LineInterpolationTest::iterate (void) 1634 { 1635 const std::string iterationDescription = "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount); 1636 const tcu::ScopedLogSection section (m_testCtx.getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription); 1637 tcu::Surface resultImage (m_renderSize, m_renderSize); 1638 std::vector<tcu::Vec4> drawBuffer; 1639 std::vector<tcu::Vec4> colorBuffer; 1640 std::vector<LineSceneSpec::SceneLine> lines; 1641 1642 // generate scene 1643 generateVertices(m_iteration, drawBuffer, colorBuffer); 1644 extractLines(lines, drawBuffer, colorBuffer); 1645 1646 // log 1647 { 1648 m_testCtx.getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage; 1649 for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx) 1650 m_testCtx.getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage; 1651 } 1652 1653 // draw image 1654 drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitive); 1655 1656 // compare 1657 { 1658 RasterizationArguments args; 1659 LineSceneSpec scene; 1660 LineInterpolationMethod iterationResult; 1661 1662 args.numSamples = m_numSamples; 1663 args.subpixelBits = m_subpixelBits; 1664 args.redBits = m_context.getRenderTarget().getPixelFormat().redBits; 1665 args.greenBits = m_context.getRenderTarget().getPixelFormat().greenBits; 1666 args.blueBits = m_context.getRenderTarget().getPixelFormat().blueBits; 1667 1668 scene.lines.swap(lines); 1669 scene.lineWidth = m_lineWidth; 1670 1671 iterationResult = verifyLineGroupInterpolation(resultImage, scene, args, m_testCtx.getLog()); 1672 switch (iterationResult) 1673 { 1674 case tcu::LINEINTERPOLATION_STRICTLY_CORRECT: 1675 // line interpolation matches the specification 1676 m_result.addResult(QP_TEST_RESULT_PASS, "Pass"); 1677 break; 1678 1679 case tcu::LINEINTERPOLATION_PROJECTED: 1680 // line interpolation weights are otherwise correct, but they are projected onto major axis 1681 m_testCtx.getLog() << tcu::TestLog::Message 1682 << "Interpolation was calculated using coordinates projected onto major axis. " 1683 "This method does not produce the same values as the non-projecting method defined in the specification." 1684 << tcu::TestLog::EndMessage; 1685 m_result.addResult(QP_TEST_RESULT_QUALITY_WARNING, "Interpolation was calculated using projected coordinateds"); 1686 break; 1687 1688 case tcu::LINEINTERPOLATION_INCORRECT: 1689 if (scene.lineWidth != 1.0f && m_numSamples > 1) 1690 { 1691 // multisampled wide lines might not be supported 1692 m_result.addResult(QP_TEST_RESULT_COMPATIBILITY_WARNING, "Interpolation of multisampled wide lines failed"); 1693 } 1694 else 1695 { 1696 // line interpolation is incorrect 1697 m_result.addResult(QP_TEST_RESULT_FAIL, "Found invalid pixel values"); 1698 } 1699 break; 1700 1701 default: 1702 DE_ASSERT(false); 1703 break; 1704 } 1705 } 1706 1707 // result 1708 if (++m_iteration == m_iterationCount) 1709 { 1710 m_result.setTestContextResult(m_testCtx); 1711 return STOP; 1712 } 1713 else 1714 return CONTINUE; 1715 } 1716 1717 void LineInterpolationTest::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const 1718 { 1719 // use only red, green and blue 1720 const tcu::Vec4 colors[] = 1721 { 1722 tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), 1723 tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), 1724 tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), 1725 }; 1726 1727 de::Random rnd(123 + iteration * 1000 + (int)m_primitive); 1728 1729 outVertices.resize(6); 1730 outColors.resize(6); 1731 1732 for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx) 1733 { 1734 outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f); 1735 outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f); 1736 outVertices[vtxNdx].z() = 0.0f; 1737 1738 if (!m_projective) 1739 outVertices[vtxNdx].w() = 1.0f; 1740 else 1741 { 1742 const float w = rnd.getFloat(0.2f, 4.0f); 1743 1744 outVertices[vtxNdx].x() *= w; 1745 outVertices[vtxNdx].y() *= w; 1746 outVertices[vtxNdx].z() *= w; 1747 outVertices[vtxNdx].w() = w; 1748 } 1749 1750 outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)]; 1751 } 1752 } 1753 1754 void LineInterpolationTest::extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const 1755 { 1756 switch (m_primitive) 1757 { 1758 case GL_LINES: 1759 { 1760 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2) 1761 { 1762 LineSceneSpec::SceneLine line; 1763 line.positions[0] = vertices[vtxNdx + 0]; 1764 line.positions[1] = vertices[vtxNdx + 1]; 1765 1766 line.colors[0] = colors[vtxNdx + 0]; 1767 line.colors[1] = colors[vtxNdx + 1]; 1768 1769 outLines.push_back(line); 1770 } 1771 break; 1772 } 1773 1774 case GL_LINE_STRIP: 1775 { 1776 for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx) 1777 { 1778 LineSceneSpec::SceneLine line; 1779 line.positions[0] = vertices[vtxNdx + 0]; 1780 line.positions[1] = vertices[vtxNdx + 1]; 1781 1782 line.colors[0] = colors[vtxNdx + 0]; 1783 line.colors[1] = colors[vtxNdx + 1]; 1784 1785 outLines.push_back(line); 1786 } 1787 break; 1788 } 1789 1790 case GL_LINE_LOOP: 1791 { 1792 for (int vtxNdx = 0; vtxNdx < (int)vertices.size(); ++vtxNdx) 1793 { 1794 LineSceneSpec::SceneLine line; 1795 line.positions[0] = vertices[(vtxNdx + 0) % (int)vertices.size()]; 1796 line.positions[1] = vertices[(vtxNdx + 1) % (int)vertices.size()]; 1797 1798 line.colors[0] = colors[(vtxNdx + 0) % (int)vertices.size()]; 1799 line.colors[1] = colors[(vtxNdx + 1) % (int)vertices.size()]; 1800 1801 outLines.push_back(line); 1802 } 1803 break; 1804 } 1805 1806 default: 1807 DE_ASSERT(false); 1808 } 1809 } 1810 1811 } // anonymous 1812 1813 RasterizationTests::RasterizationTests (Context& context) 1814 : TestCaseGroup(context, "rasterization", "Rasterization Tests") 1815 { 1816 } 1817 1818 RasterizationTests::~RasterizationTests (void) 1819 { 1820 } 1821 1822 void RasterizationTests::init (void) 1823 { 1824 // .primitives 1825 { 1826 tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(m_testCtx, "primitives", "Primitive rasterization"); 1827 1828 addChild(primitives); 1829 1830 primitives->addChild(new TrianglesCase (m_context, "triangles", "Render primitives as GL_TRIANGLES, verify rasterization result")); 1831 primitives->addChild(new TriangleStripCase (m_context, "triangle_strip", "Render primitives as GL_TRIANGLE_STRIP, verify rasterization result")); 1832 primitives->addChild(new TriangleFanCase (m_context, "triangle_fan", "Render primitives as GL_TRIANGLE_FAN, verify rasterization result")); 1833 primitives->addChild(new LinesCase (m_context, "lines", "Render primitives as GL_LINES, verify rasterization result", PRIMITIVEWIDENESS_NARROW)); 1834 primitives->addChild(new LineStripCase (m_context, "line_strip", "Render primitives as GL_LINE_STRIP, verify rasterization result", PRIMITIVEWIDENESS_NARROW)); 1835 primitives->addChild(new LineLoopCase (m_context, "line_loop", "Render primitives as GL_LINE_LOOP, verify rasterization result", PRIMITIVEWIDENESS_NARROW)); 1836 primitives->addChild(new LinesCase (m_context, "lines_wide", "Render primitives as GL_LINES with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE)); 1837 primitives->addChild(new LineStripCase (m_context, "line_strip_wide", "Render primitives as GL_LINE_STRIP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE)); 1838 primitives->addChild(new LineLoopCase (m_context, "line_loop_wide", "Render primitives as GL_LINE_LOOP with wide lines, verify rasterization result", PRIMITIVEWIDENESS_WIDE)); 1839 primitives->addChild(new PointCase (m_context, "points", "Render primitives as GL_POINTS, verify rasterization result", PRIMITIVEWIDENESS_WIDE)); 1840 } 1841 1842 // .fill_rules 1843 { 1844 tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(m_testCtx, "fill_rules", "Primitive fill rules"); 1845 1846 addChild(fillRules); 1847 1848 fillRules->addChild(new FillRuleCase(m_context, "basic_quad", "Verify fill rules", FillRuleCase::FILLRULECASE_BASIC)); 1849 fillRules->addChild(new FillRuleCase(m_context, "basic_quad_reverse", "Verify fill rules", FillRuleCase::FILLRULECASE_REVERSED)); 1850 fillRules->addChild(new FillRuleCase(m_context, "clipped_full", "Verify fill rules", FillRuleCase::FILLRULECASE_CLIPPED_FULL)); 1851 fillRules->addChild(new FillRuleCase(m_context, "clipped_partly", "Verify fill rules", FillRuleCase::FILLRULECASE_CLIPPED_PARTIAL)); 1852 fillRules->addChild(new FillRuleCase(m_context, "projected", "Verify fill rules", FillRuleCase::FILLRULECASE_PROJECTED)); 1853 } 1854 1855 // .culling 1856 { 1857 static const struct CullMode 1858 { 1859 glw::GLenum mode; 1860 const char* prefix; 1861 } cullModes[] = 1862 { 1863 { GL_FRONT, "front_" }, 1864 { GL_BACK, "back_" }, 1865 { GL_FRONT_AND_BACK, "both_" }, 1866 }; 1867 static const struct PrimitiveType 1868 { 1869 glw::GLenum type; 1870 const char* name; 1871 } primitiveTypes[] = 1872 { 1873 { GL_TRIANGLES, "triangles" }, 1874 { GL_TRIANGLE_STRIP, "triangle_strip" }, 1875 { GL_TRIANGLE_FAN, "triangle_fan" }, 1876 }; 1877 static const struct FrontFaceOrder 1878 { 1879 glw::GLenum mode; 1880 const char* postfix; 1881 } frontOrders[] = 1882 { 1883 { GL_CCW, "" }, 1884 { GL_CW, "_reverse" }, 1885 }; 1886 1887 tcu::TestCaseGroup* const culling = new tcu::TestCaseGroup(m_testCtx, "culling", "Culling"); 1888 1889 addChild(culling); 1890 1891 for (int cullModeNdx = 0; cullModeNdx < DE_LENGTH_OF_ARRAY(cullModes); ++cullModeNdx) 1892 for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx) 1893 for (int frontOrderNdx = 0; frontOrderNdx < DE_LENGTH_OF_ARRAY(frontOrders); ++frontOrderNdx) 1894 { 1895 const std::string name = std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix; 1896 1897 culling->addChild(new CullingTest(m_context, name.c_str(), "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode)); 1898 } 1899 } 1900 1901 // .interpolation 1902 { 1903 tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(m_testCtx, "interpolation", "Test interpolation"); 1904 1905 addChild(interpolation); 1906 1907 // .basic 1908 { 1909 tcu::TestCaseGroup* const basic = new tcu::TestCaseGroup(m_testCtx, "basic", "Non-projective interpolation"); 1910 1911 interpolation->addChild(basic); 1912 1913 basic->addChild(new TriangleInterpolationTest (m_context, "triangles", "Verify triangle interpolation", GL_TRIANGLES, INTERPOLATIONFLAGS_NONE)); 1914 basic->addChild(new TriangleInterpolationTest (m_context, "triangle_strip", "Verify triangle strip interpolation", GL_TRIANGLE_STRIP, INTERPOLATIONFLAGS_NONE)); 1915 basic->addChild(new TriangleInterpolationTest (m_context, "triangle_fan", "Verify triangle fan interpolation", GL_TRIANGLE_FAN, INTERPOLATIONFLAGS_NONE)); 1916 basic->addChild(new LineInterpolationTest (m_context, "lines", "Verify line interpolation", GL_LINES, INTERPOLATIONFLAGS_NONE, 1.0f)); 1917 basic->addChild(new LineInterpolationTest (m_context, "line_strip", "Verify line strip interpolation", GL_LINE_STRIP, INTERPOLATIONFLAGS_NONE, 1.0f)); 1918 basic->addChild(new LineInterpolationTest (m_context, "line_loop", "Verify line loop interpolation", GL_LINE_LOOP, INTERPOLATIONFLAGS_NONE, 1.0f)); 1919 basic->addChild(new LineInterpolationTest (m_context, "lines_wide", "Verify wide line interpolation", GL_LINES, INTERPOLATIONFLAGS_NONE, 5.0f)); 1920 basic->addChild(new LineInterpolationTest (m_context, "line_strip_wide", "Verify wide line strip interpolation", GL_LINE_STRIP, INTERPOLATIONFLAGS_NONE, 5.0f)); 1921 basic->addChild(new LineInterpolationTest (m_context, "line_loop_wide", "Verify wide line loop interpolation", GL_LINE_LOOP, INTERPOLATIONFLAGS_NONE, 5.0f)); 1922 } 1923 1924 // .projected 1925 { 1926 tcu::TestCaseGroup* const projected = new tcu::TestCaseGroup(m_testCtx, "projected", "Projective interpolation"); 1927 1928 interpolation->addChild(projected); 1929 1930 projected->addChild(new TriangleInterpolationTest (m_context, "triangles", "Verify triangle interpolation", GL_TRIANGLES, INTERPOLATIONFLAGS_PROJECTED)); 1931 projected->addChild(new TriangleInterpolationTest (m_context, "triangle_strip", "Verify triangle strip interpolation", GL_TRIANGLE_STRIP, INTERPOLATIONFLAGS_PROJECTED)); 1932 projected->addChild(new TriangleInterpolationTest (m_context, "triangle_fan", "Verify triangle fan interpolation", GL_TRIANGLE_FAN, INTERPOLATIONFLAGS_PROJECTED)); 1933 projected->addChild(new LineInterpolationTest (m_context, "lines", "Verify line interpolation", GL_LINES, INTERPOLATIONFLAGS_PROJECTED, 1.0f)); 1934 projected->addChild(new LineInterpolationTest (m_context, "line_strip", "Verify line strip interpolation", GL_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, 1.0f)); 1935 projected->addChild(new LineInterpolationTest (m_context, "line_loop", "Verify line loop interpolation", GL_LINE_LOOP, INTERPOLATIONFLAGS_PROJECTED, 1.0f)); 1936 projected->addChild(new LineInterpolationTest (m_context, "lines_wide", "Verify wide line interpolation", GL_LINES, INTERPOLATIONFLAGS_PROJECTED, 5.0f)); 1937 projected->addChild(new LineInterpolationTest (m_context, "line_strip_wide", "Verify wide line strip interpolation", GL_LINE_STRIP, INTERPOLATIONFLAGS_PROJECTED, 5.0f)); 1938 projected->addChild(new LineInterpolationTest (m_context, "line_loop_wide", "Verify wide line loop interpolation", GL_LINE_LOOP, INTERPOLATIONFLAGS_PROJECTED, 5.0f)); 1939 } 1940 } 1941 } 1942 1943 } // Functional 1944 } // gles2 1945 } // deqp 1946