1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program EGL Module
3 * ---------------------------------------
5 * Copyright 2015 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Test KHR_partial_update
22 *//*--------------------------------------------------------------------*/
24 #include "teglPartialUpdateTests.hpp"
26 #include "tcuImageCompare.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuTextureUtil.hpp"
31 #include "egluNativeWindow.hpp"
32 #include "egluUtil.hpp"
33 #include "egluConfigFilter.hpp"
35 #include "eglwLibrary.hpp"
36 #include "eglwEnums.hpp"
38 #include "gluDefs.hpp"
39 #include "gluRenderContext.hpp"
40 #include "gluShaderProgram.hpp"
42 #include "glwDefs.hpp"
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
46 #include "deRandom.hpp"
67 typedef tcu::Vector<GLubyte, 3> Color;
71 class ReferenceRenderer;
73 class PartialUpdateTest : public TestCase
82 PartialUpdateTest (EglTestContext& eglTestCtx,
83 const vector<DrawType>& oddFrameDrawType,
84 const vector<DrawType>& evenFrameDrawType,
86 const char* description);
87 ~PartialUpdateTest (void);
91 IterateResult iterate (void);
94 eglu::NativeWindow* m_window;
95 EGLConfig m_eglConfig;
96 EGLContext m_eglContext;
99 void initEGLSurface (EGLConfig config);
100 void initEGLContext (EGLConfig config);
103 const vector<DrawType> m_oddFrameDrawType;
104 const vector<DrawType> m_evenFrameDrawType;
106 bool m_supportBufferAge;
107 EGLDisplay m_eglDisplay;
108 EGLSurface m_eglSurface;
111 GLES2Renderer* m_gles2Renderer;
112 ReferenceRenderer* m_refRenderer;
118 ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
124 ColoredRect::ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_)
125 : bottomLeft (bottomLeft_)
126 , topRight (topRight_)
133 DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_);
134 PartialUpdateTest::DrawType drawType;
138 DrawCommand::DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_)
139 : drawType (drawType_)
146 Frame (int width_, int height_);
149 vector<DrawCommand> draws;
152 Frame::Frame (int width_, int height_)
158 // (x1,y1) lie in the lower-left quadrant while (x2,y2) lie in the upper-right.
159 // the coords are multiplied by 4 to amplify the minimial difference between coords to 4 (if not zero)
160 // to avoid the situation where two edges are too close to each other which makes the rounding error
161 // intoleratable by compareToReference()
162 void generateRandomFrame (Frame& dst, const vector<PartialUpdateTest::DrawType>& drawTypes, de::Random& rnd)
164 for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
166 const int x1 = rnd.getInt(0, (dst.width-1)/8) * 4;
167 const int y1 = rnd.getInt(0, (dst.height-1)/8) * 4;
168 const int x2 = rnd.getInt((dst.width-1)/8, (dst.width-1)/4) * 4;
169 const int y2 = rnd.getInt((dst.height-1)/8, (dst.height-1)/4) * 4;
170 const GLubyte r = rnd.getUint8();
171 const GLubyte g = rnd.getUint8();
172 const GLubyte b = rnd.getUint8();
173 const ColoredRect coloredRect (IVec2(x1, y1), IVec2(x2, y2), Color(r, g, b));
174 const DrawCommand drawCommand (drawTypes[ndx], coloredRect);
176 dst.draws.push_back(drawCommand);
180 typedef vector<Frame> FrameSequence;
182 //helper function declaration
183 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay);
184 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor);
185 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor);
186 void readPixels (const glw::Functions& gl, tcu::Surface* screen);
187 float windowToDeviceCoordinates (int x, int length);
188 bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum);
189 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx);
194 GLES2Renderer (const glw::Functions& gl);
195 ~GLES2Renderer (void);
196 void render (int width, int height, const Frame& frame) const;
199 GLES2Renderer (const GLES2Renderer&);
200 GLES2Renderer& operator= (const GLES2Renderer&);
202 const glw::Functions& m_gl;
203 glu::ShaderProgram m_glProgram;
204 glw::GLuint m_coordLoc;
205 glw::GLuint m_colorLoc;
208 // generate sources for vertex and fragment buffer
209 glu::ProgramSources getSources (void)
211 const char* const vertexShaderSource =
212 "attribute mediump vec2 a_pos;\n"
213 "attribute mediump vec4 a_color;\n"
214 "varying mediump vec4 v_color;\n"
217 "\tv_color = a_color;\n"
218 "\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
221 const char* const fragmentShaderSource =
222 "varying mediump vec4 v_color;\n"
225 "\tgl_FragColor = v_color;\n"
228 return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
231 GLES2Renderer::GLES2Renderer (const glw::Functions& gl)
233 , m_glProgram (gl, getSources())
234 , m_coordLoc ((glw::GLuint)-1)
235 , m_colorLoc ((glw::GLuint)-1)
237 m_colorLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_color");
238 m_coordLoc = m_gl.getAttribLocation(m_glProgram.getProgram(), "a_pos");
239 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to get attribute locations");
242 GLES2Renderer::~GLES2Renderer (void)
246 void GLES2Renderer::render (int width, int height, const Frame& frame) const
248 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
250 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
252 if (frame.draws[drawNdx].drawType == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
254 const float x1 = windowToDeviceCoordinates(coloredRect.bottomLeft.x(), width);
255 const float y1 = windowToDeviceCoordinates(coloredRect.bottomLeft.y(), height);
256 const float x2 = windowToDeviceCoordinates(coloredRect.topRight.x(), width);
257 const float y2 = windowToDeviceCoordinates(coloredRect.topRight.y(), height);
259 const glw::GLfloat coords[] =
270 const glw::GLubyte colors[] =
272 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
273 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
274 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
276 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
277 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
278 coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255,
281 m_gl.useProgram(m_glProgram.getProgram());
282 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
284 m_gl.enableVertexAttribArray(m_coordLoc);
285 m_gl.enableVertexAttribArray(m_colorLoc);
286 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
288 m_gl.vertexAttribPointer(m_coordLoc, 2, GL_FLOAT, GL_FALSE, 0, coords);
289 m_gl.vertexAttribPointer(m_colorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
290 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to set attribute pointers");
292 m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/2);
293 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed");
295 m_gl.disableVertexAttribArray(m_coordLoc);
296 m_gl.disableVertexAttribArray(m_colorLoc);
297 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
300 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
302 else if (frame.draws[drawNdx].drawType == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
304 m_gl.enable(GL_SCISSOR_TEST);
305 m_gl.scissor(coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
306 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y());
307 m_gl.clearColor(coloredRect.color.x()/255.0f, coloredRect.color.y()/255.0f, coloredRect.color.z()/255.0f, 1.0f);
308 m_gl.clear(GL_COLOR_BUFFER_BIT);
309 m_gl.disable(GL_SCISSOR_TEST);
312 DE_FATAL("Invalid drawtype");
316 class ReferenceRenderer
319 ReferenceRenderer (void);
320 void render (tcu::Surface* target, const Frame& frame) const;
322 ReferenceRenderer (const ReferenceRenderer&);
323 ReferenceRenderer& operator= (const ReferenceRenderer&);
326 ReferenceRenderer::ReferenceRenderer(void)
330 void ReferenceRenderer::render (tcu::Surface* target, const Frame& frame) const
332 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
334 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
335 if (frame.draws[drawNdx].drawType == PartialUpdateTest::DRAWTYPE_GLES2_RENDER || frame.draws[drawNdx].drawType == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
337 // tcu does not support degenerate subregions. Since they correspond to no-op rendering, just skip them.
338 if (coloredRect.bottomLeft.x() == coloredRect.topRight.x() || coloredRect.bottomLeft.y() == coloredRect.topRight.y())
341 const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
342 tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
343 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
346 DE_FATAL("Invalid drawtype");
350 PartialUpdateTest::PartialUpdateTest (EglTestContext& eglTestCtx,
351 const vector<DrawType>& oddFrameDrawType,
352 const vector<DrawType>& evenFrameDrawType,
353 const char* name, const char* description)
354 : TestCase (eglTestCtx, name, description)
356 , m_eglContext (EGL_NO_CONTEXT)
357 , m_seed (deStringHash(name))
358 , m_oddFrameDrawType (oddFrameDrawType)
359 , m_evenFrameDrawType (evenFrameDrawType)
360 , m_supportBufferAge (false)
361 , m_eglDisplay (EGL_NO_DISPLAY)
362 , m_eglSurface (EGL_NO_SURFACE)
363 , m_gles2Renderer (DE_NULL)
364 , m_refRenderer (DE_NULL)
368 PartialUpdateTest::~PartialUpdateTest (void)
373 void PartialUpdateTest::init (void)
375 const Library& egl = m_eglTestCtx.getLibrary();
377 m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
379 if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_partial_update"))
381 egl.terminate(m_eglDisplay);
382 m_eglDisplay = EGL_NO_DISPLAY;
383 TCU_THROW(NotSupportedError, "EGL_KHR_partial_update is not supported");
386 m_eglConfig = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay);
388 //create surface and context and make them current
389 initEGLSurface(m_eglConfig);
390 initEGLContext(m_eglConfig);
392 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
394 m_supportBufferAge = eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age");
396 m_gles2Renderer = new GLES2Renderer(m_gl);
397 m_refRenderer = new ReferenceRenderer();
400 void PartialUpdateTest::deinit (void)
402 const Library& egl = m_eglTestCtx.getLibrary();
404 delete m_refRenderer;
405 m_refRenderer = DE_NULL;
407 delete m_gles2Renderer;
408 m_gles2Renderer = DE_NULL;
410 if (m_eglContext != EGL_NO_CONTEXT)
412 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
413 egl.destroyContext(m_eglDisplay, m_eglContext);
414 m_eglContext = EGL_NO_CONTEXT;
417 if (m_eglSurface != EGL_NO_SURFACE)
419 egl.destroySurface(m_eglDisplay, m_eglSurface);
420 m_eglSurface = EGL_NO_SURFACE;
423 if (m_eglDisplay != EGL_NO_DISPLAY)
425 egl.terminate(m_eglDisplay);
426 m_eglDisplay = EGL_NO_DISPLAY;
433 void PartialUpdateTest::initEGLSurface (EGLConfig config)
435 const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
436 m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
437 eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
438 m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
441 void PartialUpdateTest::initEGLContext (EGLConfig config)
443 const Library& egl = m_eglTestCtx.getLibrary();
444 const EGLint attribList[] =
446 EGL_CONTEXT_CLIENT_VERSION, 2,
450 egl.bindAPI(EGL_OPENGL_ES_API);
451 m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
452 EGLU_CHECK_MSG(egl, "eglCreateContext");
453 TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
454 egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
455 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
458 // return indices of frames that have been written to the given buffer
459 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
461 DE_ASSERT(frameNdx < (int)bufferAges.size());
462 vector<int> frameOnBuffer;
463 int age = bufferAges[frameNdx];
466 frameNdx = frameNdx - age;
467 DE_ASSERT(frameNdx >= 0);
468 frameOnBuffer.push_back(frameNdx);
469 age = bufferAges[frameNdx];
472 reverse(frameOnBuffer.begin(), frameOnBuffer.end());
473 return frameOnBuffer;
476 vector<EGLint> getDamageRegion (const Frame& frame, int marginLeft, int marginBottom, int marginRight, int marginTop)
478 vector<EGLint> damageRegion;
479 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
481 const ColoredRect& rect = frame.draws[drawNdx].rect;
482 damageRegion.push_back(rect.bottomLeft.x() - marginLeft);
483 damageRegion.push_back(rect.bottomLeft.y() - marginBottom);
484 damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x() + marginLeft + marginRight);
485 damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y() + marginBottom + marginTop);
488 DE_ASSERT(damageRegion.size() % 4 == 0);
492 TestCase::IterateResult PartialUpdateTest::iterate (void)
494 de::Random rnd (m_seed);
495 const Library& egl = m_eglTestCtx.getLibrary();
496 tcu::TestLog& log = m_testCtx.getLog();
497 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
498 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
499 const float clearRed = rnd.getFloat();
500 const float clearGreen = rnd.getFloat();
501 const float clearBlue = rnd.getFloat();
502 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f);
503 const int numFrames = 20;
504 FrameSequence frameSequence;
505 vector<int> bufferAges;
506 bool hasPositiveAge = false;
508 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
510 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
512 tcu::Surface currentBuffer (width, height);
513 tcu::Surface refBuffer (width, height);
514 Frame newFrame (width, height);
515 EGLint currentBufferAge = -1;
517 if (frameNdx % 2 == 0)
518 generateRandomFrame(newFrame, m_evenFrameDrawType, rnd);
520 generateRandomFrame(newFrame, m_oddFrameDrawType, rnd);
522 frameSequence.push_back(newFrame);
524 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, ¤tBufferAge));
526 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
528 std::ostringstream stream;
529 stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
530 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
534 bufferAges.push_back(currentBufferAge);
535 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
537 if (currentBufferAge > 0)
539 vector<EGLint> damageRegion;
541 hasPositiveAge = true;
543 if (m_supportBufferAge)
545 damageRegion = getDamageRegion(newFrame, 10, 10, 10, 10);
549 damageRegion = getDamageRegion(newFrame, 0, 0, 0, 0);
552 // Set empty damage region to avoid invalidating the framebuffer. The damage area is invalidated
553 // if the buffer age extension is not supported.
554 if (damageRegion.size() == 0)
555 damageRegion = vector<EGLint>(4, 0);
557 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
561 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, NULL, 0));
562 clearColorScreen(m_gl, clearColor);
565 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
566 if (frameNdx < numFrames/2)
567 m_gles2Renderer->render(width, height, newFrame);
568 else // do verification in the second half
570 const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
572 clearColorReference(&refBuffer, clearColor);
574 for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
575 m_refRenderer->render(&refBuffer, frameSequence[*it]);
577 m_gles2Renderer->render(width, height, newFrame);
578 m_refRenderer->render(&refBuffer, newFrame);
580 readPixels(m_gl, ¤tBuffer);
582 if (!compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx))
584 string errorMessage("Fail, render result is wrong. Buffer age is ");
585 errorMessage += (m_supportBufferAge ? "supported" : "not supported");
586 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, errorMessage.c_str());
590 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
593 if (!hasPositiveAge) // fraud behavior, pretend to support partial_update
595 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, claim to support partial_update but buffer age is always 0");
599 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
603 string generateDrawTypeName (const vector<PartialUpdateTest::DrawType>& drawTypes)
605 std::ostringstream stream;
606 if (drawTypes.size() == 0)
607 return string("_none");
609 for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
611 if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
613 else if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
621 string generateTestName (const vector<PartialUpdateTest::DrawType>& oddFrameDrawType, const vector<PartialUpdateTest::DrawType>& evenFrameDrawType)
623 return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
626 bool isWindow (const eglu::CandidateConfig& c)
628 return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
631 bool isES2Renderable (const eglu::CandidateConfig& c)
633 return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
636 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay)
638 eglu::FilterList filters;
639 filters << isWindow << isES2Renderable;
640 return eglu::chooseSingleConfig(egl, eglDisplay, filters);
643 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
645 gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
646 gl.clear(GL_COLOR_BUFFER_BIT);
649 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
651 tcu::clear(ref->getAccess(), clearColor);
654 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
656 gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
659 float windowToDeviceCoordinates (int x, int length)
661 return (2.0f * float(x) / float(length)) - 1.0f;
664 bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
666 std::ostringstream stream;
667 stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
668 return tcu::intThresholdPositionDeviationCompare(log, "partial update test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
669 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
672 class RenderOutsideDamageRegion : public PartialUpdateTest
675 RenderOutsideDamageRegion (EglTestContext& eglTestCtx);
676 TestCase::IterateResult iterate (void);
679 RenderOutsideDamageRegion::RenderOutsideDamageRegion (EglTestContext& eglTestCtx)
680 : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_outside_damage_region", "")
684 TestCase::IterateResult RenderOutsideDamageRegion::iterate (void)
686 de::Random rnd (m_seed);
687 const Library& egl = m_eglTestCtx.getLibrary();
688 tcu::TestLog& log = m_testCtx.getLog();
689 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
690 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
691 const float clearRed = rnd.getFloat();
692 const float clearGreen = rnd.getFloat();
693 const float clearBlue = rnd.getFloat();
694 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f);
695 tcu::Surface currentBuffer (width, height);
696 tcu::Surface refBuffer (width, height);
697 Frame frame (width, height);
699 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
701 generateRandomFrame(frame, m_evenFrameDrawType, rnd);
704 // render outside the region
705 EGLint bufferAge = -1;
706 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
708 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
709 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
710 clearColorScreen(m_gl, clearColor);
711 m_gles2Renderer->render(width, height, frame);
713 // next line will make the bug on Nexus 6 disappear
714 // readPixels(m_gl, ¤tBuffer);
717 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
719 // render a new frame
720 clearColorScreen(m_gl, clearColor);
721 m_gles2Renderer->render(width, height, frame);
722 clearColorReference(&refBuffer, clearColor);
723 m_refRenderer->render(&refBuffer, frame);
724 readPixels(m_gl, ¤tBuffer);
726 if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
727 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, fail to recover after rendering outside damageRegion");
729 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
734 class RenderBeforeSetDamageRegion : public PartialUpdateTest
737 RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx);
738 TestCase::IterateResult iterate (void);
741 RenderBeforeSetDamageRegion::RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx)
742 : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_before_set_damage_region", "")
746 TestCase::IterateResult RenderBeforeSetDamageRegion::iterate (void)
748 de::Random rnd (m_seed);
749 const Library& egl = m_eglTestCtx.getLibrary();
750 tcu::TestLog& log = m_testCtx.getLog();
751 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
752 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
753 const float clearRed = rnd.getFloat();
754 const float clearGreen = rnd.getFloat();
755 const float clearBlue = rnd.getFloat();
756 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f);
757 tcu::Surface currentBuffer (width, height);
758 tcu::Surface refBuffer (width, height);
759 Frame frame (width, height);
761 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
763 generateRandomFrame(frame, m_evenFrameDrawType, rnd);
766 // render before setDamageRegion
767 EGLint bufferAge = -1;
768 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
770 m_gles2Renderer->render(width, height, frame);
771 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
772 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
774 // next line will make the bug on Nexus 6 disappear
775 // readPixels(m_gl, ¤tBuffer);
778 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
780 // render a new frame
781 clearColorScreen(m_gl, clearColor);
782 m_gles2Renderer->render(width, height, frame);
783 clearColorReference(&refBuffer, clearColor);
784 m_refRenderer->render(&refBuffer, frame);
785 readPixels(m_gl, ¤tBuffer);
787 if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
788 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
790 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
797 PartialUpdateTests::PartialUpdateTests (EglTestContext& eglTestCtx)
798 : TestCaseGroup(eglTestCtx, "partial_update", "Partial update tests")
802 void PartialUpdateTests::init (void)
804 const PartialUpdateTest::DrawType clearRender[2] =
806 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR,
807 PartialUpdateTest::DRAWTYPE_GLES2_RENDER
810 const PartialUpdateTest::DrawType renderClear[2] =
812 PartialUpdateTest::DRAWTYPE_GLES2_RENDER,
813 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR
816 vector< vector<PartialUpdateTest::DrawType> > frameDrawTypes;
817 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> ());
818 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
819 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
820 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
821 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
822 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
823 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
825 for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
827 const vector<PartialUpdateTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
829 for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
831 const vector<PartialUpdateTest::DrawType>& oddFrameDrawType = frameDrawTypes[oddNdx];
832 const std::string name = generateTestName(oddFrameDrawType, evenFrameDrawType);
833 if (oddFrameDrawType.size() == 0 && evenFrameDrawType.size() == 0)
836 addChild(new PartialUpdateTest(m_eglTestCtx, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
839 addChild(new RenderOutsideDamageRegion(m_eglTestCtx));
840 addChild(new RenderBeforeSetDamageRegion(m_eglTestCtx));