1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program EGL 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 Rendering tests for different config and api combinations. 22 * \todo [2013-03-19 pyry] GLES1 and VG support. 23 *//*--------------------------------------------------------------------*/ 24 25 #include "teglRenderTests.hpp" 26 #include "teglRenderCase.hpp" 27 #include "tcuRenderTarget.hpp" 28 #include "tcuTestLog.hpp" 29 #include "tcuImageCompare.hpp" 30 #include "tcuTextureUtil.hpp" 31 #include "tcuSurface.hpp" 32 33 #include "deRandom.hpp" 34 #include "deSharedPtr.hpp" 35 #include "deSemaphore.hpp" 36 #include "deThread.hpp" 37 #include "deString.h" 38 39 #include <algorithm> 40 #include <iterator> 41 #include <memory> 42 #include <set> 43 44 #include <EGL/eglext.h> 45 46 #if !defined(EGL_OPENGL_ES3_BIT_KHR) 47 # define EGL_OPENGL_ES3_BIT_KHR 0x0040 48 #endif 49 #if !defined(EGL_CONTEXT_MAJOR_VERSION_KHR) 50 # define EGL_CONTEXT_MAJOR_VERSION_KHR EGL_CONTEXT_CLIENT_VERSION 51 #endif 52 53 #if defined(DEQP_SUPPORT_GLES2) 54 # include <GLES2/gl2.h> 55 #elif defined(DEQP_SUPPORT_GLES3) 56 # include <GLES3/gl3.h> 57 #endif 58 59 #include "rrRenderer.hpp" 60 #include "rrFragmentOperations.hpp" 61 62 #if defined(DEQP_SUPPORT_GLES2) || defined(DEQP_SUPPORT_GLES3) 63 # include "gluDefs.hpp" 64 #else 65 // \todo [pyry] Move renderer to common utils 66 // \note [jarkko] gluDefs is required for GLU_CHECK_MSG 67 # error "Reference renderer requires GLES2 or GLES3 support" 68 #endif 69 70 namespace deqp 71 { 72 namespace egl 73 { 74 75 using std::string; 76 using std::vector; 77 using std::set; 78 79 using tcu::Vec4; 80 81 using tcu::TestLog; 82 83 static const tcu::Vec4 CLEAR_COLOR = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f); 84 static const float CLEAR_DEPTH = 1.0f; 85 static const int CLEAR_STENCIL = 0; 86 87 namespace 88 { 89 90 enum PrimitiveType 91 { 92 PRIMITIVETYPE_TRIANGLE = 0, //!< Triangles, requires 3 coordinates per primitive 93 // PRIMITIVETYPE_POINT, //!< Points, requires 1 coordinate per primitive (w is used as size) 94 // PRIMITIVETYPE_LINE, //!< Lines, requires 2 coordinates per primitive 95 96 PRIMITIVETYPE_LAST 97 }; 98 99 enum BlendMode 100 { 101 BLENDMODE_NONE = 0, //!< No blending 102 BLENDMODE_ADDITIVE, //!< Blending with ONE, ONE 103 BLENDMODE_SRC_OVER, //!< Blending with SRC_ALPHA, ONE_MINUS_SRC_ALPHA 104 105 BLENDMODE_LAST 106 }; 107 108 enum DepthMode 109 { 110 DEPTHMODE_NONE = 0, //!< No depth test or depth writes 111 DEPTHMODE_LESS, //!< Depth test with less & depth write 112 113 DEPTHMODE_LAST 114 }; 115 116 enum StencilMode 117 { 118 STENCILMODE_NONE = 0, //!< No stencil test or write 119 STENCILMODE_LEQUAL_INC, //!< Stencil test with LEQUAL, increment on pass 120 121 STENCILMODE_LAST 122 }; 123 124 struct DrawPrimitiveOp 125 { 126 PrimitiveType type; 127 int count; 128 vector<Vec4> positions; 129 vector<Vec4> colors; 130 BlendMode blend; 131 DepthMode depth; 132 StencilMode stencil; 133 int stencilRef; 134 }; 135 136 void randomizeDrawOp (de::Random& rnd, DrawPrimitiveOp& drawOp) 137 { 138 const int minStencilRef = 0; 139 const int maxStencilRef = 8; 140 const int minPrimitives = 2; 141 const int maxPrimitives = 4; 142 143 const float maxTriOffset = 1.0f; 144 const float minDepth = -1.0f; // \todo [pyry] Reference doesn't support Z clipping yet 145 const float maxDepth = 1.0f; 146 147 const float minRGB = 0.2f; 148 const float maxRGB = 0.9f; 149 const float minAlpha = 0.3f; 150 const float maxAlpha = 1.0f; 151 152 drawOp.type = (PrimitiveType)rnd.getInt(0, PRIMITIVETYPE_LAST-1); 153 drawOp.count = rnd.getInt(minPrimitives, maxPrimitives); 154 drawOp.blend = (BlendMode)rnd.getInt(0, BLENDMODE_LAST-1); 155 drawOp.depth = (DepthMode)rnd.getInt(0, DEPTHMODE_LAST-1); 156 drawOp.stencil = (StencilMode)rnd.getInt(0, STENCILMODE_LAST-1); 157 drawOp.stencilRef = rnd.getInt(minStencilRef, maxStencilRef); 158 159 if (drawOp.type == PRIMITIVETYPE_TRIANGLE) 160 { 161 drawOp.positions.resize(drawOp.count*3); 162 drawOp.colors.resize(drawOp.count*3); 163 164 for (int triNdx = 0; triNdx < drawOp.count; triNdx++) 165 { 166 const float cx = rnd.getFloat(-1.0f, 1.0f); 167 const float cy = rnd.getFloat(-1.0f, 1.0f); 168 169 for (int coordNdx = 0; coordNdx < 3; coordNdx++) 170 { 171 tcu::Vec4& position = drawOp.positions[triNdx*3 + coordNdx]; 172 tcu::Vec4& color = drawOp.colors[triNdx*3 + coordNdx]; 173 174 position.x() = cx + rnd.getFloat(-maxTriOffset, maxTriOffset); 175 position.y() = cy + rnd.getFloat(-maxTriOffset, maxTriOffset); 176 position.z() = rnd.getFloat(minDepth, maxDepth); 177 position.w() = 1.0f; 178 179 color.x() = rnd.getFloat(minRGB, maxRGB); 180 color.y() = rnd.getFloat(minRGB, maxRGB); 181 color.z() = rnd.getFloat(minRGB, maxRGB); 182 color.w() = rnd.getFloat(minAlpha, maxAlpha); 183 } 184 } 185 } 186 else 187 DE_ASSERT(false); 188 } 189 190 // Reference rendering code 191 192 class ReferenceShader : public rr::VertexShader, public rr::FragmentShader 193 { 194 public: 195 enum 196 { 197 VaryingLoc_Color = 0 198 }; 199 200 ReferenceShader () 201 : rr::VertexShader (2, 1) // color and pos in => color out 202 , rr::FragmentShader(1, 1) // color in => color out 203 { 204 this->rr::VertexShader::m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 205 this->rr::VertexShader::m_inputs[1].type = rr::GENERICVECTYPE_FLOAT; 206 207 this->rr::VertexShader::m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 208 this->rr::VertexShader::m_outputs[0].flatshade = false; 209 210 this->rr::FragmentShader::m_inputs[0].type = rr::GENERICVECTYPE_FLOAT; 211 this->rr::FragmentShader::m_inputs[0].flatshade = false; 212 213 this->rr::FragmentShader::m_outputs[0].type = rr::GENERICVECTYPE_FLOAT; 214 } 215 216 void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const 217 { 218 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 219 { 220 const int positionAttrLoc = 0; 221 const int colorAttrLoc = 1; 222 223 rr::VertexPacket& packet = *packets[packetNdx]; 224 225 // Transform to position 226 packet.position = rr::readVertexAttribFloat(inputs[positionAttrLoc], packet.instanceNdx, packet.vertexNdx); 227 228 // Pass color to FS 229 packet.outputs[VaryingLoc_Color] = rr::readVertexAttribFloat(inputs[colorAttrLoc], packet.instanceNdx, packet.vertexNdx); 230 } 231 } 232 233 void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const 234 { 235 for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) 236 { 237 rr::FragmentPacket& packet = packets[packetNdx]; 238 239 for (int fragNdx = 0; fragNdx < 4; ++fragNdx) 240 rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, rr::readVarying<float>(packet, context, VaryingLoc_Color, fragNdx)); 241 } 242 } 243 }; 244 245 void toReferenceRenderState (rr::RenderState& state, const DrawPrimitiveOp& drawOp) 246 { 247 state.cullMode = rr::CULLMODE_NONE; 248 249 if (drawOp.blend != BLENDMODE_NONE) 250 { 251 state.fragOps.blendMode = rr::BLENDMODE_STANDARD; 252 253 switch (drawOp.blend) 254 { 255 case BLENDMODE_ADDITIVE: 256 state.fragOps.blendRGBState.srcFunc = rr::BLENDFUNC_ONE; 257 state.fragOps.blendRGBState.dstFunc = rr::BLENDFUNC_ONE; 258 state.fragOps.blendRGBState.equation = rr::BLENDEQUATION_ADD; 259 state.fragOps.blendAState = state.fragOps.blendRGBState; 260 break; 261 262 case BLENDMODE_SRC_OVER: 263 state.fragOps.blendRGBState.srcFunc = rr::BLENDFUNC_SRC_ALPHA; 264 state.fragOps.blendRGBState.dstFunc = rr::BLENDFUNC_ONE_MINUS_SRC_ALPHA; 265 state.fragOps.blendRGBState.equation = rr::BLENDEQUATION_ADD; 266 state.fragOps.blendAState = state.fragOps.blendRGBState; 267 break; 268 269 default: 270 DE_ASSERT(false); 271 } 272 } 273 274 if (drawOp.depth != DEPTHMODE_NONE) 275 { 276 state.fragOps.depthTestEnabled = true; 277 278 DE_ASSERT(drawOp.depth == DEPTHMODE_LESS); 279 state.fragOps.depthFunc = rr::TESTFUNC_LESS; 280 } 281 282 if (drawOp.stencil != STENCILMODE_NONE) 283 { 284 state.fragOps.stencilTestEnabled = true; 285 286 DE_ASSERT(drawOp.stencil == STENCILMODE_LEQUAL_INC); 287 state.fragOps.stencilStates[0].func = rr::TESTFUNC_LEQUAL; 288 state.fragOps.stencilStates[0].sFail = rr::STENCILOP_KEEP; 289 state.fragOps.stencilStates[0].dpFail = rr::STENCILOP_INCR; 290 state.fragOps.stencilStates[0].dpPass = rr::STENCILOP_INCR; 291 state.fragOps.stencilStates[0].ref = drawOp.stencilRef; 292 state.fragOps.stencilStates[1] = state.fragOps.stencilStates[0]; 293 } 294 } 295 296 tcu::TextureFormat getColorFormat (const tcu::PixelFormat& colorBits) 297 { 298 using tcu::TextureFormat; 299 300 DE_ASSERT(de::inBounds(colorBits.redBits, 0, 0xff) && 301 de::inBounds(colorBits.greenBits, 0, 0xff) && 302 de::inBounds(colorBits.blueBits, 0, 0xff) && 303 de::inBounds(colorBits.alphaBits, 0, 0xff)); 304 305 #define PACK_FMT(R, G, B, A) (((R) << 24) | ((G) << 16) | ((B) << 8) | (A)) 306 307 // \note [pyry] This may not hold true on some implementations - best effort guess only. 308 switch (PACK_FMT(colorBits.redBits, colorBits.greenBits, colorBits.blueBits, colorBits.alphaBits)) 309 { 310 case PACK_FMT(8,8,8,8): return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8); 311 case PACK_FMT(8,8,8,0): return TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8); 312 case PACK_FMT(4,4,4,4): return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_4444); 313 case PACK_FMT(5,5,5,1): return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_SHORT_5551); 314 case PACK_FMT(5,6,5,0): return TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_SHORT_565); 315 316 // \note Defaults to RGBA8 317 default: return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8); 318 } 319 320 #undef PACK_FMT 321 } 322 323 tcu::TextureFormat getDepthFormat (const int depthBits) 324 { 325 switch (depthBits) 326 { 327 case 0: return tcu::TextureFormat(); 328 case 8: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8); 329 case 16: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16); 330 case 24: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNSIGNED_INT_24_8); 331 case 32: 332 default: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT); 333 } 334 } 335 336 tcu::TextureFormat getStencilFormat (int stencilBits) 337 { 338 switch (stencilBits) 339 { 340 case 0: return tcu::TextureFormat(); 341 case 8: 342 default: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8); 343 } 344 } 345 346 void renderReference (const tcu::PixelBufferAccess& dst, const vector<DrawPrimitiveOp>& drawOps, const tcu::PixelFormat& colorBits, const int depthBits, const int stencilBits, const int numSamples) 347 { 348 const int width = dst.getWidth(); 349 const int height = dst.getHeight(); 350 351 tcu::TextureLevel colorBuffer; 352 tcu::TextureLevel depthBuffer; 353 tcu::TextureLevel stencilBuffer; 354 355 rr::Renderer referenceRenderer; 356 rr::VertexAttrib attributes[2]; 357 const ReferenceShader shader; 358 359 attributes[0].type = rr::VERTEXATTRIBTYPE_FLOAT; 360 attributes[0].size = 4; 361 attributes[0].stride = 0; 362 attributes[0].instanceDivisor = 0; 363 364 attributes[1].type = rr::VERTEXATTRIBTYPE_FLOAT; 365 attributes[1].size = 4; 366 attributes[1].stride = 0; 367 attributes[1].instanceDivisor = 0; 368 369 // Initialize buffers. 370 colorBuffer.setStorage(getColorFormat(colorBits), numSamples, width, height); 371 rr::clearMultisampleColorBuffer(colorBuffer, CLEAR_COLOR, rr::WindowRectangle(0, 0, width, height)); 372 373 if (depthBits > 0) 374 { 375 depthBuffer.setStorage(getDepthFormat(depthBits), numSamples, width, height); 376 rr::clearMultisampleDepthBuffer(depthBuffer, CLEAR_DEPTH, rr::WindowRectangle(0, 0, width, height)); 377 } 378 379 if (stencilBits > 0) 380 { 381 stencilBuffer.setStorage(getStencilFormat(stencilBits), numSamples, width, height); 382 rr::clearMultisampleStencilBuffer(stencilBuffer, CLEAR_STENCIL, rr::WindowRectangle(0, 0, width, height)); 383 } 384 385 const rr::RenderTarget renderTarget(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()), 386 rr::MultisamplePixelBufferAccess::fromMultisampleAccess(depthBuffer.getAccess()), 387 rr::MultisamplePixelBufferAccess::fromMultisampleAccess(stencilBuffer.getAccess())); 388 389 for (vector<DrawPrimitiveOp>::const_iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); drawOp++) 390 { 391 // Translate state 392 rr::RenderState renderState((rr::ViewportState)(rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess()))); 393 toReferenceRenderState(renderState, *drawOp); 394 395 DE_ASSERT(drawOp->type == PRIMITIVETYPE_TRIANGLE); 396 397 attributes[0].pointer = &drawOp->positions[0]; 398 attributes[1].pointer = &drawOp->colors[0]; 399 400 referenceRenderer.draw( 401 rr::DrawCommand( 402 renderState, 403 renderTarget, 404 rr::Program(static_cast<const rr::VertexShader*>(&shader), static_cast<const rr::FragmentShader*>(&shader)), 405 2, 406 attributes, 407 rr::PrimitiveList(rr::PRIMITIVETYPE_TRIANGLES, drawOp->count * 3, 0))); 408 } 409 410 rr::resolveMultisampleColorBuffer(dst, rr::MultisamplePixelBufferAccess::fromMultisampleAccess(colorBuffer.getAccess())); 411 } 412 413 // API rendering code 414 415 class Program 416 { 417 public: 418 Program (void) {} 419 virtual ~Program (void) {} 420 421 virtual void setup (void) const = DE_NULL; 422 }; 423 424 typedef de::SharedPtr<Program> ProgramSp; 425 426 #if defined(DEQP_SUPPORT_GLES2) || defined(DEQP_SUPPORT_GLES3) 427 428 static const char* s_vertexSrc = 429 "attribute highp vec4 a_position;\n" 430 "attribute mediump vec4 a_color;\n" 431 "varying mediump vec4 v_color;\n" 432 "void main (void)\n" 433 "{\n" 434 " gl_Position = a_position;\n" 435 " v_color = a_color;\n" 436 "}\n"; 437 438 static const char* s_fragmentSrc = 439 "varying mediump vec4 v_color;\n" 440 "void main (void)\n" 441 "{\n" 442 " gl_FragColor = v_color;\n" 443 "}\n"; 444 445 static deUint32 createShader (deUint32 shaderType, const char* source) 446 { 447 deUint32 shader = glCreateShader(shaderType); 448 glShaderSource(shader, 1, &source, DE_NULL); 449 glCompileShader(shader); 450 451 int compileStatus = 0; 452 glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); 453 454 if (!compileStatus) 455 { 456 glDeleteShader(shader); 457 return 0; 458 } 459 460 return shader; 461 } 462 463 static deUint32 createProgram (deUint32 vertexShader, deUint32 fragmentShader) 464 { 465 deUint32 program = glCreateProgram(); 466 glAttachShader(program, vertexShader); 467 glAttachShader(program, fragmentShader); 468 glLinkProgram(program); 469 470 int linkStatus = 0; 471 glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); 472 473 if (!linkStatus) 474 { 475 glDeleteProgram(program); 476 return 0; 477 } 478 479 return program; 480 } 481 482 class GLES2Program : public Program 483 { 484 public: 485 GLES2Program (void) 486 : m_program (0) 487 , m_vertexShader (0) 488 , m_fragmentShader (0) 489 , m_positionLoc (0) 490 , m_colorLoc (0) 491 { 492 m_vertexShader = createShader(GL_VERTEX_SHADER, s_vertexSrc); 493 m_fragmentShader = createShader(GL_FRAGMENT_SHADER, s_fragmentSrc); 494 495 if (!m_vertexShader || !m_fragmentShader) 496 { 497 glDeleteShader(m_vertexShader); 498 glDeleteShader(m_fragmentShader); 499 throw tcu::TestError("Failed to compile shaders"); 500 } 501 502 m_program = createProgram(m_vertexShader, m_fragmentShader); 503 if (!m_program) 504 { 505 glDeleteShader(m_vertexShader); 506 glDeleteShader(m_fragmentShader); 507 throw tcu::TestError("Failed to link program"); 508 } 509 510 m_positionLoc = glGetAttribLocation(m_program, "a_position"); 511 m_colorLoc = glGetAttribLocation(m_program, "a_color"); 512 } 513 514 ~GLES2Program (void) 515 { 516 } 517 518 void setup (void) const 519 { 520 glUseProgram(m_program); 521 glEnableVertexAttribArray(m_positionLoc); 522 glEnableVertexAttribArray(m_colorLoc); 523 GLU_CHECK_MSG("Program setup failed"); 524 } 525 526 int getPositionLoc (void) const { return m_positionLoc; } 527 int getColorLoc (void) const { return m_colorLoc; } 528 529 private: 530 deUint32 m_program; 531 deUint32 m_vertexShader; 532 deUint32 m_fragmentShader; 533 int m_positionLoc; 534 int m_colorLoc; 535 }; 536 537 void clearGLES2 (const tcu::Vec4& color, const float depth, const int stencil) 538 { 539 glClearColor(color.x(), color.y(), color.z(), color.w()); 540 glClearDepthf(depth); 541 glClearStencil(stencil); 542 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); 543 } 544 545 void drawGLES2 (const Program& program, const DrawPrimitiveOp& drawOp) 546 { 547 const GLES2Program& gles2Program = dynamic_cast<const GLES2Program&>(program); 548 549 switch (drawOp.blend) 550 { 551 case BLENDMODE_NONE: 552 glDisable(GL_BLEND); 553 break; 554 555 case BLENDMODE_ADDITIVE: 556 glEnable(GL_BLEND); 557 glBlendFunc(GL_ONE, GL_ONE); 558 break; 559 560 case BLENDMODE_SRC_OVER: 561 glEnable(GL_BLEND); 562 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 563 break; 564 565 default: 566 DE_ASSERT(false); 567 } 568 569 switch (drawOp.depth) 570 { 571 case DEPTHMODE_NONE: 572 glDisable(GL_DEPTH_TEST); 573 break; 574 575 case DEPTHMODE_LESS: 576 glEnable(GL_DEPTH_TEST); 577 break; 578 579 default: 580 DE_ASSERT(false); 581 } 582 583 switch (drawOp.stencil) 584 { 585 case STENCILMODE_NONE: 586 glDisable(GL_STENCIL_TEST); 587 break; 588 589 case STENCILMODE_LEQUAL_INC: 590 glEnable(GL_STENCIL_TEST); 591 glStencilFunc(GL_LEQUAL, drawOp.stencilRef, ~0u); 592 glStencilOp(GL_KEEP, GL_INCR, GL_INCR); 593 break; 594 595 default: 596 DE_ASSERT(false); 597 } 598 599 glVertexAttribPointer(gles2Program.getPositionLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.positions[0]); 600 glVertexAttribPointer(gles2Program.getColorLoc(), 4, GL_FLOAT, GL_FALSE, 0, &drawOp.colors[0]); 601 602 DE_ASSERT(drawOp.type == PRIMITIVETYPE_TRIANGLE); 603 glDrawArrays(GL_TRIANGLES, 0, drawOp.count*3); 604 } 605 606 static void readPixelsGLES2 (tcu::Surface& dst) 607 { 608 glReadPixels(0, 0, dst.getWidth(), dst.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, dst.getAccess().getDataPtr()); 609 } 610 611 #endif 612 613 Program* createProgram (EGLint api) 614 { 615 switch (api) 616 { 617 #if defined(DEQP_SUPPORT_GLES2) || defined(DEQP_SUPPORT_GLES3) 618 case EGL_OPENGL_ES2_BIT: return new GLES2Program(); 619 case EGL_OPENGL_ES3_BIT_KHR: return new GLES2Program(); 620 #endif 621 default: 622 throw tcu::NotSupportedError("Unsupported API"); 623 } 624 } 625 626 void draw (EGLint api, const Program& program, const DrawPrimitiveOp& drawOp) 627 { 628 switch (api) 629 { 630 #if defined(DEQP_SUPPORT_GLES2) || defined(DEQP_SUPPORT_GLES3) 631 case EGL_OPENGL_ES2_BIT: drawGLES2(program, drawOp); break; 632 case EGL_OPENGL_ES3_BIT_KHR: drawGLES2(program, drawOp); break; 633 #endif 634 default: 635 throw tcu::NotSupportedError("Unsupported API"); 636 } 637 } 638 639 void clear (EGLint api, const tcu::Vec4& color, const float depth, const int stencil) 640 { 641 switch (api) 642 { 643 #if defined(DEQP_SUPPORT_GLES2) || defined(DEQP_SUPPORT_GLES3) 644 case EGL_OPENGL_ES2_BIT: clearGLES2(color, depth, stencil); break; 645 case EGL_OPENGL_ES3_BIT_KHR: clearGLES2(color, depth, stencil); break; 646 #endif 647 default: 648 throw tcu::NotSupportedError("Unsupported API"); 649 } 650 } 651 652 static void readPixels (EGLint api, tcu::Surface& dst) 653 { 654 switch (api) 655 { 656 #if defined(DEQP_SUPPORT_GLES2) || defined(DEQP_SUPPORT_GLES3) 657 case EGL_OPENGL_ES2_BIT: readPixelsGLES2(dst); break; 658 case EGL_OPENGL_ES3_BIT_KHR: readPixelsGLES2(dst); break; 659 #endif 660 default: 661 throw tcu::NotSupportedError("Unsupported API"); 662 } 663 } 664 665 tcu::PixelFormat getPixelFormat (const tcu::egl::Display& display, EGLConfig config) 666 { 667 tcu::PixelFormat fmt; 668 display.describeConfig(config, fmt); 669 return fmt; 670 } 671 672 } // anonymous 673 674 // SingleThreadRenderCase 675 676 class SingleThreadRenderCase : public MultiContextRenderCase 677 { 678 public: 679 SingleThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const std::vector<EGLint>& configIds, int numContextsPerApi); 680 681 private: 682 virtual void executeForContexts (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config, const std::vector<std::pair<EGLint, tcu::egl::Context*> >& contexts); 683 }; 684 685 // SingleThreadColorClearCase 686 687 SingleThreadRenderCase::SingleThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const std::vector<EGLint>& configIds, int numContextsPerApi) 688 : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, configIds, numContextsPerApi) 689 { 690 } 691 692 void SingleThreadRenderCase::executeForContexts (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config, const std::vector<std::pair<EGLint, tcu::egl::Context*> >& contexts) 693 { 694 const int width = surface.getWidth(); 695 const int height = surface.getHeight(); 696 const int numContexts = (int)contexts.size(); 697 const int drawsPerCtx = 2; 698 const int numIters = 2; 699 const float threshold = 0.02f; 700 701 const tcu::PixelFormat pixelFmt = getPixelFormat(display, config); 702 const int depthBits = display.getConfigAttrib(config, EGL_DEPTH_SIZE); 703 const int stencilBits = display.getConfigAttrib(config, EGL_STENCIL_SIZE); 704 const int numSamples = display.getConfigAttrib(config, EGL_SAMPLES); 705 706 TestLog& log = m_testCtx.getLog(); 707 708 tcu::Surface refFrame (width, height); 709 tcu::Surface frame (width, height); 710 711 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(numContexts)); 712 vector<ProgramSp> programs (contexts.size()); 713 vector<DrawPrimitiveOp> drawOps; 714 715 // Log basic information about config. 716 log << TestLog::Message << "EGL_RED_SIZE = " << pixelFmt.redBits << TestLog::EndMessage; 717 log << TestLog::Message << "EGL_GREEN_SIZE = " << pixelFmt.greenBits << TestLog::EndMessage; 718 log << TestLog::Message << "EGL_BLUE_SIZE = " << pixelFmt.blueBits << TestLog::EndMessage; 719 log << TestLog::Message << "EGL_ALPHA_SIZE = " << pixelFmt.alphaBits << TestLog::EndMessage; 720 log << TestLog::Message << "EGL_DEPTH_SIZE = " << depthBits << TestLog::EndMessage; 721 log << TestLog::Message << "EGL_STENCIL_SIZE = " << stencilBits << TestLog::EndMessage; 722 log << TestLog::Message << "EGL_SAMPLES = " << numSamples << TestLog::EndMessage; 723 724 // Generate draw ops. 725 drawOps.resize(numContexts*drawsPerCtx*numIters); 726 for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp) 727 randomizeDrawOp(rnd, *drawOp); 728 729 // Create and setup programs per context 730 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++) 731 { 732 EGLint api = contexts[ctxNdx].first; 733 tcu::egl::Context* context = contexts[ctxNdx].second; 734 735 eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext()); 736 TCU_CHECK_EGL(); 737 738 programs[ctxNdx] = ProgramSp(createProgram(api)); 739 programs[ctxNdx]->setup(); 740 } 741 742 // Clear to black using first context. 743 { 744 EGLint api = contexts[0].first; 745 tcu::egl::Context* context = contexts[0].second; 746 747 eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext()); 748 TCU_CHECK_EGL(); 749 750 clear(api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL); 751 } 752 753 // Render. 754 for (int iterNdx = 0; iterNdx < numIters; iterNdx++) 755 { 756 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++) 757 { 758 EGLint api = contexts[ctxNdx].first; 759 tcu::egl::Context* context = contexts[ctxNdx].second; 760 761 eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext()); 762 TCU_CHECK_EGL(); 763 764 for (int drawNdx = 0; drawNdx < drawsPerCtx; drawNdx++) 765 { 766 const DrawPrimitiveOp& drawOp = drawOps[iterNdx*numContexts*drawsPerCtx + ctxNdx*drawsPerCtx + drawNdx]; 767 draw(api, *programs[ctxNdx], drawOp); 768 } 769 } 770 } 771 772 // Read pixels using first context. \todo [pyry] Randomize? 773 { 774 EGLint api = contexts[0].first; 775 tcu::egl::Context* context = contexts[0].second; 776 777 eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext()); 778 TCU_CHECK_EGL(); 779 780 readPixels(api, frame); 781 } 782 783 // Render reference. 784 // \note Reference image is always generated using single-sampling. 785 renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1); 786 787 // Compare images 788 { 789 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT); 790 791 if (!imagesOk) 792 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 793 } 794 } 795 796 // MultiThreadRenderCase 797 798 class MultiThreadRenderCase : public MultiContextRenderCase 799 { 800 public: 801 MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const std::vector<EGLint>& configIds, int numContextsPerApi); 802 803 private: 804 virtual void executeForContexts (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config, const std::vector<std::pair<EGLint, tcu::egl::Context*> >& contexts); 805 }; 806 807 class RenderTestThread; 808 809 typedef de::SharedPtr<RenderTestThread> RenderTestThreadSp; 810 typedef de::SharedPtr<de::Semaphore> SemaphoreSp; 811 812 struct DrawOpPacket 813 { 814 DrawOpPacket (void) 815 : drawOps (DE_NULL) 816 , numOps (0) 817 { 818 } 819 820 const DrawPrimitiveOp* drawOps; 821 int numOps; 822 SemaphoreSp wait; 823 SemaphoreSp signal; 824 }; 825 826 class RenderTestThread : public de::Thread 827 { 828 public: 829 RenderTestThread (tcu::egl::Display& display, tcu::egl::Surface& surface, tcu::egl::Context& context, EGLint api, const Program& program, const std::vector<DrawOpPacket>& packets) 830 : m_display (display) 831 , m_surface (surface) 832 , m_context (context) 833 , m_api (api) 834 , m_program (program) 835 , m_packets (packets) 836 { 837 } 838 839 void run (void) 840 { 841 for (std::vector<DrawOpPacket>::const_iterator packetIter = m_packets.begin(); packetIter != m_packets.end(); packetIter++) 842 { 843 // Wait until it is our turn. 844 packetIter->wait->decrement(); 845 846 // Acquire context. 847 eglMakeCurrent(m_display.getEGLDisplay(), m_surface.getEGLSurface(), m_surface.getEGLSurface(), m_context.getEGLContext()); 848 849 // Execute rendering. 850 for (int ndx = 0; ndx < packetIter->numOps; ndx++) 851 draw(m_api, m_program, packetIter->drawOps[ndx]); 852 853 // Release context. 854 eglMakeCurrent(m_display.getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 855 856 // Signal completion. 857 packetIter->signal->increment(); 858 } 859 } 860 861 private: 862 tcu::egl::Display& m_display; 863 tcu::egl::Surface& m_surface; 864 tcu::egl::Context& m_context; 865 EGLint m_api; 866 const Program& m_program; 867 const std::vector<DrawOpPacket>& m_packets; 868 }; 869 870 MultiThreadRenderCase::MultiThreadRenderCase (EglTestContext& eglTestCtx, const char* name, const char* description, EGLint api, EGLint surfaceType, const std::vector<EGLint>& configIds, int numContextsPerApi) 871 : MultiContextRenderCase(eglTestCtx, name, description, api, surfaceType, configIds, numContextsPerApi) 872 { 873 } 874 875 void MultiThreadRenderCase::executeForContexts (tcu::egl::Display& display, tcu::egl::Surface& surface, EGLConfig config, const std::vector<std::pair<EGLint, tcu::egl::Context*> >& contexts) 876 { 877 const int width = surface.getWidth(); 878 const int height = surface.getHeight(); 879 const int numContexts = (int)contexts.size(); 880 const int opsPerPacket = 2; 881 const int packetsPerThread = 2; 882 const int numThreads = numContexts; 883 const int numPackets = numThreads * packetsPerThread; 884 const float threshold = 0.02f; 885 886 const tcu::PixelFormat pixelFmt = getPixelFormat(display, config); 887 const int depthBits = display.getConfigAttrib(config, EGL_DEPTH_SIZE); 888 const int stencilBits = display.getConfigAttrib(config, EGL_STENCIL_SIZE); 889 const int numSamples = display.getConfigAttrib(config, EGL_SAMPLES); 890 891 TestLog& log = m_testCtx.getLog(); 892 893 tcu::Surface refFrame (width, height); 894 tcu::Surface frame (width, height); 895 896 de::Random rnd (deStringHash(getName()) ^ deInt32Hash(numContexts)); 897 898 // Resources that need cleanup 899 vector<ProgramSp> programs (numContexts); 900 vector<SemaphoreSp> semaphores (numPackets+1); 901 vector<DrawPrimitiveOp> drawOps (numPackets*opsPerPacket); 902 vector<vector<DrawOpPacket> > packets (numThreads); 903 vector<RenderTestThreadSp> threads (numThreads); 904 905 // Log basic information about config. 906 log << TestLog::Message << "EGL_RED_SIZE = " << pixelFmt.redBits << TestLog::EndMessage; 907 log << TestLog::Message << "EGL_GREEN_SIZE = " << pixelFmt.greenBits << TestLog::EndMessage; 908 log << TestLog::Message << "EGL_BLUE_SIZE = " << pixelFmt.blueBits << TestLog::EndMessage; 909 log << TestLog::Message << "EGL_ALPHA_SIZE = " << pixelFmt.alphaBits << TestLog::EndMessage; 910 log << TestLog::Message << "EGL_DEPTH_SIZE = " << depthBits << TestLog::EndMessage; 911 log << TestLog::Message << "EGL_STENCIL_SIZE = " << stencilBits << TestLog::EndMessage; 912 log << TestLog::Message << "EGL_SAMPLES = " << numSamples << TestLog::EndMessage; 913 914 // Initialize semaphores. 915 for (vector<SemaphoreSp>::iterator sem = semaphores.begin(); sem != semaphores.end(); ++sem) 916 *sem = SemaphoreSp(new de::Semaphore(0)); 917 918 // Create draw ops. 919 for (vector<DrawPrimitiveOp>::iterator drawOp = drawOps.begin(); drawOp != drawOps.end(); ++drawOp) 920 randomizeDrawOp(rnd, *drawOp); 921 922 // Create packets. 923 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++) 924 { 925 packets[threadNdx].resize(packetsPerThread); 926 927 for (int packetNdx = 0; packetNdx < packetsPerThread; packetNdx++) 928 { 929 DrawOpPacket& packet = packets[threadNdx][packetNdx]; 930 931 // Threads take turns with packets. 932 packet.wait = semaphores[packetNdx*numThreads + threadNdx]; 933 packet.signal = semaphores[packetNdx*numThreads + threadNdx + 1]; 934 packet.numOps = opsPerPacket; 935 packet.drawOps = &drawOps[(packetNdx*numThreads + threadNdx)*opsPerPacket]; 936 } 937 } 938 939 // Create and setup programs per context 940 for (int ctxNdx = 0; ctxNdx < numContexts; ctxNdx++) 941 { 942 EGLint api = contexts[ctxNdx].first; 943 tcu::egl::Context* context = contexts[ctxNdx].second; 944 945 eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext()); 946 TCU_CHECK_EGL(); 947 948 programs[ctxNdx] = ProgramSp(createProgram(api)); 949 programs[ctxNdx]->setup(); 950 951 // Release context 952 eglMakeCurrent(display.getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 953 } 954 955 // Clear to black using first context. 956 { 957 EGLint api = contexts[0].first; 958 tcu::egl::Context* context = contexts[0].second; 959 960 eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext()); 961 TCU_CHECK_EGL(); 962 963 clear(api, CLEAR_COLOR, CLEAR_DEPTH, CLEAR_STENCIL); 964 965 // Release context 966 eglMakeCurrent(display.getEGLDisplay(), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 967 } 968 969 // Create and launch threads (actual rendering starts once first semaphore is signaled). 970 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++) 971 { 972 threads[threadNdx] = RenderTestThreadSp(new RenderTestThread(display, surface, *contexts[threadNdx].second, contexts[threadNdx].first, *programs[threadNdx], packets[threadNdx])); 973 threads[threadNdx]->start(); 974 } 975 976 // Signal start and wait until complete. 977 semaphores.front()->increment(); 978 semaphores.back()->decrement(); 979 980 // Read pixels using first context. \todo [pyry] Randomize? 981 { 982 EGLint api = contexts[0].first; 983 tcu::egl::Context* context = contexts[0].second; 984 985 eglMakeCurrent(display.getEGLDisplay(), surface.getEGLSurface(), surface.getEGLSurface(), context->getEGLContext()); 986 TCU_CHECK_EGL(); 987 988 readPixels(api, frame); 989 } 990 991 // Join threads. 992 for (int threadNdx = 0; threadNdx < numThreads; threadNdx++) 993 threads[threadNdx]->join(); 994 995 // Render reference. 996 renderReference(refFrame.getAccess(), drawOps, pixelFmt, depthBits, stencilBits, 1); 997 998 // Compare images 999 { 1000 bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, frame, threshold, tcu::COMPARE_LOG_RESULT); 1001 1002 if (!imagesOk) 1003 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Image comparison failed"); 1004 } 1005 } 1006 1007 RenderTests::RenderTests (EglTestContext& eglTestCtx) 1008 : TestCaseGroup(eglTestCtx, "render", "Basic rendering with different client APIs") 1009 { 1010 } 1011 1012 RenderTests::~RenderTests (void) 1013 { 1014 } 1015 1016 struct RenderGroupSpec 1017 { 1018 const char* name; 1019 const char* desc; 1020 EGLint apiBits; 1021 int numContextsPerApi; 1022 }; 1023 1024 template <class RenderClass> 1025 static void createRenderGroups (EglTestContext& eglTestCtx, tcu::TestCaseGroup* group, const RenderGroupSpec* first, const RenderGroupSpec* last) 1026 { 1027 for (const RenderGroupSpec* groupIter = first; groupIter != last; groupIter++) 1028 { 1029 tcu::TestCaseGroup* configGroup = new tcu::TestCaseGroup(eglTestCtx.getTestContext(), groupIter->name, groupIter->desc); 1030 group->addChild(configGroup); 1031 1032 vector<RenderConfigIdSet> configSets; 1033 eglu::FilterList filters; 1034 filters << (eglu::ConfigRenderableType() & groupIter->apiBits); 1035 getDefaultRenderConfigIdSets(configSets, eglTestCtx.getConfigs(), filters); 1036 1037 for (vector<RenderConfigIdSet>::const_iterator setIter = configSets.begin(); setIter != configSets.end(); setIter++) 1038 configGroup->addChild(new RenderClass(eglTestCtx, setIter->getName(), "", groupIter->apiBits, setIter->getSurfaceTypeMask(), setIter->getConfigIds(), groupIter->numContextsPerApi)); 1039 } 1040 } 1041 1042 void RenderTests::init (void) 1043 { 1044 static const RenderGroupSpec singleContextCases[] = 1045 { 1046 // { "gles1", "Primitive rendering using GLES1", EGL_OPENGL_ES_BIT, 1 }, 1047 { "gles2", "Primitive rendering using GLES2", EGL_OPENGL_ES2_BIT, 1 }, 1048 { "gles3", "Primitive rendering using GLES3", EGL_OPENGL_ES3_BIT_KHR, 1 }, 1049 // { "vg", "Primitive rendering using OpenVG", EGL_OPENVG_BIT, 1 } 1050 }; 1051 1052 static const RenderGroupSpec multiContextCases[] = 1053 { 1054 // { "gles1", "Primitive rendering using multiple GLES1 contexts to shared surface", EGL_OPENGL_ES_BIT, 3 }, 1055 { "gles2", "Primitive rendering using multiple GLES2 contexts to shared surface", EGL_OPENGL_ES2_BIT, 3 }, 1056 { "gles3", "Primitive rendering using multiple GLES3 contexts to shared surface", EGL_OPENGL_ES3_BIT_KHR, 3 }, 1057 // { "vg", "Primitive rendering using multiple OpenVG contexts to shared surface", EGL_OPENVG_BIT, 3 }, 1058 // { "gles1_gles2", "Primitive rendering using multiple APIs to shared surface", EGL_OPENGL_ES_BIT|EGL_OPENGL_ES2_BIT, 1 }, 1059 // { "gles1_gles2_gles3", "Primitive rendering using multiple APIs to shared surface", EGL_OPENGL_ES_BIT|EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT_KHR, 1 }, 1060 { "gles2_gles3", "Primitive rendering using multiple APIs to shared surface", EGL_OPENGL_ES2_BIT|EGL_OPENGL_ES3_BIT_KHR, 1 }, 1061 // { "gles1_vg", "Primitive rendering using multiple APIs to shared surface", EGL_OPENGL_ES_BIT|EGL_OPENVG_BIT, 1 }, 1062 // { "gles2_vg", "Primitive rendering using multiple APIs to shared surface", EGL_OPENGL_ES2_BIT|EGL_OPENVG_BIT, 1 }, 1063 // { "gles3_vg", "Primitive rendering using multiple APIs to shared surface", EGL_OPENGL_ES3_BIT_KHR|EGL_OPENVG_BIT, 1 }, 1064 // { "gles1_gles2_vg", "Primitive rendering using multiple APIs to shared surface", EGL_OPENGL_ES_BIT|EGL_OPENGL_ES2_BIT|EGL_OPENVG_BIT, 1 } 1065 }; 1066 1067 tcu::TestCaseGroup* singleContextGroup = new tcu::TestCaseGroup(m_testCtx, "single_context", "Single-context rendering"); 1068 addChild(singleContextGroup); 1069 createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, singleContextGroup, &singleContextCases[0], &singleContextCases[DE_LENGTH_OF_ARRAY(singleContextCases)]); 1070 1071 tcu::TestCaseGroup* multiContextGroup = new tcu::TestCaseGroup(m_testCtx, "multi_context", "Multi-context rendering with shared surface"); 1072 addChild(multiContextGroup); 1073 createRenderGroups<SingleThreadRenderCase>(m_eglTestCtx, multiContextGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]); 1074 1075 tcu::TestCaseGroup* multiThreadGroup = new tcu::TestCaseGroup(m_testCtx, "multi_thread", "Multi-thread rendering with shared surface"); 1076 addChild(multiThreadGroup); 1077 createRenderGroups<MultiThreadRenderCase>(m_eglTestCtx, multiThreadGroup, &multiContextCases[0], &multiContextCases[DE_LENGTH_OF_ARRAY(multiContextCases)]); 1078 } 1079 1080 } // egl 1081 } // deqp 1082