1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program EGL Module 3 * --------------------------------------- 4 * 5 * Copyright 2015 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 Test KHR_swap_buffer_with_damage 22 *//*--------------------------------------------------------------------*/ 23 24 #include "teglSwapBuffersWithDamageTests.hpp" 25 26 #include "tcuImageCompare.hpp" 27 #include "tcuSurface.hpp" 28 #include "tcuTextureUtil.hpp" 29 30 #include "egluNativeWindow.hpp" 31 #include "egluUtil.hpp" 32 #include "egluConfigFilter.hpp" 33 34 #include "eglwLibrary.hpp" 35 #include "eglwEnums.hpp" 36 37 #include "gluDefs.hpp" 38 #include "gluRenderContext.hpp" 39 #include "gluShaderProgram.hpp" 40 41 #include "glwDefs.hpp" 42 #include "glwEnums.hpp" 43 #include "glwFunctions.hpp" 44 45 #include "deRandom.hpp" 46 #include "deString.h" 47 48 #include <string> 49 #include <vector> 50 #include <sstream> 51 52 using std::string; 53 using std::vector; 54 using glw::GLubyte; 55 using tcu::IVec2; 56 57 using namespace eglw; 58 59 namespace deqp 60 { 61 namespace egl 62 { 63 namespace 64 { 65 66 typedef tcu::Vector<GLubyte, 3> Color; 67 68 enum DrawType 69 { 70 DRAWTYPE_GLES2_CLEAR, 71 DRAWTYPE_GLES2_RENDER 72 }; 73 74 enum ResizeType 75 { 76 RESIZETYPE_NONE = 0, 77 RESIZETYPE_BEFORE_SWAP, 78 RESIZETYPE_AFTER_SWAP, 79 80 RESIZETYPE_LAST 81 }; 82 83 struct ColoredRect 84 { 85 public: 86 ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_); 87 IVec2 bottomLeft; 88 IVec2 topRight; 89 Color color; 90 }; 91 92 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_) 93 : bottomLeft (bottomLeft_) 94 , topRight (topRight_) 95 , color (color_) 96 { 97 } 98 99 struct DrawCommand 100 { 101 DrawCommand (DrawType drawType_, const ColoredRect& rect_); 102 DrawType drawType; 103 ColoredRect rect; 104 }; 105 106 DrawCommand::DrawCommand (DrawType drawType_, const ColoredRect& rect_) 107 : drawType (drawType_) 108 , rect (rect_) 109 { 110 } 111 112 struct Frame 113 { 114 Frame (int width_, int height_); 115 int width; 116 int height; 117 vector<DrawCommand> draws; 118 }; 119 120 Frame::Frame (int width_, int height_) 121 : width (width_) 122 , height(height_) 123 { 124 } 125 126 typedef vector<Frame> FrameSequence; 127 128 //helper function declaration 129 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveBuffer); 130 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor); 131 float windowToDeviceCoordinates (int x, int length); 132 133 class GLES2Renderer 134 { 135 public: 136 GLES2Renderer (const glw::Functions& gl); 137 ~GLES2Renderer (void); 138 void render (int width, int height, const Frame& frame) const; 139 140 private: 141 GLES2Renderer (const GLES2Renderer&); 142 GLES2Renderer& operator= (const GLES2Renderer&); 143 144 const glw::Functions& m_gl; 145 glu::ShaderProgram m_glProgram; 146 glw::GLuint m_coordLoc; 147 glw::GLuint m_colorLoc; 148 }; 149 150 // generate sources for vertex and fragment buffer 151 glu::ProgramSources getSources (void) 152 { 153 const char* const vertexShaderSource = 154 "attribute mediump vec2 a_pos;\n" 155 "attribute mediump vec4 a_color;\n" 156 "varying mediump vec4 v_color;\n" 157 "void main(void)\n" 158 "{\n" 159 "\tv_color = a_color;\n" 160 "\tgl_Position = vec4(a_pos, 0.0, 1.0);\n" 161 "}"; 162 163 const char* const fragmentShaderSource = 164 "varying mediump vec4 v_color;\n" 165 "void main(void)\n" 166 "{\n" 167 "\tgl_FragColor = v_color;\n" 168 "}"; 169 170 return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource); 171 } 172 173 GLES2Renderer::GLES2Renderer (const glw::Functions& gl) 174 : m_gl (gl) 175 , m_glProgram (gl, getSources()) 176 , m_coordLoc ((glw::GLuint)-1) 177 , m_colorLoc ((glw::GLuint)-1) 178 { 179 m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color"); 180 m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos"); 181 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations"); 182 } 183 184 GLES2Renderer::~GLES2Renderer (void) 185 { 186 } 187 188 void GLES2Renderer::render (int width, int height, const Frame& frame) const 189 { 190 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++) 191 { 192 const ColoredRect& coloredRect = frame.draws[drawNdx].rect; 193 194 if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_RENDER) 195 { 196 const float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width); 197 const float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height); 198 const float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width); 199 const float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height); 200 201 const glw::GLfloat coords[] = 202 { 203 x1, y1, 204 x1, y2, 205 x2, y2, 206 207 x2, y2, 208 x2, y1, 209 x1, y1, 210 }; 211 212 const glw::GLubyte colors[] = 213 { 214 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, 215 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, 216 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, 217 218 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, 219 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, 220 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255, 221 }; 222 223 m_gl.useProgram(m_glProgram.getProgram()); 224 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed"); 225 226 m_gl.enableVertexAttribArray(m_coordLoc); 227 m_gl.enableVertexAttribArray(m_colorLoc); 228 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes"); 229 230 m_gl.vertexAttribPointer(m_coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords); 231 m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors); 232 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers"); 233 234 m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/2); 235 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed"); 236 237 m_gl.disableVertexAttribArray(m_coordLoc); 238 m_gl.disableVertexAttribArray(m_colorLoc); 239 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes"); 240 241 m_gl.useProgram(0); 242 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed"); 243 } 244 else if (frame.draws[drawNdx].drawType == DRAWTYPE_GLES2_CLEAR) 245 { 246 m_gl.enable(GL_SCISSOR_TEST); 247 m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(), 248 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()); 249 m_gl.clearColor(coloredRect.color.x()/255.0f, coloredRect.color.y()/255.0f, coloredRect.color.z()/255.0f, 1.0f); 250 m_gl.clear(GL_COLOR_BUFFER_BIT); 251 m_gl.disable(GL_SCISSOR_TEST); 252 } 253 else 254 DE_FATAL("Invalid drawtype"); 255 } 256 } 257 258 class SwapBuffersWithDamageTest : public TestCase 259 { 260 public: 261 SwapBuffersWithDamageTest (EglTestContext& eglTestCtx, 262 const vector<DrawType>& frameDrawType, 263 int iterationTimes, 264 ResizeType resizeType, 265 const char* name, 266 const char* description); 267 268 ~SwapBuffersWithDamageTest (void); 269 270 virtual void init (void); 271 void deinit (void); 272 virtual IterateResult iterate (void); 273 274 protected: 275 virtual EGLConfig getConfig (const Library& egl, EGLDisplay eglDisplay); 276 virtual void checkExtension (const Library& egl, EGLDisplay eglDisplay); 277 void initEGLSurface (EGLConfig config); 278 void initEGLContext (EGLConfig config); 279 280 eglu::NativeWindow* m_window; 281 EGLConfig m_eglConfig; 282 EGLContext m_eglContext; 283 const int m_seed; 284 const int m_iterationTimes; 285 const vector<DrawType> m_frameDrawType; 286 const ResizeType m_resizeType; 287 EGLDisplay m_eglDisplay; 288 EGLSurface m_eglSurface; 289 glw::Functions m_gl; 290 GLES2Renderer* m_gles2Renderer; 291 }; 292 293 SwapBuffersWithDamageTest::SwapBuffersWithDamageTest (EglTestContext& eglTestCtx, const vector<DrawType>& frameDrawType, int iterationTimes, ResizeType resizeType, const char* name, const char* description) 294 : TestCase (eglTestCtx, name, description) 295 , m_window (DE_NULL) 296 , m_eglContext (EGL_NO_CONTEXT) 297 , m_seed (deStringHash(name)) 298 , m_iterationTimes (iterationTimes) 299 , m_frameDrawType (frameDrawType) 300 , m_resizeType (resizeType) 301 , m_eglDisplay (EGL_NO_DISPLAY) 302 , m_eglSurface (EGL_NO_SURFACE) 303 , m_gles2Renderer (DE_NULL) 304 { 305 } 306 307 SwapBuffersWithDamageTest::~SwapBuffersWithDamageTest (void) 308 { 309 deinit(); 310 } 311 312 EGLConfig SwapBuffersWithDamageTest::getConfig (const Library& egl, EGLDisplay eglDisplay) 313 { 314 return getEGLConfig(egl, eglDisplay, false); 315 } 316 317 void SwapBuffersWithDamageTest::checkExtension (const Library& egl, EGLDisplay eglDisplay) 318 { 319 if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage")) 320 TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported"); 321 } 322 323 void SwapBuffersWithDamageTest::init (void) 324 { 325 const Library& egl = m_eglTestCtx.getLibrary(); 326 327 m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay()); 328 m_eglConfig = getConfig(egl, m_eglDisplay); 329 330 checkExtension(egl, m_eglDisplay); 331 332 initEGLSurface(m_eglConfig); 333 initEGLContext(m_eglConfig); 334 335 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0)); 336 m_gles2Renderer = new GLES2Renderer(m_gl); 337 } 338 339 void SwapBuffersWithDamageTest::deinit (void) 340 { 341 const Library& egl = m_eglTestCtx.getLibrary(); 342 343 delete m_gles2Renderer; 344 m_gles2Renderer = DE_NULL; 345 346 if (m_eglContext != EGL_NO_CONTEXT) 347 { 348 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 349 egl.destroyContext(m_eglDisplay, m_eglContext); 350 m_eglContext = EGL_NO_CONTEXT; 351 } 352 353 if (m_eglSurface != EGL_NO_SURFACE) 354 { 355 egl.destroySurface(m_eglDisplay, m_eglSurface); 356 m_eglSurface = EGL_NO_SURFACE; 357 } 358 359 if (m_eglDisplay != EGL_NO_DISPLAY) 360 { 361 egl.terminate(m_eglDisplay); 362 m_eglDisplay = EGL_NO_DISPLAY; 363 } 364 365 delete m_window; 366 m_window = DE_NULL; 367 } 368 369 void SwapBuffersWithDamageTest::initEGLSurface (EGLConfig config) 370 { 371 const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine()); 372 m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL, 373 eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine()))); 374 m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL); 375 } 376 377 void SwapBuffersWithDamageTest::initEGLContext (EGLConfig config) 378 { 379 const Library& egl = m_eglTestCtx.getLibrary(); 380 const EGLint attribList[] = 381 { 382 EGL_CONTEXT_CLIENT_VERSION, 2, 383 EGL_NONE 384 }; 385 386 egl.bindAPI(EGL_OPENGL_ES_API); 387 m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList); 388 EGLU_CHECK_MSG(egl, "eglCreateContext"); 389 TCU_CHECK(m_eglSurface != EGL_NO_SURFACE); 390 egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext); 391 EGLU_CHECK_MSG(egl, "eglMakeCurrent"); 392 } 393 394 FrameSequence generateFrameSequence (const vector<DrawType>& frameDrawType, de::Random& rnd, int numFrames, int width, int height); 395 vector<EGLint> getDamageRegion (const Frame& frame); 396 397 TestCase::IterateResult SwapBuffersWithDamageTest::iterate (void) 398 { 399 de::Random rnd (m_seed); 400 const Library& egl = m_eglTestCtx.getLibrary(); 401 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH); 402 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT); 403 const float clearRed = rnd.getFloat(); 404 const float clearGreen = rnd.getFloat(); 405 const float clearBlue = rnd.getFloat(); 406 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f); 407 const int numFrames = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible 408 const FrameSequence frameSequence = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height); 409 410 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 411 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED)); 412 413 for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++) 414 { 415 for (int currentFrameNdx = 0; currentFrameNdx < numFrames; currentFrameNdx++) 416 { 417 vector<EGLint> damageRegion = getDamageRegion(frameSequence[currentFrameNdx]); 418 419 clearColorScreen(m_gl, clearColor); 420 for (int ndx = 0; ndx <= currentFrameNdx; ndx++) 421 m_gles2Renderer->render(width, height, frameSequence[ndx]); 422 423 if (m_resizeType == RESIZETYPE_BEFORE_SWAP) 424 { 425 if (iterationNdx % 2 == 0) 426 m_window->setSurfaceSize(IVec2(width*2, height/2)); 427 else 428 m_window->setSurfaceSize(IVec2(height/2, width*2)); 429 } 430 431 EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4)); 432 433 if (m_resizeType == RESIZETYPE_AFTER_SWAP) 434 { 435 if (iterationNdx % 2 == 0) 436 m_window->setSurfaceSize(IVec2(width*2, height/2)); 437 else 438 m_window->setSurfaceSize(IVec2(height/2, width*2)); 439 } 440 } 441 } 442 return STOP; 443 } 444 445 class SwapBuffersWithDamageAndPreserveBufferTest : public SwapBuffersWithDamageTest 446 { 447 public: 448 SwapBuffersWithDamageAndPreserveBufferTest (EglTestContext& eglTestCtx, 449 const vector<DrawType>& frameDrawType, 450 int iterationTimes, 451 ResizeType resizeType, 452 const char* name, 453 const char* description); 454 455 IterateResult iterate (void); 456 457 protected: 458 EGLConfig getConfig (const Library& egl, EGLDisplay eglDisplay); 459 }; 460 461 SwapBuffersWithDamageAndPreserveBufferTest::SwapBuffersWithDamageAndPreserveBufferTest (EglTestContext& eglTestCtx, 462 const vector<DrawType>& frameDrawType, 463 int iterationTimes, 464 ResizeType resizeType, 465 const char* name, 466 const char* description) 467 : SwapBuffersWithDamageTest (eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description) 468 { 469 } 470 471 EGLConfig SwapBuffersWithDamageAndPreserveBufferTest::getConfig (const Library& egl, EGLDisplay eglDisplay) 472 { 473 return getEGLConfig(egl, eglDisplay, true); 474 } 475 476 TestCase::IterateResult SwapBuffersWithDamageAndPreserveBufferTest::iterate (void) 477 { 478 479 de::Random rnd (m_seed); 480 const Library& egl = m_eglTestCtx.getLibrary(); 481 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH); 482 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT); 483 const float clearRed = rnd.getFloat(); 484 const float clearGreen = rnd.getFloat(); 485 const float clearBlue = rnd.getFloat(); 486 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f); 487 const int numFrames = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible 488 const FrameSequence frameSequence = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height); 489 490 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 491 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)); 492 493 for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++) 494 { 495 clearColorScreen(m_gl, clearColor); 496 EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0)); 497 498 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++) 499 { 500 const Frame& currentFrame = frameSequence[frameNdx]; 501 vector<EGLint> damageRegion = getDamageRegion(currentFrame); 502 503 m_gles2Renderer->render(width, height, currentFrame); 504 505 if (m_resizeType == RESIZETYPE_BEFORE_SWAP) 506 { 507 if (iterationNdx % 2 == 0) 508 m_window->setSurfaceSize(IVec2(width*2, height/2)); 509 else 510 m_window->setSurfaceSize(IVec2(height/2, width*2)); 511 } 512 513 EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4)); 514 515 if (m_resizeType == RESIZETYPE_AFTER_SWAP) 516 { 517 if (iterationNdx % 2 == 0) 518 m_window->setSurfaceSize(IVec2(width*2, height/2)); 519 else 520 m_window->setSurfaceSize(IVec2(height/2, width*2)); 521 } 522 } 523 } 524 525 return STOP; 526 } 527 528 class SwapBuffersWithDamageAndBufferAgeTest : public SwapBuffersWithDamageTest 529 { 530 public: 531 SwapBuffersWithDamageAndBufferAgeTest (EglTestContext& eglTestCtx, 532 const vector<DrawType>& frameDrawType, 533 int iterationTimes, 534 ResizeType resizeType, 535 const char* name, 536 const char* description); 537 538 IterateResult iterate (void); 539 540 protected: 541 void checkExtension (const Library& egl, EGLDisplay eglDisplay); 542 }; 543 544 SwapBuffersWithDamageAndBufferAgeTest::SwapBuffersWithDamageAndBufferAgeTest (EglTestContext& eglTestCtx, 545 const vector<DrawType>& frameDrawType, 546 int iterationTimes, 547 ResizeType resizeType, 548 const char* name, 549 const char* description) 550 : SwapBuffersWithDamageTest (eglTestCtx, frameDrawType, iterationTimes, resizeType, name, description) 551 { 552 } 553 554 555 void SwapBuffersWithDamageAndBufferAgeTest::checkExtension (const Library& egl, EGLDisplay eglDisplay) 556 { 557 if (!eglu::hasExtension(egl, eglDisplay, "EGL_KHR_swap_buffers_with_damage")) 558 TCU_THROW(NotSupportedError, "EGL_KHR_swap_buffers_with_damage is not supported"); 559 560 if (!eglu::hasExtension(egl, eglDisplay, "EGL_EXT_buffer_age")) 561 TCU_THROW(NotSupportedError, "EGL_EXT_buffer_age not supported"); 562 } 563 564 TestCase::IterateResult SwapBuffersWithDamageAndBufferAgeTest::iterate (void) 565 { 566 567 de::Random rnd (m_seed); 568 const Library& egl = m_eglTestCtx.getLibrary(); 569 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH); 570 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT); 571 const float clearRed = rnd.getFloat(); 572 const float clearGreen = rnd.getFloat(); 573 const float clearBlue = rnd.getFloat(); 574 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f); 575 const int numFrames = 24; // (width, height) = (480, 480) --> numFrame = 24, divisible 576 const FrameSequence frameSequence = generateFrameSequence(m_frameDrawType, rnd, numFrames, width, height); 577 578 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass"); 579 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED)); 580 581 for (int iterationNdx = 0; iterationNdx < m_iterationTimes; iterationNdx++) 582 { 583 clearColorScreen(m_gl, clearColor); 584 EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, DE_NULL, 0)); 585 586 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++) 587 { 588 vector<EGLint> damageRegion; 589 int bufferAge = -1; 590 int startFrameNdx = -1; 591 int endFrameNdx = frameNdx; 592 593 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_EXT, &bufferAge)); 594 595 if (bufferAge < 0) // invalid buffer age 596 { 597 std::ostringstream stream; 598 stream << "Fail, the age is invalid. Age: " << bufferAge << ", frameNdx: " << frameNdx; 599 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str()); 600 return STOP; 601 } 602 603 if (bufferAge == 0 || bufferAge > frameNdx) 604 { 605 clearColorScreen(m_gl, clearColor); 606 startFrameNdx = 0; 607 } 608 else 609 startFrameNdx = frameNdx-bufferAge+1; 610 611 for (int ndx = startFrameNdx; ndx <= endFrameNdx; ndx++) 612 { 613 const vector<EGLint> partialDamageRegion = getDamageRegion(frameSequence[ndx]); 614 615 damageRegion.insert(damageRegion.end(), partialDamageRegion.begin(), partialDamageRegion.end()); 616 m_gles2Renderer->render(width, height, frameSequence[ndx]); 617 } 618 619 if (m_resizeType == RESIZETYPE_BEFORE_SWAP) 620 { 621 if (iterationNdx % 2 == 0) 622 m_window->setSurfaceSize(IVec2(width*2, height/2)); 623 else 624 m_window->setSurfaceSize(IVec2(height/2, width*2)); 625 } 626 627 EGLU_CHECK_CALL(egl, swapBuffersWithDamageKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4)); 628 629 if (m_resizeType == RESIZETYPE_AFTER_SWAP) 630 { 631 if (iterationNdx % 2 == 0) 632 m_window->setSurfaceSize(IVec2(width*2, height/2)); 633 else 634 m_window->setSurfaceSize(IVec2(height/2, width*2)); 635 } 636 } 637 } 638 return STOP; 639 } 640 641 // generate a frame sequence with certain frame for visual verification 642 FrameSequence generateFrameSequence (const vector<DrawType>& frameDrawType, de::Random& rnd, int numFrames, int width, int height) 643 { 644 const int frameDiff = height / numFrames; 645 const GLubyte r = rnd.getUint8(); 646 const GLubyte g = rnd.getUint8(); 647 const GLubyte b = rnd.getUint8(); 648 const Color color (r, g, b); 649 FrameSequence frameSequence; 650 651 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++) 652 { 653 Frame frame (width, height); 654 655 for (int rectNdx = 0; rectNdx < (int)frameDrawType.size(); rectNdx++) 656 { 657 const int rectHeight = frameDiff / (int)frameDrawType.size(); 658 const ColoredRect rect (IVec2(0, frameNdx*frameDiff+rectNdx*rectHeight), IVec2(width, frameNdx*frameDiff+(rectNdx+1)*rectHeight), color); 659 const DrawCommand drawCommand (frameDrawType[rectNdx], rect); 660 661 frame.draws.push_back(drawCommand); 662 } 663 frameSequence.push_back(frame); 664 } 665 return frameSequence; 666 } 667 668 vector<EGLint> getDamageRegion (const Frame& frame) 669 { 670 vector<EGLint> damageRegion; 671 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++) 672 { 673 const ColoredRect& rect = frame.draws[drawNdx].rect; 674 damageRegion.push_back(rect.bottomLeft.x()); 675 damageRegion.push_back(rect.bottomLeft.y()); 676 damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x()); 677 damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y()); 678 } 679 680 DE_ASSERT(damageRegion.size() % 4 == 0); 681 return damageRegion; 682 } 683 684 string generateTestName (const vector<DrawType>& frameDrawType) 685 { 686 std::ostringstream stream; 687 688 for (size_t ndx = 0; ndx < frameDrawType.size(); ndx++) 689 { 690 if (frameDrawType[ndx] == DRAWTYPE_GLES2_RENDER) 691 stream << "render"; 692 else if (frameDrawType[ndx] == DRAWTYPE_GLES2_CLEAR) 693 stream << "clear"; 694 else 695 DE_ASSERT(false); 696 697 if (ndx < frameDrawType.size()-1) 698 stream << "_"; 699 } 700 701 return stream.str(); 702 } 703 704 string generateResizeGroupName (ResizeType resizeType) 705 { 706 switch (resizeType) 707 { 708 case RESIZETYPE_NONE: 709 return "no_resize"; 710 711 case RESIZETYPE_AFTER_SWAP: 712 return "resize_after_swap"; 713 714 case RESIZETYPE_BEFORE_SWAP: 715 return "resize_before_swap"; 716 717 default: 718 DE_FATAL("Unknown resize type"); 719 return ""; 720 } 721 } 722 723 bool isWindow (const eglu::CandidateConfig& c) 724 { 725 return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT; 726 } 727 728 bool isES2Renderable (const eglu::CandidateConfig& c) 729 { 730 return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT; 731 } 732 733 bool hasPreserveSwap (const eglu::CandidateConfig& c) 734 { 735 return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT; 736 } 737 738 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay, bool preserveBuffer) 739 { 740 eglu::FilterList filters; 741 742 filters << isWindow << isES2Renderable; 743 if (preserveBuffer) 744 filters << hasPreserveSwap; 745 746 return eglu::chooseSingleConfig(egl, eglDisplay, filters); 747 } 748 749 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor) 750 { 751 gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()); 752 gl.clear(GL_COLOR_BUFFER_BIT); 753 } 754 755 float windowToDeviceCoordinates (int x, int length) 756 { 757 return (2.0f * float(x) / float(length)) - 1.0f; 758 } 759 760 } // anonymous 761 762 SwapBuffersWithDamageTests::SwapBuffersWithDamageTests (EglTestContext& eglTestCtx) 763 : TestCaseGroup(eglTestCtx, "swap_buffers_with_damage", "Swap buffers with damages tests") 764 { 765 } 766 767 void SwapBuffersWithDamageTests::init (void) 768 { 769 const DrawType clearRender[2] = 770 { 771 DRAWTYPE_GLES2_CLEAR, 772 DRAWTYPE_GLES2_RENDER 773 }; 774 775 const DrawType renderClear[2] = 776 { 777 DRAWTYPE_GLES2_RENDER, 778 DRAWTYPE_GLES2_CLEAR 779 }; 780 781 const ResizeType resizeTypes[] = 782 { 783 RESIZETYPE_NONE, 784 RESIZETYPE_BEFORE_SWAP, 785 RESIZETYPE_AFTER_SWAP 786 }; 787 788 vector< vector<DrawType> > frameDrawTypes; 789 frameDrawTypes.push_back(vector<DrawType> (1, DRAWTYPE_GLES2_CLEAR)); 790 frameDrawTypes.push_back(vector<DrawType> (1, DRAWTYPE_GLES2_RENDER)); 791 frameDrawTypes.push_back(vector<DrawType> (2, DRAWTYPE_GLES2_CLEAR)); 792 frameDrawTypes.push_back(vector<DrawType> (2, DRAWTYPE_GLES2_RENDER)); 793 frameDrawTypes.push_back(vector<DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender))); 794 frameDrawTypes.push_back(vector<DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear))); 795 796 for (size_t resizeTypeNdx = 0; resizeTypeNdx < DE_LENGTH_OF_ARRAY(resizeTypes); resizeTypeNdx++) 797 { 798 const ResizeType resizeType = resizeTypes[resizeTypeNdx]; 799 TestCaseGroup* const resizeGroup = new TestCaseGroup(m_eglTestCtx, generateResizeGroupName(resizeType).c_str(), ""); 800 801 for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++) 802 { 803 string name = generateTestName(frameDrawTypes[drawTypeNdx]); 804 resizeGroup->addChild(new SwapBuffersWithDamageTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), "")); 805 } 806 807 for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++) 808 { 809 string name = "preserve_buffer_" + generateTestName(frameDrawTypes[drawTypeNdx]); 810 resizeGroup->addChild(new SwapBuffersWithDamageAndPreserveBufferTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), "")); 811 } 812 813 for (size_t drawTypeNdx = 0; drawTypeNdx < frameDrawTypes.size(); drawTypeNdx++) 814 { 815 string name = "buffer_age_" + generateTestName(frameDrawTypes[drawTypeNdx]); 816 resizeGroup->addChild(new SwapBuffersWithDamageAndBufferAgeTest(m_eglTestCtx, frameDrawTypes[drawTypeNdx], 4, resizeType, name.c_str(), "")); 817 } 818 819 addChild(resizeGroup); 820 } 821 } 822 823 } // egl 824 } // deqp 825