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_partial_update
22 *//*--------------------------------------------------------------------*/
23
24 #include "teglPartialUpdateTests.hpp"
25
26 #include "tcuImageCompare.hpp"
27 #include "tcuTestLog.hpp"
28 #include "tcuSurface.hpp"
29 #include "tcuTextureUtil.hpp"
30
31 #include "egluNativeWindow.hpp"
32 #include "egluUtil.hpp"
33 #include "egluConfigFilter.hpp"
34
35 #include "eglwLibrary.hpp"
36 #include "eglwEnums.hpp"
37
38 #include "gluDefs.hpp"
39 #include "gluRenderContext.hpp"
40 #include "gluShaderProgram.hpp"
41
42 #include "glwDefs.hpp"
43 #include "glwEnums.hpp"
44 #include "glwFunctions.hpp"
45
46 #include "deRandom.hpp"
47 #include "deString.h"
48
49 #include <string>
50 #include <vector>
51 #include <sstream>
52
53 using std::string;
54 using std::vector;
55 using glw::GLubyte;
56 using tcu::IVec2;
57
58 using namespace eglw;
59
60 namespace deqp
61 {
62 namespace egl
63 {
64 namespace
65 {
66
67 typedef tcu::Vector<GLubyte, 3> Color;
68
69 class GLES2Renderer;
70
71 class ReferenceRenderer;
72
73 class PartialUpdateTest : public TestCase
74 {
75 public:
76 enum DrawType
77 {
78 DRAWTYPE_GLES2_CLEAR,
79 DRAWTYPE_GLES2_RENDER
80 };
81
82 PartialUpdateTest (EglTestContext& eglTestCtx,
83 const vector<DrawType>& oddFrameDrawType,
84 const vector<DrawType>& evenFrameDrawType,
85 const char* name,
86 const char* description);
87 ~PartialUpdateTest (void);
88
89 void init (void);
90 void deinit (void);
91 IterateResult iterate (void);
92
93 private:
94 eglu::NativeWindow* m_window;
95 EGLConfig m_eglConfig;
96 EGLContext m_eglContext;
97
98 protected:
99 void initEGLSurface (EGLConfig config);
100 void initEGLContext (EGLConfig config);
101
102 const int m_seed;
103 const vector<DrawType> m_oddFrameDrawType;
104 const vector<DrawType> m_evenFrameDrawType;
105
106 bool m_supportBufferAge;
107 EGLDisplay m_eglDisplay;
108 EGLSurface m_eglSurface;
109 glw::Functions m_gl;
110
111 GLES2Renderer* m_gles2Renderer;
112 ReferenceRenderer* m_refRenderer;
113 };
114
115 struct ColoredRect
116 {
117 public:
118 ColoredRect (const IVec2& bottomLeft_, const IVec2& topRight_, const Color& color_);
119 IVec2 bottomLeft;
120 IVec2 topRight;
121 Color color;
122 };
123
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_)
127 , color (color_)
128 {
129 }
130
131 struct DrawCommand
132 {
133 DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_);
134 PartialUpdateTest::DrawType drawType;
135 ColoredRect rect;
136 };
137
DrawCommand(const PartialUpdateTest::DrawType drawType_,const ColoredRect & rect_)138 DrawCommand::DrawCommand (const PartialUpdateTest::DrawType drawType_, const ColoredRect& rect_)
139 : drawType (drawType_)
140 , rect (rect_)
141 {
142 }
143
144 struct Frame
145 {
146 Frame (int width_, int height_);
147 int width;
148 int height;
149 vector<DrawCommand> draws;
150 };
151
Frame(int width_,int height_)152 Frame::Frame (int width_, int height_)
153 : width (width_)
154 , height(height_)
155 {
156 }
157
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()
generateRandomFrame(Frame & dst,const vector<PartialUpdateTest::DrawType> & drawTypes,de::Random & rnd)162 void generateRandomFrame (Frame& dst, const vector<PartialUpdateTest::DrawType>& drawTypes, de::Random& rnd)
163 {
164 for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
165 {
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);
175
176 dst.draws.push_back(drawCommand);
177 }
178 }
179
180 typedef vector<Frame> FrameSequence;
181
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);
190
191 class GLES2Renderer
192 {
193 public:
194 GLES2Renderer (const glw::Functions& gl);
195 ~GLES2Renderer (void);
196 void render (int width, int height, const Frame& frame) const;
197
198 private:
199 GLES2Renderer (const GLES2Renderer&);
200 GLES2Renderer& operator= (const GLES2Renderer&);
201
202 const glw::Functions& m_gl;
203 glu::ShaderProgram m_glProgram;
204 glw::GLuint m_coordLoc;
205 glw::GLuint m_colorLoc;
206 };
207
208 // generate sources for vertex and fragment buffer
getSources(void)209 glu::ProgramSources getSources (void)
210 {
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"
215 "void main(void)\n"
216 "{\n"
217 "\tv_color = a_color;\n"
218 "\tgl_Position = vec4(a_pos, 0.0, 1.0);\n"
219 "}";
220
221 const char* const fragmentShaderSource =
222 "varying mediump vec4 v_color;\n"
223 "void main(void)\n"
224 "{\n"
225 "\tgl_FragColor = v_color;\n"
226 "}";
227
228 return glu::makeVtxFragSources(vertexShaderSource, fragmentShaderSource);
229 }
230
GLES2Renderer(const glw::Functions & gl)231 GLES2Renderer::GLES2Renderer (const glw::Functions& gl)
232 : m_gl (gl)
233 , m_glProgram (gl, getSources())
234 , m_coordLoc ((glw::GLuint)-1)
235 , m_colorLoc ((glw::GLuint)-1)
236 {
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");
240 }
241
~GLES2Renderer(void)242 GLES2Renderer::~GLES2Renderer (void)
243 {
244 }
245
render(int width,int height,const Frame & frame) const246 void GLES2Renderer::render (int width, int height, const Frame& frame) const
247 {
248 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
249 {
250 const ColoredRect& coloredRect = frame.draws[drawNdx].rect;
251
252 if (frame.draws[drawNdx].drawType == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
253 {
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);
258
259 const glw::GLfloat coords[] =
260 {
261 x1, y1,
262 x1, y2,
263 x2, y2,
264
265 x2, y2,
266 x2, y1,
267 x1, y1,
268 };
269
270 const glw::GLubyte colors[] =
271 {
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,
275
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,
279 };
280
281 m_gl.useProgram(m_glProgram.getProgram());
282 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
283
284 m_gl.enableVertexAttribArray(m_coordLoc);
285 m_gl.enableVertexAttribArray(m_colorLoc);
286 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to enable attributes");
287
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");
291
292 m_gl.drawArrays(GL_TRIANGLES, 0, DE_LENGTH_OF_ARRAY(coords)/2);
293 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glDrawArrays(), failed");
294
295 m_gl.disableVertexAttribArray(m_coordLoc);
296 m_gl.disableVertexAttribArray(m_colorLoc);
297 GLU_EXPECT_NO_ERROR(m_gl.getError(), "Failed to disable attributes");
298
299 m_gl.useProgram(0);
300 GLU_EXPECT_NO_ERROR(m_gl.getError(), "glUseProgram() failed");
301 }
302 else if (frame.draws[drawNdx].drawType == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
303 {
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);
310 }
311 else
312 DE_FATAL("Invalid drawtype");
313 }
314 }
315
316 class ReferenceRenderer
317 {
318 public:
319 ReferenceRenderer (void);
320 void render (tcu::Surface* target, const Frame& frame) const;
321 private:
322 ReferenceRenderer (const ReferenceRenderer&);
323 ReferenceRenderer& operator= (const ReferenceRenderer&);
324 };
325
ReferenceRenderer(void)326 ReferenceRenderer::ReferenceRenderer(void)
327 {
328 }
329
render(tcu::Surface * target,const Frame & frame) const330 void ReferenceRenderer::render (tcu::Surface* target, const Frame& frame) const
331 {
332 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
333 {
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)
336 {
337 const tcu::UVec4 color(coloredRect.color.x(), coloredRect.color.y(), coloredRect.color.z(), 255);
338 tcu::clear(tcu::getSubregion(target->getAccess(), coloredRect.bottomLeft.x(), coloredRect.bottomLeft.y(),
339 coloredRect.topRight.x()-coloredRect.bottomLeft.x(), coloredRect.topRight.y()-coloredRect.bottomLeft.y()), color);
340 }
341 else
342 DE_FATAL("Invalid drawtype");
343 }
344 }
345
PartialUpdateTest(EglTestContext & eglTestCtx,const vector<DrawType> & oddFrameDrawType,const vector<DrawType> & evenFrameDrawType,const char * name,const char * description)346 PartialUpdateTest::PartialUpdateTest (EglTestContext& eglTestCtx,
347 const vector<DrawType>& oddFrameDrawType,
348 const vector<DrawType>& evenFrameDrawType,
349 const char* name, const char* description)
350 : TestCase (eglTestCtx, name, description)
351 , m_window (DE_NULL)
352 , m_eglContext (EGL_NO_CONTEXT)
353 , m_seed (deStringHash(name))
354 , m_oddFrameDrawType (oddFrameDrawType)
355 , m_evenFrameDrawType (evenFrameDrawType)
356 , m_supportBufferAge (false)
357 , m_eglDisplay (EGL_NO_DISPLAY)
358 , m_eglSurface (EGL_NO_SURFACE)
359 , m_gles2Renderer (DE_NULL)
360 , m_refRenderer (DE_NULL)
361 {
362 }
363
~PartialUpdateTest(void)364 PartialUpdateTest::~PartialUpdateTest (void)
365 {
366 deinit();
367 }
368
init(void)369 void PartialUpdateTest::init (void)
370 {
371 const Library& egl = m_eglTestCtx.getLibrary();
372
373 m_eglDisplay = eglu::getAndInitDisplay(m_eglTestCtx.getNativeDisplay());
374 m_eglConfig = getEGLConfig(m_eglTestCtx.getLibrary(), m_eglDisplay);
375
376 //create surface and context and make them current
377 initEGLSurface(m_eglConfig);
378 initEGLContext(m_eglConfig);
379
380 m_eglTestCtx.initGLFunctions(&m_gl, glu::ApiType::es(2,0));
381
382 m_supportBufferAge = eglu::hasExtension(egl, m_eglDisplay, "EGL_EXT_buffer_age");
383
384 if (!eglu::hasExtension(egl, m_eglDisplay, "EGL_KHR_partial_update"))
385 TCU_THROW(NotSupportedError, "EGL_KHR_partial_update is not supported");
386
387 m_gles2Renderer = new GLES2Renderer(m_gl);
388 m_refRenderer = new ReferenceRenderer();
389 }
390
deinit(void)391 void PartialUpdateTest::deinit (void)
392 {
393 const Library& egl = m_eglTestCtx.getLibrary();
394
395 delete m_refRenderer;
396 m_refRenderer = DE_NULL;
397
398 delete m_gles2Renderer;
399 m_gles2Renderer = DE_NULL;
400
401 if (m_eglContext != EGL_NO_CONTEXT)
402 {
403 egl.makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
404 egl.destroyContext(m_eglDisplay, m_eglContext);
405 m_eglContext = EGL_NO_CONTEXT;
406 }
407
408 if (m_eglSurface != EGL_NO_SURFACE)
409 {
410 egl.destroySurface(m_eglDisplay, m_eglSurface);
411 m_eglSurface = EGL_NO_SURFACE;
412 }
413
414 if (m_eglDisplay != EGL_NO_DISPLAY)
415 {
416 egl.terminate(m_eglDisplay);
417 m_eglDisplay = EGL_NO_DISPLAY;
418 }
419
420 delete m_window;
421 m_window = DE_NULL;
422 }
423
initEGLSurface(EGLConfig config)424 void PartialUpdateTest::initEGLSurface (EGLConfig config)
425 {
426 const eglu::NativeWindowFactory& factory = eglu::selectNativeWindowFactory(m_eglTestCtx.getNativeDisplayFactory(), m_testCtx.getCommandLine());
427 m_window = factory.createWindow(&m_eglTestCtx.getNativeDisplay(), m_eglDisplay, config, DE_NULL,
428 eglu::WindowParams(480, 480, eglu::parseWindowVisibility(m_testCtx.getCommandLine())));
429 m_eglSurface = eglu::createWindowSurface(m_eglTestCtx.getNativeDisplay(), *m_window, m_eglDisplay, config, DE_NULL);
430 }
431
initEGLContext(EGLConfig config)432 void PartialUpdateTest::initEGLContext (EGLConfig config)
433 {
434 const Library& egl = m_eglTestCtx.getLibrary();
435 const EGLint attribList[] =
436 {
437 EGL_CONTEXT_CLIENT_VERSION, 2,
438 EGL_NONE
439 };
440
441 egl.bindAPI(EGL_OPENGL_ES_API);
442 m_eglContext = egl.createContext(m_eglDisplay, config, EGL_NO_CONTEXT, attribList);
443 EGLU_CHECK_MSG(egl, "eglCreateContext");
444 TCU_CHECK(m_eglSurface != EGL_NO_SURFACE);
445 egl.makeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext);
446 EGLU_CHECK_MSG(egl, "eglMakeCurrent");
447 }
448
449 // return indices of frames that have been written to the given buffer
getFramesOnBuffer(const vector<int> & bufferAges,int frameNdx)450 vector<int> getFramesOnBuffer (const vector<int>& bufferAges, int frameNdx)
451 {
452 DE_ASSERT(frameNdx < (int)bufferAges.size());
453 vector<int> frameOnBuffer;
454 int age = bufferAges[frameNdx];
455 while (age != 0)
456 {
457 frameNdx = frameNdx - age;
458 DE_ASSERT(frameNdx >= 0);
459 frameOnBuffer.push_back(frameNdx);
460 age = bufferAges[frameNdx];
461 }
462
463 reverse(frameOnBuffer.begin(), frameOnBuffer.end());
464 return frameOnBuffer;
465 }
466
getDamageRegion(const Frame & frame,int marginLeft,int marginBottom,int marginRight,int marginTop)467 vector<EGLint> getDamageRegion (const Frame& frame, int marginLeft, int marginBottom, int marginRight, int marginTop)
468 {
469 vector<EGLint> damageRegion;
470 for (size_t drawNdx = 0; drawNdx < frame.draws.size(); drawNdx++)
471 {
472 const ColoredRect& rect = frame.draws[drawNdx].rect;
473 damageRegion.push_back(rect.bottomLeft.x() - marginLeft);
474 damageRegion.push_back(rect.bottomLeft.y() - marginBottom);
475 damageRegion.push_back(rect.topRight.x() - rect.bottomLeft.x() + marginLeft + marginRight);
476 damageRegion.push_back(rect.topRight.y() - rect.bottomLeft.y() + marginBottom + marginTop);
477 }
478
479 DE_ASSERT(damageRegion.size() % 4 == 0);
480 return damageRegion;
481 }
482
iterate(void)483 TestCase::IterateResult PartialUpdateTest::iterate (void)
484 {
485 de::Random rnd (m_seed);
486 const Library& egl = m_eglTestCtx.getLibrary();
487 tcu::TestLog& log = m_testCtx.getLog();
488 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
489 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
490 const float clearRed = rnd.getFloat();
491 const float clearGreen = rnd.getFloat();
492 const float clearBlue = rnd.getFloat();
493 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f);
494 const int numFrames = 20;
495 FrameSequence frameSequence;
496 vector<int> bufferAges;
497 bool hasPositiveAge = false;
498
499 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
500
501 for (int frameNdx = 0; frameNdx < numFrames; frameNdx++)
502 {
503 tcu::Surface currentBuffer (width, height);
504 tcu::Surface refBuffer (width, height);
505 Frame newFrame (width, height);
506 EGLint currentBufferAge = -1;
507
508 if (frameNdx % 2 == 0)
509 generateRandomFrame(newFrame, m_evenFrameDrawType, rnd);
510 else
511 generateRandomFrame(newFrame, m_oddFrameDrawType, rnd);
512
513 frameSequence.push_back(newFrame);
514
515 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, ¤tBufferAge));
516
517 if (currentBufferAge > frameNdx || currentBufferAge < 0) // invalid buffer age
518 {
519 std::ostringstream stream;
520 stream << "Fail, the age is invalid. Age: " << currentBufferAge << ", frameNdx: " << frameNdx;
521 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, stream.str().c_str());
522 return STOP;
523 }
524
525 bufferAges.push_back(currentBufferAge);
526 DE_ASSERT((int)bufferAges.size() == frameNdx+1);
527
528 if (currentBufferAge > 0)
529 {
530 vector<EGLint> damageRegion;
531
532 hasPositiveAge = true;
533
534 if (m_supportBufferAge)
535 {
536 damageRegion = getDamageRegion(newFrame, 10, 10, 10, 10);
537 }
538 else
539 {
540 damageRegion = getDamageRegion(newFrame, 0, 0, 0, 0);
541 // Set empty damage region to avoid invalidating the framebuffer. The damage area is invalidated
542 // if the buffer age extension is not supported.
543 if (damageRegion.size() == 0)
544 damageRegion = vector<EGLint>(4, 0);
545 }
546
547 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
548 }
549 else
550 {
551 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, NULL, 0));
552 clearColorScreen(m_gl, clearColor);
553 }
554
555 // during first half, just keep rendering without reading pixel back to mimic ordinary use case
556 if (frameNdx < numFrames/2)
557 m_gles2Renderer->render(width, height, newFrame);
558 else // do verification in the second half
559 {
560 const vector<int> framesOnBuffer = getFramesOnBuffer(bufferAges, frameNdx);
561
562 clearColorReference(&refBuffer, clearColor);
563
564 for (vector<int>::const_iterator it = framesOnBuffer.begin(); it != framesOnBuffer.end(); it++)
565 m_refRenderer->render(&refBuffer, frameSequence[*it]);
566
567 m_gles2Renderer->render(width, height, newFrame);
568 m_refRenderer->render(&refBuffer, newFrame);
569
570 readPixels(m_gl, ¤tBuffer);
571
572 if (!compareToReference(log, refBuffer, currentBuffer, frameNdx, frameNdx))
573 {
574 string errorMessage("Fail, render result is wrong. Buffer age is ");
575 errorMessage += (m_supportBufferAge ? "supported" : "not supported");
576 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, errorMessage.c_str());
577 return STOP;
578 }
579 }
580 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
581 }
582
583 if (!hasPositiveAge) // fraud behavior, pretend to support partial_update
584 {
585 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, claim to support partial_update but buffer age is always 0");
586 return STOP;
587 }
588
589 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
590 return STOP;
591 }
592
generateDrawTypeName(const vector<PartialUpdateTest::DrawType> & drawTypes)593 string generateDrawTypeName (const vector<PartialUpdateTest::DrawType>& drawTypes)
594 {
595 std::ostringstream stream;
596 if (drawTypes.size() == 0)
597 return string("_none");
598
599 for (size_t ndx = 0; ndx < drawTypes.size(); ndx++)
600 {
601 if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_RENDER)
602 stream << "_render";
603 else if (drawTypes[ndx] == PartialUpdateTest::DRAWTYPE_GLES2_CLEAR)
604 stream << "_clear";
605 else
606 DE_ASSERT(false);
607 }
608 return stream.str();
609 }
610
generateTestName(const vector<PartialUpdateTest::DrawType> & oddFrameDrawType,const vector<PartialUpdateTest::DrawType> & evenFrameDrawType)611 string generateTestName (const vector<PartialUpdateTest::DrawType>& oddFrameDrawType, const vector<PartialUpdateTest::DrawType>& evenFrameDrawType)
612 {
613 return "odd" + generateDrawTypeName(oddFrameDrawType) + "_even" + generateDrawTypeName(evenFrameDrawType);
614 }
615
isWindow(const eglu::CandidateConfig & c)616 bool isWindow (const eglu::CandidateConfig& c)
617 {
618 return (c.surfaceType() & EGL_WINDOW_BIT) == EGL_WINDOW_BIT;
619 }
620
isES2Renderable(const eglu::CandidateConfig & c)621 bool isES2Renderable (const eglu::CandidateConfig& c)
622 {
623 return (c.get(EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT;
624 }
625
getEGLConfig(const Library & egl,EGLDisplay eglDisplay)626 EGLConfig getEGLConfig (const Library& egl, EGLDisplay eglDisplay)
627 {
628 eglu::FilterList filters;
629 filters << isWindow << isES2Renderable;
630 return eglu::chooseSingleConfig(egl, eglDisplay, filters);
631 }
632
clearColorScreen(const glw::Functions & gl,const tcu::Vec4 & clearColor)633 void clearColorScreen (const glw::Functions& gl, const tcu::Vec4& clearColor)
634 {
635 gl.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w());
636 gl.clear(GL_COLOR_BUFFER_BIT);
637 }
638
clearColorReference(tcu::Surface * ref,const tcu::Vec4 & clearColor)639 void clearColorReference (tcu::Surface* ref, const tcu::Vec4& clearColor)
640 {
641 tcu::clear(ref->getAccess(), clearColor);
642 }
643
readPixels(const glw::Functions & gl,tcu::Surface * screen)644 void readPixels (const glw::Functions& gl, tcu::Surface* screen)
645 {
646 gl.readPixels(0, 0, screen->getWidth(), screen->getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, screen->getAccess().getDataPtr());
647 }
648
windowToDeviceCoordinates(int x,int length)649 float windowToDeviceCoordinates (int x, int length)
650 {
651 return (2.0f * float(x) / float(length)) - 1.0f;
652 }
653
compareToReference(tcu::TestLog & log,const tcu::Surface & reference,const tcu::Surface & buffer,int frameNdx,int bufferNum)654 bool compareToReference (tcu::TestLog& log, const tcu::Surface& reference, const tcu::Surface& buffer, int frameNdx, int bufferNum)
655 {
656 std::ostringstream stream;
657 stream << "FrameNdx = " << frameNdx << ", compare current buffer (numbered: " << bufferNum << ") to reference";
658 return tcu::intThresholdPositionDeviationCompare(log, "partial update test", stream.str().c_str(), reference.getAccess(), buffer.getAccess(),
659 tcu::UVec4(8, 8, 8, 0), tcu::IVec3(2,2,0), true, tcu::COMPARE_LOG_RESULT);
660 }
661
662 class RenderOutsideDamageRegion : public PartialUpdateTest
663 {
664 public:
665 RenderOutsideDamageRegion (EglTestContext& eglTestCtx);
666 TestCase::IterateResult iterate (void);
667 };
668
RenderOutsideDamageRegion(EglTestContext & eglTestCtx)669 RenderOutsideDamageRegion::RenderOutsideDamageRegion (EglTestContext& eglTestCtx)
670 : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_outside_damage_region", "")
671 {
672 }
673
iterate(void)674 TestCase::IterateResult RenderOutsideDamageRegion::iterate (void)
675 {
676 de::Random rnd (m_seed);
677 const Library& egl = m_eglTestCtx.getLibrary();
678 tcu::TestLog& log = m_testCtx.getLog();
679 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
680 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
681 const float clearRed = rnd.getFloat();
682 const float clearGreen = rnd.getFloat();
683 const float clearBlue = rnd.getFloat();
684 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f);
685 tcu::Surface currentBuffer (width, height);
686 tcu::Surface refBuffer (width, height);
687 Frame frame (width, height);
688
689 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
690
691 generateRandomFrame(frame, m_evenFrameDrawType, rnd);
692
693 {
694 // render outside the region
695 EGLint bufferAge = -1;
696 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
697
698 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
699 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
700 clearColorScreen(m_gl, clearColor);
701 m_gles2Renderer->render(width, height, frame);
702
703 // next line will make the bug on Nexus 6 disappear
704 // readPixels(m_gl, ¤tBuffer);
705 }
706
707 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
708
709 // render a new frame
710 clearColorScreen(m_gl, clearColor);
711 m_gles2Renderer->render(width, height, frame);
712 clearColorReference(&refBuffer, clearColor);
713 m_refRenderer->render(&refBuffer, frame);
714 readPixels(m_gl, ¤tBuffer);
715
716 if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
717 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail, fail to recover after rendering outside damageRegion");
718 else
719 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
720
721 return STOP;
722 }
723
724 class RenderBeforeSetDamageRegion : public PartialUpdateTest
725 {
726 public:
727 RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx);
728 TestCase::IterateResult iterate (void);
729 };
730
RenderBeforeSetDamageRegion(EglTestContext & eglTestCtx)731 RenderBeforeSetDamageRegion::RenderBeforeSetDamageRegion (EglTestContext& eglTestCtx)
732 : PartialUpdateTest (eglTestCtx, vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), vector<DrawType>(1, DRAWTYPE_GLES2_RENDER), "render_before_set_damage_region", "")
733 {
734 }
735
iterate(void)736 TestCase::IterateResult RenderBeforeSetDamageRegion::iterate (void)
737 {
738 de::Random rnd (m_seed);
739 const Library& egl = m_eglTestCtx.getLibrary();
740 tcu::TestLog& log = m_testCtx.getLog();
741 const int width = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_WIDTH);
742 const int height = eglu::querySurfaceInt(egl, m_eglDisplay, m_eglSurface, EGL_HEIGHT);
743 const float clearRed = rnd.getFloat();
744 const float clearGreen = rnd.getFloat();
745 const float clearBlue = rnd.getFloat();
746 const tcu::Vec4 clearColor (clearRed, clearGreen, clearBlue, 1.0f);
747 tcu::Surface currentBuffer (width, height);
748 tcu::Surface refBuffer (width, height);
749 Frame frame (width, height);
750
751 EGLU_CHECK_CALL(egl, surfaceAttrib(m_eglDisplay, m_eglSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED));
752
753 generateRandomFrame(frame, m_evenFrameDrawType, rnd);
754
755 {
756 // render before setDamageRegion
757 EGLint bufferAge = -1;
758 vector<EGLint> damageRegion = getDamageRegion(frame, 0, 0, 0, 0);
759
760 m_gles2Renderer->render(width, height, frame);
761 EGLU_CHECK_CALL(egl, querySurface(m_eglDisplay, m_eglSurface, EGL_BUFFER_AGE_KHR, &bufferAge));
762 EGLU_CHECK_CALL(egl, setDamageRegionKHR(m_eglDisplay, m_eglSurface, &damageRegion[0], (EGLint)damageRegion.size()/4));
763
764 // next line will make the bug on Nexus 6 disappear
765 // readPixels(m_gl, ¤tBuffer);
766 }
767
768 EGLU_CHECK_CALL(egl, swapBuffers(m_eglDisplay, m_eglSurface));
769
770 // render a new frame
771 clearColorScreen(m_gl, clearColor);
772 m_gles2Renderer->render(width, height, frame);
773 clearColorReference(&refBuffer, clearColor);
774 m_refRenderer->render(&refBuffer, frame);
775 readPixels(m_gl, ¤tBuffer);
776
777 if (!compareToReference(log, refBuffer, currentBuffer, 0, 0))
778 m_testCtx.setTestResult(QP_TEST_RESULT_FAIL, "Fail");
779 else
780 m_testCtx.setTestResult(QP_TEST_RESULT_PASS, "Pass");
781
782 return STOP;
783 }
784
785 } // anonymous
786
PartialUpdateTests(EglTestContext & eglTestCtx)787 PartialUpdateTests::PartialUpdateTests (EglTestContext& eglTestCtx)
788 : TestCaseGroup(eglTestCtx, "partial_update", "Partial update tests")
789 {
790 }
791
init(void)792 void PartialUpdateTests::init (void)
793 {
794 const PartialUpdateTest::DrawType clearRender[2] =
795 {
796 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR,
797 PartialUpdateTest::DRAWTYPE_GLES2_RENDER
798 };
799
800 const PartialUpdateTest::DrawType renderClear[2] =
801 {
802 PartialUpdateTest::DRAWTYPE_GLES2_RENDER,
803 PartialUpdateTest::DRAWTYPE_GLES2_CLEAR
804 };
805
806 vector< vector<PartialUpdateTest::DrawType> > frameDrawTypes;
807 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> ());
808 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
809 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (1, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
810 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_CLEAR));
811 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (2, PartialUpdateTest::DRAWTYPE_GLES2_RENDER));
812 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(clearRender), DE_ARRAY_END(clearRender)));
813 frameDrawTypes.push_back(vector<PartialUpdateTest::DrawType> (DE_ARRAY_BEGIN(renderClear), DE_ARRAY_END(renderClear)));
814
815 for (size_t evenNdx = 0; evenNdx < frameDrawTypes.size(); evenNdx++)
816 {
817 const vector<PartialUpdateTest::DrawType>& evenFrameDrawType = frameDrawTypes[evenNdx];
818
819 for (size_t oddNdx = evenNdx; oddNdx < frameDrawTypes.size(); oddNdx++)
820 {
821 const vector<PartialUpdateTest::DrawType>& oddFrameDrawType = frameDrawTypes[oddNdx];
822 const std::string name = generateTestName(oddFrameDrawType, evenFrameDrawType);
823 if (oddFrameDrawType.size() == 0 && evenFrameDrawType.size() == 0)
824 continue;
825
826 addChild(new PartialUpdateTest(m_eglTestCtx, oddFrameDrawType, evenFrameDrawType, name.c_str(), ""));
827 }
828 }
829 addChild(new RenderOutsideDamageRegion(m_eglTestCtx));
830 addChild(new RenderBeforeSetDamageRegion(m_eglTestCtx));
831 }
832
833 } // egl
834 } // deqp
835