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