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
ColoredRect(const IVec2 & bottomLeft_,const IVec2 & topRight_,const Color & color_)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
DrawCommand(DrawType drawType_,const ColoredRect & rect_)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
Frame(int width_,int height_)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
getSources(void)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
GLES2Renderer(const glw::Functions & gl)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
~GLES2Renderer(void)184 GLES2Renderer::~GLES2Renderer (void)
185 {
186 }
187
render(int width,int height,const Frame & frame) const188 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
SwapBuffersWithDamageTest(EglTestContext & eglTestCtx,const vector<DrawType> & frameDrawType,int iterationTimes,ResizeType resizeType,const char * name,const char * description)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
~SwapBuffersWithDamageTest(void)307 SwapBuffersWithDamageTest::~SwapBuffersWithDamageTest (void)
308 {
309 deinit();
310 }
311
getConfig(const Library & egl,EGLDisplay eglDisplay)312 EGLConfig SwapBuffersWithDamageTest::getConfig (const Library& egl, EGLDisplay eglDisplay)
313 {
314 return getEGLConfig(egl, eglDisplay, false);
315 }
316
checkExtension(const Library & egl,EGLDisplay eglDisplay)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
init(void)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
deinit(void)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
initEGLSurface(EGLConfig config)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
initEGLContext(EGLConfig config)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
iterate(void)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 (currentFrameNdx % 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 (currentFrameNdx % 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
SwapBuffersWithDamageAndPreserveBufferTest(EglTestContext & eglTestCtx,const vector<DrawType> & frameDrawType,int iterationTimes,ResizeType resizeType,const char * name,const char * description)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
getConfig(const Library & egl,EGLDisplay eglDisplay)471 EGLConfig SwapBuffersWithDamageAndPreserveBufferTest::getConfig (const Library& egl, EGLDisplay eglDisplay)
472 {
473 return getEGLConfig(egl, eglDisplay, true);
474 }
475
iterate(void)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 (frameNdx % 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 (frameNdx % 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
SwapBuffersWithDamageAndBufferAgeTest(EglTestContext & eglTestCtx,const vector<DrawType> & frameDrawType,int iterationTimes,ResizeType resizeType,const char * name,const char * description)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
checkExtension(const Library & egl,EGLDisplay eglDisplay)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
iterate(void)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 (frameNdx % 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 (frameNdx % 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
generateFrameSequence(const vector<DrawType> & frameDrawType,de::Random & rnd,int numFrames,int width,int height)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
getDamageRegion(const Frame & frame)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
generateTestName(const vector<DrawType> & frameDrawType)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
generateResizeGroupName(ResizeType resizeType)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
isWindow(const eglu::CandidateConfig & c)723 bool isWindow (const eglu::CandidateConfig& c)
724 {
725 return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
726 }
727
isES2Renderable(const eglu::CandidateConfig & c)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
hasPreserveSwap(const eglu::CandidateConfig & c)733 bool hasPreserveSwap (const eglu::CandidateConfig& c)
734 {
735 return (c.surfaceType() & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) == EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
736 }
737
getEGLConfig(const Library & egl,EGLDisplay eglDisplay,bool preserveBuffer)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
clearColorScreen(const glw::Functions & gl,const tcu::Vec4 & clearColor)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
windowToDeviceCoordinates(int x,int length)755 float windowToDeviceCoordinates (int x, int length)
756 {
757 return (2.0f * float(x) / float(length)) - 1.0f;
758 }
759
760 } // anonymous
761
SwapBuffersWithDamageTests(EglTestContext & eglTestCtx)762 SwapBuffersWithDamageTests::SwapBuffersWithDamageTests (EglTestContext& eglTestCtx)
763 : TestCaseGroup(eglTestCtx, "swap_buffers_with_damage", "Swap buffers with damages tests")
764 {
765 }
766
init(void)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